/*
 * This file contains only a very barebone sketch of how a recursive descent
 * parser might work.  It's not functional and doesn't contain nearly the
 * complete set of things that you'd need to make it really run, but it
 * should give you the general idea of how these kinds of things are set up.
 * I've included notes where possible to indicate things to watch for.
 */


/*
 * This routine parses the nonterminal "PUZZLEDEF":
 * PUZZLEDEF := "Puzzle" ( MCPUZZLE | SPPUZZLE | N2KPUZZLE )
 */
public PuzState parsePuzzleDef(Lexer l) {
  Token t=l.next();
  if (!t.tokStr().equals("Puzzle")) {
    // ParseException
  }
  t=l.next();
  // The following cascade of mutually exclusive "if" statements handles the
  // multiway decision in the PUZZLEDEF description.
  if (t.tokStr().equals("MissionariesAndCannibals")) {
    // Note!  parseMCPuzState() begins by consuming the token
    // "MissionariesAndCannibals" itself -- we need some way to ensure that it
    // gets it.  One way (not the only way, but my preferred way) is to
    // ensure that the Lexer can accept pushback of one or more tokens.
    l.pushBack(t);
    PuzState p=parseMCPuzState(l);
    return p;
  }
  if (t.tokStr().equals("NToTheKPuzzle")) {
    l.pushBack(t);
    PuzState p=parseNKPuzState(l);
    return p;
  }
  if (t.tokStr().equals("ShortestPaths")) {
    l.pushBack(t);
    PuzState p=parseSPPuzState(l);
    return p;
  }
  // unrecognized puzzle type -- if we get here, it's a parse error
}

/*
 * This method corresponds to the non-terminal BNF rule "N2KPUZZLE":
 * N2KPUZZLE := "NToTheKPuzzle" "(" HNAME ")" 
 *              "=" "{" 
 *                "StartState" "=" NKPUZSTATE 
 *                "GoalState" "=" NKPUZSTATE 
 *              "}"
 */
public PuzState parseNKPuzzle(Lexer l) {
  Token t=l.next();
  if (!t.tokStr().equals("NToTheKPuzzle")) {
    throw new ParseException("Unexpected token `" + t.tokStr() +
			     "' found when expecting N^k-1 puzzle state");
  }
  // "NToTheKPuzzle" is purely syntactic -- it tells us where we are in the
  // parse tree/BNF grammar, but it doesn't actually cause us to create any
  // data structures all by itself.  Thus, we "consume" it (i.e., drop it on
  // the floor and go on with life)
  t=l.next();
  if (!t.tokStr().equals("(")) {
    // ParseException
  }
  t=l.next();
  // Note -- here we assume that the Lexer is capable of identifying that
  // particular tokens are of types that correspond to named regular
  // expressions in the BNF grammar.
  if (t.getType()!=TT_HNAME) {
    // ParseException
  }
  // the HNAME token here _is_ semantically meaningful, and we want to keep a
  // record of it so that we can use it to instantiate it later.
  String heuristic=t.tokStr();
  // parse ")", "=", "{", "StartState", and "=".  Now ready for NKPUZSTATE
  // parseNKPuzState() is a method that parses the full, recursive state
  // representation for an N^k-1 puzzle according to the BNF rule NKPUZSTATE
  NkPuzStateRep sRep=parseNKPuzRep(l);
  // now parse "GoalState", "="
  NkPuzStateRep gRep=parseNKPuzState(l);
  // parse "}" and you know you're done with N2KPUZZLE
  // now construct and return the actual puzzle object
  if (heuristic.equals("Manhattan")) {
    NkPuz p=new NkManhattanPuz(sRep,gRep);
    return p;
  }
  if (heuristic.equals("TileCount")) {
    NkPuz p=new NkTileCountPuz(sRep,gRep);
    return p;
  }
  // unrecognized heuristic -- parse exception
}
