/** * Create a jump table for a SELECT node. * * @param node the SELECT node. * @return the jump table. */ private HashMap<Object, ICodeNode> createJumpTable(ICodeNode node) { HashMap<Object, ICodeNode> jumpTable = new HashMap<Object, ICodeNode>(); // Loop over children that are SELECT_BRANCH nodes. ArrayList<ICodeNode> selectChildren = node.getChildren(); for (int i = 1; i < selectChildren.size(); ++i) { ICodeNode branchNode = selectChildren.get(i); ICodeNode constantsNode = branchNode.getChildren().get(0); ICodeNode statementNode = branchNode.getChildren().get(1); // Loop over the constants children of the branch's CONSTANTS_NODE. ArrayList<ICodeNode> constantsList = constantsNode.getChildren(); for (ICodeNode constantNode : constantsList) { // Create a jump table entry. // Convert a single-character string constant to a character. Object value = constantNode.getAttribute(VALUE); if (constantNode.getType() == STRING_CONSTANT) { value = ((String) value).charAt(0); } jumpTable.put(value, statementNode); } } return jumpTable; }
/** * 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 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; }