diff --git a/META-INF/MANIFEST.MF b/META-INF/MANIFEST.MF index 7a62999..67b956f 100644 --- a/META-INF/MANIFEST.MF +++ b/META-INF/MANIFEST.MF @@ -6,4 +6,5 @@ Bundle-Version: 1.0.0 Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Export-Package: com.github.jhoenicke.javacup.runtime Bundle-ClassPath: . +Automatic-Module-Name: JavaCup diff --git a/build.properties b/build.properties index 2285858..31faf56 100644 --- a/build.properties +++ b/build.properties @@ -1,7 +1,6 @@ bin.includes = META-INF/,\ - java-cup-12joho.jar,\ - ant.jar,\ . output.. = bin/ -jars.extra.classpath = ant.jar +jars.extra.classpath = ../ant.jar source.. = src/ +jre.compilation.profile = JavaSE-1.8 diff --git a/build.xml b/build.xml index 83f8b5e..14ca56f 100644 --- a/build.xml +++ b/build.xml @@ -11,7 +11,7 @@ - + @@ -56,12 +56,12 @@ - + - + @@ -80,6 +80,9 @@ + + diff --git a/cup/parser.cup b/cup/parser.cup index af923ac..a437743 100644 --- a/cup/parser.cup +++ b/cup/parser.cup @@ -139,7 +139,6 @@ action code {: /* if it wasn't declared of the right type, emit a message */ if (!(sym instanceof terminal)) { - if (ErrorManager.getManager().getErrorCount() == 0) ErrorManager.getManager().emit_warning("Terminal \"" + id + "\" has not been declared", location); return null; @@ -154,7 +153,6 @@ action code {: /* if it wasn't declared of the right type, emit a message */ if (!(sym instanceof non_terminal)) { - if (ErrorManager.getManager().getErrorCount() == 0) ErrorManager.getManager().emit_warning("Non-terminal \"" + id + "\" has not been declared", location); return null; @@ -166,8 +164,7 @@ action code {: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ parser code {: - Main main; - emit emit; + Options options; /* override error routines */ public void report_fatal_error( @@ -177,7 +174,7 @@ parser code {: done_parsing(); if (info instanceof Symbol) ErrorManager.getManager().emit_fatal(message+ "\nCan't recover from previous error(s), giving up.",(Symbol)info); else ErrorManager.getManager().emit_fatal(message + "\nCan't recover from previous error(s), giving up.",cur_token); - System.exit(1); + throw new RuntimeException("jcup fatal error parsing grammar"); } public void report_error(String message, Object info) @@ -257,7 +254,7 @@ package_spec ::= PACKAGE multipart_id:id SEMI {: /* save the package name */ - parser.main.setOption("package", id.toString()); + parser.options.setOption("package", id.toString()); :} | /* empty */ @@ -269,7 +266,7 @@ import_spec ::= IMPORT import_id:id SEMI {: /* save this import on the imports list */ - parser.emit.import_list.add(id.toString()); + parser.options.import_list.add(id.toString()); :} ; @@ -286,27 +283,27 @@ code_parts ::= parser_spec ::= PARSER multipart_id:name SEMI - {: parser.main.setOption("parser", name.toString()); :} + {: parser.options.setOption("parser", name.toString()); :} | PARSER multipart_id:name LT typearglist:types GT SEMI - {: parser.main.setOption("parser", name.toString()); - parser.main.setOption("typearg", types.toString()); :} + {: parser.options.setOption("parser", name.toString()); + parser.options.setOption("typearg", types.toString()); :} ; option_spec ::= OPTION option_list SEMI; option_list ::= option_list COMMA option_ | option_; -option_ ::= robust_id:opt {: parser.main.setOption(opt); :} +option_ ::= robust_id:opt {: parser.options.setOption(opt); :} | robust_id:opt EQUALS robust_id:val - {: parser.main.setOption(opt, val); :}; + {: parser.options.setOption(opt, val); :}; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ action_code_part ::= ACTION CODE CODE_STRING:user_code SEMI? {: - if (parser.emit.action_code!=null) + if (parser.options.action_code!=null) ErrorManager.getManager().emit_warning("Redundant action code (skipping)"); else /* save the user included code string */ - parser.emit.action_code = user_code; + parser.options.action_code = user_code; :} ; @@ -315,10 +312,10 @@ action_code_part ::= parser_code_part ::= PARSER CODE CODE_STRING:user_code SEMI? {: - if (parser.emit.parser_code!=null) + if (parser.options.parser_code!=null) ErrorManager.getManager().emit_warning("Redundant parser code (skipping)"); else /* save the user included code string */ - parser.emit.parser_code = user_code; + parser.options.parser_code = user_code; :} ; @@ -327,10 +324,10 @@ parser_code_part ::= init_code ::= INIT WITH CODE_STRING:user_code SEMI? {: - if (parser.emit.init_code!=null) + if (parser.options.init_code!=null) ErrorManager.getManager().emit_warning("Redundant init code (skipping)"); else /* save the user code */ - parser.emit.init_code = user_code; + parser.options.init_code = user_code; :} ; @@ -339,10 +336,10 @@ init_code ::= scan_code ::= SCAN WITH CODE_STRING:user_code SEMI? {: - if (parser.emit.scan_code!=null) + if (parser.options.scan_code!=null) ErrorManager.getManager().emit_warning("Redundant scan code (skipping)"); else /* save the user code */ - parser.emit.scan_code = user_code; + parser.options.scan_code = user_code; :} ; @@ -351,10 +348,10 @@ scan_code ::= after_reduce_code ::= AFTER REDUCE CODE_STRING:user_code SEMI? {: - if (parser.emit.after_reduce_code!=null) + if (parser.options.after_reduce_code!=null) ErrorManager.getManager().emit_warning("Redundant after reduce code (skipping)"); else /* save the user code */ - parser.emit.after_reduce_code = user_code; + parser.options.after_reduce_code = user_code; :} ; @@ -515,9 +512,8 @@ wild_symbol_id ::= /* if that fails, symbol is undeclared */ if (symb == null) { - if (ErrorManager.getManager().getErrorCount() == 0) ErrorManager.getManager().emit_error("Symbol \"" + symid + - "\" has not been declared"); + "\" has not been declared", symid$); RESULT = null; } else @@ -627,9 +623,9 @@ robust_id ::= /* all ids that aren't reserved words in Java */ | NONASSOC | AFTER | REDUCE - | error + | error:e {: - ErrorManager.getManager().emit_error("Illegal use of reserved word"); + ErrorManager.getManager().emit_error("Illegal use of reserved word", e$); RESULT="ILLEGAL"; :} ; diff --git a/flex/Lexer.jflex b/flex/Lexer.jflex index 2fcf87c..3f8d472 100755 --- a/flex/Lexer.jflex +++ b/flex/Lexer.jflex @@ -8,7 +8,7 @@ import java.io.InputStreamReader; %% %class Lexer -%implements sym, com.github.jhoenicke.javacup.runtime.Scanner +%implements Sym, com.github.jhoenicke.javacup.runtime.Scanner %function next_token %type com.github.jhoenicke.javacup.runtime.Symbol %eofclose @@ -54,7 +54,7 @@ ident = ([:jletter:] | "_" ) ([:jletterdigit:] | [:jletter:] | "_" )* %eofval{ - return symbolFactory.newSymbol("EOF",sym.EOF); + return symbolFactory.newSymbol("EOF",Sym.EOF); %eofval} %state CODESEG diff --git a/src/com/github/jhoenicke/javacup/ErrorManager.java b/src/com/github/jhoenicke/javacup/ErrorManager.java index e40b0e0..e898b84 100644 --- a/src/com/github/jhoenicke/javacup/ErrorManager.java +++ b/src/com/github/jhoenicke/javacup/ErrorManager.java @@ -1,49 +1,113 @@ - package com.github.jhoenicke.javacup; + +import java.util.Set; +import java.util.TreeSet; + import com.github.jhoenicke.javacup.runtime.Symbol; -public class ErrorManager{ - private static ErrorManager errorManager; - private int errors = 0; - private int warnings = 0; - private int fatals = 0; - public int getFatalCount() { return fatals; } - public int getErrorCount() { return errors; } - public int getWarningCount() { return warnings; } - static { - errorManager = new ErrorManager(); - } - public static ErrorManager getManager() { return errorManager; } - private ErrorManager(){ - } - - //TODO: migrate to java.util.logging - /** - * Error message format: - * ERRORLEVEL at (LINE/COLUMN)@SYMBOL: MESSAGE - * ERRORLEVEL : MESSAGE - **/ - public void emit_fatal(String message){ - System.err.println("Fatal: "+message); - fatals++; - } - public void emit_fatal(String message, Symbol sym){ - System.err.println("Fatal: "+message+" @ "+sym); - fatals++; - } - public void emit_warning(String message){ - System.err.println("Warning: " + message); - warnings++; - } - public void emit_warning(String message, Symbol sym){ - System.err.println("Warning: " + message+" @ "+sym); - warnings++; - } - public void emit_error(String message){ - System.err.println("Error: " + message); - errors++; - } - public void emit_error(String message, Symbol sym){ - System.err.println("Error: "+message+" @ "+sym); - errors++; - } + +public class ErrorManager { + + private static ErrorManager errorManager; + + static enum Severity { + Info, + Warning, + Error, + Fatal, + } + + private int infos = 0; + private int warnings = 0; + private int errors = 0; + private int fatals = 0; + + private Set filter; + + private ErrorManager() { + } + + public static ErrorManager getManager() { + if (errorManager == null) errorManager = new ErrorManager(); + return errorManager; + } + + public static void clear () { + errorManager = null; + } + + private Set getFilter () { + if (filter == null) filter = new TreeSet<>(); + return filter; + } + + public int getFatalCount() { + return fatals; + } + + public int getErrorCount() { + return errors; + } + + public int getWarningCount() { + return warnings; + } + + /** + * Error message format: + * ERRORLEVEL : MESSAGE @ Symbol: name#token=="value"(line/column) + * ERRORLEVEL : MESSAGE + **/ + + private void emit (Severity severity, String message, Symbol sym) { + if (sym != null && sym.value != null) { + if (getFilter().contains(sym.value.toString())) return; + getFilter().add(sym.value.toString()); + } + StringBuilder tmp = new StringBuilder(); + tmp.append(severity.name()); + tmp.append(": "); + tmp.append(message); + if (sym != null) { + tmp.append(" @ "); + tmp.append(sym); + } + System.err.println(tmp); + } + + public void emit_info(String message) { + emit_info(message, null); + } + + public void emit_info(String message, Symbol sym) { + emit(Severity.Info, message, sym); + infos++; + } + + public void emit_warning(String message) { + emit_warning(message, null); + } + + public void emit_warning(String message, Symbol sym) { + emit(Severity.Warning, message, sym); + warnings++; + } + + public void emit_error(String message) { + emit_error(message, null); + } + + public void emit_error(String message, Symbol sym) { + emit(Severity.Error, message, sym); + errors++; + } + + public void emit_fatal(String message) { + emit_fatal(message, null); + } + + public void emit_fatal(String message, Symbol sym) { + emit(Severity.Fatal, message, sym); + fatals++; + } + } diff --git a/src/com/github/jhoenicke/javacup/Grammar.java b/src/com/github/jhoenicke/javacup/Grammar.java index 95deaaf..1640055 100644 --- a/src/com/github/jhoenicke/javacup/Grammar.java +++ b/src/com/github/jhoenicke/javacup/Grammar.java @@ -44,10 +44,10 @@ public class Grammar { /* . . . . . . . . . . . . . . . . . . . . . . . . . */ /** Resulting parse action table. */ - private parse_action_table action_table; + public parse_action_table action_table; /** Resulting reduce-goto table. */ - private parse_reduce_table reduce_table; + public parse_reduce_table reduce_table; public Grammar() { @@ -58,7 +58,6 @@ public Grammar() _terminals.add(terminal.error); _terminals.add(terminal.EOF); - _nonterminals.add(non_terminal.START_nt); } public non_terminal get_nonterminal(int i) @@ -194,11 +193,15 @@ public void set_start_symbol(non_terminal start_nt) rhs[1] = new symbol_part(terminal.EOF); action = new action_part("RESULT = " + result + ";\n/* ACCEPT */\nparser.done_parsing();"); + + non_terminal start = new non_terminal("$START", "Object", 0); + _nonterminals.add(start); + _start_production = - new production(0, 0, non_terminal.START_nt, rhs, -1, action, null); + new production(0, 0, start, rhs, -1, action, null); _productions.add(_start_production); _actions.add(_start_production); - non_terminal.START_nt.note_use(); + start.note_use(); } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ @@ -525,69 +528,6 @@ public lalr_state build_machine() return start_state; } - /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ - - /** Produce a human readable dump of the grammar. */ - public void dump_grammar() - { - System.err.println("===== Terminals ====="); - int cnt = 0; - for (terminal t : terminals()) - { - System.err.print("[" + t.index() + "]" + t.name() + " "); - if ((++cnt) % 5 == 0) - System.err.println(); - } - System.err.println(); - System.err.println(); - - System.err.println("===== Non terminals ====="); - cnt = 0; - for (non_terminal nt : non_terminals()) - { - System.err.print("[" + nt.index() + "]" + nt.name() - + " "); - if ((++cnt) % 5 == 0) - System.err.println(); - } - System.err.println(); - System.err.println(); - - System.err.println("===== Productions ====="); - for (production prod : productions()) - { - System.err.println("[" + prod.index() + "] " + prod); - } - System.err.println(); - } - - /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ - - /** - * Produce a (semi-) human readable dump of the complete viable prefix - * recognition state machine. - */ - public void dump_machine() - { - System.err.println("===== Viable Prefix Recognizer ====="); - for (lalr_state st : lalr_states()) - { - System.err.println(st); - System.err.println("-------------------"); - } - } - - /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ - - /** Produce a (semi-) human readable dumps of the parse tables */ - public void dump_tables() - { - System.err.println(action_table); - System.err.println(reduce_table); - } - - /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ - /** Produce a warning message for one reduce/reduce conflict. * * @param itm1 first item in conflict. @@ -615,7 +555,7 @@ public void report_reduce_reduce(lalr_state state, /* count the conflict */ _num_conflicts++; - ErrorManager.getManager().emit_warning(message.toString()); + ErrorManager.getManager().emit_error(message.toString()); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ diff --git a/src/com/github/jhoenicke/javacup/Lexer.java b/src/com/github/jhoenicke/javacup/Lexer.java index ed53d00..ce58859 100644 --- a/src/com/github/jhoenicke/javacup/Lexer.java +++ b/src/com/github/jhoenicke/javacup/Lexer.java @@ -1,4 +1,4 @@ -/* The following code was generated by JFlex 1.4.2 on 07.08.21, 12:52 */ +/* The following code was generated by JFlex 1.4.2 on 17/05/2022 17:55 */ package com.github.jhoenicke.javacup; import com.github.jhoenicke.javacup.runtime.ComplexSymbolFactory; @@ -11,10 +11,10 @@ /** * This class is a scanner generated by * JFlex 1.4.2 - * on 07.08.21, 12:52 from the specification file - * /home/hoenicke/work/git/javacup/flex/Lexer.jflex + * on 17/05/2022 17:55 from the specification file + * C:/Users/miche/eclipse-Workspaces/git-jh-javacup/flex/Lexer.jflex */ -public class Lexer implements sym, com.github.jhoenicke.javacup.runtime.Scanner { +public class Lexer implements Sym, com.github.jhoenicke.javacup.runtime.Scanner { /** This character denotes the end of file */ public static final int YYEOF = -1; @@ -51,109 +51,109 @@ public class Lexer implements sym, com.github.jhoenicke.javacup.runtime.Scanner "\4\0\14\6\16\0\5\6\7\0\1\6\1\0\1\6\21\0\160\6"+ "\5\6\1\0\2\6\2\0\4\6\1\0\1\6\6\0\1\6\1\0"+ "\3\6\1\0\1\6\1\0\24\6\1\0\123\6\1\0\213\6\1\0"+ - "\5\6\2\0\246\6\1\0\46\6\2\0\1\6\7\0\47\6\7\0"+ + "\5\6\2\0\246\6\1\0\46\6\2\0\1\6\6\0\51\6\6\0"+ "\1\6\1\0\55\6\1\0\1\6\1\0\2\6\1\0\2\6\1\0"+ - "\1\6\10\0\33\6\5\0\3\6\15\0\6\6\5\0\1\6\4\0"+ + "\1\6\10\0\33\6\4\0\4\6\15\0\6\6\5\0\1\6\4\0"+ "\13\6\1\0\1\6\3\0\53\6\37\6\4\0\2\6\1\6\143\6"+ "\1\0\1\6\10\6\1\0\6\6\2\6\2\6\1\0\4\6\2\6"+ "\12\6\3\6\2\0\1\6\17\0\1\6\1\6\1\6\36\6\33\6"+ "\2\0\131\6\13\6\1\6\16\0\12\6\41\6\11\6\2\6\4\0"+ - "\1\6\5\0\26\6\4\6\1\6\11\6\1\6\3\6\1\6\5\6"+ - "\22\0\31\6\3\6\4\0\13\6\65\0\25\6\1\0\10\6\26\0"+ - "\60\6\66\6\3\6\1\6\22\6\1\6\7\6\12\6\2\6\2\0"+ - "\12\6\1\0\20\6\3\6\1\0\10\6\2\0\2\6\2\0\26\6"+ - "\1\0\7\6\1\0\1\6\3\0\4\6\2\0\1\6\1\6\7\6"+ - "\2\0\2\6\2\0\3\6\1\6\10\0\1\6\4\0\2\6\1\0"+ - "\3\6\2\6\2\0\12\6\4\6\7\0\2\6\4\0\3\6\1\0"+ - "\6\6\4\0\2\6\2\0\26\6\1\0\7\6\1\0\2\6\1\0"+ - "\2\6\1\0\2\6\2\0\1\6\1\0\5\6\4\0\2\6\2\0"+ - "\3\6\3\0\1\6\7\0\4\6\1\0\1\6\7\0\14\6\3\6"+ - "\1\6\13\0\3\6\1\0\11\6\1\0\3\6\1\0\26\6\1\0"+ - "\7\6\1\0\2\6\1\0\5\6\2\0\1\6\1\6\10\6\1\0"+ - "\3\6\1\0\3\6\2\0\1\6\17\0\2\6\2\6\2\0\12\6"+ - "\1\0\1\6\7\0\1\6\6\6\1\0\3\6\1\0\10\6\2\0"+ - "\2\6\2\0\26\6\1\0\7\6\1\0\2\6\1\0\5\6\2\0"+ - "\1\6\1\6\7\6\2\0\2\6\2\0\3\6\10\0\2\6\4\0"+ - "\2\6\1\0\3\6\2\6\2\0\12\6\1\0\1\6\20\0\1\6"+ - "\1\6\1\0\6\6\3\0\3\6\1\0\4\6\3\0\2\6\1\0"+ - "\1\6\1\0\2\6\3\0\2\6\3\0\3\6\3\0\14\6\4\0"+ - "\5\6\3\0\3\6\1\0\4\6\2\0\1\6\6\0\1\6\16\0"+ - "\12\6\11\0\1\6\6\0\4\6\1\0\10\6\1\0\3\6\1\0"+ - "\27\6\1\0\20\6\3\0\1\6\7\6\1\0\3\6\1\0\4\6"+ - "\7\0\2\6\1\0\3\6\5\0\2\6\2\6\2\0\12\6\20\0"+ - "\1\6\3\6\1\0\10\6\1\0\3\6\1\0\27\6\1\0\12\6"+ - "\1\0\5\6\2\0\1\6\1\6\7\6\1\0\3\6\1\0\4\6"+ - "\7\0\2\6\7\0\1\6\1\0\2\6\2\6\2\0\12\6\1\0"+ - "\2\6\15\0\4\6\1\0\10\6\1\0\3\6\1\0\51\6\2\6"+ - "\1\6\7\6\1\0\3\6\1\0\4\6\1\6\5\0\3\6\1\6"+ - "\7\0\3\6\2\6\2\0\12\6\12\0\6\6\2\0\2\6\1\0"+ - "\22\6\3\0\30\6\1\0\11\6\1\0\1\6\2\0\7\6\3\0"+ - "\1\6\4\0\6\6\1\0\1\6\1\0\10\6\6\0\12\6\2\0"+ - "\2\6\15\0\60\6\1\6\2\6\7\6\4\0\10\6\10\6\1\0"+ - "\12\6\47\0\2\6\1\0\1\6\2\0\2\6\1\0\1\6\2\0"+ - "\1\6\6\0\4\6\1\0\7\6\1\0\3\6\1\0\1\6\1\0"+ - "\1\6\2\0\2\6\1\0\4\6\1\6\2\6\6\6\1\0\2\6"+ - "\1\6\2\0\5\6\1\0\1\6\1\0\6\6\2\0\12\6\2\0"+ - "\4\6\40\0\1\6\27\0\2\6\6\0\12\6\13\0\1\6\1\0"+ - "\1\6\1\0\1\6\4\0\2\6\10\6\1\0\44\6\4\0\24\6"+ - "\1\0\2\6\5\6\13\6\1\0\44\6\11\0\1\6\71\0\53\6"+ - "\24\6\1\6\12\6\6\0\6\6\4\6\4\6\3\6\1\6\3\6"+ - "\2\6\7\6\3\6\4\6\15\6\14\6\1\6\17\6\2\0\46\6"+ - "\1\0\1\6\5\0\1\6\2\0\53\6\1\0\u014d\6\1\0\4\6"+ - "\2\0\7\6\1\0\1\6\1\0\4\6\2\0\51\6\1\0\4\6"+ - "\2\0\41\6\1\0\4\6\2\0\7\6\1\0\1\6\1\0\4\6"+ - "\2\0\17\6\1\0\71\6\1\0\4\6\2\0\103\6\2\0\3\6"+ - "\40\0\20\6\20\0\126\6\2\0\6\6\3\0\u026c\6\2\0\21\6"+ - "\1\0\32\6\5\0\113\6\3\0\13\6\7\0\15\6\1\0\4\6"+ - "\3\6\13\0\22\6\3\6\13\0\22\6\2\6\14\0\15\6\1\0"+ - "\3\6\1\0\2\6\14\0\64\6\40\6\3\0\1\6\3\0\2\6"+ - "\1\6\2\0\12\6\41\0\4\6\1\0\12\6\6\0\130\6\10\0"+ - "\5\6\2\6\42\6\1\6\1\6\5\0\106\6\12\0\37\6\1\0"+ - "\14\6\4\0\14\6\12\0\12\6\36\6\2\0\5\6\13\0\54\6"+ - "\4\0\32\6\6\0\12\6\46\0\27\6\5\6\4\0\65\6\12\6"+ - "\1\0\35\6\2\0\13\6\6\0\12\6\15\0\1\6\10\0\16\6"+ - "\102\0\5\6\57\6\21\6\7\6\4\0\12\6\21\0\11\6\14\0"+ - "\3\6\36\6\15\6\2\6\12\6\54\6\16\6\14\0\44\6\24\6"+ - "\10\0\12\6\3\0\3\6\12\6\44\6\2\0\11\6\107\0\3\6"+ - "\1\0\25\6\4\6\1\6\4\6\3\6\2\6\3\6\6\0\300\6"+ - "\72\6\1\0\5\6\u0116\6\2\0\6\6\2\0\46\6\2\0\6\6"+ - "\2\0\10\6\1\0\1\6\1\0\1\6\1\0\1\6\1\0\37\6"+ - "\2\0\65\6\1\0\7\6\1\0\1\6\3\0\3\6\1\0\7\6"+ - "\3\0\4\6\2\0\6\6\4\0\15\6\5\0\3\6\1\0\7\6"+ - "\16\0\5\6\32\0\5\6\20\0\2\6\23\0\1\6\13\0\5\6"+ - "\1\0\12\6\1\0\1\6\15\0\1\6\20\0\15\6\3\0\40\6"+ - "\20\0\15\6\4\0\1\6\3\0\14\6\21\0\1\6\4\0\1\6"+ - "\2\0\12\6\1\0\1\6\3\0\5\6\6\0\1\6\1\0\1\6"+ - "\1\0\1\6\1\0\4\6\1\0\13\6\2\0\4\6\5\0\5\6"+ - "\4\0\1\6\21\0\51\6\u0a77\0\57\6\1\0\57\6\1\0\205\6"+ - "\6\0\4\6\3\6\2\6\14\0\46\6\1\0\1\6\5\0\1\6"+ - "\2\0\70\6\7\0\1\6\17\0\1\6\27\6\11\0\7\6\1\0"+ - "\7\6\1\0\7\6\1\0\7\6\1\0\7\6\1\0\7\6\1\0"+ - "\7\6\1\0\7\6\1\0\40\6\57\0\1\6\u01d5\0\3\6\31\0"+ - "\11\6\6\6\1\0\5\6\2\0\5\6\4\0\126\6\2\0\2\6"+ - "\2\0\3\6\1\0\132\6\1\0\4\6\5\0\52\6\2\0\136\6"+ - "\21\0\33\6\65\0\20\6\u0200\0\u19b6\6\112\0\u51eb\6\25\0\u048d\6"+ - "\103\0\56\6\2\0\u010d\6\3\0\20\6\12\6\2\6\24\0\57\6"+ - "\1\6\4\0\12\6\1\0\37\6\2\6\120\6\2\6\45\0\11\6"+ - "\2\0\147\6\2\0\44\6\1\0\10\6\77\0\13\6\1\6\3\6"+ - "\1\6\4\6\1\6\27\6\5\6\20\0\1\6\7\0\64\6\14\0"+ - "\2\6\62\6\22\6\12\0\12\6\6\0\22\6\6\6\3\0\1\6"+ - "\1\0\1\6\2\0\12\6\34\6\10\6\2\0\27\6\15\6\14\0"+ - "\35\6\3\0\4\6\57\6\16\6\16\0\1\6\12\6\6\0\5\6"+ - "\1\6\12\6\12\6\5\6\1\0\51\6\16\6\11\0\3\6\1\6"+ - "\10\6\2\6\2\0\12\6\6\0\27\6\3\0\1\6\3\6\62\6"+ - "\1\6\1\6\3\6\2\6\2\6\5\6\2\6\1\6\1\6\1\6"+ - "\30\0\3\6\2\0\13\6\5\6\2\0\3\6\2\6\12\0\6\6"+ - "\2\0\6\6\2\0\6\6\11\0\7\6\1\0\7\6\1\0\53\6"+ - "\1\0\12\6\12\0\163\6\10\6\1\0\2\6\2\0\12\6\6\0"+ - "\u2ba4\6\14\0\27\6\4\0\61\6\u2104\0\u016e\6\2\0\152\6\46\0"+ - "\7\6\14\0\5\6\5\0\1\6\1\6\12\6\1\0\15\6\1\0"+ - "\5\6\1\0\1\6\1\0\2\6\1\0\2\6\1\0\154\6\41\0"+ - "\u016b\6\22\0\100\6\2\0\66\6\50\0\15\6\3\0\20\6\20\0"+ - "\20\6\3\0\2\6\30\0\3\6\31\0\1\6\6\0\5\6\1\0"+ - "\207\6\2\0\1\6\4\0\1\6\13\0\12\6\7\0\32\6\4\0"+ - "\1\6\1\0\32\6\13\0\131\6\3\0\6\6\2\0\6\6\2\0"+ - "\6\6\2\0\3\6\3\0\2\6\3\0\2\6\22\0\3\6\4\0"; + "\1\6\2\0\1\6\30\6\4\6\1\6\11\6\1\6\3\6\1\6"+ + "\5\6\22\0\31\6\3\6\4\0\13\6\65\0\25\6\1\0\22\6"+ + "\13\0\61\6\66\6\3\6\1\6\22\6\1\6\7\6\12\6\2\6"+ + "\2\0\12\6\1\0\20\6\3\6\1\0\10\6\2\0\2\6\2\0"+ + "\26\6\1\0\7\6\1\0\1\6\3\0\4\6\2\0\1\6\1\6"+ + "\7\6\2\0\2\6\2\0\3\6\1\6\10\0\1\6\4\0\2\6"+ + "\1\0\3\6\2\6\2\0\12\6\4\6\7\0\2\6\1\0\1\6"+ + "\2\0\3\6\1\0\6\6\4\0\2\6\2\0\26\6\1\0\7\6"+ + "\1\0\2\6\1\0\2\6\1\0\2\6\2\0\1\6\1\0\5\6"+ + "\4\0\2\6\2\0\3\6\3\0\1\6\7\0\4\6\1\0\1\6"+ + "\7\0\14\6\3\6\1\6\13\0\3\6\1\0\11\6\1\0\3\6"+ + "\1\0\26\6\1\0\7\6\1\0\2\6\1\0\5\6\2\0\1\6"+ + "\1\6\10\6\1\0\3\6\1\0\3\6\2\0\1\6\17\0\2\6"+ + "\2\6\2\0\12\6\1\0\1\6\7\0\1\6\6\6\1\0\3\6"+ + "\1\0\10\6\2\0\2\6\2\0\26\6\1\0\7\6\1\0\2\6"+ + "\1\0\5\6\2\0\1\6\1\6\7\6\2\0\2\6\2\0\3\6"+ + "\7\0\3\6\4\0\2\6\1\0\3\6\2\6\2\0\12\6\1\0"+ + "\1\6\20\0\1\6\1\6\1\0\6\6\3\0\3\6\1\0\4\6"+ + "\3\0\2\6\1\0\1\6\1\0\2\6\3\0\2\6\3\0\3\6"+ + "\3\0\14\6\4\0\5\6\3\0\3\6\1\0\4\6\2\0\1\6"+ + "\6\0\1\6\16\0\12\6\11\0\1\6\6\0\5\6\10\6\1\0"+ + "\3\6\1\0\27\6\1\0\20\6\3\0\1\6\7\6\1\0\3\6"+ + "\1\0\4\6\7\0\2\6\1\0\3\6\5\0\2\6\2\6\2\0"+ + "\12\6\20\0\1\6\3\6\1\0\10\6\1\0\3\6\1\0\27\6"+ + "\1\0\12\6\1\0\5\6\2\0\1\6\1\6\7\6\1\0\3\6"+ + "\1\0\4\6\7\0\2\6\7\0\1\6\1\0\2\6\2\6\2\0"+ + "\12\6\1\0\2\6\15\0\4\6\11\6\1\0\3\6\1\0\51\6"+ + "\2\6\1\6\7\6\1\0\3\6\1\0\4\6\1\6\5\0\3\6"+ + "\1\6\7\0\3\6\2\6\2\0\12\6\12\0\6\6\1\0\3\6"+ + "\1\0\22\6\3\0\30\6\1\0\11\6\1\0\1\6\2\0\7\6"+ + "\3\0\1\6\4\0\6\6\1\0\1\6\1\0\10\6\6\0\12\6"+ + "\2\0\2\6\15\0\60\6\1\6\2\6\7\6\4\0\10\6\10\6"+ + "\1\0\12\6\47\0\2\6\1\0\1\6\1\0\5\6\1\0\30\6"+ + "\1\0\1\6\1\0\12\6\1\6\2\6\11\6\1\6\2\0\5\6"+ + "\1\0\1\6\1\0\6\6\2\0\12\6\2\0\4\6\40\0\1\6"+ + "\27\0\2\6\6\0\12\6\13\0\1\6\1\0\1\6\1\0\1\6"+ + "\4\0\2\6\10\6\1\0\44\6\4\0\24\6\1\0\2\6\5\6"+ + "\13\6\1\0\44\6\11\0\1\6\71\0\53\6\24\6\1\6\12\6"+ + "\6\0\6\6\4\6\4\6\3\6\1\6\3\6\2\6\7\6\3\6"+ + "\4\6\15\6\14\6\1\6\17\6\2\0\46\6\1\0\1\6\5\0"+ + "\1\6\2\0\53\6\1\0\u014d\6\1\0\4\6\2\0\7\6\1\0"+ + "\1\6\1\0\4\6\2\0\51\6\1\0\4\6\2\0\41\6\1\0"+ + "\4\6\2\0\7\6\1\0\1\6\1\0\4\6\2\0\17\6\1\0"+ + "\71\6\1\0\4\6\2\0\103\6\2\0\3\6\40\0\20\6\20\0"+ + "\126\6\2\0\6\6\3\0\u026c\6\2\0\21\6\1\0\32\6\5\0"+ + "\113\6\3\0\13\6\7\0\15\6\1\0\4\6\3\6\13\0\22\6"+ + "\3\6\13\0\22\6\2\6\14\0\15\6\1\0\3\6\1\0\2\6"+ + "\14\0\64\6\40\6\3\0\1\6\3\0\2\6\1\6\2\0\12\6"+ + "\41\0\4\6\1\0\12\6\6\0\131\6\7\0\5\6\2\6\42\6"+ + "\1\6\1\6\5\0\106\6\12\0\37\6\1\0\14\6\4\0\14\6"+ + "\12\0\12\6\36\6\2\0\5\6\13\0\54\6\4\0\32\6\6\0"+ + "\12\6\46\0\27\6\5\6\4\0\65\6\12\6\1\0\35\6\2\0"+ + "\13\6\6\0\12\6\15\0\1\6\10\0\16\6\1\0\2\6\77\0"+ + "\5\6\57\6\21\6\7\6\4\0\12\6\21\0\11\6\14\0\3\6"+ + "\36\6\15\6\2\6\12\6\54\6\16\6\14\0\44\6\24\6\10\0"+ + "\12\6\3\0\3\6\12\6\44\6\2\0\11\6\7\0\53\6\2\0"+ + "\3\6\20\0\3\6\1\0\25\6\4\6\1\6\6\6\1\6\2\6"+ + "\3\6\1\6\5\0\300\6\72\6\1\0\5\6\u0116\6\2\0\6\6"+ + "\2\0\46\6\2\0\6\6\2\0\10\6\1\0\1\6\1\0\1\6"+ + "\1\0\1\6\1\0\37\6\2\0\65\6\1\0\7\6\1\0\1\6"+ + "\3\0\3\6\1\0\7\6\3\0\4\6\2\0\6\6\4\0\15\6"+ + "\5\0\3\6\1\0\7\6\16\0\5\6\32\0\5\6\20\0\2\6"+ + "\23\0\1\6\13\0\5\6\1\0\12\6\1\0\1\6\15\0\1\6"+ + "\20\0\15\6\3\0\40\6\20\0\15\6\4\0\1\6\3\0\14\6"+ + "\21\0\1\6\4\0\1\6\2\0\12\6\1\0\1\6\3\0\5\6"+ + "\6\0\1\6\1\0\1\6\1\0\1\6\1\0\4\6\1\0\13\6"+ + "\2\0\4\6\5\0\5\6\4\0\1\6\21\0\51\6\u0a77\0\57\6"+ + "\1\0\57\6\1\0\205\6\6\0\4\6\3\6\2\6\14\0\46\6"+ + "\1\0\1\6\5\0\1\6\2\0\70\6\7\0\1\6\17\0\1\6"+ + "\27\6\11\0\7\6\1\0\7\6\1\0\7\6\1\0\7\6\1\0"+ + "\7\6\1\0\7\6\1\0\7\6\1\0\7\6\1\0\40\6\57\0"+ + "\1\6\u01d5\0\3\6\31\0\11\6\6\6\1\0\5\6\2\0\5\6"+ + "\4\0\126\6\2\0\2\6\2\0\3\6\1\0\132\6\1\0\4\6"+ + "\5\0\53\6\1\0\136\6\21\0\40\6\60\0\20\6\u0200\0\u19c0\6"+ + "\100\0\u51fd\6\3\0\u048d\6\103\0\56\6\2\0\u010d\6\3\0\20\6"+ + "\12\6\2\6\24\0\57\6\1\6\4\0\12\6\1\0\37\6\2\6"+ + "\120\6\2\6\45\0\11\6\2\0\147\6\2\0\65\6\2\0\11\6"+ + "\52\0\15\6\1\6\3\6\1\6\4\6\1\6\27\6\5\6\4\0"+ + "\1\6\13\0\1\6\7\0\64\6\14\0\2\6\62\6\22\6\12\0"+ + "\12\6\6\0\22\6\6\6\3\0\1\6\1\0\2\6\13\6\34\6"+ + "\10\6\2\0\27\6\15\6\14\0\35\6\3\0\4\6\57\6\16\6"+ + "\16\0\1\6\12\6\6\0\5\6\1\6\12\6\12\6\5\6\1\0"+ + "\51\6\16\6\11\0\3\6\1\6\10\6\2\6\2\0\12\6\6\0"+ + "\27\6\3\0\1\6\3\6\62\6\1\6\1\6\3\6\2\6\2\6"+ + "\5\6\2\6\1\6\1\6\1\6\30\0\3\6\2\0\13\6\5\6"+ + "\2\0\3\6\2\6\12\0\6\6\2\0\6\6\2\0\6\6\11\0"+ + "\7\6\1\0\7\6\1\0\53\6\1\0\16\6\6\0\163\6\10\6"+ + "\1\0\2\6\2\0\12\6\6\0\u2ba4\6\14\0\27\6\4\0\61\6"+ + "\u2104\0\u016e\6\2\0\152\6\46\0\7\6\14\0\5\6\5\0\1\6"+ + "\1\6\12\6\1\0\15\6\1\0\5\6\1\0\1\6\1\0\2\6"+ + "\1\0\2\6\1\0\154\6\41\0\u016b\6\22\0\100\6\2\0\66\6"+ + "\50\0\15\6\3\0\20\6\20\0\20\6\3\0\2\6\30\0\3\6"+ + "\31\0\1\6\6\0\5\6\1\0\207\6\2\0\1\6\4\0\1\6"+ + "\13\0\12\6\7\0\32\6\4\0\1\6\1\0\32\6\13\0\131\6"+ + "\3\0\6\6\2\0\6\6\2\0\6\6\2\0\3\6\3\0\2\6"+ + "\3\0\2\6\22\0\3\6\4\0"; /** * Translates characters to character classes @@ -513,7 +513,7 @@ public Lexer(java.io.InputStream in) { char [] map = new char[0x10000]; int i = 0; /* index in packed string */ int j = 0; /* index in unpacked array */ - while (i < 2280) { + while (i < 2270) { int count = packed.charAt(i++); char value = packed.charAt(i++); do map[j++] = value; while (--count > 0); @@ -1014,7 +1014,7 @@ else if (zzAtEOF) { if (zzInput == YYEOF && zzStartRead == zzCurrentPos) { zzAtEOF = true; zzDoEOF(); - { return symbolFactory.newSymbol("EOF",sym.EOF); + { return symbolFactory.newSymbol("EOF",Sym.EOF); } } else { diff --git a/src/com/github/jhoenicke/javacup/Main.java b/src/com/github/jhoenicke/javacup/Main.java index d5d6821..120a628 100644 --- a/src/com/github/jhoenicke/javacup/Main.java +++ b/src/com/github/jhoenicke/javacup/Main.java @@ -10,63 +10,62 @@ import com.github.jhoenicke.javacup.runtime.ComplexSymbolFactory; - /** * This class serves as the main driver for the JavaCup system. It accepts user * options and coordinates overall control flow. The main flow of control * includes the following activities: *
    - *
  • Parse user supplied arguments and options. - *
  • Open output files. - *
  • Parse the specification from standard input. - *
  • Check for unused terminals, non-terminals, and productions. - *
  • Build the state machine, tables, etc. - *
  • Output the generated code. - *
  • Close output files. - *
  • Print a summary if requested. + *
  • Parse user supplied arguments and options. + *
  • Open output files. + *
  • Parse the specification from standard input. + *
  • Check for unused terminals, non-terminals, and productions. + *
  • Build the state machine, tables, etc. + *
  • Output the generated code. + *
  • Close output files. + *
  • Print a summary if requested. *
* * Options to the main program include: *
- *
-package name - *
specify package generated classes go in [default none] - *
-parser name - *
specify parser class name [default "parser"] - *
-symbols name - *
specify name for symbol constant class [default "sym"] - *
-interface - *
emit symbol constant interface, rather than class - *
-nonterms - *
put non terminals in symbol constant class - *
-expect # - *
number of conflicts expected/allowed [default 0] - *
-compact_red - *
compact tables by defaulting to most frequent reduce - *
-nowarn - *
don't warn about useless productions, etc. - *
-nosummary - *
don't print the usual summary of parse states, etc. - *
-progress - *
print messages to indicate progress of the system - *
-time - *
print time usage summary - *
-dump_grammar - *
produce a dump of the symbols and grammar - *
-dump_states - *
produce a dump of parse state machine - *
-dump_tables - *
produce a dump of the parse tables - *
-dump - *
produce a dump of all of the above - *
-debug - *
turn on debugging messages within JavaCup - *
-nopositions - *
don't generate the positions code - *
-noscanner - *
don't refer to com.github.jhoenicke.javacup.runtime.Scanner in the parser (for compatibility - * with old runtimes) - *
-version - *
print version information for JavaCUP and halt. + *
-package name + *
specify package generated classes go in [default none] + *
-parser name + *
specify parser class name [default "parser"] + *
-symbols name + *
specify name for symbol constant class [default "sym"] + *
-interface + *
emit symbol constant interface, rather than class + *
-nonterms + *
put non terminals in symbol constant class + *
-expect # + *
number of conflicts expected/allowed [default 0] + *
-compact_red + *
compact tables by defaulting to most frequent reduce + *
-nowarn + *
don't warn about useless productions, etc. + *
-nosummary + *
don't print the usual summary of parse states, etc. + *
-progress + *
print messages to indicate progress of the system + *
-time + *
print time usage summary + *
-dump_grammar + *
produce a dump of the symbols and grammar + *
-dump_states + *
produce a dump of parse state machine + *
-dump_tables + *
produce a dump of the parse tables + *
-dump + *
produce a dump of all of the above + *
-debug + *
turn on debugging messages within JavaCup + *
-nopositions + *
don't generate the positions code + *
-noscanner + *
don't refer to com.github.jhoenicke.javacup.runtime.Scanner in the parser + * (for compatibility with old runtimes) + *
-version + *
print version information for JavaCUP and halt. *
* * @version last updated: 7/3/96 @@ -75,886 +74,578 @@ public class Main { - /*-------------------------*/ - /* Options set by the user */ - /*-------------------------*/ - /** User option -- do we print progress messages. */ - private boolean print_progress = false; - /** User option -- do we produce a dump of the state machine */ - private boolean opt_dump_states = false; - /** User option -- do we produce a dump of the parse tables */ - private boolean opt_dump_tables = false; - /** User option -- do we produce a dump of the grammar */ - private boolean opt_dump_grammar = false; - /** User option -- do we show timing information as a part of the summary */ - private boolean opt_show_timing = false; - /** User option -- do we run produce extra debugging messages */ - private boolean opt_do_debug = false; - /** - * User option -- do we compact tables by making most common reduce the - * default action - */ - private boolean opt_compact_red = false; - /** User option -- use java 1.5 syntax (generics, annotations) */ - private boolean opt_java15 = false; - /** - * User option -- should we include non terminal symbol numbers in the symbol - * constant class. - */ - private boolean include_non_terms = false; - /** User option -- do not print a summary. */ - private boolean no_summary = false; - /** User option -- number of conflicts to expect */ - private int expect_conflicts = 0; - - /* frankf added this 6/18/96 */ - /** User option -- should generator update left/right values? */ - private boolean opt_lr_values = true; - /** - * User option -- should generator generate old style access for left/right - * values? - */ - private boolean opt_old_lr_values = true; - - /** User option -- should symbols be put in a class or an interface? [CSA] */ - private boolean sym_interface = false; - - /** - * User option -- should generator suppress references to - * com.github.jhoenicke.javacup.runtime.Scanner for compatibility with old runtimes? - */ - private boolean suppress_scanner = false; - - /*----------------------------------------------------------------------*/ - /* Timing data (not all of these time intervals are mutually exclusive) */ - /*----------------------------------------------------------------------*/ - /** Timing data -- when did we start */ - private long start_time = 0; - /** Timing data -- when did we end preliminaries */ - private long prelim_end = 0; - /** Timing data -- when did we end parsing */ - private long parse_end = 0; - /** Timing data -- when did we end checking */ - private long check_end = 0; - /** Timing data -- when did we end dumping */ - private long dump_end = 0; - /** Timing data -- when did we end state and table building */ - private long build_end = 0; - /** Timing data -- when did we end nullability calculation */ - private long nullability_end = 0; - /** Timing data -- when did we end first set calculation */ - private long first_end = 0; - /** Timing data -- when did we end state machine construction */ - private long machine_end = 0; - /** Timing data -- when did we end table construction */ - private long table_end = 0; - /** Timing data -- when did we end checking for non-reduced productions */ - private long reduce_check_end = 0; - /** Timing data -- when did we finish emitting code */ - private long emit_end = 0; - /** Timing data -- when were we completely done */ - private long final_time = 0; - - emit emit = new emit(); - - /* Additional timing information is also collected in emit */ - - /*-----------------------------------------------------------*/ - /*--- Constructor(s) ----------------------------------------*/ - /*-----------------------------------------------------------*/ - - public Main() - { - start_time = System.currentTimeMillis(); - } - - public boolean run() throws Exception - { - boolean did_output = false; - - prelim_end = System.currentTimeMillis(); - - /* parse spec into internal data structures */ - if (print_progress) - System.err.println("Parsing specification..."); - Grammar grammar = parse_grammar_spec(); - grammar.add_wildcard_rules(); - - parse_end = System.currentTimeMillis(); - - /* don't proceed unless we are error free */ - if (ErrorManager.getManager().getErrorCount() == 0) - { - /* check for unused bits */ - if (print_progress) - System.err.println("Checking specification..."); - check_unused(grammar); - - check_end = System.currentTimeMillis(); - - /* build the state machine and parse tables */ - if (print_progress) - System.err.println("Building parse tables..."); - build_parser(grammar); - - build_end = System.currentTimeMillis(); - - /* output the generated code, if # of conflicts permits */ - if (ErrorManager.getManager().getErrorCount() != 0) - { - // conflicts! don't emit code, don't dump tables. - opt_dump_tables = false; - } - else - { // everything's okay, emit parser. - if (print_progress) - System.err.println("Writing parser..."); - open_files(); - emit_parser(grammar); - did_output = true; - /* close input/output files */ - if (print_progress) - System.err.println("Closing files..."); - close_files(); - } - } - /* fix up the times to make the summary easier */ - emit_end = System.currentTimeMillis(); - - /* do requested dumps */ - if (opt_dump_grammar) - grammar.dump_grammar(); - if (opt_dump_states) - grammar.dump_machine(); - if (opt_dump_tables) - grammar.dump_tables(); - - dump_end = System.currentTimeMillis(); - - /* produce a summary if desired */ - if (!no_summary) - emit_summary(grammar, did_output); - - return ErrorManager.getManager().getErrorCount() == 0; - } - - /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ - - /** - * Print a "usage message" that described possible command line options, then - * exit. - * - * @param message - * a specific error message to preface the usage message by. - */ - private void usage() - { - System.err.println(); - System.err - .println("Usage: " - + version.program_name - + " [options] [filename]\n" - + " and expects a specification file on standard input if no filename is given.\n" - + " Legal options include:\n" - + " -package name specify package generated classes go in [default none]\n" - + " -destdir name specify the destination directory, to store the generated files in\n" - + " -parser name specify parser class name [default \"parser\"]\n" - + " -typearg args specify type arguments for parser class\n" - + " -symbols name specify name for symbol constant class [default \"sym\"]\n" - + " -interface put symbols in an interface, rather than a class\n" - + " -nonterms put non terminals in symbol constant class\n" - + " -expect # number of conflicts expected/allowed [default 0]\n" - + " -compact_red compact tables by defaulting to most frequent reduce\n" - + " -newpositions don't generate old style access for left and right token\n" - + " -nowarn don't warn about useless productions, etc.\n" - + " -nosummary don't print the usual summary of parse states, etc.\n" - + " -nopositions don't propagate the left and right token position values\n" - + " -noscanner don't refer to com.github.jhoenicke.javacup.runtime.Scanner\n" - + " -progress print messages to indicate progress of the system\n" - + " -time print time usage summary\n" - + " -dump_grammar produce a human readable dump of the symbols and grammar\n" - + " -dump_states produce a dump of parse state machine\n" - + " -dump_tables produce a dump of the parse tables\n" - + " -dump produce a dump of all of the above\n" - + " -version print the version information for CUP and exit\n"); - System.exit(1); - } - - public boolean setOption(String option) - { - return setOption(option, null); - } - - public boolean setOption(String option, String arg) - { - /* try to get the various options */ - if (option.equals("package")) - { - /* must have an arg */ - if (arg != null) - { - /* record the name */ - emit.package_name = arg; - return true; - } else - System.err.println("package must have a name argument"); - } - else if (option.equals("destdir")) - { - /* must have an arg */ - if (arg != null) - { - /* record the name */ - dest_dir = new File(arg); - return true; - } else - System.err.println("destdir must have a name argument"); - /* record the name */ - } - else if (option.equals("parser")) - { - /* must have an arg */ - if (arg != null) - { - /* record the name */ - emit.parser_class_name = arg; - return true; - } else - System.err.println("parser must have a name argument"); - } - /* TUM changes; suggested by Henning Niss 20050628 */ - else if (option.equals("typearg")) - { - if (arg == null) - System.err.println("symbols must have a name argument"); - else - { - /* record the typearg */ - opt_java15 = true; - emit.class_type_argument = option; - return true; - } - } - else if (option.equals("symbols")) - { - /* must have an arg */ - if (arg != null) - { - /* record the name */ - emit.symbol_const_class_name = arg; - return true; - } else - System.err.println("symbols must have a name argument"); - } - else if (option.equals("nonterms")) - { - include_non_terms = true; - return true; - } - else if (option.equals("expect")) - { - /* must have an arg */ - if (arg == null) - System.err.println("expect must have a number argument"); - else - { - /* record the number */ - try - { - expect_conflicts = Integer.parseInt(arg); - return true; - } catch (NumberFormatException e) - { - System.err - .println("expect must be followed by a decimal integer"); + private Timer timer; + private Options options; + + /** Count of the number of non-reduced productions found. */ + public int not_reduced = 0; + + /** Count of unused terminals. */ + public int unused_term = 0; + + /** Count of unused non terminals. */ + public int unused_non_term = 0; + + /* Additional timing information is also collected in emit */ + + /*-----------------------------------------------------------*/ + /*--- Constructor(s) ----------------------------------------*/ + /*-----------------------------------------------------------*/ + + public Main() { + ErrorManager.clear(); + timer = new Timer(); + timer.pushTimer(); // global time + timer.pushTimer(); // startup time + options = new Options(); + } + + public int run() throws Exception { + boolean did_output = false; + + timer.popTimer(Timer.TIMESTAMP.preliminary_time); + + /* parse spec into internal data structures */ + timer.pushTimer(); + if (options.print_progress) + ErrorManager.getManager().emit_info("Parsing specification..."); + Grammar grammar = parse_grammar_spec(); + if (grammar == null) return 1; + grammar.add_wildcard_rules(); + timer.popTimer(Timer.TIMESTAMP.parse_time); + + /* check for unused bits */ + timer.pushTimer(); + if (options.print_progress) + ErrorManager.getManager().emit_info("Checking specification..."); + check_unused(grammar); + timer.popTimer(Timer.TIMESTAMP.check_time); + + timer.pushTimer(); + /* don't proceed unless we are error free */ + if (ErrorManager.getManager().getFatalCount() == 0 && ErrorManager.getManager().getErrorCount() == 0) { + + /* build the state machine and parse tables */ + timer.pushTimer(); + if (options.print_progress) + ErrorManager.getManager().emit_info("Building parse tables..."); + build_parser(grammar); + timer.popTimer(Timer.TIMESTAMP.build_time); + + if (options.opt_erase_generated) + emit_erase(grammar); + + /* output the generated code, if # of conflicts permits */ + if (ErrorManager.getManager().getWarningCount() != options.expect_conflicts) { + // conflicts! don't emit code, don't dump tables. + options.opt_dump_tables = false; + } else { // everything's okay, emit parser. + if (options.print_progress) + ErrorManager.getManager().emit_info("Writing parser..."); + emit_symbols(grammar); + emit_parser(grammar); + did_output = true; + if (options.print_progress) + ErrorManager.getManager().emit_info("Done..."); + } + } + timer.popTimer(Timer.TIMESTAMP.emit_time); + + timer.pushTimer(); + /* do requested dumps */ + if (options.opt_dump_grammar || options.opt_dump_states || options.opt_dump_tables) + emit_dumps(grammar); + timer.popTimer(Timer.TIMESTAMP.dump_time); + + timer.popTimer(Timer.TIMESTAMP.final_time); + /* produce a summary if desired */ + if (!options.no_summary) + emit_summary(grammar, did_output); + + return ErrorManager.getManager().getErrorCount() == 0 ? 0 : 1; + + } + + /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ + + /** + * Print a "usage message" that described possible command line options, then + * exit. + * + * @param message a specific error message to preface the usage message by. + */ + private void usage() { + System.err.println(); + System.err.println("Usage: " + version.program_name + " [options] [filename]\n" + + " and expects a specification file on standard input if no filename is given.\n" + + " Legal options include:\n" + + " -package name specify package generated classes go in [default none]\n" + + " -destdir name specify the destination directory, to store the generated files in\n" + + " -parser name specify parser class name [default \"parser\"]\n" + + " -typearg args specify type arguments for parser class\n" + + " -symbols name specify name for symbol constant class [default \"sym\"]\n" + + " -interface put symbols in an interface, rather than a class\n" + + " -nonterms put non terminals in symbol constant class\n" + + " -expect # number of conflicts expected/allowed [default 0]\n" + + " -compact_red compact tables by defaulting to most frequent reduce\n" + + " -newpositions don't generate old style access for left and right token\n" + + " -nowarn don't warn about useless productions, etc.\n" + + " -nosummary don't print the usual summary of parse states, etc.\n" + + " -nopositions don't propagate the left and right token position values\n" + + " -noscanner don't refer to com.github.jhoenicke.javacup.runtime.Scanner\n" + + " -progress print messages to indicate progress of the system\n" + + " -time print time usage summary\n" + + " -dump_grammar produce a human readable dump of the symbols and grammar\n" + + " -dump_states produce a dump of parse state machine\n" + + " -dump_tables produce a dump of the parse tables\n" + + " -dump produce a dump of all of the above\n" + + " -version print the version information for CUP and exit\n"); + } + + /** + * Parse command line options and arguments to set various user-option flags and + * variables. + * + * @param argv the command line arguments to be parsed. + */ + private int parse_args(String argv[]) { + int len = argv.length; + int i; + + /* parse the options */ + for (i = 0; i < len; i++) { + String option = argv[i]; + /* try to get the various options */ + if (option.equals("-package") || option.equals("-destdir") || option.equals("-parser") + || option.equals("-typearg") || option.equals("-symbols") || option.equals("-expect")) { + /* must have an arg */ + if (++i >= len || argv[i].startsWith("-") || argv[i].endsWith(".cup")) + ErrorManager.getManager().emit_fatal(option + " must have an argument"); + else if (!options.setOption(option.substring(1), argv[i])) { + usage(); + return 1; + } + } else if (argv[i].equals("-version")) { + System.out.println(version.title_str); + return 1; + } else if (option.startsWith("-")) { + if (!options.setOption(option.substring(1))) { + usage(); + return 1; + } + } + /* CSA 24-Jul-1999; suggestion by Jean Vaucher */ + else if (!argv[i].startsWith("-") && i == len - 1) { + /* use input from file. */ + try { + input_file = new FileInputStream(argv[i]); + } catch (FileNotFoundException e) { + ErrorManager.getManager().emit_fatal("Unable to open \"" + argv[i] + "\" for input"); + usage(); + return 1; + } + } else { + ErrorManager.getManager().emit_fatal("Unrecognized option \"" + argv[i] + "\""); + usage(); + return 1; + } + } + return 0; + } + + /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ + + /*-------*/ + /* Files */ + /*-------*/ + + /** Input file. This defaults to System.in. */ + private InputStream input_file = System.in; + + /** + * Parse the grammar specification from standard input. This produces sets of + * terminal, non-terminals, and productions which can be accessed via variables + * of the respective classes, as well as the setting of various variables + * (mostly in the emit class) for small user supplied items such as the code to + * scan with. + */ + private Grammar parse_grammar_spec() { + Parser parser_obj; + + /* create a parser and parse with it */ + ComplexSymbolFactory csf = new ComplexSymbolFactory(); + parser_obj = new Parser(new Lexer(input_file, csf), csf); + parser_obj.options = options; + try { + Grammar grammar; + if (options.opt_do_debug) + grammar = (Grammar) parser_obj.debug_parse().value; + else + grammar = (Grammar) parser_obj.parse().value; + if (input_file != System.in) + input_file.close(); + return grammar; + } catch (Exception e) { + ErrorManager.getManager().emit_fatal(e.getMessage()); + return null; } - } - } - else if (option.equals("java15")) - { - opt_java15 = true; - return true; - } - else if (option.equals("compact_red")) - { - opt_compact_red = true; - return true; - } - else if (option.equals("nosummary")) - { - no_summary = true; - return true; - } - else if (option.equals("nowarn")) - { - emit.nowarn = true; - return true; - } - else if (option.equals("dump_states")) - { - opt_dump_states = true; - return true; - } - else if (option.equals("dump_tables")) - { - opt_dump_tables = true; - return true; - } - else if (option.equals("progress")) - { - print_progress = true; - return true; - } - else if (option.equals("dump_grammar")) - { - opt_dump_grammar = true; - return true; - } - else if (option.equals("dump")) - { - opt_dump_states = opt_dump_tables = opt_dump_grammar = true; - return true; - } - else if (option.equals("time")) - { - opt_show_timing = true; - return true; - } - else if (option.equals("debug")) - { - opt_do_debug = true; - return true; - } - /* frankf 6/18/96 */ - else if (option.equals("nopositions")) - { - opt_lr_values = false; - opt_old_lr_values = false; - return true; - } - /* joho 2008-11-10 */ - else if (option.equals("newpositions")) - { - opt_old_lr_values = false; - return true; - } - /* CSA 12/21/97 */ - else if (option.equals("interface")) - { - sym_interface = true; - return true; - } - /* CSA 23-Jul-1999 */ - else if (option.equals("noscanner")) - { - suppress_scanner = true; - return true; - } - /* CSA 23-Jul-1999 */ - else - { - System.err.println("Unrecognized option \"" + option + "\""); - } - - return false; - /*-----------------------------------------------------------*/ - } - - /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ - - /** - * Parse command line options and arguments to set various user-option flags - * and variables. - * - * @param argv - * the command line arguments to be parsed. - */ - private void parse_args(String argv[]) - { - int len = argv.length; - int i; - - /* parse the options */ - for (i=0; i= len || argv[i].startsWith("-") || - argv[i].endsWith(".cup")) - System.err.println(option+" must have an argument"); - else if (!setOption(option.substring(1), argv[i])) - usage(); - } - else if (argv[i].equals("-version")) - { - System.out.println(version.title_str); - System.exit(1); - } - else if (option.startsWith("-")) - { - if (!setOption(option.substring(1))) - usage(); - } - /* CSA 24-Jul-1999; suggestion by Jean Vaucher */ - else if (!argv[i].startsWith("-") && i==len-1) - { - /* use input from file. */ - try { - input_file = new FileInputStream(argv[i]); - } catch (FileNotFoundException e) { - System.err.println("Unable to open \"" + argv[i] +"\" for input"); - usage(); - } - } - else - { - System.err.println("Unrecognized option \"" + argv[i] + "\""); - usage(); - } } - } - - /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ - /*-------*/ - /* Files */ - /*-------*/ - - /** Input file. This defaults to System.in. */ - private InputStream input_file = System.in; - - /** Output file for the parser class. */ - private PrintWriter parser_class_file; - - /** Output file for the symbol constant class. */ - private PrintWriter symbol_class_file; - - /** Output directory. */ - private File dest_dir = null; - - /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ + /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ + + /** + * Check for unused symbols. Unreduced productions get checked when tables are + * created. + */ + private void check_unused(Grammar grammar) { + /* check for unused terminals */ + unused_term = 0; + for (terminal term : grammar.terminals()) { + /* don't issue a message for EOF */ + if (term == terminal.EOF) + continue; + + /* or error */ + if (term == terminal.error) + continue; + + /* is this one unused */ + if (term.use_count() == 0) { + /* count it and warn if we are doing warnings */ + unused_term++; + if (!options.nowarn) { + ErrorManager.getManager() + .emit_warning("Terminal \"" + term.name() + "\" was declared but never used"); + } + } + } - /** Open various files used by the system. */ - private void open_files() - { - File fil; - String out_name; + unused_non_term = 0; + /* check for unused non terminals */ + for (non_terminal nt : grammar.non_terminals()) { + /* is this one unused */ + if (nt.use_count() == 0 || nt.productions().size() == 0) { + /* count and warn if we are doing warnings */ + unused_non_term++; + if (!options.nowarn) { + String reason; + if (nt.use_count() == 0) + reason = "\" was declared but never used"; + else + reason = "\" has no production"; + ErrorManager.getManager().emit_warning("Non terminal \"" + nt.name() + reason); + } + } + } - /* open each of the output files */ + } - /* parser class */ - out_name = emit.parser_class_name + ".java"; - fil = new File(dest_dir, out_name); - try - { - parser_class_file = new PrintWriter(new BufferedOutputStream( - new FileOutputStream(fil), 4096)); - } catch (Exception e) - { - System.err.println("Can't open \"" + out_name + "\" for output"); - System.exit(3); + /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ + + /** + * Build the (internal) parser from the previously parsed specification. This + * includes: + *
    + *
  • Computing nullability of non-terminals. + *
  • Computing first sets of non-terminals and productions. + *
  • Building the viable prefix recognizer machine. + *
  • Filling in the (internal) parse tables. + *
  • Checking for unreduced productions. + *
+ */ + private void build_parser(Grammar grammar) { + timer.pushTimer(); + /* compute nullability of all non terminals */ + if (options.opt_do_debug || options.print_progress) + ErrorManager.getManager().emit_info(" Computing non-terminal nullability..."); + grammar.compute_nullability(); + timer.popTimer(Timer.TIMESTAMP.nullability_time); + + timer.pushTimer(); + /* compute first sets of all non terminals */ + if (options.opt_do_debug || options.print_progress) + ErrorManager.getManager().emit_info(" Computing first sets..."); + grammar.compute_first_sets(); + timer.popTimer(Timer.TIMESTAMP.first_time); + + timer.pushTimer(); + /* build the LR viable prefix recognition machine */ + if (options.opt_do_debug || options.print_progress) + ErrorManager.getManager().emit_info(" Building state machine..."); + grammar.build_machine(); + timer.popTimer(Timer.TIMESTAMP.machine_time); + + timer.pushTimer(); + /* build the LR parser action and reduce-goto tables */ + if (options.opt_do_debug || options.print_progress) + ErrorManager.getManager().emit_info(" Filling in tables..."); + grammar.build_tables(options.opt_compact_red); + timer.popTimer(Timer.TIMESTAMP.table_time); + + timer.pushTimer(); + /* check and warn for non-reduced productions */ + if (options.opt_do_debug || options.print_progress) + ErrorManager.getManager().emit_info(" Checking for non-reduced productions..."); + if (!options.nowarn) + grammar.check_tables(); + timer.popTimer(Timer.TIMESTAMP.reduce_check_time); + + /* if we have more conflicts than we expected issue a message and die */ + if (grammar.num_conflicts() > options.expect_conflicts) { + ErrorManager.getManager() + .emit_error("*** More conflicts encountered than expected " + "-- parser generation aborted"); + // indicate the problem. + // we'll die on return, after clean up. + } } - /* symbol constants class */ - out_name = emit.symbol_const_class_name + ".java"; - fil = new File(dest_dir, out_name); - try - { - symbol_class_file = new PrintWriter(new BufferedOutputStream( - new FileOutputStream(fil), 4096)); - } catch (Exception e) - { - System.err.println("Can't open \"" + out_name + "\" for output"); - System.exit(4); + private File buildFile (String filename, String extension) { + String packageAsFileSystem = options.package_name.replace(".", "/"); + File folder = new File(new File(options.dest_dir == null ? "." : options.dest_dir), packageAsFileSystem); + folder.mkdirs(); + File file = new File(folder, filename+"."+extension); + return file; } - } - - /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ - - /** Close various files used by the system. */ - private void close_files() throws java.io.IOException - { - if (parser_class_file != null) - parser_class_file.close(); - if (symbol_class_file != null) - symbol_class_file.close(); - } - - /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ - - /** - * Parse the grammar specification from standard input. This produces sets of - * terminal, non-terminals, and productions which can be accessed via - * variables of the respective classes, as well as the setting of various - * variables (mostly in the emit class) for small user supplied items such as - * the code to scan with. - */ - private Grammar parse_grammar_spec() - { - parser parser_obj; - - /* create a parser and parse with it */ - ComplexSymbolFactory csf = new ComplexSymbolFactory(); - parser_obj = new parser(new Lexer(input_file, csf), csf); - parser_obj.main = this; - parser_obj.emit = emit; - try - { - Grammar grammar; - if (opt_do_debug) - grammar = (Grammar) parser_obj.debug_parse().value; - else - grammar = (Grammar) parser_obj.parse().value; - if (input_file != System.in) - input_file.close(); - return grammar; + + private void safeDelete (File file) { + try { + if (file.exists()) + file.delete(); + } catch (Exception e) { + ErrorManager.getManager().emit_fatal("Can't delete \"" + file.getAbsolutePath() + "\""); + } } - catch (Exception e) - { - /* The parser should never throw an exception */ - AssertionError error = new AssertionError("Exception in parser"); - error.initCause(e); - throw error; + + private PrintWriter safeOpen (File file) { + PrintWriter writer = null; + try { + writer = new PrintWriter(new BufferedOutputStream(new FileOutputStream(file), 4096)); + } catch (Exception e) { + ErrorManager.getManager().emit_fatal("Can't open \"" + file.getAbsolutePath() + "\""); + } + return writer; + } + + private void safeClose (PrintWriter writer, File file) { + try { + if (writer != null) + writer.close(); + } catch (Exception e) { + ErrorManager.getManager().emit_fatal("Can't close \"" + file.getAbsolutePath() + "\""); + } } - } - - /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ - - /** - * Check for unused symbols. Unreduced productions get checked when tables are - * created. - */ - private void check_unused(Grammar grammar) - { - /* check for unused terminals */ - for (terminal term : grammar.terminals()) - { - /* don't issue a message for EOF */ - if (term == terminal.EOF) - continue; - - /* or error */ - if (term == terminal.error) - continue; - - /* is this one unused */ - if (term.use_count() == 0) - { - /* count it and warn if we are doing warnings */ - emit.unused_term++; - if (!emit.nowarn) - { - ErrorManager.getManager().emit_warning( - "Terminal \"" + term.name() - + "\" was declared but never used"); + + private void emit_erase(Grammar grammar) { + safeDelete (buildFile(options.symbol_const_class_name, "java")); + safeDelete (buildFile(options.parser_class_name, "java")); + safeDelete (buildFile(options.parser_class_name, "dump")); + } + + private void emit_symbols(Grammar grammar) { + File file = buildFile(options.symbol_const_class_name, "java"); + PrintWriter symbol_class_file = safeOpen (file); + if (symbol_class_file != null) { + ErrorManager.getManager().emit_info("Generate Symbol file : "+file.getPath()); + emit emit = new emit (options, timer); + emit.symbols(symbol_class_file, grammar); } - } + safeClose(symbol_class_file, file); } - /* check for unused non terminals */ - for (non_terminal nt : grammar.non_terminals()) - { - /* is this one unused */ - if (nt.use_count() == 0 || nt.productions().size() == 0) - { - /* count and warn if we are doing warnings */ - emit.unused_non_term++; - if (!emit.nowarn) - { - String reason; - if (nt.use_count() == 0) - reason = "\" was declared but never used"; - else - reason = "\" has no production"; - ErrorManager.getManager().emit_warning( - "Non terminal \"" + nt.name() + reason); + private void emit_parser(Grammar grammar) { + File file = buildFile(options.parser_class_name, "java"); + PrintWriter parser_class_file = safeOpen (file); + if (parser_class_file != null) { + ErrorManager.getManager().emit_info("Generate Parser file : "+file.getPath()); + emit emit = new emit (options, timer); + emit.parser(parser_class_file, grammar); } - } + safeClose(parser_class_file, file); } - } - - /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ - - /** - * Build the (internal) parser from the previously parsed specification. This - * includes: - *
    - *
  • Computing nullability of non-terminals. - *
  • Computing first sets of non-terminals and productions. - *
  • Building the viable prefix recognizer machine. - *
  • Filling in the (internal) parse tables. - *
  • Checking for unreduced productions. - *
- */ - private void build_parser(Grammar grammar) - { - /* compute nullability of all non terminals */ - if (opt_do_debug || print_progress) - System.err.println(" Computing non-terminal nullability..."); - grammar.compute_nullability(); - - nullability_end = System.currentTimeMillis(); - - /* compute first sets of all non terminals */ - if (opt_do_debug || print_progress) - System.err.println(" Computing first sets..."); - grammar.compute_first_sets(); - - first_end = System.currentTimeMillis(); - - /* build the LR viable prefix recognition machine */ - if (opt_do_debug || print_progress) - System.err.println(" Building state machine..."); - grammar.build_machine(); - - machine_end = System.currentTimeMillis(); - - /* build the LR parser action and reduce-goto tables */ - if (opt_do_debug || print_progress) - System.err.println(" Filling in tables..."); - grammar.build_tables(opt_compact_red); - - table_end = System.currentTimeMillis(); - - /* check and warn for non-reduced productions */ - if (opt_do_debug || print_progress) - System.err.println(" Checking for non-reduced productions..."); - if (!emit.nowarn) - grammar.check_tables(); - reduce_check_end = System.currentTimeMillis(); - - /* if we have more conflicts than we expected issue a message and die */ - if (grammar.num_conflicts() > expect_conflicts) - { - ErrorManager.getManager().emit_error( - "*** More conflicts encountered than expected " - + "-- parser generation aborted"); - // indicate the problem. - // we'll die on return, after clean up. + private void emit_dumps(Grammar grammar) { + File file = buildFile(options.parser_class_name, "dump"); + PrintWriter dump_file = safeOpen (file); + if (dump_file != null) { + ErrorManager.getManager().emit_info("Generate Dump file : "+file.getPath()); + emit emit = new emit (options, timer); + emit.dumps(dump_file, grammar); + } + safeClose(dump_file, file); + } + + + /** + * Helper routine to optionally return a plural or non-plural ending. + * + * @param val the numerical value determining plurality. + */ + private String plural(int val) { + if (val == 1) + return ""; + else + return "s"; + } + + /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ + + /** + * Emit a long summary message to standard error (System.err) which summarizes + * what was found in the specification, how many states were produced, how many + * conflicts were found, etc. A detailed timing summary is also produced if it + * was requested by the user. + * + * @param output_produced did the system get far enough to generate code. + */ + private void emit_summary(Grammar grammar, boolean output_produced) { + + System.err.println("------- " + version.title_str + " Parser Generation Summary -------"); + + /* error and warning count */ + System.err.println(" " + ErrorManager.getManager().getErrorCount() + " error" + + plural(ErrorManager.getManager().getErrorCount()) + " and " + + ErrorManager.getManager().getWarningCount() + " warning" + + plural(ErrorManager.getManager().getWarningCount())); + + /* basic stats */ + System.err.print(" " + grammar.num_terminals() + " terminal" + plural(grammar.num_terminals()) + ", "); + System.err + .print(grammar.num_non_terminals() + " non-terminal" + plural(grammar.num_non_terminals()) + ", and "); + System.err + .println(grammar.num_productions() + " production" + plural(grammar.num_productions()) + " declared, "); + System.err.print(" producing " + grammar.lalr_states().size() + " unique parse states,"); + System.err.println(" " + grammar.num_actions() + " unique action" + plural(grammar.num_actions()) + ". "); + + /* unused symbols */ + System.err.println(" " + unused_term + " terminal" + plural(unused_term) + " declared but not used."); + System.err.println( + " " + unused_non_term + " non-terminal" + plural(unused_non_term) + " declared but not used."); + + /* productions that didn't reduce */ + System.err.println(" " + not_reduced + " production" + plural(not_reduced) + " never reduced."); + + /* conflicts */ + System.err.println(" " + grammar.num_conflicts() + " conflict" + plural(grammar.num_conflicts()) + " detected" + + " (" + options.expect_conflicts + " expected)."); + + /* code location */ + if (output_produced) + System.err.println(" Code written to \"" + options.parser_class_name + ".java\", and \"" + + options.symbol_const_class_name + ".java\"."); + else + System.err.println(" No code produced."); + + if (options.opt_show_timing) + show_times(); + + System.err.println("---------------------------------------------------- (" + version.version_str + ")"); + } + + /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ + + /** Produce the optional timing summary as part of an overall summary. */ + private void show_times() { + long total_time = timer.getTime(Timer.TIMESTAMP.final_time); + + System.err.println("----------------------------------------------------"); + System.err.println(" Timing Summary"); + System.err.println(timestr(" Total time ", timer.getTime(Timer.TIMESTAMP.final_time), total_time)); + System.err.println(timestr(" Startup ", timer.getTime(Timer.TIMESTAMP.preliminary_time), total_time)); + System.err.println(timestr(" Parse ", timer.getTime(Timer.TIMESTAMP.parse_time), total_time)); + if (timer.hasTime(Timer.TIMESTAMP.check_time)) + System.err.println(timestr(" Checking ", timer.getTime(Timer.TIMESTAMP.check_time), total_time)); + if (timer.hasTime(Timer.TIMESTAMP.build_time)) + System.err.println(timestr(" Parser Build ", timer.getTime(Timer.TIMESTAMP.build_time), total_time)); + if (timer.hasTime(Timer.TIMESTAMP.nullability_time)) + System.err.println(timestr(" Nullability ", timer.getTime(Timer.TIMESTAMP.nullability_time), total_time)); + if (timer.hasTime(Timer.TIMESTAMP.first_time)) + System.err.println(timestr(" First sets ", timer.getTime(Timer.TIMESTAMP.first_time), total_time)); + if (timer.hasTime(Timer.TIMESTAMP.machine_time)) + System.err.println(timestr(" State build ", timer.getTime(Timer.TIMESTAMP.machine_time), total_time)); + if (timer.hasTime(Timer.TIMESTAMP.table_time)) + System.err.println(timestr(" Table build ", timer.getTime(Timer.TIMESTAMP.table_time), total_time)); + if (timer.hasTime(Timer.TIMESTAMP.reduce_check_time)) + System.err.println(timestr(" Checking ", timer.getTime(Timer.TIMESTAMP.reduce_check_time), total_time)); + if (timer.hasTime(Timer.TIMESTAMP.emit_time)) + System.err.println(timestr(" Code Output ", timer.getTime(Timer.TIMESTAMP.emit_time), total_time)); + if (timer.hasTime(Timer.TIMESTAMP.symbols_time)) + System.err.println(timestr(" Symbols ", timer.getTime(Timer.TIMESTAMP.symbols_time), total_time)); + if (timer.hasTime(Timer.TIMESTAMP.parser_time)) + System.err.println(timestr(" Parser class ", timer.getTime(Timer.TIMESTAMP.parser_time), total_time)); + if (timer.hasTime(Timer.TIMESTAMP.action_code_time)) + System.err.println(timestr(" Actions ", timer.getTime(Timer.TIMESTAMP.action_code_time), total_time)); + if (timer.hasTime(Timer.TIMESTAMP.production_table_time)) + System.err.println(timestr(" Prod table ", timer.getTime(Timer.TIMESTAMP.production_table_time), total_time)); + if (timer.hasTime(Timer.TIMESTAMP.action_code_time)) + System.err.println(timestr(" Action tab ", timer.getTime(Timer.TIMESTAMP.action_code_time), total_time)); + if (timer.hasTime(Timer.TIMESTAMP.goto_table_time)) + System.err.println(timestr(" Reduce tab ", timer.getTime(Timer.TIMESTAMP.goto_table_time), total_time)); + + System.err.println(timestr(" Dump Output ", timer.getTime(Timer.TIMESTAMP.dump_time), total_time)); + } + + /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ + + /** + * Helper routine to format a decimal based display of seconds and percentage of + * total time given counts of milliseconds. Note: this is broken for use with + * some instances of negative time (since we don't use any negative time here, + * we let if be for now). + * + * @param prefix a prefix to prepend to the formatted value. + * @param time_val the value being formatted (in ms). + * @param total_time total time percentages are calculated against (in ms). + */ + private String timestr(String prefix, long time_val, long total_time) { + long percent10; + + /* pull out seconds and ms */ + /* construct a pad to blank fill seconds out to 4 places */ + String sec = " " + (time_val / 1000); + String ms = "00" + (time_val % 1000); + + /* calculate 10 times the percentage of total */ + percent10 = (time_val * 1000) / total_time; + + StringBuilder tmp = new StringBuilder(); + tmp.append(prefix); + tmp.append(sec.substring(sec.length() - 4)); + tmp.append("."); + tmp.append(ms.substring(ms.length() - 3)); + tmp.append("sec"); + tmp.append(" ("); + tmp.append(percent10 / 10); + tmp.append("."); + tmp.append(percent10 % 10); + tmp.append("%)"); + return tmp.toString(); + } + + /*-----------------------------------------------------------*/ + + /*-----------------------------------------------------------*/ + /*--- Main Program ------------------------------------------*/ + /*-----------------------------------------------------------*/ + + /** + * The main driver for the system. + * + * @param argv an array of strings containing command line arguments. + */ + public static void main(String argv[]) throws Exception { + Main main = new Main(); + + /* process user options and arguments */ + int code; + code = main.parse_args(argv); + if (code == 0) { + /* run parser, analyser and generater*/ + code = main.run(); + } + if (code == 0) return; + if (! main.options.opt_no_exit) { + System.exit(code); + } } - } - - /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ - - /** Call the emit routines necessary to write out the generated parser. */ - private void emit_parser(Grammar grammar) - { - emit.symbols(symbol_class_file, grammar, include_non_terms, sym_interface); - emit.parser(parser_class_file, grammar, - suppress_scanner, - opt_lr_values, opt_old_lr_values, opt_java15); - } - - /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ - - /** - * Helper routine to optionally return a plural or non-plural ending. - * - * @param val - * the numerical value determining plurality. - */ - private String plural(int val) - { - if (val == 1) - return ""; - else - return "s"; - } - - /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ - - /** - * Emit a long summary message to standard error (System.err) which summarizes - * what was found in the specification, how many states were produced, how - * many conflicts were found, etc. A detailed timing summary is also produced - * if it was requested by the user. - * - * @param output_produced - * did the system get far enough to generate code. - */ - private void emit_summary(Grammar grammar, boolean output_produced) - { - final_time = System.currentTimeMillis(); - - System.err.println("------- " + version.title_str - + " Parser Generation Summary -------"); - - /* error and warning count */ - System.err.println(" " + ErrorManager.getManager().getErrorCount() - + " error" + plural(ErrorManager.getManager().getErrorCount()) - + " and " + ErrorManager.getManager().getWarningCount() + " warning" - + plural(ErrorManager.getManager().getWarningCount())); - - /* basic stats */ - System.err.print(" " + grammar.num_terminals() + " terminal" - + plural(grammar.num_terminals()) + ", "); - System.err.print(grammar.num_non_terminals() + " non-terminal" - + plural(grammar.num_non_terminals()) + ", and "); - System.err.println(grammar.num_productions() + " production" - + plural(grammar.num_productions()) + " declared, "); - System.err.print(" producing " + grammar.lalr_states().size() - + " unique parse states,"); - System.err.println(" " + grammar.num_actions() + " unique action" - + plural(grammar.num_actions()) + ". "); - - /* unused symbols */ - System.err.println(" " + emit.unused_term + " terminal" - + plural(emit.unused_term) + " declared but not used."); - System.err.println(" " + emit.unused_non_term + " non-terminal" - + plural(emit.unused_non_term) + " declared but not used."); - - /* productions that didn't reduce */ - System.err.println(" " + emit.not_reduced + " production" - + plural(emit.not_reduced) + " never reduced."); - - /* conflicts */ - System.err.println(" " + grammar.num_conflicts() + " conflict" - + plural(grammar.num_conflicts()) + " detected" + " (" - + expect_conflicts + " expected)."); - - /* code location */ - if (output_produced) - System.err.println(" Code written to \"" + emit.parser_class_name - + ".java\", and \"" + emit.symbol_const_class_name + ".java\"."); - else - System.err.println(" No code produced."); - - if (opt_show_timing) - show_times(); - - System.err - .println("---------------------------------------------------- (" - + version.version_str + ")"); - } - - /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ - - /** Produce the optional timing summary as part of an overall summary. */ - private void show_times() - { - long total_time = final_time - start_time; - - System.err.println(". . . . . . . . . . . . . . . . . . . . . . . . . "); - System.err.println(" Timing Summary"); - System.err.println(" Total time " - + timestr(final_time - start_time, total_time)); - System.err.println(" Startup " - + timestr(prelim_end - start_time, total_time)); - System.err.println(" Parse " - + timestr(parse_end - prelim_end, total_time)); - if (check_end != 0) - System.err.println(" Checking " - + timestr(check_end - parse_end, total_time)); - if (check_end != 0 && build_end != 0) - System.err.println(" Parser Build " - + timestr(build_end - check_end, total_time)); - if (nullability_end != 0 && check_end != 0) - System.err.println(" Nullability " - + timestr(nullability_end - check_end, total_time)); - if (first_end != 0 && nullability_end != 0) - System.err.println(" First sets " - + timestr(first_end - nullability_end, total_time)); - if (machine_end != 0 && first_end != 0) - System.err.println(" State build " - + timestr(machine_end - first_end, total_time)); - if (table_end != 0 && machine_end != 0) - System.err.println(" Table build " - + timestr(table_end - machine_end, total_time)); - if (reduce_check_end != 0 && table_end != 0) - System.err.println(" Checking " - + timestr(reduce_check_end - table_end, total_time)); - if (emit_end != 0 && build_end != 0) - System.err.println(" Code Output " - + timestr(emit_end - build_end, total_time)); - if (emit.symbols_time != 0) - System.err.println(" Symbols " - + timestr(emit.symbols_time, total_time)); - if (emit.parser_time != 0) - System.err.println(" Parser class " - + timestr(emit.parser_time, total_time)); - if (emit.action_code_time != 0) - System.err.println(" Actions " - + timestr(emit.action_code_time, total_time)); - if (emit.production_table_time != 0) - System.err.println(" Prod table " - + timestr(emit.production_table_time, total_time)); - if (emit.action_table_time != 0) - System.err.println(" Action tab " - + timestr(emit.action_table_time, total_time)); - if (emit.goto_table_time != 0) - System.err.println(" Reduce tab " - + timestr(emit.goto_table_time, total_time)); - - System.err.println(" Dump Output " - + timestr(dump_end - emit_end, total_time)); - } - - /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ - - /** - * Helper routine to format a decimal based display of seconds and percentage - * of total time given counts of milliseconds. Note: this is broken for use - * with some instances of negative time (since we don't use any negative time - * here, we let if be for now). - * - * @param time_val - * the value being formatted (in ms). - * @param total_time - * total time percentages are calculated against (in ms). - */ - private String timestr(long time_val, long total_time) - { - long percent10; - - /* pull out seconds and ms */ - /* construct a pad to blank fill seconds out to 4 places */ - String sec = " "+(time_val / 1000); - String ms = "00"+(time_val % 1000); - - /* calculate 10 times the percentage of total */ - percent10 = (time_val * 1000) / total_time; - - /* build and return the output string */ - return sec.substring(sec.length() - 4) + "." - + ms.substring(ms.length() - 3) + "sec" - + " (" + percent10 / 10 + "." + percent10 % 10 + "%)"; - } - - /*-----------------------------------------------------------*/ - - /*-----------------------------------------------------------*/ - /*--- Main Program ------------------------------------------*/ - /*-----------------------------------------------------------*/ - - /** - * The main driver for the system. - * - * @param argv - * an array of strings containing command line arguments. - */ - public static void main(String argv[]) throws Exception - { - Main main = new Main(); - - /* process user options and arguments */ - main.parse_args(argv); - boolean success = main.run(); - - /* - * If there were errors during the run, exit with non-zero status - * (makefile-friendliness). --CSA - */ - if (!success) - System.exit(1); - } } diff --git a/src/com/github/jhoenicke/javacup/Options.java b/src/com/github/jhoenicke/javacup/Options.java new file mode 100644 index 0000000..5ccadd0 --- /dev/null +++ b/src/com/github/jhoenicke/javacup/Options.java @@ -0,0 +1,243 @@ +package com.github.jhoenicke.javacup; + +import java.util.ArrayList; + +public class Options { + + /** User option -- do we print progress messages. */ + public boolean print_progress = false; + /** User option -- do we produce a dump of the state machine */ + public boolean opt_dump_states = false; + /** User option -- do we produce a dump of the parse tables */ + public boolean opt_dump_tables = false; + /** User option -- do we produce a dump of the grammar */ + public boolean opt_dump_grammar = false; + /** User option -- do we show timing information as a part of the summary */ + public boolean opt_show_timing = false; + /** User option -- do we run produce extra debugging messages */ + public boolean opt_do_debug = false; + /** + * User option -- do we compact tables by making most common reduce the default + * action + */ + public boolean opt_compact_red = false; + /** User option -- use java 1.5 syntax (generics, annotations) */ + public boolean opt_java15 = false; + + /** Package that the resulting code goes into (null is used for unnamed). */ + public String package_name = null; + + /** Directory were the resulting code goes into (null is used for unnamed). */ + public String dest_dir = null; + + /** Name of the generated class for symbol constants. */ + public String symbol_const_class_name = "Sym"; + + /** Name of the generated parser class. */ + public String parser_class_name = "Parser"; + + /** + * TUM changes; proposed by Henning Niss 20050628: Type arguments for class + * declaration + */ + public String class_type_argument = null; + + /** + * User option -- should we include non terminal symbol numbers in the symbol + * constant class. + */ + public boolean include_non_terms = false; + /** User option -- do not print a summary. */ + public boolean no_summary = false; + /** User option -- number of conflicts to expect */ + public int expect_conflicts = 0; + + /** User declarations for direct inclusion in user action class. */ + public String action_code = null; + + /** User declarations for direct inclusion in parser class. */ + public String parser_code = null; + + /** User code for user_init() which is called during parser initialization. */ + public String init_code = null; + + /** User code for scan() which is called to get the next Symbol. */ + public String scan_code = null; + + /** User code that will be called after every reduce call. */ + public String after_reduce_code = null; + + /** List of imports (Strings containing class names) to go with actions. */ + public ArrayList import_list = new ArrayList(); + + /** Do we skip warnings? */ + public boolean nowarn = false; + + /* frankf added this 6/18/96 */ + /** User option -- should generator update left/right values? */ + public boolean opt_lr_values = true; + /** + * User option -- should generator generate old style access for left/right + * values? + */ + public boolean opt_old_lr_values = true; + + /** User option -- should symbols be put in a class or an interface? [CSA] */ + public boolean sym_interface = false; + + /** + * User option -- should generator suppress references to + * com.github.jhoenicke.javacup.runtime.Scanner for compatibility with old + * runtimes? + */ + public boolean suppress_scanner = false; + + /** User option -- erase generated files (parser, sym and dumps every run */ + public boolean opt_erase_generated = true; + + /** User option -- never use System.exit() */ + public boolean opt_no_exit = false; + + public boolean setOption(String option) { + return setOption(option, null); + } + + public boolean setOption(String option, String arg) { + if (option.equals("destdir")) { + if (arg != null) { + dest_dir = arg; + return true; + } else { + ErrorManager.getManager().emit_fatal("destdir must have a name argument"); + return false; + } + } + if (option.equals("package")) { + if (arg != null) { + package_name = arg; + return true; + } else { + ErrorManager.getManager().emit_fatal("package must have a name argument"); + return false; + } + } + if (option.equals("parser")) { + if (arg != null) { + parser_class_name = arg; + return true; + } else { + ErrorManager.getManager().emit_fatal("parser must have a name argument"); + return false; + } + } + if (option.equals("typearg")) { + if (arg != null) { + opt_java15 = true; + class_type_argument = option; + return true; + } else { + ErrorManager.getManager().emit_fatal("symbols must have a name argument"); + return false; + } + } + if (option.equals("symbols")) { + if (arg != null) { + symbol_const_class_name = arg; + return true; + } else { + ErrorManager.getManager().emit_fatal("symbols must have a name argument"); + return false; + } + } + if (option.equals("nonterms")) { + include_non_terms = true; + return true; + } + if (option.equals("expect")) { + if (arg != null) { + try { + expect_conflicts = Integer.parseInt(arg); + return true; + } catch (NumberFormatException e) { + ErrorManager.getManager().emit_fatal("expect must be followed by a decimal integer"); + return false; + } + } else { + ErrorManager.getManager().emit_fatal("expect must have a number argument"); + return false; + } + } + if (option.equals("java15")) { + opt_java15 = true; + return true; + } + if (option.equals("compact_red")) { + opt_compact_red = true; + return true; + } + if (option.equals("nosummary")) { + no_summary = true; + return true; + } + if (option.equals("nowarn")) { + nowarn = true; + return true; + } + if (option.equals("dump_states")) { + opt_dump_states = true; + return true; + } + if (option.equals("dump_tables")) { + opt_dump_tables = true; + return true; + } + if (option.equals("progress")) { + print_progress = true; + return true; + } + if (option.equals("dump_grammar")) { + opt_dump_grammar = true; + return true; + } + if (option.equals("dump")) { + opt_dump_states = opt_dump_tables = opt_dump_grammar = true; + return true; + } + if (option.equals("time")) { + opt_show_timing = true; + return true; + } + if (option.equals("debug")) { + opt_do_debug = true; + return true; + } + if (option.equals("nopositions")) { + opt_lr_values = false; + opt_old_lr_values = false; + return true; + } + if (option.equals("newpositions")) { + opt_old_lr_values = false; + return true; + } + if (option.equals("interface")) { + sym_interface = true; + return true; + } + if (option.equals("noscanner")) { + suppress_scanner = true; + return true; + } + if (option.equals("noerase")) { + opt_erase_generated = false; + return true; + } + if (option.equals("noexit")) { + opt_no_exit = true; + return true; + } + ErrorManager.getManager().emit_fatal("Unrecognized option \"" + option + "\""); + return false; + } + +} diff --git a/src/com/github/jhoenicke/javacup/parser.java b/src/com/github/jhoenicke/javacup/Parser.java similarity index 96% rename from src/com/github/jhoenicke/javacup/parser.java rename to src/com/github/jhoenicke/javacup/Parser.java index c43e8b6..a710923 100644 --- a/src/com/github/jhoenicke/javacup/parser.java +++ b/src/com/github/jhoenicke/javacup/Parser.java @@ -1,7 +1,7 @@ //---------------------------------------------------- -// The following code was generated by jh-javacup-1.2 20210807 -// Sat Aug 07 12:52:46 CEST 2021 +// The following code was generated by jh-javacup-1.3 20220517 +// Thu May 19 08:35:34 GMT+01:00 2022 //---------------------------------------------------- package com.github.jhoenicke.javacup; @@ -11,19 +11,19 @@ import java.util.ArrayList; import java.util.Arrays; -/** jh-javacup-1.2 20210807 generated parser. - * @version Sat Aug 07 12:52:46 CEST 2021 +/** jh-javacup-1.3 20220517 generated parser. + * @version Thu May 19 08:35:34 GMT+01:00 2022 */ -public class parser extends com.github.jhoenicke.javacup.runtime.LRParser { +public class Parser extends com.github.jhoenicke.javacup.runtime.LRParser { /** Default constructor. */ - public parser() {super();} + public Parser() {super();} /** Constructor which sets the default scanner. */ - public parser(com.github.jhoenicke.javacup.runtime.Scanner s) {super(s);} + public Parser(com.github.jhoenicke.javacup.runtime.Scanner s) {super(s);} /** Constructor which sets the default scanner. */ - public parser(com.github.jhoenicke.javacup.runtime.Scanner s, com.github.jhoenicke.javacup.runtime.SymbolFactory sf) {super(s,sf);} + public Parser(com.github.jhoenicke.javacup.runtime.Scanner s, com.github.jhoenicke.javacup.runtime.SymbolFactory sf) {super(s,sf);} /** The static parse table */ static com.github.jhoenicke.javacup.runtime.ParseTable CUP$parse_table = new com.github.jhoenicke.javacup.runtime.ParseTable(new String[] { @@ -265,8 +265,7 @@ public com.github.jhoenicke.javacup.runtime.Symbol do_action( - Main main; - emit emit; + Options options; /* override error routines */ public void report_fatal_error( @@ -276,7 +275,7 @@ public void report_fatal_error( done_parsing(); if (info instanceof Symbol) ErrorManager.getManager().emit_fatal(message+ "\nCan't recover from previous error(s), giving up.",(Symbol)info); else ErrorManager.getManager().emit_fatal(message + "\nCan't recover from previous error(s), giving up.",cur_token); - System.exit(1); + throw new RuntimeException("jcup fatal error parsing grammar"); } public void report_error(String message, Object info) @@ -331,7 +330,6 @@ private terminal get_term(Symbol location, String id) /* if it wasn't declared of the right type, emit a message */ if (!(sym instanceof terminal)) { - if (ErrorManager.getManager().getErrorCount() == 0) ErrorManager.getManager().emit_warning("Terminal \"" + id + "\" has not been declared", location); return null; @@ -346,7 +344,6 @@ private non_terminal get_nonterm(Symbol location, String id) /* if it wasn't declared of the right type, emit a message */ if (!(sym instanceof non_terminal)) { - if (ErrorManager.getManager().getErrorCount() == 0) ErrorManager.getManager().emit_warning("Non-terminal \"" + id + "\" has not been declared", location); return null; @@ -354,10 +351,10 @@ private non_terminal get_nonterm(Symbol location, String id) return (non_terminal)sym; } - private final parser parser; + private final Parser parser; /** Constructor */ - Action$(parser parser) { + Action$(Parser parser) { this.parser = parser; } @@ -409,7 +406,7 @@ private non_terminal get_nonterm(Symbol location, String id) StringBuilder id = (StringBuilder) id$.value; /* save the package name */ - parser.main.setOption("package", id.toString()); + parser.options.setOption("package", id.toString()); return parser.getSymbolFactory().newSymbol("package_spec", 1, CUP$stack.get(CUP$size - 3), CUP$stack.get(CUP$size - 1)); } @@ -428,7 +425,7 @@ private non_terminal get_nonterm(Symbol location, String id) StringBuilder id = (StringBuilder) id$.value; /* save this import on the imports list */ - parser.emit.import_list.add(id.toString()); + parser.options.import_list.add(id.toString()); return parser.getSymbolFactory().newSymbol("import_spec", 11, CUP$stack.get(CUP$size - 3), CUP$stack.get(CUP$size - 1)); } @@ -451,7 +448,7 @@ private non_terminal get_nonterm(Symbol location, String id) { com.github.jhoenicke.javacup.runtime.Symbol name$ = CUP$stack.get(CUP$size - 2); StringBuilder name = (StringBuilder) name$.value; - parser.main.setOption("parser", name.toString()); + parser.options.setOption("parser", name.toString()); return parser.getSymbolFactory().newSymbol("parser_spec", 2, CUP$stack.get(CUP$size - 3), CUP$stack.get(CUP$size - 1)); } @@ -462,8 +459,8 @@ private non_terminal get_nonterm(Symbol location, String id) StringBuilder types = (StringBuilder) types$.value; com.github.jhoenicke.javacup.runtime.Symbol name$ = CUP$stack.get(CUP$size - 5); StringBuilder name = (StringBuilder) name$.value; - parser.main.setOption("parser", name.toString()); - parser.main.setOption("typearg", types.toString()); + parser.options.setOption("parser", name.toString()); + parser.options.setOption("typearg", types.toString()); return parser.getSymbolFactory().newSymbol("parser_spec", 2, CUP$stack.get(CUP$size - 6), CUP$stack.get(CUP$size - 1)); } @@ -484,7 +481,7 @@ private non_terminal get_nonterm(Symbol location, String id) { com.github.jhoenicke.javacup.runtime.Symbol opt$ = CUP$stack.get(CUP$size - 1); String opt = (String) opt$.value; - parser.main.setOption(opt); + parser.options.setOption(opt); return parser.getSymbolFactory().newSymbol("option_", 5, opt$, opt$); } @@ -495,7 +492,7 @@ private non_terminal get_nonterm(Symbol location, String id) String val = (String) val$.value; com.github.jhoenicke.javacup.runtime.Symbol opt$ = CUP$stack.get(CUP$size - 3); String opt = (String) opt$.value; - parser.main.setOption(opt, val); + parser.options.setOption(opt, val); return parser.getSymbolFactory().newSymbol("option_", 5, opt$, val$); } @@ -505,10 +502,10 @@ private non_terminal get_nonterm(Symbol location, String id) com.github.jhoenicke.javacup.runtime.Symbol user_code$ = CUP$stack.get(CUP$size - 2); String user_code = (String) user_code$.value; - if (parser.emit.action_code!=null) + if (parser.options.action_code!=null) ErrorManager.getManager().emit_warning("Redundant action code (skipping)"); else /* save the user included code string */ - parser.emit.action_code = user_code; + parser.options.action_code = user_code; return parser.getSymbolFactory().newSymbol("action_code_part", 6, CUP$stack.get(CUP$size - 4), CUP$stack.get(CUP$size - 1)); } @@ -519,10 +516,10 @@ private non_terminal get_nonterm(Symbol location, String id) com.github.jhoenicke.javacup.runtime.Symbol user_code$ = CUP$stack.get(CUP$size - 2); String user_code = (String) user_code$.value; - if (parser.emit.parser_code!=null) + if (parser.options.parser_code!=null) ErrorManager.getManager().emit_warning("Redundant parser code (skipping)"); else /* save the user included code string */ - parser.emit.parser_code = user_code; + parser.options.parser_code = user_code; return parser.getSymbolFactory().newSymbol("parser_code_part", 9, CUP$stack.get(CUP$size - 4), CUP$stack.get(CUP$size - 1)); } @@ -533,10 +530,10 @@ private non_terminal get_nonterm(Symbol location, String id) com.github.jhoenicke.javacup.runtime.Symbol user_code$ = CUP$stack.get(CUP$size - 2); String user_code = (String) user_code$.value; - if (parser.emit.init_code!=null) + if (parser.options.init_code!=null) ErrorManager.getManager().emit_warning("Redundant init code (skipping)"); else /* save the user code */ - parser.emit.init_code = user_code; + parser.options.init_code = user_code; return parser.getSymbolFactory().newSymbol("init_code", 12, CUP$stack.get(CUP$size - 4), CUP$stack.get(CUP$size - 1)); } @@ -547,10 +544,10 @@ private non_terminal get_nonterm(Symbol location, String id) com.github.jhoenicke.javacup.runtime.Symbol user_code$ = CUP$stack.get(CUP$size - 2); String user_code = (String) user_code$.value; - if (parser.emit.scan_code!=null) + if (parser.options.scan_code!=null) ErrorManager.getManager().emit_warning("Redundant scan code (skipping)"); else /* save the user code */ - parser.emit.scan_code = user_code; + parser.options.scan_code = user_code; return parser.getSymbolFactory().newSymbol("scan_code", 13, CUP$stack.get(CUP$size - 4), CUP$stack.get(CUP$size - 1)); } @@ -561,10 +558,10 @@ private non_terminal get_nonterm(Symbol location, String id) com.github.jhoenicke.javacup.runtime.Symbol user_code$ = CUP$stack.get(CUP$size - 2); String user_code = (String) user_code$.value; - if (parser.emit.after_reduce_code!=null) + if (parser.options.after_reduce_code!=null) ErrorManager.getManager().emit_warning("Redundant after reduce code (skipping)"); else /* save the user code */ - parser.emit.after_reduce_code = user_code; + parser.options.after_reduce_code = user_code; return parser.getSymbolFactory().newSymbol("after_reduce_code", 14, CUP$stack.get(CUP$size - 4), CUP$stack.get(CUP$size - 1)); } @@ -859,9 +856,8 @@ private non_terminal get_nonterm(Symbol location, String id) /* if that fails, symbol is undeclared */ if (symb == null) { - if (ErrorManager.getManager().getErrorCount() == 0) ErrorManager.getManager().emit_error("Symbol \"" + symid + - "\" has not been declared"); + "\" has not been declared", symid$); RESULT = null; } else @@ -986,12 +982,12 @@ private non_terminal get_nonterm(Symbol location, String id) case 58: { String RESULT; + com.github.jhoenicke.javacup.runtime.Symbol e$ = CUP$stack.get(CUP$size - 1); - ErrorManager.getManager().emit_error("Illegal use of reserved word"); + ErrorManager.getManager().emit_error("Illegal use of reserved word", e$); RESULT="ILLEGAL"; - com.github.jhoenicke.javacup.runtime.Symbol CUP$sym = CUP$stack.get(CUP$size - 1); - return parser.getSymbolFactory().newSymbol("robust_id", 29, CUP$sym, CUP$sym, RESULT); + return parser.getSymbolFactory().newSymbol("robust_id", 29, e$, e$, RESULT); } // SEMI? ::= diff --git a/src/com/github/jhoenicke/javacup/sym.java b/src/com/github/jhoenicke/javacup/Sym.java similarity index 93% rename from src/com/github/jhoenicke/javacup/sym.java rename to src/com/github/jhoenicke/javacup/Sym.java index e8a5c00..dcdb635 100644 --- a/src/com/github/jhoenicke/javacup/sym.java +++ b/src/com/github/jhoenicke/javacup/Sym.java @@ -1,13 +1,13 @@ //---------------------------------------------------- -// The following code was generated by jh-javacup-1.2 20210807 -// Sat Aug 07 12:52:46 CEST 2021 +// The following code was generated by jh-javacup-1.3 20220517 +// Thu May 19 08:35:34 GMT+01:00 2022 //---------------------------------------------------- package com.github.jhoenicke.javacup; /** CUP generated interface containing symbol constants. */ -public interface sym { +public interface Sym { /* terminals */ public static final int error = 0; public static final int EOF = 1; diff --git a/src/com/github/jhoenicke/javacup/Timer.java b/src/com/github/jhoenicke/javacup/Timer.java new file mode 100644 index 0000000..4df711e --- /dev/null +++ b/src/com/github/jhoenicke/javacup/Timer.java @@ -0,0 +1,78 @@ +package com.github.jhoenicke.javacup; + +import java.util.Map; +import java.util.Stack; +import java.util.TreeMap; + +public class Timer { + + public enum TIMESTAMP { + preliminary_time, + final_time, + + parse_time, + check_time, + build_time, + emit_time, + dump_time, + + nullability_time, + first_time, + machine_time, + table_time, + reduce_check_time, + + symbols_time, + action_code_time, + production_table_time, + action_table_time, + goto_table_time, + parser_time, + + } + + private Stack starts; + + private Map times = null; + + private Stack getStarts() { + if (starts == null) starts = new Stack<>(); + return starts; + } + + private Map getTimes() { + if (times == null) times = new TreeMap<>(); + return times; + } + + public void clearAllTimer () { + starts = null; + times = null; + } + + public void pushTimer () { + getStarts().add(System.currentTimeMillis()); + } + + public void popTimer (TIMESTAMP timeStamp) { + if (getStarts().isEmpty()) { + ErrorManager.getManager().emit_fatal("Timer stack empty for : "+timeStamp.name()); + } + long started = getStarts().pop(); + long current = System.currentTimeMillis(); + getTimes().put(timeStamp, current-started ); + } + + public void insertTime (TIMESTAMP timeStamp) { + getTimes().put(timeStamp, System.currentTimeMillis()); + } + + public boolean hasTime (TIMESTAMP timeStamp) { + return getTimes().containsKey(timeStamp); + } + + public long getTime (TIMESTAMP timeStamp) { + return getTimes().get(timeStamp); + } + +} diff --git a/src/com/github/jhoenicke/javacup/anttask/CUPTask.java b/src/com/github/jhoenicke/javacup/anttask/CUPTask.java index e0e30ab..0f23e52 100644 --- a/src/com/github/jhoenicke/javacup/anttask/CUPTask.java +++ b/src/com/github/jhoenicke/javacup/anttask/CUPTask.java @@ -177,10 +177,12 @@ protected String inspect(String cupfile){ { String result = line.substring(8,line.indexOf(";")); result = result.replace('.',System.getProperty("file.separator").charAt(0)); + br.close(); return System.getProperty("file.separator") + result; } } + br.close(); }catch (IOException ioe){ } return ""; diff --git a/src/com/github/jhoenicke/javacup/emit.java b/src/com/github/jhoenicke/javacup/emit.java index 73c923a..a45d3b8 100644 --- a/src/com/github/jhoenicke/javacup/emit.java +++ b/src/com/github/jhoenicke/javacup/emit.java @@ -1,906 +1,779 @@ package com.github.jhoenicke.javacup; import java.io.PrintWriter; -import java.util.ArrayList; import java.util.Date; -/** - * This class handles emitting generated code for the resulting parser. - * The various parse tables must be constructed, etc. before calling any - * routines in this class.

+/** + * This class handles emitting generated code for the resulting parser. The + * various parse tables must be constructed, etc. before calling any routines in + * this class. + *

* * Three classes are produced by this code: - *

- *
symbol constant class - *
this contains constant declarations for each terminal (and - * optionally each non-terminal). - *
action class - *
this non-public class contains code to invoke all the user actions - * that were embedded in the parser specification. - *
parser class - *
the specialized parser class consisting primarily of some user - * supplied general and initialization code, and the parse tables. - *

+ *

+ *
symbol constant class + *
this contains constant declarations for each terminal (and optionally + * each non-terminal). + *
action class + *
this non-public class contains code to invoke all the user actions that + * were embedded in the parser specification. + *
parser class + *
the specialized parser class consisting primarily of some user supplied + * general and initialization code, and the parse tables. + *
+ *

* - * Three parse tables are created as part of the parser class: - *

- *
production table - *
lists the LHS non terminal number, and the length of the RHS of - * each production. - *
action table - *
for each state of the parse machine, gives the action to be taken - * (shift, reduce, or error) under each lookahead symbol.
- *
reduce-goto table - *
when a reduce on a given production is taken, the parse stack is - * popped back a number of elements corresponding to the RHS of the - * production. This reveals a prior state, which we transition out - * of under the LHS non terminal symbol for the production (as if we - * had seen the LHS symbol rather than all the symbols matching the - * RHS). This table is indexed by non terminal numbers and indicates - * how to make these transitions. - *

+ * Three parse tables are created as part of the parser class: + *

+ *
production table + *
lists the LHS non terminal number, and the length of the RHS of each + * production. + *
action table + *
for each state of the parse machine, gives the action to be taken (shift, + * reduce, or error) under each lookahead symbol.
+ *
reduce-goto table + *
when a reduce on a given production is taken, the parse stack is popped + * back a number of elements corresponding to the RHS of the production. This + * reveals a prior state, which we transition out of under the LHS non terminal + * symbol for the production (as if we had seen the LHS symbol rather than all + * the symbols matching the RHS). This table is indexed by non terminal numbers + * and indicates how to make these transitions. + *
+ *

* - * In addition to the method interface, this class maintains a series of - * public global variables and flags indicating how misc. parts of the code - * and other output is to be produced, and counting things such as number of - * conflicts detected (see the source code and public variables below for - * more details).

+ * In addition to the method interface, this class maintains a series of public + * global variables and flags indicating how misc. parts of the code and other + * output is to be produced, and counting things such as number of conflicts + * detected (see the source code and public variables below for more details). + *

* - * This class is "static" (contains only data and methods).

+ * This class is "static" (contains only data and methods). + *

* * @see com.github.jhoenicke.javacup.main * @version last update: 11/25/95 * @author Scott Hudson */ -/* Major externally callable routines here include: - symbols - emit the symbol constant class - parser - emit the parser class - - In addition the following major internal routines are provided: - emit_package - emit a package declaration - emit_action_code - emit the class containing the user's actions - emit_production_table - emit declaration and init for the production table - do_action_table - emit declaration and init for the action table - do_reduce_table - emit declaration and init for the reduce-goto table - - Finally, this class uses a number of public instance variables to communicate - optional parameters and flags used to control how code is generated, - as well as to report counts of various things (such as number of conflicts - detected). These include: - - prefix - a prefix string used to prefix names that would - otherwise "pollute" someone else's name space. - package_name - name of the package emitted code is placed in - (or null for an unnamed package. - symbol_const_class_name - name of the class containing symbol constants. - parser_class_name - name of the class for the resulting parser. - action_code - user supplied declarations and other code to be - placed in action class. - parser_code - user supplied declarations and other code to be - placed in parser class. - init_code - user supplied code to be executed as the parser - is being initialized. - scan_code - user supplied code to get the next Symbol. - after_reduce_code - user code that will run after every reduce. - start_production - the start production for the grammar. - import_list - list of imports for use with action class. - num_conflicts - number of conflicts detected. - nowarn - true if we are not to issue warning messages. - not_reduced - count of number of productions that never reduce. - unused_term - count of unused terminal symbols. - unused_non_term - count of unused non terminal symbols. - *_time - a series of symbols indicating how long various - sub-parts of code generation took (used to produce - optional time reports in main). -*/ +/* + * Major externally callable routines here include: symbols - emit the symbol + * constant class parser - emit the parser class + * + * In addition the following major internal routines are provided: emit_package + * - emit a package declaration emit_action_code - emit the class containing the + * user's actions emit_production_table - emit declaration and init for the + * production table do_action_table - emit declaration and init for the action + * table do_reduce_table - emit declaration and init for the reduce-goto table + * + * Finally, this class uses a number of public instance variables to communicate + * optional parameters and flags used to control how code is generated, as well + * as to report counts of various things (such as number of conflicts detected). + * These include: + * + * prefix - a prefix string used to prefix names that would otherwise "pollute" + * someone else's name space. package_name - name of the package emitted code is + * placed in (or null for an unnamed package. symbol_const_class_name - name of + * the class containing symbol constants. parser_class_name - name of the class + * for the resulting parser. action_code - user supplied declarations and other + * code to be placed in action class. parser_code - user supplied declarations + * and other code to be placed in parser class. init_code - user supplied code + * to be executed as the parser is being initialized. scan_code - user supplied + * code to get the next Symbol. after_reduce_code - user code that will run + * after every reduce. start_production - the start production for the grammar. + * import_list - list of imports for use with action class. num_conflicts - + * number of conflicts detected. nowarn - true if we are not to issue warning + * messages. not_reduced - count of number of productions that never reduce. + * unused_term - count of unused terminal symbols. unused_non_term - count of + * unused non terminal symbols. _time - a series of symbols indicating how long + * various sub-parts of code generation took (used to produce optional time + * reports in main). + */ public class emit { - /*-----------------------------------------------------------*/ - /*--- Variables ---------------------------------------------*/ - /*-----------------------------------------------------------*/ - - /** The package name of javacup's runtime. */ - public final static String RUNTIME_PACKAGE = "com.github.jhoenicke.javacup.runtime"; - - /** The prefix placed on names that pollute someone else's name space. */ - public final static String prefix = "CUP$"; - - /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ - - /** Package that the resulting code goes into (null is used for unnamed). */ - public String package_name = null; - - /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ - - /** Name of the generated class for symbol constants. */ - public String symbol_const_class_name = "sym"; - - /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ - - /** Name of the generated parser class. */ - public String parser_class_name = "parser"; - - /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ - - /** TUM changes; proposed by Henning Niss 20050628: Type arguments for class declaration */ - public String class_type_argument = null; - - /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ - - /** User declarations for direct inclusion in user action class. */ - public String action_code = null; + private Options options; + private Timer timer; - /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ + /*-----------------------------------------------------------*/ + /*--- Variables ---------------------------------------------*/ + /*-----------------------------------------------------------*/ - /** User declarations for direct inclusion in parser class. */ - public String parser_code = null; + /** The package name of javacup's runtime. */ + public final static String RUNTIME_PACKAGE = "com.github.jhoenicke.javacup.runtime"; - /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ + /** The prefix placed on names that pollute someone else's name space. */ + public final static String prefix = "CUP$"; - /** User code for user_init() which is called during parser initialization. */ - public String init_code = null; + /*-----------------------------------------------------------*/ + /*--- General Methods ---------------------------------------*/ + /*-----------------------------------------------------------*/ - /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ - - /** User code for scan() which is called to get the next Symbol. */ - public String scan_code = null; - - /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ - - /** User code that will be called after every reduce call. */ - public String after_reduce_code = null; + public emit(Options options, Timer timer) { + super(); + this.options = options; + this.timer = timer; + } - /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ + /** + * Build a string with the standard prefix. + * + * @param str string to prefix. + */ + protected final static String pre(String str) { + return prefix + str; + } - /** List of imports (Strings containing class names) to go with actions. */ - public ArrayList import_list = new ArrayList(); + /** + * TUM changes; proposed by Henning Niss 20050628 Build a string with the + * specified type arguments, if present, otherwise an empty string. + */ + protected String typeArgument() { + return options.class_type_argument == null ? "" : "<" + options.class_type_argument + ">"; + } - /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ + /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ + + /** + * Emit a package spec if the user wants one. + * + * @param out stream to produce output on. + */ + protected void emit_package(PrintWriter out) { + /* generate a package spec if we have a name for one */ + if (options.package_name != null) { + out.println("package " + options.package_name + ";"); + out.println(); + } + } - /** Do we skip warnings? */ - public boolean nowarn = false; + /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ - /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ + public String stackelem(int index, boolean is_java15) { + String access = pre("stack") + ".get(" + pre("size") + " - " + index + ")"; + return is_java15 ? access : "((" + RUNTIME_PACKAGE + ".Symbol) " + access + ")"; + } - /** Count of the number on non-reduced productions found. */ - public int not_reduced = 0; + /** + * Emit code for the symbol constant class, optionally including non terms, if + * they have been requested. + * + * @param out stream to produce output on. + * @param emit_non_terms do we emit constants for non terminals? + * @param sym_interface should we emit an interface, rather than a class? + */ + public void symbols(PrintWriter out, Grammar grammar) { + timer.pushTimer(); + + String class_or_interface = (options.sym_interface) ? "interface" : "class"; + + /* top of file */ + out.println(); + out.println("//----------------------------------------------------"); + out.println("// The following code was generated by " + version.title_str); + out.println("// " + new Date()); + out.println("//----------------------------------------------------"); + out.println(); + emit_package(out); + + /* class header */ + out.println("/** CUP generated " + class_or_interface + " containing symbol constants. */"); + out.println("public " + class_or_interface + " " + options.symbol_const_class_name + " {"); + + out.println(" /* terminals */"); + + /* walk over the terminals */ /* later might sort these */ + for (terminal term : grammar.terminals()) { + + /* output a constant decl for the terminal */ + out.println(" public static final int " + term.name() + " = " + term.index() + ";"); + } - /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ + /* do the non terminals if they want them (parser doesn't need them) */ + if (options.include_non_terms) { + out.println(); + out.println(" /* non terminals */"); - /** Count of unused terminals. */ - public int unused_term = 0; + /* walk over the non terminals */ /* later might sort these */ + for (non_terminal nt : grammar.non_terminals()) { + // **** + // TUM Comment: here we could add a typesafe enumeration + // **** - /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ + /* output a constant decl for the terminal */ + out.println(" static final int " + nt.name() + " = " + nt.index() + ";"); + } + } - /** Count of unused non terminals. */ - public int unused_non_term = 0; + /* end of class */ + out.println("}"); + out.println(); - /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ + timer.popTimer(Timer.TIMESTAMP.symbols_time); + } - /* Timing values used to produce timing report in main.*/ + private void emit_action(PrintWriter out, Grammar grammar, production prod, Options options) { + boolean is_star_action = prod.action() != null && prod.action().code_string().startsWith("CUP$STAR"); + String result = ""; + if (prod.lhs().stack_type() != null && !is_star_action) { + int lastResult = prod.getIndexOfIntermediateResult(); + String init_result = ""; + if (lastResult != -1) { + init_result = " = (" + prod.lhs().stack_type() + ") " + + stackelem(prod.rhs_stackdepth() - lastResult, options.opt_java15) + ".value"; + } else if (prod instanceof action_production) { + init_result = " = null"; + } + /* create the result symbol */ + /* + * make the variable RESULT which will point to the new Symbol (see below) and + * be changed by action code 6/13/96 frankf + */ + out.println(" " + prod.lhs().stack_type() + " RESULT" + init_result + ";"); + + result = ", RESULT"; + } - /** Time to produce symbol constant class. */ - public long symbols_time = 0; + production baseprod; + if (prod instanceof action_production) + baseprod = ((action_production) prod).base_production(); + else + baseprod = prod; + String leftsym = null, rightsym = null; + /* + * Add code to propagate RESULT assignments that occur in action code embedded + * in a production (ie, non-rightmost action code). 24-Mar-1998 CSA + */ + if (options.after_reduce_code != null) + out.println(" " + RUNTIME_PACKAGE + ".Symbol[] " + pre("symbols_array") + " = new " + + RUNTIME_PACKAGE + ".Symbol[" + prod.rhs_stackdepth() + "];"); + for (int i = prod.rhs_stackdepth() - 1; i >= 0; i--) { + symbol_part symbol = baseprod.rhs(i); + String label = symbol.label; + String symtype = symbol.the_symbol.stack_type(); + boolean is_wildcard = !is_star_action && symtype != null + && (symbol.the_symbol.name().endsWith("*") || symbol.the_symbol.name().endsWith("+")); + if (options.after_reduce_code != null) { + out.println(" " + pre("symbols_array") + "[" + i + "] = " + + stackelem(prod.rhs_stackdepth() - i, options.opt_java15) + ";"); + } + if (label != null) { + if (i == 0) + leftsym = label + "$"; + if (i == prod.rhs_stackdepth() - 1) + rightsym = label + "$"; + + out.println(" " + RUNTIME_PACKAGE + ".Symbol " + label + "$ = " + + stackelem(prod.rhs_stackdepth() - i, options.opt_java15) + ";"); + + /* Put in the left/right value labels */ + if (options.opt_old_lr_values) { + out.println(" int " + label + "left = " + label + "$.left;"); + out.println(" int " + label + "right = " + label + "$.right;"); + } + if (symtype != null) { + if (is_wildcard) { + String basetype = symtype.substring(0, symtype.length() - 2); + int arraySuffix = basetype.length(); + while (basetype.charAt(arraySuffix - 2) == '[') + arraySuffix -= 2; + String listtype = "java.util.ArrayList"; + String cast = ""; + if (options.opt_java15) + listtype += "<" + basetype + ">"; + else + cast = "(" + symtype + ") "; + String symbollist = pre("list$" + label); + out.println(" " + listtype + " " + symbollist + " = (" + listtype + ") " + label + + "$.value;"); + out.println(" " + symtype + " " + label + " = " + cast + symbollist + ".toArray(" + + "new " + basetype.substring(0, arraySuffix) + "[" + symbollist + ".size()]" + + basetype.substring(arraySuffix) + ");"); + } else { + out.println(" " + symtype + " " + label + " = (" + symtype + ") " + label + + "$.value;"); + } + } + } + } - /** Time to produce parser class. */ - public long parser_time = 0; + /* if there is an action string, emit it */ + if (prod.action() != null) { + if (prod.action().code_string().startsWith("CUP$STAR")) { + assert (prod.lhs().stack_type() != null); + String symtype = prod.lhs().stack_type(); + String basetype = symtype.substring(0, symtype.length() - 2); + String listtype = "java.util.ArrayList"; + if (options.opt_java15) + listtype += "<" + basetype + ">"; + + switch (prod.action().code_string().charAt(8)) { + case '0': + result = ", new " + listtype + "()"; + break; + case '1': + leftsym = rightsym = pre("0"); + out.println(" " + RUNTIME_PACKAGE + ".Symbol " + rightsym + " = " + + stackelem(prod.rhs_stackdepth(), options.opt_java15) + ";"); + out.println(" " + listtype + " RESULT = new " + listtype + "();"); + out.println(" " + "RESULT.add((" + basetype + ") " + rightsym + ".value);"); + result = ", RESULT"; + break; + case '2': + leftsym = pre("0"); + rightsym = pre("1"); + out.println(" " + RUNTIME_PACKAGE + ".Symbol " + rightsym + " = " + + stackelem(prod.rhs_stackdepth() - 1, options.opt_java15) + ";"); + out.println(" " + RUNTIME_PACKAGE + ".Symbol " + leftsym + " = " + + stackelem(prod.rhs_stackdepth() - 0, options.opt_java15) + ";"); + out.println(" " + listtype + " RESULT = (" + listtype + ") " + leftsym + ".value;"); + out.println(" " + "RESULT.add((" + basetype + ") " + rightsym + ".value);"); + result = ", RESULT"; + break; + } + } else { + out.println(prod.action().code_string()); + } + } - /** Time to produce action code class. */ - public long action_code_time = 0; + /* + * here we have the left and right values being propagated. must make this a + * command line option. frankf 6/18/96 + */ + + /* + * Create the code that assigns the left and right values of the new Symbol that + * the production is reducing to + */ + String leftright = ""; + if (options.opt_lr_values) { + if (prod.rhs_length() <= 1 && rightsym == null) { + leftsym = rightsym = pre("sym"); + out.println(" " + RUNTIME_PACKAGE + ".Symbol " + rightsym + " = " + + stackelem(1, options.opt_java15) + ";"); + } else { + if (rightsym == null) + rightsym = stackelem(1, options.opt_java15); + if (leftsym == null) + leftsym = stackelem(prod.rhs_stackdepth(), options.opt_java15); + } + leftright = ", " + leftsym + ", " + rightsym; + } + /* code to call the after reduce user code */ + if (options.after_reduce_code != null) + out.println(" " + pre("after_reduce") + "(RESULT, " + pre("symbols_array") + ");"); + /* code to return lhs symbol */ + out.println(" return parser.getSymbolFactory().newSymbol(" + "\"" + prod.lhs().name() + "\", " + + prod.lhs().index() + leftright + result + ");"); + } - /** Time to produce the production table. */ - public long production_table_time = 0; + /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ + + /** + * Emit code for the non-public class holding the actual action code. + * + * @param out stream to produce output on. + * @param start_prod the start production of the grammar. + */ + private void emit_action_code(PrintWriter out, Grammar grammar, String action_class, Options options) { + timer.pushTimer(); + + /* Stack generic parameter and optional casts depending on Java Version */ + String genericArg = options.opt_java15 ? "<" + RUNTIME_PACKAGE + ".Symbol>" : " "; + + /* class header */ + out.println(); + out.println("/** Cup generated class to encapsulate user supplied action code.*/"); + /* TUM changes; proposed by Henning Niss 20050628: added type argument */ + out.println((options.opt_java15 ? "static " : "") + "class " + action_class + " {"); + /* user supplied code */ + if (options.action_code != null) { + out.println(); + out.println(options.action_code); + } - /** Time to produce the action table. */ - public long action_table_time = 0; + /* field for parser object */ + /* TUM changes; proposed by Henning Niss 20050628: added typeArgument */ + out.println(" private final " + options.parser_class_name + typeArgument() + " parser;"); + + /* constructor */ + out.println(); + out.println(" /** Constructor */"); + /* TUM changes; proposed by Henning Niss 20050628: added typeArgument */ + out.println(" " + action_class + "(" + options.parser_class_name + typeArgument() + " parser) {"); + out.println(" this.parser = parser;"); + out.println(" }"); + + /* action method head */ + out.println(); + out.println(" /** Method with the actual generated action code. */"); + if (options.opt_java15) + out.println(" @SuppressWarnings({ \"unused\", \"unchecked\" })"); + out.println(" public final " + RUNTIME_PACKAGE + ".Symbol " + pre("do_action") + "("); + out.println(" int " + pre("act_num,")); + out.println(" java.util.ArrayList" + genericArg + " " + pre("stack)")); + out.println(" throws java.lang.Exception"); + out.println(" {"); + + out.println(" /* Stack size for peeking into the stack */"); + out.println(" int " + pre("size") + " = " + pre("stack") + ".size();"); + out.println(); + + /* switch top */ + out.println(" /* select the action based on the action number */"); + out.println(" switch (" + pre("act_num") + ")"); + out.println(" {"); + + /* emit action code for each production as a separate case */ + for (production prod : grammar.actions()) { + /* case label */ + for (production p2 : prod.lhs().productions()) { + if (p2.action_index() == prod.action_index()) + out.println(" // " + p2.toString()); + } + out.println(" case " + prod.action_index() + ":"); + /* give them their own block to work in */ + out.println(" {"); + + emit_action(out, grammar, prod, options); + + /* end of their block */ + out.println(" }"); + out.println(); + } - /** Time to produce the reduce-goto table. */ - public long goto_table_time = 0; + /* end of switch */ + out.println(" /* . . . . . .*/"); + out.println(" default:"); + out.println(" throw new InternalError("); + out.println(" \"Invalid action number found in " + "internal parse table\");"); + out.println(); + out.println(" }"); + + /* end of method */ + out.println(" }"); + + /* user supplied code for after reduce code */ + if (options.after_reduce_code != null) { + out.println(); + out.println(" /** After reduce code */"); + out.println(" public void " + prefix + "after_reduce(Object RESULT, " + RUNTIME_PACKAGE + + ".Symbol[] symbols) throws java.lang.Exception"); + out.println(" {"); + out.println(options.after_reduce_code); + out.println(" }"); + } - /*-----------------------------------------------------------*/ - /*--- General Methods ---------------------------------------*/ - /*-----------------------------------------------------------*/ + /* end of class */ + out.println("}"); + out.println(); + timer.popTimer(Timer.TIMESTAMP.action_code_time); + } - /** Build a string with the standard prefix. - * @param str string to prefix. - */ - protected final static String pre(String str) { - return prefix + str; - } + /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ - /** - * TUM changes; proposed by Henning Niss 20050628 - * Build a string with the specified type arguments, - * if present, otherwise an empty string. - */ - protected String typeArgument() { - return class_type_argument == null ? "" : "<" + class_type_argument + ">"; - } + /** + * Emit the production table. + * + * @param out stream to produce output on. + */ + private String do_production_table(Grammar grammar) { + timer.pushTimer(); - /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ + short[] prod_table = new short[2 * grammar.num_actions()]; + for (production prod : grammar.actions()) { + prod_table[2 * prod.action_index() + 0] = (short) prod.lhs().index(); + prod_table[2 * prod.action_index() + 1] = (short) prod.rhs_length(); + } + String result = do_array_as_string(prod_table); + timer.popTimer(Timer.TIMESTAMP.production_table_time); + return result; + } - /** Emit a package spec if the user wants one. - * @param out stream to produce output on. - */ - protected void emit_package(PrintWriter out) - { - /* generate a package spec if we have a name for one */ - if (package_name != null) { - out.println("package " + package_name + ";"); out.println(); - } - } + /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ + + /** + * Emit the action table. + * + * @param out stream to produce output on. + * @param act_tab the internal representation of the action table. + * @param compact_reduces do we use the most frequent reduce as default? + */ + private String do_action_table(Grammar grammar) { + timer.pushTimer(); + + parse_action_table act_tab = grammar.action_table(); + int[] base_tab = new int[act_tab.table.length]; + short[] action_tab = act_tab.compress(base_tab); + String result = do_array_as_string(base_tab) + do_array_as_string(action_tab); + timer.popTimer(Timer.TIMESTAMP.action_table_time); + return result; + } - /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ - - public String stackelem(int index, boolean is_java15) - { - String access = pre("stack") + ".get(" + pre("size") + " - " + index + ")"; - return is_java15 ? access : "((" + RUNTIME_PACKAGE + ".Symbol) "+access+")"; - } + /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ - /** Emit code for the symbol constant class, optionally including non terms, - * if they have been requested. - * @param out stream to produce output on. - * @param emit_non_terms do we emit constants for non terminals? - * @param sym_interface should we emit an interface, rather than a class? - */ - public void symbols(PrintWriter out, Grammar grammar, - boolean emit_non_terms, boolean sym_interface) - { - String class_or_interface = (sym_interface)?"interface":"class"; - - long start_time = System.currentTimeMillis(); - - /* top of file */ - out.println(); - out.println("//----------------------------------------------------"); - out.println("// The following code was generated by " + - version.title_str); - out.println("// " + new Date()); - out.println("//----------------------------------------------------"); - out.println(); - emit_package(out); - - /* class header */ - out.println("/** CUP generated " + class_or_interface + - " containing symbol constants. */"); - out.println("public " + class_or_interface + " " + - symbol_const_class_name + " {"); - - out.println(" /* terminals */"); - - /* walk over the terminals */ /* later might sort these */ - for (terminal term : grammar.terminals()) - { - - /* output a constant decl for the terminal */ - out.println(" public static final int " + term.name() + " = " + - term.index() + ";"); - } + /** + * Create the compressed reduce-goto table. + * + * @param red_tab the internal representation of the reduce-goto table. + */ + private String do_reduce_table(Grammar grammar) { + timer.pushTimer(); - /* do the non terminals if they want them (parser doesn't need them) */ - if (emit_non_terms) - { - out.println(); - out.println(" /* non terminals */"); - - /* walk over the non terminals */ /* later might sort these */ - for (non_terminal nt : grammar.non_terminals()) - { - // **** - // TUM Comment: here we could add a typesafe enumeration - // **** - - /* output a constant decl for the terminal */ - out.println(" static final int " + nt.name() + " = " + - nt.index() + ";"); - } + parse_reduce_table red_tab = grammar.reduce_table(); + String result = do_array_as_string(red_tab.compress()); + timer.popTimer(Timer.TIMESTAMP.goto_table_time); + return result; } - /* end of class */ - out.println("}"); - out.println(); - - symbols_time = System.currentTimeMillis() - start_time; - } - - private void emit_action(PrintWriter out, Grammar grammar, production prod, - boolean lr_values, boolean old_lr_values, boolean is_java15) - { - boolean is_star_action = - prod.action() != null && prod.action().code_string().startsWith("CUP$STAR"); - String result = ""; - if (prod.lhs().stack_type() != null && !is_star_action) - { - int lastResult = prod.getIndexOfIntermediateResult(); - String init_result = ""; - if (lastResult!=-1) - { - init_result = " = (" + prod.lhs().stack_type() + ") " + - stackelem(prod.rhs_stackdepth() - lastResult, is_java15)+".value"; - } - else if (prod instanceof action_production) - { - init_result = " = null"; - } - /* create the result symbol */ - /* make the variable RESULT which will point to the new Symbol - * (see below) and be changed by action code - * 6/13/96 frankf */ - out.println(" " + prod.lhs().stack_type() + - " RESULT"+init_result+";"); - - result = ", RESULT"; + /** create a string encoding a given short[] array. */ + private String do_array_as_string(short[] sharr) { + StringBuilder sb = new StringBuilder(); + if (sharr.length >= 0x8000) + sb.append((char) (0x8000 + (sharr.length >> 16))); + sb.append((char) (sharr.length & 0xffff)); + for (int i = 0; i < sharr.length; i++) + sb.append((char) sharr[i]); + return sb.toString(); } - production baseprod; - if (prod instanceof action_production) - baseprod = ((action_production)prod).base_production(); - else - baseprod = prod; - String leftsym = null, rightsym = null; - /* Add code to propagate RESULT assignments that occur in - * action code embedded in a production (ie, non-rightmost - * action code). 24-Mar-1998 CSA - */ - if (after_reduce_code != null) - out.println(" " + RUNTIME_PACKAGE + ".Symbol[] " + - pre("symbols_array") + " = new " + - RUNTIME_PACKAGE + ".Symbol[" + prod.rhs_stackdepth() + "];"); - for (int i=prod.rhs_stackdepth()-1; i>=0; i--) - { - symbol_part symbol = baseprod.rhs(i); - String label = symbol.label; - String symtype = symbol.the_symbol.stack_type(); - boolean is_wildcard = !is_star_action && symtype != null - && (symbol.the_symbol.name().endsWith("*") - || symbol.the_symbol.name().endsWith("+")); - if (after_reduce_code != null) - { - out.println(" " + pre("symbols_array") + "[" + i + "] = " + - stackelem(prod.rhs_stackdepth() - i, is_java15) + ";"); - } - if (label != null) - { - if (i == 0) - leftsym = label+"$"; - if (i == prod.rhs_stackdepth()-1) - rightsym = label+"$"; - - out.println(" " + RUNTIME_PACKAGE + ".Symbol " + - label + "$ = " + - stackelem(prod.rhs_stackdepth() - i, is_java15) + ";"); - - /* Put in the left/right value labels */ - if (old_lr_values) - { - out.println(" int "+label+"left = "+ - label + "$.left;"); - out.println(" int "+label+"right = "+ - label + "$.right;"); + /** create a string encoding a given short[] array. */ + private String do_array_as_string(int[] intarr) { + StringBuilder sb = new StringBuilder(); + if (intarr.length >= 0x8000) + sb.append((char) (0x8000 + (intarr.length >> 16))); + sb.append((char) (intarr.length & 0xffff)); + for (int i = 0; i < intarr.length; i++) { + assert (intarr[i] >= 0); + if (intarr[i] >= 0x8000) + sb.append((char) (0x8000 + (intarr[i] >> 16))); + sb.append((char) (intarr[i] & 0xffff)); } - if (symtype != null) - { - if (is_wildcard) - { - String basetype = symtype.substring(0, symtype.length()-2); - int arraySuffix = basetype.length(); - while (basetype.charAt(arraySuffix-2) == '[') - arraySuffix -= 2; - String listtype = "java.util.ArrayList"; - String cast = ""; - if (is_java15) - listtype += "<" + basetype + ">"; - else - cast = "(" + symtype + ") "; - String symbollist = pre("list$" + label); - out.println(" " + listtype + " " + symbollist + - " = (" + listtype + ") " + label + "$.value;"); - out.println(" " + symtype + " " + label + - " = " + cast + symbollist + ".toArray(" + - "new " + basetype.substring(0, arraySuffix) + - "[" + symbollist + ".size()]" + - basetype.substring(arraySuffix) + ");"); - } - else - { - out.println(" " + symtype + - " " + label + " = (" + symtype + ") " + - label + "$.value;"); - } - } - } + return sb.toString(); } - /* if there is an action string, emit it */ - if (prod.action() != null) - { - if (prod.action().code_string().startsWith("CUP$STAR")) - { - assert(prod.lhs().stack_type() != null); - String symtype = prod.lhs().stack_type(); - String basetype = symtype.substring(0, symtype.length()-2); - String listtype = "java.util.ArrayList"; - if (is_java15) - listtype += "<" + basetype + ">"; - - switch (prod.action().code_string().charAt(8)) - { - case '0': - result = ", new "+listtype+"()"; - break; - case '1': - leftsym = rightsym = pre("0"); - out.println(" " + RUNTIME_PACKAGE + ".Symbol " + - rightsym + " = " + - stackelem(prod.rhs_stackdepth(), is_java15) + ";"); - out.println(" " + listtype + - " RESULT = new "+listtype+"();"); - out.println(" " + - "RESULT.add((" + basetype + ") " + rightsym +".value);"); - result = ", RESULT"; - break; - case '2': - leftsym = pre("0"); - rightsym = pre("1"); - out.println(" " + RUNTIME_PACKAGE + ".Symbol " + - rightsym + " = " + - stackelem(prod.rhs_stackdepth() - 1, is_java15) + ";"); - out.println(" " + RUNTIME_PACKAGE + ".Symbol " + - leftsym + " = " + - stackelem(prod.rhs_stackdepth() - 0, is_java15) + ";"); - out.println(" " + listtype + - " RESULT = ("+listtype+") " + leftsym + ".value;"); - out.println(" " + - "RESULT.add((" + basetype + ") " + rightsym +".value);"); - result = ", RESULT"; - break; - } - } - else - { - out.println(prod.action().code_string()); - } - } - - /* here we have the left and right values being propagated. - must make this a command line option. - frankf 6/18/96 */ - - /* Create the code that assigns the left and right values of - the new Symbol that the production is reducing to */ - String leftright = ""; - if (lr_values) - { - if (prod.rhs_length() <= 1 && rightsym == null) - { - leftsym = rightsym = pre("sym"); - out.println(" " + RUNTIME_PACKAGE + ".Symbol " + rightsym + " = " + - stackelem(1, is_java15) + ";"); - } - else - { - if (rightsym == null) - rightsym = stackelem(1, is_java15); - if (leftsym == null) - leftsym = stackelem(prod.rhs_stackdepth(), is_java15); - } - leftright = ", " + leftsym + ", " + rightsym; - } - /* code to call the after reduce user code */ - if (after_reduce_code != null) - out.println(" " + pre("after_reduce") + "(RESULT, " + - pre("symbols_array") + ");"); - /* code to return lhs symbol */ - out.println(" return parser.getSymbolFactory().newSymbol(" + - "\"" + prod.lhs().name() + "\", " + - prod.lhs().index() + leftright + result + ");"); - } - - /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ - - /** Emit code for the non-public class holding the actual action code. - * @param out stream to produce output on. - * @param start_prod the start production of the grammar. - */ - private void emit_action_code(PrintWriter out, Grammar grammar, String action_class, - boolean lr_values, boolean old_lr_values, boolean is_java15) - { - long start_time = System.currentTimeMillis(); - - /* Stack generic parameter and optional casts depending on Java Version */ - String genericArg = is_java15 ? "<" + RUNTIME_PACKAGE + ".Symbol>" : " "; - - /* class header */ - out.println(); - out.println( - "/** Cup generated class to encapsulate user supplied action code.*/" - ); - /* TUM changes; proposed by Henning Niss 20050628: added type argument */ - out.println((is_java15 ? "static ": "") + "class " + action_class + " {"); - /* user supplied code */ - if (action_code != null) - { - out.println(); - out.println(action_code); + /** print a string in java source code */ + private void output_string(PrintWriter out, String str) { + int utf8len = 0; + for (int i = 0; i < str.length(); i += 11) { + StringBuilder encoded = new StringBuilder(); + encoded.append(" \""); + for (int j = 0; j < 11 && i + j < str.length(); j++) { + char c = str.charAt(i + j); + encoded.append('\\'); + if (c < 256) { + String oct = "000" + Integer.toOctalString(c); + oct = oct.substring(oct.length() - 3); + encoded.append(oct); + } else { + String hex = "0000" + Integer.toHexString(c); + hex = hex.substring(hex.length() - 4); + encoded.append('u').append(hex); + } + utf8len++; + if (c >= 128 || c == 0) { + utf8len++; + if (c >= 2048) + utf8len++; + } + } + encoded.append("\""); + if (i + 11 < str.length()) { + if (utf8len > 65000) { + encoded.append(","); + utf8len = 0; + } else + encoded.append(" +"); + } + out.println(encoded.toString()); + } } - /* field for parser object */ - /* TUM changes; proposed by Henning Niss 20050628: added typeArgument */ - out.println(" private final "+parser_class_name + typeArgument() + " parser;"); - - /* constructor */ - out.println(); - out.println(" /** Constructor */"); - /* TUM changes; proposed by Henning Niss 20050628: added typeArgument */ - out.println(" " + action_class + "("+parser_class_name+typeArgument()+" parser) {"); - out.println(" this.parser = parser;"); - out.println(" }"); - - /* action method head */ - out.println(); - out.println(" /** Method with the actual generated action code. */"); - if (is_java15) - out.println(" @SuppressWarnings({ \"unused\", \"unchecked\" })"); - out.println(" public final " + RUNTIME_PACKAGE + ".Symbol " + - pre("do_action") + "("); - out.println(" int " + pre("act_num,")); - out.println(" java.util.ArrayList"+genericArg+" " + pre("stack)")); - out.println(" throws java.lang.Exception"); - out.println(" {"); - - out.println(" /* Stack size for peeking into the stack */"); - out.println(" int " + pre("size") + " = "+pre("stack")+".size();"); - out.println(); - - /* switch top */ - out.println(" /* select the action based on the action number */"); - out.println(" switch (" + pre("act_num") + ")"); - out.println(" {"); - - /* emit action code for each production as a separate case */ - for (production prod : grammar.actions()) - { - /* case label */ - for (production p2 : prod.lhs().productions()) - { - if (p2.action_index() == prod.action_index()) - out.println(" // " + p2.toString()); - } - out.println(" case " + prod.action_index() + ":"); - /* give them their own block to work in */ - out.println(" {"); - - emit_action(out, grammar, prod, lr_values, old_lr_values, is_java15); - - /* end of their block */ - out.println(" }"); - out.println(); - } + /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ + + /** + * Emit the parser subclass with embedded tables. + * + * @param out stream to produce output on. + * @param action_table internal representation of the action table. + * @param reduce_table internal representation of the reduce-goto table. + * @param start_st start state of the parse machine. + * @param start_prod start production of the grammar. + * @param compact_reduces do we use most frequent reduce as default? + * @param suppress_scanner should scanner be suppressed for compatibility? + */ + public void parser(PrintWriter out, Grammar grammar) { + timer.pushTimer(); + + String action_class = options.opt_java15 ? "Action$" : pre(options.parser_class_name + "$action"); + + /* top of file */ + out.println(); + out.println("//----------------------------------------------------"); + out.println("// The following code was generated by " + version.title_str); + out.println("// " + new Date()); + out.println("//----------------------------------------------------"); + out.println(); + emit_package(out); + + /* user supplied imports */ + for (String imp : options.import_list) + out.println("import " + imp + ";"); + + /* class header */ + out.println(); + out.println("/** " + version.title_str + " generated parser."); + out.println(" * @version " + new Date()); + out.println(" */"); + /* TUM changes; proposed by Henning Niss 20050628: added typeArgument */ + out.println("public class " + options.parser_class_name + typeArgument() + " extends " + RUNTIME_PACKAGE + + ".LRParser {"); + + /* constructors [CSA/davidm, 24-jul-99] */ + out.println(); + out.println(" /** Default constructor. */"); + out.println(" public " + options.parser_class_name + "() {super();}"); + if (!options.suppress_scanner) { + out.println(); + out.println(" /** Constructor which sets the default scanner. */"); + out.println(" public " + options.parser_class_name + "(" + RUNTIME_PACKAGE + ".Scanner s) {super(s);}"); + // TUM 20060327 added SymbolFactory aware constructor + out.println(); + out.println(" /** Constructor which sets the default scanner. */"); + out.println(" public " + options.parser_class_name + "(" + RUNTIME_PACKAGE + ".Scanner s, " + + RUNTIME_PACKAGE + ".SymbolFactory sf) {super(s,sf);}"); + } - /* end of switch */ - out.println(" /* . . . . . .*/"); - out.println(" default:"); - out.println(" throw new InternalError("); - out.println(" \"Invalid action number found in " + - "internal parse table\");"); - out.println(); - out.println(" }"); - - /* end of method */ - out.println(" }"); - - /* user supplied code for after reduce code */ - if (after_reduce_code != null) - { - out.println(); - out.println(" /** After reduce code */"); - out.println(" public void " + prefix + "after_reduce(Object RESULT, " - + RUNTIME_PACKAGE + ".Symbol[] symbols) throws java.lang.Exception"); - out.println(" {"); - out.println(after_reduce_code); - out.println(" }"); - } + /* emit the various tables */ + String tables = do_production_table(grammar) + do_action_table(grammar) + do_reduce_table(grammar); + + out.println(" /** The static parse table */"); + out.println(" static " + RUNTIME_PACKAGE + ".ParseTable " + pre("parse_table") + " ="); + out.println(" new " + RUNTIME_PACKAGE + ".ParseTable(new String[] {"); + output_string(out, tables); + out.println(" });"); + out.println(); + + out.println(" /** Return parse table */"); + out.println(" protected " + RUNTIME_PACKAGE + ".ParseTable parse_table() {"); + out.println(" return " + pre("parse_table") + ";"); + out.println(" }"); + out.println(); + + /* instance of the action encapsulation class */ + out.println(" /** Instance of action encapsulation class. */"); + out.println(" protected " + action_class + " action_obj;"); + out.println(); + + /* action object initializer */ + out.println(" /** Action encapsulation object initializer. */"); + out.println(" protected void init_actions()"); + out.println(" {"); + out.println(" action_obj = new " + action_class + "(this);"); + out.println(" }"); + out.println(); + + /* access to action code */ + out.println(" /** Invoke a user supplied parse action. */"); + out.println(" public " + RUNTIME_PACKAGE + ".Symbol do_action("); + out.println(" int act_num,"); + if (options.opt_java15) + out.println(" java.util.ArrayList<" + RUNTIME_PACKAGE + ".Symbol> stack)"); + else + out.println(" java.util.ArrayList stack)"); + out.println(" throws java.lang.Exception"); + out.println(" {"); + out.println(" /* call code in generated class */"); + out.println(" return action_obj." + pre("do_action(") + "act_num, stack);"); + out.println(" }"); + out.println(""); + + /* user supplied code for user_init() */ + if (options.init_code != null) { + out.println(); + out.println(" /** User initialization code. */"); + out.println(" public void user_init() throws java.lang.Exception"); + out.println(" {"); + out.println(options.init_code); + out.println(" }"); + } - /* end of class */ - out.println("}"); - out.println(); + /* user supplied code for scan */ + if (options.scan_code != null) { + out.println(); + out.println(" /** Scan to get the next Symbol. */"); + out.println(" public " + RUNTIME_PACKAGE + ".Symbol scan()"); + out.println(" throws java.lang.Exception"); + out.println(" {"); + out.println(options.scan_code); + out.println(" }"); + } - action_code_time = System.currentTimeMillis() - start_time; - } + /* user supplied code */ + if (options.parser_code != null) { + out.println(); + out.println(options.parser_code); + } - /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ + /* put out the action code class as inner class */ + emit_action_code(out, grammar, action_class, options); - /** Emit the production table. - * @param out stream to produce output on. - */ - private String do_production_table(Grammar grammar) - { - long start_time = System.currentTimeMillis(); + /* end of class */ + out.println("}"); - short[] prod_table = new short[2*grammar.num_actions()]; - for (production prod : grammar.actions()) - { - prod_table[2*prod.action_index()+0] = (short) prod.lhs().index(); - prod_table[2*prod.action_index()+1] = (short) prod.rhs_length(); - } - String result = do_array_as_string(prod_table); - production_table_time = System.currentTimeMillis() - start_time; - return result; - } - - /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ - - /** Emit the action table. - * @param out stream to produce output on. - * @param act_tab the internal representation of the action table. - * @param compact_reduces do we use the most frequent reduce as default? - */ - private String do_action_table( - Grammar grammar) - { - long start_time = System.currentTimeMillis(); - parse_action_table act_tab = grammar.action_table(); - int[] base_tab = new int[act_tab.table.length]; - short[] action_tab = act_tab.compress(base_tab); - String result = do_array_as_string(base_tab) + do_array_as_string(action_tab); - action_table_time = System.currentTimeMillis() - start_time; - return result; - } - - /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ - - /** Create the compressed reduce-goto table. - * @param red_tab the internal representation of the reduce-goto table. - */ - private String do_reduce_table(Grammar grammar) - { - parse_reduce_table red_tab = grammar.reduce_table(); - long start_time = System.currentTimeMillis(); - String result = do_array_as_string(red_tab.compress()); - goto_table_time = System.currentTimeMillis() - start_time; - return result; - } - - /** create a string encoding a given short[] array.*/ - private String do_array_as_string(short[] sharr) - { - StringBuilder sb = new StringBuilder(); - if (sharr.length >= 0x8000) - sb.append((char) (0x8000+(sharr.length>>16))); - sb.append((char)(sharr.length & 0xffff)); - for (int i = 0; i < sharr.length; i++) - sb.append((char) sharr[i]); - return sb.toString(); - } - - /** create a string encoding a given short[] array.*/ - private String do_array_as_string(int[] intarr) - { - StringBuilder sb = new StringBuilder(); - if (intarr.length >= 0x8000) - sb.append((char) (0x8000+(intarr.length>>16))); - sb.append((char)(intarr.length & 0xffff)); - for (int i = 0; i < intarr.length; i++) - { - assert(intarr[i] >= 0); - if (intarr[i] >= 0x8000) - sb.append((char) (0x8000+(intarr[i]>>16))); - sb.append((char) (intarr[i]&0xffff)); - } - return sb.toString(); - } - - /** print a string in java source code */ - private void output_string(PrintWriter out, String str) { - int utf8len = 0; - for (int i = 0; i < str.length(); i += 11) - { - StringBuilder encoded = new StringBuilder(); - encoded.append(" \""); - for (int j = 0; j < 11 && i+j < str.length(); j++) - { - char c = str.charAt(i+j); - encoded.append('\\'); - if (c < 256) - { - String oct = "000"+Integer.toOctalString(c); - oct = oct.substring(oct.length()-3); - encoded.append(oct); - } - else - { - String hex = "0000"+Integer.toHexString(c); - hex = hex.substring(hex.length()-4); - encoded.append('u').append(hex); - } - utf8len++; - if (c >= 128 || c == 0) - { - utf8len++; - if (c >= 2048) - utf8len++; - } - } - encoded.append("\""); - if (i+11 < str.length()) - { - if (utf8len > 65000) - { - encoded.append(","); - utf8len = 0; - } - else - encoded.append(" +"); - } - out.println(encoded.toString()); - } - } - - /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ - - /** Emit the parser subclass with embedded tables. - * @param out stream to produce output on. - * @param action_table internal representation of the action table. - * @param reduce_table internal representation of the reduce-goto table. - * @param start_st start state of the parse machine. - * @param start_prod start production of the grammar. - * @param compact_reduces do we use most frequent reduce as default? - * @param suppress_scanner should scanner be suppressed for compatibility? - */ - public void parser( - PrintWriter out, - Grammar grammar, - boolean suppress_scanner, - boolean lr_values, - boolean old_lr_values, - boolean is_java15) - { - long start_time = System.currentTimeMillis(); - - String action_class = is_java15 ? "Action$" : pre(parser_class_name+"$action"); - - /* top of file */ - out.println(); - out.println("//----------------------------------------------------"); - out.println("// The following code was generated by " + - version.title_str); - out.println("// " + new Date()); - out.println("//----------------------------------------------------"); - out.println(); - emit_package(out); - - /* user supplied imports */ - for (String imp : import_list) - out.println("import " + imp + ";"); - - /* class header */ - out.println(); - out.println("/** "+version.title_str+" generated parser."); - out.println(" * @version " + new Date()); - out.println(" */"); - /* TUM changes; proposed by Henning Niss 20050628: added typeArgument */ - out.println("public class " + parser_class_name + typeArgument() + - " extends " + RUNTIME_PACKAGE + ".LRParser {"); - - /* constructors [CSA/davidm, 24-jul-99] */ - out.println(); - out.println(" /** Default constructor. */"); - out.println(" public " + parser_class_name + "() {super();}"); - if (!suppress_scanner) { - out.println(); - out.println(" /** Constructor which sets the default scanner. */"); - out.println(" public " + parser_class_name + - "(" + RUNTIME_PACKAGE + ".Scanner s) {super(s);}"); - // TUM 20060327 added SymbolFactory aware constructor - out.println(); - out.println(" /** Constructor which sets the default scanner. */"); - out.println(" public " + parser_class_name + - "(" + RUNTIME_PACKAGE + ".Scanner s, " + RUNTIME_PACKAGE + ".SymbolFactory sf) {super(s,sf);}"); - } - - /* emit the various tables */ - String tables = do_production_table(grammar) + - do_action_table(grammar) + - do_reduce_table(grammar); - - out.println(" /** The static parse table */"); - out.println(" static " + RUNTIME_PACKAGE + ".ParseTable " + pre("parse_table") + " ="); - out.println(" new " + RUNTIME_PACKAGE + ".ParseTable(new String[] {"); - output_string(out, tables); - out.println(" });"); - out.println(); - - out.println(" /** Return parse table */"); - out.println(" protected " + RUNTIME_PACKAGE + ".ParseTable parse_table() {"); - out.println(" return " + pre("parse_table") + ";"); - out.println(" }"); - out.println(); - - /* instance of the action encapsulation class */ - out.println(" /** Instance of action encapsulation class. */"); - out.println(" protected " + action_class + " action_obj;"); - out.println(); - - /* action object initializer */ - out.println(" /** Action encapsulation object initializer. */"); - out.println(" protected void init_actions()"); - out.println(" {"); - out.println(" action_obj = new " + action_class + "(this);"); - out.println(" }"); - out.println(); - - /* access to action code */ - out.println(" /** Invoke a user supplied parse action. */"); - out.println(" public " + RUNTIME_PACKAGE + ".Symbol do_action("); - out.println(" int act_num,"); - if (is_java15) - out.println(" java.util.ArrayList<" + RUNTIME_PACKAGE + ".Symbol> stack)"); - else - out.println(" java.util.ArrayList stack)"); - out.println(" throws java.lang.Exception"); - out.println(" {"); - out.println(" /* call code in generated class */"); - out.println(" return action_obj." + pre("do_action(") + - "act_num, stack);"); - out.println(" }"); - out.println(""); - - /* user supplied code for user_init() */ - if (init_code != null) - { - out.println(); - out.println(" /** User initialization code. */"); - out.println(" public void user_init() throws java.lang.Exception"); - out.println(" {"); - out.println(init_code); - out.println(" }"); + timer.popTimer(Timer.TIMESTAMP.parser_time); } - /* user supplied code for scan */ - if (scan_code != null) - { - out.println(); - out.println(" /** Scan to get the next Symbol. */"); - out.println(" public " + RUNTIME_PACKAGE + ".Symbol scan()"); - out.println(" throws java.lang.Exception"); - out.println(" {"); - out.println(scan_code); - out.println(" }"); + private void dump_tables(PrintWriter dump_file, Grammar grammar) { + dump_file.println(grammar.action_table); + dump_file.println(grammar.reduce_table); } - /* user supplied code */ - if (parser_code != null) - { - out.println(); - out.println(parser_code); + private void dump_machine(PrintWriter dump_file, Grammar grammar) { + dump_file.println("===== Viable Prefix Recognizer ====="); + for (lalr_state st : grammar.lalr_states()) { + dump_file.println(st); + dump_file.println("-------------------"); + } } - if (is_java15) - { - /* put out the action code class as inner class */ - emit_action_code(out, grammar, action_class, lr_values, old_lr_values, is_java15); - - /* end of class */ - out.println("}"); - } - else - { - /* end of class */ - out.println("}"); - - /* put out the action code class */ - emit_action_code(out, grammar, action_class, lr_values, old_lr_values, is_java15); + private void dump_grammar(PrintWriter dump_file, Grammar grammar) { + dump_file.println("===== Terminals ====="); + int cnt = 0; + for (terminal t : grammar.terminals()) { + dump_file.print("[" + t.index() + "]" + t.name() + " "); + if ((++cnt) % 5 == 0) + dump_file.println(); + } + dump_file.println(); + dump_file.println(); + + dump_file.println("===== Non terminals ====="); + cnt = 0; + for (non_terminal nt : grammar.non_terminals()) { + dump_file.print("[" + nt.index() + "]" + nt.name() + " "); + if ((++cnt) % 5 == 0) + dump_file.println(); + } + dump_file.println(); + dump_file.println(); + + dump_file.println("===== Productions ====="); + for (production prod : grammar.productions()) { + dump_file.println("[" + prod.index() + "] " + prod); + } + dump_file.println(); } - parser_time = System.currentTimeMillis() - start_time; - } + public void dumps(PrintWriter dump_file, Grammar grammar) { + if (options.opt_dump_grammar) + dump_grammar(dump_file, grammar); + if (options.opt_dump_states) + dump_machine(dump_file, grammar); + if (options.opt_dump_tables) + dump_tables(dump_file, grammar); + } - public void usage(String message) - { - } - + public void usage(String message) { + } } diff --git a/src/com/github/jhoenicke/javacup/non_terminal.java b/src/com/github/jhoenicke/javacup/non_terminal.java index c5a0e6e..f6ad3ae 100644 --- a/src/com/github/jhoenicke/javacup/non_terminal.java +++ b/src/com/github/jhoenicke/javacup/non_terminal.java @@ -41,9 +41,6 @@ public non_terminal(String nm, int index) /*--- (Access to) Static (Class) Variables ------------------*/ /*-----------------------------------------------------------*/ - /** special non-terminal for start symbol */ - public static final non_terminal START_nt = new non_terminal("$START", "Object", 0); - /*-----------------------------------------------------------*/ /*--- (Access to) Instance Variables ------------------------*/ /*-----------------------------------------------------------*/ diff --git a/src/com/github/jhoenicke/javacup/production.java b/src/com/github/jhoenicke/javacup/production.java index 256e7d7..d668377 100644 --- a/src/com/github/jhoenicke/javacup/production.java +++ b/src/com/github/jhoenicke/javacup/production.java @@ -73,7 +73,7 @@ public production(int index, int action_index, non_terminal lhs_sym, symbol_part for (int i = 0; i < rhs.length; i++) { symbol rhs_sym = rhs[i].the_symbol; - rhs_sym.note_use(); + if (rhs_sym != null) rhs_sym.note_use(); if (precedence == null && rhs_sym instanceof terminal) { terminal term = (terminal) rhs_sym; @@ -290,9 +290,14 @@ public String toString() StringBuilder result = new StringBuilder(); result.append(lhs().name()).append(" ::= "); - for (int i = 0; i < rhs_length(); i++) - result.append(rhs(i).the_symbol.name()).append(" "); - + for (int i = 0; i < rhs_length(); i++) { + symbol s = rhs(i).the_symbol; + //MH 07/07/2022 the_symbol can be null if a terminal is not declared + if (s == null) result.append("***UNDECLARED***"); + else result.append(s.name()); + result.append(" "); + } + return result.toString(); } diff --git a/src/com/github/jhoenicke/javacup/runtime/ComplexSymbolFactory.java b/src/com/github/jhoenicke/javacup/runtime/ComplexSymbolFactory.java index 60c6441..2150158 100644 --- a/src/com/github/jhoenicke/javacup/runtime/ComplexSymbolFactory.java +++ b/src/com/github/jhoenicke/javacup/runtime/ComplexSymbolFactory.java @@ -54,8 +54,24 @@ public ComplexSymbol(String name, int id, Object value) { this.name=name; } public String toString(){ - if (xleft==null || xright==null) return "Symbol: "+name; - return "#"+sym+"["+name+"]("+xleft+" - "+xright+")"; + StringBuilder tmp = new StringBuilder(); + tmp.append("Symbol: "); + tmp.append(name); + tmp.append("#"); + tmp.append(sym); + if (value != null) { + tmp.append("==\""); + tmp.append(value); + tmp.append("\""); + } + if (xleft!=null && xright!=null) { + tmp.append("("); + tmp.append(xleft); + tmp.append(" - "); + tmp.append(xright); + tmp.append(")"); + } + return tmp.toString(); } public ComplexSymbol(String name, int id, int state) { super(id,state); diff --git a/src/com/github/jhoenicke/javacup/terminal.java b/src/com/github/jhoenicke/javacup/terminal.java index c2b2e96..85c2a43 100644 --- a/src/com/github/jhoenicke/javacup/terminal.java +++ b/src/com/github/jhoenicke/javacup/terminal.java @@ -1,7 +1,5 @@ package com.github.jhoenicke.javacup; -import com.github.jhoenicke.javacup.assoc; - /** This class represents a terminal symbol in the grammar. Each terminal * has a textual name, an index, and a string which indicates the type of * object it will be implemented with at runtime (i.e. the class of object diff --git a/src/com/github/jhoenicke/javacup/version.java b/src/com/github/jhoenicke/javacup/version.java index 0e49627..e4e082a 100644 --- a/src/com/github/jhoenicke/javacup/version.java +++ b/src/com/github/jhoenicke/javacup/version.java @@ -24,12 +24,12 @@ public class version { /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** The minor version number. */ - public static final int minor = 2; + public static final int minor = 3; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** The update letter. */ - public static final String update = " 20210807"; + public static final String update = " 20220517"; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ @@ -45,7 +45,7 @@ public class version { /** Name of the author */ public static final String author_str = - "Scott E. Hudson, Frank Flannery, Andrea Flexeder, Michael Petter, C. Scott Ananian and Jochen Hoenicke"; + "Scott E. Hudson, Frank Flannery, Andrea Flexeder, Michael Petter, C. Scott Ananian, Jochen Hoenicke and Michel Hassenforder"; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/