Source Code Cross Referenced for CodeGenerator.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) 2004 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:         * as published by the Free Software Foundation; either version 2
0008:         * of the License, or (at your option) any later version.
0009:         *
0010:         * This program is distributed in the hope that it will be useful,
0011:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013:         * GNU General Public License for more details.
0014:         *
0015:         * You should have received a copy of the GNU General Public License
0016:         * along with this program; if not, write to the Free Software
0017:         * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
0018:         */
0019:        package xtc.parser;
0020:
0021:        import java.util.Date;
0022:        import java.util.HashMap;
0023:        import java.util.HashSet;
0024:        import java.util.Iterator;
0025:        import java.util.List;
0026:        import java.util.Map;
0027:        import java.util.Set;
0028:
0029:        import java.text.DateFormat;
0030:
0031:        import xtc.Constants;
0032:
0033:        import xtc.util.Utilities;
0034:
0035:        import xtc.tree.Attribute;
0036:        import xtc.tree.Location;
0037:        import xtc.tree.Node;
0038:        import xtc.tree.Printer;
0039:        import xtc.tree.Visitor;
0040:
0041:        /**
0042:         * The code generator. 
0043:         *
0044:         * <p />The code generator makes the following assumptions about the
0045:         * intermediate language:<ul>
0046:         *
0047:         * <li>Each {@link Production production} must have an {@link
0048:         * OrderedChoice ordered choice} as its element.<p /></li>
0049:         * 
0050:         * <li>Each {link Production production} must have been annotated
0051:         * with the appropriate {@link MetaData meta-data}.<p /></li>
0052:         *
0053:         * <li>Each option of an {@link OrderedChoice ordered choice} must
0054:         * be a {@link Sequence sequence}.<p /></li>
0055:         *
0056:         * <li>Generally, all {@link Option options}, {@link Repetition
0057:         * repetitions}, and nested {@link OrderedChoice ordered choices} must
0058:         * have been desugared into equivalent productions.  However, an
0059:         * ordered choice may appear as the <i>last</i> element of a sequence
0060:         * (that is <i>not</i> part of a predicate), and a repetition may
0061:         * appear if the repeated expressions need not be memoized.<p /></li>
0062:         *
0063:         * <li>The element of a {@link Repetition repetition} must be a {@link
0064:         * Sequence sequence} (with the last element possibly being an ordered
0065:         * choice; see previous assumption).<p /></li>
0066:         *
0067:         * <li>The {@link FollowedBy#element} and {@link
0068:         * NotFollowedBy#element} fields must reference a sequence.<p /></li>
0069:         *
0070:         * <li>All elements in a {@link CharSwitch character switch} must
0071:         * either be ordered choices or sequences.  Furthermore, character
0072:         * switches may only appear as the last element in a sequence and not
0073:         * within predicates.<p /></li>
0074:         *
0075:         * </ul>
0076:         *
0077:         * @author Robert Grimm
0078:         * @version $Revision: 1.1 $
0079:         */
0080:        public class CodeGenerator extends Visitor {
0081:
0082:            /**
0083:             * The {@link Attribute attribute} name for printing debugging
0084:             * information while parsing.  For grammars with this attribute, the
0085:             * code generator emits code that prints debugging information to
0086:             * the console while parsing.
0087:             */
0088:            public static final String ATT_DEBUG = "debug";
0089:
0090:            /**
0091:             * The {@link Attribute attribute} name for annotating instances of
0092:             * {@link Node} with their location information:
0093:             * <code>location</code>.  For grammars with this attribute, the
0094:             * code generator emits code that automatically annotates all nodes
0095:             * with their grammar {@link Location location information}.
0096:             */
0097:            public static final String ATT_LOCATION = "location";
0098:
0099:            /**
0100:             * The {@link Attribute attribute} name for making variable bindings
0101:             * constant: <code>constantBinding</code>.  For grammars with this
0102:             * attribute, the code generator declares all variable bindings to
0103:             * be constant (in the case of Java, final).
0104:             */
0105:            public static final String ATT_CONSTANT_BINDING = "constantBinding";
0106:
0107:            /**
0108:             * The {@link Attribute attribute} name for not generating specific
0109:             * parse errors when a string literal or string match fails:
0110:             * <code>noMatchingErrors</code>.  For grammars with this attribute,
0111:             * parse errrors are only generated at the granularity of an entire
0112:             * production (pointing to the beginning of the production).
0113:             */
0114:            public static final String ATT_NO_MATCHING_ERRORS = "noMatchingErrors";
0115:
0116:            /** The size of chunks. */
0117:            public static final int CHUNK_SIZE = 10;
0118:
0119:            /** The prefix for parsing method names. */
0120:            public static final String PREFIX_METHOD = "p";
0121:
0122:            /** The prefix for field names that memoize the parsers results. */
0123:            public static final String PREFIX_FIELD = "f";
0124:
0125:            /** The general prefix for internal parser fields and variables. */
0126:            public static final String PREFIX = "yy";
0127:
0128:            /** The name for the character parsing method. */
0129:            public static final String PARSE_CHAR = "character";
0130:
0131:            /** The name for the file name variable. */
0132:            public static final String FILE = PREFIX + "File";
0133:
0134:            /** The name for the line number variable. */
0135:            public static final String LINE = PREFIX + "Line";
0136:
0137:            /** The name for the column number variable. */
0138:            public static final String COLUMN = PREFIX + "Column";
0139:
0140:            /** The name for the character variable. */
0141:            public static final String CHAR = PREFIX + "C";
0142:
0143:            /** The name for the parser variable. */
0144:            public static final String PARSER = PREFIX + "Parser";
0145:
0146:            /** The prefix for the parser variable for nested choices. */
0147:            public static final String NESTED_CHOICE = PREFIX + "Choice";
0148:
0149:            /** The prefix for the parser variable for repetitions. */
0150:            public static final String REPETITION = PREFIX + "Repetition";
0151:
0152:            /**
0153:             * The prefix for the flag indicating that a repetition has been
0154:             * matched at least once.
0155:             */
0156:            public static final String REPEATED = PREFIX + "Repeated";
0157:
0158:            /** The name for the regular result variable. */
0159:            public static final String RESULT = PREFIX + "Result";
0160:
0161:            /** The name for the parse error variable. */
0162:            public static final String PARSE_ERROR = PREFIX + "Error";
0163:
0164:            /** The name for the predicate result variable. */
0165:            public static final String PRED_RESULT = PREFIX + "PredResult";
0166:
0167:            /** The name for the predicate matched variable. */
0168:            public static final String MATCHED = PREFIX + "PredMatched";
0169:
0170:            /** The name for the value variable. */
0171:            public static final String VALUE = PREFIX + "Value";
0172:
0173:            // ========================================================================
0174:
0175:            /** The analyzer utility. */
0176:            protected final Analyzer analyzer;
0177:
0178:            /** The printer utility. */
0179:            protected final Printer printer;
0180:
0181:            /** The number of spaces to align variable declarations to. */
0182:            protected int alignment = 0;
0183:
0184:            /** The flag for generating debugging code. */
0185:            protected boolean attributeDebug;
0186:
0187:            /**
0188:             * The flag for generating code to annotate nodes with location
0189:             * information.
0190:             */
0191:            protected boolean attributeLocation;
0192:
0193:            /** The flag for making variable bindings constant. */
0194:            protected boolean attributeConstantBinding;
0195:
0196:            /** The flag for not generating matching errors. */
0197:            protected boolean attributeNoMatchingErrors;
0198:
0199:            /** The class name for the current grammar. */
0200:            protected String cName;
0201:
0202:            /** Flag for whether the memoization fields are organized in chunks. */
0203:            protected boolean chunked;
0204:
0205:            /** The map from nonterminals to chunk numbers. */
0206:            protected Map chunkMap;
0207:
0208:            /** The number of chunks. */
0209:            protected int chunkCount;
0210:
0211:            /** The flag for the first element in a top-level choice. */
0212:            protected boolean firstElement;
0213:
0214:            /** The saved first element. */
0215:            protected boolean savedFirstElement;
0216:
0217:            /** The expression for the base parser. */
0218:            protected String baseParser;
0219:
0220:            /** The flag for using the base parser. */
0221:            protected boolean useBaseParser;
0222:
0223:            /** The saved base parser. */
0224:            protected String savedBaseParser;
0225:
0226:            /** The saved flag for using the base parser. */
0227:            protected boolean savedUseBaseParser;
0228:
0229:            /** The nesting level for nested choices. */
0230:            protected int choiceLevel;
0231:
0232:            /** The nesting level for repetitions. */
0233:            protected int repetitionLevel;
0234:
0235:            /** The saved repetition level (for predicates). */
0236:            protected int savedRepetitionLevel;
0237:
0238:            /** The flag for at-least-once repetitions. */
0239:            protected boolean repeatOnce;
0240:
0241:            /** Flag for whether a test has been emitted. */
0242:            protected boolean seenTest;
0243:
0244:            /** Flag for whether the current choice ends with a parse error. */
0245:            protected boolean endsWithParseError;
0246:
0247:            /** The iterator over the elements of a sequence. */
0248:            protected Iterator elementIter;
0249:
0250:            /** The name of the result variable. */
0251:            protected String resultName;
0252:
0253:            /** The name of the current binding. */
0254:            protected String bindingName;
0255:
0256:            /** The element being bound. */
0257:            protected Element bindingElement;
0258:
0259:            /** Flag for whether we are currently emitting a predicate. */
0260:            protected boolean predicate;
0261:
0262:            /**
0263:             * Flag for whether the current predicate is a not-followed-by
0264:             * predicate.
0265:             */
0266:            protected boolean notFollowedBy;
0267:
0268:            /** The predicate iterator. */
0269:            protected Iterator predicateIter;
0270:
0271:            // ========================================================================
0272:
0273:            /**
0274:             * Create a new code generator.
0275:             *
0276:             * @param analyzer The analyzer for the new code generator.
0277:             * @param printer The printer for the new code generator.
0278:             */
0279:            public CodeGenerator(Analyzer analyzer, Printer printer) {
0280:                this .analyzer = analyzer;
0281:                this .printer = printer;
0282:            }
0283:
0284:            // ========================================================================
0285:
0286:            /**
0287:             * Generate the field name for the specified nonterminal.
0288:             *
0289:             * @param nt The nonterminal.
0290:             * @return The corresponding field name.
0291:             */
0292:            public String fieldName(NonTerminal nt) {
0293:                if (chunked) {
0294:                    return PREFIX + "Chunk" + chunkMap.get(nt) + "."
0295:                            + PREFIX_FIELD + nt.name;
0296:                } else {
0297:                    return PREFIX_FIELD + nt.name;
0298:                }
0299:            }
0300:
0301:            /**
0302:             * Generate the method name for the specified nonterminal.
0303:             *
0304:             * @param nt The nonterminal.
0305:             * @return The corresponding method name.
0306:             */
0307:            public String methodName(NonTerminal nt) {
0308:                return PREFIX_METHOD + nt.name;
0309:            }
0310:
0311:            // ========================================================================
0312:
0313:            /**
0314:             * Determine the variable alignment for parse method declarations.
0315:             *
0316:             * @param includeParser Flag for whether a parser variable needs to
0317:             *   be declared.
0318:             */
0319:            protected void alignment(boolean includeParser) {
0320:                alignment = 0;
0321:                if (includeParser) {
0322:                    alignment = Math.max(alignment, cName.length() + 1);
0323:                }
0324:                alignment = Math.max(alignment, "ParseError".length() + 1);
0325:            }
0326:
0327:            // ========================================================================
0328:
0329:            /** Generate code for the specified grammar. */
0330:            public void visit(Grammar g) {
0331:                // (Re)Initialize code generator state.
0332:                analyzer.register(this );
0333:                printer.register(this );
0334:                analyzer.init(g);
0335:                cName = g.cName;
0336:
0337:                // Record the grammar attributes.
0338:                Set attributes;
0339:                if (null != g.attributes) {
0340:                    attributes = new HashSet(g.attributes);
0341:                } else {
0342:                    attributes = new HashSet();
0343:                }
0344:                attributeDebug = attributes.contains(new Attribute(ATT_DEBUG));
0345:                attributeLocation = attributes.contains(new Attribute(
0346:                        ATT_LOCATION));
0347:                attributeConstantBinding = attributes.contains(new Attribute(
0348:                        ATT_CONSTANT_BINDING));
0349:                attributeNoMatchingErrors = attributes.contains(new Attribute(
0350:                        ATT_NO_MATCHING_ERRORS));
0351:
0352:                chunked = false;
0353:                chunkMap = null;
0354:                chunkCount = 0;
0355:
0356:                // Emit header.
0357:                printer.sep();
0358:                printer.indent().pln("// This file has been generated by");
0359:                printer.indent().p("// Rats! Parser Generator, Version ").p(
0360:                        Constants.VERSION).p(", ").pln(Constants.COPY);
0361:                Date now = new Date();
0362:                printer.indent().p("// on ")
0363:                        .p(
0364:                                DateFormat.getDateInstance(DateFormat.FULL)
0365:                                        .format(now)).p(" at ").p(
0366:                                DateFormat.getTimeInstance(DateFormat.MEDIUM)
0367:                                        .format(now)).pln('.');
0368:                printer.indent().pln("// Edit at your own risk.");
0369:                printer.sep();
0370:                printer.pln();
0371:
0372:                // Emit package name.
0373:                if (null != g.pName) {
0374:                    printer.indent().p("package ").p(g.pName).pln(';');
0375:                    printer.pln();
0376:                }
0377:
0378:                // Emit imports.
0379:                printer.indent().pln("import java.io.IOException;");
0380:                printer.indent().pln("import java.io.Reader;");
0381:                printer.pln();
0382:                printer.indent().pln("import xtc.util.Pair;");
0383:                if (attributeLocation) {
0384:                    printer.pln();
0385:                    printer.indent().pln("import xtc.tree.Node;");
0386:                }
0387:                printer.pln();
0388:                printer.indent().pln("import xtc.parser.PackratParser;");
0389:                printer.indent().pln("import xtc.parser.Result;");
0390:                printer.indent().pln("import xtc.parser.SemanticValue;");
0391:                printer.indent().pln("import xtc.parser.ParseError;");
0392:                printer.pln();
0393:
0394:                // Emit header.
0395:                if (null != g.header) {
0396:                    action(g.header);
0397:                    printer.pln();
0398:                }
0399:
0400:                // Emit class name.
0401:                printer.indent().pln("/**");
0402:                if (null != g.location) {
0403:                    printer.indent().p(" * Packrat parser for grammar ").p(
0404:                            g.location.file).pln('.');
0405:                } else {
0406:                    printer.indent().pln(" * Packrat parser.");
0407:                }
0408:                printer
0409:                        .indent()
0410:                        .p(
0411:                                " * This class has been generated by the <i>Rats!</i> parser ")
0412:                        .p("generator, v. ").p(Constants.VERSION).pln('.');
0413:                printer.indent().pln(" */");
0414:                printer.indent().p("public final class ").p(cName).pln(
0415:                        " extends PackratParser {").incr();
0416:                printer.pln();
0417:
0418:                // Emit debug flag.
0419:                if (attributeDebug) {
0420:                    printer
0421:                            .indent()
0422:                            .p(
0423:                                    "/** Flag for whether to emit debugging information while ")
0424:                            .pln("parsing. */");
0425:                    printer.indent().pln(
0426:                            "public static final boolean DEBUG = true;");
0427:                    printer.pln();
0428:                }
0429:
0430:                // Determine the number of productions that require memoization.
0431:                int memoCount = 0;
0432:
0433:                Iterator iter = g.productions.iterator();
0434:                while (iter.hasNext()) {
0435:                    Production p = (Production) iter.next();
0436:                    MetaData md = (MetaData) p.getProperty(MetaData.NAME);
0437:                    // Only memoize non-transient productions that are used more
0438:                    // than once.
0439:                    if ((1 < md.usageCount) && (!p.isTransient)) {
0440:                        memoCount++;
0441:                    }
0442:                }
0443:
0444:                // To chunk or not to chunk.
0445:                if (Rats.optimizeChunks && (CHUNK_SIZE <= memoCount)) {
0446:                    chunked = true;
0447:                    chunkMap = new HashMap(memoCount * 4 / 3);
0448:
0449:                    Integer number = null;
0450:                    String sNumber = null;
0451:                    int i = CHUNK_SIZE;
0452:                    boolean first = true;
0453:                    iter = g.productions.iterator();
0454:
0455:                    while (iter.hasNext()) {
0456:                        Production p = (Production) iter.next();
0457:                        MetaData md = (MetaData) p.getProperty(MetaData.NAME);
0458:
0459:                        // Skip memoization for productions that are transient or used
0460:                        // at most once.
0461:                        if ((1 >= md.usageCount)
0462:                                || (Rats.optimizeTransient && p.isTransient)) {
0463:                            continue;
0464:                        }
0465:
0466:                        if (CHUNK_SIZE <= i) {
0467:                            chunkCount++;
0468:                            number = new Integer(chunkCount);
0469:                            sNumber = Integer.toString(chunkCount);
0470:                            i = 0;
0471:
0472:                            if (first) {
0473:                                first = false;
0474:                                printer.sep();
0475:                            } else {
0476:                                printer.decr().indent().pln('}');
0477:                            }
0478:                            printer.pln();
0479:                            printer.indent().p("/** Chunk ").p(sNumber).pln(
0480:                                    " of memoized results. */");
0481:                            printer.indent().p("static final class Chunk").p(
0482:                                    sNumber).pln(" {").incr();
0483:                        }
0484:
0485:                        NonTerminal nt = p.nonTerminal;
0486:
0487:                        chunkMap.put(nt, number);
0488:                        i++;
0489:
0490:                        printer.indent().p("Result ").p(PREFIX_FIELD)
0491:                                .p(nt.name).pln(';');
0492:                    }
0493:
0494:                    printer.decr().indent().pln('}');
0495:                    printer.pln();
0496:                }
0497:
0498:                // Emit fields.  Note that the field for memoizing the result of
0499:                // the character parsing method is already defined in
0500:                // PackratParser.
0501:                printer.sep().pln();
0502:                if (chunked) {
0503:                    for (int i = 1; i <= chunkCount; i++) {
0504:                        printer.indent().p("private Chunk").p(i).p(' ').p(
0505:                                PREFIX).p("Chunk").p(i).pln(';');
0506:                    }
0507:
0508:                } else {
0509:                    iter = g.productions.iterator();
0510:                    while (iter.hasNext()) {
0511:                        Production p = (Production) iter.next();
0512:                        MetaData md = (MetaData) p.getProperty(MetaData.NAME);
0513:
0514:                        // Only create memoization fields for non-transient
0515:                        // productions that are used more than once.
0516:                        if (((!Rats.optimizeChunks) || (1 < md.usageCount))
0517:                                && ((!Rats.optimizeTransient) || (!p.isTransient))) {
0518:                            printer.indent().p("private Result ").p(
0519:                                    fieldName(p.nonTerminal)).pln(';');
0520:                        }
0521:                    }
0522:                }
0523:                printer.pln();
0524:
0525:                // Emit constructors.
0526:                printer.sep().pln();
0527:                printer
0528:                        .indent()
0529:                        .pln(
0530:                                "/** Create a new packrat parser for the specified file. */");
0531:                printer.indent().p("public ").p(cName).pln(
0532:                        "(Reader reader, String file) {").incr();
0533:                printer.indent().pln("super(reader, file);");
0534:                printer.decr().indent().pln('}');
0535:                printer.pln();
0536:
0537:                printer.indent().p(
0538:                        "/** Create a new packrat parser, moving ahead one ")
0539:                        .pln("character. */");
0540:                printer.indent().p("protected ").p(cName).p('(').p(cName).pln(
0541:                        " previous) {").incr();
0542:                printer.indent().pln("super(previous);");
0543:                printer.decr().indent().pln('}');
0544:                printer.pln();
0545:
0546:                // Emit code for creating the next parser.
0547:                printer.sep().pln();
0548:                printer.indent().pln("protected PackratParser next() {").incr();
0549:                printer.indent().p("return new ").p(cName).pln("(this);");
0550:                printer.decr().indent().pln('}');
0551:                printer.pln();
0552:
0553:                // Emit code for productions.
0554:                iter = g.productions.iterator();
0555:                while (iter.hasNext()) {
0556:                    analyzer.process((Production) iter.next());
0557:                }
0558:
0559:                // Emit code for body.
0560:                if (null != g.body) {
0561:                    printer.sep().pln();
0562:                    action(g.body);
0563:                }
0564:
0565:                // Finish parser class.
0566:                printer.decr().indent().pln('}');
0567:
0568:                // Emit footer.
0569:                if (null != g.footer) {
0570:                    printer.pln().sep().pln();
0571:                    action(g.footer);
0572:                }
0573:            }
0574:
0575:            // ========================================================================
0576:
0577:            /** Generate code for the specified production. */
0578:            public void visit(Production p) {
0579:                MetaData md = (MetaData) p.getProperty(MetaData.NAME);
0580:                String field = fieldName(p.nonTerminal);
0581:                String method = methodName(p.nonTerminal);
0582:
0583:                printer.sep().pln();
0584:                printer.indent().pln("/**");
0585:                printer.indent().p(" * Parse ");
0586:                if (p.hasProperty(Constants.SYNTHETIC)
0587:                        && ((Boolean) p.getProperty(Constants.SYNTHETIC))
0588:                                .booleanValue()) {
0589:                    printer.p("synthetic ");
0590:                }
0591:                printer.p("nonterminal ").p(p.nonTerminal.name).pln('.');
0592:                if (p.hasProperty(DuplicateProductionFolder.DUPLICATES)) {
0593:                    List sources = (List) p
0594:                            .getProperty(DuplicateProductionFolder.DUPLICATES);
0595:                    printer
0596:                            .indent()
0597:                            .pln(
0598:                                    " * This nonterminal represents the duplicate productions ")
0599:                            .indent().p(" * ").p(Utilities.format(sources))
0600:                            .pln('.');
0601:                }
0602:                printer.indent().pln(" *");
0603:                printer.indent().pln(" * @return The result.");
0604:                printer.indent().pln(
0605:                        " * @throws IOException Signals an I/O error.");
0606:                printer.indent().pln(" */");
0607:                printer.indent();
0608:                if (analyzer.isTopLevel(p.nonTerminal)) {
0609:                    // Top-level parsing methods are public.
0610:                    printer.p("public");
0611:                } else {
0612:                    // The rest is private.
0613:                    printer.p("private");
0614:                }
0615:                printer.p(" Result ").p(method).pln("() throws IOException {")
0616:                        .incr();
0617:
0618:                // Only memoize non-transient productions that are used more than
0619:                // once.
0620:                if (((!Rats.optimizeChunks) || (1 < md.usageCount))
0621:                        && ((!Rats.optimizeTransient) || (!p.isTransient))) {
0622:                    if (chunked) {
0623:                        String chunk = chunkMap.get(p.nonTerminal).toString();
0624:                        printer.indent().p("if (null == ").p(PREFIX).p("Chunk")
0625:                                .p(chunk).p(") ").p(PREFIX).p("Chunk").p(chunk)
0626:                                .p(" = new Chunk").p(chunk).pln("();");
0627:                    }
0628:                    printer.indent().p("if (null == ").p(field).p(") ")
0629:                            .p(field).p(" = ").p(method).pln("$1();");
0630:                    printer.indent().p("return ").p(field).pln(';');
0631:                    printer.decr().indent().pln('}');
0632:
0633:                    printer.pln();
0634:
0635:                    printer.indent().p("/** Actually parse ");
0636:                    if (p.hasProperty(Constants.SYNTHETIC)) {
0637:                        printer.p("synthetic ");
0638:                    }
0639:                    printer.p("nonterminal <code>").p(p.nonTerminal.name).pln(
0640:                            "</code>. */");
0641:                    printer.indent().p("private Result ").p(method).pln(
0642:                            "$1() throws IOException {").incr();
0643:
0644:                    if (attributeDebug) {
0645:                        printer.indent().p("if (DEBUG) System.out.println(\"")
0646:                                .p(method).pln("$1: \" + toString());");
0647:                        printer.pln();
0648:                    }
0649:
0650:                } else if (attributeDebug) {
0651:                    printer.indent().p("if (DEBUG) System.out.println(\"").p(
0652:                            method).pln(": \" + toString());");
0653:                    printer.pln();
0654:                }
0655:
0656:                // Emit variable declarations.
0657:                alignment(md.requiresParser || (0 < md.repetitions.size()));
0658:                if (md.requiresParser) {
0659:                    printer.indent().p(cName).align(alignment).p(PARSER).pln(
0660:                            ';');
0661:                }
0662:                printer.indent().p("Result").align(alignment).p(RESULT)
0663:                        .pln(';');
0664:                printer.indent().p("ParseError").align(alignment)
0665:                        .p(PARSE_ERROR).pln(" = ParseError.DUMMY;");
0666:                if (md.requiresPredicate) {
0667:                    printer.indent().p("Result").align(alignment)
0668:                            .p(PRED_RESULT).pln(';');
0669:                }
0670:                if (md.requiresMatched) {
0671:                    printer.indent().p("boolean").align(alignment).p(MATCHED)
0672:                            .pln(';');
0673:                }
0674:                for (int i = 0; i < md.repetitions.size(); i++) {
0675:                    printer.indent().p(cName).align(alignment).p(REPETITION).p(
0676:                            i + 1).pln(';');
0677:                    if (((Boolean) md.repetitions.get(i)).booleanValue()) {
0678:                        printer.indent().p("boolean").align(alignment).p(
0679:                                REPEATED).p(i + 1).pln(';');
0680:                    }
0681:                }
0682:                if (Type.isVoidT(p.type)) {
0683:                    printer.indent().p(Type.voidRefT()).align(
0684:                            Type.voidRefT().length(), alignment);
0685:                } else {
0686:                    printer.indent().p(p.type)
0687:                            .align(p.type.length(), alignment);
0688:                }
0689:                printer.p(VALUE).pln(';');
0690:                if (md.requiresChar) {
0691:                    printer.indent().p(Type.charT()).align(alignment).p(CHAR)
0692:                            .pln(';');
0693:                }
0694:
0695:                // Emit code for production element.
0696:                resultName = RESULT;
0697:                baseParser = "this";
0698:                useBaseParser = true;
0699:                choiceLevel = -1;
0700:                repetitionLevel = 0;
0701:                savedRepetitionLevel = 0;
0702:                repeatOnce = false;
0703:                seenTest = false;
0704:                endsWithParseError = false;
0705:                p.element.accept(this );
0706:
0707:                if (seenTest) {
0708:                    printer.pln();
0709:                    printer.indent().pln("// Done.");
0710:                    if (endsWithParseError) {
0711:                        parseError();
0712:                    }
0713:                    printer.indent().p("return ").p(PARSE_ERROR).pln(';');
0714:                }
0715:                printer.decr().indent().pln('}');
0716:                printer.pln();
0717:            }
0718:
0719:            // ========================================================================
0720:
0721:            /**
0722:             * Emit the code for assigning the result variable, threading the
0723:             * parse error, and for testing the result.
0724:             *
0725:             * @param methodName The name of the parser method to use.
0726:             * @param saveParser Flag for whether to save the parser in the
0727:             *   parser variable.
0728:             */
0729:            protected void result(String methodName, boolean saveParser) {
0730:                printer.pln();
0731:
0732:                // Clear the first element flag.
0733:                firstElement = false;
0734:
0735:                if (useBaseParser) {
0736:                    // The first result of an ordered choice or repetition as well
0737:                    // as the first element after a repetition always builds on the
0738:                    // current base parser.  The first element of a predicate also
0739:                    // builds on the current base parser.
0740:
0741:                    if (saveParser) {
0742:                        // Assign parser and result.
0743:                        printer.indent().p(PARSER).p(" = ").p(baseParser).pln(
0744:                                ';');
0745:                        printer.indent().p(resultName).p(" = ").p(PARSER)
0746:                                .p('.').p(methodName).pln("();");
0747:                    } else {
0748:                        // Assign result.
0749:                        printer.indent().p(resultName).p(" = ").p(baseParser)
0750:                                .p('.').p(methodName).pln("();");
0751:                    }
0752:
0753:                    // Thread parse error.
0754:                    if ((!notFollowedBy()) && (!PARSE_CHAR.equals(methodName))) {
0755:                        printer.indent().p(PARSE_ERROR).p("  = ")
0756:                                .p(PARSE_ERROR).p(".select(").p(resultName)
0757:                                .pln(".parseError());");
0758:                    }
0759:
0760:                    useBaseParser = false;
0761:
0762:                } else {
0763:                    // All other elements build on the last regular/predicate
0764:                    // result, depending on whether we are processing regular or
0765:                    // predicate elements.
0766:
0767:                    if (saveParser) {
0768:                        // Assign parser and result.
0769:                        printer.indent().p(PARSER).p(" = (").p(cName).p(')').p(
0770:                                resultName).pln(".parser;");
0771:                        printer.indent().p(resultName).p(" = ").p(PARSER)
0772:                                .p('.').p(methodName).pln("();");
0773:
0774:                    } else {
0775:                        // Assign result.
0776:                        printer.indent().p(resultName).p(" = ((").p(cName).p(
0777:                                ')').p(resultName).p(".parser).").p(methodName)
0778:                                .pln("();");
0779:                    }
0780:
0781:                    // Thread parse error.
0782:                    if ((!notFollowedBy()) && (!PARSE_CHAR.equals(methodName))) {
0783:                        printer.indent().p(PARSE_ERROR).p("  = ")
0784:                                .p(PARSE_ERROR).p(".select(").p(resultName)
0785:                                .pln(".parseError());");
0786:                    }
0787:                }
0788:            }
0789:
0790:            /** Emit the code testing whether the result has a value. */
0791:            protected void valueTest() {
0792:                printer.indent().p("if (").p(resultName).pln(".hasValue()) {")
0793:                        .incr();
0794:            }
0795:
0796:            /**
0797:             * Emit the code for testing the result.
0798:             *
0799:             * @param text The expected text value.
0800:             */
0801:            protected void valueTest(String text) {
0802:                printer.indent().p("if (").p(resultName).pln(".hasValue() &&")
0803:                        .indent().p("   \"").escape(text,
0804:                                Utilities.JAVA_ESCAPES).p("\".equals(").p(
0805:                                resultName).pln(".semanticValue())) {").incr();
0806:            }
0807:
0808:            /**
0809:             * Note that a test has been emitted.  This method should be called
0810:             * at the <i>end</i> of the method that emitted the test.
0811:             */
0812:            protected void tested() {
0813:                seenTest = true;
0814:            }
0815:
0816:            /**
0817:             * Emit the code for the next element. If the next element is the
0818:             * last element in the main sequence, the code for returning a
0819:             * semantic value is also emitted.
0820:             *
0821:             * @see #returnValue()
0822:             */
0823:            protected void nextElement() {
0824:                // Process predicate elements first.
0825:                if (predicate) {
0826:                    if (predicateIter.hasNext()) {
0827:                        // Emit code for the next predicate element.
0828:                        ((Element) predicateIter.next()).accept(this );
0829:                        return;
0830:
0831:                    } else if (savedRepetitionLevel < repetitionLevel) {
0832:                        // Assign the repetition parser variable and, if necessary,
0833:                        // the repeated flag; then continue with the loop.
0834:                        printer.pln();
0835:                        printer.indent().p(REPETITION).p(repetitionLevel).p(
0836:                                " = (").p(cName).p(')').p(resultName).pln(
0837:                                ".parser;");
0838:                        if (repeatOnce) {
0839:                            printer.indent().p(REPEATED).p(repetitionLevel)
0840:                                    .pln("   = true;");
0841:                        }
0842:                        printer.indent().pln("continue;");
0843:                        return;
0844:
0845:                    } else {
0846:                        // Assign matched variable for not-followed-by predicates.
0847:                        if (notFollowedBy) {
0848:                            printer.pln();
0849:                            printer.indent().p(MATCHED).pln(" = true;");
0850:                            return;
0851:                        }
0852:
0853:                        // Restore regular element processing and fall through for
0854:                        // followed-by predicates.
0855:                        predicate = false;
0856:                        baseParser = savedBaseParser;
0857:                        useBaseParser = savedUseBaseParser;
0858:                        resultName = RESULT;
0859:                    }
0860:                }
0861:
0862:                // Process the next regular grammar element.
0863:                if (elementIter.hasNext()) {
0864:                    ((Element) elementIter.next()).accept(this );
0865:
0866:                } else if (0 < repetitionLevel) {
0867:                    printer.pln();
0868:                    printer.indent().p(REPETITION).p(repetitionLevel).p(" = (")
0869:                            .p(cName).p(')').p(resultName).pln(".parser;");
0870:                    if (repeatOnce) {
0871:                        printer.indent().p(REPEATED).p(repetitionLevel).pln(
0872:                                "   = true;");
0873:                    }
0874:                    printer.indent().pln("continue;");
0875:
0876:                } else {
0877:                    returnValue();
0878:                }
0879:            }
0880:
0881:            /**
0882:             * Emit the code for annotating semantic values with their location.
0883:             */
0884:            private void location() {
0885:                // Do not include location information if the grammar does not
0886:                // have the location attribute or the type of the production's
0887:                // semantic value is not a node.  Note that void and text-only
0888:                // productions automatically fall under the second case.
0889:                if ((!attributeLocation)
0890:                        || Type.isNotANode(analyzer.current().type)) {
0891:                    return;
0892:                }
0893:
0894:                // Emit the location test.
0895:                printer.indent().p("if (").p(VALUE).pln(" instanceof Node) {")
0896:                        .incr();
0897:                printer.indent().p("((Node)").p(VALUE).p(").")
0898:                        .p("setLocation(").p(FILE).p(", ").p(LINE).p(", ").p(
0899:                                COLUMN).pln(");");
0900:                printer.decr().indent().pln('}');
0901:            }
0902:
0903:            /**
0904:             * Emit the code for returning a semantic value.
0905:             */
0906:            protected void returnValue() {
0907:                printer.pln();
0908:
0909:                if (useBaseParser) {
0910:                    location();
0911:
0912:                    printer.indent().p("return new SemanticValue(").p(VALUE).p(
0913:                            ", ").p(baseParser).p(", ").p(PARSE_ERROR)
0914:                            .pln(");");
0915:
0916:                    useBaseParser = false;
0917:
0918:                } else {
0919:                    location();
0920:
0921:                    if (Rats.optimizeValues) {
0922:                        printer.indent().p("return ").p(RESULT).p(
0923:                                ".createValue(").p(VALUE).p(", ")
0924:                                .p(PARSE_ERROR).pln(");");
0925:                    } else {
0926:                        printer.indent().p("return new SemanticValue(")
0927:                                .p(VALUE).p(", ").p(RESULT).p(".parser, ").p(
0928:                                        PARSE_ERROR).pln(");");
0929:                    }
0930:                }
0931:            }
0932:
0933:            /**
0934:             * Emit the code for generating a parse error.
0935:             */
0936:            protected void parseError() {
0937:                printer
0938:                        .indent()
0939:                        .p(PARSE_ERROR)
0940:                        .p(" = ")
0941:                        .p(PARSE_ERROR)
0942:                        .p(".select(\"")
0943:                        .p(
0944:                                Utilities
0945:                                        .toDescription(analyzer.current().nonTerminal.name))
0946:                        .pln(" expected\", this);");
0947:            }
0948:
0949:            /**
0950:             * Emit the code for generating a parse error.
0951:             *
0952:             * @param text The expected text.
0953:             */
0954:            protected void parseError(String text) {
0955:                printer.indent().p(PARSE_ERROR).p(" = ").p(PARSE_ERROR).p(
0956:                        ".select(\"\\\"").p(
0957:                        Utilities.escape(text, Utilities.JAVA_ESCAPES
0958:                                | Utilities.ESCAPE_DOUBLE)).p(
0959:                        "\\\" expected\", ").p(PARSER).pln(");");
0960:            }
0961:
0962:            // ========================================================================
0963:
0964:            /**
0965:             * Return the name of the parser variable for the current nested
0966:             * choice level.
0967:             *
0968:             * @return The nested choice parser variable.
0969:             */
0970:            protected String nestedChoice() {
0971:                return NESTED_CHOICE + Integer.toString(choiceLevel);
0972:            }
0973:
0974:            /** Generate code for the specified ordered choice. */
0975:            public void visit(OrderedChoice c) {
0976:                String base = baseParser;
0977:                boolean used = useBaseParser;
0978:                choiceLevel++;
0979:
0980:                // For non-top-level choices, declare a parser variable and save
0981:                // the current parser.
0982:                if (0 != choiceLevel) {
0983:                    printer.pln();
0984:
0985:                    if (useBaseParser) {
0986:                        printer.indent().p("final ").p(cName).p(' ').p(
0987:                                nestedChoice()).p(" = ").p(base).pln(';');
0988:                    } else {
0989:                        printer.indent().p("final ").p(cName).p(' ').p(
0990:                                nestedChoice()).p(" = (").p(cName).p(')').p(
0991:                                resultName).pln(".parser;");
0992:                    }
0993:                }
0994:
0995:                // Process the options.
0996:                Iterator optionIter = c.options.iterator();
0997:                int optionNumber = 0;
0998:
0999:                while (optionIter.hasNext()) {
1000:                    elementIter = ((Sequence) optionIter.next()).elements
1001:                            .iterator();
1002:                    firstElement = (0 == choiceLevel);
1003:                    baseParser = (0 == choiceLevel) ? "this" : nestedChoice();
1004:                    useBaseParser = true;
1005:                    seenTest = false;
1006:                    optionNumber++;
1007:
1008:                    printer.pln();
1009:                    if (0 == choiceLevel) {
1010:                        printer.indent().p("// Option ").p(optionNumber).pln(
1011:                                '.');
1012:                    } else {
1013:                        printer.indent().p("// Nested option ").p(optionNumber)
1014:                                .pln('.');
1015:                    }
1016:
1017:                    nextElement();
1018:                }
1019:
1020:                choiceLevel--;
1021:                useBaseParser = used;
1022:                baseParser = base;
1023:            }
1024:
1025:            // ========================================================================
1026:
1027:            /** Generate code for the specified repetition. */
1028:            public void visit(Repetition r) {
1029:                firstElement = false;
1030:                String base = baseParser;
1031:                boolean used = useBaseParser;
1032:                boolean once = repeatOnce;
1033:                repeatOnce = r.once;
1034:                repetitionLevel++;
1035:
1036:                // Save current parser.
1037:                printer.pln();
1038:                printer.indent().p(REPETITION).p(repetitionLevel).p(" = ");
1039:                if (useBaseParser) {
1040:                    printer.p(base).pln(';');
1041:                } else {
1042:                    printer.p('(').p(cName).p(')').p(resultName)
1043:                            .pln(".parser;");
1044:                }
1045:
1046:                // Reset repeated flag if necessary.
1047:                if (repeatOnce) {
1048:                    printer.indent().p(REPEATED).p(repetitionLevel).pln(
1049:                            "   = false;");
1050:                }
1051:
1052:                // Save current code generation state.
1053:                Iterator iter;
1054:                if (predicate) {
1055:                    iter = predicateIter;
1056:                    predicateIter = ((Sequence) r.element).elements.iterator();
1057:                } else {
1058:                    iter = elementIter;
1059:                    elementIter = ((Sequence) r.element).elements.iterator();
1060:                }
1061:
1062:                // Emit code for the repeated elements.
1063:                printer.indent().pln("while (true) {").incr();
1064:                baseParser = REPETITION + Integer.toString(repetitionLevel);
1065:                useBaseParser = true;
1066:                nextElement();
1067:                printer.indent().pln("break;");
1068:                printer.decr().indent().pln('}');
1069:
1070:                // Restore code generation state.
1071:                if (predicate) {
1072:                    predicateIter = iter;
1073:                } else {
1074:                    elementIter = iter;
1075:                }
1076:
1077:                // Emit code for the rest of the current sequence.
1078:                if (repeatOnce) {
1079:                    printer.pln();
1080:                    printer.indent().p("if (").p(REPEATED).p(repetitionLevel)
1081:                            .pln(") {").incr();
1082:                }
1083:                repetitionLevel--;
1084:                repeatOnce = once;
1085:
1086:                baseParser = REPETITION + Integer.toString(repetitionLevel + 1);
1087:                useBaseParser = true;
1088:                if (!r.once) {
1089:                    seenTest = false;
1090:                }
1091:                nextElement();
1092:
1093:                if (r.once) {
1094:                    printer.decr().indent().pln('}');
1095:                    tested();
1096:                }
1097:                baseParser = base;
1098:                useBaseParser = used;
1099:            }
1100:
1101:            // ========================================================================
1102:
1103:            /** Generate code for the specified followed-by predicate. */
1104:            public void visit(FollowedBy p) {
1105:                if (predicate) {
1106:                    throw new IllegalStateException(
1107:                            "Predicate within predicate");
1108:                }
1109:
1110:                predicate = true;
1111:                notFollowedBy = false;
1112:                savedFirstElement = firstElement;
1113:                savedBaseParser = baseParser;
1114:                if (!useBaseParser) {
1115:                    // Only set a new base parser if the base parser is not used for
1116:                    // the next element.
1117:                    baseParser = "((" + cName + ")" + RESULT + ".parser)";
1118:                }
1119:                savedUseBaseParser = useBaseParser;
1120:                savedRepetitionLevel = repetitionLevel;
1121:                useBaseParser = true;
1122:                resultName = PRED_RESULT;
1123:                predicateIter = ((Sequence) p.element).elements.iterator();
1124:
1125:                // Emit code for the followed-by predicate and the rest of the
1126:                // rule sequence.
1127:                nextElement();
1128:
1129:                tested();
1130:            }
1131:
1132:            // ========================================================================
1133:
1134:            /**
1135:             * Determine whether we are processing a not-followed-by predicate.
1136:             *
1137:             * @return <code>true</code> if we are processing a not-followed-by
1138:             * predicate.
1139:             */
1140:            protected boolean notFollowedBy() {
1141:                return (predicate && notFollowedBy);
1142:            }
1143:
1144:            /** Generate code for the specified not-followed-by predicate. */
1145:            public void visit(NotFollowedBy p) {
1146:                if (predicate) {
1147:                    throw new IllegalStateException(
1148:                            "Predicate within predicate");
1149:                }
1150:
1151:                predicate = true;
1152:                notFollowedBy = true;
1153:                savedFirstElement = firstElement;
1154:                savedBaseParser = baseParser;
1155:                if (!useBaseParser) {
1156:                    // Only set a new base parser if the base parser is not used for
1157:                    // the next element.
1158:                    baseParser = "((" + cName + ")" + RESULT + ".parser)";
1159:                }
1160:                savedUseBaseParser = useBaseParser;
1161:                useBaseParser = true;
1162:                savedRepetitionLevel = repetitionLevel;
1163:                resultName = PRED_RESULT;
1164:                predicateIter = ((Sequence) p.element).elements.iterator();
1165:
1166:                // Emit code for the not-followed-by predicate.
1167:                printer.pln();
1168:                printer.indent().p(MATCHED).pln(" = false;");
1169:
1170:                nextElement();
1171:
1172:                // Restore regular element processing.
1173:                predicate = false;
1174:                firstElement = savedFirstElement;
1175:                baseParser = savedBaseParser;
1176:                useBaseParser = savedUseBaseParser;
1177:                resultName = RESULT;
1178:
1179:                // Emit code for the rest of the rule sequence.
1180:                printer.pln();
1181:                printer.indent().p("if (! ").p(MATCHED).pln(") {").incr();
1182:
1183:                nextElement();
1184:
1185:                printer.decr().indent().pln("} else {").incr();
1186:                parseError();
1187:                printer.decr().indent().pln('}');
1188:
1189:                tested();
1190:            }
1191:
1192:            // ========================================================================
1193:
1194:            /** Generate code for the specified semantic predicate. */
1195:            public void visit(SemanticPredicate p) {
1196:                printer.pln().indent().p("if (");
1197:
1198:                Action a = (Action) p.element;
1199:                if (1 == a.code.size()) {
1200:                    printer.p((String) a.code.get(0)).pln(") {").incr();
1201:                } else {
1202:                    boolean first = true;
1203:                    Iterator iter = a.code.iterator();
1204:                    while (iter.hasNext()) {
1205:                        if (first) {
1206:                            printer.p((String) iter.next()).incr();
1207:                            first = false;
1208:                        } else {
1209:                            printer.pln().indent().p((String) iter.next());
1210:                        }
1211:                        printer.pln(") {");
1212:                    }
1213:                }
1214:
1215:                nextElement();
1216:
1217:                printer.decr().indent().pln('}');
1218:
1219:                if (!notFollowedBy()) {
1220:                    endsWithParseError = true;
1221:                }
1222:
1223:                tested();
1224:            }
1225:
1226:            // ========================================================================
1227:
1228:            /** Generate code for the specified binding. */
1229:            public void visit(Binding b) {
1230:                // Save old name and element.
1231:                String oldName = bindingName;
1232:                Element oldElement = bindingElement;
1233:
1234:                // Set up new name and element;
1235:                bindingName = b.name;
1236:                bindingElement = b.element;
1237:
1238:                // Visit element.
1239:                b.element.accept(this );
1240:
1241:                // Restore old name and element.
1242:                bindingName = oldName;
1243:                bindingElement = oldElement;
1244:            }
1245:
1246:            /**
1247:             * Determine whether the current element has a binding.
1248:             *
1249:             * @return <code>true</code> if the current element has a binding.
1250:             */
1251:            protected boolean hasBinding() {
1252:                return (null != bindingName);
1253:            }
1254:
1255:            /** Actually emit the code for the last visited binding. */
1256:            protected void binding() {
1257:                if (bindingElement instanceof  NonTerminal) {
1258:                    String type = analyzer.lookup((NonTerminal) bindingElement).type;
1259:                    binding1(type, bindingName, type, resultName
1260:                            + ".semanticValue()");
1261:
1262:                } else if (bindingElement instanceof  CharTerminal) {
1263:                    if (VALUE.equals(bindingName)) {
1264:                        binding1(Type.charRefT(), bindingName, null,
1265:                                "new Character(" + resultName + ".charValue())");
1266:                    } else {
1267:                        binding1(Type.charT(), bindingName, null, resultName
1268:                                + ".charValue()");
1269:                    }
1270:
1271:                } else if (bindingElement instanceof  StringLiteral) {
1272:                    binding1(Type.stringT(), bindingName, null, "\""
1273:                            + Utilities.escape(
1274:                                    ((StringLiteral) bindingElement).text,
1275:                                    Utilities.JAVA_ESCAPES) + "\"");
1276:
1277:                } else if (bindingElement instanceof  StringMatch) {
1278:                    binding1(Type.stringT(), bindingName, null, "\""
1279:                            + Utilities.escape(
1280:                                    ((StringMatch) bindingElement).text,
1281:                                    Utilities.JAVA_ESCAPES) + "\"");
1282:
1283:                } else {
1284:                    throw new IllegalStateException(
1285:                            "Unrecognized binding element " + bindingElement);
1286:                }
1287:            }
1288:
1289:            /**
1290:             * Emit the binding code.
1291:             *
1292:             * @param type The variable type.
1293:             * @param name The variable name.
1294:             * @param cast The cast type, or <code>null</code> for no cast.
1295:             * @param expr The value producing expression.
1296:             */
1297:            private void binding1(String type, String name, String cast,
1298:                    String expr) {
1299:                printer.indent();
1300:
1301:                if (VALUE.equals(name)) {
1302:                    printer.p(VALUE).p(" = ");
1303:
1304:                } else {
1305:                    if (attributeConstantBinding) {
1306:                        printer.p("final ");
1307:                    }
1308:                    printer.p(type).p(' ').p(name).p(" = ");
1309:                }
1310:
1311:                if (null != cast) {
1312:                    printer.p('(').p(cast).p(')');
1313:                }
1314:
1315:                printer.p(expr).pln(';');
1316:            }
1317:
1318:            /** Clear binding information after usage. */
1319:            protected void clearBinding() {
1320:                bindingName = null;
1321:                bindingElement = null;
1322:            }
1323:
1324:            // ========================================================================
1325:
1326:            /** Generate code for the specified string match. */
1327:            public void visit(StringMatch m) {
1328:                final boolean first = firstElement;
1329:
1330:                // At this point, the element of the string match must be a
1331:                // nonterminal.
1332:                NonTerminal nt = (NonTerminal) m.element;
1333:
1334:                result(methodName(nt), ((!notFollowedBy()) && (!first)));
1335:                valueTest(m.text);
1336:
1337:                if (hasBinding()) {
1338:                    binding();
1339:                    clearBinding();
1340:                }
1341:
1342:                nextElement();
1343:
1344:                if (notFollowedBy()) {
1345:                    printer.decr().indent().pln('}');
1346:                } else if (attributeNoMatchingErrors
1347:                        || (Rats.optimizeErrors && first)) {
1348:                    printer.decr().indent().pln('}');
1349:                    endsWithParseError = true;
1350:                } else {
1351:                    printer.decr().indent().pln("} else {").incr();
1352:                    parseError(m.text);
1353:                    printer.decr().indent().pln('}');
1354:                }
1355:
1356:                tested();
1357:            }
1358:
1359:            // ========================================================================
1360:
1361:            /** Generate code for the specified nonterminal. */
1362:            public void visit(NonTerminal nt) {
1363:                result(methodName(nt), false);
1364:                valueTest();
1365:
1366:                if (hasBinding()) {
1367:                    binding();
1368:                    clearBinding();
1369:                }
1370:
1371:                nextElement();
1372:
1373:                printer.decr().indent().pln('}');
1374:                tested();
1375:            }
1376:
1377:            // ========================================================================
1378:
1379:            /** Generate code for the any character element. */
1380:            public void visit(AnyChar a) {
1381:                result(PARSE_CHAR, false);
1382:                valueTest();
1383:
1384:                if (hasBinding()) {
1385:                    binding();
1386:                    clearBinding();
1387:                }
1388:
1389:                nextElement();
1390:
1391:                printer.decr().indent().pln('}');
1392:
1393:                if (!notFollowedBy()) {
1394:                    endsWithParseError = true;
1395:                }
1396:
1397:                tested();
1398:            }
1399:
1400:            // ========================================================================
1401:
1402:            /** Generate code for the specified character literal. */
1403:            public void visit(CharLiteral l) {
1404:                result(PARSE_CHAR, false);
1405:                valueTest();
1406:
1407:                String name;
1408:                if (hasBinding()) {
1409:                    binding();
1410:                    name = bindingName;
1411:                    clearBinding();
1412:                } else {
1413:                    printer.indent().p(CHAR).p(" = ").p(resultName).pln(
1414:                            ".charValue();");
1415:                    name = CHAR;
1416:                }
1417:
1418:                printer.pln();
1419:                printer.indent().p("if (\'")
1420:                        .escape(l.c, Utilities.JAVA_ESCAPES).p("\' == ")
1421:                        .p(name).pln(") {").incr();
1422:
1423:                nextElement();
1424:
1425:                printer.decr().indent().pln('}');
1426:                printer.decr().indent().pln('}');
1427:
1428:                if (!notFollowedBy()) {
1429:                    endsWithParseError = true;
1430:                }
1431:
1432:                tested();
1433:            }
1434:
1435:            // ========================================================================
1436:
1437:            /** Generate code for the specified character class. */
1438:            public void visit(CharClass c) {
1439:                result(PARSE_CHAR, false);
1440:                valueTest();
1441:
1442:                String name;
1443:                if (hasBinding()) {
1444:                    binding();
1445:                    name = bindingName;
1446:                    clearBinding();
1447:                } else {
1448:                    printer.indent().p(CHAR).p(" = ").p(resultName).pln(
1449:                            ".charValue();");
1450:                    name = CHAR;
1451:                }
1452:
1453:                printer.pln();
1454:
1455:                final int length = c.ranges.size();
1456:                Iterator iter = c.ranges.iterator();
1457:
1458:                if (1 == length) {
1459:                    printer.indent().p("if ");
1460:                } else {
1461:                    printer.indent().p("if (");
1462:                }
1463:
1464:                while (iter.hasNext()) {
1465:                    CharRange r = (CharRange) iter.next();
1466:
1467:                    if (c.exclusive) {
1468:                        if (r.first == r.last) {
1469:                            printer.p("(\'").escape(r.first,
1470:                                    Utilities.JAVA_ESCAPES).p("\' != ").p(name)
1471:                                    .p(')');
1472:                        } else {
1473:                            printer.p('(').p(name).p(" < \'").escape(r.first,
1474:                                    Utilities.JAVA_ESCAPES).p(") || (\'")
1475:                                    .escape(r.last, Utilities.JAVA_ESCAPES).p(
1476:                                            "\' < ").p(name).p("))");
1477:                        }
1478:
1479:                    } else {
1480:                        if (r.first == r.last) {
1481:                            printer.p("(\'").escape(r.first,
1482:                                    Utilities.JAVA_ESCAPES).p("\' == ").p(name)
1483:                                    .p(')');
1484:                        } else {
1485:                            printer.p("((\'").escape(r.first,
1486:                                    Utilities.JAVA_ESCAPES).p("\' <= ").p(name)
1487:                                    .p(") && (").p(name).p(" <= \'").escape(
1488:                                            r.last, Utilities.JAVA_ESCAPES).p(
1489:                                            "\'))");
1490:                        }
1491:                    }
1492:
1493:                    if (iter.hasNext()) {
1494:                        if (c.exclusive) {
1495:                            printer.pln(" &&");
1496:                        } else {
1497:                            printer.pln(" ||");
1498:                        }
1499:                        printer.indent().p("    ");
1500:                    }
1501:                }
1502:
1503:                if (1 == length) {
1504:                    printer.pln(" {").incr();
1505:                } else {
1506:                    printer.pln(") {").incr();
1507:                }
1508:
1509:                nextElement();
1510:
1511:                printer.decr().indent().pln('}');
1512:                printer.decr().indent().pln('}');
1513:
1514:                if (!notFollowedBy()) {
1515:                    endsWithParseError = true;
1516:                }
1517:
1518:                tested();
1519:            }
1520:
1521:            // ========================================================================
1522:
1523:            /** Generate code for the specified literal. */
1524:            public void visit(StringLiteral l) {
1525:                final boolean first = firstElement;
1526:                final int length = l.text.length();
1527:
1528:                for (int i = 0; i < length; i++) {
1529:                    char c = l.text.charAt(i);
1530:
1531:                    result(PARSE_CHAR,
1532:                            ((0 == i) && (!notFollowedBy()) && (!first)));
1533:                    valueTest();
1534:                    printer.indent().p(CHAR).p(" = ").p(resultName).pln(
1535:                            ".charValue();");
1536:                    printer.pln();
1537:                    printer.indent().p("if (\'").escape(c,
1538:                            Utilities.JAVA_ESCAPES).p("\' == ").p(CHAR).pln(
1539:                            ") {").incr();
1540:                }
1541:
1542:                if (hasBinding()) {
1543:                    binding();
1544:                    clearBinding();
1545:                }
1546:
1547:                nextElement();
1548:
1549:                for (int i = 0; i < length; i++) {
1550:                    if (notFollowedBy()) {
1551:                        printer.decr().indent().pln('}');
1552:                        printer.decr().indent().pln('}');
1553:                    } else if (attributeNoMatchingErrors
1554:                            || (Rats.optimizeErrors && first)) {
1555:                        printer.decr().indent().pln('}');
1556:                        printer.decr().indent().pln('}');
1557:                        endsWithParseError = true;
1558:                    } else {
1559:                        printer.decr().indent().pln("} else {").incr();
1560:                        parseError(l.text);
1561:                        printer.decr().indent().pln('}');
1562:                        printer.decr().indent().pln("} else {").incr();
1563:                        parseError(l.text);
1564:                        printer.decr().indent().pln('}');
1565:                    }
1566:                }
1567:
1568:                tested();
1569:            }
1570:
1571:            // ========================================================================
1572:
1573:            /** Generate code for the specified character switch. */
1574:            public void visit(CharSwitch s) {
1575:                result(PARSE_CHAR, false);
1576:                valueTest();
1577:
1578:                String name;
1579:                if (hasBinding()) {
1580:                    binding();
1581:                    name = bindingName;
1582:                    clearBinding();
1583:                } else {
1584:                    printer.indent().p(CHAR).p(" = ").p(resultName).pln(
1585:                            ".charValue();");
1586:                    name = CHAR;
1587:                }
1588:
1589:                printer.pln();
1590:                printer.indent().p("switch (").p(name).pln(") {").incr();
1591:
1592:                Iterator iter = s.cases.iterator();
1593:                while (iter.hasNext()) {
1594:                    CharCase c = (CharCase) iter.next();
1595:                    Iterator iter2 = c.klass.ranges.iterator();
1596:                    while (iter2.hasNext()) {
1597:                        CharRange r = (CharRange) iter2.next();
1598:
1599:                        for (char k = r.first; k <= r.last; k++) {
1600:                            printer.indentLess().p("case \'").escape(k,
1601:                                    Utilities.JAVA_ESCAPES).pln("\':");
1602:                        }
1603:                    }
1604:
1605:                    if (null == c.element) {
1606:                        printer.indent().pln("/* No match. */");
1607:                        printer.indent().pln("break;");
1608:
1609:                    } else {
1610:                        printer.indent().p('{').incr();
1611:                        // The line terminator is printed by emitting code for
1612:                        // c.element.
1613:
1614:                        seenTest = false;
1615:
1616:                        if (c.element instanceof  OrderedChoice) {
1617:                            c.element.accept(this );
1618:                        } else {
1619:                            elementIter = ((Sequence) c.element).elements
1620:                                    .iterator();
1621:                            nextElement();
1622:                        }
1623:
1624:                        printer.decr().indent().pln('}');
1625:                        if (seenTest) {
1626:                            printer.indent().pln("break;");
1627:                        }
1628:                    }
1629:
1630:                    printer.pln();
1631:                }
1632:
1633:                if (null == s.base) {
1634:                    printer.indentLess().pln("default:");
1635:                    printer.indent().pln("/* No match. */");
1636:                } else {
1637:                    printer.indentLess().pln("default:");
1638:                    printer.indent().p('{').incr();
1639:                    // The line terminator is printed by emitting code for s.base.
1640:                    if (s.base instanceof  OrderedChoice) {
1641:                        s.base.accept(this );
1642:                    } else {
1643:                        elementIter = ((Sequence) s.base).elements.iterator();
1644:                        nextElement();
1645:                    }
1646:                    printer.decr().indent().pln('}');
1647:                }
1648:
1649:                printer.decr().indent().pln('}');
1650:                printer.decr().indent().pln('}');
1651:
1652:                endsWithParseError = true;
1653:                tested();
1654:            }
1655:
1656:            // ========================================================================
1657:
1658:            /** Actually emit code for the specified action. */
1659:            protected void action(Action a) {
1660:                Iterator iter = a.code.iterator();
1661:                while (iter.hasNext()) {
1662:                    printer.indent().pln(iter.next().toString());
1663:                }
1664:            }
1665:
1666:            /** Generate code for the specified action. */
1667:            public void visit(Action a) {
1668:                printer.pln();
1669:                action(a);
1670:
1671:                nextElement();
1672:            }
1673:
1674:            // ========================================================================
1675:
1676:            /** Generate code for the specified null value. */
1677:            public void visit(NullValue v) {
1678:                printer.pln();
1679:                printer.indent().p(VALUE).pln(" = null;");
1680:
1681:                nextElement();
1682:            }
1683:
1684:            /** Generate code for the specified string value. */
1685:            public void visit(StringValue v) {
1686:                printer.pln();
1687:                printer.indent().p(VALUE).p(" = \"").escape(v.text,
1688:                        Utilities.JAVA_ESCAPES).pln("\";");
1689:
1690:                nextElement();
1691:            }
1692:
1693:            /** Generate code for the specified text value. */
1694:            public void visit(TextValue v) {
1695:                if (predicate) {
1696:                    throw new IllegalStateException(
1697:                            "Text value within predicate");
1698:                }
1699:
1700:                printer.pln();
1701:                if (firstElement) {
1702:                    printer.indent().p(VALUE).pln(" = \"\";");
1703:                } else if (useBaseParser) {
1704:                    printer.indent().p(VALUE).p(" = getDifference(").p(
1705:                            baseParser).pln(");");
1706:                } else {
1707:                    printer.indent().p(VALUE).p(" = getDifference(").p(RESULT)
1708:                            .pln(".parser);");
1709:                }
1710:
1711:                nextElement();
1712:            }
1713:
1714:            /** Generate code for the specified empty list value. */
1715:            public void visit(EmptyListValue v) {
1716:                printer.pln();
1717:                printer.indent().p(VALUE).pln(" = Pair.EMPTY;");
1718:
1719:                nextElement();
1720:            }
1721:
1722:            /** Generate code for the specified singleton list value. */
1723:            public void visit(SingletonListValue v) {
1724:                printer.pln();
1725:                printer.indent().p(VALUE).p(" = new Pair(").p(v.value)
1726:                        .pln(");");
1727:
1728:                nextElement();
1729:            }
1730:
1731:            /** Generate code for the specified list value. */
1732:            public void visit(ListValue v) {
1733:                printer.pln();
1734:                printer.indent().p(VALUE).p(" = new Pair(").p(v.value).p(", ")
1735:                        .p(v.list).pln(");");
1736:
1737:                nextElement();
1738:            }
1739:
1740:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.