All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.javacc.parser.ParseEngine Maven / Gradle / Ivy

There is a newer version: 4.1.5
Show newest version
// Copyright 2011 Google Inc. All Rights Reserved.
// Author: [email protected] (Sreeni Viswanadha)

/* Copyright (c) 2006, Sun Microsystems, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Sun Microsystems, Inc. nor the names of its
 *       contributors may be used to endorse or promote products derived from
 *       this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */
package org.javacc.parser;

import static org.javacc.parser.JavaCCGlobals.bnfproductions;
import static org.javacc.parser.JavaCCGlobals.ccol;
import static org.javacc.parser.JavaCCGlobals.cline;
import static org.javacc.parser.JavaCCGlobals.cu_name;
import static org.javacc.parser.JavaCCGlobals.jj2index;
import static org.javacc.parser.JavaCCGlobals.lookaheadNeeded;
import static org.javacc.parser.JavaCCGlobals.maskVals;
import static org.javacc.parser.JavaCCGlobals.maskindex;
import static org.javacc.parser.JavaCCGlobals.names_of_tokens;
import static org.javacc.parser.JavaCCGlobals.production_table;
import static org.javacc.parser.JavaCCGlobals.staticOpt;
import static org.javacc.parser.JavaCCGlobals.tokenCount;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;

public class ParseEngine
{

  private int gensymindex = 0;
  private int indentamt;
  private boolean jj2LA;
  private CodeGenerator codeGenerator;
  private final boolean isJavaDialect = Options.isOutputLanguageJava ();

  /**
   * These lists are used to maintain expansions for which code generation in
   * phase 2 and phase 3 is required. Whenever a call is generated to a phase 2
   * or phase 3 routine, a corresponding entry is added here if it has not
   * already been added. The phase 3 routines have been optimized in version
   * 0.7pre2. Essentially only those methods (and only those portions of these
   * methods) are generated that are required. The lookahead amount is used to
   * determine this. This change requires the use of a hash table because it is
   * now possible for the same phase 3 routine to be requested multiple times
   * with different lookaheads. The hash table provides a easily searchable
   * capability to determine the previous requests. The phase 3 routines now are
   * performed in a two step process - the first step gathers the requests
   * (replacing requests with lower lookaheads with those requiring larger
   * lookaheads). The second step then generates these methods. This
   * optimization and the hashtable makes it look like we do not need the flag
   * "phase3done" any more. But this has not been removed yet.
   */
  private List phase2list = new ArrayList ();
  private List phase3list = new ArrayList ();
  private java.util.Hashtable phase3table = new java.util.Hashtable ();

  /**
   * The phase 1 routines generates their output into String's and dumps these
   * String's once for each method. These String's contain the special
   * characters '\u0001' to indicate a positive indent, and '\u0002' to indicate
   * a negative indent. '\n' is used to indicate a line terminator. The
   * characters '\u0003' and '\u0004' are used to delineate portions of text
   * where '\n's should not be followed by an indentation.
   */

  /**
   * Returns true if there is a JAVACODE production that the argument expansion
   * may directly expand to (without consuming tokens or encountering
   * lookahead).
   */
  private boolean javaCodeCheck (final Expansion exp)
  {
    if (exp instanceof RegularExpression)
    {
      return false;
    }
    else
      if (exp instanceof NonTerminal)
      {
        final NormalProduction prod = ((NonTerminal) exp).getProd ();
        if (prod instanceof JavaCodeProduction)
        {
          return true;
        }
        else
        {
          return javaCodeCheck (prod.getExpansion ());
        }
      }
      else
        if (exp instanceof Choice)
        {
          final Choice ch = (Choice) exp;
          for (int i = 0; i < ch.getChoices ().size (); i++)
          {
            if (javaCodeCheck ((Expansion) (ch.getChoices ().get (i))))
            {
              return true;
            }
          }
          return false;
        }
        else
          if (exp instanceof Sequence)
          {
            final Sequence seq = (Sequence) exp;
            for (int i = 0; i < seq.units.size (); i++)
            {
              final Expansion [] units = (Expansion []) seq.units.toArray (new Expansion [seq.units.size ()]);
              if (units[i] instanceof Lookahead && ((Lookahead) units[i]).isExplicit ())
              {
                // An explicit lookahead (rather than one generated implicitly).
                // Assume
                // the user knows what he / she is doing, e.g.
                // "A" ( "B" | LOOKAHEAD("X") jcode() | "C" )* "D"
                return false;
              }
              else
                if (javaCodeCheck ((units[i])))
                {
                  return true;
                }
                else
                  if (!Semanticize.emptyExpansionExists (units[i]))
                  {
                    return false;
                  }
            }
            return false;
          }
          else
            if (exp instanceof OneOrMore)
            {
              final OneOrMore om = (OneOrMore) exp;
              return javaCodeCheck (om.expansion);
            }
            else
              if (exp instanceof ZeroOrMore)
              {
                final ZeroOrMore zm = (ZeroOrMore) exp;
                return javaCodeCheck (zm.expansion);
              }
              else
                if (exp instanceof ZeroOrOne)
                {
                  final ZeroOrOne zo = (ZeroOrOne) exp;
                  return javaCodeCheck (zo.expansion);
                }
                else
                  if (exp instanceof TryBlock)
                  {
                    final TryBlock tb = (TryBlock) exp;
                    return javaCodeCheck (tb.exp);
                  }
                  else
                  {
                    return false;
                  }
  }

  /**
   * An array used to store the first sets generated by the following method. A
   * true entry means that the corresponding token is in the first set.
   */
  private boolean [] firstSet;

  /**
   * Sets up the array "firstSet" above based on the Expansion argument passed
   * to it. Since this is a recursive function, it assumes that "firstSet" has
   * been reset before the first call.
   */
  private void genFirstSet (final Expansion exp)
  {
    if (exp instanceof RegularExpression)
    {
      firstSet[((RegularExpression) exp).ordinal] = true;
    }
    else
      if (exp instanceof NonTerminal)
      {
        if (!(((NonTerminal) exp).getProd () instanceof JavaCodeProduction))
        {
          genFirstSet (((BNFProduction) (((NonTerminal) exp).getProd ())).getExpansion ());
        }
      }
      else
        if (exp instanceof Choice)
        {
          final Choice ch = (Choice) exp;
          for (int i = 0; i < ch.getChoices ().size (); i++)
          {
            genFirstSet ((Expansion) (ch.getChoices ().get (i)));
          }
        }
        else
          if (exp instanceof Sequence)
          {
            final Sequence seq = (Sequence) exp;
            final Object obj = seq.units.get (0);
            if ((obj instanceof Lookahead) && (((Lookahead) obj).getActionTokens ().size () != 0))
            {
              jj2LA = true;
            }
            for (int i = 0; i < seq.units.size (); i++)
            {
              final Expansion unit = (Expansion) seq.units.get (i);
              // Javacode productions can not have FIRST sets. Instead we
              // generate the FIRST set
              // for the preceding LOOKAHEAD (the semantic checks should have
              // made sure that
              // the LOOKAHEAD is suitable).
              if (unit instanceof NonTerminal && ((NonTerminal) unit).getProd () instanceof JavaCodeProduction)
              {
                if (i > 0 && seq.units.get (i - 1) instanceof Lookahead)
                {
                  final Lookahead la = (Lookahead) seq.units.get (i - 1);
                  genFirstSet (la.getLaExpansion ());
                }
              }
              else
              {
                genFirstSet ((Expansion) (seq.units.get (i)));
              }
              if (!Semanticize.emptyExpansionExists ((Expansion) (seq.units.get (i))))
              {
                break;
              }
            }
          }
          else
            if (exp instanceof OneOrMore)
            {
              final OneOrMore om = (OneOrMore) exp;
              genFirstSet (om.expansion);
            }
            else
              if (exp instanceof ZeroOrMore)
              {
                final ZeroOrMore zm = (ZeroOrMore) exp;
                genFirstSet (zm.expansion);
              }
              else
                if (exp instanceof ZeroOrOne)
                {
                  final ZeroOrOne zo = (ZeroOrOne) exp;
                  genFirstSet (zo.expansion);
                }
                else
                  if (exp instanceof TryBlock)
                  {
                    final TryBlock tb = (TryBlock) exp;
                    genFirstSet (tb.exp);
                  }
  }

