# jay skeleton for Java, tables via resource # character in column 1 determines outcome... # # is a comment # . is copied # t is copied as //t unless -t is set # other lines are interpreted to call jay procedures version Java tables 1.0.2 (c) 2002-2004 ats@cs.rit.edu . prolog ## %{ ... %} prior to the first %% . // %token constants tokens public static final int . . /** number of final state. . */ yyFinal protected static final int yyFinal = . . /** parser tables. . Cannot be final because they are loaded from a resource. . Order is mandated by jay. . */ . protected static short[] yyLhs, yyLen, yyDefRed, yyDgoto, . yySindex, yyRindex, yyGindex, yyTable, yyCheck; . yyLhs //yy yyLen //yy yyDefRed //yy yyDgoto //yy yySindex //yy yyRindex //yy yyGindex //yy yyTable //yy yyCheck //yy . . /** maps symbol value to printable name. . @see #yyExpecting . */ . protected static String[] yyNames; yyNames //yy . t /** printable rules for debugging. t */ t protected static String[] yyRule; t yyRule //yy . . /** loads parser table. . Format: name length newline ten-numbers newline ... . */ . protected static short[] loadShort (java.io.BufferedReader in) throws Exception { . java.util.StringTokenizer st = new java.util.StringTokenizer(in.readLine()); . st.nextToken(); . short[] result = new short[Integer.parseInt(st.nextToken())]; . for (int n = 0; n < result.length; n += 10) { . st = new java.util.StringTokenizer(in.readLine(), ", \t\r\n"); . for (int m = 0; st.hasMoreTokens(); ++ m) . result[n+m] = new Short(st.nextToken()).shortValue(); . } . return result; . } . . // once-only code to initialize parser tables . // non-static to name resource after parser class . // any error is fatal . { if (yyLhs == null) . try { . Class myClass = getClass(); . String resource = myClass.getName().replace('.', '/')+".tables"; . java.io.InputStream i; . try { // full path in jar file . i = myClass.getResourceAsStream("/"+resource); . } catch (Exception e) { // relative path . i = myClass.getResourceAsStream(resource); . } . java.io.BufferedReader in = . new java.io.BufferedReader(new java.io.InputStreamReader(i)); . . yyLhs = loadShort(in); . yyLen = loadShort(in); . yyDefRed = loadShort(in); . yyDgoto = loadShort(in); . yySindex = loadShort(in); . yyRindex = loadShort(in); . yyGindex = loadShort(in); . yyTable = loadShort(in); . yyCheck = loadShort(in); . . // load name table . // Format: yyNames length lines newline index space name newline ...for lines . { java.util.StringTokenizer st = new java.util.StringTokenizer(in.readLine()); . st.nextToken(); . yyNames = new String[Integer.parseInt(st.nextToken())]; . int max = Integer.parseInt(st.nextToken()); . for (int n = 0; n < max; ++ n) { . st = new java.util.StringTokenizer(in.readLine()); . int m = Integer.parseInt(st.nextToken()); . yyNames[m] = st.nextToken("\n").substring(1); . } . } . t // load rules table for debugging t // Format: yyRule length newline rule newline ...for length t { java.util.StringTokenizer st = new java.util.StringTokenizer(in.readLine()); t st.nextToken(); t yyRule = new String[Integer.parseInt(st.nextToken())]; t for (int n = 0; n < yyRule.length; ++ n) t yyRule[n] = in.readLine(); t } . . in.close(); . } catch (Exception e) { . throw new Error("cannot load parser tables ["+e+"]"); . } . } . # # --- rest is identical to skeleton.java --- # t /** debugging support, requires the package jay.yydebug. t Set to null to suppress debugging messages. t */ t protected jay.yydebug.yyDebug yydebug; t t /** index-checked interface to {@link #yyNames}. t @param token single character or %token value. t @return token name or [illegal] or [unknown]. t */ t public static final String yyName (int token) { t if (token < 0 || token > yyNames.length) return "[illegal]"; t String name; t if ((name = yyNames[token]) != null) return name; t return "[unknown]"; t } t . /** thrown for irrecoverable syntax errors and stack overflow. . Nested for convenience, does not depend on parser class. . */ . public static class yyException extends java.lang.Exception { . public yyException (String message) { . super(message); . } . } . . /** must be implemented by a scanner object to supply input to the parser. . Nested for convenience, does not depend on parser class. . */ . public interface yyInput { . . /** move on to next token. . @return false if positioned beyond tokens. . @throws IOException on input error. . */ . boolean advance () throws java.io.IOException; . . /** classifies current token. . Should not be called if {@link #advance()} returned false. . @return current %token or single character. . */ . int token (); . . /** associated with current token. . Should not be called if {@link #advance()} returned false. . @return value for {@link #token()}. . */ . Object value (); . } . . /** simplified error message. . @see #yyerror(java.lang.String, java.lang.String[]) . */ . public void yyerror (String message) { . yyerror(message, null); . } . . /** (syntax) error message. . Can be overwritten to control message format. . @param message text to be displayed. . @param expected list of acceptable tokens, if available. . */ . public void yyerror (String message, String[] expected) { . if (expected != null && expected.length > 0) { . System.err.print(message+", expecting"); . for (int n = 0; n < expected.length; ++ n) . System.err.print(" "+expected[n]); . System.err.println(); . } else . System.err.println(message); . } . . /** computes list of expected tokens on error by tracing the tables. . @param state for which to compute the list. . @return list of token names. . */ . protected String[] yyExpecting (int state) { . int token, n, len = 0; . boolean[] ok = new boolean[yyNames.length]; . . if ((n = yySindex[state]) != 0) . for (token = n < 0 ? -n : 0; . token < yyNames.length && n+token < yyTable.length; ++ token) . if (yyCheck[n+token] == token && !ok[token] && yyNames[token] != null) { . ++ len; . ok[token] = true; . } . if ((n = yyRindex[state]) != 0) . for (token = n < 0 ? -n : 0; . token < yyNames.length && n+token < yyTable.length; ++ token) . if (yyCheck[n+token] == token && !ok[token] && yyNames[token] != null) { . ++ len; . ok[token] = true; . } . . String result[] = new String[len]; . for (n = token = 0; n < len; ++ token) . if (ok[token]) result[n++] = yyNames[token]; . return result; . } . . /** the generated parser, with debugging messages. . Maintains a dynamic state and value stack. . @param yyLex scanner. . @param yydebug debug message writer implementing yyDebug, or null. . @return result of the last reduction, if any. . @throws yyException on irrecoverable parse error. . */ . public Object yyparse (yyInput yyLex, Object yydebug) . throws java.io.IOException, yyException { t this.yydebug = (jay.yydebug.yyDebug)yydebug; . return yyparse(yyLex); . } . . /** initial size and increment of the state/value stack [default 256]. . This is not final so that it can be overwritten outside of invocations . of {@link #yyparse}. . */ . protected int yyMax; . . /** executed at the beginning of a reduce action. . Used as $$ = yyDefault($1), prior to the user-specified action, if any. . Can be overwritten to provide deep copy, etc. . @param first value for $1, or null. . @return first. . */ . protected Object yyDefault (Object first) { . return first; . } . . /** the generated parser. . Maintains a dynamic state and value stack. . @param yyLex scanner. . @return result of the last reduction, if any. . @throws yyException on irrecoverable parse error. . */ . public Object yyparse (yyInput yyLex) throws java.io.IOException, yyException { . if (yyMax <= 0) yyMax = 256; // initial size . int yyState = 0, yyStates[] = new int[yyMax]; // state stack . Object yyVal = null, yyVals[] = new Object[yyMax]; // value stack . int yyToken = -1; // current input . int yyErrorFlag = 0; // #tokens to shift . local ## %{ ... %} after the first %% . yyLoop: for (int yyTop = 0;; ++ yyTop) { . if (yyTop >= yyStates.length) { // dynamically increase . int[] i = new int[yyStates.length+yyMax]; . System.arraycopy(yyStates, 0, i, 0, yyStates.length); . yyStates = i; . Object[] o = new Object[yyVals.length+yyMax]; . System.arraycopy(yyVals, 0, o, 0, yyVals.length); . yyVals = o; . } . yyStates[yyTop] = yyState; . yyVals[yyTop] = yyVal; t if (yydebug != null) yydebug.push(yyState, yyVal); . . yyDiscarded: for (;;) { // discarding a token does not change stack . int yyN; . if ((yyN = yyDefRed[yyState]) == 0) { // else [default] reduce (yyN) . if (yyToken < 0) { . yyToken = yyLex.advance() ? yyLex.token() : 0; t if (yydebug != null) t yydebug.lex(yyState, yyToken, yyName(yyToken), yyLex.value()); . } . if ((yyN = yySindex[yyState]) != 0 && (yyN += yyToken) >= 0 . && yyN < yyTable.length && yyCheck[yyN] == yyToken) { t if (yydebug != null) t yydebug.shift(yyState, yyTable[yyN], yyErrorFlag > 0 ? yyErrorFlag-1 : 0); . yyState = yyTable[yyN]; // shift to yyN . yyVal = yyLex.value(); . yyToken = -1; . if (yyErrorFlag > 0) -- yyErrorFlag; . continue yyLoop; . } . if ((yyN = yyRindex[yyState]) != 0 && (yyN += yyToken) >= 0 . && yyN < yyTable.length && yyCheck[yyN] == yyToken) . yyN = yyTable[yyN]; // reduce (yyN) . else . switch (yyErrorFlag) { . . case 0: . yyerror("syntax error", yyExpecting(yyState)); t if (yydebug != null) yydebug.error("syntax error"); . . case 1: case 2: . yyErrorFlag = 3; . do { . if ((yyN = yySindex[yyStates[yyTop]]) != 0 . && (yyN += yyErrorCode) >= 0 && yyN < yyTable.length . && yyCheck[yyN] == yyErrorCode) { t if (yydebug != null) t yydebug.shift(yyStates[yyTop], yyTable[yyN], 3); . yyState = yyTable[yyN]; . yyVal = yyLex.value(); . continue yyLoop; . } t if (yydebug != null) yydebug.pop(yyStates[yyTop]); . } while (-- yyTop >= 0); t if (yydebug != null) yydebug.reject(); . throw new yyException("irrecoverable syntax error"); . . case 3: . if (yyToken == 0) { t if (yydebug != null) yydebug.reject(); . throw new yyException("irrecoverable syntax error at end-of-file"); . } t if (yydebug != null) t yydebug.discard(yyState, yyToken, yyName(yyToken), t yyLex.value()); . yyToken = -1; . continue yyDiscarded; // leave stack alone . } . } . int yyV = yyTop + 1-yyLen[yyN]; t if (yydebug != null) t yydebug.reduce(yyState, yyStates[yyV-1], yyN, yyRule[yyN], yyLen[yyN]); . yyVal = yyDefault(yyV > yyTop ? null : yyVals[yyV]); . switch (yyN) { actions ## code from the actions within the grammar . } . yyTop -= yyLen[yyN]; . yyState = yyStates[yyTop]; . int yyM = yyLhs[yyN]; . if (yyState == 0 && yyM == 0) { t if (yydebug != null) yydebug.shift(0, yyFinal); . yyState = yyFinal; . if (yyToken < 0) { . yyToken = yyLex.advance() ? yyLex.token() : 0; t if (yydebug != null) t yydebug.lex(yyState, yyToken,yyName(yyToken), yyLex.value()); . } . if (yyToken == 0) { t if (yydebug != null) yydebug.accept(yyVal); . return yyVal; . } . continue yyLoop; . } . if ((yyN = yyGindex[yyM]) != 0 && (yyN += yyState) >= 0 . && yyN < yyTable.length && yyCheck[yyN] == yyState) . yyState = yyTable[yyN]; . else . yyState = yyDgoto[yyM]; t if (yydebug != null) yydebug.shift(yyStates[yyTop], yyState); . continue yyLoop; . } . } . } . epilog ## text following second %%