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: }
|