Source Code Cross Referenced for SymbolTable.java in  » Parser » Rats-Parser-Generators » xtc » util » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Parser » Rats Parser Generators » xtc.util 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * xtc - The eXTensible Compiler
0003:         * Copyright (C) 2005-2007 Robert Grimm
0004:         *
0005:         * This library is free software; you can redistribute it and/or
0006:         * modify it under the terms of the GNU Lesser General Public License
0007:         * version 2.1 as published by the Free Software Foundation.
0008:         *
0009:         * This library is distributed in the hope that it will be useful,
0010:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012:         * Lesser General Public License for more details.
0013:         *
0014:         * You should have received a copy of the GNU Lesser General Public
0015:         * License along with this library; if not, write to the Free Software
0016:         * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
0017:         * USA.
0018:         */
0019:        package xtc.util;
0020:
0021:        import java.util.ArrayList;
0022:        import java.util.HashMap;
0023:        import java.util.Iterator;
0024:        import java.util.List;
0025:        import java.util.Map;
0026:
0027:        import xtc.Constants;
0028:
0029:        import xtc.tree.Node;
0030:        import xtc.tree.Printer;
0031:
0032:        /**
0033:         * A symbol table.  This class implements a symbol table, which maps
0034:         * symbols represented as strings to values of any type.  The mapping
0035:         * is organized into hierarchical {@link Scope scopes}, which allows
0036:         * for multiple definitions of the same symbol across different
0037:         * scopes.  Additionally, a symbol may have multiple definitions
0038:         * within the same scope: if the corresponding value is a Java
0039:         * collections framework list, it is recognized as a multiply defined
0040:         * symbol.  Scopes are named, with names being represented as strings.
0041:         * Both scope names and symbols can be unqualified — that is,
0042:         * they need to be resolved relative to the {@link #current() current
0043:         * scope} — or qualified by the {@link Constants#QUALIFIER
0044:         * qualification character} '<code>.</code>' &mdash; that is, they are
0045:         * resolved relative to the symbol table's {@link #root() root}.  Once
0046:         * {@link #enter(String) created}, a scope remains in the symbol table
0047:         * and the corresponding AST node should be associated with that scope
0048:         * by setting the corresponding {@link Constants#SCOPE property} to
0049:         * the scope's qualified name.  Subsequent traversals over that node
0050:         * can then automatically {@link #enter(Node) enter} and {@link
0051:         * #exit(Node) exit} that scope.  Alternatively, if traversing out of
0052:         * tree order, the current scope can be set {@link
0053:         * #setScope(SymbolTable.Scope) explicitly}.
0054:         *
0055:         * <p />To support different name spaces within the same scope, this
0056:         * class can optionally {@link #toNameSpace mangle} and {@link
0057:         * #fromNameSpace unmangle} unqualified symbols.  By convention, a
0058:         * name in any name space besides the default name space is prefixed
0059:         * by the name of the name space and an opening parenthesis
0060:         * '<code>(</code>' and suffixed by a closing parenthesis
0061:         * '<code>)</code>'.
0062:         *
0063:         * @author Robert Grimm
0064:         * @version $Revision: 1.34 $
0065:         */
0066:        public class SymbolTable {
0067:
0068:            /**
0069:             * A symbol table scope.  A scope has a name and may have a parent
0070:             * (unless it is the root scope), one or more nested scopes, and one
0071:             * or more definitions.
0072:             */
0073:            public static class Scope {
0074:
0075:                /** The name. */
0076:                String name;
0077:
0078:                /** The fully qualified name. */
0079:                String qName;
0080:
0081:                /** The parent scope. */
0082:                Scope parent;
0083:
0084:                /** The nested scopes, if any. */
0085:                Map<String, Scope> scopes;
0086:
0087:                /** The map from symbols to values, if any. */
0088:                Map<String, Object> symbols;
0089:
0090:                /**
0091:                 * Create a new root scope with the specified name, which may be
0092:                 * the empty string.
0093:                 *
0094:                 * @param name The name.
0095:                 */
0096:                Scope(String name) {
0097:                    this .name = name;
0098:                    this .qName = name;
0099:                }
0100:
0101:                /**
0102:                 * Create a new nested scope with the specified unqualified name
0103:                 * and parent.
0104:                 *
0105:                 * @param name The unqualified name.
0106:                 * @param parent The parent.
0107:                 * @throws IllegalArgumentException
0108:                 *   Signals that the specified parent already has a nested scope
0109:                 *   with the specified name.
0110:                 */
0111:                Scope(String name, Scope parent) {
0112:                    if ((null != parent.scopes)
0113:                            && parent.scopes.containsKey(name)) {
0114:                        throw new IllegalArgumentException("Scope "
0115:                                + parent.qName + " already contains scope "
0116:                                + name);
0117:                    }
0118:                    this .name = name;
0119:                    this .qName = Utilities.qualify(parent.qName, name);
0120:                    this .parent = parent;
0121:                    if (null == parent.scopes) {
0122:                        parent.scopes = new HashMap<String, Scope>();
0123:                    }
0124:                    parent.scopes.put(name, this );
0125:                }
0126:
0127:                /**
0128:                 * Get this scope's unqualfied name.
0129:                 *
0130:                 * @return This scope's unqualified name.
0131:                 */
0132:                public String getName() {
0133:                    return name;
0134:                }
0135:
0136:                /**
0137:                 * Get this scope's qualified name.
0138:                 *
0139:                 * @return This scope's qualified name.
0140:                 */
0141:                public String getQualifiedName() {
0142:                    return qName;
0143:                }
0144:
0145:                /**
0146:                 * Update this scope's qualified name relative to the parent
0147:                 * scope's qualified name.  This method also requalifies any
0148:                 * nested scopes' qualified names.  It must not be called on the
0149:                 * root scope.
0150:                 */
0151:                void requalify() {
0152:                    qName = Utilities.qualify(parent.qName, name);
0153:
0154:                    if (null != scopes) {
0155:                        for (Scope scope : scopes.values()) {
0156:                            scope.requalify();
0157:                        }
0158:                    }
0159:                }
0160:
0161:                /**
0162:                 * Determine whether this scope is the root scope.
0163:                 *
0164:                 * @return <code>true</code> if this scope is the root scope.
0165:                 */
0166:                public boolean isRoot() {
0167:                    return (null == parent);
0168:                }
0169:
0170:                /**
0171:                 * Get this scope's parent.
0172:                 *
0173:                 * @return This scope's parent scope or <code>null</code> if this
0174:                 *   scope does not have a parent (i.e., is the root scope).
0175:                 */
0176:                public Scope getParent() {
0177:                    return parent;
0178:                }
0179:
0180:                /**
0181:                 * Determine whether this scope has any nested scopes.
0182:                 *
0183:                 * @return <code>true</code> if this scope has any nested scopes.
0184:                 */
0185:                public boolean hasNested() {
0186:                    return ((null != scopes) && (0 < scopes.size()));
0187:                }
0188:
0189:                /**
0190:                 * Get an iterator over the names of all nested scopes.
0191:                 *
0192:                 * @return An iterator over the nested scopes.
0193:                 */
0194:                public Iterator<String> nested() {
0195:                    if (null == scopes) {
0196:                        return EmptyIterator.value();
0197:                    } else {
0198:                        return scopes.keySet().iterator();
0199:                    }
0200:                }
0201:
0202:                /**
0203:                 * Determine whether this scope has the specified unqualified
0204:                 * nested scope.
0205:                 *
0206:                 * @param name The nested scope's unqualified name.
0207:                 * @return <code>true</code> if the corresponding scope exists.
0208:                 */
0209:                public boolean hasNested(String name) {
0210:                    return (null != getNested(name));
0211:                }
0212:
0213:                /**
0214:                 * Get the nested scope with the specified unqualified name.
0215:                 *
0216:                 * @param name The nested scope's unqualified name.
0217:                 * @return The corresponding scope or <code>null</code> if there is
0218:                 *   no such scope.
0219:                 */
0220:                public Scope getNested(String name) {
0221:                    return (null == scopes) ? null : scopes.get(name);
0222:                }
0223:
0224:                /**
0225:                 * Determine whether the scope with the specified unqualified name
0226:                 * can be merged into this scope.  A nested scope can be merged if
0227:                 * it (1) does not contain any bindings with the same names as
0228:                 * this scope's bindings and (2) does not have any children with
0229:                 * the same names as this scope's children.
0230:                 *
0231:                 * @param name The nested scope's unqualified name.
0232:                 * @return <code>true</code> if the scope can be merged.
0233:                 * @throws IllegalArgumentException Signals that this scope does
0234:                 *   not have a nested scope with the specified name.
0235:                 */
0236:                public boolean isMergeable(String name) {
0237:                    Scope nested = getNested(name);
0238:
0239:                    if (null == nested) {
0240:                        throw new IllegalArgumentException("Scope " + qName
0241:                                + " does not " + " contain scope " + name);
0242:                    }
0243:
0244:                    if (null != nested.scopes) {
0245:                        // Note that this scope must have nested scopes, since we just
0246:                        // looked one up.
0247:                        for (String s : nested.scopes.keySet()) {
0248:                            if ((!s.equals(name)) && this .scopes.containsKey(s)) {
0249:                                return false;
0250:                            }
0251:                        }
0252:                    }
0253:
0254:                    if ((null != this .symbols) && (null != nested.symbols)) {
0255:                        for (String s : nested.symbols.keySet()) {
0256:                            if (this .symbols.containsKey(s)) {
0257:                                return false;
0258:                            }
0259:                        }
0260:                    }
0261:
0262:                    return true;
0263:                }
0264:
0265:                /**
0266:                 * Merge the nested scope with the specified unqualified name into
0267:                 * this scope.
0268:                 *
0269:                 * @param name The nested scope's unqualified name.
0270:                 * @throws IllegalArgumentException Signals that (1) this scope
0271:                 *   does not have a nested scope with the specified name, (2) any
0272:                 *   of the nested scope's children has the same name as one of
0273:                 *   this scope's children, or (3) any of the nested scope's
0274:                 *   bindings has the same name as one of this scope's bindings.
0275:                 */
0276:                public void merge(String name) {
0277:                    final Scope nested = getNested(name);
0278:
0279:                    // Make sure the nested scope is mergeable.  Note that the
0280:                    // nested scope must exist in the consequence of the
0281:                    // if-statement, since isMergeable signals an exception for
0282:                    // non-existent scopes.
0283:                    if (!isMergeable(name)) {
0284:                        throw new IllegalArgumentException("Scope "
0285:                                + nested.qName
0286:                                + " cannot be merged into the parent");
0287:                    }
0288:
0289:                    // Remove the nested scope.
0290:                    this .scopes.remove(name);
0291:
0292:                    // Add the nested scope's children.
0293:                    if (null != nested.scopes) {
0294:                        this .scopes.putAll(nested.scopes);
0295:
0296:                        for (Scope s : nested.scopes.values()) {
0297:                            s.parent = this ;
0298:                            s.requalify();
0299:                        }
0300:                    }
0301:
0302:                    // Add the nested scope's bindings.
0303:                    if (null != nested.symbols) {
0304:                        if (null == this .symbols) {
0305:                            this .symbols = nested.symbols;
0306:                        } else {
0307:                            this .symbols.putAll(nested.symbols);
0308:                        }
0309:                    }
0310:
0311:                    // Invalidate the nested scope.
0312:                    nested.parent = null;
0313:                    nested.name = null;
0314:                    nested.qName = null;
0315:                    nested.scopes = null;
0316:                    nested.symbols = null;
0317:                }
0318:
0319:                /**
0320:                 * Determine whether this scope has any local definitions.
0321:                 *
0322:                 * @return <code>true</code> if this scope has any local
0323:                 *   definitions.
0324:                 */
0325:                public boolean hasSymbols() {
0326:                    return ((null != symbols) && (0 < symbols.size()));
0327:                }
0328:
0329:                /**
0330:                 * Get an iterator over the all locally defined symbols.
0331:                 *
0332:                 * @return An iterator over the locally defined symbols.
0333:                 */
0334:                public Iterator<String> symbols() {
0335:                    if (null == symbols) {
0336:                        return EmptyIterator.value();
0337:                    } else {
0338:                        return symbols.keySet().iterator();
0339:                    }
0340:                }
0341:
0342:                /**
0343:                 * Determine whether the specified symbol is defined in this
0344:                 * scope.
0345:                 *
0346:                 * @param symbol The unqualified symbol.
0347:                 * @return <code>true</code> if the symbol is defined in this
0348:                 *   scope.
0349:                 */
0350:                public boolean isDefinedLocally(String symbol) {
0351:                    return (null == symbols) ? false : symbols
0352:                            .containsKey(symbol);
0353:                }
0354:
0355:                /**
0356:                 * Determine whether the specified unqualified symbol is defined
0357:                 * in this scope or any of its ancestors.
0358:                 *
0359:                 * @param symbol The unqualified symbol.
0360:                 * @return <code>true</code> if the symbol is defined in this scope
0361:                 *   or any of its ancestors.
0362:                 */
0363:                public boolean isDefined(String symbol) {
0364:                    return (null != lookupScope(symbol));
0365:                }
0366:
0367:                /**
0368:                 * Determine whether the specified symbol is defined multiple
0369:                 * times in this scope or any of its ancestors.
0370:                 *
0371:                 * @param symbol The unqualified symbol.
0372:                 * @return <code>true</code> if the symbol is defined multiple
0373:                 *   times.
0374:                 */
0375:                public boolean isDefinedMultiply(String symbol) {
0376:                    Scope scope = lookupScope(symbol);
0377:                    return (null == scope) ? false
0378:                            : scope.symbols.get(symbol) instanceof  List;
0379:                }
0380:
0381:                /**
0382:                 * Get the scope defining the specified unqualified symbol.  This
0383:                 * method searches this scope and all its ancestors, returning the
0384:                 * first defining scope.
0385:                 *
0386:                 * @param symbol The unqualified symbol.
0387:                 * @return The definining scope or <code>null</code> if there is
0388:                 *   no such scope.
0389:                 */
0390:                public Scope lookupScope(String symbol) {
0391:                    Scope scope = this ;
0392:                    do {
0393:                        if ((null != scope.symbols)
0394:                                && (scope.symbols.containsKey(symbol))) {
0395:                            return scope;
0396:                        }
0397:                        scope = scope.parent;
0398:                    } while (null != scope);
0399:                    return null;
0400:                }
0401:
0402:                /**
0403:                 * Get the value for the specified unqualified symbol.  This
0404:                 * method searches this scope and all its ancestors, returning the
0405:                 * value of the first definition.
0406:                 *
0407:                 * @param symbol The unqualified symbol.
0408:                 * @return The corresponding value or <code>null</code> if there is
0409:                 *   no definition.
0410:                 */
0411:                public Object lookup(String symbol) {
0412:                    Scope scope = lookupScope(symbol);
0413:                    return (null == scope) ? null : scope.symbols.get(symbol);
0414:                }
0415:
0416:                /**
0417:                 * Get the scope named by the specified unqualified symbol, which
0418:                 * is nested in the scope defining the symbol.  This method
0419:                 * searches this scope and all its ancestors, up to the first
0420:                 * defining scope.  It then looks for the nested scope with the
0421:                 * same name.
0422:                 *
0423:                 * @param symbol The unqualified symbol.
0424:                 * @return The bound scope or <code>null</code> if there is no
0425:                 *   definition or nested scope with the same name.
0426:                 */
0427:                public Scope lookupBoundScope(String symbol) {
0428:                    Scope scope = lookupScope(symbol);
0429:                    return (null == scope) ? null : scope.getNested(symbol);
0430:                }
0431:
0432:                /**
0433:                 * Get the local value for the specified unqualified symbol.
0434:                 *
0435:                 * @param symbol The unqualified symbol.
0436:                 * @return The corresponding value or <code>null</code> if there is
0437:                 *   no local definition.
0438:                 */
0439:                public Object lookupLocally(String symbol) {
0440:                    return (null == symbols) ? null : symbols.get(symbol);
0441:                }
0442:
0443:                /**
0444:                 * Set the specified symbol's value to the specified value in this
0445:                 * scope.
0446:                 *
0447:                 * @param symbol The unqualified symbol.
0448:                 * @param value The value.
0449:                 */
0450:                public void define(String symbol, Object value) {
0451:                    if (null == symbols) {
0452:                        symbols = new HashMap<String, Object>();
0453:                    }
0454:                    symbols.put(symbol, value);
0455:                }
0456:
0457:                /**
0458:                 * Add the specified value to the specified symbol's values in
0459:                 * this scope.
0460:                 *
0461:                 * @param symbol The unqualified symbol.
0462:                 * @param value The value.
0463:                 */
0464:                @SuppressWarnings("unchecked")
0465:                public void addDefinition(String symbol, Object value) {
0466:                    if (null == symbols) {
0467:                        symbols = new HashMap<String, Object>();
0468:                    }
0469:
0470:                    if (symbols.containsKey(symbol)) {
0471:                        Object o = symbols.get(symbol);
0472:
0473:                        if (o instanceof  List) {
0474:                            ((List<Object>) o).add(value);
0475:
0476:                        } else {
0477:                            List<Object> l = new ArrayList<Object>();
0478:                            l.add(o);
0479:                            l.add(value);
0480:                            symbols.put(symbol, l);
0481:                        }
0482:
0483:                    } else {
0484:                        symbols.put(symbol, value);
0485:                    }
0486:                }
0487:
0488:                /**
0489:                 * Undefine the specified unqualified symbol.  If the symbol is
0490:                 * defined in this scope, this method removes all its values.
0491:                 *
0492:                 * @param symbol The unqualified symbol.
0493:                 */
0494:                public void undefine(String symbol) {
0495:                    if (null != symbols) {
0496:                        symbols.remove(symbol);
0497:                    }
0498:                }
0499:
0500:                /**
0501:                 * Qualify the specified unqualified symbol with this scope's
0502:                 * name.
0503:                 *
0504:                 * @param symbol The unqualified symbol.
0505:                 * @return The qualified symbol.
0506:                 */
0507:                public String qualify(String symbol) {
0508:                    return Utilities.qualify(qName, symbol);
0509:                }
0510:
0511:                /**
0512:                 * Dump the contents of this scope.  This method pretty prints the
0513:                 * contents of this scope and all nested scopes with the specified
0514:                 * printer.  If the printer is registered with a visitor, that
0515:                 * visitor is used for formatting any node values.
0516:                 *
0517:                 * @param printer The printer, which need not be registered with a
0518:                 *   visitor.
0519:                 */
0520:                public void dump(Printer printer) {
0521:                    boolean hasVisitor = (null != printer.visitor());
0522:
0523:                    printer.indent().p('.').p(name).pln(" = {").incr();
0524:
0525:                    if (null != symbols) {
0526:                        for (Map.Entry<String, Object> entry : symbols
0527:                                .entrySet()) {
0528:                            String symbol = entry.getKey();
0529:                            Object value = entry.getValue();
0530:
0531:                            printer.indent().p(symbol).p(" = ");
0532:                            if (null == value) {
0533:                                printer.p("null");
0534:                            } else if (hasVisitor && (value instanceof  Node)) {
0535:                                printer.p((Node) value);
0536:                            } else if (value instanceof  String) {
0537:                                printer.p('"').escape((String) value,
0538:                                        Utilities.JAVA_ESCAPES).p('"');
0539:                            } else {
0540:                                try {
0541:                                    printer.p(value.toString());
0542:                                } catch (final Exception e) {
0543:                                    printer
0544:                                            .p(value.getClass().getName()
0545:                                                    + "@?");
0546:                                }
0547:                            }
0548:                            printer.pln(';');
0549:
0550:                            Scope nested = getNested(symbol);
0551:                            if (null != nested) {
0552:                                nested.dump(printer);
0553:                            }
0554:                        }
0555:                    }
0556:
0557:                    if (null != scopes) {
0558:                        for (Scope nested : scopes.values()) {
0559:                            if ((null == symbols)
0560:                                    || (!symbols.containsKey(nested.name))) {
0561:                                nested.dump(printer);
0562:                            }
0563:                        }
0564:                    }
0565:
0566:                    printer.decr().indent().pln("};");
0567:                }
0568:
0569:            }
0570:
0571:            // =========================================================================
0572:
0573:            /** The root scope. */
0574:            protected Scope root;
0575:
0576:            /** The current scope. */
0577:            protected Scope current;
0578:
0579:            /** The fresh name count. */
0580:            protected int freshNameCount;
0581:
0582:            /** The fresh identifier count. */
0583:            protected int freshIdCount;
0584:
0585:            // =========================================================================
0586:
0587:            /**
0588:             * Create a new symbol table with the empty string as the root
0589:             * scope's name.
0590:             */
0591:            public SymbolTable() {
0592:                this ("");
0593:            }
0594:
0595:            /**
0596:             * Create a new symbol table.
0597:             *
0598:             * @param root The name of the root scope.
0599:             */
0600:            public SymbolTable(String root) {
0601:                this .root = new Scope(root);
0602:                current = this .root;
0603:                freshNameCount = 0;
0604:                freshIdCount = 0;
0605:            }
0606:
0607:            // =========================================================================
0608:
0609:            /**
0610:             * Clear this symbol table.  This method deletes all scopes and
0611:             * their definitions from this symbol table.
0612:             */
0613:            public void reset() {
0614:                root.scopes = null;
0615:                root.symbols = null;
0616:                current = root;
0617:                freshNameCount = 0;
0618:                freshIdCount = 0;
0619:            }
0620:
0621:            /**
0622:             * Get the root scope.
0623:             *
0624:             * @return The root scope.
0625:             */
0626:            public Scope root() {
0627:                return root;
0628:            }
0629:
0630:            /**
0631:             * Get the current scope.
0632:             *
0633:             * @return The current scope.
0634:             */
0635:            public Scope current() {
0636:                return current;
0637:            }
0638:
0639:            /**
0640:             * Get the scope with the specified qualified name.
0641:             *
0642:             * @param name The qualified name.
0643:             * @return The corresponding scope or <code>null</code> if no such
0644:             *   scope exits.
0645:             */
0646:            public Scope getScope(String name) {
0647:                // Optimize for the common case where the specified name denotes a
0648:                // scope directly nested in the current scope.
0649:                Scope scope = current;
0650:                if (name.startsWith(scope.qName)
0651:                        && (name.lastIndexOf(Constants.QUALIFIER) == scope.qName
0652:                                .length())) {
0653:                    return scope.getNested(Utilities.getName(name));
0654:                }
0655:
0656:                String[] components = Utilities.toComponents(name);
0657:                scope = root.name.equals(components[0]) ? root : null;
0658:                int index = 1;
0659:
0660:                while ((null != scope) && (index < components.length)) {
0661:                    scope = scope.getNested(components[index]);
0662:                    index++;
0663:                }
0664:
0665:                return scope;
0666:            }
0667:
0668:            /**
0669:             * Set the current scope to the specified scope.
0670:             *
0671:             * @param scope The new current scope.
0672:             * @throws IllegalArgumentException Signals that this symbol table's
0673:             *   root is not the specified scope's root.
0674:             */
0675:            public void setScope(Scope scope) {
0676:                // Check the specified scope.
0677:                Scope s = scope;
0678:                while (null != s.parent)
0679:                    s = s.parent;
0680:                if (s != root) {
0681:                    throw new IllegalArgumentException("Scope " + scope.qName
0682:                            + " not " + "in this symbol table " + this );
0683:                }
0684:
0685:                // Make the scope the current scope.
0686:                current = scope;
0687:            }
0688:
0689:            /**
0690:             * Determine whether the specified symbol is defined.  If the symbol
0691:             * is qualified, this method checks whether the symbol is defined in
0692:             * the named scope.  Otherwise, it checks whether the symbol is
0693:             * defined in the current scope or one of its ancestors.
0694:             *
0695:             * @param symbol The symbol.
0696:             * @return <code>true</code> if the specified symbol is defined.
0697:             */
0698:            public boolean isDefined(String symbol) {
0699:                Scope scope = lookupScope(symbol);
0700:                if ((null == scope) || (null == scope.symbols)) {
0701:                    return false;
0702:                } else {
0703:                    return scope.symbols.containsKey(Utilities
0704:                            .unqualify(symbol));
0705:                }
0706:            }
0707:
0708:            /**
0709:             * Determine whether the specified symbol is define multiple times.
0710:             * If the symbol is qualified, this method checks whether the symbol
0711:             * has multiple definitions in the named scope.  Otherwise, it
0712:             * checks whether the symbol has multiple definitions in the current
0713:             * scope or one of its ancestors.
0714:             *
0715:             * @param symbol The symbol.
0716:             * @return <code>true</code> if the specified symbol is multiply
0717:             *   defined.
0718:             */
0719:            public boolean isDefinedMultiply(String symbol) {
0720:                Scope scope = lookupScope(symbol);
0721:                if ((null == scope) || (null == scope.symbols)) {
0722:                    return false;
0723:                } else {
0724:                    return scope.symbols.get(Utilities.unqualify(symbol)) instanceof  List;
0725:                }
0726:            }
0727:
0728:            /**
0729:             * Get the scope for the specified symbol.  If the symbol is
0730:             * qualified, this method returns the named scope (without checking
0731:             * whether the symbol is defined in that scope).  Otherwise, it
0732:             * searches the current scope and all its ancestors, returning the
0733:             * first defining scope.
0734:             *
0735:             * @param symbol The symbol.
0736:             * @return The corresponding scope or <code>null</code> if no such
0737:             *   scope exits.
0738:             */
0739:            public Scope lookupScope(String symbol) {
0740:                if (Utilities.isQualified(symbol)) {
0741:                    return getScope(Utilities.getQualifier(symbol));
0742:
0743:                } else {
0744:                    return current.lookupScope(symbol);
0745:                }
0746:            }
0747:
0748:            /**
0749:             * Get the value for the specified symbol.  If the symbol is
0750:             * qualified, this method returns the definition within the named
0751:             * scope.  Otherwise, it searches the current scope and all its
0752:             * ancestors, returning the value of the first definition.
0753:             *
0754:             * @param symbol The symbol.
0755:             * @return The corresponding value or <code>null</code> if no such
0756:             *   definition exists.
0757:             */
0758:            public Object lookup(String symbol) {
0759:                Scope scope = lookupScope(symbol);
0760:                if ((null == scope) || (null == scope.symbols)) {
0761:                    return null;
0762:                } else {
0763:                    return scope.symbols.get(Utilities.unqualify(symbol));
0764:                }
0765:            }
0766:
0767:            /**
0768:             * Enter the scope with the specified unqualified name.  If the
0769:             * current scope does not have a scope with the specified name, a
0770:             * new scope with the specified name is created.  In either case,
0771:             * the scope with that name becomes the current scope.
0772:             *
0773:             * @param name The unqualified name.
0774:             */
0775:            public void enter(String name) {
0776:                Scope parent = current;
0777:                Scope child = parent.getNested(name);
0778:                if (null == child) {
0779:                    child = new Scope(name, parent);
0780:                }
0781:                current = child;
0782:            }
0783:
0784:            /**
0785:             * Exit the current scope.
0786:             *
0787:             * @throws IllegalStateException
0788:             *   Signals that the current scope is the root scope.
0789:             */
0790:            public void exit() {
0791:                if (null == current.parent) {
0792:                    throw new IllegalStateException("Unable to exit root scope");
0793:                }
0794:                current = current.parent;
0795:            }
0796:
0797:            /**
0798:             * Delete the scope with the specified unqualified name.  If the
0799:             * current scope contains a nested scope with the specified name,
0800:             * this method deletes that scope and <em>all its contents</em>,
0801:             * including nested scopes.
0802:             *
0803:             * @param name The unqualified name.
0804:             */
0805:            public void delete(String name) {
0806:                if (null != current.scopes) {
0807:                    current.scopes.remove(name);
0808:                }
0809:            }
0810:
0811:            /**
0812:             * Determine whether the specified node has an associated {@link
0813:             * Constants#SCOPE scope}.
0814:             *
0815:             * @param n The node.
0816:             * @return <code>true</code> if the node has an associated scope.
0817:             */
0818:            public static boolean hasScope(Node n) {
0819:                return n.hasProperty(Constants.SCOPE);
0820:            }
0821:
0822:            /**
0823:             * Mark the specified node.  If the node does not have an associated
0824:             * {@link Constants#SCOPE scope}, this method set the property with
0825:             * the current scope's qualified name.
0826:             *
0827:             * @param n The node.
0828:             */
0829:            public void mark(Node n) {
0830:                if (!n.hasProperty(Constants.SCOPE)) {
0831:                    n.setProperty(Constants.SCOPE, current.getQualifiedName());
0832:                }
0833:            }
0834:
0835:            /**
0836:             * Enter the specified node.  If the node has an associated {@link
0837:             * Constants#SCOPE scope}, this method tries to enter the scope.
0838:             * Otherwise, it does not change the scope.
0839:             *
0840:             * @param n The node.
0841:             * @throws IllegalStateException Signals that the node's scope is
0842:             *   invalid or not nested within the current scope.
0843:             */
0844:            public void enter(Node n) {
0845:                if (n.hasProperty(Constants.SCOPE)) {
0846:                    String name = n.getStringProperty(Constants.SCOPE);
0847:                    Scope scope = getScope(name);
0848:
0849:                    if (null == scope) {
0850:                        throw new IllegalStateException("Invalid scope " + name);
0851:                    } else if (scope.getParent() != current) {
0852:                        throw new IllegalStateException("Scope " + name
0853:                                + " not nested in "
0854:                                + current.getQualifiedName());
0855:                    }
0856:
0857:                    current = scope;
0858:                }
0859:            }
0860:
0861:            /**
0862:             * Exit the specified node.  If the node has an associated {@link
0863:             * Constants#SCOPE scope}, the current scope is exited.
0864:             *
0865:             * @param n The node.
0866:             */
0867:            public void exit(Node n) {
0868:                if (n.hasProperty(Constants.SCOPE)) {
0869:                    exit();
0870:                }
0871:            }
0872:
0873:            /**
0874:             * Create a fresh name.  The returned name has
0875:             * "<code>anonymous</code>" as it base name.
0876:             *
0877:             * @see #freshName(String)
0878:             * 
0879:             * @return A fresh name.
0880:             */
0881:            public String freshName() {
0882:                return freshName("anonymous");
0883:            }
0884:
0885:            /**
0886:             * Create a fresh name incorporating the specified base name.  The
0887:             * returned name is of the form
0888:             * <code><i>name</i>(<i>count</i>)</code>.
0889:             *
0890:             * @param base The base name.
0891:             * @return The corresponding fresh name.
0892:             */
0893:            public String freshName(String base) {
0894:                StringBuilder buf = new StringBuilder();
0895:                buf.append(base);
0896:                buf.append(Constants.START_OPAQUE);
0897:                buf.append(freshNameCount++);
0898:                buf.append(Constants.END_OPAQUE);
0899:                return buf.toString();
0900:            }
0901:
0902:            /**
0903:             * Create a fresh C identifier.  The returned identifier has
0904:             * "<code>tmp</code>" as its base name.
0905:             *
0906:             * @see #freshCId(String)
0907:             *
0908:             * @return A fresh C identifier.
0909:             */
0910:            public String freshCId() {
0911:                return freshCId("tmp");
0912:            }
0913:
0914:            /**
0915:             * Create a fresh C identifier incorporating the specified base
0916:             * name.  The returned name is of the form
0917:             * <code>__<i>name</i>_<i>count</i></code>.
0918:             *
0919:             * @param base The base name.
0920:             * @return The corresponding fresh C identifier.
0921:             */
0922:            public String freshCId(String base) {
0923:                StringBuilder buf = new StringBuilder();
0924:                buf.append("__");
0925:                buf.append(base);
0926:                buf.append('_');
0927:                buf.append(freshIdCount++);
0928:                return buf.toString();
0929:            }
0930:
0931:            /**
0932:             * Create a fresh Java identifier.  The returned identifier has
0933:             * "<code>tmp</code>" as its base name.
0934:             *
0935:             * @see #freshJavaId(String)
0936:             *
0937:             * @return A fresh Java identifier.
0938:             */
0939:            public String freshJavaId() {
0940:                return freshJavaId("tmp");
0941:            }
0942:
0943:            /**
0944:             * Create a fresh Java identifier incorporating the specified base
0945:             * name.  The returned name is of the form
0946:             * <code><i>name</i>$<i>count</i></code>.
0947:             *
0948:             * @param base The base name.
0949:             * @return The corresponding fresh Java identifier.
0950:             */
0951:            public String freshJavaId(String base) {
0952:                StringBuilder buf = new StringBuilder();
0953:                buf.append(base);
0954:                buf.append('$');
0955:                buf.append(freshIdCount++);
0956:                return buf.toString();
0957:            }
0958:
0959:            /**
0960:             * Convert the specified unqualified symbol to a symbol in the
0961:             * specified name space.
0962:             *
0963:             * @param symbol The symbol
0964:             * @param space The name space.
0965:             * @return The mangled symbol.
0966:             */
0967:            public static String toNameSpace(String symbol, String space) {
0968:                return space + Constants.START_OPAQUE + symbol
0969:                        + Constants.END_OPAQUE;
0970:            }
0971:
0972:            /**
0973:             * Determine whether the specified symbol is in the specified name
0974:             * space.
0975:             *
0976:             * @param symbol The symbol.
0977:             * @param space The name space.
0978:             * @return <code>true</code> if the symbol is mangled symbol in the
0979:             *   name space.
0980:             */
0981:            public static boolean isInNameSpace(String symbol, String space) {
0982:                try {
0983:                    return (symbol.startsWith(space)
0984:                            && (Constants.START_OPAQUE == symbol.charAt(space
0985:                                    .length())) && symbol.endsWith(END_OPAQUE));
0986:                } catch (IndexOutOfBoundsException x) {
0987:                    return false;
0988:                }
0989:            }
0990:
0991:            /** The end of opaqueness marker as a string. */
0992:            private static final String END_OPAQUE = Character
0993:                    .toString(Constants.END_OPAQUE);
0994:
0995:            /**
0996:             * Convert the specified unqualified symbol within a name space to a
0997:             * symbol without a name space.
0998:             *
0999:             * @param symbol The mangled symbol within a name space.
1000:             * @return The corresponding symbol without a name space.
1001:             */
1002:            public static String fromNameSpace(String symbol) {
1003:                int start = symbol.indexOf(Constants.START_OPAQUE);
1004:                int end = symbol.length() - 1;
1005:                if ((0 < start) && (Constants.END_OPAQUE == symbol.charAt(end))) {
1006:                    return symbol.substring(start + 1, end);
1007:                } else {
1008:                    throw new IllegalArgumentException("Not a mangled symbol '"
1009:                            + symbol + "'");
1010:                }
1011:            }
1012:
1013:            /**
1014:             * Conver the specified C macro identifier into a symbol table scope
1015:             * name.
1016:             *
1017:             * @param id The macro identifier.
1018:             * @return The corresponding symbol table scope name.
1019:             */
1020:            public static String toMacroScopeName(String id) {
1021:                return toNameSpace(id, "macro");
1022:            }
1023:
1024:            /**
1025:             * Determine whether the specified scope name represents a macro's
1026:             * scope.
1027:             *
1028:             * @param name The name.
1029:             * @return <code>true</code> if the name denotes a macro scope.
1030:             */
1031:            public static boolean isMacroScopeName(String name) {
1032:                return isInNameSpace(name, "macro");
1033:            }
1034:
1035:            /**
1036:             * Convert the specified C function identifier into a symbol table
1037:             * scope name.
1038:             *
1039:             * @param id The function identifier.
1040:             * @return The corresponding symbol table scope name.
1041:             */
1042:            public static String toFunctionScopeName(String id) {
1043:                return toNameSpace(id, "function");
1044:            }
1045:
1046:            /**
1047:             * Determine whether the specified scope name represents a
1048:             * function's scope.
1049:             *
1050:             * @param name The name.
1051:             * @return <code>true</code> if the name denotes a function scope.
1052:             */
1053:            public static boolean isFunctionScopeName(String name) {
1054:                return isInNameSpace(name, "function");
1055:            }
1056:
1057:            /**
1058:             * Convert the specified C struct, union, or enum tag into a symbol
1059:             * table name.
1060:             *
1061:             * @param tag The tag.
1062:             * @return The corresponding symbol table name.
1063:             */
1064:            public static String toTagName(String tag) {
1065:                return toNameSpace(tag, "tag");
1066:            }
1067:
1068:            /**
1069:             * Convert the specified label identifier into a symbol table name.
1070:             *
1071:             * @param id The identifier.
1072:             * @return The corresponding symbol table name.
1073:             */
1074:            public static String toLabelName(String id) {
1075:                return toNameSpace(id, "label");
1076:            }
1077:
1078:            /**
1079:             * Convert the specified method identifier into a symbol table name.
1080:             *
1081:             * @param id The method identifier.
1082:             * @return The corresponding symbol table name.
1083:             */
1084:            public static String toMethodName(String id) {
1085:                return toNameSpace(id, "method");
1086:            }
1087:
1088:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.