KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > antlr > works > grammar > EngineGrammar


1 /*
2
3 [The "BSD licence"]
4 Copyright (c) 2005 Jean Bovet
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
16 3. The name of the author may not be used to endorse or promote products
17 derived from this software without specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 */

31
32
33 package org.antlr.works.grammar;
34
35 import antlr.RecognitionException;
36 import antlr.TokenStreamException;
37 import org.antlr.Tool;
38 import org.antlr.analysis.NFAState;
39 import org.antlr.tool.*;
40 import org.antlr.works.ate.syntax.misc.ATEToken;
41 import org.antlr.works.components.grammar.CEditorGrammar;
42 import org.antlr.works.prefs.AWPrefs;
43 import org.antlr.works.syntax.element.ElementGrammarName;
44 import org.antlr.works.syntax.element.ElementRule;
45 import org.antlr.works.utils.Console;
46 import org.antlr.works.utils.ErrorListener;
47 import org.antlr.works.utils.Utils;
48
49 import javax.swing.*;
50 import java.util.ArrayList JavaDoc;
51 import java.util.List JavaDoc;
52 import java.util.Set JavaDoc;
53
54 public class EngineGrammar {
55
56     protected Grammar parserGrammar;
57     protected Grammar lexerGrammar;
58     protected List JavaDoc<EngineGrammarError> errors;
59
60     protected boolean grammarDirty;
61     protected boolean grammarAnalyzeDirty;
62
63     protected CEditorGrammar editor;
64
65     public EngineGrammar(CEditorGrammar editor) {
66         this.editor = editor;
67         errors = new ArrayList JavaDoc<EngineGrammarError>();
68         makeDirty();
69     }
70
71     public void makeDirty() {
72         grammarDirty = true;
73         grammarAnalyzeDirty = true;
74     }
75
76     public boolean isDirty() {
77         return grammarDirty || grammarAnalyzeDirty;
78     }
79
80     public Grammar getParserGrammar() {
81         return parserGrammar;
82     }
83
84     public Grammar getLexerGrammar() {
85         return lexerGrammar;
86     }
87
88     public NFAState getRuleStartState(String JavaDoc name) throws Exception JavaDoc {
89         Grammar g;
90         createGrammars();
91         if(ATEToken.isLexerName(name))
92             g = getLexerGrammar();
93         else
94             g = getParserGrammar();
95
96         return g == null ? null:g.getRuleStartState(name);
97     }
98
99     public Grammar getGrammarForRule(String JavaDoc name) throws Exception JavaDoc {
100         createGrammars();
101         if(ATEToken.isLexerName(name))
102             return getLexerGrammar();
103         else
104             return getParserGrammar();
105     }
106
107     public List JavaDoc<EngineGrammarError> getErrors() {
108         return errors;
109     }
110
111     public boolean isTreeParserGrammar() {
112         return getType() == ElementGrammarName.TREEPARSER;
113     }
114
115     public boolean hasGrammar() {
116         switch(getType()) {
117             case ElementGrammarName.COMBINED:
118                 return parserGrammar != null;
119             case ElementGrammarName.TREEPARSER:
120             case ElementGrammarName.PARSER:
121                 return parserGrammar != null;
122             case ElementGrammarName.LEXER:
123                 return lexerGrammar != null;
124         }
125         return false;
126     }
127
128     public Grammar getANTLRGrammar() {
129         switch(getType()) {
130             case ElementGrammarName.COMBINED:
131                 return parserGrammar;
132             case ElementGrammarName.TREEPARSER:
133             case ElementGrammarName.PARSER:
134                 return parserGrammar;
135             case ElementGrammarName.LEXER:
136                 return lexerGrammar;
137         }
138         return null;
139     }
140
141     public Tool getANTLRTool() {
142         String JavaDoc[] params = AWPrefs.getANTLR3Options();
143         if(editor.getFileFolder() != null) {
144             params = Utils.concat(params, new String JavaDoc[] { "-lib", editor.getFileFolder() });
145         }
146         return new Tool(params);
147     }
148
149     public String JavaDoc getName() {
150         ElementGrammarName name = editor.parserEngine.getName();
151         if(name == null)
152             return null;
153         else
154             return name.getName();
155     }
156
157     public int getType() {
158         ElementGrammarName name = editor.parserEngine.getName();
159         if(name == null)
160             return ElementGrammarName.COMBINED;
161         else
162             return name.getType();
163     }
164
165     public boolean createGrammars() throws Exception JavaDoc {
166         if(!grammarDirty)
167             return true;
168
169         ErrorManager.setErrorListener(ErrorListener.shared());
170         ErrorListener.shared().clear();
171
172         switch(getType()) {
173             case ElementGrammarName.COMBINED:
174                 createCombinedGrammar();
175                 break;
176             case ElementGrammarName.TREEPARSER:
177             case ElementGrammarName.PARSER:
178                 createParserGrammar();
179                 break;
180             case ElementGrammarName.LEXER:
181                 createLexerGrammar();
182                 break;
183         }
184
185         if(!ErrorListener.shared().hasErrors()) {
186             grammarDirty = false;
187             return false;
188         } else {
189             return true;
190         }
191     }
192
193     public String JavaDoc getFileName() {
194         String JavaDoc fileName = editor.getFileName();
195         return fileName==null?"<notsaved>":fileName;
196     }
197
198     protected Grammar createNewGrammar(String JavaDoc filename, String JavaDoc content) throws TokenStreamException, RecognitionException {
199         Grammar g = new Grammar();
200         g.setTool(getANTLRTool());
201         g.setFileName(filename);
202         g.setGrammarContent(content);
203         return g;
204     }
205
206     protected void createCombinedGrammar() throws Exception JavaDoc {
207         parserGrammar = createNewGrammar(getFileName(), editor.getText());
208         parserGrammar.createNFAs();
209         lexerGrammar = createLexerGrammarFromCombinedGrammar(parserGrammar);
210     }
211
212     protected Grammar createLexerGrammarFromCombinedGrammar(Grammar grammar) throws Exception JavaDoc {
213         String JavaDoc lexerGrammarStr = grammar.getLexerGrammar();
214         if(lexerGrammarStr == null)
215             return null;
216
217         Grammar lexerGrammar = new Grammar();
218         lexerGrammar.setTool(getANTLRTool());
219         lexerGrammar.setFileName("<internally-generated-lexer>");
220         lexerGrammar.importTokenVocabulary(grammar);
221
222         lexerGrammar.setGrammarContent(lexerGrammarStr);
223         lexerGrammar.createNFAs();
224
225         return lexerGrammar;
226     }
227
228     protected void createParserGrammar() throws TokenStreamException, RecognitionException {
229         parserGrammar = createNewGrammar(getFileName(), editor.getText());
230         parserGrammar.createNFAs();
231     }
232
233     protected void createLexerGrammar() throws TokenStreamException, RecognitionException {
234         lexerGrammar = createNewGrammar(getFileName(), editor.getText());
235         lexerGrammar.createNFAs();
236     }
237
238     public void printLeftRecursionToConsole(List JavaDoc rules) {
239         StringBuffer JavaDoc info = new StringBuffer JavaDoc();
240         info.append("Aborting because the following rules are mutually left-recursive:");
241         for (Object JavaDoc rule : rules) {
242             Set JavaDoc rulesSet = (Set JavaDoc) rule;
243             info.append("\n ");
244             info.append(rulesSet);
245         }
246         editor.getConsole().println(info.toString(), Console.LEVEL_ERROR);
247     }
248
249     public void markLeftRecursiveRules(List JavaDoc rules) {
250         // 'rules' is a list of set of rules given by ANTLR
251
for (Object JavaDoc rule : rules) {
252             Set JavaDoc rulesSet = (Set JavaDoc) rule;
253             for (Object JavaDoc aRulesSet : rulesSet) {
254                 String JavaDoc name = (String JavaDoc) aRulesSet;
255                 ElementRule r = editor.rules.getRuleWithName(name);
256                 if (r == null)
257                     continue;
258                 r.setLeftRecursiveRulesSet(rulesSet);
259             }
260         }
261     }
262
263     public void analyze() throws Exception JavaDoc {
264         if(!createGrammars()) {
265             return;
266         }
267
268         Grammar g = getANTLRGrammar();
269         if(g == null) {
270             return;
271         }
272
273         List JavaDoc rules = g.checkAllRulesForLeftRecursion();
274         if(!rules.isEmpty()) {
275             printLeftRecursionToConsole(rules);
276             markLeftRecursiveRules(rules);
277         }
278
279         if(ErrorManager.doNotAttemptAnalysis()) {
280             return;
281         }
282
283         if(!grammarAnalyzeDirty) {
284             return;
285         }
286
287         ErrorManager.setErrorListener(ErrorListener.shared());
288         //ErrorListener.shared().clear();
289

290         try {
291             g.createLookaheadDFAs();
292             if(getType() == ElementGrammarName.COMBINED) {
293                 // If the grammar is combined, analyze also the lexer
294
if(lexerGrammar != null)
295                     lexerGrammar.createLookaheadDFAs();
296             }
297
298             buildNonDeterministicErrors();
299             markRulesWithWarningsOrErrors();
300         } catch(Exception JavaDoc e) {
301             // ignore
302
}
303
304         if(SwingUtilities.isEventDispatchThread()) {
305             editor.engineGrammarDidAnalyze();
306         } else {
307             SwingUtilities.invokeLater(new Runnable JavaDoc() {
308                 public void run() {
309                     editor.engineGrammarDidAnalyze();
310                 }
311             });
312         }
313
314         // Only reset the dirty flag when the grammar has no errors (otherwise the next time the grammar is checked
315
// it will appear to be OK)
316
if(!ErrorListener.shared().hasErrors()) {
317             grammarAnalyzeDirty = false;
318         }
319     }
320
321     public void cancel() {
322         Grammar g = getANTLRGrammar();
323         if(g != null)
324             g.externallyAbortNFAToDFAConversion();
325     }
326
327     protected void buildNonDeterministicErrors() {
328         errors.clear();
329         for (Message warning : ErrorListener.shared().warnings) {
330             buildError(warning);
331         }
332         for (Message error : ErrorListener.shared().errors) {
333             buildError(error);
334         }
335     }
336
337     protected void buildError(Object JavaDoc o) {
338         if(o instanceof GrammarUnreachableAltsMessage)
339             errors.add(buildUnreachableAltsError((GrammarUnreachableAltsMessage)o));
340         else if(o instanceof GrammarNonDeterminismMessage)
341             errors.add(buildNonDeterministicError((GrammarNonDeterminismMessage)o));
342         else if(o instanceof NonRegularDecisionMessage)
343             errors.add(buildNonRegularDecisionError((NonRegularDecisionMessage)o));
344     }
345
346     protected EngineGrammarError buildNonDeterministicError(GrammarNonDeterminismMessage message) {
347         EngineGrammarError error = new EngineGrammarError();
348         error.setLine(message.probe.dfa.getDecisionASTNode().getLine()-1);
349
350         List JavaDoc labels = message.probe.getSampleNonDeterministicInputSequence(message.problemState);
351         error.setLabels(labels);
352
353         String JavaDoc input = message.probe.getInputSequenceDisplay(labels);
354         error.setMessageText("Decision can match input such as \""+input+"\" using multiple alternatives");
355         error.setMessage(message);
356
357         return error;
358     }
359
360     protected EngineGrammarError buildUnreachableAltsError(GrammarUnreachableAltsMessage message) {
361         EngineGrammarError error = new EngineGrammarError();
362
363         error.setLine(message.probe.dfa.getDecisionASTNode().getLine()-1);
364         error.setMessageText("The following alternatives are unreachable: "+message.alts);
365         error.setMessage(message);
366
367         return error;
368     }
369
370     protected EngineGrammarError buildNonRegularDecisionError(NonRegularDecisionMessage message) {
371         EngineGrammarError error = new EngineGrammarError();
372
373         error.setLine(message.probe.dfa.getDecisionASTNode().getLine()-1);
374         error.setMessageText(message.toString());
375         error.setMessage(message);
376
377         return error;
378     }
379
380     protected void markRulesWithWarningsOrErrors() throws Exception JavaDoc {
381         // Clear graphic cache because we have to redraw each rule again
382
editor.visual.clearCacheGraphs();
383         for (ElementRule rule : editor.getParserEngine().getRules()) {
384             updateRuleWithErrors(rule, fetchErrorsForRule(rule));
385         }
386
387         editor.rules.refreshRules();
388     }
389
390     protected void updateRuleWithErrors(ElementRule rule, List JavaDoc<EngineGrammarError> errors) throws Exception JavaDoc {
391         rule.setErrors(errors);
392         rule.setNeedsToBuildErrors(true);
393     }
394
395     protected List JavaDoc<EngineGrammarError> fetchErrorsForRule(ElementRule rule) {
396         List JavaDoc<EngineGrammarError> errors = new ArrayList JavaDoc<EngineGrammarError>();
397         for (EngineGrammarError error : getErrors()) {
398             if (error.line >= rule.start.startLineNumber && error.line <= rule.end.startLineNumber)
399                 errors.add(error);
400         }
401         return errors;
402     }
403
404     public void computeRuleErrors(ElementRule rule) {
405         List JavaDoc<EngineGrammarError> errors = rule.getErrors();
406         for (EngineGrammarError error : errors) {
407             Object JavaDoc o = error.getMessage();
408             if (o instanceof GrammarUnreachableAltsMessage)
409                 computeRuleError(rule, error, (GrammarUnreachableAltsMessage) o);
410             else if (o instanceof GrammarNonDeterminismMessage)
411                 computeRuleError(rule, error, (GrammarNonDeterminismMessage) o);
412             else if (o instanceof NonRegularDecisionMessage)
413                 computeRuleError(rule, error, (NonRegularDecisionMessage) o);
414         }
415
416         try {
417             editor.visual.createGraphsForRule(rule);
418         } catch (Exception JavaDoc e) {
419             // ignore
420
}
421
422         rule.setNeedsToBuildErrors(false);
423     }
424
425     public void computeRuleError(ElementRule rule, EngineGrammarError error, GrammarNonDeterminismMessage message) {
426         List JavaDoc nonDetAlts = message.probe.getNonDeterministicAltsForState(message.problemState);
427         Set JavaDoc disabledAlts = message.probe.getDisabledAlternatives(message.problemState);
428
429         int firstAlt = 0;
430
431         for (Object JavaDoc nonDetAlt : nonDetAlts) {
432             Integer JavaDoc displayAltI = (Integer JavaDoc) nonDetAlt;
433             NFAState nfaStart = message.probe.dfa.getNFADecisionStartState();
434
435             int tracePathAlt = nfaStart.translateDisplayAltToWalkAlt(message.probe.dfa, displayAltI);
436             if (firstAlt == 0)
437                 firstAlt = tracePathAlt;
438
439             List JavaDoc path =
440                     message.probe.getNFAPathStatesForAlt(firstAlt,
441                             tracePathAlt,
442                             error.getLabels());
443
444             error.addPath(path, disabledAlts.contains(displayAltI));
445             error.addStates(path);
446
447             // Find all rules enclosing each state (because a path can extend over multiple rules)
448
for (Object JavaDoc aPath : path) {
449                 NFAState state = (NFAState) aPath;
450                 error.addRule(state.getEnclosingRule());
451             }
452         }
453     }
454
455     public void computeRuleError(ElementRule rule, EngineGrammarError error, GrammarUnreachableAltsMessage message) {
456         NFAState state = message.probe.dfa.getNFADecisionStartState();
457         for (Object JavaDoc alt1 : message.alts) {
458             error.addUnreachableAlt(state, (Integer JavaDoc) alt1);
459             error.addStates(state);
460             error.addRule(state.getEnclosingRule());
461         }
462     }
463
464     public void computeRuleError(ElementRule rule, EngineGrammarError error, NonRegularDecisionMessage message) {
465         NFAState state = message.probe.dfa.getNFADecisionStartState();
466         for (Object JavaDoc alt : message.altsWithRecursion) {
467             // Use currently the unreachable alt for display purpose only
468
error.addUnreachableAlt(state, (Integer JavaDoc) alt);
469             error.addStates(state);
470             error.addRule(state.getEnclosingRule());
471         }
472     }
473
474 }
475
Popular Tags