示例#1
0
        // 可能不需要?编译时就确定?
        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);
        }
示例#2
0
        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();
        }