Пример #1
0
 public UnaryOperandNode VisitUnaryOperand(UnaryOperandNode uon)
 {
     if (uon.Type == SymbolType.Identifier)
     {
         SymbolTableEntry entry = CheckThatIdentifierIsDeclaredAndGetEntry(uon.Value, uon.Token);
         if (entry.Type == SymbolType.IntegerValue && uon.Negative)
         {
             int v = ConvertStringToInteger(entry.Value, uon.Token);
             return(new UnaryOperandNode(OppositeOfInteger(v), entry.Type, uon.Token));
         }
         else if (entry.Type == SymbolType.Boolean && uon.Not)
         {
             string newValue;
             if (entry.Value == "true")
             {
                 newValue = "false";
             }
             else
             {
                 newValue = "true";
             }
             return(new UnaryOperandNode(newValue, SymbolType.Boolean, uon.Token));
         }
         return(new UnaryOperandNode(entry.Value, entry.Type, uon.Token));
     }
     else if (uon.Type == SymbolType.IntegerValue)
     {
         int value = ConvertStringToInteger(uon.Value, uon.Token);
         return(new UnaryOperandNode(value.ToString(), uon.Type, uon.Token, uon.Negative));
     }
     // Do not return the AST node. Create a copy
     return(new UnaryOperandNode(uon.Value, uon.Type, uon.Token, uon.Negative));
 }
Пример #2
0
        public void VisitForLoop(ForLoopNode fln)
        {
            fln.Assignment.Visit(this);
            string           op         = CreateOperatorToForLoopCondition(fln);
            UnaryOperandNode cond       = fln.Condition.Visit(this);
            UnaryOperandNode assignment = new UnaryOperandNode(
                this.symbolTable.GetEntry(cond.Token.Value).Value,
                SymbolType.IntegerValue,
                cond.Token
                );

            this.symbolTable.LockVariable(cond.Token.Value);
            while (cond.Type == SymbolType.Boolean && cond.Value == "true")
            {
                this.symbolTable.PushBlock();
                VisitStatements(fln);
                this.symbolTable.PopBlock();

                // Left value of BinaryExpression needs to be incremented by one (Has to be Identifier)
                assignment = HandleIntegerOperation(
                    assignment,
                    new UnaryOperandNode("1", SymbolType.IntegerValue, assignment.Token),
                    op
                    );
                this.symbolTable.ForceModifyEntry(cond.Token.Value, assignment.Value);
                cond = fln.Condition.Visit(this);
            }
            this.symbolTable.ReleaseVariable(cond.Token.Value);
        }
Пример #3
0
        public UnaryOperandNode VisitBinaryExpression(BinaryExpressionNode ben)
        {
            UnaryOperandNode left  = ben.Left.Visit(this);
            UnaryOperandNode right = ben.Right.Visit(this);

            return(HandleOperation(left, right, ben.Operator));
        }
Пример #4
0
        private UnaryOperandNode HandleBooleanOperation(UnaryOperandNode left, UnaryOperandNode right, string operation)
        {
            switch (operation)
            {
            case "=":
                if (left.Value == right.Value)
                {
                    return(new UnaryOperandNode("true", SymbolType.Boolean, left.Token));
                }
                else
                {
                    return(new UnaryOperandNode("false", SymbolType.Boolean, left.Token));
                }

            case "&":
                if (left.Value == right.Value && left.Value == "true")
                {
                    return(new UnaryOperandNode("true", SymbolType.Boolean, left.Token));
                }
                else
                {
                    return(new UnaryOperandNode("false", SymbolType.Boolean, left.Token));
                }

            default:
                throw new Error($"Illegal Operation: Can not do operation {operation} between Booleans", left.Token);
            }
        }
Пример #5
0
        public UnaryOperandNode VisitUnaryOperand(UnaryOperandNode uon)
        {
            int    temp   = this.depth;
            string spaces = IncreaseDepth();

            this.io.WriteLine($"{spaces}UnaryOperand: (\n{spaces}  Value: {uon.Value},\n{spaces}  Type: {uon.Type},\n{spaces}  Token: {uon.Token},\n{spaces}  Negative: {uon.Negative},\n{spaces}  Not: {uon.Not}\n{spaces})");
            this.depth = temp;
            return(new UnaryOperandNode("", SymbolType.Invalid));
        }
Пример #6
0
        private UnaryOperandNode HandleDifferentTypeOperation(UnaryOperandNode left, UnaryOperandNode right, string operation)
        {
            switch (operation)
            {
            case "+":
                if (left.Type == SymbolType.StringValue || right.Type == SymbolType.StringValue)
                {
                    return(new UnaryOperandNode($"{left.Value}{right.Value}", SymbolType.StringValue, left.Token));
                }
                throw new Error($"Illegal Operation: Can not add {left.Type} to {right.Type}", left.Token);

            default:
                throw new Error($"Illegal Operation: Can not do operation {operation} between {left.Type} and {right.Type}", left.Token);
            }
        }
