Source Code Cross Referenced for Resolver.java in  » Parser » Rats-Parser-Generators » xtc » parser » 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.parser 
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 program is free software; you can redistribute it and/or
0006:         * modify it under the terms of the GNU General Public License
0007:         * version 2 as published by the Free Software Foundation.
0008:         *
0009:         * This program 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
0012:         * GNU General Public License for more details.
0013:         *
0014:         * You should have received a copy of the GNU General Public License
0015:         * along with this program; if not, write to the Free Software
0016:         * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
0017:         * USA.
0018:         */
0019:        package xtc.parser;
0020:
0021:        import java.io.File;
0022:        import java.io.FileNotFoundException;
0023:        import java.io.IOException;
0024:        import java.io.Reader;
0025:
0026:        import java.util.ArrayList;
0027:        import java.util.Collections;
0028:        import java.util.HashMap;
0029:        import java.util.HashSet;
0030:        import java.util.IdentityHashMap;
0031:        import java.util.Iterator;
0032:        import java.util.List;
0033:        import java.util.Map;
0034:        import java.util.Set;
0035:
0036:        import xtc.Constants;
0037:
0038:        import xtc.tree.Attribute;
0039:        import xtc.tree.Visitor;
0040:
0041:        import xtc.type.AST;
0042:        import xtc.type.ErrorT;
0043:        import xtc.type.Type;
0044:
0045:        import xtc.util.Runtime;
0046:        import xtc.util.Utilities;
0047:
0048:        /**
0049:         * Visitor to resolve grammar module dependencies.
0050:         *
0051:         * <p />Note that this visitor {@link TextTester marks} text-only
0052:         * productions as such.  It also {@link LeftRecurser detects} left
0053:         * recursions and marks direct left recursions.  Furthermore, it sets
0054:         * a grammar's {@link Properties#GENERIC} and {@link
0055:         * Properties#RECURSIVE} properties as appropriate.
0056:         *
0057:         * @author Robert Grimm
0058:         * @version $Revision: 1.124 $
0059:         */
0060:        public class Resolver extends Visitor {
0061:
0062:            /** The runtime. */
0063:            protected final Runtime runtime;
0064:
0065:            /** The analyzer utility. */
0066:            protected final Analyzer analyzer;
0067:
0068:            /** The type operations. */
0069:            protected final AST ast;
0070:
0071:            /** The current checking phase. */
0072:            protected int phase;
0073:
0074:            /** The identity hash map of erroneous nonterminals. */
0075:            protected Map<NonTerminal, NonTerminal> badNTs;
0076:
0077:            /** The flag for whether the current module has a stateful attribute. */
0078:            protected boolean hasState;
0079:
0080:            /** The flag for whether the current module is a mofunctor. */
0081:            protected boolean isMofunctor;
0082:
0083:            /** Flag for whether the current expression is a predicate. */
0084:            protected boolean isPredicate;
0085:
0086:            /** The set of sequence names for the current production. */
0087:            protected Set<SequenceName> sequenceNames;
0088:
0089:            /**
0090:             * Create a new resolver.
0091:             *
0092:             * @param runtime The runtime.
0093:             * @param analyzer The analyzer utility.
0094:             * @param ast The type operations.
0095:             */
0096:            public Resolver(Runtime runtime, Analyzer analyzer, AST ast) {
0097:                this .runtime = runtime;
0098:                this .analyzer = analyzer;
0099:                this .ast = ast;
0100:                badNTs = new IdentityHashMap<NonTerminal, NonTerminal>();
0101:                sequenceNames = new HashSet<SequenceName>();
0102:            }
0103:
0104:            /**
0105:             * Print the specified module's signature.
0106:             *
0107:             * @param m The module.
0108:             */
0109:            protected void signature(Module m) {
0110:                // Print the globally visible module name.
0111:                System.out.print("module ");
0112:                System.out.print(m.name.name);
0113:
0114:                // If the module has been instantiated from another, print the
0115:                // original invocation.
0116:                if (m.name.hasProperty(Constants.ORIGINAL)
0117:                        || (null != m.parameters)) {
0118:                    System.out.print(" = ");
0119:                    ModuleName base = m.name.hasProperty(Constants.ORIGINAL) ? (ModuleName) m.name
0120:                            .getProperty(Constants.ORIGINAL)
0121:                            : m.name;
0122:                    System.out.print(base.name);
0123:                    if (null == m.parameters) {
0124:                        System.out.print("()");
0125:                    } else {
0126:                        System.out.print(m.parameters.toString());
0127:                    }
0128:                }
0129:
0130:                if (null != m.dependencies) {
0131:                    // Print the modification, if any.
0132:                    for (ModuleDependency dep : m.dependencies) {
0133:                        if (dep.isModification()) {
0134:                            System.out.println();
0135:                            System.out.print("       modifies ");
0136:                            System.out.print(dep.visibleName().name);
0137:                            break;
0138:                        }
0139:                    }
0140:
0141:                    // Print the imports, if any.
0142:                    boolean first = true;
0143:                    for (ModuleDependency dep : m.dependencies) {
0144:                        if (dep.isImport()) {
0145:                            if (first) {
0146:                                System.out.println();
0147:                                System.out.print("       imports ");
0148:                                first = false;
0149:                            } else {
0150:                                System.out.println(',');
0151:                                System.out.print("               ");
0152:                            }
0153:                            System.out.print(dep.visibleName().name);
0154:                        }
0155:                    }
0156:                }
0157:
0158:                // Done.
0159:                System.out.println(';');
0160:            }
0161:
0162:            /**
0163:             * Load the module with the specified name.
0164:             *
0165:             * @param name The name.
0166:             * @return The corresponding grammar module.
0167:             * @throws IllegalArgmentException
0168:             *   Signals that the file is too large.
0169:             * @throws FileNotFoundException
0170:             *   Signals that the file does not exist.
0171:             * @throws IOException
0172:             *   Signals an exceptional condition while accessing the file.
0173:             * @throws ParseException
0174:             *   Signals a parse error.
0175:             */
0176:            protected Module load(String name) throws IOException,
0177:                    ParseException {
0178:                File file = runtime.locate(Utilities.toPath(name,
0179:                        Constants.EXT_GRAMMAR));
0180:
0181:                if (!file.exists()) {
0182:                    throw new FileNotFoundException(file + ": file not found");
0183:                } else if (!file.isFile()) {
0184:                    throw new IllegalArgumentException(file + ": not a file");
0185:                } else if (Integer.MAX_VALUE < file.length()) {
0186:                    throw new IllegalArgumentException(file
0187:                            + ": file too large");
0188:                }
0189:
0190:                Reader in = null;
0191:                try {
0192:                    in = runtime.getReader(file);
0193:                    PParser parser = new PParser(in, file.toString(),
0194:                            (int) file.length());
0195:                    return (Module) parser.value(parser.pModule(0));
0196:                } finally {
0197:                    if (null != in) {
0198:                        try {
0199:                            in.close();
0200:                        } catch (IOException x) {
0201:                            // Nothing to see here. Move on.
0202:                        }
0203:                    }
0204:                }
0205:            }
0206:
0207:            /**
0208:             * Rename the specified module.  This method renames all module
0209:             * names in the specified module, including the module's {@link
0210:             * Module#name name}, the module's {@link Module#dependencies
0211:             * dependencies}, and each production's {@link Production#qName
0212:             * qualified name} (if it is not <code>null</code>).
0213:             *
0214:             * @param module The module.
0215:             * @param renaming The renaming.
0216:             */
0217:            protected void rename(Module module, ModuleMap renaming) {
0218:                // Process the name.
0219:                module.name = module.name.rename(renaming);
0220:
0221:                // Process the parameters.
0222:                if (null != module.parameters) {
0223:                    module.parameters.rename(renaming);
0224:                }
0225:
0226:                // Process the dependencies.
0227:                if (null != module.dependencies) {
0228:                    for (ModuleDependency dep : module.dependencies)
0229:                        dep.rename(renaming);
0230:                }
0231:
0232:                // Process the productions.
0233:                Renamer renamer = new Renamer(runtime, analyzer, renaming);
0234:                for (Production p : module.productions) {
0235:                    if (null != p.qName) {
0236:                        p.qName = p.qName.rename(renaming);
0237:                    }
0238:                    renamer.dispatch(p);
0239:                }
0240:            }
0241:
0242:            /**
0243:             * Strip the specified production's ordered choice.
0244:             *
0245:             * @see Analyzer#stripChoices
0246:             *
0247:             * @param p The production to strip.
0248:             * @return The specified production.
0249:             */
0250:            protected Production strip(Production p) {
0251:                if ((null != p) && (null != p.choice)) {
0252:                    p.choice = Analyzer.stripChoices(p.choice);
0253:                }
0254:                return p;
0255:            }
0256:
0257:            /**
0258:             * Apply the specified alternative addition to the specified full
0259:             * production.
0260:             *
0261:             * @param p1 The alternative addition.
0262:             * @param p2 The full production.
0263:             */
0264:            protected void apply(AlternativeAddition p1, FullProduction p2) {
0265:                final int length2 = p2.choice.alternatives.size();
0266:                int index = -1;
0267:                for (int i = 0; i < length2; i++) {
0268:                    if (p1.sequence.equals(p2.choice.alternatives.get(i).name)) {
0269:                        index = i;
0270:                        break;
0271:                    }
0272:                }
0273:
0274:                if (-1 == index) {
0275:                    StringBuilder buf = new StringBuilder();
0276:                    buf.append("unable to add new alternative");
0277:                    if (1 != p1.choice.alternatives.size()) {
0278:                        buf.append('s');
0279:                    }
0280:                    if (p1.isBefore) {
0281:                        buf.append(" before ");
0282:                    } else {
0283:                        buf.append(" after ");
0284:                    }
0285:                    buf.append("non-existent alternative '");
0286:                    buf.append(p1.sequence.name);
0287:                    buf.append("'");
0288:                    runtime.error(buf.toString(), p1.sequence);
0289:
0290:                } else {
0291:                    if (!p1.isBefore) {
0292:                        index++;
0293:                    }
0294:                    p2.choice.alternatives
0295:                            .addAll(index, p1.choice.alternatives);
0296:                }
0297:            }
0298:
0299:            /**
0300:             * Apply the specified alternative removal to the specified full
0301:             * production.
0302:             *
0303:             * @param p1 The alternative removal.
0304:             * @param p2 The full production.
0305:             */
0306:            protected void apply(AlternativeRemoval p1, FullProduction p2) {
0307:                for (SequenceName name : p1.sequences) {
0308:                    boolean removed = false;
0309:
0310:                    for (Iterator<Sequence> iter = p2.choice.alternatives
0311:                            .iterator(); iter.hasNext();) {
0312:                        if (name.equals(iter.next().name)) {
0313:                            iter.remove();
0314:                            removed = true;
0315:                            break;
0316:                        }
0317:                    }
0318:
0319:                    if (!removed) {
0320:                        runtime.error(
0321:                                "unable to remove non-existent alternative '"
0322:                                        + name + "'", name);
0323:                    }
0324:                }
0325:            }
0326:
0327:            /**
0328:             * Apply the specified production override to the specified full
0329:             * production.
0330:             *
0331:             * @param p1 The production override.
0332:             * @param p2 The full production.
0333:             */
0334:            protected void apply(ProductionOverride p1, FullProduction p2) {
0335:                // Override the attributes.
0336:                if (null != p1.attributes) {
0337:                    p2.attributes = p1.attributes;
0338:                }
0339:
0340:                // Override the element.
0341:                if (null != p1.choice) {
0342:                    if (p1.isComplete) {
0343:                        p2.choice = p1.choice;
0344:
0345:                    } else {
0346:                        for (Sequence s1 : p1.choice.alternatives) {
0347:                            if (null == s1.name) {
0348:                                runtime.error(
0349:                                        "overriding sequence without name", s1);
0350:
0351:                            } else {
0352:                                final int length2 = p2.choice.alternatives
0353:                                        .size();
0354:                                boolean changed = false;
0355:                                for (int i = 0; i < length2; i++) {
0356:                                    Sequence s2 = p2.choice.alternatives.get(i);
0357:                                    if (s1.name.equals(s2.name)) {
0358:                                        p2.choice.alternatives.set(i, s1);
0359:                                        changed = true;
0360:                                        break;
0361:                                    }
0362:                                }
0363:
0364:                                if (!changed) {
0365:                                    runtime.error(
0366:                                            "unable to override non-existent alternative '"
0367:                                                    + s1.name + "'", s1);
0368:                                }
0369:                            }
0370:                        }
0371:                    }
0372:                }
0373:            }
0374:
0375:            /**
0376:             * Load all dependent modules.  This method loads the transitive
0377:             * closure of all dependent modules for the specified top-level
0378:             * module and returns the closure as a list, with the specified
0379:             * module being the first list element.  It checks that the
0380:             * specified top-level module is not parameterized, that the
0381:             * parameters of parameterized modules are well-formed, that
0382:             * arguments match parameters when instantiating parameterized
0383:             * modules, that different instantiations are consistent with each
0384:             * other, that a module does not have more than one modifies clause,
0385:             * and that module modifications do not result in circular
0386:             * dependencies.  This method also reports any file access and
0387:             * parsing errors.  Finally, this method fills in the auxiliary
0388:             * modification field for all loaded modules.
0389:             *
0390:             * @param m The module.
0391:             * @return The corresponding grammar or <code>null</code> in the
0392:             *   case of errors.
0393:             */
0394:            protected Grammar load(Module m) {
0395:                // Make sure the top-level module is not parameterized.
0396:                if ((null != m.parameters) && (0 < m.parameters.size())) {
0397:                    runtime.error("parameterized top-level module '"
0398:                            + m.name.name + "'", m.name);
0399:                    return null;
0400:                }
0401:
0402:                // Print top-level module if so requested.
0403:                PrettyPrinter pp = null;
0404:                if (runtime.test("optionLoaded")) {
0405:                    pp = new PrettyPrinter(runtime.console(), ast, true);
0406:                    pp.dispatch(m);
0407:                    pp.flush();
0408:                }
0409:
0410:                // Prepare for loading all dependent modules.  The modules list
0411:                // contains all correctly loaded modules.  The module map contains
0412:                // a mapping between visible module names (as strings) and
0413:                // modules.  The loaded map contains a mapping between visible
0414:                // module names and the corresponding module dependencies (even if
0415:                // the module contained errors).  The conflicts map is treated as
0416:                // a set that contains conflicting module dependencies that were
0417:                // already reported to the user.
0418:                List<Module> modules = new ArrayList<Module>();
0419:                Map<String, Module> moduleMap = new HashMap<String, Module>();
0420:                Map<ModuleName, ModuleDependency> loaded = new HashMap<ModuleName, ModuleDependency>();
0421:                Map<ModuleDependency, Boolean> conflicts = new IdentityHashMap<ModuleDependency, Boolean>();
0422:                modules.add(m);
0423:                moduleMap.put(m.name.name, m);
0424:                loaded.put(m.name, new ModuleImport(m.name));
0425:
0426:                // Process the top-level module's dependencies and fill in the
0427:                // auxiliary modification field.
0428:                List<ModuleDependency> workList = new ArrayList<ModuleDependency>();
0429:                if (null != m.dependencies) {
0430:                    for (ModuleDependency dep : m.dependencies) {
0431:                        if (dep.isModification()) {
0432:                            // Only process one modification per module and do not allow
0433:                            // self-mutilation.
0434:                            boolean process = true;
0435:                            if (null != m.modification) {
0436:                                runtime.error("duplicate modifies declaration",
0437:                                        dep);
0438:                                process = false;
0439:                            }
0440:                            if (dep.visibleName().equals(m.name)) {
0441:                                runtime.error("module '" + m.name
0442:                                        + "' modifies itself", dep);
0443:                                process = false;
0444:                            }
0445:                            if (process) {
0446:                                m.modification = (ModuleModification) dep;
0447:                                workList.add(dep);
0448:                            }
0449:
0450:                        } else {
0451:                            workList.add(dep);
0452:                        }
0453:                    }
0454:                }
0455:
0456:                // Print the signature if so requested.
0457:                if (runtime.test("optionDependencies")) {
0458:                    signature(m);
0459:                }
0460:
0461:                // Do the actual loading.
0462:                while (!workList.isEmpty()) {
0463:                    ModuleDependency dep = workList.remove(0);
0464:
0465:                    // Make sure that every module is processed only once.
0466:                    if (loaded.containsKey(dep.visibleName())) {
0467:                        ModuleDependency dep2 = loaded.get(dep.visibleName());
0468:
0469:                        // Since modules live in a global name space, all dependencies
0470:                        // need to be consistent with each other.  In particular, two
0471:                        // dependency declarations for the a module with the same name
0472:                        // either need to have exactly the same structure or the later
0473:                        // declaration must be a straight-forward declaration without
0474:                        // any arguments or target name.
0475:                        if (!dep.isConsistentWith(dep2)) {
0476:                            if (!conflicts.containsKey(dep2)) {
0477:                                conflicts.put(dep2, Boolean.TRUE);
0478:                                runtime.error(
0479:                                        "inconsistent instantiation of module '"
0480:                                                + dep2.module + dep2.arguments
0481:                                                + "' as '" + dep2.visibleName()
0482:                                                + "'", dep2);
0483:                            }
0484:                            runtime.error(
0485:                                    "inconsistent instantiation of module '"
0486:                                            + dep.module + dep.arguments
0487:                                            + "' as '" + dep.visibleName()
0488:                                            + "'", dep);
0489:                        }
0490:
0491:                        continue;
0492:                    }
0493:
0494:                    // Be verbose if so desired.
0495:                    if (runtime.test("optionVerbose")) {
0496:                        String path = Utilities.toPath(dep.module.name,
0497:                                Constants.EXT_GRAMMAR);
0498:                        File file = null;
0499:                        try {
0500:                            file = runtime.locate(path);
0501:                        } catch (Exception x) {
0502:                            // Ignore.
0503:                        }
0504:                        if (null == file) {
0505:                            System.err.println("[Loading module " + dep.module
0506:                                    + "]");
0507:                        } else {
0508:                            System.err.println("[Loading module " + dep.module
0509:                                    + " from " + file + "]");
0510:                        }
0511:                    }
0512:
0513:                    // Load module.
0514:                    Module m2 = null;
0515:
0516:                    try {
0517:                        m2 = load(dep.module.name);
0518:                    } catch (IllegalArgumentException x) {
0519:                        runtime.error(x.getMessage(), dep);
0520:
0521:                    } catch (FileNotFoundException x) {
0522:                        runtime.error(x.getMessage(), dep);
0523:
0524:                    } catch (IOException x) {
0525:                        if (null == x.getMessage()) {
0526:                            runtime
0527:                                    .error(
0528:                                            "I/O error while accessing corresponding file",
0529:                                            dep);
0530:                        } else {
0531:                            runtime.error(x.getMessage(), dep);
0532:                        }
0533:
0534:                    } catch (ParseException x) {
0535:                        System.err.print(x.getMessage());
0536:                        runtime.error();
0537:                    }
0538:
0539:                    // Remember that we touched this module, even if it didn't load
0540:                    // as there is no need to generate the same error message more
0541:                    // than once.
0542:                    loaded.put(dep.visibleName(), dep);
0543:
0544:                    // All the other work requires that we actually loaded the
0545:                    // module.
0546:                    if (null == m2)
0547:                        continue;
0548:
0549:                    // Print the module if so requested.
0550:                    if (runtime.test("optionLoaded")) {
0551:                        pp.dispatch(m2);
0552:                        pp.flush();
0553:                    }
0554:
0555:                    // Track errors in this module.
0556:                    boolean moduleError = false;
0557:
0558:                    // Make sure the module name matches the desired module name.
0559:                    if (!dep.module.equals(m2.name)) {
0560:                        String path = Utilities.toPath(dep.module.name,
0561:                                Constants.EXT_GRAMMAR);
0562:                        File file = null;
0563:                        try {
0564:                            file = runtime.locate(path);
0565:                        } catch (Exception x) {
0566:                            // Ignore.
0567:                        }
0568:                        if (null == file) {
0569:                            runtime.error("module name '" + m2.name
0570:                                    + "' inconsistent with file name", m2.name);
0571:                            moduleError = true;
0572:                        } else {
0573:                            runtime.error("module name '" + m2.name
0574:                                    + "' inconsistent with file name " + file,
0575:                                    m2.name);
0576:                            moduleError = true;
0577:                        }
0578:                    }
0579:
0580:                    // Check the module's parameters (if any).
0581:                    if (null != m2.parameters) {
0582:                        final int size = m2.parameters.size();
0583:                        for (int i = 0; i < size; i++) {
0584:                            ModuleName name = m2.parameters.get(i);
0585:
0586:                            if (m2.name.equals(name)) {
0587:                                runtime.error("module parameter '" + name
0588:                                        + "' same as module name", name);
0589:                                moduleError = true;
0590:                            }
0591:
0592:                            for (int j = 0; j < i; j++) {
0593:                                if (name.equals(m2.parameters.get(j))) {
0594:                                    runtime.error(
0595:                                            "duplicate module parameter '"
0596:                                                    + name + "'", name);
0597:                                    moduleError = true;
0598:                                    break;
0599:                                }
0600:                            }
0601:                        }
0602:                    }
0603:
0604:                    // Check that argument and parameter numbers match.
0605:                    final int argumentNumber = dep.arguments.size();
0606:                    final int parameterNumber = (null != m2.parameters) ? m2.parameters
0607:                            .size()
0608:                            : 0;
0609:                    if (argumentNumber != parameterNumber) {
0610:                        StringBuilder buf = new StringBuilder();
0611:                        buf.append(argumentNumber);
0612:                        buf.append(" argument");
0613:                        if (1 != argumentNumber) {
0614:                            buf.append('s');
0615:                        }
0616:                        buf.append(" for module '");
0617:                        buf.append(m2.name.name);
0618:                        buf.append("' with ");
0619:                        buf.append(parameterNumber);
0620:                        buf.append(" parameter");
0621:                        if (1 != parameterNumber) {
0622:                            buf.append('s');
0623:                        }
0624:                        runtime.error(buf.toString(), dep);
0625:                        moduleError = true;
0626:                    }
0627:
0628:                    // Only continue processing this module if there were no errors.
0629:                    if (moduleError)
0630:                        continue;
0631:
0632:                    // Perform any module renaming.
0633:                    if ((0 != argumentNumber)
0634:                            || (!dep.module.equals(dep.visibleName()))) {
0635:                        if (runtime.test("optionVerbose")) {
0636:                            StringBuilder buf = new StringBuilder();
0637:
0638:                            buf.append("[Instantiating module ");
0639:                            buf.append(m2.name);
0640:                            buf.append('(');
0641:                            for (int i = 0; i < argumentNumber; i++) {
0642:                                buf.append(dep.arguments.get(i).name);
0643:                                buf.append('/');
0644:                                buf.append(m2.parameters.get(i).name);
0645:                                if (i + 1 < argumentNumber) {
0646:                                    buf.append(", ");
0647:                                }
0648:                            }
0649:                            buf.append(") as ");
0650:                            buf.append(dep.visibleName().name);
0651:                            buf.append(']');
0652:                            System.err.println(buf.toString());
0653:                        }
0654:
0655:                        // Construct a module map for renaming.
0656:                        final ModuleMap renaming;
0657:                        if (0 != argumentNumber) {
0658:                            renaming = new ModuleMap(m2.parameters,
0659:                                    dep.arguments);
0660:                        } else {
0661:                            renaming = new ModuleMap();
0662:                        }
0663:
0664:                        // If the module's declared name and the visible name differ,
0665:                        // add the corresponding mapping to the module map.
0666:                        if (!dep.module.equals(dep.visibleName())) {
0667:                            renaming.put(dep.module, dep.visibleName());
0668:                        }
0669:
0670:                        // Rename the module.
0671:                        rename(m2, renaming);
0672:
0673:                        // The parameters are nulled out below to enable the printing
0674:                        // of module dependencies.
0675:                    }
0676:
0677:                    // Add the module to the list of modules and put the module in
0678:                    // the module map.
0679:                    modules.add(m2);
0680:                    moduleMap.put(m2.name.name, m2);
0681:
0682:                    // Process any further dependencies and fill in the module's
0683:                    // auxiliary modification field.
0684:                    if (null != m2.dependencies) {
0685:                        for (ModuleDependency dep2 : m2.dependencies) {
0686:                            if (dep2.isModification()) {
0687:                                // Only process one modification per module and do not
0688:                                // allow self-mutilation.
0689:                                boolean process = true;
0690:                                if (null != m2.modification) {
0691:                                    runtime.error(
0692:                                            "duplicate modifies declaration",
0693:                                            dep2);
0694:                                    process = false;
0695:                                }
0696:                                if (dep2.visibleName().equals(m2.name)) {
0697:                                    runtime.error("module '" + m2.name
0698:                                            + "' modifies itself", dep2);
0699:                                    process = false;
0700:                                }
0701:                                if (process) {
0702:                                    m2.modification = (ModuleModification) dep2;
0703:                                    workList.add(dep2);
0704:                                }
0705:
0706:                            } else {
0707:                                workList.add(dep2);
0708:                            }
0709:                        }
0710:                    }
0711:
0712:                    // Print the signature, if so desired.
0713:                    if (runtime.test("optionDependencies")) {
0714:                        signature(m2);
0715:                    }
0716:                    if (null != m2.parameters) {
0717:                        m2.setProperty(Constants.ARGUMENTS, m2.parameters);
0718:                        m2.parameters = null;
0719:                    }
0720:                }
0721:
0722:                // Now, check for circular module modifications.  The checked set
0723:                // tracks the names of modules that have been checked.  The
0724:                // checking map contains a mapping from module names (as module
0725:                // names) to booleans.  False indicates that the module has been
0726:                // checked once.  True indicates that the module has been checked
0727:                // twice, meaning it is part of a circular chain of dependencies.
0728:                Map<ModuleName, Boolean> checking = new HashMap<ModuleName, Boolean>();
0729:                Set<ModuleName> checked = new HashSet<ModuleName>();
0730:                for (Module m2 : modules) {
0731:                    // If the module has been checked already, move on.
0732:                    if (checked.contains(m2.name))
0733:                        continue;
0734:
0735:                    // Reset the checking map.
0736:                    checking.clear();
0737:
0738:                    do {
0739:                        if (checking.containsKey(m2.name)) {
0740:                            boolean circular = checking.get(m2.name);
0741:
0742:                            if (circular) {
0743:                                // We are checking this module for the third time and can
0744:                                // therefore stop walking the dependencies.
0745:                                break;
0746:
0747:                            } else {
0748:                                // We are checking this module for the second time.
0749:                                checking.put(m2.name, Boolean.TRUE);
0750:                            }
0751:
0752:                        } else {
0753:                            // We are checking this module for the first time.
0754:                            checking.put(m2.name, Boolean.FALSE);
0755:                        }
0756:
0757:                        // If this module has a modifies clause, we check the
0758:                        // corresponding module next.
0759:                        if (null != m2.modification) {
0760:                            // Look up the corresponding module.
0761:                            m2 = moduleMap
0762:                                    .get(m2.modification.visibleName().name);
0763:
0764:                            if (null == m2) {
0765:                                // This is an unresolved or erroneous dependency.  We need
0766:                                // to stop here.
0767:                                break;
0768:                            }
0769:
0770:                        } else {
0771:                            // This module does not modify another.
0772:                            break;
0773:                        }
0774:                    } while (true);
0775:
0776:                    // Remember all visited modules and report errors for all
0777:                    // circular dependencies.  We do this in order of the resolved
0778:                    // modules to print errors in a standardized order.
0779:                    for (Module m3 : modules) {
0780:                        if (checking.containsKey(m3.name)) {
0781:                            // Remember as visited.
0782:                            checked.add(m3.name);
0783:
0784:                            // Report error.
0785:                            if (checking.get(m3.name)) {
0786:                                runtime.error("circular modifies dependency",
0787:                                        m3.modification);
0788:                            }
0789:                        }
0790:                    }
0791:                }
0792:
0793:                // Create the grammar.
0794:                Grammar g = new Grammar(modules);
0795:
0796:                // Print instantiated modules, if so requested.
0797:                if (runtime.test("optionInstantiated")) {
0798:                    if (runtime.test("optionHtml")) {
0799:                        new HtmlPrinter(runtime, analyzer, ast, false)
0800:                                .dispatch(g);
0801:                    } else {
0802:                        pp = new PrettyPrinter(runtime.console(), ast, true);
0803:                        pp.dispatch(g);
0804:                        pp.flush();
0805:                    }
0806:                }
0807:
0808:                // We are done. 
0809:                return runtime.seenError() ? null : g;
0810:            }
0811:
0812:            /**
0813:             * Perform basic checking for the specified grammar.  This method
0814:             * does all correctness checking besides checking the contents of
0815:             * partial productions and checking for left-recursive definitions.
0816:             * Note that this method initializes the analyzer with the specified
0817:             * grammar.
0818:             *
0819:             * @param g The grammar.
0820:             * @return The list of global attributes, if any.
0821:             */
0822:            protected List<Attribute> check(Grammar g) {
0823:                // Initialize the analyzer.
0824:                analyzer.register(this );
0825:                analyzer.init(g);
0826:                phase = 1;
0827:
0828:                // Initialize the top-level module and the list of global
0829:                // attributes.
0830:                Module root = g.modules.get(0);
0831:                List<Attribute> attributes = new ArrayList<Attribute>();
0832:
0833:                // Make sure that any stateful attributes agree in their class
0834:                // names.  Additionally, collect any stateful, set, or flag
0835:                // attributes in the global list of attributes.
0836:                String stateName = null;
0837:                boolean stateError = false;
0838:                for (Module m2 : g.modules) {
0839:                    // Process stateful attribute.
0840:                    if (m2.hasAttribute(Constants.ATT_STATEFUL.getName())) {
0841:                        Attribute state = Attribute.get(Constants.ATT_STATEFUL
0842:                                .getName(), m2.attributes);
0843:                        Object value = state.getValue();
0844:                        if ((null != value) && (value instanceof  String)
0845:                                && (!((String) value).startsWith("\""))) {
0846:                            if (null == stateName) {
0847:                                attributes.add(state);
0848:                                stateName = (String) state.getValue();
0849:                            }
0850:                            if (!stateName.equals(state.getValue())) {
0851:                                stateError = true;
0852:                            }
0853:                        }
0854:                    }
0855:
0856:                    // Process set and flag attributes.
0857:                    if (m2.hasAttribute(Constants.NAME_STRING_SET)
0858:                            || m2.hasAttribute(Constants.NAME_FLAG)) {
0859:                        for (Attribute att : m2.attributes) {
0860:                            String name = att.getName();
0861:                            if ((Constants.NAME_STRING_SET.equals(name) || Constants.NAME_FLAG
0862:                                    .equals(name))
0863:                                    && (!attributes.contains(att))) {
0864:                                attributes.add(att);
0865:                            }
0866:                        }
0867:                    }
0868:                }
0869:
0870:                // Now, do the actual well-formedness checking.
0871:                Set<ModuleName> visited = new HashSet<ModuleName>();
0872:                boolean hasTopLevel = false;
0873:                for (Module m2 : g.modules) {
0874:                    analyzer.process(m2);
0875:                    hasState = false;
0876:                    isMofunctor = (null != m2.modification);
0877:
0878:                    if (null != m2.attributes) {
0879:                        final int length = m2.attributes.size();
0880:                        for (int i = 0; i < length; i++) {
0881:                            Attribute att = m2.attributes.get(i);
0882:                            String name = att.getName();
0883:                            Object value = att.getValue();
0884:
0885:                            if ((!Constants.ATT_WITH_LOCATION.equals(att))
0886:                                    && (!Constants.ATT_CONSTANT.equals(att))
0887:                                    && (!Constants.ATT_RAW_TYPES.equals(att))
0888:                                    && (!Constants.ATT_VERBOSE.equals(att))
0889:                                    && (!Constants.ATT_NO_WARNINGS.equals(att))
0890:                                    && (!Constants.ATT_IGNORING_CASE
0891:                                            .equals(att))
0892:                                    && (!Constants.ATT_STATEFUL.getName()
0893:                                            .equals(name))
0894:                                    && (!Constants.NAME_PARSER.equals(name))
0895:                                    && (!Constants.NAME_MAIN.equals(name))
0896:                                    && (!Constants.NAME_PRINTER.equals(name))
0897:                                    && (!Constants.NAME_VISIBILITY.equals(name))
0898:                                    && (!Constants.NAME_STRING_SET.equals(name))
0899:                                    && (!Constants.NAME_FLAG.equals(name))
0900:                                    && (!Constants.NAME_FACTORY.equals(name))
0901:                                    && (!Constants.ATT_FLATTEN.equals(att))
0902:                                    && (!Constants.ATT_GENERIC_AS_VOID
0903:                                            .equals(att))
0904:                                    && (!Constants.ATT_PARSE_TREE.equals(att))
0905:                                    && (!Constants.ATT_PROFILE.equals(att))
0906:                                    && (!Constants.ATT_DUMP.equals(att))) {
0907:                                runtime.error(
0908:                                        "unrecognized grammar-wide attribute '"
0909:                                                + att + "'", att);
0910:
0911:                            } else {
0912:                                for (int j = 0; j < i; j++) {
0913:                                    Attribute att2 = m2.attributes.get(j);
0914:                                    if (name.equals(Constants.NAME_STRING_SET)
0915:                                            || name.equals(Constants.NAME_FLAG)) {
0916:                                        if (att.equals(att2)) {
0917:                                            runtime.error(
0918:                                                    "duplicate attribute '"
0919:                                                            + att + "'", att);
0920:                                            break;
0921:                                        } else if ((null != value)
0922:                                                && value
0923:                                                        .equals(att2.getValue())) {
0924:                                            runtime.error(
0925:                                                    "duplicate field name '"
0926:                                                            + att + "'", att);
0927:                                        }
0928:
0929:                                    } else if (name.equals(att2.getName())) {
0930:                                        runtime.error("duplicate attribute '"
0931:                                                + name + "'", att);
0932:                                        break;
0933:                                    }
0934:                                }
0935:                            }
0936:
0937:                            if (Constants.ATT_STATEFUL.getName().equals(name)) {
0938:                                if (null == value) {
0939:                                    runtime
0940:                                            .error(
0941:                                                    "stateful attribute without class name",
0942:                                                    att);
0943:                                } else if (!(value instanceof  String)) {
0944:                                    runtime
0945:                                            .error(
0946:                                                    "stateful attribute with invalid value",
0947:                                                    att);
0948:                                } else if (((String) value).startsWith("\"")) {
0949:                                    runtime
0950:                                            .error(
0951:                                                    "stateful attribute with invalid value",
0952:                                                    att);
0953:                                } else if (stateError) {
0954:                                    runtime
0955:                                            .error(
0956:                                                    "inconsistent state class across modules",
0957:                                                    att);
0958:                                }
0959:                                hasState = true;
0960:
0961:                            } else if (Constants.NAME_PARSER.equals(name)) {
0962:                                if (null == value) {
0963:                                    runtime
0964:                                            .error(
0965:                                                    "parser attribute without class name",
0966:                                                    att);
0967:                                } else if (!(value instanceof  String)) {
0968:                                    runtime
0969:                                            .error(
0970:                                                    "parser attribute with invalid value",
0971:                                                    att);
0972:                                } else if (((String) value).startsWith("\"")) {
0973:                                    runtime
0974:                                            .error(
0975:                                                    "parser attribute with invalid value",
0976:                                                    att);
0977:                                }
0978:
0979:                            } else if (Constants.NAME_MAIN.equals(name)) {
0980:                                if (runtime.test("optionLGPL")) {
0981:                                    runtime
0982:                                            .error(
0983:                                                    "main attribute incompatible with LGPL",
0984:                                                    att);
0985:                                } else if (null == value) {
0986:                                    runtime
0987:                                            .error(
0988:                                                    "main attribute without nonterminal value",
0989:                                                    att);
0990:                                } else if (!(value instanceof  String)) {
0991:                                    runtime
0992:                                            .error(
0993:                                                    "main attribute with invalid value",
0994:                                                    att);
0995:                                } else if (((String) value).startsWith("\"")) {
0996:                                    runtime
0997:                                            .error(
0998:                                                    "main attribute with invalid value",
0999:                                                    att);
1000:                                } else {
1001:                                    NonTerminal nt = new NonTerminal(
1002:                                            (String) value);
1003:                                    Production p = null;
1004:                                    boolean err = false;
1005:
1006:                                    try {
1007:                                        p = analyzer.lookup(nt);
1008:                                    } catch (IllegalArgumentException x) {
1009:                                        runtime.error(
1010:                                                "main attribute with ambiguous nonterminal '"
1011:                                                        + nt + "'", att);
1012:                                        err = true;
1013:                                    }
1014:
1015:                                    if (!err) {
1016:                                        if (null == p) {
1017:                                            runtime.error(
1018:                                                    "main attribute with undefined nonterminal '"
1019:                                                            + nt + "'", att);
1020:                                        } else if (!analyzer.isDefined(p, m2)) {
1021:                                            runtime.error(
1022:                                                    "main attribute with another module's "
1023:                                                            + "nonterminal '"
1024:                                                            + nt + "'", att);
1025:                                        } else if (!p
1026:                                                .hasAttribute(Constants.ATT_PUBLIC)) {
1027:                                            runtime.error(
1028:                                                    "main attribute with non-public nonterminal '"
1029:                                                            + nt + "'", att);
1030:                                        }
1031:                                    }
1032:                                }
1033:
1034:                            } else if (Constants.NAME_PRINTER.equals(name)) {
1035:                                if (runtime.test("optionLGPL")) {
1036:                                    runtime
1037:                                            .error(
1038:                                                    "printer attribute incompatible with LGPL",
1039:                                                    att);
1040:                                } else if (null == value) {
1041:                                    runtime
1042:                                            .error(
1043:                                                    "printer attribute without class name",
1044:                                                    att);
1045:                                } else if (!(value instanceof  String)) {
1046:                                    runtime
1047:                                            .error(
1048:                                                    "printer attribute with invalid value",
1049:                                                    att);
1050:                                } else if (((String) value).startsWith("\"")) {
1051:                                    runtime
1052:                                            .error(
1053:                                                    "printer attribute with invalid value",
1054:                                                    att);
1055:                                }
1056:                                if (!m2.hasAttribute(Constants.NAME_MAIN)) {
1057:                                    runtime
1058:                                            .error(
1059:                                                    "printer attribute without main attribute",
1060:                                                    att);
1061:                                }
1062:
1063:                            } else if (Constants.NAME_VISIBILITY.equals(name)) {
1064:                                if (null == value) {
1065:                                    runtime
1066:                                            .error(
1067:                                                    "visibility attribute without value",
1068:                                                    att);
1069:                                } else if ((!Constants.ATT_PUBLIC.getValue()
1070:                                        .equals(value))
1071:                                        && (!Constants.ATT_PACKAGE_PRIVATE
1072:                                                .getValue().equals(value))) {
1073:                                    runtime
1074:                                            .error(
1075:                                                    "visibility attribute with invalid value",
1076:                                                    att);
1077:                                }
1078:
1079:                            } else if (Constants.NAME_STRING_SET.equals(name)) {
1080:                                if (null == value) {
1081:                                    runtime
1082:                                            .error(
1083:                                                    "string set attribute without set value",
1084:                                                    att);
1085:                                } else if (!(value instanceof  String)) {
1086:                                    runtime
1087:                                            .error(
1088:                                                    "string set attribute with invalid value",
1089:                                                    att);
1090:                                } else if (((String) value).startsWith("\"")) {
1091:                                    runtime
1092:                                            .error(
1093:                                                    "string set attribute with invalid value",
1094:                                                    att);
1095:                                }
1096:
1097:                            } else if (Constants.NAME_FLAG.equals(name)) {
1098:                                if (null == value) {
1099:                                    runtime
1100:                                            .error(
1101:                                                    "flag attribute without flag value",
1102:                                                    att);
1103:                                } else if (!(value instanceof  String)) {
1104:                                    runtime
1105:                                            .error(
1106:                                                    "flag attribute with invalid value",
1107:                                                    att);
1108:                                } else if (((String) value).startsWith("\"")) {
1109:                                    runtime
1110:                                            .error(
1111:                                                    "flag attribute with invalid value",
1112:                                                    att);
1113:                                }
1114:
1115:                            } else if (Constants.NAME_FACTORY.equals(name)) {
1116:                                if (null == value) {
1117:                                    runtime
1118:                                            .error(
1119:                                                    "factory attribute without class name",
1120:                                                    att);
1121:                                } else if (!(value instanceof  String)) {
1122:                                    runtime
1123:                                            .error(
1124:                                                    "factory attribute with invalid value",
1125:                                                    att);
1126:                                } else if (((String) value).startsWith("\"")) {
1127:                                    runtime
1128:                                            .error(
1129:                                                    "factory attribute with invalud value",
1130:                                                    att);
1131:                                }
1132:
1133:                            } else if (Constants.ATT_GENERIC_AS_VOID
1134:                                    .equals(att)) {
1135:                                if (m2.hasAttribute(Constants.ATT_PARSE_TREE)) {
1136:                                    runtime
1137:                                            .error(
1138:                                                    "genericAsVoid attribute incompatible with "
1139:                                                            + "withParseTree attribute",
1140:                                                    att);
1141:                                }
1142:
1143:                            } else if (Constants.ATT_DUMP.equals(att)) {
1144:                                if (runtime.test("optionLGPL")) {
1145:                                    runtime
1146:                                            .error(
1147:                                                    "dump attribute incompatible with LGPL",
1148:                                                    att);
1149:                                }
1150:
1151:                            } else if (Constants.ATT_RAW_TYPES.equals(att)) {
1152:                                runtime
1153:                                        .warning(
1154:                                                "the rawTypes attribute has been deprecated",
1155:                                                att);
1156:                                runtime
1157:                                        .errConsole()
1158:                                        .loc(att)
1159:                                        .pln(
1160:                                                ": warning: and will be removed in a future release")
1161:                                        .flush();
1162:                            }
1163:                        }
1164:                    }
1165:
1166:                    // If this module does not have a stateful attribute, check the
1167:                    // the current module's direct imports as well as any modified
1168:                    // modules and their direct imports.
1169:                    if (!hasState) {
1170:                        hasState = analyzer.hasAttribute(m2,
1171:                                Constants.ATT_STATEFUL.getName(), visited);
1172:                        visited.clear();
1173:                    }
1174:
1175:                    // Check the productions.
1176:                    for (Production p : m2.productions) {
1177:                        // Initialize the per-production state.
1178:                        sequenceNames.clear();
1179:
1180:                        // Process the production.
1181:                        analyzer.process(p);
1182:
1183:                        // Check for duplicate definitions.
1184:                        try {
1185:                            if ((!p.isPartial())
1186:                                    && (p != analyzer.lookup(p.name))) {
1187:                                runtime.error(
1188:                                        "duplicate definition for nonterminal '"
1189:                                                + p.name + "'", p);
1190:                            }
1191:                        } catch (IllegalArgumentException x) {
1192:                            runtime.error(
1193:                                    "duplicate definition for nonterminal '"
1194:                                            + p.name + "'", p);
1195:                        }
1196:
1197:                        // Process top-level productions.  Only public productions
1198:                        // from the top-level module are recognized as top-level for
1199:                        // the entire grammar.
1200:                        if (p.hasAttribute(Constants.ATT_PUBLIC)) {
1201:                            if (analyzer.isDefined(p, root)) {
1202:                                hasTopLevel = true;
1203:                            } else {
1204:                                p.attributes.remove(Constants.ATT_PUBLIC);
1205:                            }
1206:                        }
1207:                    }
1208:                }
1209:
1210:                // Check for top-level nonterminals.
1211:                if (!hasTopLevel) {
1212:                    runtime.error("no public nonterminal",
1213:                            g.modules.get(0).productions.get(0));
1214:                }
1215:
1216:                // Done.
1217:                return attributes;
1218:            }
1219:
1220:            /**
1221:             * Apply any module modifications.  This method applies all module
1222:             * modifications appearing in the specified grammar.  It also
1223:             * removes unused modules from the grammar.  This method assumes
1224:             * that all module dependencies have been successfully resolved,
1225:             * i.e., the specified grammar contains all module dependencies.
1226:             * This method also assumes that each module modification's {@link
1227:             * Module#modification modification} field has been correctly
1228:             * initialized.
1229:             *
1230:             * @param g The grammar.
1231:             */
1232:            protected void applyModifications(Grammar g) {
1233:                // Initialize the analyzer.
1234:                analyzer.register(this );
1235:                analyzer.init(g);
1236:                phase = 2;
1237:
1238:                // Calculate the transitive closure of imported and modified
1239:                // modules.
1240:                Module root = g.modules.get(0);
1241:                Set<ModuleName> imports = new HashSet<ModuleName>();
1242:                Map<ModuleName, Boolean> modified = new HashMap<ModuleName, Boolean>();
1243:                imports.add(root.name);
1244:                analyzer.trace(root, imports, modified);
1245:
1246:                // Remove any modules that are not reachable from the top-level
1247:                // module (i.e., modules that have been instantiated but never
1248:                // imported or modified).
1249:                for (Iterator<Module> iter = g.modules.iterator(); iter
1250:                        .hasNext();) {
1251:                    Module m = iter.next();
1252:                    if ((!imports.contains(m.name))
1253:                            && (!modified.containsKey(m.name))) {
1254:                        if (runtime.test("optionVerbose")) {
1255:                            System.err.println("[Unloading unused module "
1256:                                    + m.name + "]");
1257:                        }
1258:                        analyzer.remove(m);
1259:                        iter.remove();
1260:                    }
1261:                }
1262:
1263:                // If there are any modifications, apply them.
1264:                if (0 != modified.size()) {
1265:                    // Set up the list of module modifications (in dependency order)
1266:                    // and the base module they are applied to.  Also track the set
1267:                    // of modules with errors.  Furthermore, track the set of
1268:                    // modules checked in phase 2.  Finally, create the maps for the
1269:                    // target module's productions and for both the target and
1270:                    // source modules' productions.
1271:                    List<Module> mofunctors = new ArrayList<Module>();
1272:                    Module base;
1273:                    Set<Module> erroneous = new HashSet<Module>();
1274:                    Set<Module> checked = new HashSet<Module>();
1275:                    Map<NonTerminal, Production> targetProductions = new HashMap<NonTerminal, Production>();
1276:                    Map<NonTerminal, Production> productions = new HashMap<NonTerminal, Production>();
1277:
1278:                    while (true) {
1279:                        // Find a module modification to apply.
1280:                        mofunctors.clear();
1281:                        base = null;
1282:                        for (Module m : g.modules) {
1283:                            if ((null != m.modification)
1284:                                    && (!erroneous.contains(m))) {
1285:                                // We found a module modification without errors.  Follow
1286:                                // the the chain of dependencies until we reach the base
1287:                                // module.
1288:                                do {
1289:                                    mofunctors.add(m);
1290:                                    m = analyzer.lookup(m.modification
1291:                                            .visibleName());
1292:                                } while (null != m.modification);
1293:                                base = m;
1294:
1295:                                if (erroneous.contains(base)) {
1296:                                    // We have seen an error before.
1297:                                    erroneous.addAll(mofunctors);
1298:                                    base = null;
1299:                                }
1300:
1301:                                // We are done looking for a module modification.
1302:                                break;
1303:                            }
1304:                        }
1305:
1306:                        if (null == base) {
1307:                            // Nothing left to do, either because all module
1308:                            // modifications have been applied or there have been
1309:                            // errors.
1310:                            break;
1311:                        }
1312:
1313:                        // Set up the target module.
1314:                        Module target = base;
1315:
1316:                        // Iterate over the module modifications and apply them to the
1317:                        // target.
1318:                        for (int i = mofunctors.size() - 1; i >= 0; i--) {
1319:                            Module source = mofunctors.get(i);
1320:
1321:                            if (runtime.test("optionVerbose")) {
1322:                                System.err.println("[Applying module "
1323:                                        + source.name + " to module "
1324:                                        + target.name + "]");
1325:                            }
1326:
1327:                            // If the target module is modified in more than one way or
1328:                            // both modified and imported, then we need to modify a
1329:                            // copy.
1330:                            if (modified.get(target.name)
1331:                                    || (modified.containsKey(target.name) && imports
1332:                                            .contains(target.name))) {
1333:                                if (runtime.test("optionVerbose")) {
1334:                                    System.err
1335:                                            .println("[Copying modified module "
1336:                                                    + target.name + "]");
1337:                                }
1338:                                target = analyzer.copy(target);
1339:
1340:                            } else {
1341:                                // Remove the module from the analyzer's state, since we
1342:                                // will update that state after applying the modification.
1343:                                // Also, remove the module from the grammar, as it
1344:                                // replaces the source module.
1345:                                if (runtime.test("optionVerbose")) {
1346:                                    System.err
1347:                                            .println("[Removing modified module "
1348:                                                    + target.name + "]");
1349:                                }
1350:                                analyzer.remove(target);
1351:                                g.remove(target);
1352:                            }
1353:
1354:                            // Since the source module is effectively replaced by the
1355:                            // target module, we remove it from the analyzer state and
1356:                            // replace it in the grammar.  We need to preserve the
1357:                            // position in the grammar as the top-level module may be a
1358:                            // module modification.
1359:                            if (runtime.test("optionVerbose")) {
1360:                                System.err
1361:                                        .println("[Removing modifying module "
1362:                                                + source.name + "]");
1363:                            }
1364:                            analyzer.remove(source);
1365:                            g.replace(source, target);
1366:
1367:                            // Rename the target module.
1368:                            rename(target, new ModuleMap(target.name,
1369:                                    source.name));
1370:
1371:                            // Patch the target module's documentation comment.
1372:                            target.documentation = source.documentation;
1373:
1374:                            // Explicitly replace the target module's name with the
1375:                            // source module's to preserve the original name, if any.
1376:                            target.name = source.name;
1377:
1378:                            // Similarly, patch the arguments property.
1379:                            target.removeProperty(Constants.ARGUMENTS);
1380:                            if (source.hasProperty(Constants.ARGUMENTS)) {
1381:                                target.setProperty(Constants.ARGUMENTS, source
1382:                                        .getProperty(Constants.ARGUMENTS));
1383:                            }
1384:
1385:                            // Add the source module's dependencies, with exception of
1386:                            // the modification, to the target module's dependencies.
1387:                            // Note that we don't need to check whether the source
1388:                            // module has dependencies, as it must have at least one
1389:                            // modification dependency.
1390:                            Iterator<ModuleDependency> iter2 = source.dependencies
1391:                                    .iterator();
1392:                            while (iter2.hasNext()) {
1393:                                if (iter2.next().isModification()) {
1394:                                    iter2.remove();
1395:                                    // We continue iterating, just in case that there are
1396:                                    // several modifications.
1397:                                }
1398:                            }
1399:
1400:                            if (null == target.dependencies) {
1401:                                target.dependencies = source.dependencies;
1402:                            } else {
1403:                                target.dependencies.addAll(source.dependencies);
1404:                            }
1405:
1406:                            // Add the source module's header, body, and footer actions
1407:                            // to the target module, if they exist.
1408:                            if (null != source.header) {
1409:                                if (null == target.header) {
1410:                                    target.header = source.header;
1411:                                } else {
1412:                                    target.header.add(source.header);
1413:                                }
1414:                            }
1415:
1416:                            if (null != source.body) {
1417:                                if (null == target.body) {
1418:                                    target.body = source.body;
1419:                                } else {
1420:                                    target.body.add(source.body);
1421:                                }
1422:                            }
1423:
1424:                            if (null != source.footer) {
1425:                                if (null == target.footer) {
1426:                                    target.footer = source.footer;
1427:                                } else {
1428:                                    target.footer.add(source.footer);
1429:                                }
1430:                            }
1431:
1432:                            // Replace the target module's options with the source
1433:                            // module's options.  However, if the target module has a
1434:                            // stateful, set, or flag option, while the source module
1435:                            // does not have that same option, add the corresponding
1436:                            // option to the list of options first.
1437:                            if (null != target.attributes) {
1438:                                // Process stateful attribute.
1439:                                if (target.hasAttribute(Constants.ATT_STATEFUL
1440:                                        .getName())) {
1441:                                    if (null == source.attributes) {
1442:                                        source.attributes = new ArrayList<Attribute>();
1443:                                    }
1444:                                    if (!source
1445:                                            .hasAttribute(Constants.ATT_STATEFUL
1446:                                                    .getName())) {
1447:                                        source.attributes.add(Attribute.get(
1448:                                                Constants.ATT_STATEFUL
1449:                                                        .getName(),
1450:                                                target.attributes));
1451:                                    }
1452:                                }
1453:
1454:                                // Process set and flag attributes.
1455:                                if (target
1456:                                        .hasAttribute(Constants.NAME_STRING_SET)
1457:                                        || target
1458:                                                .hasAttribute(Constants.NAME_FLAG)) {
1459:                                    if (null == source.attributes) {
1460:                                        source.attributes = new ArrayList<Attribute>();
1461:                                    }
1462:                                    for (Attribute att : target.attributes) {
1463:                                        String name = att.getName();
1464:                                        if ((Constants.NAME_STRING_SET
1465:                                                .equals(name) || Constants.NAME_FLAG
1466:                                                .equals(name))
1467:                                                && (!source.attributes
1468:                                                        .contains(att))) {
1469:                                            source.attributes.add(att);
1470:                                        }
1471:                                    }
1472:                                }
1473:                            }
1474:                            target.attributes = source.attributes;
1475:
1476:                            // Build a map of the target module's productions and a map
1477:                            // of both the target and source modules' productions.
1478:                            // While building the maps, also strip each production.
1479:                            targetProductions.clear();
1480:                            productions.clear();
1481:                            for (Production p : target.productions) {
1482:                                p = strip(p);
1483:                                if (p.isFull()
1484:                                        && (!productions.containsKey(p.name))) {
1485:                                    targetProductions.put(p.name, p);
1486:                                    productions.put(p.name, p);
1487:                                }
1488:                            }
1489:                            for (Production p : source.productions) {
1490:                                p = strip(p);
1491:                                if (p.isFull()
1492:                                        && (!productions.containsKey(p.name))) {
1493:                                    productions.put(p.name, p);
1494:                                }
1495:                            }
1496:
1497:                            // Process the source module's productions.
1498:                            int errorCount = runtime.errorCount();
1499:                            for (Production p1 : source.productions) {
1500:                                FullProduction p2 = (FullProduction) productions
1501:                                        .get(p1.name);
1502:
1503:                                if (p1.isFull()) {
1504:                                    // If the source module's production is a duplicate
1505:                                    // definition, that error has already been reported.
1506:                                    // Otherwise, we simply add it to the target module.
1507:                                    if (!targetProductions.containsKey(p1.name)) {
1508:                                        target.productions.add(p1);
1509:                                        targetProductions.put(p1.name, p1);
1510:                                    }
1511:
1512:                                } else if (null != p2) {
1513:                                    if (p1.isAddition()) {
1514:                                        apply((AlternativeAddition) p1, p2);
1515:
1516:                                    } else if (p1.isRemoval()) {
1517:                                        apply((AlternativeRemoval) p1, p2);
1518:
1519:                                    } else if (p1.isOverride()) {
1520:                                        apply((ProductionOverride) p1, p2);
1521:
1522:                                    } else {
1523:                                        throw new AssertionError(
1524:                                                "Unrecognized production " + p1);
1525:                                    }
1526:                                }
1527:                            }
1528:
1529:                            // Add the target module into the analyzer's state.  Also,
1530:                            // mark the target module as checked in phase 2.
1531:                            if (runtime.test("optionVerbose")) {
1532:                                System.err.println("[Adding resulting module "
1533:                                        + target.name + "]");
1534:                            }
1535:                            analyzer.add(target);
1536:                            checked.add(target);
1537:
1538:                            // Re-check the target module for duplicate sequence names
1539:                            // and for ambiguous or undefined nonterminals.
1540:                            analyzer.process(target);
1541:                            for (Production p : target.productions) {
1542:                                sequenceNames.clear();
1543:                                analyzer.process(p);
1544:                            }
1545:
1546:                            // If we have seen any errors, we mark the target module and
1547:                            // any remaining module modifications as erroneous.
1548:                            if (runtime.errorCount() != errorCount) {
1549:                                erroneous.add(target);
1550:                                List<Module> l = mofunctors.subList(0, i);
1551:                                erroneous.addAll(l);
1552:                                checked.addAll(l);
1553:                            }
1554:                        }
1555:
1556:                        // Recalculate the transitive closure of imported and modified
1557:                        // modules.  We have to re-initialize the root, since that
1558:                        // module may have changed.
1559:                        root = g.modules.get(0);
1560:                        imports.clear();
1561:                        modified.clear();
1562:                        imports.add(root.name);
1563:                        analyzer.trace(root, imports, modified);
1564:
1565:                        // We do not need to remove unreachable modules, because the
1566:                        // initial removal has already removed all of them.
1567:                    }
1568:
1569:                    // Check all modules that have not been checked in phase 2 in
1570:                    // order to detect amgibuous nonterminals.
1571:                    phase = 3;
1572:                    for (Module m : g.modules) {
1573:                        if (!checked.contains(m)) {
1574:                            analyzer.process(m);
1575:                            for (Production p : m.productions) {
1576:                                analyzer.process(p);
1577:                            }
1578:                        }
1579:                    }
1580:                }
1581:
1582:                // Print the resulting modules if requested.
1583:                if (runtime.test("optionApplied")) {
1584:                    if (runtime.test("optionHtml")) {
1585:                        new HtmlPrinter(runtime, analyzer, ast, false)
1586:                                .dispatch(g);
1587:                    } else {
1588:                        PrettyPrinter pp = new PrettyPrinter(runtime.console(),
1589:                                ast, true);
1590:                        pp.dispatch(g);
1591:                        pp.flush();
1592:                    }
1593:                }
1594:
1595:                // Done.
1596:            }
1597:
1598:            /**
1599:             * Intern the grammar's types.  This method assumes that all module
1600:             * modifications have been applied.
1601:             *
1602:             * @param g The grammar.
1603:             */
1604:            protected void internTypes(Grammar g) {
1605:                // Determine the grammar's features.
1606:                boolean hasNode = false;
1607:                boolean hasToken = false;
1608:                boolean hasFormatting = false;
1609:                boolean hasAction = false;
1610:
1611:                // Check for parse trees.
1612:                if (g.modules.get(0).hasAttribute(Constants.ATT_PARSE_TREE)) {
1613:                    hasToken = true;
1614:                    hasFormatting = true;
1615:                }
1616:
1617:                // Check for generic productions, including generic productions
1618:                // that are directly left-recursive.
1619:                for (Module m : g.modules) {
1620:                    for (Production p : m.productions) {
1621:                        // Check for generic productions.
1622:                        if (ast.isGenericNode(p.dType)) {
1623:                            hasNode = true;
1624:
1625:                            // Check for direct left recursions in generic productions.
1626:                            for (Sequence s : p.choice.alternatives) {
1627:                                final Element first = s.isEmpty() ? null
1628:                                        : Analyzer.stripAndUnbind(s.get(0));
1629:
1630:                                if (p.name.equals(first)
1631:                                        || p.qName.equals(first)) {
1632:                                    hasAction = true;
1633:                                }
1634:                            }
1635:                        }
1636:                    }
1637:                }
1638:
1639:                // Only annotate the grammar if the productions are not going to
1640:                // be voided out.
1641:                if (!g.modules.get(0).hasAttribute(
1642:                        Constants.ATT_GENERIC_AS_VOID)) {
1643:                    if (hasNode) {
1644:                        g.modules.get(0).setProperty(Properties.GENERIC,
1645:                                Boolean.TRUE);
1646:                    }
1647:                    if (hasAction) {
1648:                        g.modules.get(0).setProperty(Properties.RECURSIVE,
1649:                                Boolean.TRUE);
1650:                    }
1651:                }
1652:
1653:                // Initialize the grammar's type map.
1654:                ast.initialize(hasNode, hasToken, hasFormatting, hasAction);
1655:
1656:                // Intern the types.
1657:                for (Module m : g.modules) {
1658:                    for (Production p : m.productions) {
1659:                        Type t;
1660:
1661:                        try {
1662:                            t = ast.intern(p.dType);
1663:                        } catch (IllegalArgumentException x) {
1664:                            runtime.error(x.getMessage() + " for production '"
1665:                                    + p.name + "'", p);
1666:                            t = ErrorT.TYPE;
1667:                        }
1668:
1669:                        p.type = t;
1670:                    }
1671:                }
1672:
1673:                // Check variant productions.
1674:                for (Module m : g.modules) {
1675:                    for (Production p : m.productions) {
1676:                        if (p.hasAttribute(Constants.ATT_VARIANT)) {
1677:                            if (AST.isToken(p.type)) {
1678:                                runtime.error(
1679:                                        "variant production for token type", p);
1680:                            } else if (!AST.isNode(p.type)) {
1681:                                runtime.error(
1682:                                        "variant production without node type",
1683:                                        p);
1684:                            }
1685:                        }
1686:                    }
1687:                }
1688:            }
1689:
1690:            /**
1691:             * Check for left-recursive productions.  This method assumes that
1692:             * all module modifications have been applied.
1693:             *
1694:             * @param g The grammar.
1695:             */
1696:            protected void checkRecursions(Grammar g) {
1697:                new TextTester(runtime, analyzer).dispatch(g);
1698:                LeftRecurser recurser = new LeftRecurser(runtime, analyzer);
1699:                recurser.dispatch(g);
1700:                Set<NonTerminal> recursive = recurser.recursive();
1701:
1702:                for (Module m : g.modules) {
1703:                    for (Production p : m.productions) {
1704:                        if (recursive.contains(p.qName)) {
1705:                            // Report the production as malformed.
1706:                            runtime.error(
1707:                                    "left-recursive definition for nonterminal '"
1708:                                            + p.name + "'", p);
1709:                        }
1710:                    }
1711:                }
1712:            }
1713:
1714:            /**
1715:             * Check repetitions for elements that accept the empty input.  This
1716:             * method assumes that all module modifications have been applied.
1717:             *
1718:             * @param g The grammar.
1719:             */
1720:            protected void checkRepetitions(Grammar g) {
1721:                analyzer.register(checkRepetitionsVisitor);
1722:                analyzer.init(g);
1723:
1724:                for (Module m : g.modules) {
1725:                    analyzer.process(m);
1726:                    for (Production p : m.productions) {
1727:                        if (p.isFull()) {
1728:                            analyzer.process(p);
1729:                        }
1730:                    }
1731:                }
1732:            }
1733:
1734:            /** The visitor for checking repetitions. */
1735:            @SuppressWarnings("unused")
1736:            private final Visitor checkRepetitionsVisitor = new Visitor() {
1737:                public void visit(Repetition r) {
1738:                    dispatch(r.element);
1739:                    if (analyzer.matchesEmpty(r.element)) {
1740:                        runtime
1741:                                .error("repeated element matches empty input",
1742:                                        r);
1743:                    }
1744:                }
1745:
1746:                public void visit(Option o) {
1747:                    dispatch(o.element);
1748:                    if (analyzer.matchesEmpty(o.element)
1749:                            && (!analyzer.grammar().modules.get(0)
1750:                                    .hasAttribute(Constants.ATT_NO_WARNINGS))
1751:                            && (!analyzer.current().hasAttribute(
1752:                                    Constants.ATT_NO_WARNINGS))) {
1753:                        runtime.warning(
1754:                                "optional element already matches empty input",
1755:                                o);
1756:                    }
1757:                }
1758:
1759:                public void visit(Production p) {
1760:                    dispatch(p.choice);
1761:                }
1762:
1763:                public void visit(OrderedChoice c) {
1764:                    for (Sequence alt : c.alternatives)
1765:                        dispatch(alt);
1766:                }
1767:
1768:                public void visit(Sequence s) {
1769:                    for (Element e : s.elements)
1770:                        dispatch(e);
1771:                }
1772:
1773:                public void visit(UnaryOperator op) {
1774:                    dispatch(op.element);
1775:                }
1776:
1777:                public void visit(Element e) {
1778:                    // Nothing to do.
1779:                }
1780:            };
1781:
1782:            /**
1783:             * Combine the modules in the specified grammar.  This method
1784:             * combines the modules in the grammar by modifying the grammar's
1785:             * top-level module and then returns that module.
1786:             *
1787:             * @param g The grammar.
1788:             * @param attributes The list of global attributes.
1789:             * @return The grammar as a single module.
1790:             */
1791:            protected Module combine(Grammar g, List<Attribute> attributes) {
1792:                // Get the top-level module.
1793:                Module m = g.modules.get(0);
1794:
1795:                // Null out the dependencies.
1796:                m.dependencies = null;
1797:                m.modification = null;
1798:
1799:                // Make sure that the single module has all global attributes.
1800:                if (0 < attributes.size()) {
1801:                    if (null == m.attributes) {
1802:                        m.attributes = attributes;
1803:
1804:                    } else {
1805:                        for (Attribute att : attributes) {
1806:                            if (!m.attributes.contains(att)) {
1807:                                m.attributes.add(att);
1808:                            }
1809:                        }
1810:                    }
1811:                }
1812:
1813:                // Collect headers, bodies, and footers.  We need to make sure
1814:                // that we do not add the same header, body, or footer more than
1815:                // once, since, in the presence of parameterized modules and
1816:                // module modifications, the same source module can be
1817:                // instantiated several times.
1818:                List<Action> headers = new ArrayList<Action>();
1819:                List<Action> bodies = new ArrayList<Action>();
1820:                List<Action> footers = new ArrayList<Action>();
1821:                for (Module m2 : g.modules) {
1822:                    if ((null != m2.header) && (!headers.contains(m2.header))) {
1823:                        headers.add(m2.header);
1824:                    }
1825:
1826:                    if ((null != m2.body) && (!bodies.contains(m2.body))) {
1827:                        bodies.add(m2.body);
1828:                    }
1829:
1830:                    if ((null != m2.footer) && (!footers.contains(m2.footer))) {
1831:                        footers.add(m2.footer);
1832:                    }
1833:                }
1834:
1835:                // Combine all unique headers, bodies, and footers into a single
1836:                // header, body, and footer, respectively.
1837:                m.header = null;
1838:                for (Action a : headers) {
1839:                    if (null == m.header) {
1840:                        m.header = a;
1841:                    } else {
1842:                        m.header.add(a);
1843:                    }
1844:                }
1845:
1846:                m.body = null;
1847:                for (Action a : bodies) {
1848:                    if (null == m.body) {
1849:                        m.body = a;
1850:                    } else {
1851:                        m.body.add(a);
1852:                    }
1853:                }
1854:
1855:                m.footer = null;
1856:                for (Action a : footers) {
1857:                    if (null == m.footer) {
1858:                        m.footer = a;
1859:                    } else {
1860:                        m.footer.add(a);
1861:                    }
1862:                }
1863:
1864:                // Now add in all productions.
1865:                for (Module m2 : g.modules) {
1866:                    if (m != m2) {
1867:                        m.productions.addAll(m2.productions);
1868:                    }
1869:                }
1870:
1871:                return m;
1872:            }
1873:
1874:            /**
1875:             * Visit the specified module.
1876:             *
1877:             * @param m The module to resolve.
1878:             * @return A single, self-contained grammar module or
1879:             *   <code>null</code> on an error condition.
1880:             */
1881:            public Object visit(Module m) {
1882:                // Reset the resolver state.
1883:                badNTs.clear();
1884:
1885:                // ----------------------------------------------------------------------
1886:                //                       Load all dependent modules.
1887:                // ----------------------------------------------------------------------
1888:
1889:                Grammar g = load(m);
1890:
1891:                // Only continue if there were no errors.
1892:                if (runtime.seenError() || runtime.test("optionLoaded")
1893:                        || runtime.test("optionDependencies")
1894:                        || runtime.test("optionInstantiated")) {
1895:                    return null;
1896:                }
1897:
1898:                // ----------------------------------------------------------------------
1899:                //                     Check as much as possible.
1900:                // ----------------------------------------------------------------------
1901:
1902:                List<Attribute> attributes = check(g);
1903:
1904:                // ----------------------------------------------------------------------
1905:                //                    Apply any module modifications.
1906:                // ----------------------------------------------------------------------
1907:
1908:                applyModifications(g);
1909:                if (runtime.test("optionApplied"))
1910:                    return null;
1911:
1912:                // ----------------------------------------------------------------------
1913:                //                          Intern types.
1914:                // ----------------------------------------------------------------------
1915:
1916:                internTypes(g);
1917:
1918:                // ----------------------------------------------------------------------
1919:                //           Check left-recursions and repeated elements
1920:                // ----------------------------------------------------------------------
1921:
1922:                checkRecursions(g);
1923:                checkRepetitions(g);
1924:                new ReachabilityChecker(runtime, analyzer).dispatch(g);
1925:
1926:                // Only continue if there were no errors.
1927:                if (runtime.seenError())
1928:                    return null;
1929:
1930:                // ----------------------------------------------------------------------
1931:                //                 Rename nonterminals for consistency.
1932:                // ----------------------------------------------------------------------
1933:
1934:                analyzer.uniquify();
1935:
1936:                // ----------------------------------------------------------------------
1937:                //                Combine all modules into a single module.
1938:                // ----------------------------------------------------------------------
1939:
1940:                return combine(g, attributes);
1941:            }
1942:
1943:            /** Analyze the specified production. */
1944:            public void visit(Production p) {
1945:                if (1 == phase) {
1946:                    if (Constants.ATT_PACKAGE_PRIVATE.getValue()
1947:                            .equals(p.dType)
1948:                            || Constants.ATT_INLINE.getName().equals(p.dType)) {
1949:                        runtime.error("attribute '" + p.dType
1950:                                + "' as type for production '" + p.name + "'",
1951:                                p);
1952:
1953:                    } else if (Constants.ATT_WITH_LOCATION.getName().equals(
1954:                            p.dType)
1955:                            || Constants.ATT_CONSTANT.getName().equals(p.dType)
1956:                            || Constants.ATT_NO_INLINE.getName()
1957:                                    .equals(p.dType)
1958:                            || Constants.ATT_MEMOIZED.getName().equals(p.dType)
1959:                            || Constants.ATT_VERBOSE.getName().equals(p.dType)
1960:                            || Constants.ATT_VARIANT.getName().equals(p.dType)
1961:                            || Constants.ATT_IGNORING_CASE.getName().equals(
1962:                                    p.dType)
1963:                            || Constants.ATT_STATEFUL.getName().equals(p.dType)
1964:                            || Constants.ATT_RESETTING.getName()
1965:                                    .equals(p.dType)) {
1966:                        if (!p.isPartial()
1967:                                && !analyzer.grammar().modules
1968:                                        .get(0)
1969:                                        .hasAttribute(Constants.ATT_NO_WARNINGS)
1970:                                && !p.hasAttribute(Constants.ATT_NO_WARNINGS)) {
1971:                            runtime.warning("attribute '" + p.dType
1972:                                    + "' as type for production " + p.name
1973:                                    + "'", p);
1974:                        }
1975:                    }
1976:
1977:                    if (p.isPartial()) {
1978:                        if (!isMofunctor) {
1979:                            runtime.error("production modification '" + p.name
1980:                                    + "' without modifies declaration", p);
1981:
1982:                        } else {
1983:                            // Make sure the corresponding full production is defined
1984:                            // and the types match.
1985:                            Production p2 = null;
1986:                            try {
1987:                                p2 = analyzer.lookup(p.name);
1988:                            } catch (IllegalArgumentException x) {
1989:                                // Nothing to do.
1990:                            }
1991:
1992:                            if ((null == p2)
1993:                                    || (!analyzer.isDefined(p2, analyzer
1994:                                            .currentModule()))) {
1995:                                runtime.error("production modification '"
1996:                                        + p.name + "' without full production",
1997:                                        p);
1998:
1999:                            } else if (!p.dType.equals(p2.dType)) {
2000:                                runtime
2001:                                        .error(
2002:                                                "type '"
2003:                                                        + p.dType
2004:                                                        + "' of production modification '"
2005:                                                        + p.name
2006:                                                        + "' does not match full production's type",
2007:                                                p);
2008:                            }
2009:                        }
2010:                    }
2011:
2012:                    if (null != p.attributes) {
2013:                        final int length = p.attributes.size();
2014:                        for (int i = 0; i < length; i++) {
2015:                            Attribute att = p.attributes.get(i);
2016:
2017:                            if ((!Constants.ATT_PUBLIC.equals(att))
2018:                                    && (!Constants.ATT_PROTECTED.equals(att))
2019:                                    && (!Constants.ATT_PRIVATE.equals(att))
2020:                                    && (!Constants.ATT_TRANSIENT.equals(att))
2021:                                    && (!Constants.ATT_INLINE.equals(att))
2022:                                    && (!Constants.ATT_NO_INLINE.equals(att))
2023:                                    && (!Constants.ATT_MEMOIZED.equals(att))
2024:                                    && (!Constants.ATT_WITH_LOCATION
2025:                                            .equals(att))
2026:                                    && (!Constants.ATT_CONSTANT.equals(att))
2027:                                    && (!Constants.ATT_VARIANT.equals(att))
2028:                                    && (!Constants.ATT_VERBOSE.equals(att))
2029:                                    && (!Constants.ATT_NO_WARNINGS.equals(att))
2030:                                    && (!Constants.ATT_IGNORING_CASE
2031:                                            .equals(att))
2032:                                    && (!Constants.ATT_STATEFUL.equals(att))
2033:                                    && (!Constants.ATT_RESETTING.equals(att))) {
2034:                                runtime.error(
2035:                                        "unrecognized per-production attribute '"
2036:                                                + att + "'", att);
2037:
2038:                            } else if ((!hasState)
2039:                                    && Constants.ATT_STATEFUL.equals(att)) {
2040:                                runtime.error(
2041:                                        "stateful attribute without grammar-wide stateful "
2042:                                                + "attribute", att);
2043:
2044:                            } else if ((!hasState)
2045:                                    && Constants.ATT_RESETTING.equals(att)) {
2046:                                runtime.error(
2047:                                        "resetting attribute without grammar-wide stateful "
2048:                                                + "attribute", att);
2049:
2050:                            } else {
2051:                                for (int j = 0; j < i; j++) {
2052:                                    if (att.equals(p.attributes.get(j))) {
2053:                                        runtime.error("duplicate attribute '"
2054:                                                + att.getName() + "'", att);
2055:                                        break;
2056:                                    }
2057:                                }
2058:                            }
2059:                        }
2060:
2061:                        if (p.hasAttribute(Constants.ATT_MEMOIZED)) {
2062:                            if (p.hasAttribute(Constants.ATT_TRANSIENT)) {
2063:                                runtime
2064:                                        .error(
2065:                                                "memozied attribute contradicts transient attribute",
2066:                                                Attribute.get(
2067:                                                        Constants.ATT_MEMOIZED
2068:                                                                .getName(),
2069:                                                        p.attributes));
2070:                            }
2071:                            if (p.hasAttribute(Constants.ATT_INLINE)) {
2072:                                runtime
2073:                                        .error(
2074:                                                "memoized attribute contradicts inline attribute",
2075:                                                Attribute.get(
2076:                                                        Constants.ATT_MEMOIZED
2077:                                                                .getName(),
2078:                                                        p.attributes));
2079:                            }
2080:                        }
2081:                        if (p.hasAttribute(Constants.ATT_TRANSIENT)
2082:                                && p.hasAttribute(Constants.ATT_INLINE)) {
2083:                            runtime
2084:                                    .error(
2085:                                            "inline attribute subsumes transient attribute",
2086:                                            Attribute.get(Constants.ATT_INLINE
2087:                                                    .getName(), p.attributes));
2088:                        }
2089:                        if (p.hasAttribute(Constants.ATT_INLINE)
2090:                                && p.hasAttribute(Constants.ATT_NO_INLINE)) {
2091:                            runtime
2092:                                    .error(
2093:                                            "inline attribute contradicts noinline attribute",
2094:                                            Attribute.get(
2095:                                                    Constants.ATT_NO_INLINE
2096:                                                            .getName(),
2097:                                                    p.attributes));
2098:                        }
2099:                    }
2100:                }
2101:
2102:                dispatch(p.choice);
2103:            }
2104:
2105:            /** Analyze the specified ordered choice. */
2106:            public void visit(OrderedChoice c) {
2107:                for (Sequence alt : c.alternatives)
2108:                    dispatch(alt);
2109:            }
2110:
2111:            /** Analyze the specified repetition. */
2112:            public void visit(Repetition r) {
2113:                if (1 == phase) {
2114:                    if (Analyzer.strip(r.element) instanceof  Action) {
2115:                        runtime.error("repeated action", r);
2116:                    }
2117:                }
2118:                dispatch(r.element);
2119:            }
2120:
2121:            /** Analyze the specified option.  */
2122:            public void visit(Option o) {
2123:                if (1 == phase) {
2124:                    if (Analyzer.strip(o.element) instanceof  Action) {
2125:                        runtime.error("optional action", o);
2126:                    }
2127:                }
2128:                dispatch(o.element);
2129:            }
2130:
2131:            /** Analyze the specified sequence. */
2132:            public void visit(Sequence s) {
2133:                if ((1 == phase) || (2 == phase)) {
2134:                    if (null != s.name) {
2135:                        if (sequenceNames.contains(s.name)) {
2136:                            runtime.error("duplicate sequence name '" + s.name
2137:                                    + "'", s);
2138:                        } else {
2139:                            sequenceNames.add(s.name);
2140:                        }
2141:                    }
2142:                }
2143:
2144:                for (Element e : s.elements)
2145:                    dispatch(e);
2146:            }
2147:
2148:            /** Analyze the specified predicate. */
2149:            public void visit(Predicate p) {
2150:                if (1 == phase) {
2151:                    if (isPredicate) {
2152:                        runtime
2153:                                .error(
2154:                                        "syntactic predicate within syntactic predicate",
2155:                                        p);
2156:                    }
2157:                }
2158:
2159:                boolean pred = isPredicate;
2160:                isPredicate = true;
2161:                dispatch(p.element);
2162:                isPredicate = pred;
2163:            }
2164:
2165:            /** Analyze the specified semantic predicate. */
2166:            public void visit(SemanticPredicate p) {
2167:                if (1 == phase) {
2168:                    if (!(p.element instanceof  Action)) {
2169:                        runtime.error("malformed semantic predicate", p);
2170:                    } else {
2171:                        Action a = (Action) p.element;
2172:                        if ((null == a.code) || (0 >= a.code.size())) {
2173:                            runtime.error("empty test for semantic predicate",
2174:                                    p);
2175:                        }
2176:                    }
2177:                }
2178:
2179:                dispatch(p.element);
2180:            }
2181:
2182:            /** Analyze the specified voided element. */
2183:            public void visit(VoidedElement v) {
2184:                if (1 == phase) {
2185:                    // We allow void:void:e and void:nt for void nonterminals, since
2186:                    // the simplifier removes the unnecessary voided elements.
2187:                    Element voided = Analyzer.strip(v.element);
2188:
2189:                    switch (voided.tag()) {
2190:                    case FOLLOWED_BY:
2191:                    case NOT_FOLLOWED_BY:
2192:                    case SEMANTIC_PREDICATE:
2193:                        runtime.error("voided predicate", v);
2194:                        break;
2195:
2196:                    case BINDING:
2197:                        runtime.error("voided binding", v);
2198:                        break;
2199:
2200:                    case ACTION:
2201:                        runtime.error("voided action", v);
2202:                        break;
2203:
2204:                    case PARSER_ACTION:
2205:                        runtime.error("voided parser action", v);
2206:                        break;
2207:
2208:                    case NODE_MARKER:
2209:                        runtime.error("voided node marker", v);
2210:                        break;
2211:                    }
2212:                }
2213:
2214:                dispatch(v.element);
2215:            }
2216:
2217:            /** Analyze the specified binding. */
2218:            public void visit(Binding b) {
2219:                if (1 == phase) {
2220:                    Element bound = Analyzer.strip(b.element);
2221:
2222:                    switch (bound.tag()) {
2223:                    case FOLLOWED_BY:
2224:                    case NOT_FOLLOWED_BY:
2225:                    case SEMANTIC_PREDICATE:
2226:                        runtime.error("binding for predicate", b);
2227:                        break;
2228:
2229:                    case VOIDED:
2230:                        runtime.error("binding for voided element", b);
2231:                        break;
2232:
2233:                    case BINDING:
2234:                        runtime.error("binding for binding", b);
2235:                        break;
2236:
2237:                    case NONTERMINAL: {
2238:                        NonTerminal nt = (NonTerminal) bound;
2239:                        Production p = null;
2240:                        try {
2241:                            p = analyzer.lookup(nt);
2242:                        } catch (IllegalArgumentException x) {
2243:                            // Nothing to do.
2244:                        }
2245:                        if ((null != p) && ast.isVoid(p.dType)) {
2246:                            runtime.error("binding for void nonterminal '" + nt
2247:                                    + "'", b);
2248:                        }
2249:                    }
2250:                        break;
2251:
2252:                    case ACTION:
2253:                        runtime.error("binding for action", b);
2254:                        break;
2255:
2256:                    case PARSER_ACTION:
2257:                        runtime.error("binding for parser action", b);
2258:                        break;
2259:
2260:                    case NODE_MARKER:
2261:                        runtime.error("binding for node marker", b);
2262:                        break;
2263:                    }
2264:                }
2265:
2266:                dispatch(b.element);
2267:            }
2268:
2269:            /** Analyze the specified string match. */
2270:            public void visit(StringMatch m) {
2271:                if (1 == phase) {
2272:                    Element matched = Analyzer.strip(m.element);
2273:
2274:                    switch (matched.tag()) {
2275:                    case FOLLOWED_BY:
2276:                    case NOT_FOLLOWED_BY:
2277:                    case SEMANTIC_PREDICATE:
2278:                        runtime.error("string match on predicate", m);
2279:                        break;
2280:
2281:                    case VOIDED:
2282:                        runtime.error("string match on voided element", m);
2283:                        break;
2284:
2285:                    case BINDING:
2286:                        runtime.error("string match on binding "
2287:                                + "(try binding the match instead)", m);
2288:                        break;
2289:
2290:                    case STRING_MATCH:
2291:                        runtime
2292:                                .error("string match on another string match",
2293:                                        m);
2294:                        break;
2295:
2296:                    case NONTERMINAL: {
2297:                        NonTerminal nt = (NonTerminal) matched;
2298:                        Production p = null;
2299:                        try {
2300:                            p = analyzer.lookup(nt);
2301:                        } catch (IllegalArgumentException x) {
2302:                            // Nothing to do.
2303:                        }
2304:                        if ((null != p) && ast.isVoid(p.dType)) {
2305:                            runtime.error("string match on void nonterminal '"
2306:                                    + nt + "'", m);
2307:                        }
2308:                    }
2309:                        break;
2310:
2311:                    case ANY_CHAR:
2312:                    case CHAR_CLASS:
2313:                    case CHAR_LITERAL:
2314:                    case CHAR_SWITCH:
2315:                    case STRING_LITERAL:
2316:                        runtime.error("match for terminal", m);
2317:                        break;
2318:
2319:                    case ACTION:
2320:                        runtime.error("match for action", m);
2321:                        break;
2322:
2323:                    case PARSER_ACTION:
2324:                        runtime.error("match for parser action", m);
2325:                        break;
2326:
2327:                    case NODE_MARKER:
2328:                        runtime.error("match for node marker", m);
2329:                        break;
2330:                    }
2331:                }
2332:
2333:                dispatch(m.element);
2334:            }
2335:
2336:            /** Analyze the specified nonterminal. */
2337:            public void visit(NonTerminal nt) {
2338:                Production p = null;
2339:
2340:                try {
2341:                    p = analyzer.lookup(nt);
2342:                } catch (IllegalArgumentException x) {
2343:                    if (nt.hasProperty(Constants.ORIGINAL)) {
2344:                        if (!badNTs.containsKey(nt)) {
2345:                            runtime.error("ambiguous renamed nonterminal '"
2346:                                    + nt + "'", nt);
2347:                            badNTs.put(nt, nt);
2348:                        }
2349:                    } else {
2350:                        if (!badNTs.containsKey(nt)) {
2351:                            runtime.error("ambiguous nonterminal '" + nt + "'",
2352:                                    nt);
2353:                            badNTs.put(nt, nt);
2354:                        }
2355:                    }
2356:                    return;
2357:                }
2358:                if (null == p) {
2359:                    if (nt.hasProperty(Constants.ORIGINAL)) {
2360:                        if (!badNTs.containsKey(nt)) {
2361:                            runtime.error("undefined renamed nonterminal '"
2362:                                    + nt + "'", nt);
2363:                            badNTs.put(nt, nt);
2364:                        }
2365:                    } else {
2366:                        if (!badNTs.containsKey(nt)) {
2367:                            runtime.error("undefined nonterminal '" + nt + "'",
2368:                                    nt);
2369:                            badNTs.put(nt, nt);
2370:                        }
2371:                    }
2372:                }
2373:            }
2374:
2375:            /** Analyze the specified terminal. */
2376:            public void visit(Terminal t) {
2377:                // Nothing to do.
2378:            }
2379:
2380:            /** Analyze the specified string literal. */
2381:            public void visit(StringLiteral l) {
2382:                if (1 == phase) {
2383:                    if (0 == l.text.length()) {
2384:                        runtime.error("empty string literal", l);
2385:                    }
2386:                }
2387:            }
2388:
2389:            /** Analyze the specified character class. */
2390:            public void visit(CharClass c) {
2391:                if (1 != phase)
2392:                    return;
2393:
2394:                final int length = c.ranges.size();
2395:
2396:                if (0 >= length) {
2397:                    runtime.error("empty character class", c);
2398:
2399:                } else {
2400:                    ArrayList<CharRange> list = new ArrayList<CharRange>(
2401:                            c.ranges);
2402:                    Collections.sort(list);
2403:
2404:                    for (int i = 0; i < length - 1; i++) {
2405:                        CharRange r1 = list.get(i);
2406:                        CharRange r2 = list.get(i + 1);
2407:
2408:                        if (r1.last >= r2.first) {
2409:                            boolean single1 = (r1.first == r1.last);
2410:                            boolean single2 = (r2.first == r2.last);
2411:
2412:                            if (single1) {
2413:                                if (single2) {
2414:                                    runtime.error("duplicate character '"
2415:                                            + Utilities.escape(r1.last,
2416:                                                    Utilities.FULL_ESCAPES)
2417:                                            + "' in character class", c);
2418:                                } else {
2419:                                    runtime.error("character '"
2420:                                            + Utilities.escape(r1.last,
2421:                                                    Utilities.FULL_ESCAPES)
2422:                                            + "' already contained in range "
2423:                                            + Utilities.escape(r2.first,
2424:                                                    Utilities.FULL_ESCAPES)
2425:                                            + "-"
2426:                                            + Utilities.escape(r2.last,
2427:                                                    Utilities.FULL_ESCAPES), c);
2428:                                }
2429:                            } else {
2430:                                if (single2) {
2431:                                    runtime.error("character '"
2432:                                            + Utilities.escape(r2.first,
2433:                                                    Utilities.FULL_ESCAPES)
2434:                                            + "' already contained in range "
2435:                                            + Utilities.escape(r1.first,
2436:                                                    Utilities.FULL_ESCAPES)
2437:                                            + "-"
2438:                                            + Utilities.escape(r1.last,
2439:                                                    Utilities.FULL_ESCAPES), c);
2440:                                } else {
2441:                                    runtime.error("ranges "
2442:                                            + Utilities.escape(r1.first,
2443:                                                    Utilities.FULL_ESCAPES)
2444:                                            + "-"
2445:                                            + Utilities.escape(r1.last,
2446:                                                    Utilities.FULL_ESCAPES)
2447:                                            + " and "
2448:                                            + Utilities.escape(r2.first,
2449:                                                    Utilities.FULL_ESCAPES)
2450:                                            + "-"
2451:                                            + Utilities.escape(r2.last,
2452:                                                    Utilities.FULL_ESCAPES)
2453:                                            + " overlap", c);
2454:                                }
2455:                            }
2456:                        }
2457:                    }
2458:                }
2459:            }
2460:
2461:            /** Analyze the specified null literal. */
2462:            public void visit(NullLiteral l) {
2463:                // Nothing to do.
2464:            }
2465:
2466:            /** Analyze the specified node marker. */
2467:            public void visit(NodeMarker m) {
2468:                if (!ast.isGenericNode(analyzer.current().dType)) {
2469:                    runtime.error("node marker in non-generic production", m);
2470:                } else if (isPredicate) {
2471:                    runtime.error("node marker in predicate", m);
2472:                }
2473:            }
2474:
2475:            /** Analyze the specified action. */
2476:            public void visit(Action a) {
2477:                // Nothing to do.
2478:            }
2479:
2480:            /** Analyze the specified parser action. */
2481:            public void visit(ParserAction pa) {
2482:                if (1 == phase) {
2483:                    if (!(pa.element instanceof  Action)) {
2484:                        runtime.error("malformed parser action", pa);
2485:                    }
2486:                    if (isPredicate) {
2487:                        runtime.error(
2488:                                "parser action within syntactic predicate", pa);
2489:                    }
2490:                }
2491:
2492:                dispatch(pa.element);
2493:            }
2494:
2495:            /** Analyze the specified internal element. */
2496:            public void visit(InternalElement e) {
2497:                if (1 == phase) {
2498:                    runtime.error("internal element", (Element) e);
2499:                }
2500:            }
2501:
2502:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.