  /**
   * Constants used in the following method "buildLookaheadChecker".
   */
  final int NOOPENSTM = 0;
  final int OPENIF = 1;
  final int OPENSWITCH = 2;

  private void dumpLookaheads (final Lookahead [] conds, final String [] actions)
  {
    for (int i = 0; i < conds.length; i++)
    {
      System.err.println ("Lookahead: " + i);
      System.err.println (conds[i].dump (0, new HashSet ()));
      System.err.println ();
    }
  }

  /**
   * This method takes two parameters - an array of Lookahead's "conds", and an
   * array of String's "actions". "actions" contains exactly one element more
   * than "conds". "actions" are Java source code, and "conds" translate to
   * conditions - so lets say "f(conds[i])" is true if the lookahead required by
   * "conds[i]" is indeed the case. This method returns a string corresponding
   * to the Java code for: if (f(conds[0]) actions[0] else if (f(conds[1])
   * actions[1] . . . else actions[action.length-1] A particular action entry
   * ("actions[i]") can be null, in which case, a noop is generated for that
   * action.
   */
  String buildLookaheadChecker (final Lookahead [] conds, final String [] actions)
  {

    // The state variables.
    int state = NOOPENSTM;
    int indentAmt = 0;
    final boolean [] casedValues = new boolean [tokenCount];
    String retval = "";
    Lookahead la;
    Token t = null;
    final int tokenMaskSize = (tokenCount - 1) / 32 + 1;
    int [] tokenMask = null;

    // Iterate over all the conditions.
    int index = 0;
    while (index < conds.length)
    {

      la = conds[index];
      jj2LA = false;

      if ((la.getAmount () == 0) ||
          Semanticize.emptyExpansionExists (la.getLaExpansion ()) ||
          javaCodeCheck (la.getLaExpansion ()))
      {

        // This handles the following cases:
        // . If syntactic lookahead is not wanted (and hence explicitly
        // specified
        // as 0).
        // . If it is possible for the lookahead expansion to recognize the
        // empty
        // string - in which case the lookahead trivially passes.
        // . If the lookahead expansion has a JAVACODE production that it
        // directly
        // expands to - in which case the lookahead trivially passes.
        if (la.getActionTokens ().size () == 0)
        {
          // In addition, if there is no semantic lookahead, then the
          // lookahead trivially succeeds. So break the main loop and
          // treat this case as the default last action.
          break;
        }
        else
        {
          // This case is when there is only semantic lookahead
          // (without any preceding syntactic lookahead). In this
          // case, an "if" statement is generated.
          switch (state)
          {
            case NOOPENSTM:
              retval += "\n" + "if (";
              indentAmt++;
              break;
            case OPENIF:
              retval += "\u0002\n" + "} else if (";
              break;
            case OPENSWITCH:
              retval += "\u0002\n" + "default:" + "\u0001";
              if (Options.getErrorReporting ())
              {
                retval += "\njj_la1[" + maskindex + "] = jj_gen;";
                maskindex++;
              }
              maskVals.add (tokenMask);
              retval += "\n" + "if (";
              indentAmt++;
          }
          codeGenerator.printTokenSetup ((Token) (la.getActionTokens ().get (0)));
          for (final Iterator it = la.getActionTokens ().iterator (); it.hasNext ();)
          {
            t = (Token) it.next ();
            retval += codeGenerator.getStringToPrint (t);
          }
          retval += codeGenerator.getTrailingComments (t);
          retval += ") {\u0001" + actions[index];
          state = OPENIF;
        }

      }
      else
        if (la.getAmount () == 1 && la.getActionTokens ().size () == 0)
        {
          // Special optimal processing when the lookahead is exactly 1, and
          // there
          // is no semantic lookahead.

          if (firstSet == null)
          {
            firstSet = new boolean [tokenCount];
          }
          for (int i = 0; i < tokenCount; i++)
          {
            firstSet[i] = false;
          }
          // jj2LA is set to false at the beginning of the containing "if"
          // statement.
          // It is checked immediately after the end of the same statement to
          // determine
          // if lookaheads are to be performed using calls to the jj2 methods.
          genFirstSet (la.getLaExpansion ());
          // genFirstSet may find that semantic attributes are appropriate for
          // the next
          // token. In which case, it sets jj2LA to true.
          if (!jj2LA)
          {

            // This case is if there is no applicable semantic lookahead and the
            // lookahead
            // is one (excluding the earlier cases such as JAVACODE, etc.).
            switch (state)
            {
              case OPENIF:
                retval += "\u0002\n" + "} else {\u0001";
                // Control flows through to next case.
              case NOOPENSTM:
                retval += "\n" + "switch (";
                if (Options.getCacheTokens ())
                {
                  retval += "jj_nt.kind) {\u0001";
                }
                else
                {
                  retval += "(jj_ntk==-1)?jj_ntk_f():jj_ntk) {\u0001";
                }
                for (int i = 0; i < tokenCount; i++)
                {
                  casedValues[i] = false;
                }
                indentAmt++;
                tokenMask = new int [tokenMaskSize];
                for (int i = 0; i < tokenMaskSize; i++)
                {
                  tokenMask[i] = 0;
                }
                // Don't need to do anything if state is OPENSWITCH.
            }
            for (int i = 0; i < tokenCount; i++)
            {
              if (firstSet[i])
              {
                if (!casedValues[i])
                {
                  casedValues[i] = true;
                  retval += "\u0002\ncase ";
                  final int j1 = i / 32;
                  final int j2 = i % 32;
                  tokenMask[j1] |= 1 << j2;
                  final String s = (String) (names_of_tokens.get (new Integer (i)));
                  if (s == null)
                  {
                    retval += i;
                  }
                  else
                  {
                    retval += s;
                  }
                  retval += ":\u0001";
                }
              }
            }
            retval += "{";
            retval += actions[index];
            retval += "\nbreak;\n}";
            state = OPENSWITCH;

          }

        }
        else
        {
          // This is the case when lookahead is determined through calls to
          // jj2 methods. The other case is when lookahead is 1, but semantic
          // attributes need to be evaluated. Hence this crazy control
          // structure.

          jj2LA = true;

        }

      if (jj2LA)
      {
        // In this case lookahead is determined by the jj2 methods.

        switch (state)
        {
          case NOOPENSTM:
            retval += "\n" + "if (";
            indentAmt++;
            break;
          case OPENIF:
            retval += "\u0002\n" + "} else if (";
            break;
          case OPENSWITCH:
            retval += "\u0002\n" + "default:" + "\u0001";
            if (Options.getErrorReporting ())
            {
              retval += "\njj_la1[" + maskindex + "] = jj_gen;";
              maskindex++;
            }
            maskVals.add (tokenMask);
            retval += "\n" + "if (";
            indentAmt++;
        }
        jj2index++;
        // At this point, la.la_expansion.internal_name must be "".
        la.getLaExpansion ().internal_name = "_" + jj2index;
        phase2list.add (la);
        retval += "jj_2" + la.getLaExpansion ().internal_name + "(" + la.getAmount () + ")";
        if (la.getActionTokens ().size () != 0)
        {
          // In addition, there is also a semantic lookahead. So concatenate
          // the semantic check with the syntactic one.
          retval += " && (";
          codeGenerator.printTokenSetup ((Token) (la.getActionTokens ().get (0)));
          for (final Iterator it = la.getActionTokens ().iterator (); it.hasNext ();)
          {
            t = (Token) it.next ();
            retval += codeGenerator.getStringToPrint (t);
          }
          retval += codeGenerator.getTrailingComments (t);
          retval += ")";
        }
        retval += ") {\u0001" + actions[index];
        state = OPENIF;
      }

      index++;
    }

    // Generate code for the default case. Note this may not
    // be the last entry of "actions" if any condition can be
    // statically determined to be always "true".

    switch (state)
    {
      case NOOPENSTM:
        retval += actions[index];
        break;
      case OPENIF:
        retval += "\u0002\n" + "} else {\u0001" + actions[index];
        break;
      case OPENSWITCH:
        retval += "\u0002\n" + "default:" + "\u0001";
        if (Options.getErrorReporting ())
        {
          retval += "\njj_la1[" + maskindex + "] = jj_gen;";
          maskVals.add (tokenMask);
          maskindex++;
        }
        retval += actions[index];
    }
    for (int i = 0; i < indentAmt; i++)
    {
      retval += "\u0002\n}";
    }

    return retval;

  }

