public override CodeNode Construct(AASTNode aastNode, CodeNode?parent) { Generator g = Program.currentCompiler.generator; CodeNode asgmntNode = new CodeNode(aastNode, parent); Context?ctx = SemanticAnalyzer.FindParentContext(aastNode) ?? throw new CompilationErrorException("No parent context found!!!\r\n At line " + aastNode.Token.Position.Line); // Expression (right-value) CodeNode exprNode = base.Construct((AASTNode)aastNode.Children[1], asgmntNode); asgmntNode.Children.AddLast(exprNode); byte fr0 = exprNode.ByteToReturn; // Left-value to be assigned CodeNode receiverNode = base.Construct((AASTNode)aastNode.Children[0], asgmntNode); asgmntNode.Children.AddLast(receiverNode); byte fr1 = receiverNode.ByteToReturn; switch (aastNode.Children[0].ASTType) { case "Primary": // Array or variable (TODO: dot-notation for structures and modules) { AASTNode prim = (AASTNode)aastNode.Children[0]; if (prim.Children[^ 1].ASTType.Equals("IDENTIFIER"))
/// <summary> /// Constructs a Code Node that has generated asm commands that deallocates registers (if possible) after given statement has been already constructed. /// </summary> /// <param name="aastNode">Already constructed statement.</param> /// <param name="parent">Parent Code Node</param> /// <param name="dependOnStatementNum">Whether we deallocate only those variables that are never appear after given statement /// or just to deallocate everything what has been allocated (in current context branch).</param> /// <returns>Constructed Code Node with asm commands representing register deallocation.</returns> protected CodeNode GetRegisterDeallocationNode(AASTNode aastNode, CodeNode?parent, bool dependOnStatementNum = true) { Generator g = Program.currentCompiler.generator; Context? ctx = SemanticAnalyzer.FindParentContext(aastNode); if (ctx == null) { throw new CompilationErrorException("TODO: "); } CodeNode regDeallocNode = new CodeNode("Register deallocation", parent); foreach (string var in g.regAllocVTR.Keys) { if ((ctx.IsVarDeclared(var) && !dependOnStatementNum || ctx.IsVarDeclaredInThisContext(var) && dependOnStatementNum) && !ctx.IsVarRoutine(var) && !ctx.IsVarConstant(var) && !ctx.IsVarLabel(var)) { int liEnd = ctx.GetLIEnd(var); if (liEnd <= aastNode.BlockPosition || !dependOnStatementNum) { byte reg = g.regAllocVTR[var]; regDeallocNode.Children.AddLast(GetStoreVariableNode(regDeallocNode, var, reg, ctx)); g.regAllocVTR.Remove(var); g.regAllocRTV.Remove(reg); g.FreeReg(reg); } } } return(regDeallocNode); }
public override AASTNode Annotate(ASTNode astNode, AASTNode?parent) { // TODO: name of the block body (if we really need it) string bbName = "name"; AASTNode bb = new AASTNode(astNode, parent, SemanticAnalyzer.no_type); bb.Context = new Context("BlockBody_" + bbName, SemanticAnalyzer.FindParentContext(parent), bb); bool setLIEnd = false; string varName = ""; if (Program.currentCompiler.semantics.varToAddToCtx != null) { bb.Context.AddVar(Program.currentCompiler.semantics.varToAddToCtx, Program.currentCompiler.semantics.varToAddToCtx.Token.Value); varName = Program.currentCompiler.semantics.varToAddToCtx.Token.Value; setLIEnd = true; Program.currentCompiler.semantics.varToAddToCtx = null; } foreach (ASTNode child in astNode.Children) { bb.Children.Add(base.Annotate(child, bb)); } if (setLIEnd) { bb.Context.SetLIEnd(varName, SemanticAnalyzer.GetMaxDepth(bb)); } return(bb); }
public override CodeNode Construct(AASTNode aastNode, CodeNode?parent) { Generator g = Program.currentCompiler.generator; CodeNode primNode = new CodeNode(aastNode, parent); Context? ctx = SemanticAnalyzer.FindParentContext(aastNode) ?? throw new CompilationErrorException("No parent context found!!!\r\n At line " + aastNode.Token.Position.Line); if (aastNode.Children[^ 1].ASTType.Equals("IDENTIFIER")) // Regular identifier access. TODO: context descend using dot-notation
public override CodeNode Construct(AASTNode aastNode, CodeNode?parent) { Generator g = Program.currentCompiler.generator; Context? ctx = SemanticAnalyzer.FindParentContext(aastNode) ?? throw new CompilationErrorException("No parent context found!!!\r\n At line " + aastNode.Token.Position.Line); CodeNode rbNode = new CodeNode(aastNode, parent); int frameSize = 0; foreach (AASTNode variable in ctx.GetDeclaredVars()) { frameSize += variable.AASTType.GetSize(); } rbNode.Children.AddLast(new CodeNode("Pre routine body", rbNode) .Add(GenerateST(FP, SP)) .Add(GenerateMOV(SP, FP)) .Add(GenerateLDA(FP, FP, 4)) .Add(GenerateST(27, FP)) .Add(GenerateLDA(FP, FP, 4)) .Add(GenerateMOV(FP, SP)) .Add(GenerateLDA(SP, SP, frameSize))); foreach (AASTNode statement in aastNode.Children) { rbNode.Children.AddLast(GetRegisterAllocationNode(statement, rbNode)); rbNode.Children.AddLast(base.Construct(statement, rbNode)); rbNode.Children.AddLast(GetRegisterDeallocationNode(statement, rbNode)); } for (byte i = 0; i < 26; i++) { g.FreeReg(i); if (g.regAllocRTV.ContainsKey(i)) { string varName = g.regAllocRTV[i]; g.regAllocRTV.Remove(i); g.regAllocVTR.Remove(varName); } } // Deallocate dynamic arrays rbNode.Children.AddLast(GetDynamicMemoryDeallocationNode(aastNode, rbNode)); rbNode.Children.AddLast(new CodeNode("Post routine body", rbNode) .Add(GenerateLDA(FP, FP, -4)) .Add(GenerateLD(FP, 27)) .Add(GenerateLDA(FP, FP, -4)) .Add(GenerateMOV(FP, SP)) .Add(GenerateLD(FP, FP)) .Add(GenerateCBR(27, 27))); return(rbNode); }
public override AASTNode Annotate(ASTNode astNode, AASTNode?parent) { Context? ctx = SemanticAnalyzer.FindParentContext(parent); AASTNode module = new AASTNode(astNode, parent, new VarType(VarType.ERAType.MODULE)); module.Context = new Context(astNode.Children[1].Token.Value, ctx, module); foreach (ASTNode child in astNode.Children[2].Children) { module.Children.Add(base.Annotate(child, module)); } ctx?.AddVar(module, astNode.Children[1].Token.Value); return(module); }
/// <summary> /// Recursively calculates the size of an address represented by a given expression. /// For example, if expression has some int pointers, then expression clearly points to some integer (or 4 bytes). /// If expression has only byte pointers, the expression clearly points to some byte address (1 byte). /// </summary> /// <param name="aastNode">Expression AASTNode</param> /// <returns>The size of a variable that given expression points to.</returns> protected int GetSizeOfExpressionAddressedVariable(AASTNode aastNode) { Context?ctx = SemanticAnalyzer.FindParentContext(aastNode); int size = 0; if (aastNode.ASTType.Equals("Dereference")) { // Careful here if (aastNode.Children[2].Children.Count == 1 && aastNode.Children[2].Children[0].ASTType.Equals("Primary") && aastNode.Children[2].Children[0].Children[^ 1].ASTType.Equals("IDENTIFIER")) { switch (ctx.GetVarType(aastNode.Children[2].Children[0].Children[^ 1].Token).Type)
public override AASTNode Annotate(ASTNode astNode, AASTNode?parent) { Context ctx = SemanticAnalyzer.FindParentContext(parent); AASTNode data = new AASTNode(astNode, parent, new DataType()); ((DataType)data.AASTType).Size = astNode.Children[3].Children.Count + 1; data.Children.Add(base.Annotate(astNode.Children[1], data)); // Identifier data.Children.Add(base.Annotate(astNode.Children[2], data)); // The first literal foreach (ASTNode child in astNode.Children[3].Children) { data.Children.Add(base.Annotate(child, data)); // The rest of literals } ctx.AddVar(data, astNode.Children[1].Token.Value); return(data); }
public override AASTNode Annotate(ASTNode astNode, AASTNode?parent) { AASTNode label = new AASTNode(astNode, parent, new VarType(VarType.ERAType.LABEL)); // Add label to the context Context?ctx = SemanticAnalyzer.FindParentContext(parent); ctx?.AddVar(label, astNode.Children[1].Token.Value); label.Token.Value = astNode.Children[1].Token.Value; // Put identifier label.Children.Add(base.Annotate(astNode.Children[1], label)); return(label); }
public override AASTNode Annotate(ASTNode astNode, AASTNode?parent) { string structName = astNode.Children[1].Token.Value; AASTNode structure = new AASTNode(astNode, parent, new StructType(structName)); Context? ctx = SemanticAnalyzer.FindParentContext(parent) ?? throw new SemanticErrorException("No parent context found!!!\r\n At line " + astNode.Token.Position.Line); ctx?.AddVar(structure, structName); structure.Context = new Context(structName, ctx, structure); foreach (ASTNode child in astNode.Children[2].Children) { structure.Children.Add(base.Annotate(child, structure)); } return(structure); }
public override AASTNode Annotate(ASTNode astNode, AASTNode?parent) { AASTNode code = new AASTNode(astNode, parent, new VarType(VarType.ERAType.MODULE)); code.Context = new Context("code", SemanticAnalyzer.FindParentContext(parent), code); foreach (ASTNode child in astNode.Children[1].Children) { code.Children.Add(base.Annotate(child, code)); } SemanticAnalyzer.FindParentContext(parent).AddVar(code, "code"); return(code); }
public override AASTNode Annotate(ASTNode astNode, AASTNode?parent) { AASTNode asgnmt = new AASTNode(astNode, parent, SemanticAnalyzer.no_type); // TODO: check for type accordance (debatable) // TODO: dot-notation here if (astNode.Children[0].Children[0].ASTType.Equals("Primary") && SemanticAnalyzer.FindParentContext(asgnmt).IsVarConstant(astNode.Children[0].Children[0].Token)) { Token id = astNode.Children[0].Children[0].Token; throw new SemanticErrorException("Attempt to modify a constant!!!\n" + " At(Line: " + id.Position.Line + ", Char: " + id.Position.Char + ")."); } asgnmt.Children.Add(base.Annotate(astNode.Children[0], asgnmt)); // Receiver asgnmt.Children.Add(base.Annotate(astNode.Children[2], asgnmt)); // Expression return(asgnmt); }
public override CodeNode Construct(AASTNode aastNode, CodeNode?parent) { Generator g = Program.currentCompiler.generator; CodeNode arrDefNode = new CodeNode(aastNode, parent); Context? ctx = SemanticAnalyzer.FindParentContext(aastNode) ?? throw new CompilationErrorException("No parent context found!!!\r\n At line " + aastNode.Token.Position.Line); if (((ArrayType)aastNode.AASTType).Size == 0) // We have to allocate it on the heap (dynamic arrays) { int offsetSize = ctx.GetArrayOffsetSize(aastNode.Token.Value) / 2; CodeNode exprNode = base.Construct((AASTNode)aastNode.Children[0], arrDefNode); byte fr0 = exprNode.ByteToReturn; // Execution-time array size arrDefNode.Children.AddLast(exprNode); while (offsetSize > 0) { arrDefNode.Children.AddLast(new CodeNode("Arr def ASL", arrDefNode).Add(GenerateASL(fr0, fr0))); // For 'int' its 4 bytes, and so on offsetSize /= 2; } CodeNode fr1Node = GetFreeRegisterNode(aastNode, arrDefNode); arrDefNode.Children.AddLast(fr1Node); byte fr1 = fr1Node.ByteToReturn; CodeNode fr2Node = GetFreeRegisterNode(aastNode, arrDefNode); arrDefNode.Children.AddLast(fr2Node); byte fr2 = fr2Node.ByteToReturn; /* heap: [array_size 4 bytes] [0th element] [1st element] ... [last element]; Allocated register contains address of 0th element. */ arrDefNode.Children.AddLast(new CodeNode("Array heap allocation 1", arrDefNode) .Add(GenerateLDA(fr0, fr0, 4))); // Allocate 4 additional bytes for array size arrDefNode.Children.AddLast(GetHeapTopChangeNode(arrDefNode, fr0, true)); arrDefNode.Children.AddLast(GetStoreToHeapNode(arrDefNode, fr0, 0)); // heap[0] := fr0; arrDefNode.Children.AddLast(new CodeNode("Array heap allocation 2", arrDefNode) .Add(GenerateLDC(0, fr1)) .Add(GenerateLD(fr1, fr2)) .Add(GenerateLDA(fr2, fr2, 4))); arrDefNode.Children.AddLast(GetStoreVariableNode(arrDefNode, aastNode.Token.Value, fr2, ctx)); g.FreeReg(fr0); g.FreeReg(fr1); g.FreeReg(fr2); } return(arrDefNode); }
public override CodeNode Construct(AASTNode aastNode, CodeNode?parent) { Generator g = Program.currentCompiler.generator; CodeNode varDefNode = new CodeNode(aastNode, parent); Context? ctx = SemanticAnalyzer.FindParentContext(aastNode) ?? throw new CompilationErrorException("No parent context found!!!\r\n At line " + aastNode.Token.Position.Line); switch (aastNode.AASTType.Type) { case VarType.ERAType.INT: case VarType.ERAType.SHORT: case VarType.ERAType.BYTE: case VarType.ERAType.INT_ADDR: case VarType.ERAType.SHORT_ADDR: case VarType.ERAType.BYTE_ADDR: { // If we have initial assignment - store it to register/memory if (aastNode.Children.Count > 0) { CodeNode exprNode = base.Construct((AASTNode)aastNode.Children[0], varDefNode); varDefNode.Children.AddLast(exprNode); byte fr0 = exprNode.ByteToReturn; if (g.regAllocVTR.ContainsKey(aastNode.Token.Value)) { byte reg = g.regAllocVTR[aastNode.Token.Value]; varDefNode.Children.AddLast(new CodeNode("VarDef MOV", varDefNode).Add(GenerateMOV(fr0, reg))); } varDefNode.Children.AddLast(GetStoreVariableNode(varDefNode, aastNode.Token.Value, fr0, ctx)); g.FreeReg(fr0); } break; } default: break; } return(varDefNode); }
/// <summary> /// Constructs a Code Node that has generated asm commands representing deallocation of all dynamically allocated memory from the heap. /// It is not connected to any statement number or live interval. Usually is called when current context has been constructed fully. /// </summary> /// <param name="aastNode">Some statement in current context.</param> /// <param name="parent">Parent Code Node</param> /// <returns>Constructed Code Node with asm commands representing a dynamic memory deallocation.</returns> protected CodeNode GetDynamicMemoryDeallocationNode(AASTNode aastNode, CodeNode?parent) { Context? ctx = SemanticAnalyzer.FindParentContext(aastNode); Generator g = Program.currentCompiler.generator; CodeNode arrDeallocNode = new CodeNode("Dynamic array deallocation", parent); CodeNode frNode = GetFreeRegisterNode(aastNode, arrDeallocNode); arrDeallocNode.Children.AddLast(frNode); byte fr0 = frNode.ByteToReturn; foreach (AASTNode var in ctx.GetDeclaredVars()) { if (ctx.IsVarDynamicArray(var.Token.Value) || ctx.IsVarStruct(var.Token)) { arrDeallocNode.Children.AddLast(GetLoadFromHeapNode(arrDeallocNode, fr0, 0)); // Size of dynamic array arrDeallocNode.Children.AddLast(GetHeapTopChangeNode(arrDeallocNode, fr0, true, false)); } } g.FreeReg(fr0); return(arrDeallocNode); }
public override CodeNode Construct(AASTNode aastNode, CodeNode?parent) { Context?ctx = SemanticAnalyzer.FindParentContext(aastNode) ?? throw new CompilationErrorException("No parent context found!!!\r\n At line " + aastNode.Token.Position.Line); CodeNode refNode = new CodeNode(aastNode, parent); string varName = aastNode.Children[1].Token.Value; CodeNode frNode = GetFreeRegisterNode(aastNode, refNode); byte fr0 = frNode.ByteToReturn; refNode.Children.AddLast(frNode); if (ctx.IsVarDynamicArray(varName)) { refNode.Children.AddLast(GetLoadVariableNode(refNode, varName, fr0, ctx)); // Address to the heap lies on the stack, so we load } else { refNode.Children.AddLast(GetLoadVariableAddressNode(refNode, varName, fr0, ctx)); } refNode.ByteToReturn = fr0; return(refNode); }
public override CodeNode Construct(AASTNode aastNode, CodeNode?parent) { Generator g = Program.currentCompiler.generator; Context? ctx = SemanticAnalyzer.FindParentContext(aastNode) ?? throw new CompilationErrorException("No parent context found!!!\r\n At line " + aastNode.Token.Position.Line); CodeNode derefNode = new CodeNode(aastNode, parent); CodeNode exprNode = base.Construct((AASTNode)aastNode.Children[2], derefNode); byte fr0 = exprNode.ByteToReturn; derefNode.Children.AddLast(exprNode); if (!parent.Name.Equals("Assignment")) // Right value { // Load out all visible variable since we do not know what is going to be dereferenced foreach (string varName in ctx.GetAllVisibleVars()) { if (g.regAllocVTR.ContainsKey(varName)) { derefNode.Children.AddLast(GetStoreVariableNode(derefNode, varName, g.regAllocVTR[varName], ctx)); } } int bytesToLoad = GetSizeOfExpressionAddressedVariable((AASTNode)aastNode.Children[2]); int mask = bytesToLoad == 4 ? -1 : (int)Math.Pow(256, bytesToLoad) - 1; // 00 00 00 ff or 00 00 ff ff or ff ff ff ff CodeNode frNode = GetFreeRegisterNode(ctx, derefNode); byte fr1 = frNode.ByteToReturn; derefNode.Children.AddLast(frNode); derefNode.Children.AddLast(new CodeNode("load deref cmds 1", derefNode) .Add(GenerateLDC(4 - bytesToLoad, fr1)) .Add(GenerateSUB(fr1, fr0)) .Add(GenerateLD(fr0, fr0)) .Add(GenerateLDC(0, fr1)) .Add(GenerateLDA(fr1, fr1, mask)) .Add(GenerateAND(fr1, fr0))); g.FreeReg(fr1); } derefNode.ByteToReturn = fr0; return(derefNode); }
/// <summary> /// Constructs a Code Node that has generated asm commands that allocate (statement-aware) variables to register (if possible) /// and vise versa. /// </summary> /// <param name="aastNode">Statement that we want to construct and before which we want to allocate registers.</param> /// <param name="parent">Parent Code Node</param> /// <returns>Constructed Code Node with register allocation asm commands.</returns> protected CodeNode GetRegisterAllocationNode(AASTNode aastNode, CodeNode?parent) { Generator g = Program.currentCompiler.generator; Context? ctx = SemanticAnalyzer.FindParentContext(aastNode); if (ctx == null) { throw new CompilationErrorException("TODO: "); } CodeNode regAllocNode = new CodeNode("Register allocation", parent); HashSet <string> vars = GetAllUsedVars(aastNode); foreach (string var in vars) { if (ctx.IsVarDeclared(var) && !ctx.IsVarRoutine(var) && !ctx.IsVarConstant(var) && !ctx.IsVarLabel(var) && !ctx.IsVarData(var)) { int liStart = ctx.GetLIStart(var); if (!g.regAllocVTR.ContainsKey(var) && liStart <= aastNode.BlockPosition) // Allocation (if possible) { for (byte ri = 0; ri < 27; ri++) { if (!g.regOccup[ri]) { bool arrayCheck = !ctx.IsVarDynamicArray(var) && !ctx.IsVarArray(var); if (arrayCheck) { g.regAllocVTR.Add(var, ri); g.regAllocRTV.Add(ri, var); g.OccupateReg(ri); regAllocNode.Children.AddLast(GetLoadVariableNode(regAllocNode, var, ri, ctx)); } break; } } } } } return(regAllocNode); }
public override AASTNode Annotate(ASTNode astNode, AASTNode?parent) { AASTNode somePrim = new AASTNode(astNode, parent, SemanticAnalyzer.no_type); Context? ctx = SemanticAnalyzer.FindParentContext(parent) ?? throw new SemanticErrorException("No parent context found!!!\r\n At line " + astNode.Token.Position.Line); // Identifier somePrim.Children.Add(base.Annotate(astNode.Children[0], somePrim)); ASTNode idLink = astNode.Children[0]; // If constant, convert to number if (ctx.IsVarDeclared(idLink.Token) && ctx.IsVarConstant(idLink.Token)) { int constValue = ctx.GetConstValue(idLink.Token); ASTNode number = new ASTNode(parent, new List <ASTNode>(), idLink.Token, "NUMBER"); ASTNode opMinus = new ASTNode(number, new List <ASTNode>(), idLink.Token, "[ - ]"); if (constValue < 0) { opMinus.Children.Add(new ASTNode(opMinus, new List <ASTNode>(), idLink.Token, "OPERATOR")); constValue *= -1; } number.Children.Add(opMinus); ASTNode literal = new ASTNode(number, new List <ASTNode>(), new Token(TokenType.NUMBER, constValue.ToString(), idLink.Token.Position), "SOME_LITERAL"); number.Children.Add(literal); return(base.Annotate(number, parent)); } else { // { '.' Identifier } if (astNode.Children[1].Children.Count > 0) { foreach (ASTNode child in astNode.Children[1].Children) { if (!ctx.IsVarStruct(idLink.Token)) { throw new SemanticErrorException( "Trying to access non-struct variable via \'.\' notation!!!\r\n" + "\tAt (Line: " + idLink.Token.Position.Line.ToString() + ", Char: " + idLink.Token.Position.Char.ToString() + ")." ); } if (child.ASTType.Equals("IDENTIFIER")) { idLink = child; } somePrim.Children.Add(base.Annotate(child, somePrim)); } } // [ ArrayAccess | CallArgs ] if (astNode.Children[2].Children.Count > 0) { if (astNode.Children[2].Children[0].Children[0].ASTType.Equals("Call arguments")) { somePrim.Children.Add(base.Annotate(astNode.Children[2].Children[0].Children[0], somePrim)); } else { if (!ctx.IsVarArray(idLink.Token) && !ctx.IsVarData(idLink.Token.Value)) { throw new SemanticErrorException( "Trying to access non-array variable via \'[]\' notation!!!\r\n" + "\tAt (Line: " + idLink.Token.Position.Line.ToString() + ", Char: " + idLink.Token.Position.Char.ToString() + ")." ); } // If expression is constant we can check for array boundaries if (SemanticAnalyzer.IsExprConstant(astNode.Children[2].Children[0].Children[0].Children[1], ctx)) { int index = SemanticAnalyzer.CalculateConstExpr(astNode.Children[2].Children[0].Children[0].Children[1], ctx); int arrSize = ctx.GetArrSize(idLink.Token); if (index < 0) { throw new SemanticErrorException( "Negative array index!!!\r\n" + "\tAt (Line: " + idLink.Token.Position.Line.ToString() + ", Char: " + idLink.Token.Position.Char.ToString() + ")." ); } // If we know the size of the array already (arrSize != 0 indicates this) if (arrSize != 0 && index >= arrSize) { throw new SemanticErrorException( "Accessing element with index higher than array the size!!!\r\n" + "\tAt (Line: " + idLink.Token.Position.Line.ToString() + ", Char: " + idLink.Token.Position.Char.ToString() + ")." ); } } somePrim.Children.Add(base.Annotate(astNode.Children[2].Children[0].Children[0].Children[1], somePrim)); } } } return(somePrim); }
public override CodeNode Construct(AASTNode aastNode, CodeNode?parent) { // prim [ iden, call args ] // // Generate call bytes. // TODO: Dot notation (routines in modules) // // Construct parameters and put them in the stack // Deallocate everything // R27 = SB + offset(func); // if R27 goto R27; // Allocate back // Manage return value (if any) Generator g = Program.currentCompiler.generator; Context? ctx = SemanticAnalyzer.FindParentContext(aastNode) ?? throw new CompilationErrorException("No parent context found!!!\r\n At line " + aastNode.Token.Position.Line); CodeNode callNode = new CodeNode(aastNode, parent); int i = 0; List <VarType> paramTypes = ((RoutineType)ctx.GetVarType(aastNode.Children[0].Token)).ParamTypes; int param_i = 8; foreach (AASTNode expr in aastNode.Children[1].Children) { CodeNode exprNode = base.Construct(expr, callNode); byte fr0 = exprNode.ByteToReturn; callNode.Children.AddLast(exprNode); CodeNode fr1Node = GetFreeRegisterNode(ctx, callNode); byte fr1 = fr1Node.ByteToReturn; callNode.Children.AddLast(fr1Node); CodeNode fr2Node = GetFreeRegisterNode(ctx, callNode); byte fr2 = fr2Node.ByteToReturn; callNode.Children.AddLast(fr2Node); // Store parameters depending on their size on the stack before we enter a routine. int mask = paramTypes[i].GetSize() == 4 ? 0 : ((int)Math.Pow(256, 4) - 1) << (8 * paramTypes[i].GetSize()); // ff ff ff 00 or ff ff 00 00 or 00 00 00 00 int mask2 = paramTypes[i].GetSize() == 4 ? -1 : (int)Math.Pow(256, paramTypes[i].GetSize()) - 1; // 00 00 00 ff or 00 00 ff ff or ff ff ff ff callNode.Children.AddLast(new CodeNode("Parameter store", callNode) .Add(GenerateMOV(SP, 27)) .Add(GenerateLDA(27, 27, param_i - 4 + paramTypes[i].GetSize())) .Add(GenerateLD(27, fr1)) .Add(GenerateLDC(0, fr2)) .Add(GenerateLDA(fr2, fr2, mask)) .Add(GenerateAND(fr2, fr1)) .Add(GenerateLDC(0, fr2)) .Add(GenerateLDA(fr2, fr2, mask2)) .Add(GenerateAND(fr2, fr0)) .Add(GenerateOR(fr1, fr0)) .Add(GenerateST(fr0, 27))); param_i += paramTypes[i].GetSize(); i++; g.FreeReg(fr0); g.FreeReg(fr1); g.FreeReg(fr2); } // Recursively deallocate (statement-unaware) evertything, basically, up the AAST tree since we change our context completely. AASTNode mainContextNode = aastNode; while (!mainContextNode.ASTType.Equals("Program") && !mainContextNode.ASTType.Equals("Module")) { if (mainContextNode.Parent == null) { throw new CompilationErrorException("Routine call is bad!!! (how did you manage to do that!?)"); } if (mainContextNode.Context != null) { callNode.Children.AddLast(GetRegisterDeallocationNode(mainContextNode, callNode, false)); } mainContextNode = (AASTNode)mainContextNode.Parent; } callNode.Children.AddLast(new CodeNode("Call jump", callNode) .Add(GenerateLDA(SB, 27, ctx.GetStaticOffset(aastNode.Children[0].Token.Value))) // TODO: module routine jumps. Here are only pure static routines. .Add(GenerateLD(27, 27)) .Add(GenerateCBR(27, 27))); // If routine is not NO_TYPE, then it has returned something and this return value is always in R26. if (ctx.GetRoutineReturnType(aastNode.Children[0].Token).Type != VarType.ERAType.NO_TYPE) // Return value is in R26 { CodeNode fr0Node = GetFreeRegisterNode(aastNode, callNode); byte fr0 = fr0Node.ByteToReturn; callNode.Children.AddLast(fr0Node); callNode.Children.AddLast(new CodeNode("return value", callNode).Add(GenerateMOV(26, fr0))); callNode.ByteToReturn = fr0; g.FreeReg(26); } return(callNode); }
/// <summary> /// Constructs a Code Node that has asm commands representing a free register allocation (if all are allocated already). /// Some variables could be deallocated randomly when calling this function. /// </summary> /// <param name="aastNode">Some statement in current context.</param> /// <param name="parent">Parent Code Node</param> /// <returns>Constructed Code Node with asm commands representing a free register allocation.</returns> protected CodeNode GetFreeRegisterNode(AASTNode aastNode, CodeNode?parent) { return(GetFreeRegisterNode(SemanticAnalyzer.FindParentContext(aastNode), parent)); }
private List <AASTNode> IdentifyVarDecl(ASTNode node, AASTNode parent, VarType type) { List <AASTNode> lst = new List <AASTNode>(); Context? ctx = SemanticAnalyzer.FindParentContext(parent) ?? throw new SemanticErrorException("No parent context found!!!\r\n At line " + node.Token.Position.Line); switch (node.ASTType) { case "Variable": { // VarDefinition { , VarDefinition } ; AASTNode firstDef = new AASTNode(node.Children[0], parent, type); lst.Add(firstDef); ctx.AddVar(firstDef, node.Children[0].Children[0].Token.Value); // VarDef's identifier // Check expr if exists if (node.Children[0].Children[1].Children.Count > 0) { AASTNode firstExpr = base.Annotate(node.Children[0].Children[1].Children[0].Children[1], firstDef); firstDef.Children.Add(firstExpr); } // Repeat for { , VarDefinition } foreach (ASTNode varDef in node.Children[1].Children) { if (varDef.ASTType.Equals("Variable definition")) // Skip comma rule { AASTNode def = new AASTNode(varDef, parent, type); lst.Add(def); ctx.AddVar(def, varDef.Children[0].Token.Value); // VarDef's identifier if (varDef.Children[1].Children.Count > 0) { AASTNode expr = base.Annotate(varDef.Children[1].Children[0].Children[1], def); def.Children.Add(expr); } } } break; } case "Constant": { // 'const' ConstDefinition { , ConstDefinition } ; AASTNode firstDef = new AASTNode(node.Children[1], parent, type); lst.Add(firstDef); ctx.AddVar(firstDef, node.Children[1].Children[0].Token.Value); // ConstDef's identifier if (!SemanticAnalyzer.IsExprConstant(node.Children[1].Children[2], ctx)) { throw new SemanticErrorException( "Expression for a constant definition is not constant!!!\r\n" + " At (Line: " + node.Children[1].Children[2].Token.Position.Line.ToString() + ", Char: " + node.Children[1].Children[2].Token.Position.Char.ToString() + ")." ); } firstDef.AASTValue = SemanticAnalyzer.CalculateConstExpr(node.Children[1].Children[2], ctx); // Repeat for { , ConstDefinition } foreach (ASTNode varDef in node.Children[2].Children) { if (varDef.ASTType.Equals("Constant definition")) // Skip comma rule { AASTNode def = new AASTNode(varDef, parent, type); lst.Add(def); ctx.AddVar(def, varDef.Children[0].Token.Value); // ConstDef's identifier if (!SemanticAnalyzer.IsExprConstant(varDef.Children[2], ctx)) { throw new SemanticErrorException( "Expression for a constant definition is not constant!!!\r\n" + " At (Line: " + varDef.Children[2].Token.Position.Line.ToString() + ", Char: " + varDef.Children[2].Token.Position.Char.ToString() + ")." ); } def.AASTValue = SemanticAnalyzer.CalculateConstExpr(varDef.Children[2], ctx); } } break; } case "Array": { // '[' ']' ArrDefinition { , ArrDefinition } ; AASTNode firstDef = new AASTNode(node.Children[2], parent, type); lst.Add(firstDef); ctx.AddVar(firstDef, node.Children[2].Children[0].Token.Value); // ArrDef's identifier //CheckVariablesForExistance(node.Children[2].Children[2], ctx); // Expression of ArrDefinition if (SemanticAnalyzer.IsExprConstant(node.Children[2].Children[2], ctx)) { int arrSize = SemanticAnalyzer.CalculateConstExpr(node.Children[2].Children[2], ctx); if (arrSize <= 0) { throw new SemanticErrorException( "Incorrect array size!!!\r\n" + " At (Line: " + node.Children[2].Children[2].Token.Position.Line.ToString() + ", Char: " + node.Children[2].Children[2].Token.Position.Char.ToString() + ")." ); } ((ArrayType)type).Size = arrSize; } else { // If size is not constant, just pass the expression firstDef.Children.Add(base.Annotate(node.Children[2].Children[2], firstDef)); } // Repeat for { , ArrDefinition } foreach (ASTNode arrDef in node.Children[3].Children) { ArrayType arrType = new ArrayType(((ArrayType)type).ElementType); // Each array can have it's own size if (arrDef.ASTType.Equals("Array definition")) // Skip comma rule { AASTNode def = new AASTNode(arrDef, parent, arrType); lst.Add(def); ctx.AddVar(def, arrDef.Children[0].Token.Value); // ArrDef's identifier //CheckVariablesForExistance(arrDef.Children[2], ctx); // Expression of ArrDefinition if (SemanticAnalyzer.IsExprConstant(arrDef.Children[2], ctx)) { int _arrSize = SemanticAnalyzer.CalculateConstExpr(arrDef.Children[2], ctx); if (_arrSize <= 0) { throw new SemanticErrorException( "Incorrect array size!!!\r\n" + " At (Line: " + arrDef.Children[2].Token.Position.Line.ToString() + ", Char: " + arrDef.Children[2].Token.Position.Char.ToString() + ")." ); } arrType.Size = _arrSize; } else { // If size is not constant, just pass the expression def.Children.Add(base.Annotate(arrDef.Children[2], def)); } } } break; } default: break; } return(lst); }
public override AASTNode Annotate(ASTNode astNode, AASTNode?parent) { string routineName = astNode.Children[1].Token.Value; Context?ctx = SemanticAnalyzer.FindParentContext(parent) ?? throw new SemanticErrorException("No parent context found!!!\r\n At line " + astNode.Token.Position.Line); List <VarType> paramTypes = new List <VarType>(); VarType returnType = SemanticAnalyzer.no_type; // Default value // Determine parameter types and return type if (astNode.Children[3].Children.Count > 0) { paramTypes.AddRange(SemanticAnalyzer.RetrieveParamTypes(astNode.Children[3].Children[0])); // Parameters } if (astNode.Children[5].Children.Count > 0) { returnType = SemanticAnalyzer.IdentifyType(astNode.Children[5].Children[1]); } AASTNode routine = new AASTNode(astNode, parent, new RoutineType(paramTypes, returnType)); ctx?.AddVar(routine, routineName); routine.Context = new Context(routineName, ctx, routine); // Add params to the context if any if (astNode.Children[3].Children.Count > 0) { AASTNode firstParam = new AASTNode(astNode.Children[3].Children[0].Children[0], routine, paramTypes[0]); firstParam.Token.Type = TokenType.IDENTIFIER; firstParam.Token.Value = astNode.Children[3].Children[0].Children[0].Children[1].Token.Value; firstParam.LIStart = 1; routine.Context.AddVar(firstParam, astNode.Children[3].Children[0].Children[0].Children[1].Token.Value); int i = 1; foreach (ASTNode child in astNode.Children[3].Children[0].Children[1].Children) { if (child.ASTType.Equals("Parameter")) // Skip comma rule { AASTNode param = new AASTNode(child, routine, paramTypes[i]); param.Token.Type = TokenType.IDENTIFIER; param.Token.Value = child.Children[1].Token.Value; param.LIStart = 1; routine.Context.AddVar(param, child.Children[1].Token.Value); i++; } } } // Annotate routine body routine.Children.Add(base.Annotate(astNode.Children[6], routine)); // Check if return statement exists if (!CheckForReturn(astNode, ctx.GetRoutineReturnType(astNode.Children[1].Token).Type == VarType.ERAType.NO_TYPE)) { throw new SemanticErrorException("A routine has no 'return' statement!!!\r\n" + " At (Line: " + astNode.Children[1].Token.Position.Line.ToString() + ", Char: " + astNode.Children[1].Token.Position.Char.ToString() + ")." ); } // Set LI end of parameters int maxDepth = SemanticAnalyzer.GetMaxDepth(routine); Dictionary <string, AASTNode> .ValueCollection parameters = routine.Context.GetDeclaredVars(); int j = 0; foreach (AASTNode param in parameters) { if (j >= paramTypes.Count) { break; } routine.Context.SetLIEnd(param.Token.Value, maxDepth); j++; } return(routine); }
public override AASTNode Annotate(ASTNode astNode, AASTNode?parent) { astNode = astNode.Children[0]; AASTNode asmStmnt = new AASTNode(astNode, parent, SemanticAnalyzer.no_type); if (astNode.ASTType.Equals("format ( 8 | 16 | 32 )")) { int frmt = int.Parse(astNode.Children[1].Token.Value); if (!(frmt == 8 || frmt == 16 || frmt == 32)) { throw new SemanticErrorException( "Incorrect format at assembly block!!!\r\n" + " At (Line: " + astNode.Children[1].Token.Position.Line.ToString() + ", Char: " + astNode.Children[1].Token.Position.Char.ToString() + ")." ); } } if (astNode.ASTType.Equals("Register := Expression")) { // Check if expression is constant Context ctx = SemanticAnalyzer.FindParentContext(parent); if (!SemanticAnalyzer.IsExprConstant(astNode.Children[2], ctx)) { throw new SemanticErrorException( "This expression should be constant (refer to the documentation)!!!\r\n" + " At (Line: " + astNode.Children[2].Token.Position.Line.ToString() + ", Char: " + astNode.Children[2].Token.Position.Char.ToString() + ")." ); } } else if (astNode.ASTType.Equals("Register := Register + Expression")) { // Check if expression is constant Context ctx = SemanticAnalyzer.FindParentContext(parent); if (!SemanticAnalyzer.IsExprConstant(astNode.Children[4], ctx)) { throw new SemanticErrorException( "This expression should be constant (refer to the documentation)!!!\r\n" + " At (Line: " + astNode.Children[4].Token.Position.Line.ToString() + ", Char: " + astNode.Children[4].Token.Position.Char.ToString() + ")." ); } } else if (astNode.ASTType.Equals("Register := Identifier")) { // Check if identifier is label Context ctx = SemanticAnalyzer.FindParentContext(parent); if (ctx.IsVarDeclared(astNode.Children[2].Token) && !ctx.IsVarLabel(astNode.Children[2].Token)) { if (!ctx.IsVarConstant(astNode.Children[2].Token)) { throw new SemanticErrorException( "Label expected!!!\r\n" + " At (Line: " + astNode.Children[2].Token.Position.Line.ToString() + ", Char: " + astNode.Children[2].Token.Position.Char.ToString() + ")." ); } } } else if (astNode.ASTType.Equals("< Identifier >")) { Context?ctx = SemanticAnalyzer.FindParentContext(parent); ctx?.AddVar(new AASTNode(astNode.Children[1], parent, new VarType(VarType.ERAType.LABEL)), astNode.Children[1].Token.Value); } foreach (ASTNode child in astNode.Children) { asmStmnt.Children.Add(base.Annotate(child, asmStmnt)); // Just pass everything down } return(asmStmnt); }
public override AASTNode Annotate(ASTNode astNode, AASTNode?parent) { AASTNode expr = new AASTNode(astNode, parent, SemanticAnalyzer.no_type); List <ASTNode> children = astNode.Children; Context ctx = SemanticAnalyzer.FindParentContext(parent); // Special case -1: if we have constant expression - calculate it and return literal instead // ATTENTION: need to be tested. UPD: it's okay if (SemanticAnalyzer.IsExprConstant(astNode, ctx)) { int exprValue = SemanticAnalyzer.CalculateConstExpr(astNode, ctx); ASTNode number = new ASTNode(expr, new List <ASTNode>(), expr.Token, "NUMBER"); ASTNode opMinus = new ASTNode(number, new List <ASTNode>(), expr.Token, "[ - ]"); if (exprValue < 0) { opMinus.Children.Add(new ASTNode(opMinus, new List <ASTNode>(), expr.Token, "OPERATOR")); exprValue *= -1; } number.Children.Add(opMinus); ASTNode literal = new ASTNode(number, new List <ASTNode>(), new Token(TokenType.NUMBER, exprValue.ToString(), expr.Token.Position), "SOME_LITERAL"); number.Children.Add(literal); expr.Children.Add(base.Annotate(number, expr)); return(expr); } // Special case 0: if we have "legal" or initial Expression from Syntax Analyzer if (astNode.Children.Count == 2 && astNode.Children[1].ASTType.Equals("{ Operator Operand }")) { children = astNode.Children[1].Children; children.Insert(0, astNode.Children[0]); } // Special case 1: only one operand if (children.Count == 1) { expr.Children.Add(base.Annotate(children[0], expr)); return(expr); } // Special case 2: operand, operator, and operand if (children.Count == 3) { foreach (var child in children) { expr.Children.Add(base.Annotate(child, expr)); } return(expr); } // If more, we need to rearrange the operands and operators to follow the operation priority // -- Gospod' dast - srabotaet -- // UPD: Gospod' smilovilsya nado mnoy, spasibo emu // Priority list List <string> ops = new List <string>() { "*", "+", "-", ">=", "<=", ">", "<", "=", "/=", "&", "^", "|", "?" }; foreach (string op in ops) { if (children.Count <= 3) { break; } for (int i = 1; i < children.Count; i += 2) // Iterate over operators { if (children[i].ASTType.Equals("Operator") && children[i].Token.Value.Equals(op)) { ASTNode child_expr = new ASTNode(astNode, new List <ASTNode>(), astNode.Token, "Expression"); // Create additional expression child_expr.Children.Add(children[i - 1]); child_expr.Children.Add(children[i]); child_expr.Children.Add(children[i + 1]); children.RemoveRange(i - 1, 3); children.Insert(i - 1, child_expr); i -= 2; } } } // Annotate modified AST and put it to expression foreach (ASTNode child in children) { expr.Children.Add(base.Annotate(child, expr)); } return(expr); }