| /* |
| * [The "BSD license"] |
| * Copyright (c) 2010 Terence Parr |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. The name of the author may not be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
| * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
| * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| package org.antlr.tool; |
| |
| import org.antlr.codegen.CodeGenerator; |
| import org.antlr.runtime.Token; |
| |
| import java.util.*; |
| |
| /** Track the attributes within a scope. A named scoped has just its list |
| * of attributes. Each rule has potentially 3 scopes: return values, |
| * parameters, and an implicitly-named scope (i.e., a scope defined in a rule). |
| * Implicitly-defined scopes are named after the rule; rules and scopes then |
| * must live in the same name space--no collisions allowed. |
| */ |
| public class AttributeScope { |
| |
| /** All token scopes (token labels) share the same fixed scope of |
| * of predefined attributes. I keep this out of the runtime.Token |
| * object to avoid a runtime space burden. |
| */ |
| public static AttributeScope tokenScope = new AttributeScope("Token",null); |
| static { |
| tokenScope.addAttribute("text", null); |
| tokenScope.addAttribute("type", null); |
| tokenScope.addAttribute("line", null); |
| tokenScope.addAttribute("index", null); |
| tokenScope.addAttribute("pos", null); |
| tokenScope.addAttribute("channel", null); |
| tokenScope.addAttribute("tree", null); |
| tokenScope.addAttribute("int", null); |
| } |
| |
| /** This scope is associated with which input token (for error handling)? */ |
| public Token derivedFromToken; |
| |
| public Grammar grammar; |
| |
| /** The scope name */ |
| private String name; |
| |
| /** Not a rule scope, but visible to all rules "scope symbols { ...}" */ |
| public boolean isDynamicGlobalScope; |
| |
| /** Visible to all rules, but defined in rule "scope { int i; }" */ |
| public boolean isDynamicRuleScope; |
| |
| public boolean isParameterScope; |
| |
| public boolean isReturnScope; |
| |
| public boolean isPredefinedRuleScope; |
| |
| public boolean isPredefinedLexerRuleScope; |
| |
| /** The list of Attribute objects */ |
| protected LinkedHashMap<String,Attribute> attributes = new LinkedHashMap(); |
| |
| /* Placeholder for compatibility with the CSharp3 target. */ |
| public LinkedHashMap<String, GrammarAST> actions = new LinkedHashMap(); |
| |
| public AttributeScope(String name, Token derivedFromToken) { |
| this(null,name,derivedFromToken); |
| } |
| |
| public AttributeScope(Grammar grammar, String name, Token derivedFromToken) { |
| this.grammar = grammar; |
| this.name = name; |
| this.derivedFromToken = derivedFromToken; |
| } |
| |
| public String getName() { |
| if ( isParameterScope ) { |
| return name+"_parameter"; |
| } |
| else if ( isReturnScope ) { |
| return name+"_return"; |
| } |
| return name; |
| } |
| |
| /** From a chunk of text holding the definitions of the attributes, |
| * pull them apart and create an Attribute for each one. Add to |
| * the list of attributes for this scope. Pass in the character |
| * that terminates a definition such as ',' or ';'. For example, |
| * |
| * scope symbols { |
| * int n; |
| * List names; |
| * } |
| * |
| * would pass in definitions equal to the text in between {...} and |
| * separator=';'. It results in two Attribute objects. |
| */ |
| public void addAttributes(String definitions, int separator) { |
| List<String> attrs = new ArrayList<String>(); |
| CodeGenerator.getListOfArgumentsFromAction(definitions,0,-1,separator,attrs); |
| for (String a : attrs) { |
| Attribute attr = new Attribute(a); |
| if ( !isReturnScope && attr.initValue!=null ) { |
| ErrorManager.grammarError(ErrorManager.MSG_ARG_INIT_VALUES_ILLEGAL, |
| grammar, |
| derivedFromToken, |
| attr.name); |
| attr.initValue=null; // wipe it out |
| } |
| attributes.put(attr.name, attr); |
| } |
| } |
| |
| public void addAttribute(String name, String decl) { |
| attributes.put(name, new Attribute(name,decl)); |
| } |
| |
| /** Given @scope::name {action} define it for this attribute scope. Later, |
| * the code generator will ask for the actions table. |
| */ |
| public final void defineNamedAction(GrammarAST nameAST, GrammarAST actionAST) |
| { |
| String actionName = nameAST.getText(); |
| GrammarAST a = actions.get(actionName); |
| if (a != null) { |
| ErrorManager.grammarError(ErrorManager.MSG_ACTION_REDEFINITION, |
| grammar, |
| nameAST.getToken(), |
| nameAST.getText()); |
| } else { |
| actions.put(actionName, actionAST); |
| } |
| } |
| |
| public Attribute getAttribute(String name) { |
| return (Attribute)attributes.get(name); |
| } |
| |
| /** Used by templates to get all attributes */ |
| public List<Attribute> getAttributes() { |
| List<Attribute> a = new ArrayList<Attribute>(); |
| a.addAll(attributes.values()); |
| return a; |
| } |
| |
| /** Return the set of keys that collide from |
| * this and other. |
| */ |
| public Set intersection(AttributeScope other) { |
| if ( other==null || other.size()==0 || size()==0 ) { |
| return null; |
| } |
| Set inter = new HashSet(); |
| Set thisKeys = attributes.keySet(); |
| for (Iterator it = thisKeys.iterator(); it.hasNext();) { |
| String key = (String) it.next(); |
| if ( other.attributes.get(key)!=null ) { |
| inter.add(key); |
| } |
| } |
| if ( inter.size()==0 ) { |
| return null; |
| } |
| return inter; |
| } |
| |
| public int size() { |
| return attributes==null?0:attributes.size(); |
| } |
| |
| public String toString() { |
| return (isDynamicGlobalScope?"global ":"")+getName()+":"+attributes; |
| } |
| } |