  void dumpFormattedString (final String str)
  {
    char ch = ' ';
    char prevChar;
    boolean indentOn = true;
    for (int i = 0; i < str.length (); i++)
    {
      prevChar = ch;
      ch = str.charAt (i);
      if (ch == '\n' && prevChar == '\r')
      {
        // do nothing - we've already printed a new line for the '\r'
        // during the previous iteration.
      }
      else
        if (ch == '\n' || ch == '\r')
        {
          if (indentOn)
          {
            phase1NewLine ();
          }
          else
          {
            codeGenerator.genCodeLine ("");
          }
        }
        else
          if (ch == '\u0001')
          {
            indentamt += 2;
          }
          else
            if (ch == '\u0002')
            {
              indentamt -= 2;
            }
            else
              if (ch == '\u0003')
              {
                indentOn = false;
              }
              else
                if (ch == '\u0004')
                {
                  indentOn = true;
                }
                else
                {
                  codeGenerator.genCode (ch);
                }
    }
  }

  // Print method header and return the ERROR_RETURN string.
  private String generateCPPMethodheader (final BNFProduction p, Token t)
  {
    final StringBuffer sig = new StringBuffer ();
    String ret, params;

    final String method_name = p.getLhs ();
    boolean void_ret = false;
    boolean ptr_ret = false;

    codeGenerator.printTokenSetup (t);
    ccol = 1;
    final String comment1 = codeGenerator.getLeadingComments (t);
    cline = t.beginLine;
    ccol = t.beginColumn;
    sig.append (t.image);
    if (t.image.equals ("void"))
      void_ret = true;
    if (t.image.equals ("*"))
      ptr_ret = true;

    for (int i = 1; i < p.getReturnTypeTokens ().size (); i++)
    {
      t = (Token) (p.getReturnTypeTokens ().get (i));
      sig.append (codeGenerator.getStringToPrint (t));
      if (t.equals ("void"))
        void_ret = true;
      if (t.equals ("*"))
        ptr_ret = true;
    }

    final String comment2 = codeGenerator.getTrailingComments (t);
    ret = sig.toString ();

    sig.setLength (0);
    sig.append ("(");
    if (p.getParameterListTokens ().size () != 0)
    {
      codeGenerator.printTokenSetup ((Token) (p.getParameterListTokens ().get (0)));
      for (final java.util.Iterator it = p.getParameterListTokens ().iterator (); it.hasNext ();)
      {
        t = (Token) it.next ();
        sig.append (codeGenerator.getStringToPrint (t));
      }
      sig.append (codeGenerator.getTrailingComments (t));
    }
    sig.append (")");
    params = sig.toString ();

    // For now, just ignore comments
    codeGenerator.generateMethodDefHeader (ret, cu_name, p.getLhs () + params, sig.toString ());

    // Generate a default value for error return.
    String default_return;
    if (ptr_ret)
      default_return = "NULL";
    else
      if (void_ret)
        default_return = "";
      else
        default_return = "0"; // 0 converts to most (all?) basic types.

    final StringBuffer ret_val = new StringBuffer ("\n#if !defined ERROR_RET_" + method_name + "\n");
    ret_val.append ("#define ERROR_RET_" + method_name + " " + default_return + "\n");
    ret_val.append ("#endif\n");
    ret_val.append ("#define __ERROR_RET__ ERROR_RET_" + method_name + "\n");

    return ret_val.toString ();
  }

  void buildPhase1Routine (final BNFProduction p)
  {
    Token t;
    t = (Token) (p.getReturnTypeTokens ().get (0));
    boolean voidReturn = false;
    if (t.kind == JavaCCParserConstants.VOID)
    {
      voidReturn = true;
    }
    String error_ret = null;
    if (isJavaDialect)
    {
      codeGenerator.printTokenSetup (t);
      ccol = 1;
      codeGenerator.printLeadingComments (t);
      codeGenerator.genCode ("  " +
                             staticOpt () +
                             "final " +
                             (p.getAccessMod () != null ? p.getAccessMod () : "public") +
                             " ");
      cline = t.beginLine;
      ccol = t.beginColumn;
      codeGenerator.printTokenOnly (t);
      for (int i = 1; i < p.getReturnTypeTokens ().size (); i++)
      {
        t = (Token) (p.getReturnTypeTokens ().get (i));
        codeGenerator.printToken (t);
      }
      codeGenerator.printTrailingComments (t);
      codeGenerator.genCode (" " + p.getLhs () + "(");
      if (p.getParameterListTokens ().size () != 0)
      {
        codeGenerator.printTokenSetup ((Token) (p.getParameterListTokens ().get (0)));
        for (final java.util.Iterator it = p.getParameterListTokens ().iterator (); it.hasNext ();)
        {
          t = (Token) it.next ();
          codeGenerator.printToken (t);
        }
        codeGenerator.printTrailingComments (t);
      }
      codeGenerator.genCode (")");
      if (isJavaDialect)
      {
        codeGenerator.genCode (" throws ParseException");
      }

      for (final java.util.Iterator it = p.getThrowsList ().iterator (); it.hasNext ();)
      {
        codeGenerator.genCode (", ");
        final java.util.List name = (java.util.List) it.next ();
        for (final java.util.Iterator it2 = name.iterator (); it2.hasNext ();)
        {
          t = (Token) it2.next ();
          codeGenerator.genCode (t.image);
        }
      }
    }
    else
    {
      error_ret = generateCPPMethodheader (p, t);
    }

    codeGenerator.genCode (" {");

    if (Options.booleanValue (Options.USEROPTION__CPP_STOP_ON_FIRST_ERROR) && error_ret != null)
    {
      codeGenerator.genCode (error_ret);
    }

    indentamt = 4;
    if (Options.getDebugParser ())
    {
      codeGenerator.genCodeLine ("");
      codeGenerator.genCodeLine ("    trace_call(\"" + JavaCCGlobals.addUnicodeEscapes (p.getLhs ()) + "\");");
      codeGenerator.genCode ("    try {");
      indentamt = 6;
    }
    if (!Options.booleanValue (Options.USEROPTION__CPP_IGNORE_ACTIONS) && p.getDeclarationTokens ().size () != 0)
    {
      codeGenerator.printTokenSetup ((Token) (p.getDeclarationTokens ().get (0)));
      cline--;
      for (final Iterator it = p.getDeclarationTokens ().iterator (); it.hasNext ();)
      {
        t = (Token) it.next ();
        codeGenerator.printToken (t);
      }
      codeGenerator.printTrailingComments (t);
    }
    final String code = phase1ExpansionGen (p.getExpansion ());
    dumpFormattedString (code);
    codeGenerator.genCodeLine ("");
    if (p.isJumpPatched () && !voidReturn)
    {
      if (isJavaDialect)
      {
        // TODO :: I don't think we need to throw an Error/Exception to mark
        // that a return statement is missing as the compiler will flag this
        // error automatically

        // [ph] commented, because of all the "if (true)" the compiler gets
        // confused and requires some form of terminating exception :(
        // if (Options.isLegacyExceptionHandling ())
        {
          codeGenerator.genCodeLine ("    throw new " +
                                     (Options.isLegacyExceptionHandling () ? "Error" : "RuntimeException") +
                                     "(\"Missing return statement in function\");");
        }
      }
      else
      {
        codeGenerator.genCodeLine ("    throw \"Missing return statement in function\";");
      }
    }
    if (Options.getDebugParser ())
    {
      if (isJavaDialect)
      {
        codeGenerator.genCodeLine ("    } finally {");
      }
      else
      {
        codeGenerator.genCodeLine ("    } catch(...) { }");
      }
      codeGenerator.genCodeLine ("      trace_return(\"" + JavaCCGlobals.addUnicodeEscapes (p.getLhs ()) + "\");");
      if (isJavaDialect)
      {
        codeGenerator.genCodeLine ("    }");
      }
    }
    if (!isJavaDialect && !voidReturn)
    {
      codeGenerator.genCodeLine ("assert(false);");
    }

    if (Options.booleanValue (Options.USEROPTION__CPP_STOP_ON_FIRST_ERROR))
    {
      codeGenerator.genCodeLine ("\n#undef __ERROR_RET__\n");
    }
    codeGenerator.genCodeLine ("  }");
    codeGenerator.genCodeLine ("");
  }

