// 可能不需要?编译时就确定? private void BuildGlobalVarsInitFunction() { var globalVars = m_Tree.Root.OfType <VariableDeclarationStmt>(); var body = new BlockStmt() { Statements = new List <Statement>() }; var func = new FunctionStmt() { Declaration = new FunctionDeclarationStmt { Name = "$init", Signature = new FunctionSignature { Arguments = new List <Argument>(), Return = "void" } }, Body = body }; foreach (var g in globalVars) { body.Statements.Add(new ExpressionStmt { Expression = new Op2Expr { Operator = Op2Expr.Type.Assign, Left = new VariableValueExpr { Name = g.Name }, Right = g.Assignment } }); g.Assignment = null; } m_Tree.Root.Add(func); }
private void VisitStmt(Statement stmt, bool root = false) { if (stmt == null) { return; } m_StmtStack.Push(stmt); Assert(!root || m_CanBeRoot.Contains(stmt.GetType()), $"Only function and variable declaration can be a root statement."); Assert(root || !m_MustBeRoot.Contains(stmt.GetType()), $"Function defination must be a root statement."); switch (stmt) { case FunctionDeclarationStmt fd: { VisitFunctionDeclaration(fd, false); break; } case FunctionStmt f: { Assert(root, "Functions can only be the root statements."); f.Symbol = VisitFunctionDeclaration(f.Declaration, true); f.ScopeSymbols = f.Body.ScopeSymbols = new SymbolTable(); // function body has the same scope with arguments foreach (var arg in f.Declaration.Signature.Arguments) { if (string.IsNullOrEmpty(arg.Name)) { continue; } var argSym = new VariableSymbol { Name = arg.Name, Type = arg.Type }; Assert(f.ScopeSymbols.TryAdd(argSym), $"Argument name '{arg.Name}' duplicated."); arg.Symbol = argSym; } VisitStmt(f.Body); break; } case BlockStmt block: { block.ScopeSymbols = block.ScopeSymbols ?? new SymbolTable(); // initialize a symbol table if not explicitly specified foreach (var childStmt in block.Statements) { VisitStmt(childStmt); } break; } case VariableDeclarationStmt vd: { LinkTypeSymbol(vd.Type); Assert(vd.Type != "void", $"'void' can't be used as a type."); var sym = new VariableSymbol { Name = vd.Name, Type = vd.Type, IsGlobal = root }; Assert(GetNearestSymbolTable().TryAdd(sym), $"Variable name '{vd.Name}' duplicated with another symbol under the same scope."); vd.Symbol = sym; VisitExpr(vd.Assignment); if (vd.Assignment != null) { vd.Assignment = EliminateImplicitConv(vd.Assignment, vd.Type.Symbol); } break; } case IfStmt i: { VisitExpr(i.Condition); i.Condition = EliminateImplicitConv(i.Condition, FindSymbol(CPrimitiveType.Int)); i.True.ScopeSymbols = new SymbolTable(); VisitStmt(i.True); if (i.False != null) { i.False.ScopeSymbols = new SymbolTable(); } VisitStmt(i.False); break; } case ReturnStmt ret: { VisitExpr(ret.Value); FunctionStmt func = null; foreach (var ss in m_StmtStack.Reverse()) { if (ss is FunctionStmt) { func = (FunctionStmt)ss; break; } } Assert(func.Declaration.Signature.Return != "void" || ret.Value == null, "This function does not return a value."); Assert(ret.Value != null, "This function needs to return a value."); ret.Value = EliminateImplicitConv(ret.Value, func.Declaration.Signature.Return.Symbol); break; } case WhileStmt wh: { VisitExpr(wh.Condition); wh.Condition = EliminateImplicitConv(wh.Condition, FindSymbol(CPrimitiveType.Int)); wh.Body.ScopeSymbols = new SymbolTable(); VisitStmt(wh.Body); break; } case BreakStmt brk: { foreach (var st in m_StmtStack) { if (st is WhileStmt) { brk.Host = st; break; } } if (brk.Host == null) { SemanticsError("A 'break' statement may only be used within a 'while' statement."); } break; } case ExpressionStmt exprStmt: { switch (exprStmt.Expression) { case Op2Expr op2 when op2.Operator == Op2Expr.Type.Assign: case FunctionCallExpr funcCall: break; default: SemanticsError("Only assignment and function call expression can be a statement."); break; } VisitExpr(exprStmt.Expression); break; } default: { throw new ArgumentException("Unrecognizable statement type."); } } m_StmtStack.Pop(); }