Пример #7
0
        public void VisitAssignment(AssignmentNode an)
        {
            SymbolType typeOfIdentifier = CheckThatIdentifierIsDeclaredAndGetEntry(an.Identifier, an.Token).Type;

            UnaryOperandNode expression = an.Expression.Visit(this);

            if (typeOfIdentifier != expression.Type)
            {
                throw new Error($"Illegal Assignment: Can not assign {expression.Type} to variable {an.Identifier}, because it is a {typeOfIdentifier}", expression.Token);
            }
            if (!this.symbolTable.ModifyEntry(an.Identifier, expression.Value))
            {
                throw new Error($"Illegal Assignment: Can not assign to variable {an.Identifier}, because it is used in For Loop", expression.Token);
            }
        }
Пример #8
0
        public UnaryOperandNode VisitExpressionOperand(ExpressionOperandNode eon)
        {
            UnaryOperandNode node = eon.Expression.Visit(this);

            if (node.Type == SymbolType.IntegerValue)
            {
                if (eon.Not)
                {
                    throw new Error($"Can not have ! in front of an expression that returns {node.Type}", node.Token);
                }
                if (eon.Negative)
                {
                    int v = ConvertStringToInteger(node.Value, node.Token);
                    node.Value = OppositeOfInteger(v);
                }
            }
            else if (node.Type == SymbolType.Boolean)
            {
                if (eon.Negative)
                {
                    throw new Error($"Can not have a - in front of an expression that returns {node.Type}", node.Token);
                }
                if (eon.Not)
                {
                    if (node.Value == "true")
                    {
                        node.Value = "false";
                    }
                    else
                    {
                        node.Value = "true";
                    }
                }
            }
            else
            {
                if (eon.Negative)
                {
                    throw new Error($"Can not have a - in front of an expression that returns {node.Type}", node.Token);
                }
                if (eon.Not)
                {
                    throw new Error($"Can not have ! in front of an expression that returns {node.Type}", node.Token);
                }
            }
            return(node);
        }
Пример #9
0
        private UnaryOperandNode HandleStringOperation(UnaryOperandNode left, UnaryOperandNode right, string operation)
        {
            switch (operation)
            {
            case "+":
                return(new UnaryOperandNode(left.Value + right.Value, SymbolType.StringValue, left.Token));

            case "=":
                if (left.Value == right.Value)
                {
                    return(new UnaryOperandNode("true", SymbolType.Boolean, left.Token));
                }
                return(new UnaryOperandNode("false", SymbolType.Boolean, left.Token));

            default:
                throw new Error($"Illegal Operation: Strings can only be concatenated with + operator", left.Token);
            }
        }
Пример #10
0
        /***************** HELPER METHODS *************************/

        private string CreateOperatorToForLoopCondition(ForLoopNode fln)
        {
            UnaryOperandNode left  = fln.Condition.Left.Visit(this);
            UnaryOperandNode right = fln.Condition.Right.Visit(this);
            UnaryOperandNode res   = HandleIntegerOperation(left, right, ">");
            string           op    = "+";

            if (res.Value == "true")
            {
                fln.Condition.Operator = ">=";
                op = "-";
            }
            else
            {
                fln.Condition.Operator = "<=";
            }
            return(op);
        }
Пример #11
0
 private UnaryOperandNode HandleOperation(UnaryOperandNode left, UnaryOperandNode right, string operation)
 {
     if (left.Type == right.Type && left.Type == SymbolType.StringValue)
     {
         return(HandleStringOperation(left, right, operation));
     }
     if (left.Type == right.Type && left.Type == SymbolType.IntegerValue)
     {
         return(HandleIntegerOperation(left, right, operation));
     }
     if (left.Type == right.Type && left.Type == SymbolType.Boolean)
     {
         return(HandleBooleanOperation(left, right, operation));
     }
     if (left.Type != right.Type)
     {
         return(HandleDifferentTypeOperation(left, right, operation));
     }
     throw new Error($"Unexpected Error occured..", left.Token);
 }
Пример #12
0
        public void VisitAssert(AssertNode an)
        {
            UnaryOperandNode node = an.Expression.Visit(this);

            if (node.Type == SymbolType.Boolean && node.Value == "false")
            {
                UnaryOperandNode left  = an.Expression.Left.Visit(this);
                UnaryOperandNode right = an.Expression.Right.Visit(this);
                string           op;
                string           message = "Assert was false.";
                if (right.Type != SymbolType.Invalid)
                {
                    // BinaryExpression
                    op      = an.Expression.Operator;
                    message = $"Assert was false. Received assert ({left.Value} {op} {right.Value})";
                }
                throw new Error(message, node.Token);
            }
            if (node.Type != SymbolType.Boolean)
            {
                throw new Error($"Expected Boolean value inside assert (Boolean). Instead found {node.Type}", node.Token);
            }
        }