  void phase1NewLine ()
  {
    codeGenerator.genCodeLine ("");
    for (int i = 0; i < indentamt; i++)
    {
      codeGenerator.genCode (" ");
    }
  }

  String phase1ExpansionGen (final Expansion e)
  {
    String retval = "";
    Token t = null;
    Lookahead [] conds;
    String [] actions;
    if (e instanceof RegularExpression)
    {
      final RegularExpression e_nrw = (RegularExpression) e;
      retval += "\n";
      if (e_nrw.lhsTokens.size () != 0)
      {
        codeGenerator.printTokenSetup ((Token) (e_nrw.lhsTokens.get (0)));
        for (final java.util.Iterator it = e_nrw.lhsTokens.iterator (); it.hasNext ();)
        {
          t = (Token) it.next ();
          retval += codeGenerator.getStringToPrint (t);
        }
        retval += codeGenerator.getTrailingComments (t);
        retval += " = ";
      }
      final String tail = e_nrw.rhsToken == null ? ");" : (isJavaDialect ? ")." : ")->") + e_nrw.rhsToken.image + ";";
      if (e_nrw.label.equals (""))
      {
        final Object label = names_of_tokens.get (new Integer (e_nrw.ordinal));
        if (label != null)
        {
          retval += "jj_consume_token(" + (String) label + tail;
        }
        else
        {
          retval += "jj_consume_token(" + e_nrw.ordinal + tail;
        }
      }
      else
      {
        retval += "jj_consume_token(" + e_nrw.label + tail;
      }

      if (!isJavaDialect && Options.booleanValue (Options.USEROPTION__CPP_STOP_ON_FIRST_ERROR))
      {
        retval += "\n    { if (hasError) { return __ERROR_RET__; } }\n";
      }

    }
    else
      if (e instanceof NonTerminal)
      {
        final NonTerminal e_nrw = (NonTerminal) e;
        retval += "\n";
        if (e_nrw.getLhsTokens ().size () != 0)
        {
          codeGenerator.printTokenSetup ((Token) (e_nrw.getLhsTokens ().get (0)));
          for (final java.util.Iterator it = e_nrw.getLhsTokens ().iterator (); it.hasNext ();)
          {
            t = (Token) it.next ();
            retval += codeGenerator.getStringToPrint (t);
          }
          retval += codeGenerator.getTrailingComments (t);
          retval += " = ";
        }
        retval += e_nrw.getName () + "(";
        if (e_nrw.getArgumentTokens ().size () != 0)
        {
          codeGenerator.printTokenSetup ((Token) (e_nrw.getArgumentTokens ().get (0)));
          for (final java.util.Iterator it = e_nrw.getArgumentTokens ().iterator (); it.hasNext ();)
          {
            t = (Token) it.next ();
            retval += codeGenerator.getStringToPrint (t);
          }
          retval += codeGenerator.getTrailingComments (t);
        }
        retval += ");";
        if (!isJavaDialect && Options.booleanValue (Options.USEROPTION__CPP_STOP_ON_FIRST_ERROR))
        {
          retval += "\n    { if (hasError) { return __ERROR_RET__; } }\n";
        }
      }
      else
        if (e instanceof Action)
        {
          final Action e_nrw = (Action) e;
          retval += "\u0003\n";
          if (!Options.booleanValue (Options.USEROPTION__CPP_IGNORE_ACTIONS) && e_nrw.getActionTokens ().size () != 0)
          {
            codeGenerator.printTokenSetup ((Token) (e_nrw.getActionTokens ().get (0)));
            ccol = 1;
            for (final Iterator it = e_nrw.getActionTokens ().iterator (); it.hasNext ();)
            {
              t = (Token) it.next ();
              retval += codeGenerator.getStringToPrint (t);
            }
            retval += codeGenerator.getTrailingComments (t);
          }
          retval += "\u0004";
        }
        else
          if (e instanceof Choice)
          {
            final Choice e_nrw = (Choice) e;
            conds = new Lookahead [e_nrw.getChoices ().size ()];
            actions = new String [e_nrw.getChoices ().size () + 1];
            actions[e_nrw.getChoices ()
                         .size ()] = "\n" +
                                     "jj_consume_token(-1);\n" +
                                     (isJavaDialect ? "throw new ParseException();"
                                                    : ("errorHandler->handleParseError(token, getToken(1), __FUNCTION__, this), hasError = true;" +
                                                       (Options.booleanValue (Options.USEROPTION__CPP_STOP_ON_FIRST_ERROR) ? "return __ERROR_RET__;\n"
                                                                                                                           : "")));

            // In previous line, the "throw" never throws an exception since the
            // evaluation of jj_consume_token(-1) causes ParseException to be
            // thrown first.
            Sequence nestedSeq;
            for (int i = 0; i < e_nrw.getChoices ().size (); i++)
            {
              nestedSeq = (Sequence) (e_nrw.getChoices ().get (i));
              actions[i] = phase1ExpansionGen (nestedSeq);
              conds[i] = (Lookahead) (nestedSeq.units.get (0));
            }
            retval = buildLookaheadChecker (conds, actions);
          }
          else
            if (e instanceof Sequence)
            {
              final Sequence e_nrw = (Sequence) e;
              // We skip the first element in the following iteration since it
              // is the
              // Lookahead object.
              for (int i = 1; i < e_nrw.units.size (); i++)
              {
                // For C++, since we are not using exceptions, we will protect
                // all the
                // expansion choices with if (!error)
                boolean wrap_in_block = false;
                if (!JavaCCGlobals.jjtreeGenerated && !isJavaDialect)
                {
                  // for the last one, if it's an action, we will not protect
                  // it.
                  final Expansion elem = (Expansion) e_nrw.units.get (i);
                  if (!(elem instanceof Action) || !(e.parent instanceof BNFProduction) || i != e_nrw.units.size () - 1)
                  {
                    wrap_in_block = true;
                    retval += "if (" + (isJavaDialect ? "true" : "!hasError") + ") {\n";
                  }
                }
                retval += phase1ExpansionGen ((Expansion) (e_nrw.units.get (i)));
                if (wrap_in_block)
                {
                  retval += "\n}\n";
                }
              }
            }
            else
              if (e instanceof OneOrMore)
              {
                final OneOrMore e_nrw = (OneOrMore) e;
                final Expansion nested_e = e_nrw.expansion;
                Lookahead la;
                if (nested_e instanceof Sequence)
                {
                  la = (Lookahead) (((Sequence) nested_e).units.get (0));
                }
                else
                {
                  la = new Lookahead ();
                  la.setAmount (Options.getLookahead ());
                  la.setLaExpansion (nested_e);
                }
                retval += "\n";
                final int labelIndex = ++gensymindex;
                if (isJavaDialect)
                {
                  retval += "label_" + labelIndex + ":\n";
                }
                retval += "while (" + (isJavaDialect ? "true" : "!hasError") + ") {\u0001";
                retval += phase1ExpansionGen (nested_e);
                conds = new Lookahead [1];
                conds[0] = la;
                actions = new String [2];
                actions[0] = "\n;";

                if (isJavaDialect)
                {
                  actions[1] = "\nbreak label_" + labelIndex + ";";
                }
                else
                {
                  actions[1] = "\ngoto end_label_" + labelIndex + ";";
                }

                retval += buildLookaheadChecker (conds, actions);
                retval += "\u0002\n" + "}";
                if (!isJavaDialect)
                {
                  retval += "\nend_label_" + labelIndex + ": ;";
                }
              }
              else
                if (e instanceof ZeroOrMore)
                {
                  final ZeroOrMore e_nrw = (ZeroOrMore) e;
                  final Expansion nested_e = e_nrw.expansion;
                  Lookahead la;
                  if (nested_e instanceof Sequence)
                  {
                    la = (Lookahead) (((Sequence) nested_e).units.get (0));
                  }
                  else
                  {
                    la = new Lookahead ();
                    la.setAmount (Options.getLookahead ());
                    la.setLaExpansion (nested_e);
                  }
                  retval += "\n";
                  final int labelIndex = ++gensymindex;
                  if (isJavaDialect)
                  {
                    retval += "label_" + labelIndex + ":\n";
                  }
                  retval += "while (" + (isJavaDialect ? "true" : "!hasError") + ") {\u0001";
                  conds = new Lookahead [1];
                  conds[0] = la;
                  actions = new String [2];
                  actions[0] = "\n;";
                  if (isJavaDialect)
                  {
                    actions[1] = "\nbreak label_" + labelIndex + ";";
                  }
                  else
                  {
                    actions[1] = "\ngoto end_label_" + labelIndex + ";";
                  }
                  retval += buildLookaheadChecker (conds, actions);
                  retval += phase1ExpansionGen (nested_e);
                  retval += "\u0002\n" + "}";
                  if (!isJavaDialect)
                  {
                    retval += "\nend_label_" + labelIndex + ": ;";
                  }
                }
                else
                  if (e instanceof ZeroOrOne)
                  {
                    final ZeroOrOne e_nrw = (ZeroOrOne) e;
                    final Expansion nested_e = e_nrw.expansion;
                    Lookahead la;
                    if (nested_e instanceof Sequence)
                    {
                      la = (Lookahead) (((Sequence) nested_e).units.get (0));
                    }
                    else
                    {
                      la = new Lookahead ();
                      la.setAmount (Options.getLookahead ());
                      la.setLaExpansion (nested_e);
                    }
                    conds = new Lookahead [1];
                    conds[0] = la;
                    actions = new String [2];
                    actions[0] = phase1ExpansionGen (nested_e);
                    actions[1] = "\n;";
                    retval += buildLookaheadChecker (conds, actions);
                  }
                  else
                    if (e instanceof TryBlock)
                    {
                      final TryBlock e_nrw = (TryBlock) e;
                      final Expansion nested_e = e_nrw.exp;
                      java.util.List list;
                      retval += "\n";
                      retval += "try {\u0001";
                      retval += phase1ExpansionGen (nested_e);
                      retval += "\u0002\n" + "}";
                      for (int i = 0; i < e_nrw.catchblks.size (); i++)
                      {
                        retval += " catch (";
                        list = (java.util.List) (e_nrw.types.get (i));
                        if (list.size () != 0)
                        {
                          codeGenerator.printTokenSetup ((Token) (list.get (0)));
                          for (final java.util.Iterator it = list.iterator (); it.hasNext ();)
                          {
                            t = (Token) it.next ();
                            retval += codeGenerator.getStringToPrint (t);
                          }
                          retval += codeGenerator.getTrailingComments (t);
                        }
                        retval += " ";
                        t = (Token) (e_nrw.ids.get (i));
                        codeGenerator.printTokenSetup (t);
                        retval += codeGenerator.getStringToPrint (t);
                        retval += codeGenerator.getTrailingComments (t);
                        retval += ") {\u0003\n";
                        list = (java.util.List) (e_nrw.catchblks.get (i));
                        if (list.size () != 0)
                        {
                          codeGenerator.printTokenSetup ((Token) (list.get (0)));
                          ccol = 1;
                          for (final java.util.Iterator it = list.iterator (); it.hasNext ();)
                          {
                            t = (Token) it.next ();
                            retval += codeGenerator.getStringToPrint (t);
                          }
                          retval += codeGenerator.getTrailingComments (t);
                        }
                        retval += "\u0004\n" + "}";
                      }
                      if (e_nrw.finallyblk != null)
                      {
                        if (isJavaDialect)
                        {
                          retval += " finally {\u0003\n";
                        }
                        else
                        {
                          retval += " finally {\u0003\n";
                        }

                        if (e_nrw.finallyblk.size () != 0)
                        {
                          codeGenerator.printTokenSetup ((Token) (e_nrw.finallyblk.get (0)));
                          ccol = 1;
                          for (final java.util.Iterator it = e_nrw.finallyblk.iterator (); it.hasNext ();)
                          {
                            t = (Token) it.next ();
                            retval += codeGenerator.getStringToPrint (t);
                          }
                          retval += codeGenerator.getTrailingComments (t);
                        }
                        retval += "\u0004\n" + "}";
                      }
                    }
    return retval;
  }

