/** * Parse a simple expression. * * @param token the initial token. * @return the root of the generated parse subtree. * @throws Exception if an error occurred. */ private ICodeNode parseSimpleExpression(Token token) throws Exception { TokenType signType = null; // type of leading sign (if any) // Look for a leading + or - sign. TokenType tokenType = token.getType(); if ((tokenType == PLUS) || (tokenType == MINUS)) { signType = tokenType; token = nextToken(); // consume the + or - } // Parse a term and make the root of its tree the root node. ICodeNode rootNode = parseTerm(token); // Was there a leading - sign? if (signType == MINUS) { // Create a NEGATE node and adopt the current tree // as its child. The NEGATE node becomes the new root node. ICodeNode negateNode = ICodeFactory.createICodeNode(NEGATE); negateNode.addChild(rootNode); rootNode = negateNode; } token = currentToken(); tokenType = token.getType(); // Loop over additive operators. while (ADD_OPS.contains(tokenType)) { // Create a new operator node and adopt the current tree // as its first child. ICodeNodeType nodeType = ADD_OPS_OPS_MAP.get(tokenType); ICodeNode opNode = ICodeFactory.createICodeNode(nodeType); opNode.addChild(rootNode); token = nextToken(); // consume the operator // Parse another term. The operator node adopts // the term's tree as its second child. opNode.addChild(parseTerm(token)); // The operator node becomes the new root node. rootNode = opNode; token = currentToken(); tokenType = token.getType(); } return rootNode; }
/** * Parse a set. * * @param token the initial token. * @return the root of the generated parse subtree. * @throws Exception if an error occurred. */ private ICodeNode parseSet(Token token) throws Exception { ICodeNode rootNode = ICodeFactory.createICodeNode(SETS); int tempInteger = 0; token = nextToken(); // consume left bracket while (token.getType() != RIGHT_BRACKET) { if (token.getType() == INTEGER) { tempInteger = (int) token.getValue(); rootNode.addChild(parseTerm(token)); token = currentToken(); } else if (token.getType() == IDENTIFIER) { ICodeNode var = parseFactor(token); rootNode.addChild(var); token = currentToken(); } if (token.getType() == COMMA) { token = nextToken(); // consume next token if (token.getType() == COMMA) { errorHandler.flag(token, EXTRA_COMMA, this); } } else if (token.getType() == RIGHT_BRACKET) { // do nothing } else if (token.getType() == SEMICOLON) { errorHandler.flag(token, MISSING_CLOSE_SQUARE_BRACKET, this); break; } else if (token.getType() == DOT_DOT) { token = nextToken(); // consume the integer. // Create a STRING_CONSTANT node as the root node. ICodeNode node = ICodeFactory.createICodeNode(SUBRANGE); // denotes the maximum value of the range. if (token.getType() != INTEGER) { errorHandler.flag(token, MISSING_MAX_VAL_SUBRANGE, this); } else { int value = (int) token.getValue(); node.setAttribute(VALUE, value); } rootNode.addChild(node); token = nextToken(); } else { errorHandler.flag(token, MISSING_COMMA, this); } } if (token.getType() != SEMICOLON) { token = nextToken(); // consume right bracket } return rootNode; }
/** * Parse an expression. * * @param token the initial token. * @return the root of the generated parse subtree. * @throws Exception if an error occurred. */ private ICodeNode parseExpression(Token token) throws Exception { // Parse a simple expression and make the root of its tree // the root node. ICodeNode rootNode = parseSimpleExpression(token); token = currentToken(); TokenType tokenType = token.getType(); // Look for a relational operator. if (REL_OPS.contains(tokenType)) { // Create a new operator node and adopt the current tree // as its first child. ICodeNodeType nodeType = REL_OPS_MAP.get(tokenType); ICodeNode opNode = ICodeFactory.createICodeNode(nodeType); opNode.addChild(rootNode); token = nextToken(); // consume the operator // Parse the second simple expression. The operator node adopts // the simple expression's tree as its second child. opNode.addChild(parseSimpleExpression(token)); // The operator node becomes the new root node. rootNode = opNode; } return rootNode; }
/** * Parse a term. * * @param token the initial token. * @return the root of the generated parse subtree. * @throws Exception if an error occurred. */ private ICodeNode parseTerm(Token token) throws Exception { // Parse a factor and make its node the root node. ICodeNode rootNode = parseFactor(token); token = currentToken(); TokenType tokenType = token.getType(); // Loop over multiplicative operators. while (MULT_OPS.contains(tokenType)) { // Create a new operator node and adopt the current tree // as its first child. ICodeNodeType nodeType = MULT_OPS_OPS_MAP.get(tokenType); ICodeNode opNode = ICodeFactory.createICodeNode(nodeType); opNode.addChild(rootNode); token = nextToken(); // consume the operator // Parse another factor. The operator node adopts // the term's tree as its second child. opNode.addChild(parseFactor(token)); // The operator node becomes the new root node. rootNode = opNode; token = currentToken(); tokenType = token.getType(); } return rootNode; }
/** * Parse a term. * * @param token the initial token. * @return the root of the generated parse subtree. * @throws Exception if an error occurred. */ private ICodeNode parseTerm(Token token) throws Exception { // Parse a factor and make its node the root node. ICodeNode rootNode = parseFactor(token); token = currentToken(); TokenType tokenType = token.getType(); if (rootNode.getType() == ICodeNodeTypeImpl.SET && (tokenType == PascalTokenType.OR || tokenType == PascalTokenType.AND)) { errorHandler.flag(token, INVALID_OPERATOR, this); } // Loop over multiplicative operators. while (MULT_OPS.contains(tokenType)) { // Create a new operator node and adopt the current tree // as its first child. ICodeNodeType nodeType = MULT_OPS_OPS_MAP.get(tokenType); ICodeNode opNode = ICodeFactory.createICodeNode(nodeType); opNode.addChild(rootNode); switch ((ICodeNodeTypeImpl) opNode.getType()) { case INTEGER_DIVIDE: case FLOAT_DIVIDE: if (rootNode.getType() == ICodeNodeTypeImpl.SET) { errorHandler.flag(token, INVALID_OPERATOR, this); } } token = nextToken(); // consume the operator // Parse another factor. The operator node adopts // the term's tree as its second child. opNode.addChild(parseFactor(token)); // The operator node becomes the new root node. rootNode = opNode; token = currentToken(); tokenType = token.getType(); } return rootNode; }
/** * Parse an expression. * * @param token the initial token. * @return the root of the generated parse subtree. * @throws Exception if an error occurred. */ private ICodeNode parseExpression(Token token) throws Exception { // Parse a simple expression and make the root of its tree // the root node. ICodeNode rootNode = parseSimpleExpression(token); token = currentToken(); TokenType tokenType = token.getType(); // Look for a relational operator. if (REL_OPS.contains(tokenType)) { // Create a new operator node and adopt the current tree // as its first child. ICodeNodeType nodeType = REL_OPS_MAP.get(tokenType); ICodeNode opNode = ICodeFactory.createICodeNode(nodeType); opNode.addChild(rootNode); ICodeNodeTypeImpl type = (ICodeNodeTypeImpl) opNode.getType(); if (type == LT || type == GT || type == IN_SET) { if (rootNode.getType() == ICodeNodeTypeImpl.SET) { errorHandler.flag(token, INVALID_OPERATOR, this); } } Token previousToken = token; token = nextToken(); // consume the operator // Parse the second simple expression. The operator node adopts // the simple expression's tree as its second child. ICodeNode rightNode = parseSimpleExpression(token); opNode.addChild(rightNode); if (opNode.getType() == IN_SET && rightNode.getType() == INTEGER_CONSTANT) { errorHandler.flag(previousToken, INVALID_OPERATOR, this); } // The operator node becomes the new root node. rootNode = opNode; } return rootNode; }
/** * Parse an expression * * @param token the initial token. * @return the root of the generated parse subtree. * @throws Exception if an error occurred. */ private ICodeNode parseExpression(Token token) throws Exception { // Parse a simple expression and make the root of its tree // the root node. ICodeNode rootNode = parseSimpleExpression(token); TypeSpec resultType = rootNode != null ? rootNode.getTypeSpec() : Predefined.undefinedType; token = currentToken(); TokenType tokenType = token.getType(); // Look for a relational operator. if (REL_OPS.contains(tokenType)) { // Create a new operator node and adopt the current tree as its first child ICodeNodeType nodeType = REL_OPS_MAP.get(tokenType); ICodeNode opNode = ICodeFactory.createICodeNode(nodeType); opNode.addChild(rootNode); token = nextToken(); // consume the operator // Parse the second simple expression. // The operator node adopts the simple expression's tree as its second child. ICodeNode simExprNode = parseSimpleExpression(token); opNode.addChild(simExprNode); // The operator node becomes the new root node. rootNode = opNode; // Type check: The operands must be comparison compatible. TypeSpec simExprType = simExprNode != null ? simExprNode.getTypeSpec() : Predefined.undefinedType; if (TypeChecker.areComparisionCompatible(resultType, simExprType)) resultType = Predefined.booleanType; else { errorHandler.flag(token, INCOMPATIBLE_TYPES, this); resultType = Predefined.undefinedType; } } if (rootNode != null) rootNode.setTypeSpec(resultType); return rootNode; }
/** * Parse a Triangle SingleDeclarationParser. * * <p>Single-Declaration ::= const Identifier ~ Expression | var Identifier : Type-Denoter | proc * Identifier (Formal-Parameter-Sequence) ~ Single-Command | func Identifier * (Formal-Parameter-Sequence) : Type-Denoter ~ Expression | Type Identifier ~ Type-Denoter * * <p>To be overridden by the specialized command parse subclasses. * * @param token the initial token. * @return the root node of the generated parse tree. * @throws Exception if an error occurred. */ public void parse(Token token) throws Exception { SingleCommandParser singleCommand = null; ExpressionParser expression = null; FormalParameterSequenceParser formalParameterSequence = null; TypeDenoterParser typeDenoter = null; EnumSet<TriangleTokenType> syncSet = null; TypeSpec identifierType = TrianglePredefined.undefinedType; Token identifierToken = null; ICode routineICode = null; token = currentToken(); switch ((TriangleTokenType) token.getType()) { case CONST: identifierToken = nextToken(); syncSet = EnumSet.of(TILDE); syncSet.addAll(ExpressionParser.FIRST_FOLLOW_SET); synchronize(IDENTIFIER, MISSING_IDENTIFIER, syncSet); syncSet.remove(TILDE); token = synchronize(TILDE, MISSING_TILDE, syncSet); expression = new ExpressionParser(this); ICodeNode expressionNode = expression.parse(token); SymTabEntry constantId = symTabStack.lookupLocal(identifierToken.getText().toLowerCase()); // Enter the new identifier into the symbol table // but don't set how it's defined yet. if (constantId == null) { constantId = symTabStack.enterLocal(identifierToken.getText().toLowerCase()); constantId.setDefinition(DefinitionImpl.CONSTANT); constantId.setAttribute(CONSTANT_VALUE, expressionNode); constantId.appendLineNumber(identifierToken.getLineNumber()); constantId.setTypeSpec(expressionNode.getTypeSpec()); } else { errorHandler.flag(identifierToken, IDENTIFIER_REDEFINED, this); } break; case VAR: identifierToken = nextToken(); syncSet = EnumSet.of(COLON); syncSet.addAll(TypeDenoterParser.FIRST_FOLLOW_SET); synchronize(IDENTIFIER, MISSING_IDENTIFIER, syncSet); syncSet.remove(COLON); token = synchronize(COLON, MISSING_COLON, syncSet); typeDenoter = new TypeDenoterParser(this); identifierType = typeDenoter.parse(token); SymTabEntry variableId = symTabStack.lookupLocal(identifierToken.getText().toLowerCase()); // Enter the new identifier into the symbol table // but don't set how it's defined yet. if (variableId == null) { variableId = symTabStack.enterLocal(identifierToken.getText().toLowerCase()); variableId.setDefinition(DefinitionImpl.VARIABLE); variableId.appendLineNumber(identifierToken.getLineNumber()); variableId.setTypeSpec(identifierType); } else { errorHandler.flag(identifierToken, IDENTIFIER_REDEFINED, this); } break; case PROC: identifierToken = nextToken(); routineICode = ICodeFactory.createICode(); syncSet = EnumSet.of(LEFT_PAREN); syncSet.addAll(FormalParameterSequenceParser.FIRST_FOLLOW_SET); token = synchronize(IDENTIFIER, MISSING_IDENTIFIER, syncSet); syncSet.remove(LEFT_PAREN); token = synchronize(LEFT_PAREN, MISSING_LEFT_PAREN, syncSet); SymTabEntry procId = symTabStack.lookupLocal(identifierToken.getText().toLowerCase()); // Enter the new identifier into the symbol table // but don't set how it's defined yet. if (procId == null) { procId = symTabStack.enterLocal(identifierToken.getText().toLowerCase()); procId.setTypeSpec(TrianglePredefined.undefinedType); procId.setDefinition(DefinitionImpl.PROCEDURE); procId.appendLineNumber(identifierToken.getLineNumber()); procId.setAttribute(ROUTINE_SYMTAB, symTabStack.push()); procId.setAttribute(ROUTINE_ICODE, routineICode); } else { errorHandler.flag(identifierToken, IDENTIFIER_REDEFINED, this); procId = null; } formalParameterSequence = new FormalParameterSequenceParser(this); ArrayList<SymTabEntry> procParamList = formalParameterSequence.parse(token); syncSet = EnumSet.of(TILDE); syncSet.addAll(SingleCommandParser.FIRST_FOLLOW_SET); token = synchronize(RIGHT_PAREN, MISSING_RIGHT_PAREN, syncSet); syncSet.remove(TILDE); token = synchronize(TILDE, MISSING_TILDE, syncSet); singleCommand = new SingleCommandParser(this); routineICode.setRoot(singleCommand.parse(token)); if (procId != null) { procId.setAttribute(ROUTINE_PARMS, procParamList); } symTabStack.pop(); break; case FUNC: identifierToken = nextToken(); routineICode = ICodeFactory.createICode(); SymTabEntry funcId = symTabStack.lookupLocal(identifierToken.getText().toLowerCase()); // Enter the new identifier into the symbol table // but don't set how it's defined yet. if (funcId == null) { funcId = symTabStack.enterLocal(identifierToken.getText().toLowerCase()); funcId.setDefinition(DefinitionImpl.FUNCTION); funcId.appendLineNumber(identifierToken.getLineNumber()); funcId.setTypeSpec(TrianglePredefined.undefinedType); funcId.setAttribute(ROUTINE_SYMTAB, symTabStack.push()); funcId.setAttribute(ROUTINE_ICODE, routineICode); } else { errorHandler.flag(identifierToken, IDENTIFIER_REDEFINED, this); funcId = null; } syncSet = EnumSet.of(LEFT_PAREN); syncSet.addAll(FormalParameterSequenceParser.FIRST_FOLLOW_SET); token = synchronize(IDENTIFIER, MISSING_IDENTIFIER, syncSet); syncSet.remove(LEFT_PAREN); token = synchronize(LEFT_PAREN, MISSING_LEFT_PAREN, syncSet); formalParameterSequence = new FormalParameterSequenceParser(this); ArrayList<SymTabEntry> funcParamList = formalParameterSequence.parse(token); syncSet = EnumSet.of(COLON); syncSet.addAll(TypeDenoterParser.FIRST_FOLLOW_SET); synchronize(RIGHT_PAREN, MISSING_RIGHT_PAREN, syncSet); syncSet.remove(COLON); token = synchronize(COLON, MISSING_COLON, syncSet); Token typeToken = currentToken(); typeDenoter = new TypeDenoterParser(this); TypeSpec funcType = typeDenoter.parse(token); syncSet = ExpressionParser.FIRST_FOLLOW_SET.clone(); token = synchronize(TILDE, MISSING_TILDE, syncSet); expression = new ExpressionParser(this); routineICode.setRoot(expression.parse(token)); if (funcId != null) { funcId.setTypeSpec(funcType); funcId.setAttribute(ROUTINE_PARMS, funcParamList); if (!routineICode.getRoot().getTypeSpec().equals(funcType)) { errorHandler.flag(typeToken, RETURN_TYPE_MISMATCH, this); } } symTabStack.pop(); break; case TYPE: identifierToken = nextToken(); syncSet = EnumSet.of(TILDE); syncSet.addAll(TypeDenoterParser.FIRST_FOLLOW_SET); synchronize(IDENTIFIER, MISSING_IDENTIFIER, syncSet); syncSet.remove(TILDE); token = synchronize(TILDE, MISSING_TILDE, syncSet); typeDenoter = new TypeDenoterParser(this); TypeSpec typeType = typeDenoter.parse(token); SymTabEntry typeId = symTabStack.lookupLocal(identifierToken.getText().toLowerCase()); // Enter the new identifier into the symbol table // but don't set how it's defined yet. if (typeId == null) { typeId = symTabStack.enterLocal(identifierToken.getText().toLowerCase()); typeId.setDefinition(DefinitionImpl.TYPE); typeId.appendLineNumber(identifierToken.getLineNumber()); typeId.setTypeSpec(typeType); } else { errorHandler.flag(token, IDENTIFIER_REDEFINED, this); } break; default: errorHandler.flag(token, MISSING_DECLARATION, this); break; } }
/** * Parse a factor. * * @param token the initial token. * @return the root of the generated parse subtree. * @throws Exception if an error occurred. */ private ICodeNode parseFactor(Token token) throws Exception { TokenType tokenType = token.getType(); ICodeNode rootNode = null; switch ((PascalTokenType) tokenType) { case IDENTIFIER: { // Look up the identifier in the symbol table stack. // Flag the identifier as undefined if it's not found. String name = token.getText().toLowerCase(); SymTabEntry id = symTabStack.lookup(name); if (id == null) { errorHandler.flag(token, IDENTIFIER_UNDEFINED, this); id = symTabStack.enterLocal(name); } rootNode = ICodeFactory.createICodeNode(VARIABLE); rootNode.setAttribute(ID, id); id.appendLineNumber(token.getLineNumber()); token = nextToken(); // consume the identifier break; } case INTEGER: { // Create an INTEGER_CONSTANT node as the root node. rootNode = ICodeFactory.createICodeNode(INTEGER_CONSTANT); rootNode.setAttribute(VALUE, token.getValue()); token = nextToken(); // consume the number break; } case REAL: { // Create an REAL_CONSTANT node as the root node. rootNode = ICodeFactory.createICodeNode(REAL_CONSTANT); rootNode.setAttribute(VALUE, token.getValue()); token = nextToken(); // consume the number break; } case STRING: { String value = (String) token.getValue(); // Create a STRING_CONSTANT node as the root node. rootNode = ICodeFactory.createICodeNode(STRING_CONSTANT); rootNode.setAttribute(VALUE, value); token = nextToken(); // consume the string break; } case NOT: { token = nextToken(); // consume the NOT // Create a NOT node as the root node. rootNode = ICodeFactory.createICodeNode(ICodeNodeTypeImpl.NOT); // Parse the factor. The NOT node adopts the // factor node as its child. rootNode.addChild(parseFactor(token)); break; } case LEFT_PAREN: { token = nextToken(); // consume the ( // Parse an expression and make its node the root node. rootNode = parseExpression(token); // Look for the matching ) token. token = currentToken(); if (token.getType() == RIGHT_PAREN) { token = nextToken(); // consume the ) } else { errorHandler.flag(token, MISSING_RIGHT_PAREN, this); } break; } case LEFT_BRACKET: { rootNode = parseSet(token); break; } default: { errorHandler.flag(token, UNEXPECTED_TOKEN, this); break; } } return rootNode; }
/** * Parse a set. * * @param token the initial token. * @return the root of the generated parse subtree. * @throws Exception if an error occurred. */ private ICodeNode parseSet(Token token) throws Exception { ICodeNode rootNode = ICodeFactory.createICodeNode(ICodeNodeTypeImpl.SET); HashSet<Integer> values = new HashSet<>(); rootNode.setAttribute(VALUE, new HashSet<Integer>()); boolean isFinished = false; while (token.getType() != RIGHT_BRACKET && token.getType() != ERROR && !isFinished) { ICodeNode leftNode = parseSimpleExpression(token); if (leftNode.getType() == INTEGER_CONSTANT && !values.add((Integer) leftNode.getAttribute(VALUE))) { errorHandler.flag(token, NON_UNIQUE_MEMBERS, this); } token = currentToken(); switch ((PascalTokenType) token.getType()) { case RIGHT_BRACKET: rootNode.addChild(leftNode); break; case COMMA: rootNode.addChild(leftNode); token = nextToken(); // Consume the , if (token.getType() == COMMA) { errorHandler.flag(token, EXTRA_COMMAS, this); token = nextToken(); // Consume the extra , } break; case DOT_DOT: token = nextToken(); // Consume the .. if (token.getType() == COMMA) { errorHandler.flag(token, INVALID_SUBRANGE, this); token = nextToken(); // Consume the , rootNode.addChild(leftNode); } else { ICodeNode rightNode = parseSimpleExpression(token); ICodeNode subrangeNode = ICodeFactory.createICodeNode(SUBRANGE); subrangeNode.addChild(leftNode); subrangeNode.addChild(rightNode); rootNode.addChild(subrangeNode); if (leftNode.getType() == INTEGER_CONSTANT && rightNode.getType() == INTEGER_CONSTANT) { boolean duplicateFound = false; Integer leftRange = (Integer) leftNode.getAttribute(VALUE) + 1; Integer rightRange = (Integer) rightNode.getAttribute(VALUE); while (leftRange <= rightRange) { if (!values.add(leftRange++) && !duplicateFound) { errorHandler.flag(token, NON_UNIQUE_MEMBERS, this); duplicateFound = true; } } } token = currentToken(); if (token.getType() == COMMA) { token = nextToken(); // Consume the , } else if (token.getType() != RIGHT_BRACKET) { errorHandler.flag(token, MISSING_COMMA, this); } } break; case INTEGER: errorHandler.flag(token, MISSING_COMMA, this); break; case SEMICOLON: isFinished = true; break; default: errorHandler.flag(token, UNEXPECTED_TOKEN, this); break; } } return rootNode; }
public SymTabEntry parse(Token token, SymTabEntry parentId) throws Exception { Token FunctionReturnToken = token; Definition routineDefn = null; String dummyName = null; SymTabEntry routineId = null; TokenType routineType = token.getType(); // Initialize. switch ((WookieTokenType) routineType) { case INT: { // save the int data type for use later FunctionReturnToken = token; token = nextToken(); // consume Int routineDefn = DefinitionImpl.FUNCTION; dummyName = "DummyProgramName".toLowerCase() + String.format("%03d", ++dummyCounter); break; } case CHAR: { // save the char data type for use later FunctionReturnToken = token; token = nextToken(); // consume Char routineDefn = DefinitionImpl.FUNCTION; dummyName = "DummyProgramName".toLowerCase() + String.format("%03d", ++dummyCounter); break; } case VOID: { // save the void data type for use later FunctionReturnToken = token; token = nextToken(); // consume PROGRAM routineDefn = DefinitionImpl.PROCEDURE; dummyName = "DummyProgramName".toLowerCase() + String.format("%03d", ++dummyCounter); break; } default: { routineDefn = DefinitionImpl.PROGRAM; dummyName = "DummyProgramName".toLowerCase(); break; } } // Parse the routine name. routineId = parseRoutineName(token, dummyName); routineId.setDefinition(routineDefn); token = currentToken(); // Create new intermediate code for the routine. ICode iCode = ICodeFactory.createICode(); routineId.setAttribute(ROUTINE_ICODE, iCode); routineId.setAttribute(ROUTINE_ROUTINES, new ArrayList<SymTabEntry>()); SymTab symTab = symTabStack.push(); routineId.setAttribute(ROUTINE_SYMTAB, symTab); ((SymTabImpl) symTab).setfuncName(routineId.getName()); parseFormalParameters(token, routineId); token = currentToken(); if (FunctionReturnToken.getType() == INT) { routineId.setTypeSpec(integerType); } else if (FunctionReturnToken.getType() == CHAR) { routineId.setTypeSpec(charType); } // Parse the routine's block declaration. if (token.getType() == LEFT_BRACE) { routineId.setAttribute(ROUTINE_CODE, DECLARED); BlockParser blockParser = new BlockParser(this); ICodeNode rootNode = blockParser.parse(token, routineId); iCode.setRoot(rootNode); } ArrayList<SymTabEntry> subroutines = (ArrayList<SymTabEntry>) parentId.getAttribute(ROUTINE_ROUTINES); subroutines.add(routineId); // Pop the routine's symbol table off the stack. symTabStack.pop(); return routineId; }
private ICodeNode parseIdentifier(Token token) throws Exception { ICodeNode rootNode = null; // Look up the identifier in the symbol table stack. // Flag the identifier as undefined if it's not found. String name = token.getText().toLowerCase(); SymTabEntry id = symTabStack.lookup(name); // Undefined. if (id == null) { errorHandler.flag(token, IDENTIFIER_UNDEFINED, this); id = symTabStack.enterLocal(name); id.setDefinition(UNDEFINED); id.setTypeSpec(Predefined.undefinedType); } Definition defnCode = id.getDefinition(); switch ((DefinitionImpl) defnCode) { case CONSTANT: { Object value = id.getAttribute(CONSTANT_VALUE); TypeSpec type = id.getTypeSpec(); if (value instanceof Integer) { rootNode = ICodeFactory.createICodeNode(INTEGER_CONSTANT); rootNode.setAttribute(VALUE, value); } else if (value instanceof Float) { rootNode = ICodeFactory.createICodeNode(REAL_CONSTANT); rootNode.setAttribute(VALUE, value); } else if (value instanceof String) { rootNode = ICodeFactory.createICodeNode(STRING_CONSTANT); rootNode.setAttribute(VALUE, value); } id.appendLineNumber(token.getLineNumber()); token = nextToken(); // consume the constant identifier if (rootNode != null) { rootNode.setTypeSpec(type); } break; } case ENUMERATION_CONSTANT: { Object value = id.getAttribute(CONSTANT_VALUE); TypeSpec type = id.getTypeSpec(); rootNode = ICodeFactory.createICodeNode(INTEGER_CONSTANT); rootNode.setAttribute(VALUE, value); id.appendLineNumber(token.getLineNumber()); token = nextToken(); // consume the enum constant identifier rootNode.setTypeSpec(type); break; } case FUNCTION: { CallParser callParser = new CallParser(this); rootNode = callParser.parse(token); break; } default: { VariableParser variableParser = new VariableParser(this); rootNode = variableParser.parse(token, id); break; } } return rootNode; }
/** * Parse a factor. * * @param token the initial token. * @return the root of the generated parse subtree. * @throws Exception if an error occurred. */ private ICodeNode parseFactor(Token token) throws Exception { TokenType tokenType = token.getType(); ICodeNode rootNode = null; switch ((PascalTokenType) tokenType) { case IDENTIFIER: { return parseIdentifier(token); } case INTEGER: { // Create an INTEGER_CONSTANT node as the root node rootNode = ICodeFactory.createICodeNode(INTEGER_CONSTANT); rootNode.setAttribute(VALUE, token.getValue()); token = nextToken(); // consume the number rootNode.setTypeSpec(Predefined.integerType); break; } case REAL: { // Create an REAL_CONSTANT node as the root node. rootNode = ICodeFactory.createICodeNode(REAL_CONSTANT); rootNode.setAttribute(VALUE, token.getValue()); token = nextToken(); // consume the number rootNode.setTypeSpec(Predefined.realType); break; } case STRING: { String value = (String) token.getValue(); // Create a STRING_CONSTANT node as the root node. rootNode = ICodeFactory.createICodeNode(STRING_CONSTANT); rootNode.setAttribute(VALUE, value); TypeSpec resultType = value.length() == 1 ? Predefined.charType : TypeFactory.createStringType(value); token = nextToken(); // consume the string rootNode.setTypeSpec(resultType); break; } case NOT: { token = nextToken(); // consume the NOT // Create a NOT node as the root node. rootNode = ICodeFactory.createICodeNode(ICodeNodeTypeImpl.NOT); // Parse the factor. The NOT node adopts the factor node as its child. ICodeNode factorNode = parseFactor(token); rootNode.addChild(factorNode); // Type check: the factor must be boolean. TypeSpec factorType = factorNode != null ? factorNode.getTypeSpec() : Predefined.undefinedType; if (!TypeChecker.isBoolean(factorType)) errorHandler.flag(token, INCOMPATIBLE_TYPES, this); rootNode.setTypeSpec(Predefined.booleanType); break; } case LEFT_PAREN: { token = nextToken(); // consume the ( // Parse an expression and make its node the root node. rootNode = parseExpression(token); TypeSpec resultType = rootNode != null ? rootNode.getTypeSpec() : Predefined.undefinedType; // Look for the matching ) token. token = currentToken(); if (token.getType() == RIGHT_PAREN) token = nextToken(); // consume the ) else errorHandler.flag(token, MISSING_RIGHT_PAREN, this); rootNode.setTypeSpec(resultType); break; } default: { errorHandler.flag(token, UNEXPECTED_TOKEN, this); break; } } return rootNode; }
/** * Parse a term. * * @param token the initial token. * @return the root of the generated parse subtree. * @throws Exception if an error occurred. */ private ICodeNode parseTerm(Token token) throws Exception { // Parse a factor and makes its node the root node. ICodeNode rootNode = parseFactor(token); TypeSpec resultType = rootNode != null ? rootNode.getTypeSpec() : Predefined.undefinedType; token = currentToken(); TokenType tokenType = token.getType(); // Loop over multiplicative operators. while (MULT_OPS.contains(tokenType)) { TokenType operator = tokenType; // Create a new operator node and adopt the current tree as its first child. ICodeNodeType nodeType = MULT_OPS_OPS_MAP.get(operator); ICodeNode opNode = ICodeFactory.createICodeNode(nodeType); opNode.addChild(rootNode); token = nextToken(); // consume the operator // Parse another factor. // The operator node adopts the term's tree as its secomd child. ICodeNode factorNode = parseFactor(token); opNode.addChild(factorNode); TypeSpec factorType = factorNode != null ? factorNode.getTypeSpec() : Predefined.undefinedType; // The operator node becomes the new root node. rootNode = opNode; // Determine the result type. switch ((PascalTokenType) operator) { case STAR: { // Both operands integer ==> integer result. if (TypeChecker.areBothInteger(resultType, factorType)) { resultType = Predefined.integerType; } // Both real operands or one real and one integer operand // ==> real result. else if (TypeChecker.isAtLeastOneReal(resultType, factorType)) { resultType = Predefined.realType; } else { errorHandler.flag(token, INCOMPATIBLE_TYPES, this); } break; } case SLASH: { // All integer and real operand combinations // ==> real result. if (TypeChecker.areBothInteger(resultType, factorType) || TypeChecker.isAtLeastOneReal(resultType, factorType)) { resultType = Predefined.realType; } else { errorHandler.flag(token, INCOMPATIBLE_TYPES, this); } break; } case DIV: case MOD: { // Both operands integer ==> integer result. if (TypeChecker.areBothInteger(resultType, factorType)) { resultType = Predefined.integerType; } else { errorHandler.flag(token, INCOMPATIBLE_TYPES, this); } break; } case AND: { // Both operands boolean ==> boolean result. if (TypeChecker.areBothBoolean(resultType, factorType)) { resultType = Predefined.booleanType; } else { errorHandler.flag(token, INCOMPATIBLE_TYPES, this); } break; } } // The operator node becomes the new root node. rootNode.setTypeSpec(resultType); token = currentToken(); tokenType = token.getType(); } return rootNode; }
/** * Parse a simple expression. * * @param token the initial token. * @return the root of the generated parse subtree. * @throws Exception if an error occurred. */ private ICodeNode parseSimpleExpression(Token token) throws Exception { Token signToken = null; TokenType signType = null; // type of leading sign (if any) // Look for a leading + or - sign TokenType tokenType = token.getType(); if ((tokenType == PLUS) || (tokenType == MINUS)) { signType = tokenType; signToken = token; token = nextToken(); // consume the + or - } // Parse a term and make the root of its tree the root node. ICodeNode rootNode = parseTerm(token); TypeSpec resultType = rootNode != null ? rootNode.getTypeSpec() : Predefined.undefinedType; // Type check: Leading sign. if ((signType != null) && (!TypeChecker.isIntegerOrReal(resultType))) errorHandler.flag(signToken, INCOMPATIBLE_TYPES, this); // Was there a leading - sign? if (signType == MINUS) { // Create a NEGATE node and adopt the current tree as its child. // The NEGATE node becomes the new root node. ICodeNode negateNode = ICodeFactory.createICodeNode(NEGATE); negateNode.addChild(rootNode); negateNode.setTypeSpec(rootNode.getTypeSpec()); rootNode = negateNode; } token = currentToken(); tokenType = token.getType(); // Loop over additive operators. while (ADD_OPS.contains(tokenType)) { TokenType operator = tokenType; // Create a new operator node and adopt the current tree as its first child. ICodeNodeType nodeType = ADD_OPS_OPS_MAP.get(operator); ICodeNode opNode = ICodeFactory.createICodeNode(nodeType); opNode.addChild(rootNode); token = nextToken(); // consume the operator // Parse another term. // The operator node adopts the term's tree as its second child. ICodeNode termNode = parseTerm(token); opNode.addChild(termNode); TypeSpec termType = termNode != null ? termNode.getTypeSpec() : Predefined.undefinedType; // The operator node becomes the new root node. rootNode = opNode; switch ((PascalTokenType) operator) { case PLUS: case MINUS: { // Both operands integer => integer result. if (TypeChecker.areBothInteger(resultType, termType)) resultType = Predefined.integerType; // Both real operands or one real and one integer operand => real result. else if (TypeChecker.isAtLeastOneReal(resultType, termType)) resultType = Predefined.realType; else errorHandler.flag(token, INCOMPATIBLE_TYPES, this); break; } case OR: { // Both operands boolean ==> boolean result. if (TypeChecker.areBothBoolean(resultType, termType)) resultType = Predefined.booleanType; else errorHandler.flag(token, INCOMPATIBLE_TYPES, this); break; } } rootNode.setTypeSpec(resultType); token = currentToken(); tokenType = token.getType(); } return rootNode; }