KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > antlr > MakeGrammar


1 package antlr;
2
3 /* ANTLR Translator Generator
4  * Project led by Terence Parr at http://www.jGuru.com
5  * Software rights: http://www.antlr.org/RIGHTS.html
6  *
7  * $Id: //depot/code/org.antlr/main/main/antlr/MakeGrammar.java#10 $
8  */

9
10 import antlr.collections.Stack;
11 import antlr.collections.impl.LList;
12 import antlr.collections.impl.Vector;
13
14 public class MakeGrammar extends DefineGrammarSymbols {
15
16     protected Stack blocks = new LList(); // track subrules--Stack<BlockContext>
17
protected RuleRefElement lastRuleRef;
18
19     protected RuleEndElement ruleEnd; // used if not nested
20
protected RuleBlock ruleBlock; // points to block of current rule.
21
protected int nested = 0; // nesting inside a subrule
22
protected boolean grammarError = false;
23
24     ExceptionSpec currentExceptionSpec = null;
25
26     public MakeGrammar(Tool tool_, String JavaDoc[] args_, LLkAnalyzer analyzer_) {
27         super(tool_, args_, analyzer_);
28     }
29
30     /** Abort the processing of a grammar (due to syntax errors) */
31     public void abortGrammar() {
32         String JavaDoc s = "unknown grammar";
33         if (grammar != null) {
34             s = grammar.getClassName();
35         }
36         tool.error("aborting grammar '" + s + "' due to errors");
37         super.abortGrammar();
38     }
39
40     protected void addElementToCurrentAlt(AlternativeElement e) {
41         e.enclosingRuleName = ruleBlock.ruleName;
42         context().addAlternativeElement(e);
43     }
44
45     public void beginAlt(boolean doAutoGen_) {
46         super.beginAlt(doAutoGen_);
47         Alternative alt = new Alternative();
48         alt.setAutoGen(doAutoGen_);
49         context().block.addAlternative(alt);
50     }
51
52     public void beginChildList() {
53         super.beginChildList();
54         context().block.addAlternative(new Alternative());
55     }
56
57     /** Add an exception group to a rule (currently a no-op) */
58     public void beginExceptionGroup() {
59         super.beginExceptionGroup();
60         if (!(context().block instanceof RuleBlock)) {
61             tool.panic("beginExceptionGroup called outside of rule block");
62         }
63     }
64
65     /** Add an exception spec to an exception group or rule block */
66     public void beginExceptionSpec(Token label) {
67         // Hack the label string a bit to remove leading/trailing space.
68
if (label != null) {
69             label.setText(StringUtils.stripFront(StringUtils.stripBack(label.getText(), " \n\r\t"), " \n\r\t"));
70         }
71         super.beginExceptionSpec(label);
72         // Don't check for currentExceptionSpec!=null because syntax errors
73
// may leave it set to something.
74
currentExceptionSpec = new ExceptionSpec(label);
75     }
76
77     public void beginSubRule(Token label, Token start, boolean not) {
78         super.beginSubRule(label, start, not);
79         // we don't know what kind of subrule it is yet.
80
// push a dummy one that will allow us to collect the
81
// alternatives. Later, we'll switch to real object.
82
blocks.push(new BlockContext());
83         context().block = new AlternativeBlock(grammar, start, not);
84         context().altNum = 0; // reset alternative number
85
nested++;
86         // create a final node to which the last elememt of each
87
// alternative will point.
88
context().blockEnd = new BlockEndElement(grammar);
89         // make sure end node points to start of block
90
context().blockEnd.block = context().block;
91         labelElement(context().block, label);
92     }
93
94     public void beginTree(Token tok) throws SemanticException {
95         if (!(grammar instanceof TreeWalkerGrammar)) {
96             tool.error("Trees only allowed in TreeParser", grammar.getFilename(), tok.getLine(), tok.getColumn());
97             throw new SemanticException("Trees only allowed in TreeParser");
98         }
99         super.beginTree(tok);
100         blocks.push(new TreeBlockContext());
101         context().block = new TreeElement(grammar, tok);
102         context().altNum = 0; // reset alternative number
103
}
104
105     public BlockContext context() {
106         if (blocks.height() == 0) {
107             return null;
108         }
109         else {
110             return (BlockContext)blocks.top();
111         }
112     }
113
114     /**Used to build nextToken() for the lexer.
115      * This builds a rule which has every "public" rule in the given Vector of
116      * rules as it's alternate. Each rule ref generates a Token object.
117      * @param g The Grammar that is being processed
118      * @param lexRules A vector of lexer rules that will be used to create an alternate block.
119      * @param rname The name of the resulting rule.
120      */

121     public static RuleBlock createNextTokenRule(Grammar g, Vector lexRules, String JavaDoc rname) {
122         // create actual rule data structure
123
RuleBlock rb = new RuleBlock(g, rname);
124         rb.setDefaultErrorHandler(g.getDefaultErrorHandler());
125         RuleEndElement ruleEnd = new RuleEndElement(g);
126         rb.setEndElement(ruleEnd);
127         ruleEnd.block = rb;
128         // Add an alternative for each element of the rules vector.
129
for (int i = 0; i < lexRules.size(); i++) {
130             RuleSymbol r = (RuleSymbol)lexRules.elementAt(i);
131             if (!r.isDefined()) {
132                 g.antlrTool.error("Lexer rule " + r.id.substring(1) + " is not defined");
133             }
134             else {
135                 if (r.access.equals("public")) {
136                     // create a rule ref to lexer rule
137
// the Token is a RULE_REF not a TOKEN_REF since the
138
// conversion to mRulename has already taken place
139
RuleRefElement rr =
140                         new RuleRefElement(g,
141                                            new CommonToken(ANTLRTokenTypes.RULE_REF, r.getId()),
142                                            GrammarElement.AUTO_GEN_NONE);
143                     //labelElement(rr, new Token("_rettoken"));
144
// rr.setIdAssign("_ttype");
145
rr.setLabel("theRetToken");
146                     rr.enclosingRuleName = "nextToken";
147                     rr.next = ruleEnd;
148                     Alternative alt = new Alternative(rr);
149                     alt.setAutoGen(true); // keep text of elements
150
rb.addAlternative(alt);
151                     // Add a reference to the rule used for the alt
152
r.addReference(rr);
153                 }
154             }
155         }
156
157         rb.setAutoGen(true); // keep text of elements
158
rb.prepareForAnalysis();
159         //System.out.println(rb);
160
return rb;
161     }
162
163     /** Return block as if they had typed: "( rule )?" */
164     private AlternativeBlock createOptionalRuleRef(String JavaDoc rule, Token start) {
165         // Make the subrule
166
AlternativeBlock blk = new AlternativeBlock(grammar, start, false);
167
168         // Make sure rule is defined
169
String JavaDoc mrule = CodeGenerator.encodeLexerRuleName(rule); // can only be a lexer rule!
170
if (!grammar.isDefined(mrule)) {
171             grammar.define(new RuleSymbol(mrule));
172         }
173
174         // Make the rule ref element
175
// RK: fixme probably easier to abuse start token..
176
Token t = new CommonToken(ANTLRTokenTypes.TOKEN_REF, rule);
177         t.setLine(start.getLine());
178         t.setLine(start.getColumn());
179         RuleRefElement rref =
180             new RuleRefElement(grammar, t, GrammarElement.AUTO_GEN_NONE);
181
182         rref.enclosingRuleName = ruleBlock.ruleName;
183
184         // Make the end of block element
185
BlockEndElement end = new BlockEndElement(grammar);
186         end.block = blk; // end block points back to start of blk
187

188         // Make an alternative, putting the rule ref into it
189
Alternative alt = new Alternative(rref);
190         alt.addElement(end); // last element in alt points to end of block
191

192         // Add the alternative to this block
193
blk.addAlternative(alt);
194
195         // create an empty (optional) alt and add to blk
196
Alternative optAlt = new Alternative();
197         optAlt.addElement(end); // points immediately to end of block
198

199         blk.addAlternative(optAlt);
200
201         blk.prepareForAnalysis();
202         return blk;
203     }
204
205     public void defineRuleName(Token r,
206                                String JavaDoc access,
207                                boolean ruleAutoGen,
208                                String JavaDoc docComment)
209         throws SemanticException {
210         // if ( Character.isUpperCase(r.getText().charAt(0)) ) {
211
if (r.type == ANTLRTokenTypes.TOKEN_REF) {
212             if (!(grammar instanceof LexerGrammar)) {
213                 tool.error("Lexical rule " + r.getText() +
214                            " defined outside of lexer",
215                            grammar.getFilename(), r.getLine(), r.getColumn());
216                 r.setText(r.getText().toLowerCase());
217             }
218         }
219         else {
220             if (grammar instanceof LexerGrammar) {
221                 tool.error("Lexical rule names must be upper case, '" + r.getText() +
222                            "' is not",
223                            grammar.getFilename(), r.getLine(), r.getColumn());
224                 r.setText(r.getText().toUpperCase());
225             }
226         }
227
228         super.defineRuleName(r, access, ruleAutoGen, docComment);
229         String JavaDoc id = r.getText();
230         // if ( Character.isUpperCase(id.charAt(0)) ) { // lexer rule?
231
if (r.type == ANTLRTokenTypes.TOKEN_REF) { // lexer rule?
232
id = CodeGenerator.encodeLexerRuleName(id);
233         }
234         RuleSymbol rs = (RuleSymbol)grammar.getSymbol(id);
235         RuleBlock rb = new RuleBlock(grammar, r.getText(), r.getLine(), ruleAutoGen);
236
237         // Lexer rules do not generate default error handling
238
rb.setDefaultErrorHandler(grammar.getDefaultErrorHandler());
239
240         ruleBlock = rb;
241         blocks.push(new BlockContext()); // enter new context
242
context().block = rb;
243         rs.setBlock(rb);
244         ruleEnd = new RuleEndElement(grammar);
245         rb.setEndElement(ruleEnd);
246         nested = 0;
247     }
248
249     public void endAlt() {
250         super.endAlt();
251         if (nested == 0) { // all rule-level alts link to ruleEnd node
252
addElementToCurrentAlt(ruleEnd);
253         }
254         else {
255             addElementToCurrentAlt(context().blockEnd);
256         }
257         context().altNum++;
258     }
259
260     public void endChildList() {
261         super.endChildList();
262         // create a final node to which the last elememt of the single
263
// alternative will point. Done for compatibility with analyzer.
264
// Does NOT point to any block like alternative blocks because the
265
// TreeElement is not a block. This is used only as a placeholder.
266
BlockEndElement be = new BlockEndElement(grammar);
267         be.block = context().block;
268         addElementToCurrentAlt(be);
269     }
270
271     public void endExceptionGroup() {
272         super.endExceptionGroup();
273     }
274
275     public void endExceptionSpec() {
276         super.endExceptionSpec();
277         if (currentExceptionSpec == null) {
278             tool.panic("exception processing internal error -- no active exception spec");
279         }
280         if (context().block instanceof RuleBlock) {
281             // Named rule
282
((RuleBlock)context().block).addExceptionSpec(currentExceptionSpec);
283         }
284         else {
285             // It must be a plain-old alternative block
286
if (context().currentAlt().exceptionSpec != null) {
287                 tool.error("Alternative already has an exception specification", grammar.getFilename(), context().block.getLine(), context().block.getColumn());
288             }
289             else {
290                 context().currentAlt().exceptionSpec = currentExceptionSpec;
291             }
292         }
293         currentExceptionSpec = null;
294     }
295
296     /** Called at the end of processing a grammar */
297     public void endGrammar() {
298         if (grammarError) {
299             abortGrammar();
300         }
301         else {
302             super.endGrammar();
303         }
304     }
305
306     public void endRule(String JavaDoc rule) {
307         super.endRule(rule);
308         BlockContext ctx = (BlockContext)blocks.pop(); // remove scope
309
// record the start of this block in the ending node
310
ruleEnd.block = ctx.block;
311         ruleEnd.block.prepareForAnalysis();
312         //System.out.println(ctx.block);
313
}
314
315     public void endSubRule() {
316         super.endSubRule();
317         nested--;
318         // remove subrule context from scope stack
319
BlockContext ctx = (BlockContext)blocks.pop();
320         AlternativeBlock block = ctx.block;
321
322         // If the subrule is marked with ~, check that it is
323
// a valid candidate for analysis
324
if (
325             block.not &&
326             !(block instanceof SynPredBlock) &&
327             !(block instanceof ZeroOrMoreBlock) &&
328             !(block instanceof OneOrMoreBlock)
329         ) {
330             if (!analyzer.subruleCanBeInverted(block, grammar instanceof LexerGrammar)) {
331                 String JavaDoc newline = System.getProperty("line.separator");
332                 tool.error(
333                     "This subrule cannot be inverted. Only subrules of the form:" + newline +
334                     " (T1|T2|T3...) or" + newline +
335                     " ('c1'|'c2'|'c3'...)" + newline +
336                     "may be inverted (ranges are also allowed).",
337                     grammar.getFilename(),
338                     block.getLine(), block.getColumn()
339                 );
340             }
341         }
342
343         // add the subrule as element if not a syn pred
344
if (block instanceof SynPredBlock) {
345             // record a reference to the recently-recognized syn pred in the
346
// enclosing block.
347
SynPredBlock synpred = (SynPredBlock)block;
348             context().block.hasASynPred = true;
349             context().currentAlt().synPred = synpred;
350             grammar.hasSyntacticPredicate = true;
351             synpred.removeTrackingOfRuleRefs(grammar);
352         }
353         else {
354             addElementToCurrentAlt(block);
355         }
356         ctx.blockEnd.block.prepareForAnalysis();
357     }
358
359     public void endTree() {
360         super.endTree();
361         BlockContext ctx = (BlockContext)blocks.pop();
362         addElementToCurrentAlt(ctx.block); // add new TreeElement to enclosing alt.
363
}
364
365     /** Remember that a major error occured in the grammar */
366     public void hasError() {
367         grammarError = true;
368     }
369
370     private void labelElement(AlternativeElement el, Token label) {
371         if (label != null) {
372             // Does this label already exist?
373
for (int i = 0; i < ruleBlock.labeledElements.size(); i++) {
374                 AlternativeElement altEl = (AlternativeElement)ruleBlock.labeledElements.elementAt(i);
375                 String JavaDoc l = altEl.getLabel();
376                 if (l != null && l.equals(label.getText())) {
377                     tool.error("Label '" + label.getText() + "' has already been defined", grammar.getFilename(), label.getLine(), label.getColumn());
378                     return;
379                 }
380             }
381             // add this node to the list of labeled elements
382
el.setLabel(label.getText());
383             ruleBlock.labeledElements.appendElement(el);
384         }
385     }
386
387     public void noAutoGenSubRule() {
388         context().block.setAutoGen(false);
389     }
390
391     public void oneOrMoreSubRule() {
392         if (context().block.not) {
393             tool.error("'~' cannot be applied to (...)* subrule", grammar.getFilename(), context().block.getLine(), context().block.getColumn());
394         }
395         // create the right kind of object now that we know what that is
396
// and switch the list of alternatives. Adjust the stack of blocks.
397
// copy any init action also.
398
OneOrMoreBlock b = new OneOrMoreBlock(grammar);
399         setBlock(b, context().block);
400         BlockContext old = (BlockContext)blocks.pop(); // remove old scope; we want new type of subrule
401
blocks.push(new BlockContext());
402         context().block = b;
403         context().blockEnd = old.blockEnd;
404         context().blockEnd.block = b;
405     }
406
407     public void optionalSubRule() {
408         if (context().block.not) {
409             tool.error("'~' cannot be applied to (...)? subrule", grammar.getFilename(), context().block.getLine(), context().block.getColumn());
410         }
411         // convert (X)? -> (X|) so that we can ignore optional blocks altogether!
412
// It already thinks that we have a simple subrule, just add option block.
413
beginAlt(false);
414         endAlt();
415     }
416
417     public void refAction(Token action) {
418         super.refAction(action);
419         context().block.hasAnAction = true;
420         addElementToCurrentAlt(new ActionElement(grammar, action));
421     }
422
423     public void setUserExceptions(String JavaDoc thr) {
424         ((RuleBlock)context().block).throwsSpec = thr;
425     }
426
427     // Only called for rule blocks
428
public void refArgAction(Token action) {
429         ((RuleBlock)context().block).argAction = action.getText();
430     }
431
432     public void refCharLiteral(Token lit, Token label, boolean inverted, int autoGenType, boolean lastInRule) {
433         if (!(grammar instanceof LexerGrammar)) {
434             tool.error("Character literal only valid in lexer", grammar.getFilename(), lit.getLine(), lit.getColumn());
435             return;
436         }
437         super.refCharLiteral(lit, label, inverted, autoGenType, lastInRule);
438         CharLiteralElement cl = new CharLiteralElement((LexerGrammar)grammar, lit, inverted, autoGenType);
439
440         // Generate a warning for non-lowercase ASCII when case-insensitive
441
if (
442             !((LexerGrammar)grammar).caseSensitive && cl.getType() < 128 &&
443             Character.toLowerCase((char)cl.getType()) != (char)cl.getType()
444         ) {
445             tool.warning("Character literal must be lowercase when caseSensitive=false", grammar.getFilename(), lit.getLine(), lit.getColumn());
446         }
447
448         addElementToCurrentAlt(cl);
449         labelElement(cl, label);
450
451         // if ignore option is set, must add an optional call to the specified rule.
452
String JavaDoc ignore = ruleBlock.getIgnoreRule();
453         if (!lastInRule && ignore != null) {
454             addElementToCurrentAlt(createOptionalRuleRef(ignore, lit));
455         }
456     }
457
458     public void refCharRange(Token t1, Token t2, Token label, int autoGenType, boolean lastInRule) {
459         if (!(grammar instanceof LexerGrammar)) {
460             tool.error("Character range only valid in lexer", grammar.getFilename(), t1.getLine(), t1.getColumn());
461             return;
462         }
463         int rangeMin = ANTLRLexer.tokenTypeForCharLiteral(t1.getText());
464         int rangeMax = ANTLRLexer.tokenTypeForCharLiteral(t2.getText());
465         if (rangeMax < rangeMin) {
466             tool.error("Malformed range.", grammar.getFilename(), t1.getLine(), t1.getColumn());
467             return;
468         }
469
470         // Generate a warning for non-lowercase ASCII when case-insensitive
471
if (!((LexerGrammar)grammar).caseSensitive) {
472             if (rangeMin < 128 && Character.toLowerCase((char)rangeMin) != (char)rangeMin) {
473                 tool.warning("Character literal must be lowercase when caseSensitive=false", grammar.getFilename(), t1.getLine(), t1.getColumn());
474             }
475             if (rangeMax < 128 && Character.toLowerCase((char)rangeMax) != (char)rangeMax) {
476                 tool.warning("Character literal must be lowercase when caseSensitive=false", grammar.getFilename(), t2.getLine(), t2.getColumn());
477             }
478         }
479
480         super.refCharRange(t1, t2, label, autoGenType, lastInRule);
481         CharRangeElement cr = new CharRangeElement((LexerGrammar)grammar, t1, t2, autoGenType);
482         addElementToCurrentAlt(cr);
483         labelElement(cr, label);
484
485         // if ignore option is set, must add an optional call to the specified rule.
486
String JavaDoc ignore = ruleBlock.getIgnoreRule();
487         if (!lastInRule && ignore != null) {
488             addElementToCurrentAlt(createOptionalRuleRef(ignore, t1));
489         }
490     }
491
492     public void refTokensSpecElementOption(Token tok,
493                                            Token option,
494                                            Token value) {
495         /*
496         System.out.println("setting tokens spec option for "+tok.getText());
497         System.out.println(option.getText()+","+value.getText());
498         */

499         TokenSymbol ts = (TokenSymbol)
500             grammar.tokenManager.getTokenSymbol(tok.getText());
501         if (ts == null) {
502             tool.panic("cannot find " + tok.getText() + "in tokens {...}");
503         }
504         if (option.getText().equals("AST")) {
505             ts.setASTNodeType(value.getText());
506         }
507         else {
508             grammar.antlrTool.error("invalid tokens {...} element option:" +
509                                option.getText(),
510                                grammar.getFilename(),
511                                option.getLine(), option.getColumn());
512         }
513     }
514
515     public void refElementOption(Token option, Token value) {
516         /*
517         System.out.println("setting option for "+context().currentElement());
518         System.out.println(option.getText()+","+value.getText());
519         */

520         AlternativeElement e = context().currentElement();
521         if (e instanceof StringLiteralElement ||
522             e instanceof TokenRefElement ||
523             e instanceof WildcardElement) {
524             ((GrammarAtom)e).setOption(option, value);
525         }
526         else {
527             tool.error("cannot use element option (" + option.getText() +
528                        ") for this kind of element",
529                        grammar.getFilename(), option.getLine(), option.getColumn());
530         }
531     }
532
533     /** Add an exception handler to an exception spec */
534     public void refExceptionHandler(Token exTypeAndName, Token action) {
535         super.refExceptionHandler(exTypeAndName, action);
536         if (currentExceptionSpec == null) {
537             tool.panic("exception handler processing internal error");
538         }
539         currentExceptionSpec.addHandler(new ExceptionHandler(exTypeAndName, action));
540     }
541
542     public void refInitAction(Token action) {
543         super.refAction(action);
544         context().block.setInitAction(action.getText());
545     }
546
547     public void refMemberAction(Token act) {
548         grammar.classMemberAction = act;
549     }
550
551     public void refPreambleAction(Token act) {
552         super.refPreambleAction(act);
553     }
554
555     // Only called for rule blocks
556
public void refReturnAction(Token returnAction) {
557         if (grammar instanceof LexerGrammar) {
558             String JavaDoc name = CodeGenerator.encodeLexerRuleName(((RuleBlock)context().block).getRuleName());
559             RuleSymbol rs = (RuleSymbol)grammar.getSymbol(name);
560             if (rs.access.equals("public")) {
561                 tool.warning("public Lexical rules cannot specify return type", grammar.getFilename(), returnAction.getLine(), returnAction.getColumn());
562                 return;
563             }
564         }
565         ((RuleBlock)context().block).returnAction = returnAction.getText();
566     }
567
568     public void refRule(Token idAssign,
569                         Token r,
570                         Token label,
571                         Token args,
572                         int autoGenType) {
573         // Disallow parser rule references in the lexer
574
if (grammar instanceof LexerGrammar) {
575             // if (!Character.isUpperCase(r.getText().charAt(0))) {
576
if (r.type != ANTLRTokenTypes.TOKEN_REF) {
577                 tool.error("Parser rule " + r.getText() + " referenced in lexer");
578                 return;
579             }
580             if (autoGenType == GrammarElement.AUTO_GEN_CARET) {
581                 tool.error("AST specification ^ not allowed in lexer", grammar.getFilename(), r.getLine(), r.getColumn());
582             }
583         }
584
585         super.refRule(idAssign, r, label, args, autoGenType);
586         lastRuleRef = new RuleRefElement(grammar, r, autoGenType);
587         if (args != null) {
588             lastRuleRef.setArgs(args.getText());
589         }
590         if (idAssign != null) {
591             lastRuleRef.setIdAssign(idAssign.getText());
592         }
593         addElementToCurrentAlt(lastRuleRef);
594
595         String JavaDoc id = r.getText();
596         // if ( Character.isUpperCase(id.charAt(0)) ) { // lexer rule?
597
if (r.type == ANTLRTokenTypes.TOKEN_REF) { // lexer rule?
598
id = CodeGenerator.encodeLexerRuleName(id);
599         }
600         // update symbol table so it knows what nodes reference the rule.
601
RuleSymbol rs = (RuleSymbol)grammar.getSymbol(id);
602         rs.addReference(lastRuleRef);
603         labelElement(lastRuleRef, label);
604     }
605
606     public void refSemPred(Token pred) {
607         //System.out.println("refSemPred "+pred.getText());
608
super.refSemPred(pred);
609         //System.out.println("context().block: "+context().block);
610
if (context().currentAlt().atStart()) {
611             context().currentAlt().semPred = pred.getText();
612         }
613         else {
614             ActionElement a = new ActionElement(grammar, pred);
615             a.isSemPred = true;
616             addElementToCurrentAlt(a);
617         }
618         //System.out.println("DONE refSemPred "+pred.getText());
619
}
620
621     public void refStringLiteral(Token lit, Token label, int autoGenType, boolean lastInRule) {
622         super.refStringLiteral(lit, label, autoGenType, lastInRule);
623         if (grammar instanceof TreeWalkerGrammar && autoGenType == GrammarElement.AUTO_GEN_CARET) {
624             tool.error("^ not allowed in here for tree-walker", grammar.getFilename(), lit.getLine(), lit.getColumn());
625         }
626         StringLiteralElement sl = new StringLiteralElement(grammar, lit, autoGenType);
627
628         // If case-insensitive, then check each char of the stirng literal
629
if (grammar instanceof LexerGrammar && !((LexerGrammar)grammar).caseSensitive) {
630             for (int i = 1; i < lit.getText().length() - 1; i++) {
631                 char c = lit.getText().charAt(i);
632                 if (c < 128 && Character.toLowerCase(c) != c) {
633                     tool.warning("Characters of string literal must be lowercase when caseSensitive=false", grammar.getFilename(), lit.getLine(), lit.getColumn());
634                     break;
635                 }
636             }
637         }
638
639         addElementToCurrentAlt(sl);
640         labelElement(sl, label);
641
642         // if ignore option is set, must add an optional call to the specified rule.
643
String JavaDoc ignore = ruleBlock.getIgnoreRule();
644         if (!lastInRule && ignore != null) {
645             addElementToCurrentAlt(createOptionalRuleRef(ignore, lit));
646         }
647     }
648
649     public void refToken(Token idAssign, Token t, Token label, Token args,
650                          boolean inverted, int autoGenType, boolean lastInRule) {
651         if (grammar instanceof LexerGrammar) {
652             // In lexer, token references are really rule references
653
if (autoGenType == GrammarElement.AUTO_GEN_CARET) {
654                 tool.error("AST specification ^ not allowed in lexer", grammar.getFilename(), t.getLine(), t.getColumn());
655             }
656             if (inverted) {
657                 tool.error("~TOKEN is not allowed in lexer", grammar.getFilename(), t.getLine(), t.getColumn());
658             }
659             refRule(idAssign, t, label, args, autoGenType);
660
661             // if ignore option is set, must add an optional call to the specified token rule.
662
String JavaDoc ignore = ruleBlock.getIgnoreRule();
663             if (!lastInRule && ignore != null) {
664                 addElementToCurrentAlt(createOptionalRuleRef(ignore, t));
665             }
666         }
667         else {
668             // Cannot have token ref args or assignment outside of lexer
669
if (idAssign != null) {
670                 tool.error("Assignment from token reference only allowed in lexer", grammar.getFilename(), idAssign.getLine(), idAssign.getColumn());
671             }
672             if (args != null) {
673                 tool.error("Token reference arguments only allowed in lexer", grammar.getFilename(), args.getLine(), args.getColumn());
674             }
675             super.refToken(idAssign, t, label, args, inverted, autoGenType, lastInRule);
676             TokenRefElement te = new TokenRefElement(grammar, t, inverted, autoGenType);
677             addElementToCurrentAlt(te);
678             labelElement(te, label);
679         }
680     }
681
682     public void refTokenRange(Token t1, Token t2, Token label, int autoGenType, boolean lastInRule) {
683         if (grammar instanceof LexerGrammar) {
684             tool.error("Token range not allowed in lexer", grammar.getFilename(), t1.getLine(), t1.getColumn());
685             return;
686         }
687         super.refTokenRange(t1, t2, label, autoGenType, lastInRule);
688         TokenRangeElement tr = new TokenRangeElement(grammar, t1, t2, autoGenType);
689         if (tr.end < tr.begin) {
690             tool.error("Malformed range.", grammar.getFilename(), t1.getLine(), t1.getColumn());
691             return;
692         }
693         addElementToCurrentAlt(tr);
694         labelElement(tr, label);
695     }
696
697     public void refTreeSpecifier(Token treeSpec) {
698         context().currentAlt().treeSpecifier = treeSpec;
699     }
700
701     public void refWildcard(Token t, Token label, int autoGenType) {
702         super.refWildcard(t, label, autoGenType);
703         WildcardElement wc = new WildcardElement(grammar, t, autoGenType);
704         addElementToCurrentAlt(wc);
705         labelElement(wc, label);
706     }
707
708     /** Get ready to process a new grammar */
709     public void reset() {
710         super.reset();
711         blocks = new LList();
712         lastRuleRef = null;
713         ruleEnd = null;
714         ruleBlock = null;
715         nested = 0;
716         currentExceptionSpec = null;
717         grammarError = false;
718     }
719
720     public void setArgOfRuleRef(Token argAction) {
721         super.setArgOfRuleRef(argAction);
722         lastRuleRef.setArgs(argAction.getText());
723     }
724
725     public static void setBlock(AlternativeBlock b, AlternativeBlock src) {
726         b.setAlternatives(src.getAlternatives());
727         b.initAction = src.initAction;
728         //b.lookaheadDepth = src.lookaheadDepth;
729
b.label = src.label;
730         b.hasASynPred = src.hasASynPred;
731         b.hasAnAction = src.hasAnAction;
732         b.warnWhenFollowAmbig = src.warnWhenFollowAmbig;
733         b.generateAmbigWarnings = src.generateAmbigWarnings;
734         b.line = src.line;
735         b.greedy = src.greedy;
736         b.greedySet = src.greedySet;
737     }
738
739     public void setRuleOption(Token key, Token value) {
740         //((RuleBlock)context().block).setOption(key, value);
741
ruleBlock.setOption(key, value);
742     }
743
744     public void setSubruleOption(Token key, Token value) {
745         ((AlternativeBlock)context().block).setOption(key, value);
746     }
747
748     public void synPred() {
749         if (context().block.not) {
750             tool.error("'~' cannot be applied to syntactic predicate", grammar.getFilename(), context().block.getLine(), context().block.getColumn());
751         }
752         // create the right kind of object now that we know what that is
753
// and switch the list of alternatives. Adjust the stack of blocks.
754
// copy any init action also.
755
SynPredBlock b = new SynPredBlock(grammar);
756         setBlock(b, context().block);
757         BlockContext old = (BlockContext)blocks.pop(); // remove old scope; we want new type of subrule
758
blocks.push(new BlockContext());
759         context().block = b;
760         context().blockEnd = old.blockEnd;
761         context().blockEnd.block = b;
762     }
763
764     public void zeroOrMoreSubRule() {
765         if (context().block.not) {
766             tool.error("'~' cannot be applied to (...)+ subrule", grammar.getFilename(), context().block.getLine(), context().block.getColumn());
767         }
768         // create the right kind of object now that we know what that is
769
// and switch the list of alternatives. Adjust the stack of blocks.
770
// copy any init action also.
771
ZeroOrMoreBlock b = new ZeroOrMoreBlock(grammar);
772         setBlock(b, context().block);
773         BlockContext old = (BlockContext)blocks.pop(); // remove old scope; we want new type of subrule
774
blocks.push(new BlockContext());
775         context().block = b;
776         context().blockEnd = old.blockEnd;
777         context().blockEnd.block = b;
778     }
779 }
780
Popular Tags