package ca.uwaterloo.joos;

import java.util.*;
import java.util.logging.*;

import ca.uwaterloo.joos.LR1.*;

/**
 *
 * @author Wenzhu Man
 *
 *
 */

public class LR1Parser {
	private static final Logger logger = Main.getLogger();
	private final LR1 lr1;

	private class TransitionState {
		private Token token;
		private int state;

		public TransitionState(Token token, int state) {
			this.state = state;
			this.token = token;
		}

		public int getState() {
			return state;
		}

		public String toString() {
			return "<TransitionState> " + String.valueOf(this.state) + " | " + this.token;
		}
	}

	public LR1Parser(LR1 lr1) {
		this.lr1 = lr1;
	}

	public boolean checkGrammer(List<Token> tokens) {
		// Initialize startSymbol, tokens iterator and parsing stack
		String startSymbol = lr1.getStartSymbol();
		ListIterator<Token> tokensIterator = tokens.listIterator();
		Stack<TransitionState> parseStack = new Stack<TransitionState>();
		parseStack.push(new TransitionState(null, 0));

		// Initialize parsing state variables
		Token nextToken = tokensIterator.next();
		Action nextAction = null;
		
		// Execute lr1 parsing until the tokens has been reduced to the startSymbol
		while (!nextToken.getKind().equals(startSymbol)) {
			
			// Acquire next action, according to the current state and the next token kind
			nextAction = lr1.actionFor(parseStack.peek().getState(), nextToken.getKind());
			LR1Parser.logger.fine("Next:\tState " + parseStack.peek().getState() + " + " + nextToken + " => " + nextAction);

			// If is a shift
			if (nextAction instanceof LR1.ActionShift) {
				ActionShift shift = (ActionShift) nextAction;
				LR1Parser.logger.info("Shift:\t" + shift);

				// Push the transitionState to the stack
				TransitionState transitionState = new TransitionState(nextToken, shift.getToState());
				parseStack.push(transitionState);
				LR1Parser.logger.info("├─ Push:\t" + transitionState);

				// Iterate to next token
				// Note: if there is no next, move cursor back to front first
				if(!tokensIterator.hasNext()) tokensIterator = tokens.listIterator();
				nextToken = tokensIterator.next();
			}
			// If is a reduction
			else if (nextAction instanceof LR1.ActionReduce){
				ActionReduce reduce = (ActionReduce) nextAction;
				LR1Parser.logger.info("Redue:\t" + reduce);

				// Pop the stack according to the length of the production rule's RHS
				for (int i = 0; i < reduce.getInt(); i++) {
					TransitionState poppedState = parseStack.pop();
					LR1Parser.logger.info("├─ Pop:\t" + poppedState);
				}
				
				// Iterate back one token, since it has not been pushed to the stack
				tokensIterator.previous();
				
				// Next token is the production rule's LHS
				nextToken = new Token(reduce.getProductionRule().getLefthand(), Arrays.toString(reduce.getProductionRule().getRighthand()));
			}
			// No action found, validation failed
			else {
				LR1Parser.logger.severe("ERROR: No valid action for State " + parseStack.peek().getState() + " + " + nextToken);
				return false;
			}
		}

		// The tokens has been reduced to startSymbol, validation succeed
		LR1Parser.logger.info("Tokens has been validated against LR1");
		return true;
	}
}

@@ -107,19 +107,95 @@
 *;%0A%0A/**%0A
+ * LR1 Parser%0A *%0A * which use the given LR1 table to parse a list of tokens%0A
  *%0A
-
  * @auth
@@ -215,16 +215,12 @@
 %0A *%0A
- *%0A
  */%0A
-%0A
 publ
@@ -715,24 +715,187 @@
  = lr1;%0A%09%7D%0A%0A
+%09/**%0A%09 * Validate a list of tokens against the LR1%0A%09 * %0A%09 * @param tokens the list of tokens to be validated%0A%09 * @return whether the list of tokens is valid %0A%09 */%0A
 %09public bool
@@ -1332,19 +1332,17 @@
 = null;%0A
-%09%09
 %0A
+
 %09%09// Exe
@@ -1464,20 +1464,17 @@
 bol)) %7B%0A
-%09%09%09
 %0A
+
 %09%09%09// Ac
@@ -2773,21 +2773,17 @@
 ;%0A%09%09%09%09%7D%0A
-%09%09%09%09
 %0A
+
 %09%09%09%09// I
@@ -2878,20 +2878,16 @@
 ious();%0A
-%09%09%09%09
 %0A%09%09%09%09// 

Add javadocs to LR1Parser