  void buildPhase2Routine (final Lookahead la)
  {
    final Expansion e = la.getLaExpansion ();
    if (isJavaDialect)
    {
      codeGenerator.genCodeLine ("  " +
                                 staticOpt () +
                                 "private " +
                                 Options.getBooleanType () +
                                 " jj_2" +
                                 e.internal_name +
                                 "(int xla)");
    }
    else
    {
      codeGenerator.genCodeLine (" inline bool ", "jj_2" + e.internal_name + "(int xla)");
    }
    codeGenerator.genCodeLine (" {");
    codeGenerator.genCodeLine ("    jj_la = xla; jj_lastpos = jj_scanpos = token;");
    if (isJavaDialect)
    {
      codeGenerator.genCodeLine ("    try { return !jj_3" + e.internal_name + "(); }");
      codeGenerator.genCodeLine ("    catch(LookaheadSuccess ls) { return true; }");
    }
    else
    {
      codeGenerator.genCodeLine ("    jj_done = false;");
      codeGenerator.genCodeLine ("    return !jj_3" + e.internal_name + "() || jj_done;");
      // codeGenerator.genCodeLine(" catch(LookaheadSuccess ls) { return true;
      // }");
    }
    if (Options.getErrorReporting ())
    {
      codeGenerator.genCodeLine ((isJavaDialect ? "    finally " : " ") +
                                 "{ jj_save(" +
                                 (Integer.parseInt (e.internal_name.substring (1)) - 1) +
                                 ", xla); }");
    }
    codeGenerator.genCodeLine ("  }");
    codeGenerator.genCodeLine ("");
    final Phase3Data p3d = new Phase3Data (e, la.getAmount ());
    phase3list.add (p3d);
    phase3table.put (e, p3d);
  }

  private boolean xsp_declared;

