• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * [The "BSD license"]
3  *  Copyright (c) 2010 Terence Parr
4  *  All rights reserved.
5  *
6  *  Redistribution and use in source and binary forms, with or without
7  *  modification, are permitted provided that the following conditions
8  *  are met:
9  *  1. Redistributions of source code must retain the above copyright
10  *      notice, this list of conditions and the following disclaimer.
11  *  2. Redistributions in binary form must reproduce the above copyright
12  *      notice, this list of conditions and the following disclaimer in the
13  *      documentation and/or other materials provided with the distribution.
14  *  3. The name of the author may not be used to endorse or promote products
15  *      derived from this software without specific prior written permission.
16  *
17  *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 package org.antlr.tool;
29 
30 import org.antlr.analysis.Label;
31 import org.antlr.runtime.Token;
32 
33 import java.util.Iterator;
34 import java.util.List;
35 import java.util.Set;
36 
37 public class NameSpaceChecker {
38 	protected Grammar grammar;
39 
NameSpaceChecker(Grammar grammar)40 	public NameSpaceChecker(Grammar grammar) {
41 		this.grammar = grammar;
42 	}
43 
checkConflicts()44 	public void checkConflicts() {
45 		for (int i = CompositeGrammar.MIN_RULE_INDEX; i < grammar.composite.ruleIndexToRuleList.size(); i++) {
46 			Rule r = grammar.composite.ruleIndexToRuleList.elementAt(i);
47 			if ( r==null ) {
48 				continue;
49 			}
50 			// walk all labels for Rule r
51 			if ( r.labelNameSpace!=null ) {
52 				Iterator it = r.labelNameSpace.values().iterator();
53 				while ( it.hasNext() ) {
54 					Grammar.LabelElementPair pair = (Grammar.LabelElementPair) it.next();
55 					checkForLabelConflict(r, pair.label);
56 				}
57 			}
58 			// walk rule scope attributes for Rule r
59 			if ( r.ruleScope!=null ) {
60 				List attributes = r.ruleScope.getAttributes();
61 				for (int j = 0; j < attributes.size(); j++) {
62 					Attribute attribute = (Attribute) attributes.get(j);
63 					checkForRuleScopeAttributeConflict(r, attribute);
64 				}
65 			}
66 			checkForRuleDefinitionProblems(r);
67 			checkForRuleArgumentAndReturnValueConflicts(r);
68 		}
69 		// check all global scopes against tokens
70 		Iterator it = grammar.getGlobalScopes().values().iterator();
71 		while (it.hasNext()) {
72 			AttributeScope scope = (AttributeScope) it.next();
73 			checkForGlobalScopeTokenConflict(scope);
74 		}
75 		// check for missing rule, tokens
76 		lookForReferencesToUndefinedSymbols();
77 	}
78 
checkForRuleArgumentAndReturnValueConflicts(Rule r)79 	protected void checkForRuleArgumentAndReturnValueConflicts(Rule r) {
80 		if ( r.returnScope!=null ) {
81 			Set conflictingKeys = r.returnScope.intersection(r.parameterScope);
82 			if (conflictingKeys!=null) {
83 				for (Iterator it = conflictingKeys.iterator(); it.hasNext();) {
84 					String key = (String) it.next();
85 					ErrorManager.grammarError(
86 						ErrorManager.MSG_ARG_RETVAL_CONFLICT,
87 						grammar,
88 						r.tree.getToken(),
89 						key,
90 						r.name);
91 				}
92 			}
93 		}
94 	}
95 
checkForRuleDefinitionProblems(Rule r)96 	protected void checkForRuleDefinitionProblems(Rule r) {
97 		String ruleName = r.name;
98 		Token ruleToken = r.tree.getToken();
99 		int msgID = 0;
100 		if ( (grammar.type==Grammar.PARSER||grammar.type==Grammar.TREE_PARSER) &&
101 			 Character.isUpperCase(ruleName.charAt(0)) )
102 		{
103 			msgID = ErrorManager.MSG_LEXER_RULES_NOT_ALLOWED;
104         }
105         else if ( grammar.type==Grammar.LEXER &&
106 			      Character.isLowerCase(ruleName.charAt(0)) &&
107 			      !r.isSynPred )
108 		{
109 			msgID = ErrorManager.MSG_PARSER_RULES_NOT_ALLOWED;
110         }
111 		else if ( grammar.getGlobalScope(ruleName)!=null ) {
112 			msgID = ErrorManager.MSG_SYMBOL_CONFLICTS_WITH_GLOBAL_SCOPE;
113 		}
114 		if ( msgID!=0 ) {
115 			ErrorManager.grammarError(msgID, grammar, ruleToken, ruleName);
116 		}
117 	}
118 
119 	/** If ref to undefined rule, give error at first occurrence.
120 	 *
121 	 *  Give error if you cannot find the scope override on a rule reference.
122 	 *
123 	 *  If you ref ID in a combined grammar and don't define ID as a lexer rule
124 	 *  it is an error.
125 	 */
lookForReferencesToUndefinedSymbols()126 	protected void lookForReferencesToUndefinedSymbols() {
127 		// for each rule ref, ask if there is a rule definition
128 		for (Iterator iter = grammar.ruleRefs.iterator(); iter.hasNext();) {
129 			GrammarAST refAST = (GrammarAST)iter.next();
130 			Token tok = refAST.token;
131 			String ruleName = tok.getText();
132 			Rule localRule = grammar.getLocallyDefinedRule(ruleName);
133 			Rule rule = grammar.getRule(ruleName);
134 			if ( localRule==null && rule!=null ) { // imported rule?
135 				grammar.delegatedRuleReferences.add(rule);
136 				rule.imported = true;
137 			}
138 			if ( rule==null && grammar.getTokenType(ruleName)!=Label.EOF ) {
139 				ErrorManager.grammarError(ErrorManager.MSG_UNDEFINED_RULE_REF,
140 										  grammar,
141 										  tok,
142 										  ruleName);
143 			}
144         }
145 		if ( grammar.type==Grammar.COMBINED ) {
146 			// if we're a combined grammar, we know which token IDs have no
147 			// associated lexer rule.
148 			for (Iterator iter = grammar.tokenIDRefs.iterator(); iter.hasNext();) {
149 				Token tok = (Token) iter.next();
150 				String tokenID = tok.getText();
151 				if ( !grammar.composite.lexerRules.contains(tokenID) &&
152 					 grammar.getTokenType(tokenID)!=Label.EOF )
153 				{
154 					ErrorManager.grammarWarning(ErrorManager.MSG_NO_TOKEN_DEFINITION,
155 												grammar,
156 												tok,
157 												tokenID);
158 				}
159 			}
160 		}
161 		// check scopes and scoped rule refs
162 		for (Iterator it = grammar.scopedRuleRefs.iterator(); it.hasNext();) {
163 			GrammarAST scopeAST = (GrammarAST)it.next(); // ^(DOT ID atom)
164 			Grammar scopeG = grammar.composite.getGrammar(scopeAST.getText());
165 			GrammarAST refAST = (GrammarAST)scopeAST.getChild(1);
166 			String ruleName = refAST.getText();
167 			if ( scopeG==null ) {
168 				ErrorManager.grammarError(ErrorManager.MSG_NO_SUCH_GRAMMAR_SCOPE,
169 										  grammar,
170 										  scopeAST.getToken(),
171 										  scopeAST.getText(),
172 										  ruleName);
173 			}
174 			else {
175 				Rule rule = grammar.getRule(scopeG.name, ruleName);
176 				if ( rule==null ) {
177 					ErrorManager.grammarError(ErrorManager.MSG_NO_SUCH_RULE_IN_SCOPE,
178 											  grammar,
179 											  scopeAST.getToken(),
180 											  scopeAST.getText(),
181 											  ruleName);
182 				}
183 			}
184 		}
185 	}
186 
checkForGlobalScopeTokenConflict(AttributeScope scope)187 	protected void checkForGlobalScopeTokenConflict(AttributeScope scope) {
188 		if ( grammar.getTokenType(scope.getName())!=Label.INVALID ) {
189 			ErrorManager.grammarError(ErrorManager.MSG_SYMBOL_CONFLICTS_WITH_GLOBAL_SCOPE,
190 									  grammar, null, scope.getName());
191 		}
192 	}
193 
194 	/** Check for collision of a rule-scope dynamic attribute with:
195 	 *  arg, return value, rule name itself.  Labels are checked elsewhere.
196 	 */
checkForRuleScopeAttributeConflict(Rule r, Attribute attribute)197 	public void checkForRuleScopeAttributeConflict(Rule r, Attribute attribute) {
198 		int msgID = 0;
199 		Object arg2 = null;
200 		String attrName = attribute.name;
201 		if ( r.name.equals(attrName) ) {
202 			msgID = ErrorManager.MSG_ATTRIBUTE_CONFLICTS_WITH_RULE;
203 			arg2 = r.name;
204 		}
205 		else if ( (r.returnScope!=null&&r.returnScope.getAttribute(attrName)!=null) ||
206 				  (r.parameterScope!=null&&r.parameterScope.getAttribute(attrName)!=null) )
207 		{
208 			msgID = ErrorManager.MSG_ATTRIBUTE_CONFLICTS_WITH_RULE_ARG_RETVAL;
209 			arg2 = r.name;
210 		}
211 		if ( msgID!=0 ) {
212 			ErrorManager.grammarError(msgID,grammar,r.tree.getToken(),attrName,arg2);
213 		}
214 	}
215 
216 	/** Make sure a label doesn't conflict with another symbol.
217 	 *  Labels must not conflict with: rules, tokens, scope names,
218 	 *  return values, parameters, and rule-scope dynamic attributes
219 	 *  defined in surrounding rule.
220 	 */
checkForLabelConflict(Rule r, Token label)221 	protected void checkForLabelConflict(Rule r, Token label) {
222 		int msgID = 0;
223 		Object arg2 = null;
224 		if ( grammar.getGlobalScope(label.getText())!=null ) {
225 			msgID = ErrorManager.MSG_SYMBOL_CONFLICTS_WITH_GLOBAL_SCOPE;
226 		}
227 		else if ( grammar.getRule(label.getText())!=null ) {
228 			msgID = ErrorManager.MSG_LABEL_CONFLICTS_WITH_RULE;
229 		}
230 		else if ( grammar.getTokenType(label.getText())!=Label.INVALID ) {
231 			msgID = ErrorManager.MSG_LABEL_CONFLICTS_WITH_TOKEN;
232 		}
233 		else if ( r.ruleScope!=null && r.ruleScope.getAttribute(label.getText())!=null ) {
234 			msgID = ErrorManager.MSG_LABEL_CONFLICTS_WITH_RULE_SCOPE_ATTRIBUTE;
235 			arg2 = r.name;
236 		}
237 		else if ( (r.returnScope!=null&&r.returnScope.getAttribute(label.getText())!=null) ||
238 				  (r.parameterScope!=null&&r.parameterScope.getAttribute(label.getText())!=null) )
239 		{
240 			msgID = ErrorManager.MSG_LABEL_CONFLICTS_WITH_RULE_ARG_RETVAL;
241 			arg2 = r.name;
242 		}
243 		if ( msgID!=0 ) {
244 			ErrorManager.grammarError(msgID,grammar,label,label.getText(),arg2);
245 		}
246 	}
247 
248 	/** If type of previous label differs from new label's type, that's an error.
249 	 */
checkForLabelTypeMismatch(Rule r, Token label, int type)250 	public boolean checkForLabelTypeMismatch(Rule r, Token label, int type) {
251 		Grammar.LabelElementPair prevLabelPair =
252 			(Grammar.LabelElementPair)r.labelNameSpace.get(label.getText());
253 		if ( prevLabelPair!=null ) {
254 			// label already defined; if same type, no problem
255 			if ( prevLabelPair.type != type ) {
256 				String typeMismatchExpr =
257 					Grammar.LabelTypeToString[type]+"!="+
258 					Grammar.LabelTypeToString[prevLabelPair.type];
259 				ErrorManager.grammarError(
260 					ErrorManager.MSG_LABEL_TYPE_CONFLICT,
261 					grammar,
262 					label,
263 					label.getText(),
264 					typeMismatchExpr);
265 				return true;
266 			}
267 		}
268 		return false;
269 	}
270 }
271