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 antlr.collections.impl.Vector;
009:
010: import java.util.Hashtable;
011:
012: /**A list of alternatives and info contained in
013: * the rule definition.
014: */
015: public class RuleBlock extends AlternativeBlock {
016: protected String ruleName;
017: protected String argAction = null; // string for rule arguments [...]
018: protected String throwsSpec = null;
019: protected String returnAction = null;// string for rule return type(s) <...>
020: protected RuleEndElement endNode; // which node ends this rule?
021:
022: // Generate literal-testing code for lexer rule?
023: protected boolean testLiterals = false;
024:
025: Vector labeledElements; // List of labeled elements found in this rule
026: // This is a list of AlternativeElement (or subclass)
027:
028: protected boolean[] lock; // for analysis; used to avoid infinite loops
029: // 1..k
030: protected Lookahead cache[];// Each rule can cache it's lookahead computation.
031:
032: // This cache contains an epsilon
033: // imaginary token if the FOLLOW is required. No
034: // FOLLOW information is cached here.
035: // The FIRST(rule) is stored in this cache; 1..k
036: // This set includes FIRST of all alts.
037:
038: Hashtable exceptionSpecs; // table of String-to-ExceptionSpec.
039:
040: // grammar-settable options
041: protected boolean defaultErrorHandler = true;
042: protected boolean constText = false;
043: protected boolean checkSkip = !Tool.agressive;
044: protected String ignoreRule = null;
045:
046: /** Construct a named rule. */
047: public RuleBlock(Grammar g, String r) {
048: super (g);
049: ruleName = r;
050: labeledElements = new Vector();
051: cache = new Lookahead[g.maxk + 1];
052: exceptionSpecs = new Hashtable();
053: setAutoGen(g instanceof ParserGrammar);
054: }
055:
056: /** Construct a named rule with line number information */
057: public RuleBlock(Grammar g, String r, int line, boolean doAutoGen_) {
058: this (g, r);
059: this .line = line;
060: setAutoGen(doAutoGen_);
061: }
062:
063: public void addExceptionSpec(ExceptionSpec ex) {
064: if (findExceptionSpec(ex.label) != null) {
065: if (ex.label != null) {
066: grammar.antlrTool
067: .error("Rule '"
068: + ruleName
069: + "' already has an exception handler for label: "
070: + ex.label);
071: } else {
072: grammar.antlrTool.error("Rule '" + ruleName
073: + "' already has an exception handler");
074: }
075: } else {
076: exceptionSpecs.put((ex.label == null ? "" : ex.label
077: .getText()), ex);
078: }
079: }
080:
081: public ExceptionSpec findExceptionSpec(Token label) {
082: return (ExceptionSpec) exceptionSpecs.get(label == null ? ""
083: : label.getText());
084: }
085:
086: public ExceptionSpec findExceptionSpec(String label) {
087: return (ExceptionSpec) exceptionSpecs.get(label == null ? ""
088: : label);
089: }
090:
091: public void generate(Context context) {
092: grammar.generator.gen(this , context);
093: }
094:
095: public boolean getDefaultErrorHandler() {
096: return defaultErrorHandler;
097: }
098:
099: public boolean isCheckSkip() {
100: return checkSkip;
101: }
102:
103: public boolean isConstText() {
104: return constText;
105: }
106:
107: public RuleEndElement getEndElement() {
108: return endNode;
109: }
110:
111: public String getIgnoreRule() {
112: return ignoreRule;
113: }
114:
115: public String getRuleName() {
116: return ruleName;
117: }
118:
119: public boolean getTestLiterals() {
120: return testLiterals;
121: }
122:
123: public boolean isLexerAutoGenRule() {
124: return ruleName.equals("nextToken");
125: }
126:
127: public Lookahead look(int k) {
128: return grammar.theLLkAnalyzer.look(k, this );
129: }
130:
131: public void prepareForAnalysis() {
132: super .prepareForAnalysis();
133: lock = new boolean[grammar.maxk + 1];
134: }
135:
136: // rule option values
137: public void setDefaultErrorHandler(boolean value) {
138: defaultErrorHandler = value;
139: }
140:
141: public void setEndElement(RuleEndElement re) {
142: endNode = re;
143: }
144:
145: public void setOption(Token key, Token value) {
146: // Const option to generate const text tokens
147: if (key.getText().equals("constText")) {
148: if (value.getText().equals("true")) {
149: constText = true;
150: } else if (value.getText().equals("false")) {
151: constText = false;
152: } else {
153: grammar.antlrTool.error(
154: "Value for constText must be true or false",
155: grammar.getFilename(), key.getLine(), key
156: .getColumn());
157: }
158: } else if (key.getText().equals("checkSkip")) {
159: if (value.getText().equals("true")) {
160: checkSkip = true;
161: } else if (value.getText().equals("false")) {
162: checkSkip = false;
163: } else {
164: grammar.antlrTool.error(
165: "Value for checkSkip must be true or false",
166: grammar.getFilename(), key.getLine(), key
167: .getColumn());
168: }
169: } else if (key.getText().equals("defaultErrorHandler")) {
170: if (value.getText().equals("true")) {
171: defaultErrorHandler = true;
172: } else if (value.getText().equals("false")) {
173: defaultErrorHandler = false;
174: } else {
175: grammar.antlrTool
176: .error(
177: "Value for defaultErrorHandler must be true or false",
178: grammar.getFilename(), key.getLine(),
179: key.getColumn());
180: }
181: } else if (key.getText().equals("testLiterals")) {
182: if (!(grammar instanceof LexerGrammar)) {
183: grammar.antlrTool
184: .error(
185: "testLiterals option only valid for lexer rules",
186: grammar.getFilename(), key.getLine(),
187: key.getColumn());
188: } else {
189: if (value.getText().equals("true")) {
190: testLiterals = true;
191: } else if (value.getText().equals("false")) {
192: testLiterals = false;
193: } else {
194: grammar.antlrTool
195: .error(
196: "Value for testLiterals must be true or false",
197: grammar.getFilename(), key
198: .getLine(), key.getColumn());
199: }
200: }
201: } else if (key.getText().equals("ignore")) {
202: if (!(grammar instanceof LexerGrammar)) {
203: grammar.antlrTool.error(
204: "ignore option only valid for lexer rules",
205: grammar.getFilename(), key.getLine(), key
206: .getColumn());
207: } else {
208: ignoreRule = value.getText();
209: }
210: } else if (key.getText().equals("paraphrase")) {
211: if (!(grammar instanceof LexerGrammar)) {
212: grammar.antlrTool.error(
213: "paraphrase option only valid for lexer rules",
214: grammar.getFilename(), key.getLine(), key
215: .getColumn());
216: } else {
217: // find token def associated with this rule
218: TokenSymbol ts = grammar.tokenManager
219: .getTokenSymbol(ruleName);
220: if (ts == null) {
221: grammar.antlrTool
222: .fatalError("Cannot find token associated with rule "
223: + ruleName);
224: }
225: ts.setParaphrase(value.getText());
226: }
227: } else if (key.getText().equals("generateAmbigWarnings")) {
228: if (value.getText().equals("true")) {
229: generateAmbigWarnings = true;
230: } else if (value.getText().equals("false")) {
231: generateAmbigWarnings = false;
232: } else {
233: grammar.antlrTool
234: .error(
235: "Value for generateAmbigWarnings must be true or false",
236: grammar.getFilename(), key.getLine(),
237: key.getColumn());
238: }
239: } else {
240: grammar.antlrTool.error("Invalid rule option: "
241: + key.getText(), grammar.getFilename(), key
242: .getLine(), key.getColumn());
243: }
244: }
245:
246: public String toString() {
247: String s = " FOLLOW={";
248: Lookahead cache[] = endNode.cache;
249: int k = grammar.maxk;
250: boolean allNull = true;
251: for (int j = 1; j <= k; j++) {
252: if (cache[j] == null)
253: continue;
254: s += cache[j].toString(",", grammar.tokenManager
255: .getVocabulary());
256: allNull = false;
257: if (j < k && cache[j + 1] != null)
258: s += ";";
259: }
260: s += "}";
261: if (allNull)
262: s = "";
263: return ruleName + ": " + super .toString() + " ;" + s;
264: }
265: }
|