public Tuple<AST.Env, AST.ExprType> GetExprTypeEnv(Boolean is_struct, AST.Env env, Boolean is_const, Boolean is_volatile) { if (name == "") { // If no name is supplied: must be complete. // struct { ... } or union { ... } if (declns == null) { throw new ArgumentNullException("Error: parser should ensure declns != null"); } Tuple<AST.Env, List<Tuple<String, AST.ExprType>>> r_attribs = GetAttribs(env); env = r_attribs.Item1; if (is_struct) { return new Tuple<AST.Env, AST.ExprType>(env, AST.TStructOrUnion.CreateStruct("<anonymous>", r_attribs.Item2, is_const, is_volatile)); } else { return new Tuple<AST.Env, AST.ExprType>(env, AST.TStructOrUnion.CreateUnion("<anonymous>", r_attribs.Item2, is_const, is_volatile)); } } else { // If a name is supplied, split into 2 cases. String typename = is_struct ? $"struct {name}" : $"union {name}"; if (declns == null) { // Case 1: If no attribute list supplied, then we are either // 1) mentioning an already-existed struct/union // or 2) creating an incomplete struct/union Option<AST.Env.Entry> entry_opt = env.Find(typename); if (entry_opt.IsNone) { // If the struct/union is not in the current environment, // then add an incomplete struct/union into the environment AST.ExprType type = is_struct ? AST.TStructOrUnion.CreateIncompleteStruct(name, is_const, is_volatile) : AST.TStructOrUnion.CreateIncompleteUnion(name, is_const, is_volatile); env = env.PushEntry(AST.Env.EntryKind.TYPEDEF, typename, type); return Tuple.Create(env, type); } if (entry_opt.Value.kind != AST.Env.EntryKind.TYPEDEF) { throw new InvalidProgramException(typename + " is not a type? This should be my fault."); } // If the struct/union is found, return it. return Tuple.Create(env, entry_opt.Value.type); } else { // Case 2: If an attribute list is supplied. // 1) Make sure there is no complete struct/union in the current environment. Option<AST.Env.Entry> entry_opt = env.Find(typename); if (entry_opt.IsSome && entry_opt.Value.type.kind == AST.ExprType.Kind.STRUCT_OR_UNION && ((AST.TStructOrUnion)entry_opt.Value.type).IsComplete) { throw new InvalidOperationException($"Redefining {typename}"); } // 2) Add an incomplete struct/union into the environment. AST.TStructOrUnion type = is_struct ? AST.TStructOrUnion.CreateIncompleteStruct(name, is_const, is_volatile) : AST.TStructOrUnion.CreateIncompleteUnion(name, is_const, is_volatile); env = env.PushEntry(AST.Env.EntryKind.TYPEDEF, typename, type); // 3) Iterate over the attributes. Tuple<AST.Env, List<Tuple<String, AST.ExprType>>> r_attribs = GetAttribs(env); env = r_attribs.Item1; // 4) Make the type complete. This would also change the entry inside env. if (is_struct) { type.DefineStruct(r_attribs.Item2); } else { type.DefineUnion(r_attribs.Item2); } return new Tuple<AST.Env, AST.ExprType>(env, type); } } }
public override Tuple<AST.Env, AST.ExprType> GetExprTypeEnv(AST.Env env, Boolean is_const, Boolean is_volatile) { if (enums == null) { // if there is no content in this enum type, we must find it's definition in the environment Option<AST.Env.Entry> entry_opt = env.Find($"enum {name}"); if (entry_opt.IsNone || entry_opt.Value.kind != AST.Env.EntryKind.TYPEDEF) { throw new InvalidOperationException($"Type 'enum {name}' has not been defined."); } } else { // so there are something in this enum type, we need to put this type into the environment Int32 idx = 0; foreach (Enumerator elem in enums) { Tuple<AST.Env, String, Int32> r_enum = elem.GetEnumerator(env, idx); env = r_enum.Item1; String name = r_enum.Item2; idx = r_enum.Item3; env = env.PushEnum(name, new AST.TLong(), idx); idx++; } env = env.PushEntry(AST.Env.EntryKind.TYPEDEF, "enum " + name, new AST.TLong()); } return new Tuple<AST.Env, AST.ExprType>(env, new AST.TLong(is_const, is_volatile)); }
public override AST.Expr GetExpr(AST.Env env) { Option<AST.Env.Entry> entry_opt = env.Find(name); if (entry_opt.IsNone) { throw new InvalidOperationException($"Cannot find variable '{name}'"); } AST.Env.Entry entry = entry_opt.Value; switch (entry.kind) { case AST.Env.EntryKind.TYPEDEF: throw new InvalidOperationException($"Expected a variable '{name}', not a typedef."); case AST.Env.EntryKind.ENUM: return new AST.ConstLong(entry.offset, env); case AST.Env.EntryKind.FRAME: case AST.Env.EntryKind.GLOBAL: case AST.Env.EntryKind.STACK: return new AST.Variable(entry.type, name, env); default: throw new InvalidOperationException($"Cannot find variable '{name}'"); } }
public override Tuple<AST.Env, AST.ExprType> GetExprTypeEnv(AST.Env env, Boolean is_const, Boolean is_volatile) { Option<AST.Env.Entry> entry_opt = env.Find(name); if (entry_opt.IsNone) { throw new InvalidOperationException($"Cannot find name \"{name}\"."); } AST.Env.Entry entry = entry_opt.Value; if (entry.kind != AST.Env.EntryKind.TYPEDEF) { throw new InvalidOperationException($"\"{name}\" is not a typedef."); } return Tuple.Create(env, entry.type.GetQualifiedType(is_const, is_volatile)); }
public override AST.Expr GetExpr(AST.Env env) { // Step 1: get arguments passed into the function. // Note that currently the arguments are not casted based on the prototype. var args = this.args.Select(_ => _.GetExpr(env)).ToList(); // A special case: // If we cannot find the function prototype in the environment, make one up. // This function returns int. // Update the environment to add this function type. if ((this.func is Variable) && env.Find((this.func as Variable).name).IsNone) { // TODO: get this env used. env = env.PushEntry( loc: AST.Env.EntryKind.TYPEDEF, name: (this.func as Variable).name, type: AST.TFunction.Create( ret_type: new AST.TLong(is_const: true), args: args.ConvertAll(_ => Tuple.Create("", _.type)), is_varargs: false ) ); } // Step 2: get function expression. AST.Expr func = this.func.GetExpr(env); // Step 3: get the function type. AST.TFunction func_type; switch (func.type.kind) { case AST.ExprType.Kind.FUNCTION: func_type = func.type as AST.TFunction; break; case AST.ExprType.Kind.POINTER: var ref_t = (func.type as AST.TPointer).ref_t; if (!(ref_t is AST.TFunction)) { throw new InvalidOperationException("Expected a function pointer."); } func_type = ref_t as AST.TFunction; break; default: throw new InvalidOperationException("Expected a function in function call."); } Int32 num_args_prototype = func_type.args.Count; Int32 num_args_actual = args.Count; // If this function doesn't take varargs, make sure the number of arguments match that in the prototype. if (!func_type.is_varargs && num_args_actual != num_args_prototype) { throw new InvalidOperationException("Number of arguments mismatch."); } // Anyway, you can't call a function with fewer arguments than the prototype. if (num_args_actual < num_args_prototype) { throw new InvalidOperationException("Too few arguments."); } // Make implicit cast. args = Enumerable.Zip( args.GetRange(0, num_args_prototype), func_type.args, (arg, entry) => AST.TypeCast.MakeCast(arg, entry.type) ).Concat(args.GetRange(num_args_prototype, num_args_actual - num_args_prototype)).ToList(); return new AST.FuncCall(func, func_type, args); }