import demeter.*;
public class Parser implements ParserConstants {

  static char unescapifyChar(String s) {
    char c = s.charAt(0);
    if (c == '\\') {
      switch (s.charAt(1)) {
      case 'n': c = '\n'; break;
      case 't': c = '\t'; break;
      case 'b': c = '\b'; break;
      case 'r': c = '\r'; break;
      case 'f': c = '\f'; break;
      case '\\': c = '\\'; break;
      case '\'': c = '\''; break;
      case '\"': c = '\"'; break;
      default:
         c = (char) Integer.parseInt(s.substring(2, s.length()), 8);
         break;
      }
    }
    return c;
  }

  static String unescapify(String s) {
    char str[] = new char[s.length()];
    int i = 0, o = 0;
    while (i < s.length()) {
      char c = s.charAt(i++);
      if (c == '\\') {
         int j = i + 1;
         while (j < s.length() &&
                Character.digit(s.charAt(j), 8) != -1) {
           j++;
         }
         c = unescapifyChar(s.substring(i-1, j));
         i = j;
      }
      str[o++] = c;
    }
    return String.valueOf(str, 0, o);
  }

  protected ParserTokenManager token_source;
  protected Token token = new Token();
  protected Token scanpos, lastpos;
  private int la;
  protected Parser me;

  private int[] scan_hist_kind = new int[10000];
  private Token[] scan_hist_index = new Token[10000];
  int scan_hist_ptr = 0;

  public Parser(java.io.InputStream stream) {
    me = this;
    ASCII_CharStream input_stream = new ASCII_CharStream(stream, 1, 1);
    token_source = new ParserTokenManager(input_stream);
  }

  public void ReInit(java.io.InputStream stream) {
    ASCII_CharStream input_stream = new ASCII_CharStream(stream, 1, 1);
    token_source.ReInit(input_stream);
    token = new Token();
    scan_hist_ptr = 0;
  }

  public Parser(ParserTokenManager tm) {
    me = this;
    token_source = tm;
  }

  public void ReInit(ParserTokenManager tm) {
    token_source = tm;
    token = new Token();
    scan_hist_ptr = 0;
  }

  final private Token consume_token(int kind) throws ParseError {
    if (token.next != null) token = token.next;
    else token = token_source.getNextToken();
    scan_hist_kind[scan_hist_ptr] = kind;
    scan_hist_index[scan_hist_ptr++] = token;
    if (token.kind == kind) {
      scan_hist_ptr = 0;
      return token;
    }
    token_error_setup(0);
    throw new ParseError();
  }

  final private boolean scan_token(int kind) throws ParseError {
    if (scanpos == lastpos) {
      la--;
      if (scanpos.next == null) {
        lastpos = scanpos = scanpos.next = token_source.getNextToken();
      } else {
        lastpos = scanpos = scanpos.next;
      }
    } else {
      scanpos = scanpos.next;
    }
    scan_hist_kind[scan_hist_ptr] = kind;
    scan_hist_index[scan_hist_ptr++] = scanpos;
    return (scanpos.kind != kind);
  }

  final public Token getNextToken() throws ParseError {
    if (token.next != null) token = token.next;
    else token = token_source.getNextToken();
    return token;
  }

  final public Token getToken(int index) throws ParseError {
    scanpos = token;
    for (int i = 0; i < index; i++) {
      if (scanpos.next != null) scanpos = scanpos.next;
      else scanpos = scanpos.next = token_source.getNextToken();
    }
    return scanpos;
  }

  static final String add_escapes(String str) {
    String retval = "";
    char ch;
    for (int i = 0; i < str.length(); i++) {
      ch = str.charAt(i);
      if (ch == '\b') {
        retval += "\\b";
      } else if (ch == '\t') {
        retval += "\\t";
      } else if (ch == '\n') {
        retval += "\\n";
      } else if (ch == '\f') {
        retval += "\\f";
      } else if (ch == '\r') {
        retval += "\\r";
      } else if (ch == '\"') {
        retval += "\\\"";
      } else if (ch == '\'') {
        retval += "\\\'";
      } else if (ch == '\\') {
        retval += "\\\\";
      } else {
        retval += ch;
      }
    }
    return retval;
  }

  protected int error_line;
  protected int error_column;
  protected String error_string;
  protected String[] expected_tokens;

  protected void token_error() {
    System.out.println("");
    System.out.println("Parse error at line " + error_line + ", column " + error_column + ".  Encountered:");
    System.out.println("    \"" + add_escapes(error_string) + "\"");
    System.out.println("");
    if (expected_tokens.length == 1) {
      System.out.println("Was expecting:");
    } else {
      System.out.println("Was expecting one of:");
    }
    for (int i = 0; i < expected_tokens.length; i++) {
      System.out.println("    " + expected_tokens[i]);
    }
    System.out.println("");
  }

