001: package antlr;
002:
003: /* ANTLR Translator Generator
004: * Project led by Terence Parr at http://www.cs.usfca.edu
005: * Software rights: http://www.antlr.org/license.html
006: */
007:
008: import java.util.Hashtable;
009: import java.util.Enumeration;
010: import java.io.IOException;
011:
012: import antlr.collections.impl.BitSet;
013: import antlr.collections.impl.Vector;
014:
015: /**A Grammar holds a set of rules (which are stored
016: * in a symbol table). Most of the time a grammar
017: * needs a code generator and an LLkAnalyzer too.
018: */
019: public abstract class Grammar {
020: protected Tool antlrTool;
021: protected CodeGenerator generator;
022: protected LLkGrammarAnalyzer theLLkAnalyzer;
023: protected Hashtable symbols;
024: protected boolean buildAST = false;
025: protected boolean analyzerDebug = false;
026: protected boolean interactive = false;
027: protected String super Class = null;
028:
029: /** The token manager associated with the grammar, if any.
030: // The token manager is responsible for maintaining the set of valid tokens, and
031: // is conceptually shared between the lexer and parser. This may be either a
032: // LexerGrammar or a ImportVocabTokenManager.
033: */
034: protected TokenManager tokenManager;
035:
036: /** The name of the export vocabulary...used to generate the output
037: * token types interchange file.
038: */
039: protected String exportVocab = null;
040:
041: /** The name of the import vocabulary. "Initial conditions"
042: */
043: protected String importVocab = null;
044:
045: // Mapping from String keys to Token option values
046: protected Hashtable options;
047: // Vector of RuleSymbol entries
048: protected Vector rules;
049:
050: protected Token preambleAction = new CommonToken(
051: Token.INVALID_TYPE, "");
052: protected String className = null;
053: protected String fileName = null;
054: protected Token classMemberAction = new CommonToken(
055: Token.INVALID_TYPE, "");
056: protected boolean hasSyntacticPredicate = false;
057: protected boolean hasUserErrorHandling = false;
058:
059: // max lookahead that can be attempted for this parser.
060: protected int maxk = 1;
061:
062: // options
063: protected boolean traceRules = false;
064: protected boolean debuggingOutput = false;
065: protected boolean traceSyntacticPredicates = false;
066: protected boolean defaultErrorHandler = true;
067:
068: protected String comment = null; // javadoc comment
069:
070: public Grammar(String className_, Tool tool_, String super Class) {
071: className = className_;
072: antlrTool = tool_;
073: symbols = new Hashtable();
074: options = new Hashtable();
075: rules = new Vector(100);
076: this .super Class = super Class;
077: }
078:
079: /** Define a rule */
080: public void define(RuleSymbol rs) {
081: rules.appendElement(rs);
082: // add the symbol to the rules hash table
083: symbols.put(rs.getId(), rs);
084: }
085:
086: /** Top-level call to generate the code for this grammar */
087: public abstract void generate() throws IOException;
088:
089: protected String getClassName() {
090: return className;
091: }
092:
093: /* Does this grammar have a default error handler? */
094: public boolean getDefaultErrorHandler() {
095: return defaultErrorHandler;
096: }
097:
098: public String getFilename() {
099: return fileName;
100: }
101:
102: /** Get an integer option. Given the name of the option find its
103: * associated integer value. If the associated value is not an integer or
104: * is not in the table, then throw an exception of type NumberFormatException.
105: * @param key The name of the option
106: * @return The value associated with the key.
107: */
108: public int getIntegerOption(String key)
109: throws NumberFormatException {
110: Token t = (Token) options.get(key);
111: if (t == null || t.getType() != ANTLRTokenTypes.INT) {
112: throw new NumberFormatException();
113: } else {
114: return Integer.parseInt(t.getText());
115: }
116: }
117:
118: /** Get an option. Given the name of the option find its associated value.
119: * @param key The name of the option
120: * @return The value associated with the key, or null if the key has not been set.
121: */
122: public Token getOption(String key) {
123: return (Token) options.get(key);
124: }
125:
126: // Get name of class from which generated parser/lexer inherits
127: protected abstract String getSuperClass();
128:
129: public GrammarSymbol getSymbol(String s) {
130: return (GrammarSymbol) symbols.get(s);
131: }
132:
133: public Enumeration getSymbols() {
134: return symbols.elements();
135: }
136:
137: /** Check the existence of an option in the table
138: * @param key The name of the option
139: * @return true if the option is in the table
140: */
141: public boolean hasOption(String key) {
142: return options.containsKey(key);
143: }
144:
145: /** Is a rule symbol defined? (not used for tokens) */
146: public boolean isDefined(String s) {
147: return symbols.containsKey(s);
148: }
149:
150: /**Process command line arguments. Implemented in subclasses */
151: public abstract void processArguments(String[] args);
152:
153: public void setCodeGenerator(CodeGenerator gen) {
154: generator = gen;
155: }
156:
157: public void setFilename(String s) {
158: fileName = s;
159: }
160:
161: public void setGrammarAnalyzer(LLkGrammarAnalyzer a) {
162: theLLkAnalyzer = a;
163: }
164:
165: /** Set a generic option.
166: * This associates a generic option key with a Token value.
167: * No validation is performed by this method, although users of the value
168: * (code generation and/or analysis) may require certain formats.
169: * The value is stored as a token so that the location of an error
170: * can be reported.
171: * @param key The name of the option.
172: * @param value The value to associate with the key.
173: * @return true if the option was a valid generic grammar option, false o/w
174: */
175: public boolean setOption(String key, Token value) {
176: options.put(key, value);
177: String s = value.getText();
178: int i;
179: if (key.equals("k")) {
180: try {
181: maxk = getIntegerOption("k");
182: if (maxk <= 0) {
183: antlrTool.error(
184: "option 'k' must be greater than 0 (was "
185: + value.getText() + ")",
186: getFilename(), value.getLine(), value
187: .getColumn());
188: maxk = 1;
189: }
190: } catch (NumberFormatException e) {
191: antlrTool.error("option 'k' must be an integer (was "
192: + value.getText() + ")", getFilename(), value
193: .getLine(), value.getColumn());
194: }
195: return true;
196: }
197: if (key.equals("codeGenMakeSwitchThreshold")) {
198: try {
199: i = getIntegerOption("codeGenMakeSwitchThreshold");
200: } catch (NumberFormatException e) {
201: antlrTool
202: .error(
203: "option 'codeGenMakeSwitchThreshold' must be an integer",
204: getFilename(), value.getLine(), value
205: .getColumn());
206: }
207: return true;
208: }
209: if (key.equals("codeGenBitsetTestThreshold")) {
210: try {
211: i = getIntegerOption("codeGenBitsetTestThreshold");
212: } catch (NumberFormatException e) {
213: antlrTool
214: .error(
215: "option 'codeGenBitsetTestThreshold' must be an integer",
216: getFilename(), value.getLine(), value
217: .getColumn());
218: }
219: return true;
220: }
221: if (key.equals("defaultErrorHandler")) {
222: if (s.equals("true")) {
223: defaultErrorHandler = true;
224: } else if (s.equals("false")) {
225: defaultErrorHandler = false;
226: } else {
227: antlrTool
228: .error(
229: "Value for defaultErrorHandler must be true or false",
230: getFilename(), value.getLine(), value
231: .getColumn());
232: }
233: return true;
234: }
235: if (key.equals("analyzerDebug")) {
236: if (s.equals("true")) {
237: analyzerDebug = true;
238: } else if (s.equals("false")) {
239: analyzerDebug = false;
240: } else {
241: antlrTool.error(
242: "option 'analyzerDebug' must be true or false",
243: getFilename(), value.getLine(), value
244: .getColumn());
245: }
246: return true;
247: }
248: if (key.equals("codeGenDebug")) {
249: if (s.equals("true")) {
250: analyzerDebug = true;
251: } else if (s.equals("false")) {
252: analyzerDebug = false;
253: } else {
254: antlrTool.error(
255: "option 'codeGenDebug' must be true or false",
256: getFilename(), value.getLine(), value
257: .getColumn());
258: }
259: return true;
260: }
261: if (key.equals("classHeaderSuffix")) {
262: return true;
263: }
264: if (key.equals("classHeaderPrefix")) {
265: return true;
266: }
267: if (key.equals("namespaceAntlr")) {
268: return true;
269: }
270: if (key.equals("namespaceStd")) {
271: return true;
272: }
273: if (key.equals("genHashLines")) {
274: return true;
275: }
276: if (key.equals("noConstructors")) {
277: return true;
278: }
279: return false;
280: }
281:
282: public void setTokenManager(TokenManager tokenManager_) {
283: tokenManager = tokenManager_;
284: }
285:
286: /** Print out the grammar without actions */
287: public String toString() {
288: StringBuffer buf = new StringBuffer(20000);
289: Enumeration ids = rules.elements();
290: while (ids.hasMoreElements()) {
291: RuleSymbol rs = (RuleSymbol) ids.nextElement();
292: if (!rs.id.equals("mnextToken")) {
293: buf.append(rs.getBlock().toString());
294: buf.append("\n\n");
295: }
296: }
297: return buf.toString();
298: }
299:
300: }
|