public override ISemantReturn <ABT.ExprType> DecorateType(ABT.Env env, ABT.ExprType targetType) { var isConst = this.TypeQuals.Contains(TypeQual.CONST); var isVolatile = this.TypeQuals.Contains(TypeQual.VOLATILE); return(SemantReturn.Create(env, new ABT.PointerType(targetType, isConst, isVolatile))); }
public ISemantReturn <ImmutableList <Tuple <Option <String>, ExprType> > > GetMembers(Env env, ImmutableList <StructDecln> memberDeclns) { var result = memberDeclns.Aggregate(ImmutableList <Tuple <Option <String>, ExprType> > .Empty, (acc, decln) => acc.AddRange(Semant(decln.GetMemberDeclns, ref env)) ); return(SemantReturn.Create(env, result)); }
public ISemantReturn <ExprType> GetParamType(Env env) { var baseType = Semant(this.DeclnSpecs.GetExprType, ref env); var type = Semant(this.ParamDeclr.DecorateType, baseType, ref env); return(SemantReturn.Create(env, type)); }
public ISemantReturn <ImmutableList <Tuple <Env, ExternDecln> > > GetExternDecln(Env env) { var declns = Semant(GetDeclns, ref env); var externDeclns = declns.ConvertAll(_ => Tuple.Create(_.Item1, _.Item2 as ExternDecln)); return(SemantReturn.Create(env, externDeclns)); }
public ISemantReturn <ExprType> GetExprType(Env env) { var baseType = Semant(this.SpecQualList.GetExprType, ref env); var type = Semant(this.AbstractDeclr.DecorateType, baseType, ref env); return(SemantReturn.Create(env, type)); }
public ISemantReturn <ImmutableList <Tuple <Env, ExternDecln> > > GetExternDecln(Env env) { var storageClass = this.Specs.GetStorageClass(); var baseType = Semant(this.Specs.GetExprType, ref env); var name = this.Declr.Name; var type = Semant(this.Declr.DecorateType, baseType, ref env); var funcType = type as FunctionType; if (funcType == null) { throw new InvalidOperationException("Expected a function Type."); } switch (storageClass) { case StorageClass.AUTO: case StorageClass.EXTERN: case StorageClass.STATIC: env = env.PushEntry(Env.EntryKind.GLOBAL, name, type); break; case StorageClass.TYPEDEF: default: throw new InvalidOperationException("Invalid storage class specifier for function definition."); } env = env.InScope(); env = env.SetCurrentFunction(funcType); var stmt = SemantStmt(this.Stmt.GetStmt, ref env); env = env.OutScope(); return(SemantReturn.Create(env, ImmutableList.Create(Tuple.Create(env, new ABT.FuncDef(name, storageClass, funcType, stmt) as ExternDecln)))); }
public ISemantReturn <ABT.TranslnUnit> GetTranslnUnit() { var env = new Env(); var externDeclns = this.Declns.Aggregate(ImmutableList <Tuple <Env, ExternDecln> > .Empty, (acc, externDecln) => acc.AddRange(Semant(externDecln.GetExternDecln, ref env)) ); return(SemantReturn.Create(env, new ABT.TranslnUnit(externDeclns.ToList()))); }
public override ISemantReturn <ABT.Initr> GetInitr(ABT.Env env) { var initrs = this.Initrs.ConvertAll( initr => Semant(initr.GetInitr, ref env) ); return(SemantReturn.Create(env, new ABT.InitList(initrs.ToList()))); }
public override ISemantReturn <ExprType> GetExprType(Env env) { if (this.Enumrs.IsNone) { // If no enumerators provided: must find enum Type in the current environment. if (this.Name.IsNone) { throw new InvalidProgramException("This should not pass the parser."); } var name = this.Name.Value; var entryOpt = env.Find($"enum {name}"); if (entryOpt.IsNone || entryOpt.Value.Kind != Env.EntryKind.TYPEDEF) { throw new InvalidOperationException($"enum {name} has not been defined."); } return(SemantReturn.Create(env, new LongType())); } // If enumerators are provided: add names to environment Int32 offset = 0; foreach (var enumr in this.Enumrs.Value) { if (enumr.Init.IsSome) { // If the user provides an initialization Value, use it. var init = SemantExpr(enumr.Init.Value, ref env); init = ABT.TypeCast.MakeCast(init, new LongType()); if (!init.IsConstExpr) { throw new InvalidOperationException("Enumerator initialization must have a constant Value."); } offset = ((ConstLong)init).Value; } env = env.PushEnum(enumr.Name, new LongType(), offset); offset++; } // If the user provides a name to the enum, add it to the environment. if (this.Name.IsSome) { var typeName = $"enum {this.Name.Value}"; if (env.FindInCurrentScope(typeName).IsSome) { throw new InvalidOperationException($"{typeName} is already defined."); } env = env.PushEntry(Env.EntryKind.TYPEDEF, typeName, new LongType()); } return(SemantReturn.Create(env, new LongType())); }
public ISemantReturn <ABT.ExprType> DecorateType(ABT.Env env, ABT.ExprType baseType) { var type = this.TypeModifiers .Reverse() // The first Type modifier is nearest to the symbol name, which indicates the outmost Type. .Aggregate( // Wrap up the Type based on the Type modifiers. baseType, (currentType, typeModifier) => Semant(typeModifier.DecorateType, currentType, ref env) ); return(SemantReturn.Create(env, type)); }
public ISemantReturn <ImmutableList <Tuple <Option <String>, ABT.ExprType> > > GetNamesAndTypes(ABT.Env env) { var namesAndTypes = this.ParamDeclns.ConvertAll( paramDecln => Tuple.Create( paramDecln.ParamDeclr.Name, Semant(paramDecln.GetParamType, ref env) ) ); return(SemantReturn.Create(env, namesAndTypes)); }
public ISemantReturn <Tuple <ABT.ExprType, Option <ABT.Initr> > > GetDecoratedTypeAndInitr(ABT.Env env, ABT.ExprType baseType) { // Get the Type based on the declarator. Note that this might be an incomplete array. var type = Semant(this.Declr.DecorateType, baseType, ref env); Option <ABT.Initr> initrOption; if (this.Initr.IsNone) { initrOption = Option <ABT.Initr> .None; } else { // If an initializer is present: var initr = Semant(this.Initr.Value.GetInitr, ref env); // Check that the initializer conforms to the Type. initr = initr.ConformType(type); // If the object is an incomplete array, we must determine the length based on the initializer. if (type.Kind == ABT.ExprTypeKind.INCOMPLETE_ARRAY) { // Now we need to determine the length. // Find the last element in the Init list. var lastOffset = -1; initr.Iterate(type, (offset, _) => { lastOffset = offset; }); if (lastOffset == -1) { throw new InvalidOperationException("Cannot determine the length of the array based on an empty initializer list."); } var elemType = ((ABT.IncompleteArrayType)type).ElemType; var numElems = 1 + lastOffset / ((ABT.IncompleteArrayType)type).ElemType.SizeOf; type = new ABT.ArrayType(elemType, numElems); } initrOption = Option.Some(initr); } // Now everything is created. Check that the Type is complete. if (!type.IsComplete) { throw new InvalidOperationException("Cannot create an object with an incomplete Type."); } return(SemantReturn.Create(env, Tuple.Create(type, initrOption))); }
public override ISemantReturn <ABT.ExprType> DecorateType(ABT.Env env, ABT.ExprType returnType) { if (this.ParamTypeList.IsNone) { return(SemantReturn.Create(env, ABT.FunctionType.Create(returnType))); } var paramTypeList = this.ParamTypeList.Value; var namesAndTypes = Semant(paramTypeList.GetNamesAndTypes, ref env); var hasVarArgs = paramTypeList.HasVarArgs; return(SemantReturn.Create(env, ABT.FunctionType.Create(returnType, namesAndTypes, hasVarArgs))); }
public ISemantReturn <ImmutableList <Tuple <Env, ABT.Decln> > > GetDeclns(Env env) { var storageClass = this.DeclnSpecs.GetStorageClass(); var baseType = Semant(this.DeclnSpecs.GetExprType, ref env); var declns = this.InitDeclrs.ConvertAll( initDeclr => { var typeAndInitr = Semant(initDeclr.GetDecoratedTypeAndInitr, baseType, ref env); var type = typeAndInitr.Item1; var initr = typeAndInitr.Item2; var name = initDeclr.GetName(); // Add the new symbol into the environment. Env.EntryKind kind; switch (storageClass) { case StorageClass.AUTO: if (env.IsGlobal()) { kind = Env.EntryKind.GLOBAL; } else { kind = Env.EntryKind.STACK; } break; case StorageClass.EXTERN: kind = Env.EntryKind.GLOBAL; break; case StorageClass.STATIC: kind = Env.EntryKind.GLOBAL; break; case StorageClass.TYPEDEF: kind = Env.EntryKind.TYPEDEF; break; default: throw new InvalidOperationException(); } env = env.PushEntry(kind, name, type); return(Tuple.Create(env, new ABT.Decln(name, storageClass, type, initr))); } ); return(SemantReturn.Create(env, declns)); }
public override ISemantReturn <ExprType> GetExprType(Env env) { var entryOpt = env.Find(this.Name); if (entryOpt.IsNone) { throw new InvalidProgramException("This should not pass the parser."); } var entry = entryOpt.Value; if (entry.Kind != Env.EntryKind.TYPEDEF) { throw new InvalidProgramException("This should not pass the parser."); } return(SemantReturn.Create(env, entry.Type)); }
public ISemantReturn <ExprType> GetExprType(Env env) { Boolean isConst = this.TypeQuals.Contains(TypeQual.CONST); Boolean isVolatile = this.TypeQuals.Contains(TypeQual.VOLATILE); // If no Type specifier is given, assume long Type. if (this.TypeSpecs.IsEmpty) { return(SemantReturn.Create(env, new LongType(isConst, isVolatile))); } // If every Type specifier is basic, go to the lookup table. if (this.TypeSpecs.All(typeSpec => typeSpec.Kind != TypeSpecKind.NON_BASIC)) { var basicTypeSpecKinds = this.TypeSpecs .ConvertAll(typeSpec => typeSpec.Kind) .Distinct() .ToImmutableSortedSet(); foreach (var pair in BasicTypeSpecLookupTable) { if (pair.Key.SetEquals(basicTypeSpecKinds)) { return(SemantReturn.Create(env, pair.Value)); } } throw new InvalidOperationException("Invalid Type specifier set."); } // If there is a non-basic Type specifier, semant it. if (this.TypeSpecs.Count != 1) { throw new InvalidOperationException("Invalid Type specifier set."); } var type = Semant(this.TypeSpecs[0].GetExprType, ref env); return(SemantReturn.Create(env, type.GetQualifiedType(isConst, isVolatile))); }
public ISemantReturn <ImmutableList <Tuple <Option <String>, ExprType> > > GetMemberDeclns(Env env) { // Semant specifier-qualifier-list. var baseType = Semant(this.SpecQualList.GetExprType, ref env); // Decorate types, based on struct declarators. var memberTypes = this.StructDeclrs .ConvertAll( structDeclr => Semant(structDeclr.DecorateType, baseType, ref env) ); // Get (optional) member names. var memberNames = this.StructDeclrs .ConvertAll( structDeclr => structDeclr.Name ); return(SemantReturn.Create(env, memberNames.Zip(memberTypes, Tuple.Create).ToImmutableList())); }
public override ISemantReturn <ABT.ExprType> DecorateType(ABT.Env env, ABT.ExprType elemType) { if (this.NumElems.IsNone) { return(SemantReturn.Create(env, new ABT.IncompleteArrayType(elemType))); } // Get number of elements. // Be careful: the environment might change. var numElems = SemantExpr(this.NumElems.Value, ref env); // Try to cast number of elements to a integer. // TODO: allow float??? numElems = ABT.TypeCast.MakeCast(numElems, new ABT.LongType(true, false)); if (!numElems.IsConstExpr) { throw new InvalidOperationException("Number of elements of an array must be constant."); } return(SemantReturn.Create(env, new ABT.ArrayType(elemType, ((ABT.ConstLong)numElems).Value))); }
public override ISemantReturn <ABT.Initr> GetInitr(ABT.Env env) { var expr = SemantExpr(this.Expr, ref env); return(SemantReturn.Create(env, new ABT.InitExpr(expr))); }
public override ISemantReturn <ExprType> GetExprType(Env env) { StructOrUnionType type; // If no members provided, then we need to find the Type in the current environment. if (this.MemberDeclns.IsNone) { if (this.Name.IsNone) { throw new InvalidProgramException("This should not pass the parser"); } var name = this.Name.Value; var typeName = (this.StructOrUnion == StructOrUnion.STRUCT ? "struct" : "union") + $" {name}"; // Try to find Type name in the current environment. var entryOpt = env.Find(typeName); // If name not found: create an incomplete Type and add it into the environment. if (entryOpt.IsNone) { type = StructOrUnionType.CreateIncompleteType(this.StructOrUnion, name); env = env.PushEntry(Env.EntryKind.TYPEDEF, typeName, type); return(SemantReturn.Create(env, type)); } // If name found: fetch it. if (entryOpt.Value.Kind != Env.EntryKind.TYPEDEF) { throw new InvalidProgramException("A struct or union in env that is not typedef? This should not appear."); } return(SemantReturn.Create(env, entryOpt.Value.Type)); } // If members are provided, the user is trying to define a new struct/union. if (this.Name.IsSome) { var name = this.Name.Value; var typeName = (this.StructOrUnion == StructOrUnion.STRUCT ? "struct" : "union") + $" {name}"; // Try to find Type name in the current environment. // Notice we need to search the current **scope** only. var entryOpt = env.FindInCurrentScope(typeName); // If name not found: create an incomplete Type and add it into the environment. if (entryOpt.IsNone) { type = StructOrUnionType.CreateIncompleteType(this.StructOrUnion, name); env = env.PushEntry(Env.EntryKind.TYPEDEF, typeName, type); } else { if (entryOpt.Value.Kind != Env.EntryKind.TYPEDEF) { throw new InvalidProgramException( "A struct or union in env that is not typedef? This should not appear."); } type = entryOpt.Value.Type as StructOrUnionType; if (type == null) { throw new InvalidProgramException( $"{typeName} is not a struct or union? This should not appear."); } } // Current Type mustn't be already complete. if (type.IsComplete) { throw new InvalidOperationException($"Redifinition of {typeName}"); } } else { var typeName = (this.StructOrUnion == StructOrUnion.STRUCT ? "struct" : "union") + " <unnamed>"; type = StructOrUnionType.CreateIncompleteType(this.StructOrUnion, typeName); } var members = Semant(GetMembers, this.MemberDeclns.Value, ref env); type.Define(this.StructOrUnion, members); return(SemantReturn.Create(env, type)); }