Exemple #1
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);
        }
        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);
        }
        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);
        }