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: /** Track the names of attributes define in arg lists, return values,
031: * scope blocks etc...
032: */
033: public class Attribute {
034: /** The entire declaration such as "String foo;" */
035: public String decl;
036:
037: /** The type; might be empty such as for Python which has no static typing */
038: public String type;
039:
040: /** The name of the attribute "foo" */
041: public String name;
042:
043: /** The optional attribute intialization expression */
044: public String initValue;
045:
046: public Attribute(String decl) {
047: extractAttribute(decl);
048: }
049:
050: public Attribute(String name, String decl) {
051: this .name = name;
052: this .decl = decl;
053: }
054:
055: /** For decls like "String foo" or "char *foo32[3]" compute the ID
056: * and type declarations. Also handle "int x=3" and 'T t = new T("foo")'
057: * but if the separator is ',' you cannot use ',' in the initvalue.
058: * AttributeScope.addAttributes takes care of the separation so we are
059: * free here to use from '=' to end of string as the expression.
060: *
061: * Set name, type, initvalue, and full decl instance vars.
062: */
063: protected void extractAttribute(String decl) {
064: if (decl == null) {
065: return;
066: }
067: boolean inID = false;
068: int start = -1;
069: int rightEdgeOfDeclarator = decl.length() - 1;
070: int equalsIndex = decl.indexOf('=');
071: if (equalsIndex > 0) {
072: // everything after the '=' is the init value
073: this .initValue = decl.substring(equalsIndex + 1, decl
074: .length());
075: rightEdgeOfDeclarator = equalsIndex - 1;
076: }
077: // walk backwards looking for start of an ID
078: for (int i = rightEdgeOfDeclarator; i >= 0; i--) {
079: // if we haven't found the end yet, keep going
080: if (!inID && Character.isLetterOrDigit(decl.charAt(i))) {
081: inID = true;
082: } else if (inID
083: && !(Character.isLetterOrDigit(decl.charAt(i)) || decl
084: .charAt(i) == '_')) {
085: start = i + 1;
086: break;
087: }
088: }
089: if (start < 0 && inID) {
090: start = 0;
091: }
092: if (start < 0) {
093: ErrorManager
094: .error(
095: ErrorManager.MSG_CANNOT_FIND_ATTRIBUTE_NAME_IN_DECL,
096: decl);
097: }
098: // walk forwards looking for end of an ID
099: int stop = -1;
100: for (int i = start; i <= rightEdgeOfDeclarator; i++) {
101: // if we haven't found the end yet, keep going
102: if (!(Character.isLetterOrDigit(decl.charAt(i)) || decl
103: .charAt(i) == '_')) {
104: stop = i;
105: break;
106: }
107: if (i == rightEdgeOfDeclarator) {
108: stop = i + 1;
109: }
110: }
111:
112: // the name is the last ID
113: this .name = decl.substring(start, stop);
114:
115: // the type is the decl minus the ID (could be empty)
116: this .type = decl.substring(0, start);
117: if (stop <= rightEdgeOfDeclarator) {
118: this .type += decl
119: .substring(stop, rightEdgeOfDeclarator + 1);
120: }
121: this .type = type.trim();
122: if (this .type.length() == 0) {
123: this .type = null;
124: }
125:
126: this .decl = decl;
127: }
128:
129: public String toString() {
130: if (initValue != null) {
131: return type + " " + name + "=" + initValue;
132: }
133: return type + " " + name;
134: }
135: }
|