  final protected void token_error_setup(int stream_ptr) {
    Token tok;
    int[] tokenbuf = new int[100];
    int tokenbufptr = 0;
    int maxsize = 0;
    String[] exp = new String[1000];
    int exp_count = 0;
    for (int i = 0; i < scan_hist_ptr; i++) {
      if (i == 0 || scan_hist_index[i-1].next == scan_hist_index[i]) {
        tokenbuf[tokenbufptr++] = scan_hist_kind[i];
        if (tokenbufptr > maxsize) maxsize = tokenbufptr;
      } else {
        exp[exp_count] = "";
        for (int j = 0; j < tokenbufptr; j++) {
          exp[exp_count] += tokenImage[tokenbuf[j]] + " ";
        }
        if (tokenbuf[tokenbufptr-1] != 0) exp[exp_count] += "...";
        exp_count++;
        for (int j = 0; j < exp_count-1; j++) {
          if (exp[j].equals(exp[exp_count-1])) {
            exp_count--; break;
          }
        }
        tok = token;
        if (stream_ptr == 1) tok = tok.next;
        tokenbufptr = 1;
        while (tok != scan_hist_index[i]) {
          tok = tok.next;
          tokenbufptr++;
        }
        tokenbuf[tokenbufptr-1] = scan_hist_kind[i];
      }
    }
    exp[exp_count] = "";
    for (int j = 0; j < tokenbufptr; j++) {
      exp[exp_count] += tokenImage[tokenbuf[j]] + " ";
    }
    if (tokenbuf[tokenbufptr-1] != 0) exp[exp_count] += "...";
    exp_count++;
    for (int j = 0; j < exp_count-1; j++) {
      if (exp[j].equals(exp[exp_count-1])) {
        exp_count--; break;
      }
    }
    expected_tokens = new String[exp_count];
    for (int i = 0; i < exp_count; i++) {
      expected_tokens[i] = exp[i];
    }
    error_line = token.beginLine;
    error_column = token.beginColumn;
    error_string = "";
    tok = token;
    if (stream_ptr == 1) tok = tok.next;
    for (int i = 0; i < maxsize; i++) {
      if (tok.kind == 0) {
        error_string += " " + tokenImage[0];
        break;
      }
      error_string += " " + tok.image;
      tok = tok.next;
    }
    error_string = error_string.substring(1);
    me.token_error();
  }

  final public A A() throws ParseError {
  A it;
  X _x;
  C _c;
  D _d;
    it=new A();
    consume_token(1);
    _x = X();
                it.set_x(_x);
    _c = C();
           it.set_c(_c);
    if (_Jack2_1(1)) {
      _d = D();
              it.set_d(_d);
    }
    return it;
  }

  final public X X() throws ParseError {
  X it;
  B _b;
    it=new X();
    _b = B();
           it.set_b(_b);
    return it;
  }

  final public B B() throws ParseError {
  B it;
    if (_Jack2_2(1)) {
      it = E();
    } else if (_Jack2_3(1)) {
      it = F();
    } else {
      token_error_setup(1);
      throw new ParseError();
    }
    return it;
  }

  final public C C() throws ParseError {
  C it;
    it=new C();
    return it;
  }

  final public D D() throws ParseError {
  D it;
    it=new D();
    consume_token(2);
         return it;
  }

  final public E E() throws ParseError {
  E it;
    it=new E();
    consume_token(3);
         return it;
  }

  final public F F() throws ParseError {
  F it;
  G _g;
  H _h;
    it=new F();
    _g = G();
           it.set_g(_g);
    _h = H();
           it.set_h(_h);
    return it;
  }

  final public G G() throws ParseError {
  G it;
    it=new G();
    return it;
  }

  final public H H() throws ParseError {
  H it;
    it=new H();
    consume_token(4);
         return it;
  }

  final public Main Main() throws ParseError {
  Main it;
    it=new Main();
    return it;
  }

  final public PrintingVisitor PrintingVisitor() throws ParseError {
  PrintingVisitor it;
    it=new PrintingVisitor();
    return it;
  }

  final public TreeStructureVisitor TreeStructureVisitor() throws ParseError {
  TreeStructureVisitor it;
  Integer _indent;
    it=new TreeStructureVisitor();
    _indent = Integer();
                      it.set_indent(_indent);
    return it;
  }

  final public Ident Ident() throws ParseError {
                  Token t;
    t = consume_token(IDENTIFIER);
         return new Ident(t.image);
  }

  final public String String() throws ParseError {
                    Token t;
    t = consume_token(STRING_LITERAL);
         String s = t.image;
         return unescapify(s.substring(1, s.length()-1));
  }

  final public Text Text() throws ParseError {
                Token t;
    t = consume_token(TEXT_LITERAL);
         String s = t.image;
         return new Text(s.substring(2, s.length()-2));
  }

