2
* STANDARD ML OF NEW JERSEY COPYRIGHT NOTICE, LICENSE AND DISCLAIMER.
4
* Copyright (c) 1989-1998 by Lucent Technologies
6
* Permission to use, copy, modify, and distribute this software and its
7
* documentation for any purpose and without fee is hereby granted, provided
8
* that the above copyright notice appear in all copies and that both the
9
* copyright notice and this permission notice and warranty disclaimer appear
10
* in supporting documentation, and that the name of Lucent Technologies, Bell
11
* Labs or any Lucent entity not be used in advertising or publicity pertaining
12
* to distribution of the software without specific, written prior permission.
14
* Lucent disclaims all warranties with regard to this software, including all
15
* implied warranties of merchantability and fitness. In no event shall Lucent
16
* be liable for any special, indirect or consequential damages or any damages
17
* whatsoever resulting from loss of use, data or profits, whether in an action
18
* of contract, negligence or other tortious action, arising out of or in
19
* connection with the use or performance of this software.
21
* Taken from this URL:
22
* http://www.smlnj.org/license.html
24
* This license is compatible with the GNU GPL (see section "Standard ML of New
25
* Jersey Copyright License"):
26
* http://www.gnu.org/licenses/license-list.html#StandardMLofNJ
30
* Copyright 1996-1999 by Scott Hudson, Frank Flannery, C. Scott Ananian
34
/*================================================================*/
36
JavaCup Specification for the JavaCup Specification Language
37
by Scott Hudson, GVU Center, Georgia Tech, August 1995
38
and Frank Flannery, Department of Computer Science, Princeton Univ,
40
Bug Fixes: C. Scott Ananian, Dept of Electrical Engineering, Princeton
41
University, October 1996. [later Massachusetts Institute of Technology]
44
This JavaCup specification is used to implement JavaCup itself.
45
It specifies the parser for the JavaCup specification language.
46
(It also serves as a reasonable example of what a typical JavaCup
49
The specification has the following parts:
50
Package and import declarations
51
These serve the same purpose as in a normal Java source file
52
(and will appear in the generated code for the parser). In this
53
case we are part of the java_cup package and we import both the
54
java_cup runtime system and Hashtable from the standard Java
58
This section provides code that is included with the class encapsulating
59
the various pieces of user code embedded in the grammar (i.e., the
60
semantic actions). This provides a series of helper routines and
61
data structures that the semantic actions use.
64
This section provides code included in the parser class itself. In
65
this case we override the default error reporting routines.
67
Init with and scan with
68
These sections provide small bits of code that initialize, then
69
indicate how to invoke the scanner.
72
These sections declare all the terminal and non terminal symbols
73
and the types of objects that they will be represented by at runtime,
74
then indicate the start symbol of the grammar (), and finally provide
75
the grammar itself (with embedded actions).
77
Operation of the parser
78
The parser acts primarily by accumulating data structures representing
79
various parts of the specification. Various small parts (e.g., single
80
code strings) are stored as static variables of the emit class and
81
in a few cases as variables declared in the action code section.
82
Terminals, non terminals, and productions, are maintained as collection
83
accessible via static methods of those classes. In addition, two
84
symbol tables are kept:
85
symbols maintains the name to object mapping for all symbols
86
non_terms maintains a separate mapping containing only the non terms
88
Several intermediate working structures are also declared in the action
89
code section. These include: rhs_parts, rhs_pos, and lhs_nt which
90
build up parts of the current production while it is being parsed.
93
Scott Hudson, GVU Center, Georgia Tech.
94
Frank Flannery, Department of Computer Science, Princeton Univ.
95
C. Scott Ananian, Department of Electrical Engineering, Princeton Univ.
98
v0.9a First released version [SEH] 8/29/95
99
v0.9b Updated for beta language (throws clauses) [SEH] 11/25/95
100
v0.10a Made many improvements/changes. now offers:
102
left/right positions and propagations
103
cleaner label references
104
precedence and associativity for terminals
105
contextual precedence for productions
107
v0.10b Fixed %prec directive so it works like it's supposed to.
109
v0.10g Added support for array types on symbols.
111
v0.10i Broaden set of IDs allowed in multipart_id and label_id so
112
that only java reserved words (and not CUP reserved words like
113
'parser' and 'start') are prohibited. Allow reordering of
114
action code, parser code, init code, and scan with sections,
115
and made closing semicolon optional for these sections.
116
Added 'nonterminal' as a terminal symbol, finally fixing a
117
spelling mistake that's been around since the beginning.
118
For backwards compatibility, you can still misspell the
121
/*================================================================*/
123
package weka.core.parser.java_cup;
124
import weka.core.parser.java_cup.runtime.*;
125
import java.util.Hashtable;
126
import java.util.Stack;
127
/*----------------------------------------------------------------*/
130
/** helper routine to clone a new production part adding a given label */
131
protected production_part add_lab(production_part part, String lab)
132
throws internal_error
134
/* if there is no label, or this is an action, just return the original */
135
if (lab == null || part.is_action()) return part;
137
/* otherwise build a new one with the given label attached */
138
return new symbol_part(((symbol_part)part).the_symbol(),lab);
141
/** max size of right hand side we will support */
142
protected final int MAX_RHS = 200;
144
/** array for accumulating right hand side parts */
145
protected production_part[] rhs_parts = new production_part[MAX_RHS];
147
/** where we are currently in building a right hand side */
148
protected int rhs_pos = 0;
150
/** start a new right hand side */
151
protected void new_rhs() {rhs_pos = 0; }
153
/** add a new right hand side part */
154
protected void add_rhs_part(production_part part) throws java.lang.Exception
156
if (rhs_pos >= MAX_RHS)
157
throw new Exception("Internal Error: Productions limited to " +
158
MAX_RHS + " symbols and actions");
160
rhs_parts[rhs_pos] = part;
164
/** string to build up multiple part names */
165
protected String multipart_name = new String();
166
protected Stack multipart_names = new Stack();
167
/** append a new name segment to the accumulated multipart name */
170
// protected void append_multipart(String name)
174
// /* if we aren't just starting out, put on a dot */
175
// if (multipart_name.length() != 0) dot = ".";
177
// multipart_name = multipart_name.concat(dot + name);
181
/** table of declared symbols -- contains production parts indexed by name */
182
protected Hashtable symbols = new Hashtable();
184
/** table of just non terminals -- contains non_terminals indexed by name */
185
protected Hashtable non_terms = new Hashtable();
187
/** declared start non_terminal */
188
protected non_terminal start_nt = null;
190
/** left hand side non terminal of the current production */
191
protected non_terminal lhs_nt;
193
/** Current precedence number */
196
/** Current precedence side */
197
int _cur_side = assoc.no_prec;
199
/** update the precedences we are declaring */
200
protected void update_precedence(int p) {
204
/** add relevant data to terminals */
205
protected void add_precedence(String term) {
207
System.err.println("Unable to add precedence to nonexistent terminal");
209
symbol_part sp = (symbol_part)symbols.get(term);
211
System.err.println("Could find terminal " + term + " while declaring precedence");
213
java_cup.symbol sym = sp.the_symbol();
214
if (sym instanceof terminal)
215
((terminal)sym).set_precedence(_cur_side, _cur_prec);
216
else System.err.println("Precedence declaration: Can't find terminal " + term);
222
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
226
/* override error routines */
227
protected Lexer lexer;
228
public void report_fatal_error(
233
if (info instanceof Symbol) ErrorManager.getManager().emit_fatal(message+ "\nCan't recover from previous error(s), giving up.",(Symbol)info);
234
else ErrorManager.getManager().emit_fatal(message + "\nCan't recover from previous error(s), giving up.",cur_token);
238
public void report_error(String message, Object info)
240
if (info instanceof Symbol)
241
ErrorManager.getManager().emit_error(message,(Symbol)info);
243
ErrorManager.getManager().emit_error(message,cur_token);
247
/*---------------------------------------------------------------- */
250
ComplexSymbolFactory f = new ComplexSymbolFactory();
252
lexer = new Lexer(f);
254
/*lexer.init(); :};*/
256
return lexer.next_token();
259
/*----------------------------------------------------------------*/
262
PACKAGE, IMPORT, CODE, ACTION, PARSER, TERMINAL, NON, INIT, SCAN, WITH,
263
START, SEMI, COMMA, STAR, DOT, COLON, COLON_COLON_EQUALS, BAR, PRECEDENCE,
264
LEFT, RIGHT, NONASSOC, PERCENT_PREC, LBRACK, RBRACK, NONTERMINAL, GT, LT,
265
QUESTION, SUPER, EXTENDS;
267
terminal String ID, CODE_STRING;
270
spec, package_spec, import_list, action_code_part,
271
code_parts, code_part, opt_semi, non_terminal,
272
parser_code_part, symbol_list, start_spec, production_list,
273
multipart_id, import_spec, import_id, init_code, scan_code, symbol,
274
type_id, term_name_list, non_term_name_list, production, prod_part_list,
275
prod_part, new_term_id, new_non_term_id, rhs_list, rhs, empty,
276
precedence_list, preced, terminal_list, precedence_l, declares_term,
279
non terminal String nt_id, symbol_id, label_id, opt_label, terminal_id,
280
term_id, robust_id, typearglist, typearguement, wildcard;
282
/*----------------------------------------------------------------*/
286
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
290
/* declare "error" as a terminal */
291
symbols.put("error", new symbol_part(terminal.error));
293
/* declare start non terminal */
294
non_terms.put("$START", non_terminal.START_nt);
304
/* error recovery assuming something went wrong before symbols
305
and we have TERMINAL or NON TERMINAL to sync on. if we get
306
an error after that, we recover inside symbol_list or
316
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
322
/* save the package name */
323
emit.package_name = multipart_name;
325
/* reset the accumulated multipart name */
326
multipart_name = new String();
333
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
342
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
348
/* save this import on the imports list */
349
emit.import_list.push(multipart_name);
351
/* reset the accumulated multipart name */
352
multipart_name = new String();
357
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
359
// allow any order; all parts are optional. [CSA, 23-Jul-1999]
360
// (we check in the part action to make sure we don't have 2 of any part)
362
action_code_part | parser_code_part | init_code | scan_code ;
364
| code_parts code_part;
366
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
369
ACTION CODE CODE_STRING:user_code opt_semi
371
if (emit.action_code!=null)
372
ErrorManager.getManager().emit_warning("Redundant action code (skipping)");
373
else /* save the user included code string */
374
emit.action_code = user_code;
378
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
381
PARSER CODE CODE_STRING:user_code opt_semi
383
if (emit.parser_code!=null)
384
ErrorManager.getManager().emit_warning("Redundant parser code (skipping)");
385
else /* save the user included code string */
386
emit.parser_code = user_code;
390
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
393
INIT WITH CODE_STRING:user_code opt_semi
395
if (emit.init_code!=null)
396
ErrorManager.getManager().emit_warning("Redundant init code (skipping)");
397
else /* save the user code */
398
emit.init_code = user_code;
402
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
405
SCAN WITH CODE_STRING:user_code opt_semi
407
if (emit.scan_code!=null)
408
ErrorManager.getManager().emit_warning("Redundant scan code (skipping)");
409
else /* save the user code */
410
emit.scan_code = user_code;
414
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
416
symbol_list ::= symbol_list symbol | symbol;
418
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
435
/* error recovery productions -- sync on semicolon */
440
/* reset the accumulated multipart name */
441
multipart_name = new String();
448
/* reset the accumulated multipart name */
449
multipart_name = new String();
454
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
459
/* reset the accumulated multipart name */
460
multipart_name = new String();
464
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
466
declares_non_term ::=
469
/* reset the accumulated multipart name */
470
multipart_name = new String();
474
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
476
term_name_list ::= term_name_list COMMA new_term_id | new_term_id;
478
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
480
non_term_name_list ::=
488
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
491
precedence_list ::= precedence_l | empty;
493
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
495
precedence_l ::= precedence_l preced | preced;
497
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
502
update_precedence(assoc.left);
508
update_precedence(assoc.right);
514
update_precedence(assoc.nonassoc);
519
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
521
terminal_list ::= terminal_list COMMA terminal_id
526
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
528
terminal_id ::= term_id:sym
534
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
536
term_id ::= symbol_id:sym
538
/* check that the symbol_id is a terminal */
539
if (symbols.get(sym) == null)
541
/* issue a message */
542
ErrorManager.getManager().emit_error("Terminal \"" + sym +
543
"\" has not been declared");
548
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
551
START WITH nt_id:start_name
553
/* verify that the name has been declared as a non terminal */
554
non_terminal nt = (non_terminal)non_terms.get(start_name);
557
ErrorManager.getManager().emit_error( "Start non terminal \"" + start_name +
558
"\" has not been declared");
562
/* remember the non-terminal for later */
565
/* build a special start production */
567
add_rhs_part(add_lab(new symbol_part(start_nt), "start_val"));
568
add_rhs_part(new symbol_part(terminal.EOF));
569
add_rhs_part(new action_part("RESULT = start_val;"));
570
emit.start_production =
571
new production(non_terminal.START_nt, rhs_parts, rhs_pos);
580
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
582
production_list ::= production_list production | production;
584
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
589
/* lookup the lhs nt */
590
lhs_nt = (non_terminal)non_terms.get(lhs_id);
592
/* if it wasn't declared, emit a message */
595
if (ErrorManager.getManager().getErrorCount() == 0)
596
ErrorManager.getManager().emit_warning("LHS non terminal \"" + lhs_id +
597
"\" has not been declared");
600
/* reset the rhs accumulation */
609
{: ErrorManager.getManager().emit_error("Syntax Error"); :}
613
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
615
rhs_list ::= rhs_list BAR rhs | rhs;
617
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
620
prod_part_list PERCENT_PREC term_id:term_name
622
java_cup.symbol sym = null;
625
/* Find the precedence symbol */
626
if (term_name == null) {
627
System.err.println("No terminal for contextual precedence");
630
sym = ((symbol_part)symbols.get(term_name)).the_symbol();
632
/* build the production */
634
if ((sym!=null) && (sym instanceof terminal)) {
635
p = new production(lhs_nt, rhs_parts, rhs_pos,
636
((terminal)sym).precedence_num(),
637
((terminal)sym).precedence_side());
638
((symbol_part)symbols.get(term_name)).the_symbol().note_use();
640
System.err.println("Invalid terminal " + term_name +
641
" for contextual precedence assignment");
642
p = new production(lhs_nt, rhs_parts, rhs_pos);
645
/* if we have no start non-terminal declared and this is
646
the first production, make its lhs nt the start_nt
647
and build a special start production for it. */
648
if (start_nt == null)
652
/* build a special start production */
654
add_rhs_part(add_lab(new symbol_part(start_nt),"start_val"));
655
add_rhs_part(new symbol_part(terminal.EOF));
656
add_rhs_part(new action_part("RESULT = start_val;"));
657
if ((sym!=null) && (sym instanceof terminal)) {
658
emit.start_production =
659
new production(non_terminal.START_nt, rhs_parts,
660
rhs_pos, ((terminal)sym).precedence_num(),
661
((terminal)sym).precedence_side());
663
emit.start_production =
664
new production(non_terminal.START_nt, rhs_parts, rhs_pos);
670
/* reset the rhs accumulation in any case */
678
/* build the production */
679
production p = new production(lhs_nt, rhs_parts, rhs_pos);
681
/* if we have no start non-terminal declared and this is
682
the first production, make its lhs nt the start_nt
683
and build a special start production for it. */
684
if (start_nt == null)
688
/* build a special start production */
690
add_rhs_part(add_lab(new symbol_part(start_nt),"start_val"));
691
add_rhs_part(new symbol_part(terminal.EOF));
692
add_rhs_part(new action_part("RESULT = start_val;"));
693
emit.start_production =
694
new production(non_terminal.START_nt, rhs_parts, rhs_pos);
700
/* reset the rhs accumulation in any case */
705
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
707
prod_part_list ::= prod_part_list prod_part | empty;
709
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
712
symbol_id:symid opt_label:labid
714
/* try to look up the id */
715
production_part symb = (production_part)symbols.get(symid);
717
/* if that fails, symbol is undeclared */
720
if (ErrorManager.getManager().getErrorCount() == 0)
721
ErrorManager.getManager().emit_error("java_cup.runtime.Symbol \"" + symid +
722
"\" has not been declared");
726
/* add a labeled production part */
727
add_rhs_part(add_lab(symb, labid));
733
/* add a new production part */
734
add_rhs_part(new action_part(code_str));
738
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
742
{: RESULT = labid; :}
748
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
751
multipart_id DOT robust_id:another_id
752
{: multipart_name = multipart_name.concat("."+another_id); :}
754
{: multipart_names.push(multipart_name); multipart_name="";:}
755
LT typearglist:types GT
757
((String)multipart_names.pop()).concat("<"+types+">"); :}
760
{: multipart_name = multipart_name.concat(an_id); :}
762
/*. . . . . . . . . . . .TUM CHANGES. . . . . . . . . . . . . . . */
768
| typearglist:list COMMA typearguement:arg
769
{: RESULT = list + "," + arg; :}
774
{: RESULT = multipart_name; multipart_name = new String(); :}
781
{: RESULT = " ? "; :}
782
| QUESTION EXTENDS type_id
783
{: RESULT = " ? extends "+multipart_name; multipart_name = new
785
| QUESTION SUPER type_id
786
{: RESULT = " ? super "+multipart_name; multipart_name = new
790
/*. . . . . . . . . . .END TUM CHANGES. . . . . . . . . . . . . . */
793
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
796
multipart_id DOT STAR
797
{: multipart_name = multipart_name.concat(".*"); :}
802
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
804
type_id ::= multipart_id
805
| type_id LBRACK RBRACK
806
{: multipart_name = multipart_name.concat("[]"); :}
809
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
814
/* see if this terminal has been declared before */
815
if (symbols.get(term_id) != null)
817
/* issue a message */
818
ErrorManager.getManager().emit_error("java_cup.runtime.Symbol \"" + term_id +
819
"\" has already been declared");
823
/* if no type declared, declare one */
824
if (multipart_name.equals("")) {
825
multipart_name = "Object";
827
/* build a production_part and put it in the table */
829
new symbol_part(new terminal(term_id, multipart_name)));
834
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
839
/* see if this non terminal has been declared before */
840
if (symbols.get(non_term_id) != null)
842
/* issue a message */
843
ErrorManager.getManager().emit_error( "java_cup.runtime.Symbol \"" + non_term_id +
844
"\" has already been declared");
848
if (multipart_name.equals("")) {
849
multipart_name ="Object";
851
/* build the non terminal object */
852
non_terminal this_nt =
853
new non_terminal(non_term_id, multipart_name);
855
/* put it in the non_terms table */
856
non_terms.put(non_term_id, this_nt);
858
/* build a production_part and put it in the symbols table */
859
symbols.put(non_term_id, new symbol_part(this_nt));
864
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
868
{: RESULT = the_id; :}
871
ErrorManager.getManager().emit_error("Illegal use of reserved word");
876
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
880
{: RESULT = the_id; :}
883
ErrorManager.getManager().emit_error("Illegal use of reserved word");
888
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
892
{: RESULT = the_id; :}
895
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
897
robust_id ::= /* all ids that aren't reserved words in Java */
898
ID:the_id {: RESULT = the_id; :}
899
/* package is reserved. */
900
/* import is reserved. */
901
| CODE {: RESULT = "code"; :}
902
| ACTION {: RESULT = "action"; :}
903
| PARSER {: RESULT = "parser"; :}
904
| TERMINAL {: RESULT = "terminal"; :}
905
| NON {: RESULT = "non"; :}
906
| NONTERMINAL {: RESULT = "nonterminal"; :}
907
| INIT {: RESULT = "init"; :}
908
| SCAN {: RESULT = "scan"; :}
909
| WITH {: RESULT = "with"; :}
910
| START {: RESULT = "start"; :}
911
| PRECEDENCE {: RESULT = "precedence"; :}
912
| LEFT {: RESULT = "left"; :}
913
| RIGHT {: RESULT = "right"; :}
914
| NONASSOC {: RESULT = "nonassoc"; :}
917
ErrorManager.getManager().emit_error("Illegal use of reserved word");
922
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
924
non_terminal ::= NON TERMINAL | NONTERMINAL;
926
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
928
opt_semi ::= /* nothing */
931
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
933
empty ::= /* nothing */;
935
/*----------------------------------------------------------------*/