  Expansion jj3_expansion;

  String genReturn (final boolean value)
  {
    final String retval = (value ? "true" : "false");
    if (Options.getDebugLookahead () && jj3_expansion != null)
    {
      String tracecode = "trace_return(\"" +
                         JavaCCGlobals.addUnicodeEscapes (((NormalProduction) jj3_expansion.parent).getLhs ()) +
                         "(LOOKAHEAD " +
                         (value ? "FAILED" : "SUCCEEDED") +
                         ")\");";
      if (Options.getErrorReporting ())
      {
        tracecode = "if (!jj_rescan) " + tracecode;
      }
      return "{ " + tracecode + " return " + retval + "; }";
    }
    else
    {
      return "return " + retval + ";";
    }
  }

  private void generate3R (final Expansion e, final Phase3Data inf)
  {
    Expansion seq = e;
    if (e.internal_name.equals (""))
    {
      while (true)
      {
        if (seq instanceof Sequence && ((Sequence) seq).units.size () == 2)
        {
          seq = (Expansion) ((Sequence) seq).units.get (1);
        }
        else
          if (seq instanceof NonTerminal)
          {
            final NonTerminal e_nrw = (NonTerminal) seq;
            final NormalProduction ntprod = (NormalProduction) (production_table.get (e_nrw.getName ()));
            if (ntprod instanceof JavaCodeProduction)
            {
              break; // nothing to do here
            }
            else
            {
              seq = ntprod.getExpansion ();
            }
          }
          else
            break;
      }

      if (seq instanceof RegularExpression)
      {
        e.internal_name = "jj_scan_token(" + ((RegularExpression) seq).ordinal + ")";
        return;
      }

      gensymindex++;
      // if (gensymindex == 100)
      // {
      // new Error().codeGenerator.printStackTrace();
      // System.out.println(" ***** seq: " + seq.internal_name + "; size: " +
      // ((Sequence)seq).units.size());
      // }
      e.internal_name = "R_" + gensymindex;
    }
    Phase3Data p3d = (Phase3Data) (phase3table.get (e));
    if (p3d == null || p3d.count < inf.count)
    {
      p3d = new Phase3Data (e, inf.count);
      phase3list.add (p3d);
      phase3table.put (e, p3d);
    }
  }

  void setupPhase3Builds (final Phase3Data inf)
  {
    final Expansion e = inf.exp;
    if (e instanceof RegularExpression)
    {
      ; // nothing to here
    }
    else
      if (e instanceof NonTerminal)
      {
        // All expansions of non-terminals have the "name" fields set. So
        // there's no need to check it below for "e_nrw" and "ntexp". In
        // fact, we rely here on the fact that the "name" fields of both these
        // variables are the same.
        final NonTerminal e_nrw = (NonTerminal) e;
        final NormalProduction ntprod = (NormalProduction) (production_table.get (e_nrw.getName ()));
        if (ntprod instanceof JavaCodeProduction)
        {
          ; // nothing to do here
        }
        else
        {
          generate3R (ntprod.getExpansion (), inf);
        }
      }
      else
        if (e instanceof Choice)
        {
          final Choice e_nrw = (Choice) e;
          for (int i = 0; i < e_nrw.getChoices ().size (); i++)
          {
            generate3R ((Expansion) (e_nrw.getChoices ().get (i)), inf);
          }
        }
        else
          if (e instanceof Sequence)
          {
            final Sequence e_nrw = (Sequence) e;
            // We skip the first element in the following iteration since it is
            // the
            // Lookahead object.
            int cnt = inf.count;
            for (int i = 1; i < e_nrw.units.size (); i++)
            {
              final Expansion eseq = (Expansion) (e_nrw.units.get (i));
              setupPhase3Builds (new Phase3Data (eseq, cnt));
              cnt -= minimumSize (eseq);
              if (cnt <= 0)
                break;
            }
          }
          else
            if (e instanceof TryBlock)
            {
              final TryBlock e_nrw = (TryBlock) e;
              setupPhase3Builds (new Phase3Data (e_nrw.exp, inf.count));
            }
            else
              if (e instanceof OneOrMore)
              {
                final OneOrMore e_nrw = (OneOrMore) e;
                generate3R (e_nrw.expansion, inf);
              }
              else
                if (e instanceof ZeroOrMore)
                {
                  final ZeroOrMore e_nrw = (ZeroOrMore) e;
                  generate3R (e_nrw.expansion, inf);
                }
                else
                  if (e instanceof ZeroOrOne)
                  {
                    final ZeroOrOne e_nrw = (ZeroOrOne) e;
                    generate3R (e_nrw.expansion, inf);
                  }
  }

  private String getTypeForToken ()
  {
    return isJavaDialect ? "Token" : "Token *";
  }

  private String genjj_3Call (final Expansion e)
  {
    if (e.internal_name.startsWith ("jj_scan_token"))
      return e.internal_name;
    else
      return "jj_3" + e.internal_name + "()";
  }

  Hashtable generated = new Hashtable ();

