001: /*
002: [The "BSD licence"]
003: Copyright (c) 2005-2006 Terence Parr
004: All rights reserved.
005:
006: Redistribution and use in source and binary forms, with or without
007: modification, are permitted provided that the following conditions
008: are met:
009: 1. Redistributions of source code must retain the above copyright
010: notice, this list of conditions and the following disclaimer.
011: 2. Redistributions in binary form must reproduce the above copyright
012: notice, this list of conditions and the following disclaimer in the
013: documentation and/or other materials provided with the distribution.
014: 3. The name of the author may not be used to endorse or promote products
015: derived from this software without specific prior written permission.
016:
017: THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
018: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
019: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
020: IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
021: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
022: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
023: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
024: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
026: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: */
028: package org.antlr.tool;
029:
030: import antlr.Token;
031:
032: import java.util.*;
033:
034: /** Track the attributes within a scope. A named scoped has just its list
035: * of attributes. Each rule has potentially 3 scopes: return values,
036: * parameters, and an implicitly-named scope (i.e., a scope defined in a rule).
037: * Implicitly-defined scopes are named after the rule; rules and scopes then
038: * must live in the same name space--no collisions allowed.
039: */
040: public class AttributeScope {
041:
042: /** All token scopes (token labels) share the same fixed scope of
043: * of predefined attributes. I keep this out of the runtime.Token
044: * object to avoid a runtime space burden.
045: */
046: public static AttributeScope tokenScope = new AttributeScope(
047: "Token", null);
048: static {
049: tokenScope.addAttribute("text", null);
050: tokenScope.addAttribute("type", null);
051: tokenScope.addAttribute("line", null);
052: tokenScope.addAttribute("index", null);
053: tokenScope.addAttribute("pos", null);
054: tokenScope.addAttribute("channel", null);
055: tokenScope.addAttribute("tree", null);
056: }
057:
058: /** This scope is associated with which input token (for error handling)? */
059: public Token derivedFromToken;
060:
061: public Grammar grammar;
062:
063: /** The scope name */
064: private String name;
065:
066: /** Not a rule scope, but visible to all rules "scope symbols { ...}" */
067: public boolean isDynamicGlobalScope;
068:
069: /** Visible to all rules, but defined in rule "scope { int i; }" */
070: public boolean isDynamicRuleScope;
071:
072: public boolean isParameterScope;
073:
074: public boolean isReturnScope;
075:
076: public boolean isPredefinedRuleScope;
077:
078: public boolean isPredefinedLexerRuleScope;
079:
080: /** The list of Attribute objects */
081:
082: protected LinkedHashMap attributes = new LinkedHashMap();
083:
084: public AttributeScope(String name, Token derivedFromToken) {
085: this (null, name, derivedFromToken);
086: }
087:
088: public AttributeScope(Grammar grammar, String name,
089: Token derivedFromToken) {
090: this .grammar = grammar;
091: this .name = name;
092: this .derivedFromToken = derivedFromToken;
093: }
094:
095: public String getName() {
096: if (isParameterScope) {
097: return name + "_parameter";
098: } else if (isReturnScope) {
099: return name + "_return";
100: }
101: return name;
102: }
103:
104: /** From a chunk of text holding the definitions of the attributes,
105: * pull them apart and create an Attribute for each one. Add to
106: * the list of attributes for this scope. Pass in the character
107: * that terminates a definition such as ',' or ';'. For example,
108: *
109: * scope symbols {
110: * int n;
111: * List names;
112: * }
113: *
114: * would pass in definitions equal to the text in between {...} and
115: * separator=';'. It results in two Attribute objects.
116: */
117: public void addAttributes(String definitions, String separator) {
118: StringTokenizer st = new StringTokenizer(definitions, separator);
119: while (st.hasMoreElements()) {
120: String decl = (String) st.nextElement();
121: decl = decl.trim();
122: if (decl.length() == 0) {
123: break; // final bit of whitespace; ignore
124: }
125: Attribute attr = new Attribute(decl);
126: if (!isReturnScope && attr.initValue != null) {
127: ErrorManager.grammarError(
128: ErrorManager.MSG_ARG_INIT_VALUES_ILLEGAL,
129: grammar, derivedFromToken, attr.name);
130: attr.initValue = null; // wipe it out
131: }
132: attributes.put(attr.name, attr);
133: }
134: }
135:
136: public void addAttribute(String name, String decl) {
137: attributes.put(name, new Attribute(name, decl));
138: }
139:
140: public Attribute getAttribute(String name) {
141: return (Attribute) attributes.get(name);
142: }
143:
144: /** Used by templates to get all attributes */
145: public List getAttributes() {
146: List a = new ArrayList();
147: a.addAll(attributes.values());
148: return a;
149: }
150:
151: /** Return the set of keys that collide from
152: * this and other.
153: */
154: public Set intersection(AttributeScope other) {
155: if (other == null || other.size() == 0 || size() == 0) {
156: return null;
157: }
158: Set inter = new HashSet();
159: Set this Keys = attributes.keySet();
160: for (Iterator it = this Keys.iterator(); it.hasNext();) {
161: String key = (String) it.next();
162: if (other.attributes.get(key) != null) {
163: inter.add(key);
164: }
165: }
166: if (inter.size() == 0) {
167: return null;
168: }
169: return inter;
170: }
171:
172: public int size() {
173: return attributes == null ? 0 : attributes.size();
174: }
175:
176: public String toString() {
177: return (isDynamicGlobalScope ? "global " : "") + getName()
178: + ":" + attributes;
179: }
180: }
|