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