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