public override void Generate(AsmCode asmCode, SymTable symTable) { int stackSize = 4; if (Childs[0] is ExpressionListNode el) { foreach (var node in el.Childs.AsEnumerable().Reverse()) { var child = (ExpressionNode)node; child.Generate(asmCode, symTable); stackSize += ((TypeSymbol)child.Type).Size; } string fmt = string.Join( " ", el.Childs.Cast <ExpressionNode>(). Select(i => _fmtDictionary[(TypeSymbol)i.Type])); string val = $"__@string{asmCode.CurrentID++}"; if (!asmCode.ConstDictionary.ContainsKey(fmt)) { asmCode.ConstDictionary[fmt] = val; } asmCode.Add(AsmCmd.Cmd.Push, $"offset {asmCode.ConstDictionary[fmt]}"); } else if (Childs[0] is StringNode sn) { sn.GenerateLValue(asmCode, symTable); } // asmCode.Add(AsmCmd.Cmd.And, AsmReg.Reg.Esp, -4); asmCode.Add(AsmCmd.Cmd.Call, "crt_printf"); asmCode.Add(AsmCmd.Cmd.Add, AsmReg.Reg.Esp, stackSize); }
public override void GenerateLValue(AsmCode asmCode, SymTable symTable) { var t = symTable.LookUpLevel(Value.ToString()); VarSymbol v = (VarSymbol)t?.Item1; int level = t.Value.Item2; asmCode.Add(AsmCmd.Cmd.Mov, AsmReg.Reg.Eax, AsmReg.Reg.Ebp); while (level-- > 0) { asmCode.Add( AsmCmd.Cmd.Mov, AsmReg.Reg.Eax, new AsmOffset(-8, 4, AsmReg.Reg.Eax)); } asmCode.Add( AsmCmd.Cmd.Lea, AsmReg.Reg.Eax, new AsmOffset(v.Offset, 0, AsmReg.Reg.Eax)); if (v is ParameterSymbol ps && ps.ParameterModifier != ParameterModifier.Value) { asmCode.Add( AsmCmd.Cmd.Mov, AsmReg.Reg.Eax, new AsmOffset(0, 4, AsmReg.Reg.Eax)); } asmCode.Add(AsmCmd.Cmd.Push, AsmReg.Reg.Eax); }
private static List <Statement> OptimizeStatements( List <Statement> statements, SymTable symTable) { return(OptimizeStatements(statements.Cast <Node>().ToList(), symTable). Cast <Statement>(). ToList()); }
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); }
private DesignatorNode ParseMemberAccess(SymTable symTable, DesignatorNode record) { while (true) { if (Current.SubType != Dot) { return(record); } Next(); var rt = (RecordTypeSymbol)record.Type; var c = Current; Require(Identifier); if (!rt.Fields.Contains(c.Value.ToString())) { throw new ParserException("Illegal identifier", c.Line, c.Position); } var f = new MemberAccessOperator(new List <Node> { record, new IdentNode(null, c) }, "Member access", c.Line, c.Position) { Type = ((VarSymbol)rt.Fields[c.Value.ToString()]).Type }; switch (f.Type) { case RecordTypeSymbol _: record = f; continue; case ArrayTypeSymbol _: return(ParseIndex(symTable, f)); } return(f); } }
private ArrayConstant ParseArrayConstant(SymTable symTable, ArrayTypeSymbol arrayType) { Require(LParenthesis); List <Constant> arrayElem = new List <Constant> { ParseTypedConstant(symTable, arrayType.ElementType) }; while (Current.SubType != RParenthesis) { Require(Comma); arrayElem.Add(ParseTypedConstant(symTable, arrayType.ElementType)); } foreach (var el in arrayElem) { CheckImplicitTypeCompatibility(el.Type, arrayType.ElementType); } if (arrayType.Length != arrayElem.Count) { throw new ParserException("Invalid array length", Current.Line, Current.Position); } Require(RParenthesis); return(new ArrayConstant { Elements = arrayElem, Type = arrayType }); }
private SimpleConstant ParseConstExpr(SymTable symTable) { var e = ParseExpression(symTable); try { var t = EvaluateConstExpr(e, symTable); TypeSymbol type; switch (t) { case int _: type = TypeSymbol.IntTypeSymbol; break; case double _: type = TypeSymbol.RealTypeSymbol; break; case char _: type = TypeSymbol.CharTypeSymbol; break; default: throw new InvalidOperationException("Const type is invalid"); } return(new SimpleConstant { Value = t, Type = type }); } catch (EvaluatorException ex) { throw new ParserException(ex.Message, Current.Line, Current.Position); } }
private RecordConstant ParseRecordConstant(SymTable symTable, RecordTypeSymbol recordType) { Require(LParenthesis); Dictionary <VarSymbol, Constant> recordElem = new Dictionary <VarSymbol, Constant>(); for (var index = 0; Current.SubType == Identifier && index < recordType.Fields.Count; ++index) { var i = Current; if (((VarSymbol)recordType.Fields[index]).Name != i.Value.ToString()) { throw new ParserException("Invalid identifier", Current.Line, Current.Position); } Next(); Require(Colon); var v = ParseTypedConstant(symTable, ((VarSymbol)recordType.Fields[index]).Type); CheckImplicitTypeCompatibility(v.Type, ((VarSymbol)recordType.Fields[index]).Type); recordElem.Add((VarSymbol)recordType.Fields[index], v); if (Current.SubType == RParenthesis) { break; } Require(Semicolon); } Require(RParenthesis); return(new RecordConstant { Type = recordType, Values = recordElem }); }
public override void Generate(AsmCode asmCode, SymTable symTable) { if (asmCode.SubprogramStack.Count == 0) { asmCode.Add(AsmCmd.Cmd.Exit); return; } var sp = asmCode.SubprogramStack.Peek(); switch (sp) { case FunctionSymbol fs: Childs[0].Generate(asmCode, symTable); if (fs.ReturnType == TypeSymbol.IntTypeSymbol || fs.ReturnType == TypeSymbol.CharTypeSymbol) { asmCode.Add(AsmCmd.Cmd.Pop, AsmReg.Reg.Eax); } else if (fs.ReturnType == TypeSymbol.RealTypeSymbol) { asmCode.Add( AsmCmd.Cmd.Movsd, AsmReg.Reg.Xmm0, new AsmOffset(0, 8, AsmReg.Reg.Esp)); asmCode.Add(AsmCmd.Cmd.Sub, AsmReg.Reg.Esp, 8); } else { throw new NotImplementedException(); } break; } asmCode.Add(AsmCmd.Cmd.Leave); asmCode.Add(AsmCmd.Cmd.Ret, $"{-sp.ParameterOffset - 4}"); }
private static List <Node> OptimizeStatements(List <Node> list, SymTable symTable) { for (var i = 0; i < list.Count; i++) { FindAndOptimizeExpressions(list[i], symTable); switch (list[i]) { case IfStatementNode ifs: OptimizeStatements(ifs.Childs, symTable); list[i] = OptimizeIf(ifs, symTable); break; case RepeatStatementNode rs: OptimizeStatements(rs.Childs, symTable); list[i] = OptimizeRepeat(rs, symTable); break; case WhileStatementNode ws: OptimizeStatements(ws.Childs, symTable); list[i] = OptimizeWhile(ws, symTable); break; case ForStatementNode fs: OptimizeStatements(fs.Childs, symTable); list[i] = OptimizeFor(fs, symTable); break; case CompoundStatementNode csn: csn.Statements = OptimizeStatements(csn.Statements, symTable); break; } } return(list); }
private ExpressionNode ParseTerm(SymTable symTable) { var f = ParseFactor(symTable); var c = Current; while (MulOps.Contains(c.SubType)) { Next(); var t = ParseFactor(symTable); if ( t.Type is ArrayTypeSymbol || t.Type is RecordTypeSymbol || f.Type is ArrayTypeSymbol || f.Type is RecordTypeSymbol ) { throw new ParserException("Incompatible types", c.Line, c.Position); } if (c.SubType == Slash) { f = ToType(f, TypeSymbol.RealTypeSymbol); } (f, t) = SelectType(f, t); f = new BinOpNode(new List <Node> { f, t }, c.SubType, c.Line, c.Position) { Type = f.Type }; c = Current; } return(f); }
private ExpressionNode ParseExpression(SymTable symTable) { var e = ParseSimpleExpression(symTable); var c = Current; while (RelOps.Contains(c.SubType)) { Next(); var t = ParseSimpleExpression(symTable); if ( t.Type is ArrayTypeSymbol || t.Type is RecordTypeSymbol || e.Type is ArrayTypeSymbol || e.Type is RecordTypeSymbol ) { throw new ParserException("Incompatible types", c.Line, c.Position); } (e, t) = SelectType(e, t); e = new BinOpNode(new List <Node> { e, t }, c.SubType, c.Line, c.Position) { Type = TypeSymbol.IntTypeSymbol }; c = Current; } return(e); }
private static void FindAndOptimizeExpressions(Node start, SymTable symTable) { switch (start) { case RepeatStatementNode rn: rn.Condition = OptimizeExpression( (ExpressionNode)rn.Condition, symTable); break; case WhileStatementNode wn: wn.Condition = OptimizeExpression( (ExpressionNode)wn.Condition, symTable); break; case CompoundStatementNode csn: foreach (var statement in csn.Statements) { FindAndOptimizeExpressions(statement, symTable); } break; } for (var i = 0; i < start.Childs?.Count; i++) { if (start.Childs[i] is ExpressionNode en) { start.Childs[i] = OptimizeExpression(en, symTable); } else { FindAndOptimizeExpressions(start.Childs[i], symTable); } } }
private DesignatorNode ParseIndex(SymTable symTable, DesignatorNode array) { while (true) { if (Current.SubType != LBracket) { return(array); } var ars = (ArrayTypeSymbol)array.Type; var p = ParseIndexParam(symTable); CheckImplicitTypeCompatibility((TypeSymbol)p.Type, TypeSymbol.IntTypeSymbol); var i = new IndexOperator(new List <Node> { array, p }, "Index", p.Line, p.Position) { Type = ars.ElementType }; switch (ars.ElementType) { case RecordTypeSymbol _: return(ParseMemberAccess(symTable, i)); case ArrayTypeSymbol _: array = i; continue; } return(i); } }
private WriteStatementNode ParseWriteStatement(SymTable symTable) { var c = Current; Require(Write); if (Current.SubType != LParenthesis) { return(new WriteStatementNode(null, "Write", c.Line, c.Position)); } Next(); if (Current.SubType == StringConstant) { var s = Current; Next(); Require(RParenthesis); return(new WriteStatementNode(new List <Node> { new StringNode(null, s) }, "Write", c.Line, c.Position)); } var e = ParseExpressionList(symTable); Require(RParenthesis); return(new WriteStatementNode(new List <Node> { e }, "Write", c.Line, c.Position)); }
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 Statement ParseExitStatement(SymTable symTable) { var c = Current; Require(Exit); if (Current.SubType != LParenthesis) { return(new ExitNode(null, c.Value, c.Line, c.Position)); } Next(); if (Current.SubType == RParenthesis) { Next(); return(new ExitNode(null, c.Value, c.Line, c.Position)); } if (CurrentReturnType == null) { throw new ParserException("Procedures cannot return a value", Current.Line, Current.Position); } var e = ParseExpression(symTable); Require(RParenthesis); CheckImplicitTypeCompatibility((TypeSymbol)e.Type, CurrentReturnType); return(new ExitNode(new List <Node> { e }, c.Value, c.Line, c.Position)); }
private void ParseFunctionDecl(SymTable symTable) { var c = Current; SymTable procSymTable = new SymTable { Parent = symTable }; var h = ParseFunctionHeading(procSymTable); Require(Semicolon); if (symTable.Contains(h.Name)) { throw new ParserException("Duplicate identifier {h.Name}", c.Line, c.Position); } var f = new FunctionSymbol { Name = h.Name, Parameters = h.Parameters, ReturnType = h.ReturnType }; symTable.Add(h.Name, f); var backup = CurrentReturnType; CurrentReturnType = f.ReturnType; var b = ParseBlock(procSymTable); CurrentReturnType = backup; Require(Semicolon); f.Block = b; }
private void ParseDeclSection(SymTable symTable) { while (true) { switch (Current.SubType) { case Const: ParseConstSection(symTable); break; case Var: ParseVarSection(symTable); break; case Tokenizer.TokenSubType.Type: ParseTypeSection(symTable); break; case Procedure: ParseProcedureDecl(symTable); break; case Function: ParseFunctionDecl(symTable); break; default: return; } } }
private void ParseProcedureDecl(SymTable symTable) { var c = Current; SymTable procSymTable = new SymTable { Parent = symTable }; var h = ParseProcedureHeading(procSymTable); Require(Semicolon); if (symTable.Contains(h.Name)) { throw new ParserException($"Duplicate identifier {h.Name}", c.Line, c.Position); } var p = new ProcedureSymbol { Name = h.Name, Parameters = h.Parameters }; symTable.Add(h.Name, p); var backup = CurrentReturnType; CurrentReturnType = null; var b = ParseBlock(procSymTable); CurrentReturnType = backup; p.Block = b; Require(Semicolon); }
public override void Generate(AsmCode asmCode, SymTable symTable) { if (Type == TypeSymbol.IntTypeSymbol) { asmCode.Add(AsmCmd.Cmd.Push, Value.ToString()); } else if (Type == TypeSymbol.CharTypeSymbol) { asmCode.Add(AsmCmd.Cmd.Push, Convert.ToInt32(Value).ToString()); } else if (Type == TypeSymbol.RealTypeSymbol) { string val = $"__@real{HexConverter.DoubleToHexString((double) Value)}"; if (!asmCode.ConstDictionary.ContainsKey(Value)) { asmCode.ConstDictionary[Value] = val; } asmCode.Add(AsmCmd.Cmd.Sub, AsmReg.Reg.Esp, 8); asmCode.Add( AsmCmd.Cmd.Movsd, AsmReg.Reg.Xmm0, asmCode.ConstDictionary[Value]); asmCode.Add( AsmCmd.Cmd.Movsd, new AsmOffset(0, 8, AsmReg.Reg.Esp), AsmReg.Reg.Xmm0); } }
private void ParseFieldDecl(SymTable parentSymTable, SymTable recSymTable) { var c = Current; Require(Identifier); List <string> idents = new List <string> { c.Value.ToString() }; var t = Current; while (t.SubType == Comma) { Next(); t = Current; Require(Identifier); idents.Add(t.Value.ToString()); } Require(Colon); var tp = ParseType(parentSymTable); foreach (var i in idents) { if (recSymTable.Contains(i)) { throw new ParserException($"Field {i} already declared", c.Line, c.Position); } recSymTable.Add(i, new VarSymbol { Name = i, Type = tp, Value = null }); } }
private void ParseTypeDecl(SymTable symTable) { var c = Current; Require(Identifier); Require(Equal); var t = ParseType(symTable); switch (t) { case ArrayTypeSymbol at: at.Name = c.Value.ToString(); symTable.Add(at.Name, at); break; case RecordTypeSymbol rt: rt.Name = c.Value.ToString(); symTable.Add(rt.Name, rt); break; default: symTable.Add(c.Value.ToString(), t); break; } }
private ExpressionNode ParseCastParam(SymTable symTable) { Require(LParenthesis); var t = ParseExpression(symTable); Require(RParenthesis); return(t); }
private ExpressionNode ParseIndexParam(SymTable symTable) { Require(LBracket); var t = ParseExpression(symTable); Require(RBracket); return(t); }
private Block ParseBlock(SymTable symTable) { if (Current.SubType != Begin) { ParseDeclSection(symTable); } return(new Block { StatementList = ParseCompoundStatement(symTable).Statements, SymTable = symTable }); }
public void GenerateLValue(AsmCode asmCode, SymTable symTable) { string val = $"__@string{asmCode.CurrentID++}"; if (!asmCode.ConstDictionary.ContainsKey(Value)) { asmCode.ConstDictionary[Value] = val; } asmCode.Add(AsmCmd.Cmd.Push, $"offset {asmCode.ConstDictionary[Value]}"); }
private void ParseTypeSection(SymTable symTable) { Require(Tokenizer.TokenSubType.Type); ParseTypeDecl(symTable); Require(Semicolon); while (Current.SubType == Identifier) { ParseTypeDecl(symTable); Require(Semicolon); } }
private Parameters ParseConstParameter(SymTable symTable) { Require(Const); var p = ParseValueParameter(symTable); foreach (ParameterSymbol ps in p) { ps.ParameterModifier = ParameterModifier.Const; } return(p); }
private DesignatorNode ParseProcedureCall(SymTable symTable, DesignatorNode procedure) { var ps = (ProcedureSymbol)procedure.Type; var p = ParseActualParameters(symTable); CheckParameters(ps.Parameters, p); return(new CallOperator(p.Childs, "Call", p.Line, p.Position) { Subprogram = ps }); }