cup-0.11a+20060608/0000755000175000017500000000000011075731252013225 5ustar twernertwernercup-0.11a+20060608/bin/0000755000175000017500000000000011075722356014002 5ustar twernertwernercup-0.11a+20060608/cup/0000755000175000017500000000000011075720101014003 5ustar twernertwernercup-0.11a+20060608/cup/parser.cup0000644000175000017500000006244510441773704016040 0ustar twernertwerner /*================================================================*/ /* JavaCup Specification for the JavaCup Specification Language by Scott Hudson, GVU Center, Georgia Tech, August 1995 and Frank Flannery, Department of Computer Science, Princeton Univ, July 1996 Bug Fixes: C. Scott Ananian, Dept of Electrical Engineering, Princeton University, October 1996. [later Massachusetts Institute of Technology] This JavaCup specification is used to implement JavaCup itself. It specifies the parser for the JavaCup specification language. (It also serves as a reasonable example of what a typical JavaCup spec looks like). The specification has the following parts: Package and import declarations These serve the same purpose as in a normal Java source file (and will appear in the generated code for the parser). In this case we are part of the java_cup package and we import both the java_cup runtime system and Hashtable from the standard Java utilities package. Action code This section provides code that is included with the class encapsulating the various pieces of user code embedded in the grammar (i.e., the semantic actions). This provides a series of helper routines and data structures that the semantic actions use. Parser code This section provides code included in the parser class itself. In this case we override the default error reporting routines. Init with and scan with These sections provide small bits of code that initialize, then indicate how to invoke the scanner. Symbols and grammar These sections declare all the terminal and non terminal symbols and the types of objects that they will be represented by at runtime, then indicate the start symbol of the grammar (), and finally provide the grammar itself (with embedded actions). Operation of the parser The parser acts primarily by accumulating data structures representing various parts of the specification. Various small parts (e.g., single code strings) are stored as static variables of the emit class and in a few cases as variables declared in the action code section. Terminals, non terminals, and productions, are maintained as collection accessible via static methods of those classes. In addition, two symbol tables are kept: symbols maintains the name to object mapping for all symbols non_terms maintains a separate mapping containing only the non terms Several intermediate working structures are also declared in the action code section. These include: rhs_parts, rhs_pos, and lhs_nt which build up parts of the current production while it is being parsed. Author(s) Scott Hudson, GVU Center, Georgia Tech. Frank Flannery, Department of Computer Science, Princeton Univ. C. Scott Ananian, Department of Electrical Engineering, Princeton Univ. Revisions v0.9a First released version [SEH] 8/29/95 v0.9b Updated for beta language (throws clauses) [SEH] 11/25/95 v0.10a Made many improvements/changes. now offers: return value left/right positions and propagations cleaner label references precedence and associativity for terminals contextual precedence for productions [FF] 7/3/96 v0.10b Fixed %prec directive so it works like it's supposed to. [CSA] 10/10/96 v0.10g Added support for array types on symbols. [CSA] 03/23/98 v0.10i Broaden set of IDs allowed in multipart_id and label_id so that only java reserved words (and not CUP reserved words like 'parser' and 'start') are prohibited. Allow reordering of action code, parser code, init code, and scan with sections, and made closing semicolon optional for these sections. Added 'nonterminal' as a terminal symbol, finally fixing a spelling mistake that's been around since the beginning. For backwards compatibility, you can still misspell the word if you like. */ /*================================================================*/ package java_cup; import java_cup.runtime.*; import java.util.Hashtable; import java.util.Stack; /*----------------------------------------------------------------*/ action code {: /** helper routine to clone a new production part adding a given label */ protected production_part add_lab(production_part part, String lab) throws internal_error { /* if there is no label, or this is an action, just return the original */ if (lab == null || part.is_action()) return part; /* otherwise build a new one with the given label attached */ return new symbol_part(((symbol_part)part).the_symbol(),lab); } /** max size of right hand side we will support */ protected final int MAX_RHS = 200; /** array for accumulating right hand side parts */ protected production_part[] rhs_parts = new production_part[MAX_RHS]; /** where we are currently in building a right hand side */ protected int rhs_pos = 0; /** start a new right hand side */ protected void new_rhs() {rhs_pos = 0; } /** add a new right hand side part */ protected void add_rhs_part(production_part part) throws java.lang.Exception { if (rhs_pos >= MAX_RHS) throw new Exception("Internal Error: Productions limited to " + MAX_RHS + " symbols and actions"); rhs_parts[rhs_pos] = part; rhs_pos++; } /** string to build up multiple part names */ protected String multipart_name = new String(); protected Stack multipart_names = new Stack(); /** append a new name segment to the accumulated multipart name */ // TUM CHANGES // protected void append_multipart(String name) // { // String dot = ""; // // /* if we aren't just starting out, put on a dot */ // if (multipart_name.length() != 0) dot = "."; // // multipart_name = multipart_name.concat(dot + name); // } // TUM CHANGES /** table of declared symbols -- contains production parts indexed by name */ protected Hashtable symbols = new Hashtable(); /** table of just non terminals -- contains non_terminals indexed by name */ protected Hashtable non_terms = new Hashtable(); /** declared start non_terminal */ protected non_terminal start_nt = null; /** left hand side non terminal of the current production */ protected non_terminal lhs_nt; /** Current precedence number */ int _cur_prec = 0; /** Current precedence side */ int _cur_side = assoc.no_prec; /** update the precedences we are declaring */ protected void update_precedence(int p) { _cur_side = p; _cur_prec++; } /** add relevant data to terminals */ protected void add_precedence(String term) { if (term == null) { System.err.println("Unable to add precedence to nonexistent terminal"); } else { symbol_part sp = (symbol_part)symbols.get(term); if (sp == null) { System.err.println("Could find terminal " + term + " while declaring precedence"); } else { java_cup.symbol sym = sp.the_symbol(); if (sym instanceof terminal) ((terminal)sym).set_precedence(_cur_side, _cur_prec); else System.err.println("Precedence declaration: Can't find terminal " + term); } } } :}; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ parser code {: /* override error routines */ protected Lexer lexer; public void report_fatal_error( String message, Object info) { 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); } public void report_error(String message, Object info) { if (info instanceof Symbol) ErrorManager.getManager().emit_error(message,(Symbol)info); else ErrorManager.getManager().emit_error(message,cur_token); } :}; /*---------------------------------------------------------------- */ init with {: ComplexSymbolFactory f = new ComplexSymbolFactory(); symbolFactory = f; lexer = new Lexer(f); :} /*lexer.init(); :};*/ scan with {: return lexer.next_token(); :}; /*----------------------------------------------------------------*/ terminal PACKAGE, IMPORT, CODE, ACTION, PARSER, TERMINAL, NON, INIT, SCAN, WITH, START, SEMI, COMMA, STAR, DOT, COLON, COLON_COLON_EQUALS, BAR, PRECEDENCE, LEFT, RIGHT, NONASSOC, PERCENT_PREC, LBRACK, RBRACK, NONTERMINAL, GT, LT, QUESTION, SUPER, EXTENDS; terminal String ID, CODE_STRING; non terminal spec, package_spec, import_list, action_code_part, code_parts, code_part, opt_semi, non_terminal, parser_code_part, symbol_list, start_spec, production_list, multipart_id, import_spec, import_id, init_code, scan_code, symbol, type_id, term_name_list, non_term_name_list, production, prod_part_list, prod_part, new_term_id, new_non_term_id, rhs_list, rhs, empty, precedence_list, preced, terminal_list, precedence_l, declares_term, declares_non_term; non terminal String nt_id, symbol_id, label_id, opt_label, terminal_id, term_id, robust_id, typearglist, typearguement, wildcard; /*----------------------------------------------------------------*/ start with spec; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ spec ::= {: /* declare "error" as a terminal */ symbols.put("error", new symbol_part(terminal.error)); /* declare start non terminal */ non_terms.put("$START", non_terminal.START_nt); :} package_spec import_list code_parts symbol_list precedence_list start_spec production_list | /* error recovery assuming something went wrong before symbols and we have TERMINAL or NON TERMINAL to sync on. if we get an error after that, we recover inside symbol_list or production_list */ error symbol_list precedence_list start_spec production_list ; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ package_spec ::= PACKAGE multipart_id {: /* save the package name */ emit.package_name = multipart_name; /* reset the accumulated multipart name */ multipart_name = new String(); :} SEMI | empty ; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ import_list ::= import_list import_spec | empty ; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ import_spec ::= IMPORT import_id {: /* save this import on the imports list */ emit.import_list.push(multipart_name); /* reset the accumulated multipart name */ multipart_name = new String(); :} SEMI ; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ // allow any order; all parts are optional. [CSA, 23-Jul-1999] // (we check in the part action to make sure we don't have 2 of any part) code_part ::= action_code_part | parser_code_part | init_code | scan_code ; code_parts ::= | code_parts code_part; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ action_code_part ::= ACTION CODE CODE_STRING:user_code opt_semi {: if (emit.action_code!=null) ErrorManager.getManager().emit_warning("Redundant action code (skipping)"); else /* save the user included code string */ emit.action_code = user_code; :} ; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ parser_code_part ::= PARSER CODE CODE_STRING:user_code opt_semi {: if (emit.parser_code!=null) ErrorManager.getManager().emit_warning("Redundant parser code (skipping)"); else /* save the user included code string */ emit.parser_code = user_code; :} ; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ init_code ::= INIT WITH CODE_STRING:user_code opt_semi {: if (emit.init_code!=null) ErrorManager.getManager().emit_warning("Redundant init code (skipping)"); else /* save the user code */ emit.init_code = user_code; :} ; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ scan_code ::= SCAN WITH CODE_STRING:user_code opt_semi {: if (emit.scan_code!=null) ErrorManager.getManager().emit_warning("Redundant scan code (skipping)"); else /* save the user code */ emit.scan_code = user_code; :} ; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ symbol_list ::= symbol_list symbol | symbol; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ symbol ::= TERMINAL type_id declares_term | TERMINAL declares_term | non_terminal type_id declares_non_term | non_terminal declares_non_term | /* error recovery productions -- sync on semicolon */ TERMINAL error {: /* reset the accumulated multipart name */ multipart_name = new String(); :} SEMI | non_terminal error {: /* reset the accumulated multipart name */ multipart_name = new String(); :} SEMI ; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ declares_term ::= term_name_list {: /* reset the accumulated multipart name */ multipart_name = new String(); :} SEMI ; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ declares_non_term ::= non_term_name_list {: /* reset the accumulated multipart name */ multipart_name = new String(); :} SEMI ; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ term_name_list ::= term_name_list COMMA new_term_id | new_term_id; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ non_term_name_list ::= non_term_name_list COMMA new_non_term_id | new_non_term_id ; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ precedence_list ::= precedence_l | empty; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ precedence_l ::= precedence_l preced | preced; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ preced ::= PRECEDENCE LEFT {: update_precedence(assoc.left); :} terminal_list SEMI | PRECEDENCE RIGHT {: update_precedence(assoc.right); :} terminal_list SEMI | PRECEDENCE NONASSOC {: update_precedence(assoc.nonassoc); :} terminal_list SEMI ; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ terminal_list ::= terminal_list COMMA terminal_id | terminal_id ; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ terminal_id ::= term_id:sym {: add_precedence(sym); RESULT = sym; :}; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ term_id ::= symbol_id:sym {: /* check that the symbol_id is a terminal */ if (symbols.get(sym) == null) { /* issue a message */ ErrorManager.getManager().emit_error("Terminal \"" + sym + "\" has not been declared"); } RESULT = sym; :}; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ start_spec ::= START WITH nt_id:start_name {: /* verify that the name has been declared as a non terminal */ non_terminal nt = (non_terminal)non_terms.get(start_name); if (nt == null) { ErrorManager.getManager().emit_error( "Start non terminal \"" + start_name + "\" has not been declared"); } else { /* remember the non-terminal for later */ start_nt = nt; /* build a special start production */ new_rhs(); add_rhs_part(add_lab(new symbol_part(start_nt), "start_val")); add_rhs_part(new symbol_part(terminal.EOF)); add_rhs_part(new action_part("RESULT = start_val;")); emit.start_production = new production(non_terminal.START_nt, rhs_parts, rhs_pos); new_rhs(); } :} SEMI | empty ; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ production_list ::= production_list production | production; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ production ::= nt_id:lhs_id {: /* lookup the lhs nt */ lhs_nt = (non_terminal)non_terms.get(lhs_id); /* if it wasn't declared, emit a message */ if (lhs_nt == null) { if (ErrorManager.getManager().getErrorCount() == 0) ErrorManager.getManager().emit_warning("LHS non terminal \"" + lhs_id + "\" has not been declared"); } /* reset the rhs accumulation */ new_rhs(); :} COLON_COLON_EQUALS /* {: :}*/ rhs_list SEMI | error {: ErrorManager.getManager().emit_error("Syntax Error"); :} SEMI ; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ rhs_list ::= rhs_list BAR rhs | rhs; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ rhs ::= prod_part_list PERCENT_PREC term_id:term_name {: java_cup.symbol sym = null; if (lhs_nt != null) { /* Find the precedence symbol */ if (term_name == null) { System.err.println("No terminal for contextual precedence"); sym = null; } else { sym = ((symbol_part)symbols.get(term_name)).the_symbol(); } /* build the production */ production p; if ((sym!=null) && (sym instanceof terminal)) { p = new production(lhs_nt, rhs_parts, rhs_pos, ((terminal)sym).precedence_num(), ((terminal)sym).precedence_side()); ((symbol_part)symbols.get(term_name)).the_symbol().note_use(); } else { System.err.println("Invalid terminal " + term_name + " for contextual precedence assignment"); p = new production(lhs_nt, rhs_parts, rhs_pos); } /* if we have no start non-terminal declared and this is the first production, make its lhs nt the start_nt and build a special start production for it. */ if (start_nt == null) { start_nt = lhs_nt; /* build a special start production */ new_rhs(); add_rhs_part(add_lab(new symbol_part(start_nt),"start_val")); add_rhs_part(new symbol_part(terminal.EOF)); add_rhs_part(new action_part("RESULT = start_val;")); if ((sym!=null) && (sym instanceof terminal)) { emit.start_production = new production(non_terminal.START_nt, rhs_parts, rhs_pos, ((terminal)sym).precedence_num(), ((terminal)sym).precedence_side()); } else { emit.start_production = new production(non_terminal.START_nt, rhs_parts, rhs_pos); } new_rhs(); } } /* reset the rhs accumulation in any case */ new_rhs(); :} | prod_part_list {: if (lhs_nt != null) { /* build the production */ production p = new production(lhs_nt, rhs_parts, rhs_pos); /* if we have no start non-terminal declared and this is the first production, make its lhs nt the start_nt and build a special start production for it. */ if (start_nt == null) { start_nt = lhs_nt; /* build a special start production */ new_rhs(); add_rhs_part(add_lab(new symbol_part(start_nt),"start_val")); add_rhs_part(new symbol_part(terminal.EOF)); add_rhs_part(new action_part("RESULT = start_val;")); emit.start_production = new production(non_terminal.START_nt, rhs_parts, rhs_pos); new_rhs(); } } /* reset the rhs accumulation in any case */ new_rhs(); :} ; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ prod_part_list ::= prod_part_list prod_part | empty; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ prod_part ::= symbol_id:symid opt_label:labid {: /* try to look up the id */ production_part symb = (production_part)symbols.get(symid); /* if that fails, symbol is undeclared */ if (symb == null) { if (ErrorManager.getManager().getErrorCount() == 0) ErrorManager.getManager().emit_error("java_cup.runtime.Symbol \"" + symid + "\" has not been declared"); } else { /* add a labeled production part */ add_rhs_part(add_lab(symb, labid)); } :} | CODE_STRING:code_str {: /* add a new production part */ add_rhs_part(new action_part(code_str)); :} ; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ opt_label ::= COLON label_id:labid {: RESULT = labid; :} | empty {: RESULT = null; :} ; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ multipart_id ::= multipart_id DOT robust_id:another_id {: multipart_name = multipart_name.concat("."+another_id); :} |multipart_id {: multipart_names.push(multipart_name); multipart_name="";:} LT typearglist:types GT {: multipart_name = ((String)multipart_names.pop()).concat("<"+types+">"); :} | robust_id:an_id {: multipart_name = multipart_name.concat(an_id); :} ; /*. . . . . . . . . . . .TUM CHANGES. . . . . . . . . . . . . . . */ typearglist ::= typearguement:arg {: RESULT = arg; :} | typearglist:list COMMA typearguement:arg {: RESULT = list + "," + arg; :} ; typearguement ::= type_id {: RESULT = multipart_name; multipart_name = new String(); :} | wildcard:w {: RESULT = w; :} ; wildcard ::= QUESTION {: RESULT = " ? "; :} | QUESTION EXTENDS type_id {: RESULT = " ? extends "+multipart_name; multipart_name = new String(); :} | QUESTION SUPER type_id {: RESULT = " ? super "+multipart_name; multipart_name = new String(); :} ; /*. . . . . . . . . . .END TUM CHANGES. . . . . . . . . . . . . . */ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ import_id ::= multipart_id DOT STAR {: multipart_name = multipart_name.concat(".*"); :} | multipart_id ; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ type_id ::= multipart_id | type_id LBRACK RBRACK {: multipart_name = multipart_name.concat("[]"); :} ; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ new_term_id ::= ID:term_id {: /* see if this terminal has been declared before */ if (symbols.get(term_id) != null) { /* issue a message */ ErrorManager.getManager().emit_error("java_cup.runtime.Symbol \"" + term_id + "\" has already been declared"); } else { /* if no type declared, declare one */ if (multipart_name.equals("")) { multipart_name = "Object"; } /* build a production_part and put it in the table */ symbols.put(term_id, new symbol_part(new terminal(term_id, multipart_name))); } :} ; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ new_non_term_id ::= ID:non_term_id {: /* see if this non terminal has been declared before */ if (symbols.get(non_term_id) != null) { /* issue a message */ ErrorManager.getManager().emit_error( "java_cup.runtime.Symbol \"" + non_term_id + "\" has already been declared"); } else { if (multipart_name.equals("")) { multipart_name ="Object"; } /* build the non terminal object */ non_terminal this_nt = new non_terminal(non_term_id, multipart_name); /* put it in the non_terms table */ non_terms.put(non_term_id, this_nt); /* build a production_part and put it in the symbols table */ symbols.put(non_term_id, new symbol_part(this_nt)); } :} ; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ nt_id ::= ID:the_id {: RESULT = the_id; :} | error {: ErrorManager.getManager().emit_error("Illegal use of reserved word"); RESULT="ILLEGAL"; :} ; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ symbol_id ::= ID:the_id {: RESULT = the_id; :} | error {: ErrorManager.getManager().emit_error("Illegal use of reserved word"); RESULT="ILLEGAL"; :} ; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ label_id ::= robust_id:the_id {: RESULT = the_id; :} ; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ robust_id ::= /* all ids that aren't reserved words in Java */ ID:the_id {: RESULT = the_id; :} /* package is reserved. */ /* import is reserved. */ | CODE {: RESULT = "code"; :} | ACTION {: RESULT = "action"; :} | PARSER {: RESULT = "parser"; :} | TERMINAL {: RESULT = "terminal"; :} | NON {: RESULT = "non"; :} | NONTERMINAL {: RESULT = "nonterminal"; :} | INIT {: RESULT = "init"; :} | SCAN {: RESULT = "scan"; :} | WITH {: RESULT = "with"; :} | START {: RESULT = "start"; :} | PRECEDENCE {: RESULT = "precedence"; :} | LEFT {: RESULT = "left"; :} | RIGHT {: RESULT = "right"; :} | NONASSOC {: RESULT = "nonassoc"; :} | error {: ErrorManager.getManager().emit_error("Illegal use of reserved word"); RESULT="ILLEGAL"; :} ; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ non_terminal ::= NON TERMINAL | NONTERMINAL; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ opt_semi ::= /* nothing */ | SEMI; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ empty ::= /* nothing */; /*----------------------------------------------------------------*/ cup-0.11a+20060608/lib/0000755000175000017500000000000011075720101013762 5ustar twernertwernercup-0.11a+20060608/src/0000755000175000017500000000000011075720101014003 5ustar twernertwernercup-0.11a+20060608/src/java_cup/0000755000175000017500000000000011075720102015574 5ustar twernertwernercup-0.11a+20060608/src/java_cup/lr_item_core.java0000644000175000017500000001756510250537770021133 0ustar twernertwerner package java_cup; /** The "core" of an LR item. This includes a production and the position * of a marker (the "dot") within the production. Typically item cores * are written using a production with an embedded "dot" to indicate their * position. For example:
 *     A ::= B * C d E
 *  
* This represents a point in a parse where the parser is trying to match * the given production, and has succeeded in matching everything before the * "dot" (and hence is expecting to see the symbols after the dot next). See * lalr_item, lalr_item_set, and lalr_start for full details on the meaning * and use of items. * * @see java_cup.lalr_item * @see java_cup.lalr_item_set * @see java_cup.lalr_state * @version last updated: 11/25/95 * @author Scott Hudson */ public class lr_item_core { /*-----------------------------------------------------------*/ /*--- Constructor(s) ----------------------------------------*/ /*-----------------------------------------------------------*/ /** Full constructor. * @param prod production this item uses. * @param pos position of the "dot" within the item. */ public lr_item_core(production prod, int pos) throws internal_error { symbol after_dot = null; production_part part; if (prod == null) throw new internal_error( "Attempt to create an lr_item_core with a null production"); _the_production = prod; if (pos < 0 || pos > _the_production.rhs_length()) throw new internal_error( "Attempt to create an lr_item_core with a bad dot position"); _dot_pos = pos; /* compute and cache hash code now */ _core_hash_cache = 13*_the_production.hashCode() + pos; /* cache the symbol after the dot */ if (_dot_pos < _the_production.rhs_length()) { part = _the_production.rhs(_dot_pos); if (!part.is_action()) _symbol_after_dot = ((symbol_part)part).the_symbol(); } } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Constructor for dot at start of right hand side. * @param prod production this item uses. */ public lr_item_core(production prod) throws internal_error { this(prod,0); } /*-----------------------------------------------------------*/ /*--- (Access to) Instance Variables ------------------------*/ /*-----------------------------------------------------------*/ /** The production for the item. */ protected production _the_production; /** The production for the item. */ public production the_production() {return _the_production;} /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** The position of the "dot" -- this indicates the part of the production * that the marker is before, so 0 indicates a dot at the beginning of * the RHS. */ protected int _dot_pos; /** The position of the "dot" -- this indicates the part of the production * that the marker is before, so 0 indicates a dot at the beginning of * the RHS. */ public int dot_pos() {return _dot_pos;} /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Cache of the hash code. */ protected int _core_hash_cache; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Cache of symbol after the dot. */ protected symbol _symbol_after_dot = null; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Is the dot at the end of the production? */ public boolean dot_at_end() { return _dot_pos >= _the_production.rhs_length(); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Return the symbol after the dot. If there is no symbol after the dot * we return null. */ public symbol symbol_after_dot() { /* use the cached symbol */ return _symbol_after_dot; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Determine if we have a dot before a non terminal, and if so which one * (return null or the non terminal). */ public non_terminal dot_before_nt() { symbol sym; /* get the symbol after the dot */ sym = symbol_after_dot(); /* if it exists and is a non terminal, return it */ if (sym != null && sym.is_non_term()) return (non_terminal)sym; else return null; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Produce a new lr_item_core that results from shifting the dot one * position to the right. */ public lr_item_core shift_core() throws internal_error { if (dot_at_end()) throw new internal_error( "Attempt to shift past end of an lr_item_core"); return new lr_item_core(_the_production, _dot_pos+1); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Equality comparison for the core only. This is separate out because we * need separate access in a super class. */ public boolean core_equals(lr_item_core other) { return other != null && _the_production.equals(other._the_production) && _dot_pos == other._dot_pos; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Equality comparison. */ public boolean equals(lr_item_core other) {return core_equals(other);} /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Generic equality comparison. */ public boolean equals(Object other) { if (!(other instanceof lr_item_core)) return false; else return equals((lr_item_core)other); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Hash code for the core (separated so we keep non overridden version). */ public int core_hashCode() { return _core_hash_cache; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Hash code for the item. */ public int hashCode() { return _core_hash_cache; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Return the hash code that object would have provided for us so we have * a (nearly) unique id for debugging. */ protected int obj_hash() { return super.hashCode(); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Convert to a string (separated out from toString() so we can call it * from subclass that overrides toString()). */ public String to_simple_string() throws internal_error { String result; production_part part; if (_the_production.lhs() != null && _the_production.lhs().the_symbol() != null && _the_production.lhs().the_symbol().name() != null) result = _the_production.lhs().the_symbol().name(); else result = "$$NULL$$"; result += " ::= "; for (int i = 0; i<_the_production.rhs_length(); i++) { /* do we need the dot before this one? */ if (i == _dot_pos) result += "(*) "; /* print the name of the part */ if (_the_production.rhs(i) == null) { result += "$$NULL$$ "; } else { part = _the_production.rhs(i); if (part == null) result += "$$NULL$$ "; else if (part.is_action()) result += "{ACTION} "; else if (((symbol_part)part).the_symbol() != null && ((symbol_part)part).the_symbol().name() != null) result += ((symbol_part)part).the_symbol().name() + " "; else result += "$$NULL$$ "; } } /* put the dot after if needed */ if (_dot_pos == _the_production.rhs_length()) result += "(*) "; return result; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Convert to a string */ public String toString() { /* can't throw here since super class doesn't, so we crash instead */ try { return to_simple_string(); } catch(internal_error e) { e.crash(); return null; } } /*-----------------------------------------------------------*/ } cup-0.11a+20060608/src/java_cup/terminal_set.java0000644000175000017500000001473510250537770021152 0ustar twernertwerner package java_cup; import java.util.BitSet; /** A set of terminals implemented as a bitset. * @version last updated: 11/25/95 * @author Scott Hudson */ public class terminal_set { /*-----------------------------------------------------------*/ /*--- Constructor(s) ----------------------------------------*/ /*-----------------------------------------------------------*/ /** Constructor for an empty set. */ public terminal_set() { /* allocate the bitset at what is probably the right size */ _elements = new BitSet(terminal.number()); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Constructor for cloning from another set. * @param other the set we are cloning from. */ public terminal_set(terminal_set other) throws internal_error { not_null(other); _elements = (BitSet)other._elements.clone(); } /*-----------------------------------------------------------*/ /*--- (Access to) Static (Class) Variables ------------------*/ /*-----------------------------------------------------------*/ /** Constant for the empty set. */ public static final terminal_set EMPTY = new terminal_set(); /*-----------------------------------------------------------*/ /*--- (Access to) Instance Variables ------------------------*/ /*-----------------------------------------------------------*/ /** Bitset to implement the actual set. */ protected BitSet _elements; /*-----------------------------------------------------------*/ /*--- General Methods ----------------------------------------*/ /*-----------------------------------------------------------*/ /** Helper function to test for a null object and throw an exception if * one is found. * @param obj the object we are testing. */ protected void not_null(Object obj) throws internal_error { if (obj == null) throw new internal_error("Null object used in set operation"); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Determine if the set is empty. */ public boolean empty() { return equals(EMPTY); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Determine if the set contains a particular terminal. * @param sym the terminal symbol we are looking for. */ public boolean contains(terminal sym) throws internal_error { not_null(sym); return _elements.get(sym.index()); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Given its index determine if the set contains a particular terminal. * @param indx the index of the terminal in question. */ public boolean contains(int indx) { return _elements.get(indx); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Determine if this set is an (improper) subset of another. * @param other the set we are testing against. */ public boolean is_subset_of(terminal_set other) throws internal_error { not_null(other); /* make a copy of the other set */ BitSet copy_other = (BitSet)other._elements.clone(); /* and or in */ copy_other.or(_elements); /* if it hasn't changed, we were a subset */ return copy_other.equals(other._elements); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Determine if this set is an (improper) superset of another. * @param other the set we are testing against. */ public boolean is_superset_of(terminal_set other) throws internal_error { not_null(other); return other.is_subset_of(this); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Add a single terminal to the set. * @param sym the terminal being added. * @return true if this changes the set. */ public boolean add(terminal sym) throws internal_error { boolean result; not_null(sym); /* see if we already have this */ result = _elements.get(sym.index()); /* if not we add it */ if (!result) _elements.set(sym.index()); return result; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Remove a terminal if it is in the set. * @param sym the terminal being removed. */ public void remove(terminal sym) throws internal_error { not_null(sym); _elements.clear(sym.index()); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Add (union) in a complete set. * @param other the set being added. * @return true if this changes the set. */ public boolean add(terminal_set other) throws internal_error { not_null(other); /* make a copy */ BitSet copy = (BitSet)_elements.clone(); /* or in the other set */ _elements.or(other._elements); /* changed if we are not the same as the copy */ return !_elements.equals(copy); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Determine if this set intersects another. * @param other the other set in question. */ public boolean intersects(terminal_set other) throws internal_error { not_null(other); /* make a copy of the other set */ BitSet copy = (BitSet)other._elements.clone(); /* xor out our values */ copy.xor(this._elements); /* see if its different */ return !copy.equals(other._elements); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Equality comparison. */ public boolean equals(terminal_set other) { if (other == null) return false; else return _elements.equals(other._elements); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Generic equality comparison. */ public boolean equals(Object other) { if (!(other instanceof terminal_set)) return false; else return equals((terminal_set)other); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Convert to string. */ public String toString() { String result; boolean comma_flag; result = "{"; comma_flag = false; for (int t = 0; t < terminal.number(); t++) { if (_elements.get(t)) { if (comma_flag) result += ", "; else comma_flag = true; result += terminal.find(t).name(); } } result += "}"; return result; } /*-----------------------------------------------------------*/ } cup-0.11a+20060608/src/java_cup/version.java0000644000175000017500000000364410441773704020147 0ustar twernertwerner package java_cup; /** This class contains version and authorship information. * It contains only static data elements and basically just a central * place to put this kind of information so it can be updated easily * for each release. * * Version numbers used here are broken into 3 parts: major, minor, and * update, and are written as v.. (e.g. v0.10a). * Major numbers will change at the time of major reworking of some * part of the system. Minor numbers for each public release or * change big enough to cause incompatibilities. Finally update * letter will be incremented for small bug fixes and changes that * probably wouldn't be noticed by a user. * * @version last updated: 12/22/97 [CSA] * @author Frank Flannery */ public class version { /** The major version number. */ public static final int major = 0; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** The minor version number. */ public static final int minor = 11; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** The update letter. */ public static final String update = "a beta 20060608"; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** String for the current version. */ public static final String version_str = "v" + major + "." + minor + update; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Full title of the system */ public static final String title_str = "CUP " + version_str; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Name of the author */ public static final String author_str = "Scott E. Hudson, Frank Flannery, Andrea Flexeder, Michael Petter and C. Scott Ananian"; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** The command name normally used to invoke this program */ public static final String program_name = "java_cup"; } cup-0.11a+20060608/src/java_cup/parse_action.java0000644000175000017500000000532710250537770021130 0ustar twernertwerner package java_cup; /** This class serves as the base class for entries in a parse action table. * Full entries will either be SHIFT(state_num), REDUCE(production), NONASSOC, * or ERROR. Objects of this base class will default to ERROR, while * the other three types will be represented by subclasses. * * @see java_cup.reduce_action * @see java_cup.shift_action * @version last updated: 7/2/96 * @author Frank Flannery */ public class parse_action { /*-----------------------------------------------------------*/ /*--- Constructor(s) ----------------------------------------*/ /*-----------------------------------------------------------*/ /** Simple constructor. */ public parse_action() { /* nothing to do in the base class */ } /*-----------------------------------------------------------*/ /*--- (Access to) Static (Class) Variables ------------------*/ /*-----------------------------------------------------------*/ /** Constant for action type -- error action. */ public static final int ERROR = 0; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Constant for action type -- shift action. */ public static final int SHIFT = 1; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Constants for action type -- reduce action. */ public static final int REDUCE = 2; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Constants for action type -- reduce action. */ public static final int NONASSOC = 3; /*-----------------------------------------------------------*/ /*--- General Methods ---------------------------------------*/ /*-----------------------------------------------------------*/ /** Quick access to the type -- base class defaults to error. */ public int kind() {return ERROR;} /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Equality test. */ public boolean equals(parse_action other) { /* we match all error actions */ return other != null && other.kind() == ERROR; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Generic equality test. */ public boolean equals(Object other) { if (other instanceof parse_action) return equals((parse_action)other); else return false; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Compute a hash code. */ public int hashCode() { /* all objects of this class hash together */ return 0xCafe123; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Convert to string. */ public String toString() {return "ERROR";} /*-----------------------------------------------------------*/ } cup-0.11a+20060608/src/java_cup/terminal.java0000644000175000017500000001216710252326462020270 0ustar twernertwernerpackage java_cup; import java_cup.assoc; import java.util.Hashtable; import java.util.Enumeration; /** 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 * that will be returned by the scanner and pushed on the parse stack to * represent it). * * @version last updated: 7/3/96 * @author Frank Flannery */ public class terminal extends symbol { /*-----------------------------------------------------------*/ /*--- Constructor(s) ----------------------------------------*/ /*-----------------------------------------------------------*/ /** Full constructor. * @param nm the name of the terminal. * @param tp the type of the terminal. */ public terminal(String nm, String tp, int precedence_side, int precedence_num) { /* superclass does most of the work */ super(nm, tp); /* add to set of all terminals and check for duplicates */ Object conflict = _all.put(nm,this); if (conflict != null) // can't throw an execption here because this is used in static // initializers, so we do a crash instead // was: // throw new internal_error("Duplicate terminal (" + nm + ") created"); (new internal_error("Duplicate terminal (" + nm + ") created")).crash(); /* assign a unique index */ _index = next_index++; /* set the precedence */ _precedence_num = precedence_num; _precedence_side = precedence_side; /* add to by_index set */ _all_by_index.put(new Integer(_index), this); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Constructor for non-precedented terminal */ public terminal(String nm, String tp) { this(nm, tp, assoc.no_prec, -1); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Constructor with default type. * @param nm the name of the terminal. */ public terminal(String nm) { this(nm, null); } /*-----------------------------------------------------------*/ /*------------------- Class Variables ---------------------*/ /*-----------------------------------------------------------*/ private int _precedence_num; private int _precedence_side; /*-----------------------------------------------------------*/ /*--- (Access to) Static (Class) Variables ------------------*/ /*-----------------------------------------------------------*/ /** Table of all terminals. Elements are stored using name strings as * the key */ protected static Hashtable _all = new Hashtable(); //Hm Added clear to clear all static fields public static void clear() { _all.clear(); _all_by_index.clear(); next_index=0; EOF = new terminal("EOF"); error = new terminal ("error"); } /** Access to all terminals. */ public static Enumeration all() {return _all.elements();} /** Lookup a terminal by name string. */ public static terminal find(String with_name) { if (with_name == null) return null; else return (terminal)_all.get(with_name); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Table of all terminals indexed by their index number. */ protected static Hashtable _all_by_index = new Hashtable(); /** Lookup a terminal by index. */ public static terminal find(int indx) { Integer the_indx = new Integer(indx); return (terminal)_all_by_index.get(the_indx); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Total number of terminals. */ public static int number() {return _all.size();} /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Static counter to assign unique index. */ protected static int next_index = 0; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Special terminal for end of input. */ public static terminal EOF = new terminal("EOF"); /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** special terminal used for error recovery */ public static terminal error = new terminal("error"); /*-----------------------------------------------------------*/ /*--- General Methods ---------------------------------------*/ /*-----------------------------------------------------------*/ /** Report this symbol as not being a non-terminal. */ public boolean is_non_term() { return false; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Convert to a string. */ public String toString() { return super.toString() + "[" + index() + "]"; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** get the precedence of a terminal */ public int precedence_num() { return _precedence_num; } public int precedence_side() { return _precedence_side; } /** set the precedence of a terminal */ public void set_precedence(int p, int new_prec) { _precedence_side = p; _precedence_num = new_prec; } /*-----------------------------------------------------------*/ } cup-0.11a+20060608/src/java_cup/lalr_transition.java0000644000175000017500000000566310250537770021670 0ustar twernertwernerpackage java_cup; /** This class represents a transition in an LALR viable prefix recognition * machine. Transitions can be under terminals for non-terminals. They are * internally linked together into singly linked lists containing all the * transitions out of a single state via the _next field. * * @see java_cup.lalr_state * @version last updated: 11/25/95 * @author Scott Hudson * */ public class lalr_transition { /*-----------------------------------------------------------*/ /*--- Constructor(s) ----------------------------------------*/ /*-----------------------------------------------------------*/ /** Full constructor. * @param on_sym symbol we are transitioning on. * @param to_st state we transition to. * @param nxt next transition in linked list. */ public lalr_transition(symbol on_sym, lalr_state to_st, lalr_transition nxt) throws internal_error { /* sanity checks */ if (on_sym == null) throw new internal_error("Attempt to create transition on null symbol"); if (to_st == null) throw new internal_error("Attempt to create transition to null state"); /* initialize */ _on_symbol = on_sym; _to_state = to_st; _next = nxt; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Constructor with null next. * @param on_sym symbol we are transitioning on. * @param to_st state we transition to. */ public lalr_transition(symbol on_sym, lalr_state to_st) throws internal_error { this(on_sym, to_st, null); } /*-----------------------------------------------------------*/ /*--- (Access to) Instance Variables ------------------------*/ /*-----------------------------------------------------------*/ /** The symbol we make the transition on. */ protected symbol _on_symbol; /** The symbol we make the transition on. */ public symbol on_symbol() {return _on_symbol;} /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** The state we transition to. */ protected lalr_state _to_state; /** The state we transition to. */ public lalr_state to_state() {return _to_state;} /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Next transition in linked list of transitions out of a state */ protected lalr_transition _next; /** Next transition in linked list of transitions out of a state */ public lalr_transition next() {return _next;} /*-----------------------------------------------------------*/ /*--- General Methods ---------------------------------------*/ /*-----------------------------------------------------------*/ /** Convert to a string. */ public String toString() { String result; result = "transition on " + on_symbol().name() + " to state ["; result += _to_state.index(); result += "]"; return result; } /*-----------------------------------------------------------*/ } cup-0.11a+20060608/src/java_cup/ErrorManager.java0000644000175000017500000000452210412217534021032 0ustar twernertwerner package java_cup; import java_cup.runtime.Symbol; import java.lang.reflect.Field; import java.lang.reflect.Modifier; 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 at ("+sym.left+"/"+sym.right+")@"+convSymbol(sym)+" : "+message); 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 at ("+sym.left+"/"+sym.right+")@"+convSymbol(sym)+" : "+message); System.err.println("Fatal: "+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 at ("+sym.left+"/"+sym.right+")@"+convSymbol(sym)+" : "+message); System.err.println("Error: "+message+" @ "+sym); errors++; } private static String convSymbol(Symbol symbol){ String result = (symbol.value == null)? "" : " (\""+symbol.value.toString()+"\")"; Field [] fields = sym.class.getFields(); for (int i = 0; i < fields.length ; i++){ if (!Modifier.isPublic(fields[i].getModifiers())) continue; try { if (fields[i].getInt(null) == symbol.sym) return fields[i].getName()+result; }catch (Exception ex) { } } return symbol.toString()+result; } } cup-0.11a+20060608/src/java_cup/runtime/0000755000175000017500000000000011075720101017256 5ustar twernertwernercup-0.11a+20060608/src/java_cup/runtime/Scanner.java0000644000175000017500000000153610250537770021533 0ustar twernertwernerpackage java_cup.runtime; /** * Defines the Scanner interface, which CUP uses in the default * implementation of lr_parser.scan(). Integration * of scanners implementing Scanner is facilitated. * * @version last updated 23-Jul-1999 * @author David MacMahon */ /* ************************************************* Interface Scanner Declares the next_token() method that should be implemented by scanners. This method is typically called by lr_parser.scan(). End-of-file can be indicated either by returning new Symbol(lr_parser.EOF_sym()) or null. ***************************************************/ public interface Scanner { /** Return the next token, or null on end-of-file. */ public Symbol next_token() throws java.lang.Exception; } cup-0.11a+20060608/src/java_cup/runtime/virtual_parse_stack.java0000644000175000017500000001157710250537770024215 0ustar twernertwerner package java_cup.runtime; import java.util.Stack; /** This class implements a temporary or "virtual" parse stack that * replaces the top portion of the actual parse stack (the part that * has been changed by some set of operations) while maintaining its * original contents. This data structure is used when the parse needs * to "parse ahead" to determine if a given error recovery attempt will * allow the parse to continue far enough to consider it successful. Once * success or failure of parse ahead is determined the system then * reverts to the original parse stack (which has not actually been * modified). Since parse ahead does not execute actions, only parse * state is maintained on the virtual stack, not full Symbol objects. * * @see java_cup.runtime.lr_parser * @version last updated: 7/3/96 * @author Frank Flannery */ public class virtual_parse_stack { /*-----------------------------------------------------------*/ /*--- Constructor(s) ----------------------------------------*/ /*-----------------------------------------------------------*/ /** Constructor to build a virtual stack out of a real stack. */ public virtual_parse_stack(Stack shadowing_stack) throws java.lang.Exception { /* sanity check */ if (shadowing_stack == null) throw new Exception( "Internal parser error: attempt to create null virtual stack"); /* set up our internals */ real_stack = shadowing_stack; vstack = new Stack(); real_next = 0; /* get one element onto the virtual portion of the stack */ get_from_real(); } /*-----------------------------------------------------------*/ /*--- (Access to) Instance Variables ------------------------*/ /*-----------------------------------------------------------*/ /** The real stack that we shadow. This is accessed when we move off * the bottom of the virtual portion of the stack, but is always left * unmodified. */ protected Stack real_stack; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Top of stack indicator for where we leave off in the real stack. * This is measured from top of stack, so 0 would indicate that no * elements have been "moved" from the real to virtual stack. */ protected int real_next; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** The virtual top portion of the stack. This stack contains Integer * objects with state numbers. This stack shadows the top portion * of the real stack within the area that has been modified (via operations * on the virtual stack). When this portion of the stack becomes empty we * transfer elements from the underlying stack onto this stack. */ protected Stack vstack; /*-----------------------------------------------------------*/ /*--- General Methods ---------------------------------------*/ /*-----------------------------------------------------------*/ /** Transfer an element from the real to the virtual stack. This assumes * that the virtual stack is currently empty. */ protected void get_from_real() { Symbol stack_sym; /* don't transfer if the real stack is empty */ if (real_next >= real_stack.size()) return; /* get a copy of the first Symbol we have not transfered */ stack_sym = (Symbol)real_stack.elementAt(real_stack.size()-1-real_next); /* record the transfer */ real_next++; /* put the state number from the Symbol onto the virtual stack */ vstack.push(new Integer(stack_sym.parse_state)); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Indicate whether the stack is empty. */ public boolean empty() { /* if vstack is empty then we were unable to transfer onto it and the whole thing is empty. */ return vstack.empty(); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Return value on the top of the stack (without popping it). */ public int top() throws java.lang.Exception { if (vstack.empty()) throw new Exception( "Internal parser error: top() called on empty virtual stack"); return ((Integer)vstack.peek()).intValue(); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Pop the stack. */ public void pop() throws java.lang.Exception { if (vstack.empty()) throw new Exception( "Internal parser error: pop from empty virtual stack"); /* pop it */ vstack.pop(); /* if we are now empty transfer an element (if there is one) */ if (vstack.empty()) get_from_real(); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Push a state number onto the stack. */ public void push(int state_num) { vstack.push(new Integer(state_num)); } /*-----------------------------------------------------------*/ } cup-0.11a+20060608/src/java_cup/runtime/ComplexSymbolFactory.java0000644000175000017500000000762710413036260024263 0ustar twernertwernerpackage java_cup.runtime; /** * Default Implementation for SymbolFactory, creates * plain old Symbols * * @version last updated 27-03-2006 * @author Michael Petter */ /* ************************************************* class DefaultSymbolFactory interface for creating new symbols ***************************************************/ public class ComplexSymbolFactory implements SymbolFactory{ public static class Location { private String unit="unknown"; private int line, column; public Location(String unit, int line, int column){ this.unit=unit; this.line=line; this.column=column; } public Location(int line, int column){ this.line=line; this.column=column; } public String toString(){ return unit+":"+line+"/"+column; } public int getColumn(){ return column; } public int getLine(){ return line; } public String getUnit(){ return unit; } } /** * ComplexSymbol with detailed Location Informations and a Name */ public static class ComplexSymbol extends Symbol { protected String name; protected Location xleft,xright; public ComplexSymbol(String name, int id) { super(id); this.name=name; } public ComplexSymbol(String name, int id, Object value) { super(id,value); this.name=name; } public String toString(){ if (xleft==null || xright==null) return "Symbol: "+name; return "Symbol: "+name+" ("+xleft+" - "+xright+")"; } public ComplexSymbol(String name, int id, int state) { super(id,state); this.name=name; } public ComplexSymbol(String name, int id, Symbol left, Symbol right) { super(id,left,right); this.name=name; if (left!=null) this.xleft = ((ComplexSymbol)left).xleft; if (right!=null) this.xright= ((ComplexSymbol)right).xright; } public ComplexSymbol(String name, int id, Location left, Location right) { super(id); this.name=name; this.xleft=left; this.xright=right; } public ComplexSymbol(String name, int id, Symbol left, Symbol right, Object value) { super(id,value); this.name=name; if (left!=null) this.xleft = ((ComplexSymbol)left).xleft; if (right!=null) this.xright= ((ComplexSymbol)right).xright; } public ComplexSymbol(String name, int id, Location left, Location right, Object value) { super(id,value); this.name=name; this.xleft=left; this.xright=right; } public Location getLeft(){ return xleft; } public Location getRight(){ return xright; } } // Factory methods public Symbol newSymbol(String name, int id, Location left, Location right, Object value){ return new ComplexSymbol(name,id,left,right,value); } public Symbol newSymbol(String name, int id, Location left, Location right){ return new ComplexSymbol(name,id,left,right); } public Symbol newSymbol(String name, int id, Symbol left, Symbol right, Object value){ return new ComplexSymbol(name,id,left,right,value); } public Symbol newSymbol(String name, int id, Symbol left, Symbol right){ return new ComplexSymbol(name,id,left,right); } public Symbol newSymbol(String name, int id){ return new ComplexSymbol(name,id); } public Symbol newSymbol(String name, int id, Object value){ return new ComplexSymbol(name,id,value); } public Symbol startSymbol(String name, int id, int state){ return new ComplexSymbol(name,id,state); } } cup-0.11a+20060608/src/java_cup/runtime/Symbol.java0000644000175000017500000000611510412217534021376 0ustar twernertwernerpackage java_cup.runtime; /** * Defines the Symbol class, which is used to represent all terminals * and nonterminals while parsing. The lexer should pass CUP Symbols * and CUP returns a Symbol. * * @version last updated: 7/3/96 * @author Frank Flannery */ /* **************************************************************** Class Symbol what the parser expects to receive from the lexer. the token is identified as follows: sym: the symbol type parse_state: the parse state. value: is the lexical value of type Object left : is the left position in the original input file right: is the right position in the original input file xleft: is the left position Object in the original input file xright: is the left position Object in the original input file ******************************************************************/ public class Symbol { // TUM 20060327: Added new Constructor to provide more flexible way // for location handling /******************************* *******************************/ public Symbol(int id, Symbol left, Symbol right, Object o){ this(id,left.left,right.right,o); } public Symbol(int id, Symbol left, Symbol right){ this(id,left.left,right.right); } /******************************* Constructor for l,r values *******************************/ public Symbol(int id, int l, int r, Object o) { this(id); left = l; right = r; value = o; } /******************************* Constructor for no l,r values ********************************/ public Symbol(int id, Object o) { this(id, -1, -1, o); } /***************************** Constructor for no value ***************************/ public Symbol(int id, int l, int r) { this(id, l, r, null); } /*********************************** Constructor for no value or l,r ***********************************/ public Symbol(int sym_num) { this(sym_num, -1); left = -1; right = -1; } /*********************************** Constructor to give a start state ***********************************/ Symbol(int sym_num, int state) { sym = sym_num; parse_state = state; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** The symbol number of the terminal or non terminal being represented */ public int sym; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** The parse state to be recorded on the parse stack with this symbol. * This field is for the convenience of the parser and shouldn't be * modified except by the parser. */ public int parse_state; /** This allows us to catch some errors caused by scanners recycling * symbols. For the use of the parser only. [CSA, 23-Jul-1999] */ boolean used_by_parser = false; /******************************* The data passed to parser *******************************/ public int left, right; public Object value; /***************************** Printing this token out. (Override for pretty-print). ****************************/ public String toString() { return "#"+sym; } } cup-0.11a+20060608/src/java_cup/runtime/DefaultSymbolFactory.java0000644000175000017500000000334210413036260024226 0ustar twernertwernerpackage java_cup.runtime; /** * Default Implementation for SymbolFactory, creates * plain old Symbols * * @version last updated 27-03-2006 * @author Michael Petter */ /* ************************************************* class DefaultSymbolFactory interface for creating new symbols ***************************************************/ public class DefaultSymbolFactory implements SymbolFactory{ // Factory methods /** * DefaultSymbolFactory for CUP. * Users are strongly encoraged to use ComplexSymbolFactory instead, since * it offers more detailed information about Symbols in source code. * Yet since migrating has always been a critical process, You have the * chance of still using the oldstyle Symbols. * * @deprecated as of CUP v11a * replaced by the new java_cup.runtime.ComplexSymbolFactory */ //@deprecated public DefaultSymbolFactory(){ } public Symbol newSymbol(String name ,int id, Symbol left, Symbol right, Object value){ return new Symbol(id,left,right,value); } public Symbol newSymbol(String name, int id, Symbol left, Symbol right){ return new Symbol(id,left,right); } public Symbol newSymbol(String name, int id, int left, int right, Object value){ return new Symbol(id,left,right,value); } public Symbol newSymbol(String name, int id, int left, int right){ return new Symbol(id,left,right); } public Symbol startSymbol(String name, int id, int state){ return new Symbol(id,state); } public Symbol newSymbol(String name, int id){ return new Symbol(id); } public Symbol newSymbol(String name, int id, Object value){ return new Symbol(id,value); } } cup-0.11a+20060608/src/java_cup/runtime/SymbolFactory.java0000644000175000017500000000207210413036260022720 0ustar twernertwernerpackage java_cup.runtime; /** * Creates the Symbols interface, which CUP uses as default * * @version last updated 27-03-2006 * @author Michael Petter */ /* ************************************************* Interface SymbolFactory interface for creating new symbols You can also use this interface for your own callback hooks Declare Your own factory methods for creation of Objects in Your scanner! ***************************************************/ public interface SymbolFactory { // Factory methods /** * Construction with left/right propagation switched on */ public Symbol newSymbol(String name, int id, Symbol left, Symbol right, Object value); public Symbol newSymbol(String name, int id, Symbol left, Symbol right); /** * Construction with left/right propagation switched off */ public Symbol newSymbol(String name, int id, Object value); public Symbol newSymbol(String name, int id); /** * Construction of start symbol */ public Symbol startSymbol(String name, int id, int state); } cup-0.11a+20060608/src/java_cup/runtime/lr_parser.java0000644000175000017500000012742610412217534022133 0ustar twernertwerner package java_cup.runtime; import java.util.Stack; /** This class implements a skeleton table driven LR parser. In general, * LR parsers are a form of bottom up shift-reduce parsers. Shift-reduce * parsers act by shifting input onto a parse stack until the Symbols * matching the right hand side of a production appear on the top of the * stack. Once this occurs, a reduce is performed. This involves removing * the Symbols corresponding to the right hand side of the production * (the so called "handle") and replacing them with the non-terminal from * the left hand side of the production.

* * To control the decision of whether to shift or reduce at any given point, * the parser uses a state machine (the "viable prefix recognition machine" * built by the parser generator). The current state of the machine is placed * on top of the parse stack (stored as part of a Symbol object representing * a terminal or non terminal). The parse action table is consulted * (using the current state and the current lookahead Symbol as indexes) to * determine whether to shift or to reduce. When the parser shifts, it * changes to a new state by pushing a new Symbol (containing a new state) * onto the stack. When the parser reduces, it pops the handle (right hand * side of a production) off the stack. This leaves the parser in the state * it was in before any of those Symbols were matched. Next the reduce-goto * table is consulted (using the new state and current lookahead Symbol as * indexes) to determine a new state to go to. The parser then shifts to * this goto state by pushing the left hand side Symbol of the production * (also containing the new state) onto the stack.

* * This class actually provides four LR parsers. The methods parse() and * debug_parse() provide two versions of the main parser (the only difference * being that debug_parse() emits debugging trace messages as it parses). * In addition to these main parsers, the error recovery mechanism uses two * more. One of these is used to simulate "parsing ahead" in the input * without carrying out actions (to verify that a potential error recovery * has worked), and the other is used to parse through buffered "parse ahead" * input in order to execute all actions and re-synchronize the actual parser * configuration.

* * This is an abstract class which is normally filled out by a subclass * generated by the JavaCup parser generator. In addition to supplying * the actual parse tables, generated code also supplies methods which * invoke various pieces of user supplied code, provide access to certain * special Symbols (e.g., EOF and error), etc. Specifically, the following * abstract methods are normally supplied by generated code: *

*
short[][] production_table() *
Provides a reference to the production table (indicating the index of * the left hand side non terminal and the length of the right hand side * for each production in the grammar). *
short[][] action_table() *
Provides a reference to the parse action table. *
short[][] reduce_table() *
Provides a reference to the reduce-goto table. *
int start_state() *
Indicates the index of the start state. *
int start_production() *
Indicates the index of the starting production. *
int EOF_sym() *
Indicates the index of the EOF Symbol. *
int error_sym() *
Indicates the index of the error Symbol. *
Symbol do_action() *
Executes a piece of user supplied action code. This always comes at * the point of a reduce in the parse, so this code also allocates and * fills in the left hand side non terminal Symbol object that is to be * pushed onto the stack for the reduce. *
void init_actions() *
Code to initialize a special object that encapsulates user supplied * actions (this object is used by do_action() to actually carry out the * actions). *
* * In addition to these routines that must be supplied by the * generated subclass there are also a series of routines that may * be supplied. These include: *
*
Symbol scan() *
Used to get the next input Symbol from the scanner. *
Scanner getScanner() *
Used to provide a scanner for the default implementation of * scan(). *
int error_sync_size() *
This determines how many Symbols past the point of an error * must be parsed without error in order to consider a recovery to * be valid. This defaults to 3. Values less than 2 are not * recommended. *
void report_error(String message, Object info) *
This method is called to report an error. The default implementation * simply prints a message to System.err and where the error occurred. * This method is often replaced in order to provide a more sophisticated * error reporting mechanism. *
void report_fatal_error(String message, Object info) *
This method is called when a fatal error that cannot be recovered from * is encountered. In the default implementation, it calls * report_error() to emit a message, then throws an exception. *
void syntax_error(Symbol cur_token) *
This method is called as soon as syntax error is detected (but * before recovery is attempted). In the default implementation it * invokes: report_error("Syntax error", null); *
void unrecovered_syntax_error(Symbol cur_token) *
This method is called if syntax error recovery fails. In the default * implementation it invokes:
* report_fatal_error("Couldn't repair and continue parse", null); *
* * @see java_cup.runtime.Symbol * @see java_cup.runtime.Symbol * @see java_cup.runtime.virtual_parse_stack * @version last updated: 7/3/96 * @author Frank Flannery */ public abstract class lr_parser { /*-----------------------------------------------------------*/ /*--- Constructor(s) ----------------------------------------*/ /*-----------------------------------------------------------*/ /** * Simple constructor. */ public lr_parser() { } /** * Constructor that sets the default scanner. [CSA/davidm] */ public lr_parser(Scanner s) { this(s,new DefaultSymbolFactory()); // TUM 20060327 old cup v10 Symbols as default } /** * Constructor that sets the default scanner and a SymbolFactory */ public lr_parser(Scanner s, SymbolFactory symfac) { this(); // in case default constructor someday does something symbolFactory = symfac; setScanner(s); } public SymbolFactory symbolFactory;// = new DefaultSymbolFactory(); /** * Whenever creation of a new Symbol is necessary, one should use this factory. */ public SymbolFactory getSymbolFactory(){ return symbolFactory; } /*-----------------------------------------------------------*/ /*--- (Access to) Static (Class) Variables ------------------*/ /*-----------------------------------------------------------*/ /** The default number of Symbols after an error we much match to consider * it recovered from. */ protected final static int _error_sync_size = 3; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** The number of Symbols after an error we much match to consider it * recovered from. */ protected int error_sync_size() {return _error_sync_size; } /*-----------------------------------------------------------*/ /*--- (Access to) Instance Variables ------------------------*/ /*-----------------------------------------------------------*/ /** Table of production information (supplied by generated subclass). * This table contains one entry per production and is indexed by * the negative-encoded values (reduce actions) in the action_table. * Each entry has two parts, the index of the non-terminal on the * left hand side of the production, and the number of Symbols * on the right hand side. */ public abstract short[][] production_table(); /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** The action table (supplied by generated subclass). This table is * indexed by state and terminal number indicating what action is to * be taken when the parser is in the given state (i.e., the given state * is on top of the stack) and the given terminal is next on the input. * States are indexed using the first dimension, however, the entries for * a given state are compacted and stored in adjacent index, value pairs * which are searched for rather than accessed directly (see get_action()). * The actions stored in the table will be either shifts, reduces, or * errors. Shifts are encoded as positive values (one greater than the * state shifted to). Reduces are encoded as negative values (one less * than the production reduced by). Error entries are denoted by zero. * * @see java_cup.runtime.lr_parser#get_action */ public abstract short[][] action_table(); /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** The reduce-goto table (supplied by generated subclass). This * table is indexed by state and non-terminal number and contains * state numbers. States are indexed using the first dimension, however, * the entries for a given state are compacted and stored in adjacent * index, value pairs which are searched for rather than accessed * directly (see get_reduce()). When a reduce occurs, the handle * (corresponding to the RHS of the matched production) is popped off * the stack. The new top of stack indicates a state. This table is * then indexed by that state and the LHS of the reducing production to * indicate where to "shift" to. * * @see java_cup.runtime.lr_parser#get_reduce */ public abstract short[][] reduce_table(); /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** The index of the start state (supplied by generated subclass). */ public abstract int start_state(); /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** The index of the start production (supplied by generated subclass). */ public abstract int start_production(); /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** The index of the end of file terminal Symbol (supplied by generated * subclass). */ public abstract int EOF_sym(); /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** The index of the special error Symbol (supplied by generated subclass). */ public abstract int error_sym(); /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Internal flag to indicate when parser should quit. */ protected boolean _done_parsing = false; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** This method is called to indicate that the parser should quit. This is * normally called by an accept action, but can be used to cancel parsing * early in other circumstances if desired. */ public void done_parsing() { _done_parsing = true; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /* Global parse state shared by parse(), error recovery, and * debugging routines */ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Indication of the index for top of stack (for use by actions). */ protected int tos; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** The current lookahead Symbol. */ protected Symbol cur_token; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** The parse stack itself. */ protected Stack stack = new Stack(); /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Direct reference to the production table. */ protected short[][] production_tab; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Direct reference to the action table. */ protected short[][] action_tab; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Direct reference to the reduce-goto table. */ protected short[][] reduce_tab; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** This is the scanner object used by the default implementation * of scan() to get Symbols. To avoid name conflicts with existing * code, this field is private. [CSA/davidm] */ private Scanner _scanner; /** * Simple accessor method to set the default scanner. */ public void setScanner(Scanner s) { _scanner = s; } /** * Simple accessor method to get the default scanner. */ public Scanner getScanner() { return _scanner; } /*-----------------------------------------------------------*/ /*--- General Methods ---------------------------------------*/ /*-----------------------------------------------------------*/ /** Perform a bit of user supplied action code (supplied by generated * subclass). Actions are indexed by an internal action number assigned * at parser generation time. * * @param act_num the internal index of the action to be performed. * @param parser the parser object we are acting for. * @param stack the parse stack of that object. * @param top the index of the top element of the parse stack. */ public abstract Symbol do_action( int act_num, lr_parser parser, Stack stack, int top) throws java.lang.Exception; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** User code for initialization inside the parser. Typically this * initializes the scanner. This is called before the parser requests * the first Symbol. Here this is just a placeholder for subclasses that * might need this and we perform no action. This method is normally * overridden by the generated code using this contents of the "init with" * clause as its body. */ public void user_init() throws java.lang.Exception { } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Initialize the action object. This is called before the parser does * any parse actions. This is filled in by generated code to create * an object that encapsulates all action code. */ protected abstract void init_actions() throws java.lang.Exception; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Get the next Symbol from the input (supplied by generated subclass). * Once end of file has been reached, all subsequent calls to scan * should return an EOF Symbol (which is Symbol number 0). By default * this method returns getScanner().next_token(); this implementation * can be overriden by the generated parser using the code declared in * the "scan with" clause. Do not recycle objects; every call to * scan() should return a fresh object. */ public Symbol scan() throws java.lang.Exception { Symbol sym = getScanner().next_token(); return (sym!=null) ? sym : getSymbolFactory().newSymbol("END_OF_FILE",EOF_sym()); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Report a fatal error. This method takes a message string and an * additional object (to be used by specializations implemented in * subclasses). Here in the base class a very simple implementation * is provided which reports the error then throws an exception. * * @param message an error message. * @param info an extra object reserved for use by specialized subclasses. */ public void report_fatal_error( String message, Object info) throws java.lang.Exception { /* stop parsing (not really necessary since we throw an exception, but) */ done_parsing(); /* use the normal error message reporting to put out the message */ report_error(message, info); /* throw an exception */ throw new Exception("Can't recover from previous error(s)"); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Report a non fatal error (or warning). This method takes a message * string and an additional object (to be used by specializations * implemented in subclasses). Here in the base class a very simple * implementation is provided which simply prints the message to * System.err. * * @param message an error message. * @param info an extra object reserved for use by specialized subclasses. */ public void report_error(String message, Object info) { System.err.print(message); System.err.flush(); if (info instanceof Symbol) if (((Symbol)info).left != -1) System.err.println(" at character " + ((Symbol)info).left + " of input"); else System.err.println(""); else System.err.println(""); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** This method is called when a syntax error has been detected and recovery * is about to be invoked. Here in the base class we just emit a * "Syntax error" error message. * * @param cur_token the current lookahead Symbol. */ public void syntax_error(Symbol cur_token) { report_error("Syntax error", cur_token); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** This method is called if it is determined that syntax error recovery * has been unsuccessful. Here in the base class we report a fatal error. * * @param cur_token the current lookahead Symbol. */ public void unrecovered_syntax_error(Symbol cur_token) throws java.lang.Exception { report_fatal_error("Couldn't repair and continue parse", cur_token); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Fetch an action from the action table. The table is broken up into * rows, one per state (rows are indexed directly by state number). * Within each row, a list of index, value pairs are given (as sequential * entries in the table), and the list is terminated by a default entry * (denoted with a Symbol index of -1). To find the proper entry in a row * we do a linear or binary search (depending on the size of the row). * * @param state the state index of the action being accessed. * @param sym the Symbol index of the action being accessed. */ protected final short get_action(int state, int sym) { short tag; int first, last, probe; short[] row = action_tab[state]; /* linear search if we are < 10 entries */ if (row.length < 20) for (probe = 0; probe < row.length; probe++) { /* is this entry labeled with our Symbol or the default? */ tag = row[probe++]; if (tag == sym || tag == -1) { /* return the next entry */ return row[probe]; } } /* otherwise binary search */ else { first = 0; last = (row.length-1)/2 - 1; /* leave out trailing default entry */ while (first <= last) { probe = (first+last)/2; if (sym == row[probe*2]) return row[probe*2+1]; else if (sym > row[probe*2]) first = probe+1; else last = probe-1; } /* not found, use the default at the end */ return row[row.length-1]; } /* shouldn't happened, but if we run off the end we return the default (error == 0) */ return 0; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Fetch a state from the reduce-goto table. The table is broken up into * rows, one per state (rows are indexed directly by state number). * Within each row, a list of index, value pairs are given (as sequential * entries in the table), and the list is terminated by a default entry * (denoted with a Symbol index of -1). To find the proper entry in a row * we do a linear search. * * @param state the state index of the entry being accessed. * @param sym the Symbol index of the entry being accessed. */ protected final short get_reduce(int state, int sym) { short tag; short[] row = reduce_tab[state]; /* if we have a null row we go with the default */ if (row == null) return -1; for (int probe = 0; probe < row.length; probe++) { /* is this entry labeled with our Symbol or the default? */ tag = row[probe++]; if (tag == sym || tag == -1) { /* return the next entry */ return row[probe]; } } /* if we run off the end we return the default (error == -1) */ return -1; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** This method provides the main parsing routine. It returns only when * done_parsing() has been called (typically because the parser has * accepted, or a fatal error has been reported). See the header * documentation for the class regarding how shift/reduce parsers operate * and how the various tables are used. */ public Symbol parse() throws java.lang.Exception { /* the current action code */ int act; /* the Symbol/stack element returned by a reduce */ Symbol lhs_sym = null; /* information about production being reduced with */ short handle_size, lhs_sym_num; /* set up direct reference to tables to drive the parser */ production_tab = production_table(); action_tab = action_table(); reduce_tab = reduce_table(); /* initialize the action encapsulation object */ init_actions(); /* do user initialization */ user_init(); /* get the first token */ cur_token = scan(); /* push dummy Symbol with start state to get us underway */ stack.removeAllElements(); stack.push(getSymbolFactory().startSymbol("START", 0, start_state())); tos = 0; /* continue until we are told to stop */ for (_done_parsing = false; !_done_parsing; ) { /* Check current token for freshness. */ if (cur_token.used_by_parser) throw new Error("Symbol recycling detected (fix your scanner)."); /* current state is always on the top of the stack */ /* look up action out of the current state with the current input */ act = get_action(((Symbol)stack.peek()).parse_state, cur_token.sym); /* decode the action -- > 0 encodes shift */ if (act > 0) { /* shift to the encoded state by pushing it on the stack */ cur_token.parse_state = act-1; cur_token.used_by_parser = true; stack.push(cur_token); tos++; /* advance to the next Symbol */ cur_token = scan(); } /* if its less than zero, then it encodes a reduce action */ else if (act < 0) { /* perform the action for the reduce */ lhs_sym = do_action((-act)-1, this, stack, tos); /* look up information about the production */ lhs_sym_num = production_tab[(-act)-1][0]; handle_size = production_tab[(-act)-1][1]; /* pop the handle off the stack */ for (int i = 0; i < handle_size; i++) { stack.pop(); tos--; } /* look up the state to go to from the one popped back to */ act = get_reduce(((Symbol)stack.peek()).parse_state, lhs_sym_num); /* shift to that state */ lhs_sym.parse_state = act; lhs_sym.used_by_parser = true; stack.push(lhs_sym); tos++; } /* finally if the entry is zero, we have an error */ else if (act == 0) { /* call user syntax error reporting routine */ syntax_error(cur_token); /* try to error recover */ if (!error_recovery(false)) { /* if that fails give up with a fatal syntax error */ unrecovered_syntax_error(cur_token); /* just in case that wasn't fatal enough, end parse */ done_parsing(); } else { lhs_sym = (Symbol)stack.peek(); } } } return lhs_sym; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Write a debugging message to System.err for the debugging version * of the parser. * * @param mess the text of the debugging message. */ public void debug_message(String mess) { System.err.println(mess); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Dump the parse stack for debugging purposes. */ public void dump_stack() { if (stack == null) { debug_message("# Stack dump requested, but stack is null"); return; } debug_message("============ Parse Stack Dump ============"); /* dump the stack */ for (int i=0; i"); if ((i%3)==2 || (i==(stack.size()-1))) { debug_message(sb.toString()); sb = new StringBuffer(" "); } } } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Perform a parse with debugging output. This does exactly the * same things as parse(), except that it calls debug_shift() and * debug_reduce() when shift and reduce moves are taken by the parser * and produces various other debugging messages. */ public Symbol debug_parse() throws java.lang.Exception { /* the current action code */ int act; /* the Symbol/stack element returned by a reduce */ Symbol lhs_sym = null; /* information about production being reduced with */ short handle_size, lhs_sym_num; /* set up direct reference to tables to drive the parser */ production_tab = production_table(); action_tab = action_table(); reduce_tab = reduce_table(); debug_message("# Initializing parser"); /* initialize the action encapsulation object */ init_actions(); /* do user initialization */ user_init(); /* the current Symbol */ cur_token = scan(); debug_message("# Current Symbol is #" + cur_token.sym); /* push dummy Symbol with start state to get us underway */ stack.removeAllElements(); stack.push(getSymbolFactory().startSymbol("START",0, start_state())); tos = 0; /* continue until we are told to stop */ for (_done_parsing = false; !_done_parsing; ) { /* Check current token for freshness. */ if (cur_token.used_by_parser) throw new Error("Symbol recycling detected (fix your scanner)."); /* current state is always on the top of the stack */ //debug_stack(); /* look up action out of the current state with the current input */ act = get_action(((Symbol)stack.peek()).parse_state, cur_token.sym); /* decode the action -- > 0 encodes shift */ if (act > 0) { /* shift to the encoded state by pushing it on the stack */ cur_token.parse_state = act-1; cur_token.used_by_parser = true; debug_shift(cur_token); stack.push(cur_token); tos++; /* advance to the next Symbol */ cur_token = scan(); debug_message("# Current token is " + cur_token); } /* if its less than zero, then it encodes a reduce action */ else if (act < 0) { /* perform the action for the reduce */ lhs_sym = do_action((-act)-1, this, stack, tos); /* look up information about the production */ lhs_sym_num = production_tab[(-act)-1][0]; handle_size = production_tab[(-act)-1][1]; debug_reduce((-act)-1, lhs_sym_num, handle_size); /* pop the handle off the stack */ for (int i = 0; i < handle_size; i++) { stack.pop(); tos--; } /* look up the state to go to from the one popped back to */ act = get_reduce(((Symbol)stack.peek()).parse_state, lhs_sym_num); debug_message("# Reduce rule: top state " + ((Symbol)stack.peek()).parse_state + ", lhs sym " + lhs_sym_num + " -> state " + act); /* shift to that state */ lhs_sym.parse_state = act; lhs_sym.used_by_parser = true; stack.push(lhs_sym); tos++; debug_message("# Goto state #" + act); } /* finally if the entry is zero, we have an error */ else if (act == 0) { /* call user syntax error reporting routine */ syntax_error(cur_token); /* try to error recover */ if (!error_recovery(true)) { /* if that fails give up with a fatal syntax error */ unrecovered_syntax_error(cur_token); /* just in case that wasn't fatal enough, end parse */ done_parsing(); } else { lhs_sym = (Symbol)stack.peek(); } } } return lhs_sym; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /* Error recovery code */ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Attempt to recover from a syntax error. This returns false if recovery * fails, true if it succeeds. Recovery happens in 4 steps. First we * pop the parse stack down to a point at which we have a shift out * of the top-most state on the error Symbol. This represents the * initial error recovery configuration. If no such configuration is * found, then we fail. Next a small number of "lookahead" or "parse * ahead" Symbols are read into a buffer. The size of this buffer is * determined by error_sync_size() and determines how many Symbols beyond * the error must be matched to consider the recovery a success. Next, * we begin to discard Symbols in attempt to get past the point of error * to a point where we can continue parsing. After each Symbol, we attempt * to "parse ahead" though the buffered lookahead Symbols. The "parse ahead" * process simulates that actual parse, but does not modify the real * parser's configuration, nor execute any actions. If we can parse all * the stored Symbols without error, then the recovery is considered a * success. Once a successful recovery point is determined, we do an * actual parse over the stored input -- modifying the real parse * configuration and executing all actions. Finally, we return the the * normal parser to continue with the overall parse. * * @param debug should we produce debugging messages as we parse. */ protected boolean error_recovery(boolean debug) throws java.lang.Exception { if (debug) debug_message("# Attempting error recovery"); /* first pop the stack back into a state that can shift on error and do that shift (if that fails, we fail) */ if (!find_recovery_config(debug)) { if (debug) debug_message("# Error recovery fails"); return false; } /* read ahead to create lookahead we can parse multiple times */ read_lookahead(); /* repeatedly try to parse forward until we make it the required dist */ for (;;) { /* try to parse forward, if it makes it, bail out of loop */ if (debug) debug_message("# Trying to parse ahead"); if (try_parse_ahead(debug)) { break; } /* if we are now at EOF, we have failed */ if (lookahead[0].sym == EOF_sym()) { if (debug) debug_message("# Error recovery fails at EOF"); return false; } /* otherwise, we consume another Symbol and try again */ // BUG FIX by Bruce Hutton // Computer Science Department, University of Auckland, // Auckland, New Zealand. // It is the first token that is being consumed, not the one // we were up to parsing if (debug) debug_message("# Consuming Symbol #" + lookahead[ 0 ].sym); restart_lookahead(); } /* we have consumed to a point where we can parse forward */ if (debug) debug_message("# Parse-ahead ok, going back to normal parse"); /* do the real parse (including actions) across the lookahead */ parse_lookahead(debug); /* we have success */ return true; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Determine if we can shift under the special error Symbol out of the * state currently on the top of the (real) parse stack. */ protected boolean shift_under_error() { /* is there a shift under error Symbol */ return get_action(((Symbol)stack.peek()).parse_state, error_sym()) > 0; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Put the (real) parse stack into error recovery configuration by * popping the stack down to a state that can shift on the special * error Symbol, then doing the shift. If no suitable state exists on * the stack we return false * * @param debug should we produce debugging messages as we parse. */ protected boolean find_recovery_config(boolean debug) { Symbol error_token; int act; if (debug) debug_message("# Finding recovery state on stack"); /* Remember the right-position of the top symbol on the stack */ Symbol right = ((Symbol)stack.peek());// TUM 20060327 removed .right Symbol left = right;// TUM 20060327 removed .left /* pop down until we can shift under error Symbol */ while (!shift_under_error()) { /* pop the stack */ if (debug) debug_message("# Pop stack by one, state was # " + ((Symbol)stack.peek()).parse_state); left = ((Symbol)stack.pop()); // TUM 20060327 removed .left tos--; /* if we have hit bottom, we fail */ if (stack.empty()) { if (debug) debug_message("# No recovery state found on stack"); return false; } } /* state on top of the stack can shift under error, find the shift */ act = get_action(((Symbol)stack.peek()).parse_state, error_sym()); if (debug) { debug_message("# Recover state found (#" + ((Symbol)stack.peek()).parse_state + ")"); debug_message("# Shifting on error to state #" + (act-1)); } /* build and shift a special error Symbol */ error_token = getSymbolFactory().newSymbol("ERROR",error_sym(), left, right); error_token.parse_state = act-1; error_token.used_by_parser = true; stack.push(error_token); tos++; return true; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Lookahead Symbols used for attempting error recovery "parse aheads". */ protected Symbol lookahead[]; /** Position in lookahead input buffer used for "parse ahead". */ protected int lookahead_pos; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Read from input to establish our buffer of "parse ahead" lookahead * Symbols. */ protected void read_lookahead() throws java.lang.Exception { /* create the lookahead array */ lookahead = new Symbol[error_sync_size()]; /* fill in the array */ for (int i = 0; i < error_sync_size(); i++) { lookahead[i] = cur_token; cur_token = scan(); } /* start at the beginning */ lookahead_pos = 0; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Return the current lookahead in our error "parse ahead" buffer. */ protected Symbol cur_err_token() { return lookahead[lookahead_pos]; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Advance to next "parse ahead" input Symbol. Return true if we have * input to advance to, false otherwise. */ protected boolean advance_lookahead() { /* advance the input location */ lookahead_pos++; /* return true if we didn't go off the end */ return lookahead_pos < error_sync_size(); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Reset the parse ahead input to one Symbol past where we started error * recovery (this consumes one new Symbol from the real input). */ protected void restart_lookahead() throws java.lang.Exception { /* move all the existing input over */ for (int i = 1; i < error_sync_size(); i++) lookahead[i-1] = lookahead[i]; /* read a new Symbol into the last spot */ // BUG Fix by Bruce Hutton // Computer Science Department, University of Auckland, // Auckland, New Zealand. [applied 5-sep-1999 by csa] // The following two lines were out of order!! lookahead[error_sync_size()-1] = cur_token; cur_token = scan(); /* reset our internal position marker */ lookahead_pos = 0; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Do a simulated parse forward (a "parse ahead") from the current * stack configuration using stored lookahead input and a virtual parse * stack. Return true if we make it all the way through the stored * lookahead input without error. This basically simulates the action of * parse() using only our saved "parse ahead" input, and not executing any * actions. * * @param debug should we produce debugging messages as we parse. */ protected boolean try_parse_ahead(boolean debug) throws java.lang.Exception { int act; short lhs, rhs_size; /* create a virtual stack from the real parse stack */ virtual_parse_stack vstack = new virtual_parse_stack(stack); /* parse until we fail or get past the lookahead input */ for (;;) { /* look up the action from the current state (on top of stack) */ act = get_action(vstack.top(), cur_err_token().sym); /* if its an error, we fail */ if (act == 0) return false; /* > 0 encodes a shift */ if (act > 0) { /* push the new state on the stack */ vstack.push(act-1); if (debug) debug_message("# Parse-ahead shifts Symbol #" + cur_err_token().sym + " into state #" + (act-1)); /* advance simulated input, if we run off the end, we are done */ if (!advance_lookahead()) return true; } /* < 0 encodes a reduce */ else { /* if this is a reduce with the start production we are done */ if ((-act)-1 == start_production()) { if (debug) debug_message("# Parse-ahead accepts"); return true; } /* get the lhs Symbol and the rhs size */ lhs = production_tab[(-act)-1][0]; rhs_size = production_tab[(-act)-1][1]; /* pop handle off the stack */ for (int i = 0; i < rhs_size; i++) vstack.pop(); if (debug) debug_message("# Parse-ahead reduces: handle size = " + rhs_size + " lhs = #" + lhs + " from state #" + vstack.top()); /* look up goto and push it onto the stack */ vstack.push(get_reduce(vstack.top(), lhs)); if (debug) debug_message("# Goto state #" + vstack.top()); } } } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Parse forward using stored lookahead Symbols. In this case we have * already verified that parsing will make it through the stored lookahead * Symbols and we are now getting back to the point at which we can hand * control back to the normal parser. Consequently, this version of the * parser performs all actions and modifies the real parse configuration. * This returns once we have consumed all the stored input or we accept. * * @param debug should we produce debugging messages as we parse. */ protected void parse_lookahead(boolean debug) throws java.lang.Exception { /* the current action code */ int act; /* the Symbol/stack element returned by a reduce */ Symbol lhs_sym = null; /* information about production being reduced with */ short handle_size, lhs_sym_num; /* restart the saved input at the beginning */ lookahead_pos = 0; if (debug) { debug_message("# Reparsing saved input with actions"); debug_message("# Current Symbol is #" + cur_err_token().sym); debug_message("# Current state is #" + ((Symbol)stack.peek()).parse_state); } /* continue until we accept or have read all lookahead input */ while(!_done_parsing) { /* current state is always on the top of the stack */ /* look up action out of the current state with the current input */ act = get_action(((Symbol)stack.peek()).parse_state, cur_err_token().sym); /* decode the action -- > 0 encodes shift */ if (act > 0) { /* shift to the encoded state by pushing it on the stack */ cur_err_token().parse_state = act-1; cur_err_token().used_by_parser = true; if (debug) debug_shift(cur_err_token()); stack.push(cur_err_token()); tos++; /* advance to the next Symbol, if there is none, we are done */ if (!advance_lookahead()) { if (debug) debug_message("# Completed reparse"); /* scan next Symbol so we can continue parse */ // BUGFIX by Chris Harris : // correct a one-off error by commenting out // this next line. /*cur_token = scan();*/ /* go back to normal parser */ return; } if (debug) debug_message("# Current Symbol is #" + cur_err_token().sym); } /* if its less than zero, then it encodes a reduce action */ else if (act < 0) { /* perform the action for the reduce */ lhs_sym = do_action((-act)-1, this, stack, tos); /* look up information about the production */ lhs_sym_num = production_tab[(-act)-1][0]; handle_size = production_tab[(-act)-1][1]; if (debug) debug_reduce((-act)-1, lhs_sym_num, handle_size); /* pop the handle off the stack */ for (int i = 0; i < handle_size; i++) { stack.pop(); tos--; } /* look up the state to go to from the one popped back to */ act = get_reduce(((Symbol)stack.peek()).parse_state, lhs_sym_num); /* shift to that state */ lhs_sym.parse_state = act; lhs_sym.used_by_parser = true; stack.push(lhs_sym); tos++; if (debug) debug_message("# Goto state #" + act); } /* finally if the entry is zero, we have an error (shouldn't happen here, but...)*/ else if (act == 0) { report_fatal_error("Syntax error", lhs_sym); return; } } } /*-----------------------------------------------------------*/ /** Utility function: unpacks parse tables from strings */ protected static short[][] unpackFromStrings(String[] sa) { // Concatanate initialization strings. StringBuffer sb = new StringBuffer(sa[0]); for (int i=1; i * * I addition to construction and manipulation operations, productions provide * methods for factoring out actions (see remove_embedded_actions()), for * computing the nullability of the production (i.e., can it derive the empty * string, see check_nullable()), and operations for computing its first * set (i.e., the set of terminals that could appear at the beginning of some * string derived from the production, see check_first_set()). * * @see java_cup.production_part * @see java_cup.symbol_part * @see java_cup.action_part * @version last updated: 7/3/96 * @author Frank Flannery */ public class production { /*-----------------------------------------------------------*/ /*--- Constructor(s) ----------------------------------------*/ /*-----------------------------------------------------------*/ /** Full constructor. This constructor accepts a LHS non terminal, * an array of RHS parts (including terminals, non terminals, and * actions), and a string for a final reduce action. It does several * manipulations in the process of creating a production object. * After some validity checking it translates labels that appear in * actions into code for accessing objects on the runtime parse stack. * It them merges adjacent actions if they appear and moves any trailing * action into the final reduce actions string. Next it removes any * embedded actions by factoring them out with new action productions. * Finally it assigns a unique index to the production.

* * Factoring out of actions is accomplished by creating new "hidden" * non terminals. For example if the production was originally:

   *    A ::= B {action} C D
   *  
* then it is factored into two productions:
   *    A ::= B X C D
   *    X ::= {action}
   *  
* (where X is a unique new non terminal). This has the effect of placing * all actions at the end where they can be handled as part of a reduce by * the parser. */ public production( non_terminal lhs_sym, production_part rhs_parts[], int rhs_l, String action_str) throws internal_error { int i; action_part tail_action; String declare_str; int rightlen = rhs_l; /* remember the length */ if (rhs_l >= 0) _rhs_length = rhs_l; else if (rhs_parts != null) _rhs_length = rhs_parts.length; else _rhs_length = 0; /* make sure we have a valid left-hand-side */ if (lhs_sym == null) throw new internal_error( "Attempt to construct a production with a null LHS"); /* I'm not translating labels anymore, I'm adding code to declare labels as valid variables. This way, the users code string is untouched 6/96 frankf */ /* check if the last part of the right hand side is an action. If it is, it won't be on the stack, so we don't want to count it in the rightlen. Then when we search down the stack for a Symbol, we don't try to search past action */ if (rhs_l > 0) { if (rhs_parts[rhs_l - 1].is_action()) { rightlen = rhs_l - 1; } else { rightlen = rhs_l; } } /* get the generated declaration code for the necessary labels. */ declare_str = declare_labels( rhs_parts, rightlen, action_str); if (action_str == null) action_str = declare_str; else action_str = declare_str + action_str; /* count use of lhs */ lhs_sym.note_use(); /* create the part for left-hand-side */ _lhs = new symbol_part(lhs_sym); /* merge adjacent actions (if any) */ _rhs_length = merge_adjacent_actions(rhs_parts, _rhs_length); /* strip off any trailing action */ tail_action = strip_trailing_action(rhs_parts, _rhs_length); if (tail_action != null) _rhs_length--; /* Why does this run through the right hand side happen over and over? here a quick combination of two prior runs plus one I wanted of my own frankf 6/25/96 */ /* allocate and copy over the right-hand-side */ /* count use of each rhs symbol */ _rhs = new production_part[_rhs_length]; for (i=0; i<_rhs_length; i++) { _rhs[i] = rhs_parts[i]; if (!_rhs[i].is_action()) { ((symbol_part)_rhs[i]).the_symbol().note_use(); if (((symbol_part)_rhs[i]).the_symbol() instanceof terminal) { _rhs_prec = ((terminal)((symbol_part)_rhs[i]).the_symbol()).precedence_num(); _rhs_assoc = ((terminal)((symbol_part)_rhs[i]).the_symbol()).precedence_side(); } } } /*now action string is really declaration string, so put it in front! 6/14/96 frankf */ if (action_str == null) action_str = ""; if (tail_action != null && tail_action.code_string() != null) action_str = action_str + "\t\t" + tail_action.code_string(); /* stash the action */ _action = new action_part(action_str); /* rewrite production to remove any embedded actions */ remove_embedded_actions(); /* assign an index */ _index = next_index++; /* put us in the global collection of productions */ _all.put(new Integer(_index),this); /* put us in the production list of the lhs non terminal */ lhs_sym.add_production(this); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Constructor with no action string. */ public production( non_terminal lhs_sym, production_part rhs_parts[], int rhs_l) throws internal_error { this(lhs_sym,rhs_parts,rhs_l,null); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /* Constructor with precedence and associativity of production contextually define */ public production( non_terminal lhs_sym, production_part rhs_parts[], int rhs_l, String action_str, int prec_num, int prec_side) throws internal_error { this(lhs_sym,rhs_parts,rhs_l,action_str); /* set the precedence */ set_precedence_num(prec_num); set_precedence_side(prec_side); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /* Constructor w/ no action string and contextual precedence defined */ public production( non_terminal lhs_sym, production_part rhs_parts[], int rhs_l, int prec_num, int prec_side) throws internal_error { this(lhs_sym,rhs_parts,rhs_l,null); /* set the precedence */ set_precedence_num(prec_num); set_precedence_side(prec_side); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /*-----------------------------------------------------------*/ /*--- (Access to) Static (Class) Variables ------------------*/ /*-----------------------------------------------------------*/ /** Table of all productions. Elements are stored using their index as * the key. */ protected static Hashtable _all = new Hashtable(); /** Access to all productions. */ public static Enumeration all() {return _all.elements();} /** Lookup a production by index. */ public static production find(int indx) { return (production) _all.get(new Integer(indx)); } //Hm Added clear to clear all static fields public static void clear() { _all.clear(); next_index=0; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Total number of productions. */ public static int number() {return _all.size();} /** Static counter for assigning unique index numbers. */ protected static int next_index; /*-----------------------------------------------------------*/ /*--- (Access to) Instance Variables ------------------------*/ /*-----------------------------------------------------------*/ /** The left hand side non-terminal. */ protected symbol_part _lhs; /** The left hand side non-terminal. */ public symbol_part lhs() {return _lhs;} /** The precedence of the rule */ protected int _rhs_prec = -1; protected int _rhs_assoc = -1; /** Access to the precedence of the rule */ public int precedence_num() { return _rhs_prec; } public int precedence_side() { return _rhs_assoc; } /** Setting the precedence of a rule */ public void set_precedence_num(int prec_num) { _rhs_prec = prec_num; } public void set_precedence_side(int prec_side) { _rhs_assoc = prec_side; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** A collection of parts for the right hand side. */ protected production_part _rhs[]; /** Access to the collection of parts for the right hand side. */ public production_part rhs(int indx) throws internal_error { if (indx >= 0 && indx < _rhs_length) return _rhs[indx]; else throw new internal_error( "Index out of range for right hand side of production"); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** How much of the right hand side array we are presently using. */ protected int _rhs_length; /** How much of the right hand side array we are presently using. */ public int rhs_length() {return _rhs_length;} /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** An action_part containing code for the action to be performed when we * reduce with this production. */ protected action_part _action; /** An action_part containing code for the action to be performed when we * reduce with this production. */ public action_part action() {return _action;} /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Index number of the production. */ protected int _index; /** Index number of the production. */ public int index() {return _index;} /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Count of number of reductions using this production. */ protected int _num_reductions = 0; /** Count of number of reductions using this production. */ public int num_reductions() {return _num_reductions;} /** Increment the count of reductions with this non-terminal */ public void note_reduction_use() {_num_reductions++;} /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Is the nullability of the production known or unknown? */ protected boolean _nullable_known = false; /** Is the nullability of the production known or unknown? */ public boolean nullable_known() {return _nullable_known;} /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Nullability of the production (can it derive the empty string). */ protected boolean _nullable = false; /** Nullability of the production (can it derive the empty string). */ public boolean nullable() {return _nullable;} /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** First set of the production. This is the set of terminals that * could appear at the front of some string derived from this production. */ protected terminal_set _first_set = new terminal_set(); /** First set of the production. This is the set of terminals that * could appear at the front of some string derived from this production. */ public terminal_set first_set() {return _first_set;} /*-----------------------------------------------------------*/ /*--- Static Methods ----------------------------------------*/ /*-----------------------------------------------------------*/ /** Determine if a given character can be a label id starter. * @param c the character in question. */ protected static boolean is_id_start(char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_'); //later need to handle non-8-bit chars here } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Determine if a character can be in a label id. * @param c the character in question. */ protected static boolean is_id_char(char c) { return is_id_start(c) || (c >= '0' && c <= '9'); } /*-----------------------------------------------------------*/ /*--- General Methods ---------------------------------------*/ /*-----------------------------------------------------------*/ /** Return label declaration code * @param labelname the label name * @param stack_type the stack type of label? * @author frankf */ protected String make_declaration( String labelname, String stack_type, int offset) { String ret; /* Put in the left/right value labels */ if (emit.lr_values()) ret = "\t\tint " + labelname + "left = ((java_cup.runtime.Symbol)" + emit.pre("stack") + // TUM 20050917 ((offset==0)?".peek()":(".elementAt(" + emit.pre("top") + "-" + offset + ")"))+ ").left;\n" + "\t\tint " + labelname + "right = ((java_cup.runtime.Symbol)" + emit.pre("stack") + // TUM 20050917 ((offset==0)?".peek()":(".elementAt(" + emit.pre("top") + "-" + offset + ")"))+ ").right;\n"; else ret = ""; /* otherwise, just declare label. */ return ret + "\t\t" + stack_type + " " + labelname + " = (" + stack_type + ")((" + "java_cup.runtime.Symbol) " + emit.pre("stack") + // TUM 20050917 ((offset==0)?".peek()":(".elementAt(" + emit.pre("top") + "-" + offset + ")"))+ ").value;\n"; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Declare label names as valid variables within the action string * @param rhs array of RHS parts. * @param rhs_len how much of rhs to consider valid. * @param final_action the final action string of the production. * @param lhs_type the object type associated with the LHS symbol. */ protected String declare_labels( production_part rhs[], int rhs_len, String final_action) { String declaration = ""; symbol_part part; action_part act_part; int pos; /* walk down the parts and extract the labels */ for (pos = 0; pos < rhs_len; pos++) { if (!rhs[pos].is_action()) { part = (symbol_part)rhs[pos]; /* if it has a label, make declaration! */ if (part.label() != null) { declaration = declaration + make_declaration(part.label(), part.the_symbol().stack_type(), rhs_len-pos-1); } } } return declaration; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Helper routine to merge adjacent actions in a set of RHS parts * @param rhs_parts array of RHS parts. * @param len amount of that array that is valid. * @return remaining valid length. */ protected int merge_adjacent_actions(production_part rhs_parts[], int len) { int from_loc, to_loc, merge_cnt; /* bail out early if we have no work to do */ if (rhs_parts == null || len == 0) return 0; merge_cnt = 0; to_loc = -1; for (from_loc=0; from_loc * A ::= B {action1} C {action2} D * * then it will be factored into:
   *    A ::= B NT$1 C NT$2 D
   *    NT$1 ::= {action1}
   *    NT$2 ::= {action2}
   *  
* where NT$1 and NT$2 are new system created non terminals. */ /* the declarations added to the parent production are also passed along, as they should be perfectly valid in this code string, since it was originally a code string in the parent, not on its own. frank 6/20/96 */ protected void remove_embedded_actions( ) throws internal_error { non_terminal new_nt; production new_prod; String declare_str; int lastLocation = -1; /* walk over the production and process each action */ for (int act_loc = 0; act_loc < rhs_length(); act_loc++) if (rhs(act_loc).is_action()) { declare_str = declare_labels( _rhs, act_loc, ""); /* create a new non terminal for the action production */ new_nt = non_terminal.create_new(null, lhs().the_symbol().stack_type()); // TUM 20060608 embedded actions patch new_nt.is_embedded_action = true; /* 24-Mar-1998, CSA */ /* create a new production with just the action */ new_prod = new action_production(this, new_nt, null, 0, declare_str + ((action_part)rhs(act_loc)).code_string(), (lastLocation==-1)?-1:(act_loc-lastLocation)); /* replace the action with the generated non terminal */ _rhs[act_loc] = new symbol_part(new_nt); lastLocation = act_loc; } } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Check to see if the production (now) appears to be nullable. * A production is nullable if its RHS could derive the empty string. * This results when the RHS is empty or contains only non terminals * which themselves are nullable. */ public boolean check_nullable() throws internal_error { production_part part; symbol sym; int pos; /* if we already know bail out early */ if (nullable_known()) return nullable(); /* if we have a zero size RHS we are directly nullable */ if (rhs_length() == 0) { /* stash and return the result */ return set_nullable(true); } /* otherwise we need to test all of our parts */ for (pos=0; pos *
  • 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 java_cup.runtime.Scanner in the parser * (for compatibility with old runtimes) *
    -version *
    print version information for JavaCUP and halt. *
    * * @version last updated: 7/3/96 * @author Frank Flannery */ public class Main { /*-----------------------------------------------------------*/ /*--- Constructor(s) ----------------------------------------*/ /*-----------------------------------------------------------*/ /** Only constructor is private, so we do not allocate any instances of this class. */ private Main() { } /*-------------------------*/ /* Options set by the user */ /*-------------------------*/ /** User option -- do we print progress messages. */ protected static boolean print_progress = false; /** User option -- do we produce a dump of the state machine */ protected static boolean opt_dump_states = false; /** User option -- do we produce a dump of the parse tables */ protected static boolean opt_dump_tables = false; /** User option -- do we produce a dump of the grammar */ protected static boolean opt_dump_grammar = false; /** User option -- do we show timing information as a part of the summary */ protected static boolean opt_show_timing = false; /** User option -- do we run produce extra debugging messages */ protected static boolean opt_do_debug = false; /** User option -- do we compact tables by making most common reduce the default action */ protected static boolean opt_compact_red = false; /** User option -- should we include non terminal symbol numbers in the symbol constant class. */ protected static boolean include_non_terms = false; /** User option -- do not print a summary. */ protected static boolean no_summary = false; /** User option -- number of conflicts to expect */ protected static int expect_conflicts = 0; /* frankf added this 6/18/96 */ /** User option -- should generator generate code for left/right values? */ protected static boolean lr_values = true; /** User option -- should symbols be put in a class or an interface? [CSA]*/ protected static boolean sym_interface = false; /** User option -- should generator suppress references to * java_cup.runtime.Scanner for compatibility with old runtimes? */ protected static boolean suppress_scanner = false; /*----------------------------------------------------------------------*/ /* Timing data (not all of these time intervals are mutually exclusive) */ /*----------------------------------------------------------------------*/ /** Timing data -- when did we start */ protected static long start_time = 0; /** Timing data -- when did we end preliminaries */ protected static long prelim_end = 0; /** Timing data -- when did we end parsing */ protected static long parse_end = 0; /** Timing data -- when did we end checking */ protected static long check_end = 0; /** Timing data -- when did we end dumping */ protected static long dump_end = 0; /** Timing data -- when did we end state and table building */ protected static long build_end = 0; /** Timing data -- when did we end nullability calculation */ protected static long nullability_end = 0; /** Timing data -- when did we end first set calculation */ protected static long first_end = 0; /** Timing data -- when did we end state machine construction */ protected static long machine_end = 0; /** Timing data -- when did we end table construction */ protected static long table_end = 0; /** Timing data -- when did we end checking for non-reduced productions */ protected static long reduce_check_end = 0; /** Timing data -- when did we finish emitting code */ protected static long emit_end = 0; /** Timing data -- when were we completely done */ protected static long final_time = 0; /* Additional timing information is also collected in emit */ /*-----------------------------------------------------------*/ /*--- 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 internal_error, java.io.IOException, java.lang.Exception { boolean did_output = false; start_time = System.currentTimeMillis(); /** clean all static members, that contain remaining stuff from earlier calls */ terminal.clear(); production.clear(); action_production.clear(); emit.clear(); non_terminal.clear(); parse_reduce_row.clear(); parse_action_row.clear(); lalr_state.clear(); /* process user options and arguments */ parse_args(argv); /* frankf 6/18/96 hackish, yes, but works */ emit.set_lr_values(lr_values); /* open output files */ if (print_progress) System.err.println("Opening files..."); /* use a buffered version of standard input */ input_file = new BufferedInputStream(System.in); prelim_end = System.currentTimeMillis(); /* parse spec into internal data structures */ if (print_progress) System.err.println("Parsing specification from standard input..."); parse_grammar_spec(); 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(); check_end = System.currentTimeMillis(); /* build the state machine and parse tables */ if (print_progress) System.err.println("Building parse tables..."); build_parser(); 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(); did_output = true; } } /* fix up the times to make the summary easier */ emit_end = System.currentTimeMillis(); /* do requested dumps */ if (opt_dump_grammar) dump_grammar(); if (opt_dump_states) dump_machine(); if (opt_dump_tables) dump_tables(); dump_end = System.currentTimeMillis(); /* close input/output files */ if (print_progress) System.err.println("Closing files..."); close_files(); /* produce a summary if desired */ if (!no_summary) emit_summary(did_output); /* If there were errors during the run, * exit with non-zero status (makefile-friendliness). --CSA */ if (ErrorManager.getManager().getErrorCount() != 0) System.exit(100); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Print a "usage message" that described possible command line options, * then exit. * @param message a specific error message to preface the usage message by. */ protected static void usage(String message) { System.err.println(); System.err.println(message); 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" + " -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 java_cup.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); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Parse command line options and arguments to set various user-option * flags and variables. * @param argv the command line arguments to be parsed. */ protected static 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")) usage("-package must have a name argument"); /* record the name */ emit.package_name = argv[i]; } else if (argv[i].equals("-destdir")) { /* must have an arg */ if (++i >= len || argv[i].startsWith("-") || argv[i].endsWith(".cup")) usage("-destdir must have a name argument"); /* record the name */ Main.dest_dir = new java.io.File(argv[i]); } else if (argv[i].equals("-parser")) { /* must have an arg */ if (++i >= len || argv[i].startsWith("-") || argv[i].endsWith(".cup")) usage("-parser must have a name argument"); /* record the name */ emit.parser_class_name = argv[i]; } else if (argv[i].equals("-symbols")) { /* must have an arg */ if (++i >= len || argv[i].startsWith("-") || argv[i].endsWith(".cup")) usage("-symbols must have a name argument"); /* record the name */ emit.symbol_const_class_name = argv[i]; } else if (argv[i].equals("-nonterms")) { include_non_terms = true; } else if (argv[i].equals("-expect")) { /* must have an arg */ if (++i >= len || argv[i].startsWith("-") || argv[i].endsWith(".cup")) usage("-expect must have a name argument"); /* record the number */ try { expect_conflicts = Integer.parseInt(argv[i]); } catch (NumberFormatException e) { usage("-expect must be followed by a decimal integer"); } } else if (argv[i].equals("-compact_red")) opt_compact_red = true; else if (argv[i].equals("-nosummary")) no_summary = true; else if (argv[i].equals("-nowarn")) emit.nowarn = true; else if (argv[i].equals("-dump_states")) opt_dump_states = true; else if (argv[i].equals("-dump_tables")) opt_dump_tables = true; else if (argv[i].equals("-progress")) print_progress = true; else if (argv[i].equals("-dump_grammar")) opt_dump_grammar = true; else if (argv[i].equals("-dump")) opt_dump_states = opt_dump_tables = opt_dump_grammar = true; else if (argv[i].equals("-time")) opt_show_timing = true; else if (argv[i].equals("-debug")) opt_do_debug = true; /* frankf 6/18/96 */ else if (argv[i].equals("-nopositions")) lr_values = false; /* CSA 12/21/97 */ else if (argv[i].equals("-interface")) sym_interface = true; /* CSA 23-Jul-1999 */ else if (argv[i].equals("-noscanner")) suppress_scanner = true; /* CSA 23-Jul-1999 */ else if (argv[i].equals("-version")) { System.out.println(version.title_str); System.exit(1); } /* TUM changes; suggested by Henning Niss 20050628*/ else if (argv[i].equals("-typearg")){ if (++i >= len || argv[i].startsWith("-") || argv[i].endsWith(".cup")) usage("-symbols must have a name argument"); /* record the typearg */ emit.class_type_argument = argv[i]; } /* CSA 24-Jul-1999; suggestion by Jean Vaucher */ else if (!argv[i].startsWith("-") && i==len-1) { /* use input from file. */ try { System.setIn(new FileInputStream(argv[i])); } catch (java.io.FileNotFoundException e) { usage("Unable to open \"" + argv[i] +"\" for input"); } } else { usage("Unrecognized option \"" + argv[i] + "\""); } } } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /*-------*/ /* Files */ /*-------*/ /** Input file. This is a buffered version of System.in. */ protected static BufferedInputStream input_file; /** Output file for the parser class. */ protected static PrintWriter parser_class_file; /** Output file for the symbol constant class. */ protected static PrintWriter symbol_class_file; /** Output directory. */ protected static File dest_dir = null; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Open various files used by the system. */ protected static void open_files() { File fil; String out_name; /* 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); } /* 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); } } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Close various files used by the system. */ protected static void close_files() throws java.io.IOException { if (input_file != null) input_file.close(); 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 static 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. */ protected static void parse_grammar_spec() throws java.lang.Exception { parser parser_obj; /* create a parser and parse with it */ ComplexSymbolFactory csf = new ComplexSymbolFactory(); parser_obj = new parser(new Lexer(csf),csf); try { if (opt_do_debug) parser_obj.debug_parse(); else parser_obj.parse(); } catch (Exception e) { /* something threw an exception. catch it and emit a message so we have a line number to work with, then re-throw it */ ErrorManager.getManager().emit_error("Internal error: Unexpected exception"); throw e; } } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Check for unused symbols. Unreduced productions get checked when * tables are created. */ protected static void check_unused() { terminal term; non_terminal nt; /* check for unused terminals */ for (Enumeration t = terminal.all(); t.hasMoreElements(); ) { term = (terminal)t.nextElement(); /* 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"); } } } /* check for unused non terminals */ for (Enumeration n = non_terminal.all(); n.hasMoreElements(); ) { nt = (non_terminal)n.nextElement(); /* is this one unused */ if (nt.use_count() == 0) { /* count and warn if we are doing warnings */ emit.unused_term++; if (!emit.nowarn) { ErrorManager.getManager().emit_warning("Non terminal \"" + nt.name() + "\" was declared but never used"); } } } } /* . . . . . . . . . . . . . . . . . . . . . . . . .*/ /* . . Internal Results of Generating the Parser . .*/ /* . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Start state in the overall state machine. */ protected static lalr_state start_state; /** Resulting parse action table. */ protected static parse_action_table action_table; /** Resulting reduce-goto table. */ protected static parse_reduce_table reduce_table; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** 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. *
    */ protected static void build_parser() throws internal_error { /* compute nullability of all non terminals */ if (opt_do_debug || print_progress) System.err.println(" Computing non-terminal nullability..."); non_terminal.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..."); non_terminal.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..."); start_state = lalr_state.build_machine(emit.start_production); 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..."); action_table = new parse_action_table(); reduce_table = new parse_reduce_table(); for (Enumeration st = lalr_state.all(); st.hasMoreElements(); ) { lalr_state lst = (lalr_state)st.nextElement(); lst.build_table_entries( action_table, reduce_table); } 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..."); action_table.check_reductions(); reduce_check_end = System.currentTimeMillis(); /* if we have more conflicts than we expected issue a message and die */ if (emit.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. } } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Call the emit routines necessary to write out the generated parser. */ protected static void emit_parser() throws internal_error { emit.symbols(symbol_class_file, include_non_terms, sym_interface); emit.parser(parser_class_file, action_table, reduce_table, start_state.index(), emit.start_production, opt_compact_red, suppress_scanner); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Helper routine to optionally return a plural or non-plural ending. * @param val the numerical value determining plurality. */ protected static 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. */ protected static void emit_summary(boolean output_produced) { final_time = System.currentTimeMillis(); if (no_summary) return; 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(" " + terminal.number() + " terminal" + plural(terminal.number()) + ", "); System.err.print(non_terminal.number() + " non-terminal" + plural(non_terminal.number()) + ", and "); System.err.println(production.number() + " production" + plural(production.number()) + " declared, "); System.err.println(" producing " + lalr_state.number() + " unique parse states."); /* 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_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(" " + emit.num_conflicts + " conflict" + plural(emit.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. */ protected static 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). */ protected static String timestr(long time_val, long total_time) { boolean neg; long ms = 0; long sec = 0; long percent10; String pad; /* work with positives only */ neg = time_val < 0; if (neg) time_val = -time_val; /* pull out seconds and ms */ ms = time_val % 1000; sec = time_val / 1000; /* construct a pad to blank fill seconds out to 4 places */ if (sec < 10) pad = " "; else if (sec < 100) pad = " "; else if (sec < 1000) pad = " "; else pad = ""; /* calculate 10 times the percentage of total */ percent10 = (time_val*1000)/total_time; /* build and return the output string */ return (neg ? "-" : "") + pad + sec + "." + ((ms%1000)/100) + ((ms%100)/10) + (ms%10) + "sec" + " (" + percent10/10 + "." + percent10%10 + "%)"; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Produce a human readable dump of the grammar. */ public static void dump_grammar() throws internal_error { System.err.println("===== Terminals ====="); for (int tidx=0, cnt=0; tidx < terminal.number(); tidx++, cnt++) { System.err.print("["+tidx+"]"+terminal.find(tidx).name()+" "); if ((cnt+1) % 5 == 0) System.err.println(); } System.err.println(); System.err.println(); System.err.println("===== Non terminals ====="); for (int nidx=0, cnt=0; nidx < non_terminal.number(); nidx++, cnt++) { System.err.print("["+nidx+"]"+non_terminal.find(nidx).name()+" "); if ((cnt+1) % 5 == 0) System.err.println(); } System.err.println(); System.err.println(); System.err.println("===== Productions ====="); for (int pidx=0; pidx < production.number(); pidx++) { production prod = production.find(pidx); System.err.print("["+pidx+"] "+prod.lhs().the_symbol().name() + " ::= "); for (int i=0; i