  final public Number Number() throws ParseError {
    Token t;
    String s;
    int radix;
    Number num;
    if (_Jack2_4(1)) {
      if (_Jack2_5(1)) {
        t = consume_token(DECIMAL_LITERAL);
         s = t.image;
         radix = 10;
      } else if (_Jack2_6(1)) {
        t = consume_token(HEX_LITERAL);
         s = t.image.substring(2, t.image.length());
         radix = 16;
      } else if (_Jack2_7(1)) {
        t = consume_token(OCTAL_LITERAL);
         s = t.image;
         radix = 8;
      } else {
        token_error_setup(1);
        throw new ParseError();
      }
         switch (s.charAt(s.length()-1)) {
         case 'l': case 'L':
             num = Long.valueOf(s.substring(0, s.length()-1), radix);
             break;
         default:
             num = Integer.valueOf(s, radix);
             break;
         }
    } else if (_Jack2_8(1)) {
      t = consume_token(FLOATING_POINT_LITERAL);
         s = t.image;
         switch (s.charAt(s.length()-1)) {
         case 'd': case 'D':
             num = Double.valueOf(s.substring(0, s.length()-1));
             break;
         case 'f': case 'F':
             num = Float.valueOf(s.substring(0, s.length()-1));
             break;
         default:
             num = Float.valueOf(s);
             break;
         }
    } else {
      token_error_setup(1);
      throw new ParseError();
    }
      return num;
  }

  final public Integer Integer() throws ParseError {
                      Number num;
    num = Number();
                 return new Integer(num.intValue());
  }

  final public Long Long() throws ParseError {
                Number num;
    num = Number();
                 return new Long(num.longValue());
  }

  final public Float Float() throws ParseError {
                  Number num;
    num = Number();
                 return new Float(num.floatValue());
  }

  final public Double Double() throws ParseError {
                    Number num;
    num = Number();
                 return new Double(num.doubleValue());
  }

  final private boolean _Jack2_1(int xla) throws ParseError {
    la = xla; lastpos = scanpos = token;
    return !_Jack3_1();
  }

  final private boolean _Jack2_2(int xla) throws ParseError {
    la = xla; lastpos = scanpos = token;
    return !_Jack3_2();
  }

  final private boolean _Jack2_3(int xla) throws ParseError {
    la = xla; lastpos = scanpos = token;
    return !_Jack3_3();
  }

  final private boolean _Jack2_4(int xla) throws ParseError {
    la = xla; lastpos = scanpos = token;
    return !_Jack3_4();
  }

  final private boolean _Jack2_5(int xla) throws ParseError {
    la = xla; lastpos = scanpos = token;
    return !_Jack3_5();
  }

  final private boolean _Jack2_6(int xla) throws ParseError {
    la = xla; lastpos = scanpos = token;
    return !_Jack3_6();
  }

  final private boolean _Jack2_7(int xla) throws ParseError {
    la = xla; lastpos = scanpos = token;
    return !_Jack3_7();
  }

  final private boolean _Jack2_8(int xla) throws ParseError {
    la = xla; lastpos = scanpos = token;
    return !_Jack3_8();
  }

  final private boolean _Jack3_1() throws ParseError {
    if (_Jack3D()) return true;
    if (la == 0 && scanpos == lastpos) return false;
    return false;
  }

  final private boolean _Jack3_2() throws ParseError {
    if (_Jack3E()) return true;
    if (la == 0 && scanpos == lastpos) return false;
    return false;
  }

  final private boolean _Jack3_3() throws ParseError {
    if (_Jack3F()) return true;
    if (la == 0 && scanpos == lastpos) return false;
    return false;
  }

  final private boolean _Jack3_4() throws ParseError {
    Token xsp;
    xsp = scanpos;
    if (_Jack3_5()) {
    scanpos = xsp;
    if (_Jack3_6()) {
    scanpos = xsp;
    if (_Jack3_7()) return true;
    if (la == 0 && scanpos == lastpos) return false;
    } else if (la == 0 && scanpos == lastpos) return false;
    } else if (la == 0 && scanpos == lastpos) return false;
    return false;
  }

  final private boolean _Jack3_5() throws ParseError {
    if (scan_token(DECIMAL_LITERAL)) return true;
    if (la == 0 && scanpos == lastpos) return false;
    return false;
  }

  final private boolean _Jack3_6() throws ParseError {
    if (scan_token(HEX_LITERAL)) return true;
    if (la == 0 && scanpos == lastpos) return false;
    return false;
  }

  final private boolean _Jack3_7() throws ParseError {
    if (scan_token(OCTAL_LITERAL)) return true;
    if (la == 0 && scanpos == lastpos) return false;
    return false;
  }

  final private boolean _Jack3_8() throws ParseError {
    if (scan_token(FLOATING_POINT_LITERAL)) return true;
    if (la == 0 && scanpos == lastpos) return false;
    return false;
  }

  final private boolean _Jack3D() throws ParseError {
    if (scan_token(2)) return true;
    if (la == 0 && scanpos == lastpos) return false;
    return false;
  }

  final private boolean _Jack3E() throws ParseError {
    if (scan_token(3)) return true;
    if (la == 0 && scanpos == lastpos) return false;
    return false;
  }

  final private boolean _Jack3F() throws ParseError {
    if (_Jack3G()) return true;
    if (la == 0 && scanpos == lastpos) return false;
    if (_Jack3H()) return true;
    if (la == 0 && scanpos == lastpos) return false;
    return false;
  }

  final private boolean _Jack3G() throws ParseError {
    return false;
  }

  final private boolean _Jack3H() throws ParseError {
    if (scan_token(4)) return true;
    if (la == 0 && scanpos == lastpos) return false;
    return false;
  }

}