Exemple #1
0
        public static dynamic EvaluateConstExpr(Node expr, SymTable symTable)
        {
            try
            {
                switch (expr)
                {
                case ConstNode _:
                    return(expr.Value);

                case CastOperator _:
                    return(EvaluateConstExpr(expr.Childs[0], symTable));

                case DesignatorNode _:
                    var temp = symTable.LookUp(expr.Value.ToString());
                    if (temp is ConstSymbol)
                    {
                        return(((SimpleConstant)(temp as ConstSymbol).Value).Value);
                    }
                    throw new EvaluatorException("Illegal operation");

                case BinOpNode _:
                    return(BinaryOps[(Tokenizer.TokenSubType)expr.Value](EvaluateConstExpr(expr.Childs[0], symTable),
                                                                         EvaluateConstExpr(expr.Childs[1], symTable)));

                case UnOpNode _:
                    return(UnaryOps[(Tokenizer.TokenSubType)expr.Value](EvaluateConstExpr(expr.Childs[0], symTable)));
                }
            }
            catch (RuntimeBinderException)
            {
                throw new ParserException("Invalid operation in constant expression", expr.Line, expr.Position);
            }
            throw new InvalidOperationException($"Node of type {expr.GetType()} met in expression");
        }
        private Parameters ParseValueParameter(SymTable symTable)
        {
            List <string> idents = new List <string>();

            while (Current.SubType == Identifier)
            {
                idents.Add(Current.Value.ToString());
                Next();
                if (Current.SubType != Comma)
                {
                    break;
                }
                Next();
            }
            Require(Colon);
            var t = Current;

            Require(Identifier);
            var tp = symTable.LookUp(t.Value.ToString());

            if (!(tp is TypeSymbol))
            {
                throw new ParserException("Illegal type declaration", t.Line, t.Position);
            }
            if (Current.SubType == Equal)
            {
                if (idents.Count != 1)
                {
                    throw new ParserException("Only one parameter can have default value", Current.Line,
                                              Current.Position);
                }
                Require(Equal);
                var v = ParseConstExpr(symTable);
                var s = new ParameterSymbol
                {
                    Name = idents[0],
                    ParameterModifier = ParameterModifier.Value,
                    Type  = (TypeSymbol)tp,
                    Value = v
                };
                symTable.Add(idents[0], s);
                return(new Parameters {
                    s
                });
            }
            var p = new Parameters();

            foreach (var i in idents)
            {
                var s = new ParameterSymbol
                {
                    Name = i,
                    ParameterModifier = ParameterModifier.Value,
                    Type = (TypeSymbol)tp,
                };
                p.Add(s);
                symTable.Add(i, s);
            }
            return(p);
        }
        public override void Generate(AsmCode asmCode, SymTable symTable)
        {
            long id = asmCode.CurrentID++;

            StartLabel = new AsmLabel($"Cycle{id}Start");
            EndLabel   = new AsmLabel($"Cycle{id}End");
            AsmLabel bodyLabel = new AsmLabel($"Cycle{id}Body");
            var      v         = (VarSymbol)symTable.LookUp(Childs[0].Value.ToString());

            Childs[1].Generate(asmCode, symTable);                    // Initial value
            ((IdentNode)Childs[0]).GenerateLValue(asmCode, symTable); // Cycle counter
            asmCode.Add(AsmCmd.Cmd.Pop, AsmReg.Reg.Eax);
            asmCode.Add(AsmCmd.Cmd.Pop, AsmReg.Reg.Ebx);

            asmCode.Add(AsmCmd.Cmd.Sub, AsmReg.Reg.Ebx, 1);

            asmCode.Add(
                AsmCmd.Cmd.Mov,
                new AsmOffset(0, v.Type.Size, AsmReg.Reg.Eax),
                AsmReg.Reg.Ebx);
            // Value initialized
            asmCode.Add(AsmCmd.Cmd.Jmp, StartLabel);
            asmCode.Add(bodyLabel);
            asmCode.LoopStack.Push(this);
            Childs[3].Generate(asmCode, symTable); // Cycle body
            asmCode.LoopStack.Pop();

            asmCode.Add(StartLabel);

            ((IdentNode)Childs[0]).GenerateLValue(asmCode, symTable);
            asmCode.Add(AsmCmd.Cmd.Pop, AsmReg.Reg.Eax);
            asmCode.Add(AsmCmd.Cmd.Inc, new AsmOffset(0, v.Type.Size, AsmReg.Reg.Eax));


            Childs[2].Generate(asmCode, symTable); // Cycle counter target

            ((IdentNode)Childs[0]).GenerateLValue(asmCode, symTable);
            asmCode.Add(AsmCmd.Cmd.Pop, AsmReg.Reg.Eax);

            asmCode.Add(
                AsmCmd.Cmd.Mov,
                AsmReg.Reg.Eax,
                new AsmOffset(0, v.Type.Size, AsmReg.Reg.Eax));
            asmCode.Add(AsmCmd.Cmd.Pop, AsmReg.Reg.Ebx);
            asmCode.Add(AsmCmd.Cmd.Cmp, AsmReg.Reg.Eax, AsmReg.Reg.Ebx);
            asmCode.Add(AsmCmd.Cmd.Jle, bodyLabel);
            asmCode.Add(EndLabel);
        }
        private DesignatorNode ParseDesignator(SymTable symTable)
        {
            var c = Current;

            Require(Identifier);
            var t = symTable.LookUp(c.Value.ToString());

            switch (t)
            {
            case TypeSymbol ts:
                return(ParseCast(symTable, new IdentNode(null, c)
                {
                    Type = ts
                }));

            case ProcedureSymbol ps:
                return(ParseProcedureCall(symTable, new IdentNode(null, c)
                {
                    Type = ps
                }));

            case FunctionSymbol fs:
                return(ParseFunctionCall(symTable, new IdentNode(null, c)
                {
                    Type = fs
                }));

            case ValueSymbol vs:
                DesignatorNode v = new IdentNode(null, c)
                {
                    Type = vs.Type
                };
                switch (vs.Type)
                {
                case RecordTypeSymbol _:
                    return(ParseMemberAccess(symTable, v));

                case ArrayTypeSymbol _:
                    return(ParseIndex(symTable, v));
                }
                return(v);

            default:
                throw new ParserException("Illegal identifier", c.Line, c.Position);
            }
        }
        private PascalProgram ParseProgram()
        {
            var    c    = Current;
            string name = "";

            if (c.SubType == Tokenizer.TokenSubType.Program)
            {
                Next();
                var n = Current;
                Require(Identifier);
                name = n.Value.ToString();
                Require(Semicolon);
            }
            SymTable st = new SymTable
            {
                { TypeSymbol.IntTypeSymbol.Name, TypeSymbol.IntTypeSymbol },
                { TypeSymbol.RealTypeSymbol.Name, TypeSymbol.RealTypeSymbol },
                { TypeSymbol.CharTypeSymbol.Name, TypeSymbol.CharTypeSymbol }
            };

            if (st.LookUp(name) != null)
            {
                throw new ParserException("Illegal program name", c.Line, c.Position);
            }
            ProgramSymbol pn;

            if (name != "")
            {
                pn = new ProgramSymbol {
                    Name = name
                };
                st.Add(name, pn);
            }
            else
            {
                pn = new ProgramSymbol {
                    Name = ""
                };
            }
            var b = ParseBlock(st);

            Require(Dot);
            return(new PascalProgram {
                Block = b, Name = pn
            });
        }
        private Parameters ParseVarParameter(SymTable symTable)
        {
            Require(Var);
            List <string> idents = new List <string>();

            while (Current.SubType == Identifier)
            {
                idents.Add(Current.Value.ToString());
                Next();
                if (Current.SubType != Comma)
                {
                    break;
                }
                Next();
            }
            if (idents.Count == 0)
            {
                throw new ParserException("Empty parameter list", Current.Line, Current.Position);
            }
            Require(Colon);
            var t = Current;

            Require(Identifier);
            var tp = symTable.LookUp(t.Value.ToString());

            if (!(tp is TypeSymbol))
            {
                throw new ParserException("Illegal type declaration", t.Line, t.Position);
            }
            var p = new Parameters();

            foreach (var i in idents)
            {
                var s = new ParameterSymbol
                {
                    Name = i,
                    ParameterModifier = ParameterModifier.Var,
                    Type = (TypeSymbol)tp
                };
                p.Add(s);
                symTable.Add(i, s);
            }
            return(p);
        }
        private TypeSymbol ParseType(SymTable symTable)
        {
            var c = Current;

            switch (c.SubType)
            {
            case Identifier:
                Next();
                var t = symTable.LookUp(c.Value.ToString());
                if (!(t is TypeSymbol))
                {
                    throw new ParserException("Error in type definition", c.Line, c.Position);
                }
                return((TypeSymbol)t);

            case Tokenizer.TokenSubType.Array:
                return(ParseArrayType(symTable));

            case Record:
                return(ParseRecordType(symTable));
            }
            throw new ParserException($"Expected type, found '{c.SubType}'", c.Line, c.Position);
        }
        private ExpressionNode ParseFactor(SymTable symTable)
        {
            var c = Current;

            switch (c.SubType)
            {
            case Identifier:
                Next();
                var t = symTable.LookUp(c.Value.ToString());
                switch (t)
                {
                case TypeSymbol ts:
                    return(ParseCast(symTable, new IdentNode(null, c)
                    {
                        Type = ts
                    }));

                case FunctionSymbol fs:
                    return(ParseFunctionCall(symTable, new IdentNode(null, c)
                    {
                        Type = fs
                    }));

                case ValueSymbol vs:
                    DesignatorNode v = new IdentNode(null, c)
                    {
                        Type = vs.Type
                    };
                    switch (vs.Type)
                    {
                    case RecordTypeSymbol _:
                        return(ParseMemberAccess(symTable, v));

                    case ArrayTypeSymbol _:
                        return(ParseIndex(symTable, v));
                    }
                    return(v);

                default:
                    throw new ParserException("Illegal identifier", c.Line, c.Position);
                }

            case IntegerConstant:
                Next();
                return(new ConstNode(null, c.Value, c.Line, c.Position)
                {
                    Type = TypeSymbol.IntTypeSymbol
                });

            case FloatConstant:
                Next();
                return(new ConstNode(null, c.Value, c.Line, c.Position)
                {
                    Type = TypeSymbol.RealTypeSymbol
                });

            case LParenthesis:
                Next();
                var e = ParseExpression(symTable);
                Require(RParenthesis);
                return(e);

            case Plus:
            case Minus:
            {
                Next();
                var tmp = ParseFactor(symTable);
                return(new UnOpNode(new List <Node> {
                        tmp
                    }, c.SubType, c.Line, c.Position)
                    {
                        Type = tmp.Type
                    });
            }

            case Not:
            {
                Next();
                var tmp = ParseFactor(symTable);
                if (tmp.Type == TypeSymbol.IntTypeSymbol)
                {
                    return(new UnOpNode(new List <Node> {
                            tmp
                        }, c.SubType, c.Line, c.Position)
                        {
                            Type = tmp.Type
                        });
                }
                throw new ParserException("Illegal operation", c.Line, c.Position);
            }
            }
            throw new ParserException($"Unexpected token {c.SubType}", c.Line, c.Position);
        }