Пример #13
0
        private Operand Operand()
        {
            // <opnd> ::= [Minus] <int> | <string> | [Minus | Exclamation] <var_ident> | [Minus | Exclamation] "(" expr ")"
            bool  negative = false;
            bool  not      = false;
            Token minus    = this.token;

            if (this.token.SymbolType == SymbolType.Minus)
            {
                negative   = true;
                this.token = this.scanner.NextToken();
            }
            else if (this.token.SymbolType == SymbolType.Exclamation)
            {
                not        = true;
                this.token = this.scanner.NextToken();
            }
            Operand o;

            switch (this.token.SymbolType)
            {
            case SymbolType.IntegerValue:
                if (not)
                {
                    throw new Error($"! is not allowed in front of an IntegerValue", minus);
                }
                if (negative)
                {
                    o = new UnaryOperandNode($"{Integer.minus}{this.token.Value}", this.token.SymbolType, minus);
                }
                else
                {
                    o = new UnaryOperandNode(this.token.Value, this.token.SymbolType, this.token);
                }
                this.token = this.scanner.NextToken();
                return(o);

            case SymbolType.StringValue:
                if (not)
                {
                    throw new Error($"! is not allowed in front of a StringValue", minus);
                }
                if (negative)
                {
                    throw new Error($"- is not allowed in front of a StringValue", minus);
                }
                o          = new UnaryOperandNode(this.token.Value, this.token.SymbolType, this.token);
                this.token = this.scanner.NextToken();
                return(o);

            case SymbolType.Identifier:
                if (not)
                {
                    o = new UnaryOperandNode(this.token.Value, this.token.SymbolType, this.token, false, true);
                }
                else if (negative)
                {
                    o = new UnaryOperandNode(this.token.Value, this.token.SymbolType, this.token, true);
                }
                else
                {
                    o = new UnaryOperandNode(this.token.Value, this.token.SymbolType, this.token);
                }
                this.token = this.scanner.NextToken();
                return(o);

            case SymbolType.LeftParenthesis:
                this.token = this.scanner.NextToken();
                Expression e = Expression();
                if (negative)
                {
                    o = new ExpressionOperandNode(e, true);
                }
                else if (not)
                {
                    o = new ExpressionOperandNode(e, false, true);
                }
                else
                {
                    o = new ExpressionOperandNode(e);
                }
                Match(SymbolType.RightParenthesis);
                return(o);

            default:
                throw new Error($"Unexpected token: {this.token.SymbolType}", this.token);
            }
        }
Пример #14
0
        public void VisitPrint(PrintNode prn)
        {
            UnaryOperandNode expr = prn.Expression.Visit(this);

            this.io.WriteLine(expr.Value);
        }
Пример #15
0
        private UnaryOperandNode HandleIntegerOperation(UnaryOperandNode left, UnaryOperandNode right, string operation)
        {
            int leftValue  = ConvertStringToInteger(left.Value, left.Token);
            int rightValue = ConvertStringToInteger(right.Value, right.Token);
            int result;

            switch (operation)
            {
            case "+":
                result = leftValue + rightValue;
                return(new UnaryOperandNode(result.ToString(), SymbolType.IntegerValue, left.Token));

            case "-":
                result = leftValue - rightValue;
                return(new UnaryOperandNode(result.ToString(), SymbolType.IntegerValue, left.Token));

            case "*":
                result = leftValue * rightValue;
                return(new UnaryOperandNode(result.ToString(), SymbolType.IntegerValue, left.Token));

            case "/":
                result = leftValue / rightValue;
                return(new UnaryOperandNode(result.ToString(), SymbolType.IntegerValue, left.Token));

            case "<":
                if (leftValue < rightValue)
                {
                    return(new UnaryOperandNode("true", SymbolType.Boolean, left.Token));
                }
                return(new UnaryOperandNode("false", SymbolType.Boolean, left.Token));

            case ">":
                if (leftValue > rightValue)
                {
                    return(new UnaryOperandNode("true", SymbolType.Boolean, left.Token));
                }
                return(new UnaryOperandNode("false", SymbolType.Boolean, left.Token));

            case "<=":
                if (leftValue <= rightValue)
                {
                    return(new UnaryOperandNode("true", SymbolType.Boolean, left.Token));
                }
                return(new UnaryOperandNode("false", SymbolType.Boolean, left.Token));

            case ">=":
                if (leftValue >= rightValue)
                {
                    return(new UnaryOperandNode("true", SymbolType.Boolean, left.Token));
                }
                return(new UnaryOperandNode("false", SymbolType.Boolean, left.Token));

            case "=":
                if (leftValue == rightValue)
                {
                    return(new UnaryOperandNode("true", SymbolType.Boolean, left.Token));
                }
                return(new UnaryOperandNode("false", SymbolType.Boolean, left.Token));

            default:
                throw new Error($"Can not do operation {operation} between two Integers", left.Token);
            }
        }