// Insert the following code into Declaration.java //=================================================================== // Code for Lab2: bottomUpParse. //=================================================================== // It turns out that if we use the same grammar we used from lab 1, the // resulting parse table would have 11 states and 18 entries. We can // re-write the grammar so that is a little more efficient: // decl --> "int" list ";" // list --> var "," list | var // var --> "id" "=" "num" // We won't actually create a parse table. As in top-down parsing, we'll // just enumerate the valid transitions. /** bottomUpParse(): We assume that scan() has already been called, so that * the input tokens are now stored in the ArrayList called tokenList. * Here is how parsing works bottom up. * Start in state 0. Push the number 0 on the state stack. * We make our decision based on what state we're in, and next input symbol. * Next input symbol is at beginning of tokenList. * If it's a "goto", then we change state, push the new state number, and * consume the input token (get rid of first element from ArrayList). * If it's a reduce, we have to pop some states off the state-stack, go to * the state that's now at the top of the stack, then append a nonterminal * onto the beginning of the tokenList. * If it's the happy state, we're done. Also could have syntax error anytime. * Note that we are treating the tokenList differently to how we did top-down * parsing: it's a little easier to implement bottom-up parsing if we can * change the input stream (take things off, and append stuff), rather than * just traversing it with the pos (index) variable. */ public void bottomUpParse() { // To begin with, let's put a '$' at end of input. tokenList.add("$"); Stack stateStack = new Stack(); stateStack.push(new Integer(0)); // Start in state 0. We always keep the current state number on top of // the state-stack. boolean done = false; while (true) { String input = tokenList.get(0); int state = stateStack.peek().intValue(); System.out.printf("state %d, next input token '%s'\n", state, input); switch(state) { // State 0 is a typical "goto" case. We push next state on state-stack, // and we consume the input token. case 0: if (input.equals("int")) { stateStack.push(new Integer(1)); tokenList.remove(0); } else error("syntax error - type name expected"); break; // Here we have a case of a reduce operation. case 3: if (input.equals(";")) { stateStack.pop(); tokenList.add(0, "list"); } else if (input.equals(",")) { stateStack.push(new Integer(6)); tokenList.remove(0); } else error("syntax error - comma or semicolon expected"); break; } } } public void error(String s) { System.out.printf("%s\n", s); System.exit(1); }