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 29 package org.antlr.tool; 30 31 import org.antlr.codegen.CodeGenerator; 32 import org.antlr.runtime.Token; 33 34 import java.util.*; 35 36 /** Track the attributes within a scope. A named scoped has just its list 37 * of attributes. Each rule has potentially 3 scopes: return values, 38 * parameters, and an implicitly-named scope (i.e., a scope defined in a rule). 39 * Implicitly-defined scopes are named after the rule; rules and scopes then 40 * must live in the same name space--no collisions allowed. 41 */ 42 public class AttributeScope { 43 44 /** All token scopes (token labels) share the same fixed scope of 45 * of predefined attributes. I keep this out of the runtime.Token 46 * object to avoid a runtime space burden. 47 */ 48 public static AttributeScope tokenScope = new AttributeScope("Token",null); 49 static { 50 tokenScope.addAttribute("text", null); 51 tokenScope.addAttribute("type", null); 52 tokenScope.addAttribute("line", null); 53 tokenScope.addAttribute("index", null); 54 tokenScope.addAttribute("pos", null); 55 tokenScope.addAttribute("channel", null); 56 tokenScope.addAttribute("tree", null); 57 tokenScope.addAttribute("int", null); 58 } 59 60 /** This scope is associated with which input token (for error handling)? */ 61 public Token derivedFromToken; 62 63 public Grammar grammar; 64 65 /** The scope name */ 66 private String name; 67 68 /** Not a rule scope, but visible to all rules "scope symbols { ...}" */ 69 public boolean isDynamicGlobalScope; 70 71 /** Visible to all rules, but defined in rule "scope { int i; }" */ 72 public boolean isDynamicRuleScope; 73 74 public boolean isParameterScope; 75 76 public boolean isReturnScope; 77 78 public boolean isPredefinedRuleScope; 79 80 public boolean isPredefinedLexerRuleScope; 81 82 /** The list of Attribute objects */ 83 protected LinkedHashMap<String,Attribute> attributes = new LinkedHashMap(); 84 85 /* Placeholder for compatibility with the CSharp3 target. */ 86 public LinkedHashMap<String, GrammarAST> actions = new LinkedHashMap(); 87 AttributeScope(String name, Token derivedFromToken)88 public AttributeScope(String name, Token derivedFromToken) { 89 this(null,name,derivedFromToken); 90 } 91 AttributeScope(Grammar grammar, String name, Token derivedFromToken)92 public AttributeScope(Grammar grammar, String name, Token derivedFromToken) { 93 this.grammar = grammar; 94 this.name = name; 95 this.derivedFromToken = derivedFromToken; 96 } 97 getName()98 public String getName() { 99 if ( isParameterScope ) { 100 return name+"_parameter"; 101 } 102 else if ( isReturnScope ) { 103 return name+"_return"; 104 } 105 return name; 106 } 107 108 /** From a chunk of text holding the definitions of the attributes, 109 * pull them apart and create an Attribute for each one. Add to 110 * the list of attributes for this scope. Pass in the character 111 * that terminates a definition such as ',' or ';'. For example, 112 * 113 * scope symbols { 114 * int n; 115 * List names; 116 * } 117 * 118 * would pass in definitions equal to the text in between {...} and 119 * separator=';'. It results in two Attribute objects. 120 */ addAttributes(String definitions, int separator)121 public void addAttributes(String definitions, int separator) { 122 List<String> attrs = new ArrayList<String>(); 123 CodeGenerator.getListOfArgumentsFromAction(definitions,0,-1,separator,attrs); 124 for (String a : attrs) { 125 Attribute attr = new Attribute(a); 126 if ( !isReturnScope && attr.initValue!=null ) { 127 ErrorManager.grammarError(ErrorManager.MSG_ARG_INIT_VALUES_ILLEGAL, 128 grammar, 129 derivedFromToken, 130 attr.name); 131 attr.initValue=null; // wipe it out 132 } 133 attributes.put(attr.name, attr); 134 } 135 } 136 addAttribute(String name, String decl)137 public void addAttribute(String name, String decl) { 138 attributes.put(name, new Attribute(name,decl)); 139 } 140 141 /** Given @scope::name {action} define it for this attribute scope. Later, 142 * the code generator will ask for the actions table. 143 */ defineNamedAction(GrammarAST nameAST, GrammarAST actionAST)144 public final void defineNamedAction(GrammarAST nameAST, GrammarAST actionAST) 145 { 146 String actionName = nameAST.getText(); 147 GrammarAST a = actions.get(actionName); 148 if (a != null) { 149 ErrorManager.grammarError(ErrorManager.MSG_ACTION_REDEFINITION, 150 grammar, 151 nameAST.getToken(), 152 nameAST.getText()); 153 } else { 154 actions.put(actionName, actionAST); 155 } 156 } 157 getAttribute(String name)158 public Attribute getAttribute(String name) { 159 return (Attribute)attributes.get(name); 160 } 161 162 /** Used by templates to get all attributes */ getAttributes()163 public List<Attribute> getAttributes() { 164 List<Attribute> a = new ArrayList<Attribute>(); 165 a.addAll(attributes.values()); 166 return a; 167 } 168 169 /** Return the set of keys that collide from 170 * this and other. 171 */ intersection(AttributeScope other)172 public Set intersection(AttributeScope other) { 173 if ( other==null || other.size()==0 || size()==0 ) { 174 return null; 175 } 176 Set inter = new HashSet(); 177 Set thisKeys = attributes.keySet(); 178 for (Iterator it = thisKeys.iterator(); it.hasNext();) { 179 String key = (String) it.next(); 180 if ( other.attributes.get(key)!=null ) { 181 inter.add(key); 182 } 183 } 184 if ( inter.size()==0 ) { 185 return null; 186 } 187 return inter; 188 } 189 size()190 public int size() { 191 return attributes==null?0:attributes.size(); 192 } 193 toString()194 public String toString() { 195 return (isDynamicGlobalScope?"global ":"")+getName()+":"+attributes; 196 } 197 } 198