• 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 				for (Grammar.LabelElementPair pair : r.labelNameSpace.values()) {
53 					checkForLabelConflict(r, pair.label);
54 				}
55 			}
56 			// walk rule scope attributes for Rule r
57 			if ( r.ruleScope!=null ) {
58 				List<Attribute> attributes = r.ruleScope.getAttributes();
59 				for (int j = 0; j < attributes.size(); j++) {
60 					Attribute attribute = attributes.get(j);
61 					checkForRuleScopeAttributeConflict(r, attribute);
62 				}
63 			}
64 			checkForRuleDefinitionProblems(r);
65 			checkForRuleArgumentAndReturnValueConflicts(r);
66 		}
67 		// check all global scopes against tokens
68 		for (AttributeScope scope : grammar.getGlobalScopes().values()) {
69 			checkForGlobalScopeTokenConflict(scope);
70 		}
71 		// check for missing rule, tokens
72 		lookForReferencesToUndefinedSymbols();
73 	}
74 
checkForRuleArgumentAndReturnValueConflicts(Rule r)75 	protected void checkForRuleArgumentAndReturnValueConflicts(Rule r) {
76 		if ( r.returnScope!=null ) {
77 			Set<String> conflictingKeys = r.returnScope.intersection(r.parameterScope);
78 			if (conflictingKeys!=null) {
79 				for (String key : conflictingKeys) {
80 					ErrorManager.grammarError(
81 						ErrorManager.MSG_ARG_RETVAL_CONFLICT,
82 						grammar,
83 						r.tree.getToken(),
84 						key,
85 						r.name);
86 				}
87 			}
88 		}
89 	}
90 
checkForRuleDefinitionProblems(Rule r)91 	protected void checkForRuleDefinitionProblems(Rule r) {
92 		String ruleName = r.name;
93 		Token ruleToken = r.tree.getToken();
94 		int msgID = 0;
95 		if ( (grammar.type==Grammar.PARSER||grammar.type==Grammar.TREE_PARSER) &&
96 			 Character.isUpperCase(ruleName.charAt(0)) )
97 		{
98 			msgID = ErrorManager.MSG_LEXER_RULES_NOT_ALLOWED;
99         }
100         else if ( grammar.type==Grammar.LEXER &&
101 			      Character.isLowerCase(ruleName.charAt(0)) &&
102 			      !r.isSynPred )
103 		{
104 			msgID = ErrorManager.MSG_PARSER_RULES_NOT_ALLOWED;
105         }
106 		else if ( grammar.getGlobalScope(ruleName)!=null ) {
107 			msgID = ErrorManager.MSG_SYMBOL_CONFLICTS_WITH_GLOBAL_SCOPE;
108 		}
109 		if ( msgID!=0 ) {
110 			ErrorManager.grammarError(msgID, grammar, ruleToken, ruleName);
111 		}
112 	}
113 
114 	/** If ref to undefined rule, give error at first occurrence.
115 	 *
116 	 *  Give error if you cannot find the scope override on a rule reference.
117 	 *
118 	 *  If you ref ID in a combined grammar and don't define ID as a lexer rule
119 	 *  it is an error.
120 	 */
lookForReferencesToUndefinedSymbols()121 	protected void lookForReferencesToUndefinedSymbols() {
122 		// for each rule ref, ask if there is a rule definition
123 		for (GrammarAST refAST : grammar.ruleRefs) {
124 			Token tok = refAST.token;
125 			String ruleName = tok.getText();
126 			Rule localRule = grammar.getLocallyDefinedRule(ruleName);
127 			Rule rule = grammar.getRule(ruleName);
128 			if ( localRule==null && rule!=null ) { // imported rule?
129 				grammar.delegatedRuleReferences.add(rule);
130 				rule.imported = true;
131 			}
132 			if ( rule==null && grammar.getTokenType(ruleName)!=Label.EOF ) {
133 				ErrorManager.grammarError(ErrorManager.MSG_UNDEFINED_RULE_REF,
134 										  grammar,
135 										  tok,
136 										  ruleName);
137 			}
138         }
139 		if ( grammar.type==Grammar.COMBINED ) {
140 			// if we're a combined grammar, we know which token IDs have no
141 			// associated lexer rule.
142 			for (Token tok : grammar.tokenIDRefs) {
143 				String tokenID = tok.getText();
144 				if ( !grammar.composite.lexerRules.contains(tokenID) &&
145 					 grammar.getTokenType(tokenID)!=Label.EOF )
146 				{
147 					ErrorManager.grammarWarning(ErrorManager.MSG_NO_TOKEN_DEFINITION,
148 												grammar,
149 												tok,
150 												tokenID);
151 				}
152 			}
153 		}
154 		// check scopes and scoped rule refs
155 		for (GrammarAST scopeAST : grammar.scopedRuleRefs) { // ^(DOT ID atom)
156 			Grammar scopeG = grammar.composite.getGrammar(scopeAST.getText());
157 			GrammarAST refAST = (GrammarAST)scopeAST.getChild(1);
158 			String ruleName = refAST.getText();
159 			if ( scopeG==null ) {
160 				ErrorManager.grammarError(ErrorManager.MSG_NO_SUCH_GRAMMAR_SCOPE,
161 										  grammar,
162 										  scopeAST.getToken(),
163 										  scopeAST.getText(),
164 										  ruleName);
165 			}
166 			else {
167 				Rule rule = grammar.getRule(scopeG.name, ruleName);
168 				if ( rule==null ) {
169 					ErrorManager.grammarError(ErrorManager.MSG_NO_SUCH_RULE_IN_SCOPE,
170 											  grammar,
171 											  scopeAST.getToken(),
172 											  scopeAST.getText(),
173 											  ruleName);
174 				}
175 			}
176 		}
177 	}
178 
checkForGlobalScopeTokenConflict(AttributeScope scope)179 	protected void checkForGlobalScopeTokenConflict(AttributeScope scope) {
180 		if ( grammar.getTokenType(scope.getName())!=Label.INVALID ) {
181 			ErrorManager.grammarError(ErrorManager.MSG_SYMBOL_CONFLICTS_WITH_GLOBAL_SCOPE,
182 									  grammar, null, scope.getName());
183 		}
184 	}
185 
186 	/** Check for collision of a rule-scope dynamic attribute with:
187 	 *  arg, return value, rule name itself.  Labels are checked elsewhere.
188 	 */
checkForRuleScopeAttributeConflict(Rule r, Attribute attribute)189 	public void checkForRuleScopeAttributeConflict(Rule r, Attribute attribute) {
190 		int msgID = 0;
191 		Object arg2 = null;
192 		String attrName = attribute.name;
193 		if ( r.name.equals(attrName) ) {
194 			msgID = ErrorManager.MSG_ATTRIBUTE_CONFLICTS_WITH_RULE;
195 			arg2 = r.name;
196 		}
197 		else if ( (r.returnScope!=null&&r.returnScope.getAttribute(attrName)!=null) ||
198 				  (r.parameterScope!=null&&r.parameterScope.getAttribute(attrName)!=null) )
199 		{
200 			msgID = ErrorManager.MSG_ATTRIBUTE_CONFLICTS_WITH_RULE_ARG_RETVAL;
201 			arg2 = r.name;
202 		}
203 		if ( msgID!=0 ) {
204 			ErrorManager.grammarError(msgID,grammar,r.tree.getToken(),attrName,arg2);
205 		}
206 	}
207 
208 	/** Make sure a label doesn't conflict with another symbol.
209 	 *  Labels must not conflict with: rules, tokens, scope names,
210 	 *  return values, parameters, and rule-scope dynamic attributes
211 	 *  defined in surrounding rule.
212 	 */
checkForLabelConflict(Rule r, Token label)213 	protected void checkForLabelConflict(Rule r, Token label) {
214 		int msgID = 0;
215 		Object arg2 = null;
216 		if ( grammar.getGlobalScope(label.getText())!=null ) {
217 			msgID = ErrorManager.MSG_SYMBOL_CONFLICTS_WITH_GLOBAL_SCOPE;
218 		}
219 		else if ( grammar.getRule(label.getText())!=null ) {
220 			msgID = ErrorManager.MSG_LABEL_CONFLICTS_WITH_RULE;
221 		}
222 		else if ( grammar.getTokenType(label.getText())!=Label.INVALID ) {
223 			msgID = ErrorManager.MSG_LABEL_CONFLICTS_WITH_TOKEN;
224 		}
225 		else if ( r.ruleScope!=null && r.ruleScope.getAttribute(label.getText())!=null ) {
226 			msgID = ErrorManager.MSG_LABEL_CONFLICTS_WITH_RULE_SCOPE_ATTRIBUTE;
227 			arg2 = r.name;
228 		}
229 		else if ( (r.returnScope!=null&&r.returnScope.getAttribute(label.getText())!=null) ||
230 				  (r.parameterScope!=null&&r.parameterScope.getAttribute(label.getText())!=null) )
231 		{
232 			msgID = ErrorManager.MSG_LABEL_CONFLICTS_WITH_RULE_ARG_RETVAL;
233 			arg2 = r.name;
234 		}
235 		if ( msgID!=0 ) {
236 			ErrorManager.grammarError(msgID,grammar,label,label.getText(),arg2);
237 		}
238 	}
239 
240 	/** If type of previous label differs from new label's type, that's an error.
241 	 */
checkForLabelTypeMismatch(Rule r, Token label, int type)242 	public boolean checkForLabelTypeMismatch(Rule r, Token label, int type) {
243 		Grammar.LabelElementPair prevLabelPair =
244 			r.labelNameSpace.get(label.getText());
245 		if ( prevLabelPair!=null ) {
246 			// label already defined; if same type, no problem
247 			if ( prevLabelPair.type != type ) {
248 				String typeMismatchExpr =
249 					Grammar.LabelTypeToString[type]+"!="+
250 					Grammar.LabelTypeToString[prevLabelPair.type];
251 				ErrorManager.grammarError(
252 					ErrorManager.MSG_LABEL_TYPE_CONFLICT,
253 					grammar,
254 					label,
255 					label.getText(),
256 					typeMismatchExpr);
257 				return true;
258 			}
259 		}
260 		return false;
261 	}
262 }
263