  void buildPhase3Routine (final Phase3Data inf, final boolean recursive_call)
  {
    final Expansion e = inf.exp;
    Token t = null;
    if (e.internal_name.startsWith ("jj_scan_token"))
      return;

    if (!recursive_call)
    {
      if (isJavaDialect)
      {
        codeGenerator.genCodeLine ("  " +
                                   staticOpt () +
                                   "private " +
                                   Options.getBooleanType () +
                                   " jj_3" +
                                   e.internal_name +
                                   "()");
      }
      else
      {
        codeGenerator.genCodeLine (" inline bool ", "jj_3" + e.internal_name + "()");
      }

      codeGenerator.genCodeLine (" {");
      if (!isJavaDialect)
      {
        codeGenerator.genCodeLine ("    if (jj_done) return true;");
      }
      xsp_declared = false;
      if (Options.getDebugLookahead () && e.parent instanceof NormalProduction)
      {
        codeGenerator.genCode ("    ");
        if (Options.getErrorReporting ())
        {
          codeGenerator.genCode ("if (!jj_rescan) ");
        }
        codeGenerator.genCodeLine ("trace_call(\"" +
                                   JavaCCGlobals.addUnicodeEscapes (((NormalProduction) e.parent).getLhs ()) +
                                   "(LOOKING AHEAD...)\");");
        jj3_expansion = e;
      }
      else
      {
        jj3_expansion = null;
      }
    }
    if (e instanceof RegularExpression)
    {
      final RegularExpression e_nrw = (RegularExpression) e;
      if (e_nrw.label.equals (""))
      {
        final Object label = names_of_tokens.get (new Integer (e_nrw.ordinal));
        if (label != null)
        {
          codeGenerator.genCodeLine ("    if (jj_scan_token(" + (String) label + ")) " + genReturn (true));
        }
        else
        {
          codeGenerator.genCodeLine ("    if (jj_scan_token(" + e_nrw.ordinal + ")) " + genReturn (true));
        }
      }
      else
      {
        codeGenerator.genCodeLine ("    if (jj_scan_token(" + e_nrw.label + ")) " + genReturn (true));
      }
      // codeGenerator.genCodeLine(" if (jj_la == 0 && jj_scanpos == jj_lastpos)
      // "
      // + genReturn(false));
    }
    else
      if (e instanceof NonTerminal)
      {
        // All expansions of non-terminals have the "name" fields set. So
        // there's no need to check it below for "e_nrw" and "ntexp". In
        // fact, we rely here on the fact that the "name" fields of both these
        // variables are the same.
        final NonTerminal e_nrw = (NonTerminal) e;
        final NormalProduction ntprod = (NormalProduction) (production_table.get (e_nrw.getName ()));
        if (ntprod instanceof JavaCodeProduction)
        {
          codeGenerator.genCodeLine ("    if (true) { jj_la = 0; jj_scanpos = jj_lastpos; " + genReturn (false) + "}");
        }
        else
        {
          final Expansion ntexp = ntprod.getExpansion ();
          // codeGenerator.genCodeLine(" if (jj_3" + ntexp.internal_name +
          // "()) " + genReturn(true));
          codeGenerator.genCodeLine ("    if (" + genjj_3Call (ntexp) + ") " + genReturn (true));
          // codeGenerator.genCodeLine(" if (jj_la == 0 && jj_scanpos ==
          // jj_lastpos) "
          // + genReturn(false));
        }
      }
      else
        if (e instanceof Choice)
        {
          Sequence nested_seq;
          final Choice e_nrw = (Choice) e;
          if (e_nrw.getChoices ().size () != 1)
          {
            if (!xsp_declared)
            {
              xsp_declared = true;
              codeGenerator.genCodeLine ("    " + getTypeForToken () + " xsp;");
            }
            codeGenerator.genCodeLine ("    xsp = jj_scanpos;");
          }
          for (int i = 0; i < e_nrw.getChoices ().size (); i++)
          {
            nested_seq = (Sequence) (e_nrw.getChoices ().get (i));
            final Lookahead la = (Lookahead) (nested_seq.units.get (0));
            if (la.getActionTokens ().size () != 0)
            {
              // We have semantic lookahead that must be evaluated.
              lookaheadNeeded = true;
              codeGenerator.genCodeLine ("    jj_lookingAhead = true;");
              codeGenerator.genCode ("    jj_semLA = ");
              codeGenerator.printTokenSetup ((Token) (la.getActionTokens ().get (0)));
              for (final Iterator it = la.getActionTokens ().iterator (); it.hasNext ();)
              {
                t = (Token) it.next ();
                codeGenerator.printToken (t);
              }
              codeGenerator.printTrailingComments (t);
              codeGenerator.genCodeLine (";");
              codeGenerator.genCodeLine ("    jj_lookingAhead = false;");
            }
            codeGenerator.genCode ("    if (");
            if (la.getActionTokens ().size () != 0)
            {
              codeGenerator.genCode ("!jj_semLA || ");
            }
            if (i != e_nrw.getChoices ().size () - 1)
            {
              // codeGenerator.genCodeLine("jj_3" + nested_seq.internal_name +
              // "()) {");
              codeGenerator.genCodeLine (genjj_3Call (nested_seq) + ") {");
              codeGenerator.genCodeLine ("    jj_scanpos = xsp;");
            }
            else
            {
              // codeGenerator.genCodeLine("jj_3" + nested_seq.internal_name +
              // "()) " + genReturn(true));
              codeGenerator.genCodeLine (genjj_3Call (nested_seq) + ") " + genReturn (true));
              // codeGenerator.genCodeLine(" if (jj_la == 0 && jj_scanpos ==
              // jj_lastpos) "
              // + genReturn(false));
            }
          }
          for (int i = 1; i < e_nrw.getChoices ().size (); i++)
          {
            // codeGenerator.genCodeLine(" } else if (jj_la == 0 && jj_scanpos
            // == jj_lastpos) "
            // + genReturn(false));
            codeGenerator.genCodeLine ("    }");
          }
        }
        else
          if (e instanceof Sequence)
          {
            final Sequence e_nrw = (Sequence) e;
            // We skip the first element in the following iteration since it is
            // the
            // Lookahead object.
            int cnt = inf.count;
            for (int i = 1; i < e_nrw.units.size (); i++)
            {
              final Expansion eseq = (Expansion) (e_nrw.units.get (i));
              buildPhase3Routine (new Phase3Data (eseq, cnt), true);

              // System.out.println("minimumSize: line: " + eseq.line +
              // ", column: " + eseq.column + ": " +
              // minimumSize(eseq));//Test Code

              cnt -= minimumSize (eseq);
              if (cnt <= 0)
                break;
            }
          }
          else
            if (e instanceof TryBlock)
            {
              final TryBlock e_nrw = (TryBlock) e;
              buildPhase3Routine (new Phase3Data (e_nrw.exp, inf.count), true);
            }
            else
              if (e instanceof OneOrMore)
              {
                if (!xsp_declared)
                {
                  xsp_declared = true;
                  codeGenerator.genCodeLine ("    " + getTypeForToken () + " xsp;");
                }
                final OneOrMore e_nrw = (OneOrMore) e;
                final Expansion nested_e = e_nrw.expansion;
                // codeGenerator.genCodeLine(" if (jj_3" +
                // nested_e.internal_name + "()) " + genReturn(true));
                codeGenerator.genCodeLine ("    if (" + genjj_3Call (nested_e) + ") " + genReturn (true));
                // codeGenerator.genCodeLine(" if (jj_la == 0 && jj_scanpos ==
                // jj_lastpos) "
                // + genReturn(false));
                codeGenerator.genCodeLine ("    while (true) {");
                codeGenerator.genCodeLine ("      xsp = jj_scanpos;");
                // codeGenerator.genCodeLine(" if (jj_3" +
                // nested_e.internal_name + "()) { jj_scanpos = xsp; break; }");
                codeGenerator.genCodeLine ("      if (" + genjj_3Call (nested_e) + ") { jj_scanpos = xsp; break; }");
                // codeGenerator.genCodeLine(" if (jj_la == 0 && jj_scanpos ==
                // jj_lastpos) "
                // + genReturn(false));
                codeGenerator.genCodeLine ("    }");
              }
              else
                if (e instanceof ZeroOrMore)
                {
                  if (!xsp_declared)
                  {
                    xsp_declared = true;
                    codeGenerator.genCodeLine ("    " + getTypeForToken () + " xsp;");
                  }
                  final ZeroOrMore e_nrw = (ZeroOrMore) e;
                  final Expansion nested_e = e_nrw.expansion;
                  codeGenerator.genCodeLine ("    while (true) {");
                  codeGenerator.genCodeLine ("      xsp = jj_scanpos;");
                  // codeGenerator.genCodeLine(" if (jj_3" +
                  // nested_e.internal_name +
                  // "()) { jj_scanpos = xsp; break; }");
                  codeGenerator.genCodeLine ("      if (" + genjj_3Call (nested_e) + ") { jj_scanpos = xsp; break; }");
                  // codeGenerator.genCodeLine(" if (jj_la == 0 && jj_scanpos ==
                  // jj_lastpos) "
                  // + genReturn(false));
                  codeGenerator.genCodeLine ("    }");
                }
                else
                  if (e instanceof ZeroOrOne)
                  {
                    if (!xsp_declared)
                    {
                      xsp_declared = true;
                      codeGenerator.genCodeLine ("    " + getTypeForToken () + " xsp;");
                    }
                    final ZeroOrOne e_nrw = (ZeroOrOne) e;
                    final Expansion nested_e = e_nrw.expansion;
                    codeGenerator.genCodeLine ("    xsp = jj_scanpos;");
                    // codeGenerator.genCodeLine(" if (jj_3" +
                    // nested_e.internal_name + "()) jj_scanpos = xsp;");
                    codeGenerator.genCodeLine ("    if (" + genjj_3Call (nested_e) + ") jj_scanpos = xsp;");
                    // codeGenerator.genCodeLine(" else if (jj_la == 0 &&
                    // jj_scanpos == jj_lastpos) "
                    // + genReturn(false));
                  }
    if (!recursive_call)
    {
      codeGenerator.genCodeLine ("    " + genReturn (false));
      codeGenerator.genCodeLine ("  }");
      codeGenerator.genCodeLine ("");
    }
  }

  int minimumSize (final Expansion e)
  {
    return minimumSize (e, Integer.MAX_VALUE);
  }

