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