1 | package antlr.preprocessor; |
---|
2 | |
---|
3 | /* ANTLR Translator Generator |
---|
4 | * Project led by Terence Parr at http://www.cs.usfca.edu |
---|
5 | * Software rights: http://www.antlr.org/license.html |
---|
6 | * |
---|
7 | * $Id: //depot/code/org.antlr/release/antlr-2.7.7/antlr/preprocessor/Grammar.java#2 $ |
---|
8 | */ |
---|
9 | |
---|
10 | import antlr.collections.impl.IndexedVector; |
---|
11 | |
---|
12 | import java.util.Hashtable; |
---|
13 | import java.util.Enumeration; |
---|
14 | import java.io.IOException; |
---|
15 | |
---|
16 | class Grammar { |
---|
17 | protected String name; |
---|
18 | protected String fileName; // where does it come from? |
---|
19 | protected String superGrammar; // null if no super class |
---|
20 | protected String type; // lexer? parser? tree parser? |
---|
21 | protected IndexedVector rules; // text of rules as they were read in |
---|
22 | protected IndexedVector options;// rule options |
---|
23 | protected String tokenSection; // the tokens{} stuff |
---|
24 | protected String preambleAction;// action right before grammar |
---|
25 | protected String memberAction; // action inside grammar |
---|
26 | protected Hierarchy hier; // hierarchy of grammars |
---|
27 | protected boolean predefined = false; // one of the predefined grammars? |
---|
28 | protected boolean alreadyExpanded = false; |
---|
29 | protected boolean specifiedVocabulary = false; // found importVocab option? |
---|
30 | |
---|
31 | /** if not derived from another grammar, might still specify a non-ANTLR |
---|
32 | * class to derive from like this "class T extends Parser(MyParserClass);" |
---|
33 | */ |
---|
34 | protected String superClass = null; |
---|
35 | |
---|
36 | protected String importVocab = null; |
---|
37 | protected String exportVocab = null; |
---|
38 | protected antlr.Tool antlrTool; |
---|
39 | |
---|
40 | public Grammar(antlr.Tool tool, String name, String superGrammar, IndexedVector rules) { |
---|
41 | this.name = name; |
---|
42 | this.superGrammar = superGrammar; |
---|
43 | this.rules = rules; |
---|
44 | this.antlrTool = tool; |
---|
45 | } |
---|
46 | |
---|
47 | public void addOption(Option o) { |
---|
48 | if (options == null) { // if not already there, create it |
---|
49 | options = new IndexedVector(); |
---|
50 | } |
---|
51 | options.appendElement(o.getName(), o); |
---|
52 | } |
---|
53 | |
---|
54 | public void addRule(Rule r) { |
---|
55 | rules.appendElement(r.getName(), r); |
---|
56 | } |
---|
57 | |
---|
58 | /** Copy all nonoverridden rules, vocabulary, and options into this grammar from |
---|
59 | * supergrammar chain. The change is made in place; e.g., this grammar's vector |
---|
60 | * of rules gets bigger. This has side-effects: all grammars on path to |
---|
61 | * root of hierarchy are expanded also. |
---|
62 | */ |
---|
63 | public void expandInPlace() { |
---|
64 | // if this grammar already expanded, just return |
---|
65 | if (alreadyExpanded) { |
---|
66 | return; |
---|
67 | } |
---|
68 | |
---|
69 | // Expand super grammar first (unless it's a predefined or subgrammar of predefined) |
---|
70 | Grammar superG = getSuperGrammar(); |
---|
71 | if (superG == null) |
---|
72 | return; // error (didn't provide superclass) |
---|
73 | if (exportVocab == null) { |
---|
74 | // if no exportVocab for this grammar, make it same as grammar name |
---|
75 | exportVocab = getName(); |
---|
76 | } |
---|
77 | if (superG.isPredefined()) |
---|
78 | return; // can't expand Lexer, Parser, ... |
---|
79 | superG.expandInPlace(); |
---|
80 | |
---|
81 | // expand current grammar now. |
---|
82 | alreadyExpanded = true; |
---|
83 | // track whether a grammar file needed to have a grammar expanded |
---|
84 | GrammarFile gf = hier.getFile(getFileName()); |
---|
85 | gf.setExpanded(true); |
---|
86 | |
---|
87 | // Copy rules from supergrammar into this grammar |
---|
88 | IndexedVector inhRules = superG.getRules(); |
---|
89 | for (Enumeration e = inhRules.elements(); e.hasMoreElements();) { |
---|
90 | Rule r = (Rule)e.nextElement(); |
---|
91 | inherit(r, superG); |
---|
92 | } |
---|
93 | |
---|
94 | // Copy options from supergrammar into this grammar |
---|
95 | // Modify tokdef options so that they point to dir of enclosing grammar |
---|
96 | IndexedVector inhOptions = superG.getOptions(); |
---|
97 | if (inhOptions != null) { |
---|
98 | for (Enumeration e = inhOptions.elements(); e.hasMoreElements();) { |
---|
99 | Option o = (Option)e.nextElement(); |
---|
100 | inherit(o, superG); |
---|
101 | } |
---|
102 | } |
---|
103 | |
---|
104 | // add an option to load the superGrammar's output vocab |
---|
105 | if ((options != null && options.getElement("importVocab") == null) || options == null) { |
---|
106 | // no importVocab found, add one that grabs superG's output vocab |
---|
107 | Option inputV = new Option("importVocab", superG.exportVocab + ";", this); |
---|
108 | addOption(inputV); |
---|
109 | // copy output vocab file to current dir |
---|
110 | String originatingGrFileName = superG.getFileName(); |
---|
111 | String path = antlrTool.pathToFile(originatingGrFileName); |
---|
112 | String superExportVocabFileName = path + superG.exportVocab + |
---|
113 | antlr.CodeGenerator.TokenTypesFileSuffix + |
---|
114 | antlr.CodeGenerator.TokenTypesFileExt; |
---|
115 | String newImportVocabFileName = antlrTool.fileMinusPath(superExportVocabFileName); |
---|
116 | if (path.equals("." + System.getProperty("file.separator"))) { |
---|
117 | // don't copy tokdef file onto itself (must be current directory) |
---|
118 | // System.out.println("importVocab file same dir; leaving as " + superExportVocabFileName); |
---|
119 | } |
---|
120 | else { |
---|
121 | try { |
---|
122 | antlrTool.copyFile(superExportVocabFileName, newImportVocabFileName); |
---|
123 | } |
---|
124 | catch (IOException io) { |
---|
125 | antlrTool.toolError("cannot find/copy importVocab file " + superExportVocabFileName); |
---|
126 | return; |
---|
127 | } |
---|
128 | } |
---|
129 | } |
---|
130 | |
---|
131 | // copy member action from supergrammar into this grammar |
---|
132 | inherit(superG.memberAction, superG); |
---|
133 | } |
---|
134 | |
---|
135 | public String getFileName() { |
---|
136 | return fileName; |
---|
137 | } |
---|
138 | |
---|
139 | public String getName() { |
---|
140 | return name; |
---|
141 | } |
---|
142 | |
---|
143 | public IndexedVector getOptions() { |
---|
144 | return options; |
---|
145 | } |
---|
146 | |
---|
147 | public IndexedVector getRules() { |
---|
148 | return rules; |
---|
149 | } |
---|
150 | |
---|
151 | public Grammar getSuperGrammar() { |
---|
152 | if (superGrammar == null) return null; |
---|
153 | Grammar g = (Grammar)hier.getGrammar(superGrammar); |
---|
154 | return g; |
---|
155 | } |
---|
156 | |
---|
157 | public String getSuperGrammarName() { |
---|
158 | return superGrammar; |
---|
159 | } |
---|
160 | |
---|
161 | public String getType() { |
---|
162 | return type; |
---|
163 | } |
---|
164 | |
---|
165 | public void inherit(Option o, Grammar superG) { |
---|
166 | // do NOT inherit importVocab/exportVocab options under any circumstances |
---|
167 | if (o.getName().equals("importVocab") || |
---|
168 | o.getName().equals("exportVocab")) { |
---|
169 | return; |
---|
170 | } |
---|
171 | |
---|
172 | Option overriddenOption = null; |
---|
173 | if (options != null) { // do we even have options? |
---|
174 | overriddenOption = (Option)options.getElement(o.getName()); |
---|
175 | } |
---|
176 | // if overridden, do not add to this grammar |
---|
177 | if (overriddenOption == null) { // not overridden |
---|
178 | addOption(o); // copy option into this grammar--not overridden |
---|
179 | } |
---|
180 | } |
---|
181 | |
---|
182 | public void inherit(Rule r, Grammar superG) { |
---|
183 | // if overridden, do not add to this grammar |
---|
184 | Rule overriddenRule = (Rule)rules.getElement(r.getName()); |
---|
185 | if (overriddenRule != null) { |
---|
186 | // rule is overridden in this grammar. |
---|
187 | if (!overriddenRule.sameSignature(r)) { |
---|
188 | // warn if different sig |
---|
189 | antlrTool.warning("rule " + getName() + "." + overriddenRule.getName() + |
---|
190 | " has different signature than " + |
---|
191 | superG.getName() + "." + overriddenRule.getName()); |
---|
192 | } |
---|
193 | } |
---|
194 | else { // not overridden, copy rule into this |
---|
195 | addRule(r); |
---|
196 | } |
---|
197 | } |
---|
198 | |
---|
199 | public void inherit(String memberAction, Grammar superG) { |
---|
200 | if (this.memberAction != null) return; // do nothing if already have member action |
---|
201 | if (memberAction != null) { // don't have one here, use supergrammar's action |
---|
202 | this.memberAction = memberAction; |
---|
203 | } |
---|
204 | } |
---|
205 | |
---|
206 | public boolean isPredefined() { |
---|
207 | return predefined; |
---|
208 | } |
---|
209 | |
---|
210 | public void setFileName(String f) { |
---|
211 | fileName = f; |
---|
212 | } |
---|
213 | |
---|
214 | public void setHierarchy(Hierarchy hier) { |
---|
215 | this.hier = hier; |
---|
216 | } |
---|
217 | |
---|
218 | public void setMemberAction(String a) { |
---|
219 | memberAction = a; |
---|
220 | } |
---|
221 | |
---|
222 | public void setOptions(IndexedVector options) { |
---|
223 | this.options = options; |
---|
224 | } |
---|
225 | |
---|
226 | public void setPreambleAction(String a) { |
---|
227 | preambleAction = a; |
---|
228 | } |
---|
229 | |
---|
230 | public void setPredefined(boolean b) { |
---|
231 | predefined = b; |
---|
232 | } |
---|
233 | |
---|
234 | public void setTokenSection(String tk) { |
---|
235 | tokenSection = tk; |
---|
236 | } |
---|
237 | |
---|
238 | public void setType(String t) { |
---|
239 | type = t; |
---|
240 | } |
---|
241 | |
---|
242 | public String toString() { |
---|
243 | StringBuffer s = new StringBuffer(10000); |
---|
244 | if (preambleAction != null) { |
---|
245 | s.append(preambleAction); |
---|
246 | } |
---|
247 | if (superGrammar == null) { |
---|
248 | return "class " + name + ";"; |
---|
249 | } |
---|
250 | if ( superClass!=null ) { |
---|
251 | // replace with specified superclass not actual grammar |
---|
252 | // user must make sure that the superclass derives from super grammar class |
---|
253 | s.append("class " + name + " extends " + superClass + ";"); |
---|
254 | } |
---|
255 | else { |
---|
256 | s.append("class " + name + " extends " + type + ";"); |
---|
257 | } |
---|
258 | s.append( |
---|
259 | System.getProperty("line.separator") + |
---|
260 | System.getProperty("line.separator")); |
---|
261 | if (options != null) { |
---|
262 | s.append(Hierarchy.optionsToString(options)); |
---|
263 | } |
---|
264 | if (tokenSection != null) { |
---|
265 | s.append(tokenSection + "\n"); |
---|
266 | } |
---|
267 | if (memberAction != null) { |
---|
268 | s.append(memberAction + System.getProperty("line.separator")); |
---|
269 | } |
---|
270 | for (int i = 0; i < rules.size(); i++) { |
---|
271 | Rule r = (Rule)rules.elementAt(i); |
---|
272 | if (!getName().equals(r.enclosingGrammar.getName())) { |
---|
273 | s.append("// inherited from grammar " + r.enclosingGrammar.getName() + System.getProperty("line.separator")); |
---|
274 | } |
---|
275 | s.append(r + |
---|
276 | System.getProperty("line.separator") + |
---|
277 | System.getProperty("line.separator")); |
---|
278 | } |
---|
279 | return s.toString(); |
---|
280 | } |
---|
281 | } |
---|