Esempio n. 1
0
        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);
        }