//////////////////////////////////////////////////////////////// // // Parsing benchmark. // Uses a StringBuilder to represent a mutable string. // Uses a StringBuilder to represent the input string. // // Reads nboyer.sch into a string before timing begins. // // The timed portion of the benchmark parses the string // representation of nboyer.sch 1000 times. // // The output of that parse is checked only by counting the // number of expressions that were parsed. // // Usage, assuming the OS shell prompt is %: // // To parse the "nboyer.sch" file 1000 times: // % java Parsing // // To parse the "nboyer.sch" file n times: // % java Parsing n // // To parse the specified input file n times: // % java Parsing n input // //////////////////////////////////////////////////////////////// import java.math.BigInteger; import java.io.*; public class ParsingFastSB { private static final int REPEAT_COUNT = 1000; private static final String INPUT_FILE = "nboyer.sch"; private static final String usageMsg = "Usage: java Parsing "; public static void main (String[] args) { int repeatCount = REPEAT_COUNT; String inputFile = INPUT_FILE; if (args.length >= 1) try { repeatCount = Integer.valueOf (args[0]); } catch (NumberFormatException e) { usageMessage(); } if (args.length >= 2) inputFile = args[1]; StringBuilder input = readFile (inputFile); Ast result = Ast.theEmptyList; long tStart, tFinish; tStart = System.currentTimeMillis(); for (int i = 0; i < repeatCount; i = i + 1) { result = parseString (input); } tFinish = System.currentTimeMillis(); System.out.println("Parsing:" + repeatCount + ":" + inputFile + " took " + (tFinish - tStart) + " msecs"); int exprCount = repeatCount * result.length(); System.out.println(" and parsed " + exprCount + " expressions."); } private static void usageMessage () { System.err.println (usageMsg); System.exit(1); } private static StringBuilder readFile (String inputFile) { StringBuilder buf = new StringBuilder(); try { FileInputStream fin = new FileInputStream (inputFile); InputStreamReader isr = new InputStreamReader (fin); int c = isr.read(); while (c >= 0) { buf.append ((char) c); c = isr.read(); } return buf; } catch (FileNotFoundException e) { System.err.println ("File not found."); } catch (java.io.IOException e) { System.err.println ("I/O error while reading input file."); } return new StringBuilder(); } private static Ast parseString (StringBuilder input) { Ast result = Ast.theEmptyList; Ast results = result; Scanner scanner = new Scanner (input); Actions actions = new Actions (scanner); Parser parser = new Parser (scanner, actions); result = parser.parseDatum(); while (result != null) { results = Ast.cons (result, results); result = parser.parseDatum(); } return results; } } final class Scanner { public Scanner (StringBuilder input) { this.inputString = input; this.inputLength = input.length(); lineNumber = 1; lineNumberOfLastError = 0; totalErrors = 0; string_accumulator.setLength (0); nextTokenIsReady = false; nextCharacterIsReady = false; } // Any character that doesn't appear within nboyer.sch // (or the input file, if different) can be used to // represent end-of-file. private static final char EOF = '\uffff'; // Length of longest token allowed. // (This allows static allocation in C.) private static final int max_token_size = 1024; static final int errLongToken = 1; /* Extremely long token. */ static final int errIncompleteToken = 2; /* Any lexical error, really. */ static final int errIllegalChar = 3; /* Illegal character. */ static final int errLexGenBug = 4; /* Can't happen. */ // State for one-token buffering in lexical analyzer. // kindOfNextToken is valid iff nextTokenIsReady private int kindOfNextToken; private boolean nextTokenIsReady = false; // string associated with current token StringBuilder tokenValue = new StringBuilder(); public int totalErrors; /* errors so far */ int lineNumber = 1; /* rudimentary source code location */ int lineNumberOfLastError = 0; /* ditto */ // A string buffer for the characters of the current token. private StringBuilder string_accumulator = new StringBuilder (max_token_size); // A single character of buffering. // nextCharacter is valid iff nextCharacterIsReady private char nextCharacter; private boolean nextCharacterIsReady = false; // The input string we're parsing. private StringBuilder inputString; // Index of next character to be read from inputString. private int inputIndex = 0; // Length of inputString. private int inputLength; int nextToken () { if (nextTokenIsReady) return kindOfNextToken; else { string_accumulator.setLength (0); return scanner0(); } } void consumeToken () { nextTokenIsReady = false; } static void error (int lineNumber, String msg) { String msgtxt = "Lexical Error: " + msg + " in line " + lineNumber; System.err.println (msgtxt); throw new RuntimeException (msgtxt); } //////////////////////////////////////////////////////////////// // // Error procedure called by the parser. // As a hack, this error procedure recovers from end-of-file. // //////////////////////////////////////////////////////////////// Ast parseError (int nonterminal, Tokens tlist) { if ((nonterminal == Parser.ydatum) && (nextToken() == Parser.zeof)) return null; //String s = nonterminalToString (nonterminal); String msg = " Syntax Error: while parsing " + nonterminal; error (lineNumber, msg); System.exit(1); // FIXME (just to keep the compiler happy) return null; } /* Reporting and recovery of lexical errors. */ private int scannerError(int msg) { String msgtxt = ""; switch (msg) { case errLongToken: msgtxt = "Amazingly long token"; break; case errIncompleteToken: msgtxt = ""; break; case errIllegalChar: msgtxt = "Illegal character"; break; case errLexGenBug: msgtxt = "Bug in lexical analyzer (generated)"; break; default: msgtxt = "Bug in lexical analyzer"; } error (lineNumber, "Lexical Error: " + msgtxt); nextTokenIsReady = false; nextCharacterIsReady = false; return nextToken(); } // The scanner generator doesn't have a notation for "any character". // This method is never called when nboyer.sch is the input file. private static final boolean isCharacter (char c) { return true; } private static final boolean isNotDoubleQuote (char c) { return (c != '"'); } private static final boolean isNotNewline (char c) { return (c != '\n'); } private int accept (int t) { if ((t == Parser.zboolean) || (t == Parser.zcharacter) || (t == Parser.zid) || (t == Parser.znumber) || (t == Parser.zstring)) { tokenValue.setLength (0); tokenValue.append (string_accumulator, 0, string_accumulator.length()); } kindOfNextToken = t; nextTokenIsReady = true; return t; } //////////////////////////////////////////////////////////////// // // Character i/o, so to speak. // Uses the input-string as input. // //////////////////////////////////////////////////////////////// private static final boolean DEBUGGING = false; private char scanChar() { if (! nextCharacterIsReady) { if (inputIndex < inputLength) { nextCharacter = inputString.charAt (inputIndex); inputIndex = inputIndex + 1; if (DEBUGGING) System.err.print(nextCharacter); } else { nextCharacter = EOF; } nextCharacterIsReady = true; } return nextCharacter; } private void consumeChar() { if (! nextCharacterIsReady) scanChar(); if (string_accumulator.length() < max_token_size) { nextCharacterIsReady = false; if (nextCharacter == '\n') lineNumber = lineNumber + 1; string_accumulator.append (nextCharacter); } else scannerError(errLongToken); } //////////////////////////////////////////////////////////////// // // LexGen generated the code for the state machine. // //////////////////////////////////////////////////////////////// private int scanner0() { int state = 0; char c = scanChar(); /* Edit here to consume whitespace. */ while (Character.isWhitespace(c)) { consumeChar(); string_accumulator.setLength(0); c = scanChar(); } if (c == EOF) return accept(Parser.zeof); else do switch (state) { case 0: switch (c) { case '`': consumeChar(); if (true) return accept(Parser.zbackquote); case '\'': consumeChar(); if (true) return accept(Parser.zquote); case ')': consumeChar(); if (true) return accept(Parser.zrparen); case '(': consumeChar(); if (true) return accept(Parser.zlparen); case ';': consumeChar(); c = scanChar(); state = 29; break; case '+': case '-': consumeChar(); c = scanChar(); state = 28; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': consumeChar(); c = scanChar(); state = 27; break; case '.': consumeChar(); c = scanChar(); state = 16; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '!': case '$': case '%': case '&': case '*': case '/': case ':': case '<': case '=': case '>': case '?': case '^': case '_': case '~': consumeChar(); c = scanChar(); state = 14; break; case '#': consumeChar(); c = scanChar(); state = 13; break; case '"': consumeChar(); c = scanChar(); state = 2; break; case ',': consumeChar(); c = scanChar(); state = 1; break; default: if (Character.isWhitespace(c)) { consumeChar(); c = scanChar(); state = 30; break; } else if (true) return scannerError(errIncompleteToken); } break; case 1: switch (c) { case '@': consumeChar(); if (true) return accept(Parser.zsplicing); default: if (true) return accept(Parser.zcomma); } break; case 2: switch (c) { case '"': consumeChar(); if (true) return accept(Parser.zstring); default: if (isNotDoubleQuote(c)) { consumeChar(); c = scanChar(); state = 2; break; } else if (true) return scannerError(errIncompleteToken); } break; case 3: switch (c) { case 'n': consumeChar(); c = scanChar(); state = 8; break; default: if (true) return scannerError(errIncompleteToken); } break; case 4: switch (c) { case 'i': consumeChar(); c = scanChar(); state = 3; break; default: if (true) return scannerError(errIncompleteToken); } break; case 5: switch (c) { case 'l': consumeChar(); c = scanChar(); state = 4; break; default: if (true) return scannerError(errIncompleteToken); } break; case 6: switch (c) { case 'w': consumeChar(); c = scanChar(); state = 5; break; default: if (true) return scannerError(errIncompleteToken); } break; case 7: switch (c) { case 'e': consumeChar(); c = scanChar(); state = 6; break; default: if (true) return scannerError(errIncompleteToken); } break; case 8: switch (c) { case 'e': consumeChar(); if (true) return accept(Parser.zcharacter); default: if (true) return scannerError(errIncompleteToken); } break; case 9: switch (c) { case 'c': consumeChar(); c = scanChar(); state = 8; break; default: if (true) return scannerError(errIncompleteToken); } break; case 10: switch (c) { case 'a': consumeChar(); c = scanChar(); state = 9; break; default: if (true) return scannerError(errIncompleteToken); } break; case 11: switch (c) { case 'p': consumeChar(); c = scanChar(); state = 10; break; default: if (true) return scannerError(errIncompleteToken); } break; case 12: switch (c) { case 's': consumeChar(); c = scanChar(); state = 11; break; case 'n': consumeChar(); c = scanChar(); state = 7; break; default: if (isCharacter(c)) { consumeChar(); if (true) return accept(Parser.zcharacter); } else if (true) return scannerError(errIncompleteToken); } break; case 13: switch (c) { case '(': consumeChar(); if (true) return accept(Parser.zvecstart); case 't': case 'f': consumeChar(); if (true) return accept(Parser.zboolean); case '\\': consumeChar(); c = scanChar(); state = 12; break; default: if (true) return scannerError(errIncompleteToken); } break; case 14: switch (c) { case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '!': case '$': case '%': case '&': case '*': case '/': case ':': case '<': case '=': case '>': case '?': case '^': case '_': case '~': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '+': case '-': case '.': case '@': consumeChar(); c = scanChar(); state = 14; break; default: if (true) return accept(Parser.zid); } break; case 15: switch (c) { case '.': consumeChar(); if (true) return accept(Parser.zid); default: if (true) return scannerError(errIncompleteToken); } break; case 16: switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': consumeChar(); c = scanChar(); state = 18; break; case '.': consumeChar(); c = scanChar(); state = 15; break; default: if (true) return accept(Parser.zperiod); } break; case 17: switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': consumeChar(); c = scanChar(); state = 18; break; default: if (true) return scannerError(errIncompleteToken); } break; case 18: switch (c) { case 'e': case 's': case 'f': case 'd': case 'l': consumeChar(); c = scanChar(); state = 22; break; case '#': consumeChar(); c = scanChar(); state = 19; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': consumeChar(); c = scanChar(); state = 18; break; default: if (true) return accept(Parser.znumber); } break; case 19: switch (c) { case 'e': case 's': case 'f': case 'd': case 'l': consumeChar(); c = scanChar(); state = 22; break; case '#': consumeChar(); c = scanChar(); state = 19; break; default: if (true) return accept(Parser.znumber); } break; case 20: switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': consumeChar(); c = scanChar(); state = 20; break; default: if (true) return accept(Parser.znumber); } break; case 21: switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': consumeChar(); c = scanChar(); state = 20; break; default: if (true) return scannerError(errIncompleteToken); } break; case 22: switch (c) { case '+': case '-': consumeChar(); c = scanChar(); state = 21; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': consumeChar(); c = scanChar(); state = 20; break; default: if (true) return scannerError(errIncompleteToken); } break; case 23: switch (c) { case '#': consumeChar(); c = scanChar(); state = 23; break; default: if (true) return accept(Parser.znumber); } break; case 24: switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': consumeChar(); c = scanChar(); state = 24; break; case '#': consumeChar(); c = scanChar(); state = 23; break; default: if (true) return accept(Parser.znumber); } break; case 25: switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': consumeChar(); c = scanChar(); state = 24; break; default: if (true) return scannerError(errIncompleteToken); } break; case 26: switch (c) { case '#': consumeChar(); c = scanChar(); state = 26; break; case '/': consumeChar(); c = scanChar(); state = 25; break; case 'e': case 's': case 'f': case 'd': case 'l': consumeChar(); c = scanChar(); state = 22; break; case '.': consumeChar(); c = scanChar(); state = 19; break; default: if (true) return accept(Parser.znumber); } break; case 27: switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': consumeChar(); c = scanChar(); state = 27; break; case '#': consumeChar(); c = scanChar(); state = 26; break; case '/': consumeChar(); c = scanChar(); state = 25; break; case 'e': case 's': case 'f': case 'd': case 'l': consumeChar(); c = scanChar(); state = 22; break; case '.': consumeChar(); c = scanChar(); state = 18; break; default: if (true) return accept(Parser.znumber); } break; case 28: switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': consumeChar(); c = scanChar(); state = 27; break; case '.': consumeChar(); c = scanChar(); state = 17; break; default: if (true) return accept(Parser.zid); } break; case 29: switch (c) { case '\n': consumeChar(); string_accumulator.setLength(0); c = scanChar(); state = 0; break; default: if (isNotNewline(c)) { consumeChar(); c = scanChar(); state = 29; break; } else if (true) return scannerError(errIncompleteToken); } break; case 30: switch (c) { default: if (Character.isWhitespace(c)) { consumeChar(); c = scanChar(); state = 30; break; } else string_accumulator.setLength(0); c = scanChar(); state = 0; break; } break; default: return scannerError(errIllegalChar); } while (state >= 0); return scannerError(errLexGenBug); } //////////////////////////////////////////////////////////////// // // End of state machine generated by LexGen. // //////////////////////////////////////////////////////////////// } final class Parser { //////////////////////////////////////////////////////////////// // // ParseGen generated the code for the strong LL(1) parser. // //////////////////////////////////////////////////////////////// public Parser (Scanner s, Actions a) { scanner = s; actions = a; } private Scanner scanner; private Actions actions; /* Tokens. */ public static final int zbackquote = 1; public static final int zboolean = 2; public static final int zcharacter = 3; public static final int zcomma = 4; public static final int zeof = 5; public static final int zid = 6; public static final int zlparen = 7; public static final int znumber = 8; public static final int zperiod = 9; public static final int zquote = 10; public static final int zrparen = 11; public static final int zsplicing = 12; public static final int zstring = 13; public static final int zvecstart = 14; /* Nonterminals. */ public static final int yabbrevPrefix = 1; public static final int yabbreviation = 2; public static final int ycompoundDatum = 3; public static final int ydata = 4; public static final int ydatum = 5; public static final int ylist = 6; public static final int ylist2 = 7; public static final int ylist3 = 8; public static final int ylist4 = 9; public static final int ysimpleDatum = 10; public static final int ysymbol = 11; public static final int yvector = 12; /* Scanner routines. */ private final int nextToken () { return scanner.nextToken(); } private final void consumeToken () { scanner.consumeToken(); } /* Error routine. */ private final Ast parseError (int x, Tokens y) { return scanner.parseError (x, y); } /* Action routines. */ private final Ast cons(Ast xdatum_1, Ast xdata_2) { return actions.cons (xdatum_1, xdata_2); } private final Ast emptyList() { return actions.emptyList (); } private final Ast identity(Ast xdatum_1) { return actions.identity (xdatum_1); } private final Ast list(Ast xabbrevPrefix_1, Ast xdatum_2) { return actions.list (xabbrevPrefix_1, xdatum_2); } private final Ast list2vector(Ast xdata_1) { return actions.list2vector (xdata_1); } private final Ast makeBool() { return actions.makeBool (); } private final Ast makeChar() { return actions.makeChar (); } private final Ast makeNum() { return actions.makeNum (); } private final Ast makeString() { return actions.makeString (); } private final Ast makeSym() { return actions.makeSym (); } private final Ast pseudoAppend(Ast xdata_1, Ast xlist4_2) { return actions.pseudoAppend (xdata_1, xlist4_2); } private final Ast symBackquote() { return actions.symBackquote (); } private final Ast symQuote() { return actions.symQuote (); } private final Ast symSplicing() { return actions.symSplicing (); } private final Ast symUnquote() { return actions.symUnquote (); } /* Parsing routines. */ public Ast parseDatum () { Ast ast1; switch (nextToken()) { case zsplicing: case zcomma: case zbackquote: case zquote: case zlparen: case zvecstart: ast1 = parseCompoundDatum(); return identity (ast1); case zboolean: case znumber: case zcharacter: case zstring: case zid: ast1 = parseSimpleDatum(); return identity (ast1); default: return parseError (ydatum, new Tokens (zbackquote, new Tokens (zboolean, new Tokens (zcharacter, new Tokens (zcomma, new Tokens (zid, new Tokens (zlparen, new Tokens (znumber, new Tokens (zquote, new Tokens (zsplicing, new Tokens (zstring, new Tokens (zvecstart, null)))))))))))); } } /* end of parseDatum */ private Ast parseSimpleDatum () { Ast ast1; switch (nextToken()) { case zid: ast1 = parseSymbol(); return identity (ast1); case zstring: consumeToken(); return makeString (); case zcharacter: consumeToken(); return makeChar (); case znumber: consumeToken(); return makeNum (); case zboolean: consumeToken(); return makeBool (); default: return parseError (ysimpleDatum, new Tokens (zboolean, new Tokens (zcharacter, new Tokens (zid, new Tokens (znumber, new Tokens (zstring, null)))))); } } /* end of parseSimpleDatum */ private Ast parseSymbol () { switch (nextToken()) { case zid: consumeToken(); return makeSym (); default: return parseError (ysymbol, new Tokens (zid, null)); } } /* end of parseSymbol */ private Ast parseCompoundDatum () { Ast ast1; switch (nextToken()) { case zvecstart: ast1 = parseVector(); return identity (ast1); case zlparen: case zquote: case zbackquote: case zcomma: case zsplicing: ast1 = parseList(); return identity (ast1); default: return parseError (ycompoundDatum, new Tokens (zbackquote, new Tokens (zcomma, new Tokens (zlparen, new Tokens (zquote, new Tokens (zsplicing, new Tokens (zvecstart, null))))))); } } /* end of parseCompoundDatum */ private Ast parseList () { Ast ast1; switch (nextToken()) { case zsplicing: case zcomma: case zbackquote: case zquote: ast1 = parseAbbreviation(); return identity (ast1); case zlparen: consumeToken(); ast1 = parseList2(); return identity (ast1); default: return parseError (ylist, new Tokens (zbackquote, new Tokens (zcomma, new Tokens (zlparen, new Tokens (zquote, new Tokens (zsplicing, null)))))); } } /* end of parseList */ private Ast parseList2 () { Ast ast1, ast2; switch (nextToken()) { case zid: case zstring: case zcharacter: case znumber: case zboolean: case zvecstart: case zlparen: case zquote: case zbackquote: case zcomma: case zsplicing: ast1 = parseDatum(); ast2 = parseList3(); return cons (ast1, ast2); case zrparen: consumeToken(); return emptyList (); default: return parseError (ylist2, new Tokens (zbackquote, new Tokens (zboolean, new Tokens (zcharacter, new Tokens (zcomma, new Tokens (zid, new Tokens (zlparen, new Tokens (znumber, new Tokens (zquote, new Tokens (zrparen, new Tokens (zsplicing, new Tokens (zstring, new Tokens (zvecstart, null))))))))))))); } } /* end of parseList2 */ private Ast parseList3 () { Ast ast1, ast2; switch (nextToken()) { case zrparen: case zperiod: case zsplicing: case zcomma: case zbackquote: case zquote: case zlparen: case zvecstart: case zboolean: case znumber: case zcharacter: case zstring: case zid: ast1 = parseData(); ast2 = parseList4(); return pseudoAppend (ast1, ast2); default: return parseError (ylist3, new Tokens (zbackquote, new Tokens (zboolean, new Tokens (zcharacter, new Tokens (zcomma, new Tokens (zid, new Tokens (zlparen, new Tokens (znumber, new Tokens (zperiod, new Tokens (zquote, new Tokens (zrparen, new Tokens (zsplicing, new Tokens (zstring, new Tokens (zvecstart, null)))))))))))))); } } /* end of parseList3 */ private Ast parseList4 () { Ast ast1; switch (nextToken()) { case zperiod: consumeToken(); ast1 = parseDatum(); if (nextToken() == zrparen) { consumeToken(); return identity (ast1); } else return parseError(ylist4, new Tokens (zrparen, null)); case zrparen: consumeToken(); return emptyList (); default: return parseError (ylist4, new Tokens (zperiod, new Tokens (zrparen, null))); } } /* end of parseList4 */ private Ast parseAbbreviation () { Ast ast1, ast2; switch (nextToken()) { case zquote: case zbackquote: case zcomma: case zsplicing: ast1 = parseAbbrevPrefix(); ast2 = parseDatum(); return list (ast1, ast2); default: return parseError (yabbreviation, new Tokens (zbackquote, new Tokens (zcomma, new Tokens (zquote, new Tokens (zsplicing, null))))); } } /* end of parseAbbreviation */ private Ast parseAbbrevPrefix () { switch (nextToken()) { case zsplicing: consumeToken(); return symSplicing (); case zcomma: consumeToken(); return symUnquote (); case zbackquote: consumeToken(); return symBackquote (); case zquote: consumeToken(); return symQuote (); default: return parseError (yabbrevPrefix, new Tokens (zbackquote, new Tokens (zcomma, new Tokens (zquote, new Tokens (zsplicing, null))))); } } /* end of parseAbbrevPrefix */ private Ast parseVector () { Ast ast1; switch (nextToken()) { case zvecstart: consumeToken(); ast1 = parseData(); if (nextToken() == zrparen) { consumeToken(); return list2vector (ast1); } else return parseError(yvector, new Tokens (zrparen, null)); default: return parseError (yvector, new Tokens (zvecstart, null)); } } /* end of parseVector */ private Ast parseData () { Ast ast1, ast2; switch (nextToken()) { case zid: case zstring: case zcharacter: case znumber: case zboolean: case zvecstart: case zlparen: case zquote: case zbackquote: case zcomma: case zsplicing: ast1 = parseDatum(); ast2 = parseData(); return cons (ast1, ast2); case zrparen: case zperiod: return emptyList (); default: return parseError (ydata, new Tokens (zbackquote, new Tokens (zboolean, new Tokens (zcharacter, new Tokens (zcomma, new Tokens (zid, new Tokens (zlparen, new Tokens (znumber, new Tokens (zperiod, new Tokens (zquote, new Tokens (zrparen, new Tokens (zsplicing, new Tokens (zstring, new Tokens (zvecstart, null)))))))))))))); } } /* end of parseData */ //////////////////////////////////////////////////////////////// // // End of parser generated by ParseGen. // //////////////////////////////////////////////////////////////// } //////////////////////////////////////////////////////////////// // // Action routines for parser. // //////////////////////////////////////////////////////////////// final class Actions { // The action routines need access to some of the scanner's // data structures, notably tokenValue. private Scanner scanner; Actions (Scanner scanner) { this.scanner = scanner; } /* Action routines. */ Ast cons(Ast xdatum_1, Ast xdata_2) { return Ast.cons (xdatum_1, xdata_2); } Ast emptyList() { return Ast.theEmptyList; } Ast identity(Ast xdatum_1) { return xdatum_1; } Ast list(Ast xabbrevPrefix_1, Ast xdatum_2) { return Ast.cons (xabbrevPrefix_1, Ast.cons (xdatum_2, Ast.theEmptyList)); } Ast list2vector(Ast xdata_1) { return Ast.listToVector (xdata_1); } Ast makeBool() { // The tokenValue is "#f" or "#t". char c = scanner.tokenValue.charAt (1); if (c == 'f') return Ast.theFalseBoolean; else return Ast.theTrueBoolean; } Ast makeChar() { // The tokenValue is "#\c", where c is any character. char c = scanner.tokenValue.charAt (1); return Ast.theCharacter (c); } Ast makeNum() { return Ast.StringBuilderToNumber (scanner.tokenValue); } Ast makeString() { return Ast.StringBuilderToString (scanner.tokenValue); } Ast makeSym() { return Ast.StringBuilderToSymbol (scanner.tokenValue); } Ast pseudoAppend(Ast xdata_1, Ast xlist4_2) { return Ast.pseudoAppend (xdata_1, xlist4_2); } Ast symBackquote() { return Ast.theBackquote; } Ast symQuote() { return Ast.theQuote; } Ast symSplicing() { return Ast.theUnquoteSplicing; } Ast symUnquote() { return Ast.theUnquote; } } //////////////////////////////////////////////////////////////// // // Minimal implementation of representations for Scheme data. // //////////////////////////////////////////////////////////////// class Ast { static final Ast theEmptyList = new EmptyList(); static final Ast theFalseBoolean = new SchemeBoolean (false); static final Ast theTrueBoolean = new SchemeBoolean (true); // These aren't interned, but that doesn't matter // unless the input file contains the spelled-out versions // of these symbols. static final Ast theBackquote = new SchemeSymbol ("`"); static final Ast theQuote = new SchemeSymbol ("'"); static final Ast theUnquoteSplicing = new SchemeSymbol (",@"); static final Ast theUnquote = new SchemeSymbol (","); // There are no character literals in nboyer.sch. static final int NUMBER_OF_PREBOXED_CHARACTERS = 0; static final SchemeObject[] preBoxedCharacters = new SchemeObject [NUMBER_OF_PREBOXED_CHARACTERS]; // There are few numeric literals in nboyer.sch. static final int LEAST_FIXNUM = -1; static final int GREATEST_FIXNUM = 10; static final SchemeObject[] preBoxedFixnums = { new Fixnum(-1), new Fixnum(0), new Fixnum(1), new Fixnum(2), new Fixnum(3), new Fixnum(4), new Fixnum(5), new Fixnum(6), new Fixnum(7), new Fixnum(8), new Fixnum(9), new Fixnum(10) }; // Methods called by the action routines. static final Ast cons (Ast x, Ast y) { return new Pair (x, y); } static final Ast listToVector (Ast elements) { int n = elements.length(); Ast[] contents = new Ast [n]; for (int i = 0; i < n; i = i + 1) { contents[i] = elements.car(); elements = elements.cdr(); } return new SchemeVector (contents); } static final Ast theCharacter (char c) { int n = (int) c; if (n < NUMBER_OF_PREBOXED_CHARACTERS) return preBoxedCharacters [n]; else return new SchemeCharacter (c); } static final Ast StringBuilderToNumber (StringBuilder buf) { // Ouch. String s = buf.toString(); try { int n = Integer.valueOf (s); if ((LEAST_FIXNUM <= n) && (n <= GREATEST_FIXNUM)) return preBoxedFixnums [n - LEAST_FIXNUM]; else return new Bignum (BigInteger.valueOf (n)); } catch (NumberFormatException e) { } try { double x = Double.valueOf (s); return new Flonum (x); } catch (NumberFormatException e) { } try { BigInteger n = new BigInteger (s); return new Bignum (n); } catch (NumberFormatException e) { } throw new RuntimeException ("Unimplemented number syntax."); } static final Ast StringBuilderToString (StringBuilder buf) { return new SchemeStringImmutable (buf.toString()); } static final Ast StringBuilderToSymbol (StringBuilder buf) { return SchemeSymbol.intern (buf); } static final Ast pseudoAppend (Ast vals, Ast terminus) { if (vals == theEmptyList) return terminus; else return cons (vals.car(), pseudoAppend (vals.cdr(), terminus)); } // Miscellaneous operations needed by the benchmark. private static final String nonListMsg = "Not a list."; int length () { throw new RuntimeException (nonListMsg); } Ast car () { throw new RuntimeException (nonListMsg); } Ast cdr () { throw new RuntimeException (nonListMsg); } // SchemeObject creates a tiny boundary between the Ast class // and the classes that implement Scheme data. private static class SchemeObject extends Ast { // Used by SchemeSymbol. static java.util.Dictionary dict = new java.util.Hashtable(); } private static final class SchemeSymbol extends SchemeObject { static SchemeSymbol intern (StringBuilder buf) { return intern (buf.toString()); } static SchemeSymbol intern (String s) { SchemeSymbol sym = (SchemeSymbol) dict.get(s); if (sym == null) { sym = new SchemeSymbol (s); dict.put (s, sym); } return sym; } // The usual Java stuff. private String printName; SchemeSymbol (String s) { this.printName = s; } public String toString () { return printName; } public int hashCode () { return printName.hashCode(); } public boolean equals (Object x) { if (x == null) return false; else if (x instanceof SchemeSymbol) { SchemeSymbol sym = (SchemeSymbol) x; String symName = sym.printName; return this.printName == symName; } else return false; } } private static final class SchemeStringImmutable extends SchemeObject { String s; SchemeStringImmutable (String s) { this.s = s; } } private static final class EmptyList extends SchemeObject { EmptyList () { } int length () { return 0; } } private static final class Pair extends SchemeObject { Ast x; // the car Ast y; // the cdr Pair (Ast x, Ast y) { this.x = x; this.y = y; } int length () { return y.length() + 1; } Ast car () { return x; } Ast cdr () { return y; } } private static final class SchemeBoolean extends SchemeObject { boolean val; SchemeBoolean (boolean val) { this.val = val; } } private static final class SchemeCharacter extends SchemeObject { char val; SchemeCharacter (char val) { this.val = val; } } private static final class Fixnum extends SchemeObject { int val; Fixnum (int val) { this.val = val; } } private static final class Flonum extends SchemeObject { double val; Flonum (double val) { this.val = val; } } private static final class Bignum extends SchemeObject { BigInteger val; Bignum (BigInteger val) { this.val = val; } } private static final class SchemeVector extends SchemeObject { Ast[] val; SchemeVector (Ast[] val) { this.val = val; } } } //////////////////////////////////////////////////////////////// // // Tokens is just a null-terminated, linked list of int values // that represent a set of tokens. // //////////////////////////////////////////////////////////////// class Tokens { int val; Tokens others; Tokens (int val, Tokens others) { this.val = val; this.others = others; } }