/** * 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; }