001: /*
002: [The "BSD licence"]
003: Copyright (c) 2005-2006 Terence Parr
004: All rights reserved.
005:
006: Redistribution and use in source and binary forms, with or without
007: modification, are permitted provided that the following conditions
008: are met:
009: 1. Redistributions of source code must retain the above copyright
010: notice, this list of conditions and the following disclaimer.
011: 2. Redistributions in binary form must reproduce the above copyright
012: notice, this list of conditions and the following disclaimer in the
013: documentation and/or other materials provided with the distribution.
014: 3. The name of the author may not be used to endorse or promote products
015: derived from this software without specific prior written permission.
016:
017: THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
018: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
019: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
020: IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
021: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
022: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
023: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
024: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
026: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: */
028: package org.antlr.tool;
029:
030: import antlr.Token;
031: import org.antlr.analysis.Label;
032:
033: import java.util.Iterator;
034: import java.util.List;
035: import java.util.Set;
036:
037: public class NameSpaceChecker {
038: protected Grammar grammar;
039:
040: public NameSpaceChecker(Grammar grammar) {
041: this .grammar = grammar;
042: }
043:
044: public void checkConflicts() {
045: for (int i = 0; i < grammar.ruleIndexToRuleList.size(); i++) {
046: String ruleName = (String) grammar.ruleIndexToRuleList
047: .elementAt(i);
048: if (ruleName == null) {
049: continue;
050: }
051: Rule r = grammar.getRule(ruleName);
052: // walk all labels for Rule r
053: if (r.labelNameSpace != null) {
054: Iterator it = r.labelNameSpace.values().iterator();
055: while (it.hasNext()) {
056: Grammar.LabelElementPair pair = (Grammar.LabelElementPair) it
057: .next();
058: checkForLabelConflict(r, pair.label);
059: }
060: }
061: // walk rule scope attributes for Rule r
062: if (r.ruleScope != null) {
063: List attributes = r.ruleScope.getAttributes();
064: for (int j = 0; j < attributes.size(); j++) {
065: Attribute attribute = (Attribute) attributes.get(j);
066: checkForRuleScopeAttributeConflict(r, attribute);
067: }
068: }
069: checkForRuleDefinitionProblems(r);
070: checkForRuleArgumentAndReturnValueConflicts(r);
071: }
072: // check all global scopes against tokens
073: Iterator it = grammar.getGlobalScopes().values().iterator();
074: while (it.hasNext()) {
075: AttributeScope scope = (AttributeScope) it.next();
076: checkForGlobalScopeTokenConflict(scope);
077: }
078: // check for missing rule, tokens
079: lookForReferencesToUndefinedSymbols();
080: }
081:
082: protected void checkForRuleArgumentAndReturnValueConflicts(Rule r) {
083: if (r.returnScope != null) {
084: Set conflictingKeys = r.returnScope
085: .intersection(r.parameterScope);
086: if (conflictingKeys != null) {
087: for (Iterator it = conflictingKeys.iterator(); it
088: .hasNext();) {
089: String key = (String) it.next();
090: ErrorManager.grammarError(
091: ErrorManager.MSG_ARG_RETVAL_CONFLICT,
092: grammar, r.tree.getToken(), key, r.name);
093: }
094: }
095: }
096: }
097:
098: protected void checkForRuleDefinitionProblems(Rule r) {
099: String ruleName = r.name;
100: antlr.Token ruleToken = r.tree.getToken();
101: int msgID = 0;
102: if (grammar.type == Grammar.PARSER
103: && Character.isUpperCase(ruleName.charAt(0))) {
104: msgID = ErrorManager.MSG_LEXER_RULES_NOT_ALLOWED;
105: } else if (grammar.type == Grammar.LEXER
106: && Character.isLowerCase(ruleName.charAt(0))
107: && !r.isSynPred) {
108: msgID = ErrorManager.MSG_PARSER_RULES_NOT_ALLOWED;
109: } else if (grammar.getGlobalScope(ruleName) != null) {
110: msgID = ErrorManager.MSG_SYMBOL_CONFLICTS_WITH_GLOBAL_SCOPE;
111: }
112: if (msgID != 0) {
113: ErrorManager.grammarError(msgID, grammar, ruleToken,
114: ruleName);
115: }
116: }
117:
118: /** If ref to undefined rule, give error at first occurrence.
119: *
120: * If you ref ID in a combined grammar and don't define ID as a lexer rule
121: * it is an error.
122: */
123: protected void lookForReferencesToUndefinedSymbols() {
124: // for each rule ref, ask if there is a rule definition
125: for (Iterator iter = grammar.ruleRefs.iterator(); iter
126: .hasNext();) {
127: Token tok = (Token) iter.next();
128: String ruleName = tok.getText();
129: if (grammar.getRule(ruleName) == null
130: && grammar.getTokenType(ruleName) != Label.EOF) {
131: ErrorManager.grammarError(
132: ErrorManager.MSG_UNDEFINED_RULE_REF, grammar,
133: tok, ruleName);
134: }
135: }
136: if (grammar.type == Grammar.COMBINED) {
137: for (Iterator iter = grammar.tokenIDRefs.iterator(); iter
138: .hasNext();) {
139: Token tok = (Token) iter.next();
140: String tokenID = tok.getText();
141: if (!grammar.lexerRules.contains(tokenID)
142: && grammar.getTokenType(tokenID) != Label.EOF) {
143: ErrorManager.grammarWarning(
144: ErrorManager.MSG_NO_TOKEN_DEFINITION,
145: grammar, tok, tokenID);
146: }
147: }
148: }
149: }
150:
151: protected void checkForGlobalScopeTokenConflict(AttributeScope scope) {
152: if (grammar.getTokenType(scope.getName()) != Label.INVALID) {
153: ErrorManager
154: .grammarError(
155: ErrorManager.MSG_SYMBOL_CONFLICTS_WITH_GLOBAL_SCOPE,
156: grammar, null, scope.getName());
157: }
158: }
159:
160: /** Check for collision of a rule-scope dynamic attribute with:
161: * arg, return value, rule name itself. Labels are checked elsewhere.
162: */
163: public void checkForRuleScopeAttributeConflict(Rule r,
164: Attribute attribute) {
165: int msgID = 0;
166: Object arg2 = null;
167: String attrName = attribute.name;
168: if (r.name.equals(attrName)) {
169: msgID = ErrorManager.MSG_ATTRIBUTE_CONFLICTS_WITH_RULE;
170: arg2 = r.name;
171: } else if ((r.returnScope != null && r.returnScope
172: .getAttribute(attrName) != null)
173: || (r.parameterScope != null && r.parameterScope
174: .getAttribute(attrName) != null)) {
175: msgID = ErrorManager.MSG_ATTRIBUTE_CONFLICTS_WITH_RULE_ARG_RETVAL;
176: arg2 = r.name;
177: }
178: if (msgID != 0) {
179: ErrorManager.grammarError(msgID, grammar,
180: r.tree.getToken(), attrName, arg2);
181: }
182: }
183:
184: /** Make sure a label doesn't conflict with another symbol.
185: * Labels must not conflict with: rules, tokens, scope names,
186: * return values, parameters, and rule-scope dynamic attributes
187: * defined in surrounding rule.
188: */
189: protected void checkForLabelConflict(Rule r, antlr.Token label) {
190: int msgID = 0;
191: Object arg2 = null;
192: if (grammar.getGlobalScope(label.getText()) != null) {
193: msgID = ErrorManager.MSG_SYMBOL_CONFLICTS_WITH_GLOBAL_SCOPE;
194: } else if (grammar.getRule(label.getText()) != null) {
195: msgID = ErrorManager.MSG_LABEL_CONFLICTS_WITH_RULE;
196: } else if (grammar.getTokenType(label.getText()) != Label.INVALID) {
197: msgID = ErrorManager.MSG_LABEL_CONFLICTS_WITH_TOKEN;
198: } else if (r.ruleScope != null
199: && r.ruleScope.getAttribute(label.getText()) != null) {
200: msgID = ErrorManager.MSG_LABEL_CONFLICTS_WITH_RULE_SCOPE_ATTRIBUTE;
201: arg2 = r.name;
202: } else if ((r.returnScope != null && r.returnScope
203: .getAttribute(label.getText()) != null)
204: || (r.parameterScope != null && r.parameterScope
205: .getAttribute(label.getText()) != null)) {
206: msgID = ErrorManager.MSG_LABEL_CONFLICTS_WITH_RULE_ARG_RETVAL;
207: arg2 = r.name;
208: }
209: if (msgID != 0) {
210: ErrorManager.grammarError(msgID, grammar, label, label
211: .getText(), arg2);
212: }
213: }
214:
215: /** If type of previous label differs from new label's type, that's an error.
216: */
217: public boolean checkForLabelTypeMismatch(Rule r, antlr.Token label,
218: int type) {
219: Grammar.LabelElementPair prevLabelPair = (Grammar.LabelElementPair) r.labelNameSpace
220: .get(label.getText());
221: if (prevLabelPair != null) {
222: // label already defined; if same type, no problem
223: if (prevLabelPair.type != type) {
224: String typeMismatchExpr = Grammar.LabelTypeToString[type]
225: + "!="
226: + Grammar.LabelTypeToString[prevLabelPair.type];
227: ErrorManager.grammarError(
228: ErrorManager.MSG_LABEL_TYPE_CONFLICT, grammar,
229: label, label.getText(), typeMismatchExpr);
230: return true;
231: }
232: }
233: return false;
234: }
235: }
|