  /*
   * Returns the minimum number of tokens that can parse to this expansion.
   */
  int minimumSize (final Expansion e, final int oldMin)
  {
    int retval = 0; // should never be used. Will be bad if it is.
    if (e.inMinimumSize)
    {
      // recursive search for minimum size unnecessary.
      return Integer.MAX_VALUE;
    }
    e.inMinimumSize = true;
    if (e instanceof RegularExpression)
    {
      retval = 1;
    }
    else
      if (e instanceof NonTerminal)
      {
        final NonTerminal e_nrw = (NonTerminal) e;
        final NormalProduction ntprod = (NormalProduction) (production_table.get (e_nrw.getName ()));
        if (ntprod instanceof JavaCodeProduction)
        {
          retval = Integer.MAX_VALUE;
          // Make caller think this is unending (for we do not go beyond
          // JAVACODE during
          // phase3 execution).
        }
        else
        {
          final Expansion ntexp = ntprod.getExpansion ();
          retval = minimumSize (ntexp);
        }
      }
      else
        if (e instanceof Choice)
        {
          int min = oldMin;
          Expansion nested_e;
          final Choice e_nrw = (Choice) e;
          for (int i = 0; min > 1 && i < e_nrw.getChoices ().size (); i++)
          {
            nested_e = (Expansion) (e_nrw.getChoices ().get (i));
            final int min1 = minimumSize (nested_e, min);
            if (min > min1)
              min = min1;
          }
          retval = min;
        }
        else
          if (e instanceof Sequence)
          {
            int min = 0;
            final Sequence e_nrw = (Sequence) e;
            // We skip the first element in the following iteration since it is
            // the
            // Lookahead object.
            for (int i = 1; i < e_nrw.units.size (); i++)
            {
              final Expansion eseq = (Expansion) (e_nrw.units.get (i));
              final int mineseq = minimumSize (eseq);
              if (min == Integer.MAX_VALUE || mineseq == Integer.MAX_VALUE)
              {
                min = Integer.MAX_VALUE; // Adding infinity to something results
                                         // in infinity.
              }
              else
              {
                min += mineseq;
                if (min > oldMin)
                  break;
              }
            }
            retval = min;
          }
          else
            if (e instanceof TryBlock)
            {
              final TryBlock e_nrw = (TryBlock) e;
              retval = minimumSize (e_nrw.exp);
            }
            else
              if (e instanceof OneOrMore)
              {
                final OneOrMore e_nrw = (OneOrMore) e;
                retval = minimumSize (e_nrw.expansion);
              }
              else
                if (e instanceof ZeroOrMore)
                {
                  retval = 0;
                }
                else
                  if (e instanceof ZeroOrOne)
                  {
                    retval = 0;
                  }
                  else
                    if (e instanceof Lookahead)
                    {
                      retval = 0;
                    }
                    else
                      if (e instanceof Action)
                      {
                        retval = 0;
                      }
    e.inMinimumSize = false;
    return retval;
  }

  void build (final CodeGenerator codeGenerator)
  {
    NormalProduction p;
    JavaCodeProduction jp;
    Token t = null;

    this.codeGenerator = codeGenerator;
    for (final java.util.Iterator prodIterator = bnfproductions.iterator (); prodIterator.hasNext ();)
    {
      p = (NormalProduction) prodIterator.next ();
      if (p instanceof JavaCodeProduction)
      {
        if (!isJavaDialect)
        {
          JavaCCErrors.semantic_error ("Cannot use JAVACODE productions with C++ output (yet).");
          continue;
        }
        jp = (JavaCodeProduction) p;
        t = (Token) (jp.getReturnTypeTokens ().get (0));
        codeGenerator.printTokenSetup (t);
        ccol = 1;
        codeGenerator.printLeadingComments (t);
        codeGenerator.genCode ("  " + staticOpt () + (p.getAccessMod () != null ? p.getAccessMod () + " " : ""));
        cline = t.beginLine;
        ccol = t.beginColumn;
        codeGenerator.printTokenOnly (t);
        for (int i = 1; i < jp.getReturnTypeTokens ().size (); i++)
        {
          t = (Token) (jp.getReturnTypeTokens ().get (i));
          codeGenerator.printToken (t);
        }
        codeGenerator.printTrailingComments (t);
        codeGenerator.genCode (" " + jp.getLhs () + "(");
        if (jp.getParameterListTokens ().size () != 0)
        {
          codeGenerator.printTokenSetup ((Token) (jp.getParameterListTokens ().get (0)));
          for (final java.util.Iterator it = jp.getParameterListTokens ().iterator (); it.hasNext ();)
          {
            t = (Token) it.next ();
            codeGenerator.printToken (t);
          }
          codeGenerator.printTrailingComments (t);
        }
        codeGenerator.genCode (")");
        if (isJavaDialect)
        {
          codeGenerator.genCode (" throws ParseException");
        }
        for (final java.util.Iterator it = jp.getThrowsList ().iterator (); it.hasNext ();)
        {
          codeGenerator.genCode (", ");
          final java.util.List name = (java.util.List) it.next ();
          for (final java.util.Iterator it2 = name.iterator (); it2.hasNext ();)
          {
            t = (Token) it2.next ();
            codeGenerator.genCode (t.image);
          }
        }
        codeGenerator.genCode (" {");
        if (Options.getDebugParser ())
        {
          codeGenerator.genCodeLine ("");
          codeGenerator.genCodeLine ("    trace_call(\"" + JavaCCGlobals.addUnicodeEscapes (jp.getLhs ()) + "\");");
          codeGenerator.genCode ("    try {");
        }
        if (jp.getCodeTokens ().size () != 0)
        {
          codeGenerator.printTokenSetup ((Token) (jp.getCodeTokens ().get (0)));
          cline--;
          codeGenerator.printTokenList (jp.getCodeTokens ());
        }
        codeGenerator.genCodeLine ("");
        if (Options.getDebugParser ())
        {
          if (isJavaDialect)
          {
            codeGenerator.genCodeLine ("    } finally {");
          }
          else
          {
            codeGenerator.genCodeLine ("    } catch(...) { } finally {");
          }
          codeGenerator.genCodeLine ("      trace_return(\"" + JavaCCGlobals.addUnicodeEscapes (jp.getLhs ()) + "\");");
          codeGenerator.genCodeLine ("    }");
        }
        codeGenerator.genCodeLine ("  }");
        codeGenerator.genCodeLine ("");
      }
      else
      {
        buildPhase1Routine ((BNFProduction) p);
      }
    }

    codeGenerator.switchToIncludeFile ();
    for (int phase2index = 0; phase2index < phase2list.size (); phase2index++)
    {
      buildPhase2Routine ((Lookahead) (phase2list.get (phase2index)));
    }

    int phase3index = 0;

    while (phase3index < phase3list.size ())
    {
      for (; phase3index < phase3list.size (); phase3index++)
      {
        setupPhase3Builds ((Phase3Data) (phase3list.get (phase3index)));
      }
    }

    for (final java.util.Enumeration enumeration = phase3table.elements (); enumeration.hasMoreElements ();)
    {
      buildPhase3Routine ((Phase3Data) (enumeration.nextElement ()), false);
    }

    codeGenerator.switchToMainFile ();
  }

  public void reInit ()
  {
    gensymindex = 0;
    indentamt = 0;
    jj2LA = false;
    phase2list = new ArrayList ();
    phase3list = new ArrayList ();
    phase3table = new java.util.Hashtable ();
    firstSet = null;
    xsp_declared = false;
    jj3_expansion = null;
  }

}

/**
 * This class stores information to pass from phase 2 to phase 3.
 */
class Phase3Data
{

  /*
   * This is the expansion to generate the jj3 method for.
   */
  Expansion exp;

  /*
   * This is the number of tokens that can still be consumed. This number is
   * used to limit the number of jj3 methods generated.
   */
  int count;

  Phase3Data (final Expansion e, final int c)
  {
    exp = e;
    count = c;
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy