Ejemplo n.º 1
0
        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"))
Ejemplo n.º 2
0
        /// <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
Ejemplo n.º 5
0
        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);
        }
Ejemplo n.º 6
0
        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);
        }
Ejemplo n.º 7
0
        /// <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);
        }
Ejemplo n.º 9
0
        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);
        }
Ejemplo n.º 10
0
        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);
        }
Ejemplo n.º 15
0
        /// <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);
        }
Ejemplo n.º 16
0
        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);
        }
Ejemplo n.º 18
0
        /// <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);
        }
Ejemplo n.º 19
0
        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);
        }
Ejemplo n.º 20
0
        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);
        }
Ejemplo n.º 21
0
 /// <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);
        }
Ejemplo n.º 23
0
        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);
        }
Ejemplo n.º 24
0
        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);
        }
Ejemplo n.º 25
0
        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);
        }