/// <summary> /// Checks the static semantic constraints of a BinOpNode. /// </summary> /// /// <returns>An ISemanticCheckValue.</returns> /// <param name="node">Node.</param> public ISemanticCheckValue VisitDeclarationNode(DeclarationNode node) { // check that the id property is ok IProperty property = getVariableProperty(node); if (property == voidProperty) { return(voidProperty); } VariableIdNode idNode = node.IDNode; // if the property is declared already, it's an error if (property.Declared) { analyzer.notifyError(new DeclarationError(idNode)); } else { // if it wasn't declared, now it is. property.Declared = true; // check the AssignNode node.AssignNode.Accept(this); } return(voidProperty); }
/// <summary> /// Parses a for-loop block. /// </summary> /// <returns>The next token.</returns> /// <param name="token">Token.</param> /// <param name="statementsNode">Statements node.</param> private Token ParseForLoop(Token token, StatementsNode statementsNode) { // first we prepare the ForLoopNode VariableIdNode idNode = nodeBuilder.CreateIdNode(); ForLoopNode forLoop = nodeBuilder.CreateForLoopNode(idNode, statementsNode, token); Token next = null; try { // then we try to parse the control variables that handle the accumulation and // condition checking every time at the beginning of every loop next = ParseForLoopControl(forLoop, token); } catch (UnexpectedTokenException ex) { // fastforward to a safe spot if (ex.Token.Type == TokenType.END_OF_BLOCK) { return(FastForwardToStatementEnd(ex)); } notifyError(new SyntaxError(ex.Token, ex.ExpectedType, ex.ExpectationSet)); next = FastForwardTo(ParserConstants.BLOCK_DEF_FASTFORWARD_TO, ex.Token); } try { // now we parse the statements that are executed during each loop next = ParseForLoopStatements(forLoop, next); } catch (UnexpectedTokenException ex) { return(FastForwardToStatementEnd(ex)); } // finally, parse the loop finalization return(ParseForLoopEndBlock(forLoop, next)); }
/// <summary> /// Parses a variable's type into a VariableIdNode and adds the variable to the symbol table. /// </summary> /// <returns>The next token.</returns> /// <param name="token">Token.</param> /// <param name="idNode">Identifier node.</param> private Token ParseType(Token token, VariableIdNode idNode) { // In case the symbol table already contains the variable, we don't try ro add it twice. // This would of course be an error since it means the declaration for this variable // has already been made earlier, but this will be handled during the semantic analysis. if (!symbolTable.ContainsKey(idNode.ID)) { switch (token.Type) { case TokenType.INT_VAR: // set the id node's type idNode.VariableType = TokenType.INT_VAL; // add the id to the symbol table, with its value set to default value symbolTable.Add(idNode.ID, (new IntegerProperty(SemanticAnalysisConstants.DEFAULT_INTEGER_VALUE))); break; case TokenType.STR_VAR: idNode.VariableType = TokenType.STR_VAL; symbolTable.Add(idNode.ID, new StringProperty(SemanticAnalysisConstants.DEFAULT_STRING_VALUE)); break; case TokenType.BOOL_VAR: idNode.VariableType = TokenType.BOOL_VAL; symbolTable.Add(idNode.ID, new BooleanProperty(SemanticAnalysisConstants.DEFAULT_BOOL_VALUE)); break; default: throw new UnexpectedTokenException(token, TokenType.UNDEFINED, ParserConstants.EXPECTATION_SET_DECLARATION_TYPE); } } return(scanner.getNextToken(token)); }
public ForLoopNode(VariableIdNode idNode, Dictionary <string, IProperty> symbolTable, Token token) { this.idNode = idNode; this.token = token; this.indexAccumulator = createIndexAccumulator(idNode, symbolTable, token); }
/// <summary> /// Checks the static semantic constraints of an AssignNode. /// </summary> /// <returns>An ISemanticCheckValue.</returns> /// <param name="node">Node.</param> public ISemanticCheckValue VisitAssignNode(AssignNode node) { // Check that the id property in this AssignNode is ok. IProperty property = getVariableProperty(node); // if the property was voidProperty, return at this point, // an error has been reported already if (property == voidProperty) { return(voidProperty); } VariableIdNode idNode = node.IDNode; // check that the id variable is declared checkPropertyDeclared(idNode, property, true); // check that the id property we should be assigning to is not constant // at this point of its lifecycle (i.e. not a current block's control variable) if (property.Constant) { analyzer.notifyError(new IllegalAssignmentError(node)); } // evaluate the type of this property IProperty evaluated = node.Accept(this.typeChecker).asProperty(); // check the type of the expression in the assign node matches the one in the symbol table if (!checkPropertyType(property, evaluated.GetTokenType())) { analyzer.notifyError(new IllegalTypeError(idNode)); } return(voidProperty); }
/// <summary> /// Checks the static semantic constraints of a ForLoopNode. /// </summary> /// <returns>An ISemanticCheckValue.</returns> /// <param name="node">Node.</param> public ISemanticCheckValue VisitForLoopNode(ForLoopNode node) { // check that the id property is ok IProperty property = getVariableProperty(node); if (property == voidProperty) { return(voidProperty); } VariableIdNode controlVariable = node.IDNode; // check that the control variable is declared checkPropertyDeclared(node, property, true); // check that the control variable's type is integer if (property.GetTokenType() != TokenType.INT_VAL) { analyzer.notifyError(new IllegalTypeError(controlVariable)); } // set the control variable as static so any attempts to assign new value // to it inside the loop reports an error analyzer.SymbolicTable [controlVariable.ID].Constant = true; IExpressionNode max = node.MaxValue; // check that the expression that defines the maximum value of the control variable // exists and evaluates to an integer if (max == null) { analyzer.notifyError(new NullPointerError(node)); } else { IProperty maxProperty = max.Accept(this.typeChecker).asProperty(); if (!checkPropertyType(maxProperty, TokenType.INT_VAL)) { analyzer.notifyError(new IllegalTypeError(max)); } } // check that the assingment that sets the control variables initial value // evaluates to an integer IProperty rangeFromProperty = node.RangeFrom.Accept(this.typeChecker).asProperty(); if (!checkPropertyType(rangeFromProperty, TokenType.INT_VAL)) { analyzer.notifyError(new IllegalTypeError(node.RangeFrom)); } // check the statements of this for loop node.Statements.Accept(this); // the control variable needs not to ba constant any more analyzer.SymbolicTable [controlVariable.ID].Constant = false; return(voidProperty); }
public IOReadNode CreateIOReadNode(VariableIdNode idNode, StatementsNode statementsNode, Token t) { IOReadNode ioReadNode = new IOReadNode(idNode, symbolTable, t); statementsNode.Statement = ioReadNode; return(ioReadNode); }
public ForLoopNode CreateForLoopNode(VariableIdNode idNode, StatementsNode statementsNode, Token t) { ForLoopNode node = new ForLoopNode(idNode, symbolTable, t); statementsNode.Statement = node; return(node); }
public AssignNode CreateAssignNode(VariableIdNode idNode, StatementsNode statementsNode, Token t) { AssignNode assignNode = new AssignNode(idNode, symbolTable, t); statementsNode.Statement = assignNode; return(assignNode); }
public AssignNode CreateAssignNode(VariableIdNode idNode, Token t) { if (idNode.Token == null) { idNode.Token = t; } return(new AssignNode(idNode, symbolTable, t)); }
public IExpressionNode CreateIdNode(Token t, IExpressionContainer parent) { VariableIdNode node = new VariableIdNode(t.Value, symbolTable, t); parent.AddExpression(node); return(node); }
public DeclarationNode CreateDeclarationNode(VariableIdNode idNode, StatementsNode statementsNode, Token t) { DeclarationNode declarationNode = new DeclarationNode(idNode, symbolTable, t); declarationNode.AssignNode = CreateAssignNode(idNode, t); statementsNode.Statement = declarationNode; return(declarationNode); }
/// <summary> /// Visits the assign node. /// </summary> /// <returns>An ISemanticCheckValue.</returns> /// <param name="node">Node.</param> public ISemanticCheckValue VisitAssignNode(AssignNode node) { // assign the idNode's value to the one in the expression node VariableIdNode idNode = node.IDNode; IProperty assignValue = node.ExprNode.Accept(this).asProperty(); symbolTable [idNode.ID] = assignValue; return(voidProperty); }
/// <summary> /// Parses a read statement into an IOReadNode. /// </summary> /// <returns>The next token</returns> /// <param name="token">Token.</param> /// <param name="statementsNode">A StatementsNode.</param> private Token ParseRead(Token token, StatementsNode statementsNode) { try { VariableIdNode varId = nodeBuilder.CreateIdNode(); // create the IOReadNode and affiliate it with the statementsNode nodeBuilder.CreateIOReadNode(varId, statementsNode, token); // parses the variable id that the read operation's value is saved to return(ParseVarId(scanner.getNextToken(token), varId)); } catch (UnexpectedTokenException ex) { return(FastForwardToStatementEnd(ex)); } }
private AssignNode createIndexAccumulator(VariableIdNode idNode, Dictionary <string, IProperty> symbolTable, Token token) { AssignNode accumulator = new AssignNode(idNode, symbolTable, token); BinOpNode accumulationOperation = new BinOpNode(token); accumulationOperation.Operation = TokenType.BINARY_OP_ADD; accumulationOperation.AddExpression(idNode); accumulationOperation.AddExpression(new IntValueNode(1, token)); accumulator.ExprNode = accumulationOperation; return(accumulator); }
/// <summary> /// Parses a variable id into a VariableIdNode /// </summary> /// <returns>The next token.</returns> /// <param name="token">Token.</param> /// <param name="idNode">An IdentifierNode.</param> private Token ParseVarId(Token token, VariableIdNode idNode) { switch (token.Type) { case TokenType.ID: idNode.ID = token.Value; idNode.Token = token; return(scanner.getNextToken(token)); default: throw new UnexpectedTokenException(token, TokenType.ID, null); } }
/// <summary> /// Visits the variable identifier node. /// </summary> /// <returns>An ISemanticCheckValue.</returns> /// <param name="node">Node.</param> public ISemanticCheckValue VisitVariableIdNode(VariableIdNode node) { // The IProperty interface that all the different Property classes // implement implements itself the ISemanticValue interface and can // returned themselves. // Primarily, return the property found in the symbolic table if (analyzer.SymbolicTable.ContainsKey(node.ID)) { return(analyzer.SymbolicTable[node.ID]); } // otherwise, return an error property analyzer.notifyError(new UninitializedVariableError(node)); return(new ErrorProperty()); }
/// <summary> /// Parses an assign statement. /// </summary> /// <returns>The next token.</returns> /// <param name="token">Token.</param> /// <param name="statementsNode">Statements node.</param> private Token ParseVariableAssign(Token token, StatementsNode statementsNode) { try { VariableIdNode idNode = nodeBuilder.CreateIdNode(); // parse the target id Token next = ParseVarId(token, idNode); match(next, TokenType.ASSIGN); AssignNode assignNode = nodeBuilder.CreateAssignNode(idNode, statementsNode, token); // parses the expression of the assignment return(ParseExpression(scanner.getNextToken(next), assignNode)); } catch (UnexpectedTokenException ex) { return(FastForwardToStatementEnd(ex)); } }
/// <summary> /// Parses for-loop control block. /// </summary> /// <returns>The next token.</returns> /// <param name="forLoop">ForLoopNode.</param> /// <param name="token">Token.</param> private Token ParseForLoopControl(ForLoopNode forLoop, Token token) { VariableIdNode idNode = forLoop.IDNode; // first, parse the id that holds the accumulator value Token next = ParseVarId(scanner.getNextToken(token), idNode); match(next, TokenType.RANGE_FROM); // second, parse the start index as an assignment for the accumulator id forLoop.RangeFrom = nodeBuilder.CreateAssignNode(idNode, next); next = ParseExpression(scanner.getNextToken(next), forLoop.RangeFrom); match(next, TokenType.RANGE_UPTO); // third, parse the maximum value of the index next = ParseExpression(scanner.getNextToken(next), forLoop); match(next, TokenType.START_BLOCK); return(next); }
/// <summary> /// Visits for loop node. /// </summary> /// <returns>An ISemanticCheckValue.</returns> /// <param name="node">Node.</param> public ISemanticCheckValue VisitForLoopNode(ForLoopNode node) { // evaluate the maximum value of the loop's control id int max = node.MaxValue.Accept(this).asProperty().asInteger(); // set the control variable's value to the start index node.RangeFrom.Accept(this); VariableIdNode idNode = node.IDNode; // while the max index value is not reached while (idNode.Accept(this).asProperty().asInteger() <= max) { // execute the statements node.Statements.Accept(this); // call for the accumulator to accumulate the control variable's value node.Accumulator.Accept(this); } return(voidProperty); }
/// <summary> /// Visits the variable identifier node. /// </summary> /// <returns>An ISemanticCheckValue.</returns> /// <param name="node">Node.</param> public ISemanticCheckValue VisitVariableIdNode(VariableIdNode node) { // return a copy of the variable's current value in the symbol table IProperty idProperty = symbolTable [node.ID]; switch (idProperty.GetTokenType()) { case TokenType.INT_VAL: return(new IntegerProperty(idProperty.asInteger())); case TokenType.STR_VAL: return(new StringProperty(idProperty.asString())); case TokenType.BOOL_VAL: return(new BooleanProperty(idProperty.asBoolean())); default: throw new ArgumentException(); } }
/// <summary> /// Parses a declaration statement. /// </summary> /// <returns>The next token.</returns> /// <param name="token">Token.</param> /// <param name="statementsNode">A StatementsNode.</param> private Token ParseDeclaration(Token token, StatementsNode statementsNode) { // Try to parse all the pieces that a DeclarationNode needs to be evaluated. try { VariableIdNode idNode = nodeBuilder.CreateIdNode(); // parse the target id Token next = ParseVarId(scanner.getNextToken(token), idNode); match(next, TokenType.SET_TYPE); // parse the id's type next = ParseType(scanner.getNextToken(next), idNode); // create the actual DeclarationNode DeclarationNode declarationNode = nodeBuilder.CreateDeclarationNode(idNode, statementsNode, token); // parse the assign for the DeclarationNode return(ParseAssign(next, declarationNode.AssignNode)); } catch (UnexpectedTokenException ex) { return(FastForwardToStatementEnd(ex)); } }
/// <summary> /// Adds a new identifier to the symbol table. /// </summary> /// <param name="idNode">Identifier node.</param> private void addNewId(VariableIdNode idNode) { // add the id to the symbol table and set its value to default switch (idNode.VariableType) { case TokenType.INT_VAL: symbolTable [idNode.ID] = new IntegerProperty(SemanticAnalysisConstants.DEFAULT_INTEGER_VALUE); break; case TokenType.STR_VAL: symbolTable [idNode.ID] = new StringProperty(SemanticAnalysisConstants.DEFAULT_STRING_VALUE); break; case TokenType.BOOL_VAL: symbolTable [idNode.ID] = new BooleanProperty(SemanticAnalysisConstants.DEFAULT_BOOL_VALUE); break; default: throw new RuntimeException(ErrorConstants.RUNTIME_ERROR_MESSAGE, idNode.Token); } }
/// <summary> /// Checks the static semantic constraints of an IOReadNode. /// </summary> /// <returns>An ISemanticCheckValue.</returns> /// <param name="node">Node.</param> public ISemanticCheckValue VisitIOReadNode(IOReadNode node) { // check that the id property is ok IProperty property = getVariableProperty(node); if (property == voidProperty) { return(voidProperty); } VariableIdNode idNode = node.IDNode; // check that the variable we're about to read into is declared checkPropertyDeclared(node, property, true); // check that we don't try to read a boolean value if (checkPropertyType(property, TokenType.BOOL_VAL)) { analyzer.notifyError(new IllegalTypeError(idNode)); } return(voidProperty); }
/// <summary> /// A private helper method to check for an IIdentifierContainer's /// VariableIdNode. /// </summary> /// <returns>An IProperty.</returns> /// <param name="node">Node.</param> private IProperty getVariableProperty(IIdentifierContainer node) { // if the variable node is not set, report an error and return // a VoidProperty to signal this one doesn't evaluate if (node.IDNode == null) { analyzer.notifyError(new UninitializedVariableError(node)); return(voidProperty); } VariableIdNode idNode = node.IDNode; // check the evaluation type of the id node IProperty property = idNode.Accept(this.typeChecker).asProperty(); // if it wasn't declared, report an error if (property.GetTokenType() == TokenType.ERROR) { analyzer.notifyError(new UninitializedVariableError(node)); return(voidProperty); } return(property); }
public AssignNode(VariableIdNode idNode, Dictionary <string, IProperty> symbolTable, Token token) { this.idNode = idNode; this.exprNode = null; this.token = token; }
public AssignNode(VariableIdNode idNode, Dictionary <string, IProperty> symbolTable) : this(idNode, symbolTable, null) { }
/// <summary> /// Visits the variable identifier node. /// </summary> /// <returns>An ISemanticCheckValue.</returns> /// <param name="node">Node.</param> public ISemanticCheckValue VisitVariableIdNode(VariableIdNode node) { // let the evaluator evaluate this node return(node.Accept(evaluator)); }
/// <summary> /// Checks the static semantic constraints of a VariableIdNode. /// </summary> /// <returns>The variable identifier node.</returns> /// <param name="node">An ISemanticCheckValue.</param> public ISemanticCheckValue VisitVariableIdNode(VariableIdNode node) { // This is not a statement so it needs not to be actually checked here. // So, we pass it to the TypeCheckerVisitor instead. return(voidProperty); }
public IOReadNode(VariableIdNode idNode, Dictionary <string, IProperty> symbolTable, Token t) { this.idNode = idNode; this.assignNode = new AssignNode(this.idNode, symbolTable, t); this.token = t; }