/// <summary> /// Constructs a Code Node with asm commands representing a heap top modification on a given offset. /// </summary> /// <param name="parent">Parent Code Node</param> /// <param name="offset">How much we can change heap top</param> /// <param name="useAsReg">It this true, 'offset' would be considered as register number and /// instead of constant heap top change, execution-time change commands would be generated</param> /// <param name="decrease">If 'useAsReg' is true, defines whether we allocating heap memory or deallocating ('decrease = true' means allocation)</param> /// <returns></returns> protected CodeNode GetHeapTopChangeNode(CodeNode?parent, int offset, bool useAsReg = false, bool decrease = true) { CodeNode heapTopNode = new CodeNode("Heap top change by " + (useAsReg ? (decrease ? ("-R" + offset) : ("+R" + offset)) : offset.ToString()) + " bytes", parent) .Add(GenerateLDC(0, 27)) .Add(GenerateLD(27, 27)); if (useAsReg) { if (decrease) { heapTopNode.Add(GenerateSUB(offset, 27)); // When we load the heap } else { heapTopNode.Add(GenerateADD(offset, 27)); // When we free the heap } } else { heapTopNode.Add(GenerateLDA(27, 27, offset)); } heapTopNode .Add(GenerateLDC(0, SB)) .Add(GenerateST(27, SB)) .Add(GenerateLDC(4, SB)); // Tricky trick return(heapTopNode); }
/// <summary> /// Constructs a Code Node that has generated binary code of loading a given variable address (on the stack) to the given register. /// </summary> /// <param name="parent">Parent Code Node.</param> /// <param name="varName">Variable name which address is to be loaded into register.</param> /// <param name="reg">Register to load to given variable address.</param> /// <param name="ctx">Current context.</param> /// <returns>Constructed Code Node that represents binary code that loads given variable address to the given register.</returns> protected CodeNode GetLoadVariableAddressNode(CodeNode?parent, string varName, byte reg, Context?ctx) { CodeNode loadVarNode = new CodeNode("Load variable address \'" + varName + "\' into R" + reg.ToString(), parent); if (ctx.IsVarGlobal(varName)) { loadVarNode .Add(GenerateLDA(SB, 27, ctx.GetStaticOffset(varName))) .Add(GenerateMOV(27, reg)); } else { int blockOffset = ctx.GetVarDeclarationBlockOffset(varName); loadVarNode.Add(GenerateMOV(FP, 27)); for (int i = 0; i < blockOffset; i++) { loadVarNode .Add(GenerateLDA(27, 27, -4)) .Add(GenerateLD(27, 27)); } loadVarNode .Add(GenerateLDA(27, 27, ctx.GetFrameOffset(varName))) .Add(GenerateMOV(27, reg)); } return(loadVarNode); }
void Language(StructuredReport report) { CodeNode language = new CodeNode(new CodedEntry("121049", "DCM", "Language of Content Item and Descendants")); language.Value = new CodedEntry("en", "RFC3066", "English"); report.Root.Add(language, RelationshipType.HasConceptModifier); CodeNode country = new CodeNode(new CodedEntry("121046", "DCM", "Country of Language")); country.Value = new CodedEntry("US", "ISO3166_1", "UNITED STATES"); language.Add(country, RelationshipType.HasConceptModifier); }
public override CodeNode Construct(AASTNode aastNode, CodeNode?parent) { Generator g = Program.currentCompiler.generator; CodeNode exprNode = new CodeNode(aastNode, parent); // 1) Store result of the left operand in FR0 CodeNode firstOpNode = base.Construct((AASTNode)aastNode.Children[0], exprNode); byte fr0 = firstOpNode.ByteToReturn; exprNode.Children.AddLast(firstOpNode); exprNode.ByteToReturn = fr0; if (aastNode.Children.Count > 1) { exprNode.OperandByte = fr0; // Update operand register // 2) Store result of the right operand in FR0/FR1 CodeNode secondOpNode = base.Construct((AASTNode)aastNode.Children[2], exprNode); byte fr1 = secondOpNode.ByteToReturn; exprNode.Children.AddLast(secondOpNode); // 3) Generate a code of the operation itself using these two register // and put an extra byte indicating the register with the result // (this byte is being removed upper in the call stack) string op = aastNode.Children[1].Token.Value; CodeNode operationNode = new CodeNode("Operation \'" + op + "\'", exprNode); switch (op) { // ATTENTION: What about command "format"? I use 32 everywhere. ANSWER: it's okay. case "+": { // FR0 += FR1; FR0 # In this case order does not matter operationNode.Add(GenerateADD(fr1, fr0)); exprNode.ByteToReturn = fr0; break; } case "-": { // FR0 -= FR1; FR0 operationNode.Add(GenerateSUB(fr1, fr0)); exprNode.ByteToReturn = fr0; break; } case ">=": { // FR2 := 1; // FR3 := <lsr>; // <lsr> // FR0 >= FR0; // FR1 -= FR2; // if FR1 goto FR3; // fr0 CodeNode fr2Node = GetFreeRegisterNode(aastNode, operationNode); operationNode.Children.AddLast(fr2Node); byte fr2 = fr2Node.ByteToReturn; CodeNode fr3Node = GetFreeRegisterNode(aastNode, operationNode); operationNode.Children.AddLast(fr3Node); byte fr3 = fr3Node.ByteToReturn; CodeNode lsrNode1 = new CodeNode("LSR cmds 1", operationNode) .Add(GenerateLDC(1, fr2)); CodeNode lsrNode2 = new CodeNode("LSR cmds 2", operationNode) .Add(GenerateLSR(fr0, fr0)) .Add(GenerateSUB(fr2, fr1)) .Add(GenerateCBR(fr1, fr3)); CodeNode lsrLabelDecl = new CodeNode("Label declaration", operationNode).Add(new byte[8]); lsrLabelDecl.ByteToReturn = fr3; CodeNode lsrLabel = new CodeNode("Label", operationNode); lsrLabel.LabelDecl = lsrLabelDecl; operationNode.Children.AddLast(lsrNode1); operationNode.Children.AddLast(lsrLabelDecl); operationNode.Children.AddLast(lsrLabel); operationNode.Children.AddLast(lsrNode2); exprNode.ByteToReturn = fr0; g.FreeReg(fr2); g.FreeReg(fr3); break; } case "<=": { // FR2 := 1; // FR3 := <lsr>; // <lsr> // FR0 >= FR0; // FR1 -= FR2; // if FR1 goto FR3; // fr0 CodeNode fr2Node = GetFreeRegisterNode(aastNode, operationNode); operationNode.Children.AddLast(fr2Node); byte fr2 = fr2Node.ByteToReturn; CodeNode fr3Node = GetFreeRegisterNode(aastNode, operationNode); operationNode.Children.AddLast(fr3Node); byte fr3 = fr3Node.ByteToReturn; CodeNode lslNode1 = new CodeNode("LSL cmds 1", operationNode) .Add(GenerateLDC(1, fr2)); CodeNode lslNode2 = new CodeNode("LSL cmds 2", operationNode) .Add(GenerateLSL(fr0, fr0)) .Add(GenerateSUB(fr2, fr1)) .Add(GenerateCBR(fr1, fr3)); CodeNode lslLabelDecl = new CodeNode("Label declaration", operationNode).Add(new byte[8]); lslLabelDecl.ByteToReturn = fr3; CodeNode lslLabel = new CodeNode("Label", operationNode); lslLabel.LabelDecl = lslLabelDecl; operationNode.Children.AddLast(lslNode1); operationNode.Children.AddLast(lslLabelDecl); operationNode.Children.AddLast(lslLabel); operationNode.Children.AddLast(lslNode2); exprNode.ByteToReturn = fr0; g.FreeReg(fr2); g.FreeReg(fr3); break; } case "&": { // FR0 &= FR1; FR0 operationNode.Add(GenerateAND(fr1, fr0)); exprNode.ByteToReturn = fr0; break; } case "|": { // FR0 |= FR1; FR0 operationNode.Add(GenerateOR(fr1, fr0)); exprNode.ByteToReturn = fr0; break; } case "^": { // FR0 ^= FR1; FR0 operationNode.Add(GenerateXOR(fr1, fr0)); exprNode.ByteToReturn = fr0; break; } case "?": { // FR0 ?= FR1; FR0 operationNode.Add(GenerateCND(fr1, fr0)); exprNode.ByteToReturn = fr0; break; } case "=": case "/=": case ">": case "<": { int mask = op.Equals("=") ? 4 : op.Equals("/=") ? 3 : op.Equals(">") ? 1 : op.Equals("<") ? 2 : 7; CodeNode fr2Node = GetFreeRegisterNode(aastNode, operationNode); operationNode.Children.AddLast(fr2Node); byte fr2 = fr2Node.ByteToReturn; // FR2 := mask; // FR1 ?= FR0; // FR2 &= FR1; // FR0 = 1; // FR1 = <true>; // if FR2 goto FR1; // FR0 := 0; // <true> // fr0 operationNode.Children.AddLast(new CodeNode("cond cmds 1", operationNode) .Add(GenerateLDC(mask, fr2)) .Add(GenerateCND(fr0, fr1)) .Add(GenerateAND(fr1, fr2)) .Add(GenerateLDC(1, fr0))); CodeNode labelDeclNode = new CodeNode("Label declaration", operationNode).Add(new byte[8]); labelDeclNode.ByteToReturn = fr1; CodeNode labelNode = new CodeNode("Label", operationNode); labelNode.LabelDecl = labelDeclNode; operationNode.Children.AddLast(labelDeclNode); operationNode.Children.AddLast(new CodeNode("cond cmds 2", operationNode) .Add(GenerateCBR(fr2, fr1)) .Add(GenerateLDC(0, fr0))); operationNode.Children.AddLast(labelNode); exprNode.ByteToReturn = fr0; g.FreeReg(fr2); break; } case "*": { // WHAT A MONSTROSITY! // ------------------- // FR2 := 0; // FR2 := FR2 + 32; // FR3 := mult (27); // FR4 := add (27); // FR5 := not_add (21); // FR6 := 1; # Mask // FR7 := 0; # For result // FR8 := 1; # For iteration // <mult> // FR9 := 0; # For loop exit // FR6 &= FR1; // if FR6 goto FR4; // if FR8 goto FR5; // <add> // FR7 += FR0; // <not_add> // FR6 := 1; // FR8 := 1; // FR0 <= FR0; // FR1 >= FR1; // FR2 -= FR8; // FR9 ?= FR2; // FR9 &= FR8; // if FR9 goto FR3; // FR0 := FR7; // fr0 // --- // Can be definitely optimized (in case of multiplying by power of 2, for example) CodeNode fr2Node = GetFreeRegisterNode(aastNode, operationNode); operationNode.Children.AddLast(fr2Node); byte fr2 = fr2Node.ByteToReturn; CodeNode fr3Node = GetFreeRegisterNode(aastNode, operationNode); operationNode.Children.AddLast(fr3Node); byte fr3 = fr3Node.ByteToReturn; CodeNode fr4Node = GetFreeRegisterNode(aastNode, operationNode); operationNode.Children.AddLast(fr4Node); byte fr4 = fr4Node.ByteToReturn; CodeNode fr5Node = GetFreeRegisterNode(aastNode, operationNode); operationNode.Children.AddLast(fr5Node); byte fr5 = fr5Node.ByteToReturn; CodeNode fr6Node = GetFreeRegisterNode(aastNode, operationNode); operationNode.Children.AddLast(fr6Node); byte fr6 = fr6Node.ByteToReturn; CodeNode fr7Node = GetFreeRegisterNode(aastNode, operationNode); operationNode.Children.AddLast(fr7Node); byte fr7 = fr7Node.ByteToReturn; CodeNode fr8Node = GetFreeRegisterNode(aastNode, operationNode); operationNode.Children.AddLast(fr8Node); byte fr8 = fr8Node.ByteToReturn; CodeNode fr9Node = GetFreeRegisterNode(aastNode, operationNode); operationNode.Children.AddLast(fr9Node); byte fr9 = fr9Node.ByteToReturn; operationNode.Children.AddLast(new CodeNode("mult 1", operationNode) .Add(GenerateLDC(0, fr2)) .Add(GenerateLDA(fr2, fr2, 32))); CodeNode fr3LabelDeclNode = new CodeNode("Label declaration", operationNode).Add(new byte[8]); fr3LabelDeclNode.ByteToReturn = fr3; CodeNode fr3LabelNode = new CodeNode("Label", operationNode); fr3LabelNode.LabelDecl = fr3LabelDeclNode; CodeNode fr4LabelDeclNode = new CodeNode("Label declaration", operationNode).Add(new byte[8]); fr4LabelDeclNode.ByteToReturn = fr4; CodeNode fr4LabelNode = new CodeNode("Label", operationNode); fr4LabelNode.LabelDecl = fr4LabelDeclNode; CodeNode fr5LabelDeclNode = new CodeNode("Label declaration", operationNode).Add(new byte[8]); fr5LabelDeclNode.ByteToReturn = fr5; CodeNode fr5LabelNode = new CodeNode("Label", operationNode); fr5LabelNode.LabelDecl = fr5LabelDeclNode; operationNode.Children.AddLast(fr3LabelDeclNode); operationNode.Children.AddLast(fr4LabelDeclNode); operationNode.Children.AddLast(fr5LabelDeclNode); operationNode.Children.AddLast(new CodeNode("mult 2", operationNode) .Add(GenerateLDC(1, fr6)) .Add(GenerateLDC(0, fr7)) .Add(GenerateLDC(1, fr8))); operationNode.Children.AddLast(fr3LabelNode); operationNode.Children.AddLast(new CodeNode("mult 3", operationNode) .Add(GenerateLDC(0, fr9)) .Add(GenerateAND(fr1, fr6)) .Add(GenerateCBR(fr6, fr4)) .Add(GenerateCBR(fr8, fr5))); operationNode.Children.AddLast(fr4LabelNode); operationNode.Children.AddLast(new CodeNode("mult 4", operationNode) .Add(GenerateADD(fr0, fr7))); operationNode.Children.AddLast(fr5LabelNode); operationNode.Children.AddLast(new CodeNode("mult 5", operationNode) .Add(GenerateLDC(1, fr6)) .Add(GenerateLDC(1, fr8)) .Add(GenerateLSL(fr0, fr0)) .Add(GenerateLSR(fr1, fr1)) .Add(GenerateSUB(fr8, fr2)) .Add(GenerateCND(fr2, fr9)) .Add(GenerateAND(fr8, fr9)) .Add(GenerateCBR(fr9, fr3)) .Add(GenerateMOV(fr7, fr0))); exprNode.ByteToReturn = fr0; g.FreeReg(fr2); g.FreeReg(fr3); g.FreeReg(fr4); g.FreeReg(fr5); g.FreeReg(fr6); g.FreeReg(fr7); g.FreeReg(fr8); g.FreeReg(fr9); break; } default: break; } exprNode.Children.AddLast(operationNode); // 4) Free the other register (the resulting register is freed upper in the call stack) g.FreeReg(fr1); } return(exprNode); }
public override CodeNode Construct(AASTNode aastNode, CodeNode?parent) { CodeNode programNode = new CodeNode(aastNode, parent); CodeNode vptNode = new CodeNode("Version/padding/tech bytes", programNode); // Used for simulator CodeNode staticNode = new CodeNode("Static bytes", programNode); // All static data CodeNode unitsNode = new CodeNode("Units' addresses node", programNode); // Code that puts proper unit addresses in static data CodeNode codeNode = new CodeNode("Actual program code", programNode); CodeNode skipStopNode = new CodeNode("Skip/Stop", programNode); programNode.Children.AddLast(vptNode); programNode.Children.AddLast(staticNode); programNode.Children.AddLast(unitsNode); programNode.Children.AddLast(codeNode); programNode.Children.AddLast(skipStopNode); staticNode.Add(GetConstBytes(Program.config.MemorySize)) .Add(GetLList(new byte[aastNode.AASTValue])); int staticLength = (staticNode.Count() + staticNode.Count() % 2) / 2; // We count in words (2 bytes) (???) DECISION: ok // Identify all data blocks beforehand and populate static data with its values foreach (AASTNode child in aastNode.Children) { if (child.ASTType.Equals("Data")) { LinkedList <byte> data = new LinkedList <byte>(); for (int i = 1; i < child.Children.Count; i++) { foreach (byte b in GetConstBytes(((AASTNode)child.Children[i]).AASTValue)) { data.AddLast(b); } } staticNode.Replace(aastNode.Context.GetStaticOffset(child.Children[0].Token.Value) + 4, data); } } // First unit offset - to store correct addresses inside static frame int techOffset = 16; // LDA(SB), LDA(SB + codeOffset), 27 = ->27, if 27 goto 27 // Identify all modules and routines int modulesAndRoutines = 0; foreach (AASTNode child in aastNode.Children) { if (child.ASTType.Equals("Routine") || child.ASTType.Equals("Module") || child.ASTType.Equals("Code")) { modulesAndRoutines++; } } techOffset += modulesAndRoutines * 16; CodeNode dummyNode = new CodeNode("dummy. Do not add it anywhere in a CodeNode tree. Used for label resolution.", null); unitsNode.Add(new byte[techOffset]); // Just fill bytes with zeros for a while (due to label resolution). // Identify all code data int staticSize = staticNode.Count(); int codeSize = 0; foreach (AASTNode child in aastNode.Children) { if (child.ASTType.Equals("Routine") || child.ASTType.Equals("Module") || child.ASTType.Equals("Code")) { dummyNode.Add(GenerateLDA(SB, 27, aastNode.Context.GetStaticOffset(child.Context.Name))) .Add(GenerateLDC(0, 26)) .Add(GenerateLDA(26, 26, staticSize + techOffset + codeSize)) .Add(GenerateST(26, 27)); } codeNode.Children.AddLast(base.Construct(child, codeNode)); codeSize += codeNode.Children.Last.Value.Count(); } unitsNode.Bytes.Clear(); unitsNode.Add(GenerateLDA(SB, SB, 4)); // Put the actual units' code after it has been processed unitsNode.Add(dummyNode.Bytes); // Go to code module uncoditionally unitsNode.Add(GenerateLDA(SB, 27, aastNode.Context.GetStaticOffset("code"))) .Add(GenerateLD(27, 27)) .Add(GenerateCBR(27, 27)); #region GOTO resolution List <CodeNode> gotoNodes = new List <CodeNode>(); FindAllCodeNodesWithName(programNode, "Goto", gotoNodes); foreach (CodeNode gotoNode in gotoNodes) { int ctxNum = -1; // minus one since Program context does not have a stack allocated. It is static or global. string labelName = gotoNode.AASTLink.Children[0].Token.Value; AASTNode mainContextNode = gotoNode.AASTLink; // If we jump from some contexts, we have to deallocate stack, heap, and other related memory while (true) { if (mainContextNode.Parent == null) { throw new CompilationErrorException("No label \'" + labelName + "\' found in the current context!!!\r\n" + " At (Line: " + gotoNode.AASTLink.Token.Position.Line + ", Char: " + gotoNode.AASTLink.Token.Position.Char + ")."); } if (mainContextNode.Context != null) { ctxNum++; if (mainContextNode.Context.IsVarDeclaredInThisContext(labelName)) { break; } gotoNode.Children.AddLast(GetDynamicMemoryDeallocationNode(mainContextNode, gotoNode)); if (mainContextNode.ASTType.Equals("For")) { gotoNode.Children.AddLast(GetHeapTopChangeNode(gotoNode, 16)); } if (mainContextNode.ASTType.Equals("While")) { gotoNode.Children.AddLast(GetHeapTopChangeNode(gotoNode, 12)); } if (mainContextNode.ASTType.Equals("Loop While")) { gotoNode.Children.AddLast(GetHeapTopChangeNode(gotoNode, 4)); } } mainContextNode = (AASTNode)mainContextNode.Parent; } for (int i = 0; i < ctxNum; i++) { gotoNode.Children.AddLast(new CodeNode("Return stack back", gotoNode) .Add(GenerateLDA(FP, FP, -4)) .Add(GenerateMOV(FP, SP)) .Add(GenerateLD(FP, FP))); } CodeNode?gotoLabelNode = gotoNode; while (true) { if (gotoLabelNode == null) { throw new CompilationErrorException("No label \'" + labelName + "\' found in the current context!!!\r\n" + " At (Line: " + gotoNode.AASTLink.Token.Position.Line + ", Char: " + gotoNode.AASTLink.Token.Position.Char + ")."); } bool found = false; foreach (CodeNode child in gotoLabelNode.Children) { if (child.Name.Equals("Statement") && child.Children.First.Value.Name.Equals("Goto label") && child.Children.First.Value.AASTLink.Children[0].Token.Value.Equals(labelName)) { gotoLabelNode = child.Children.First.Value; found = true; break; } } if (found) { break; } gotoLabelNode = gotoLabelNode.Parent; } CodeNode labelDecl = new CodeNode("Label declaration", gotoNode).Add(new byte[8]); labelDecl.ByteToReturn = 27; gotoNode.Children.AddLast(labelDecl); gotoNode.Children.AddLast(new CodeNode("goto jump", gotoNode).Add(GenerateCBR(27, 27))); CodeNode labelNode = new CodeNode("Label", gotoLabelNode); labelNode.LabelDecl = labelDecl; gotoLabelNode.Children.AddLast(labelNode); gotoLabelNode.Children.AddLast(GetRegisterAllocationNode((AASTNode)gotoLabelNode.AASTLink.Parent, gotoLabelNode)); } #endregion #region Label resolution /*List<CodeNode> labels = new List<CodeNode>(); * FindAllCodeNodesWithName(programNode, "Label", labels); * foreach (CodeNode label in labels) * { * int labelAddr = GetCurrentBinarySize(label); // Always the first child * label.LabelDecl.Bytes.Clear(); * label.LabelDecl.Add(GenerateLDL(label.LabelDecl.ByteToReturn, labelAddr)); * }*/ ResolveLabels(programNode); #endregion // Move code data by the static data length codeAddrBase += staticSize; int codeLength = (unitsNode.Count() + codeNode.Count() + codeNode.Count() % 2) / 2 + 2; // Convert static data and code lengths to chunks of four bytes vptNode.Add(0x00, 0x01); vptNode.Add(GetConstBytes(staticDataAddrBase)) .Add(GetConstBytes(staticLength)) .Add(GetConstBytes(codeAddrBase)) .Add(GetConstBytes(codeLength)); skipStopNode.Add(GenerateSKIP()).Add(GenerateSTOP()); return(programNode); }