public override AST.Node ToAST(Env env) { /// A return statement with an expression shall not appear in a function whose return type is void. /// A return statement without an expression shall only appear in a function whose return type is void. TFunc f = env.GetFuncType(); string returnLabel = env.GetReturnLabel(); if (expr != null) { if (f.ret.IsVoid) { throw new Error(Pos, "a return statement with an expression shall not appear a function whose return type is void"); } AST.Expr e = expr.ToASTExpr(env).ValueTransform(); if (!Assign.SimpleAssignable(f.ret, e)) { throw new ETypeError(Pos, string.Format("cannot assign {0} to {1}", e.Type, f.ret)); } return(new AST.Return(returnLabel, e.ImplicitConvert(f.ret))); } else { if (!f.ret.IsVoid) { throw new Error(Pos, "a return statement without an expression shall only appear in a function whose return type is void"); } return(new AST.Return(returnLabel, null)); } }
public override AST.Node ToAST(Env env) { T baseType = specifiers.GetT(env); var result = declarator.Declare(env, baseType); if (declarations != null) { throw new Error(Pos, "sorry we donot support old-style function definition"); } /// The identifier declared in a function definition (which is the name of the function) shall /// have a function type if (!result.Item2.IsFunc) { throw new ETypeError(Pos, "function definition should have function type"); } /// The storage-class specifier, if any, shall be either extern or static. if (specifiers.storage != StoreSpec.Kind.EXTERN && specifiers.storage != StoreSpec.Kind.NONE && specifiers.storage != StoreSpec.Kind.STATIC) { throw new Error(Pos, string.Format("illegal storage specifier {0} in function definition", specifiers.storage)); } /// Determine the linkage. var link = specifiers.storage == StoreSpec.Kind.STATIC ? SymbolEntry.Link.INTERNAL : SymbolEntry.Link.EXTERNAL; var entry = env.GetSymbol(result.Item1); if (entry == null) { /// This identifier has not been used. env.AddFunc(result.Item1, result.Item2, link, Pos); } else { /// This identifier has been declared. /// Check if it's a function type. if (!entry.type.Equals(result.Item2)) { throw new ERedefineSymbolTypeConflict(Pos, result.Item1, entry.type, result.Item2); } /// Check if the function has already been defined. if (entry.type.IsDefined) { throw new ERedefineFunction(Pos, result.Item1); } /// Define the function. entry.type.DefFunc(); } TFunc type = result.Item2.nake as TFunc; /// Push a new scope. env.PushFuncScope(result.Item1, type, result.Item3, Pos); /// Semantic check the function body. AST.CompoundStmt b = body.ToASTCompoundStmt(env); string returnLabel = env.GetReturnLabel(); env.PopScope(); return(new AST.FuncDef( result.Item1, returnLabel, type, result.Item3, b, env.ASTEnv, specifiers.storage != StoreSpec.Kind.STATIC )); }