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)); }
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); }
public UnaryOperandNode VisitBinaryExpression(BinaryExpressionNode ben) { UnaryOperandNode left = ben.Left.Visit(this); UnaryOperandNode right = ben.Right.Visit(this); return(HandleOperation(left, right, ben.Operator)); }
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); } }
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)); }
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); } }
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); } }
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); }
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); } }
/***************** 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); }
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); }
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); } }
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); } }
public void VisitPrint(PrintNode prn) { UnaryOperandNode expr = prn.Expression.Visit(this); this.io.WriteLine(expr.Value); }
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); } }