# E4GLParser.java

    // $ANTLR 2.7.7 (20060906): "e4gl.g" -> "E4GLParser.java"$

    /*
    ** Module   : E4GLParser.java
    **            E4GLTokenTypes.java
    **            E4GLLexer.java
    ** Abstract : lex and parse E4GL source code (html files)
    **
    ** Copyright (c) 2007-2025, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- -T- --JPRM-- ----------------Description-----------------
    ** 001 GES 20070820 NEW   @348xx WARNING, THIS IS A GENERATED FILE!!!
    **                               DO NOT EDIT THIS FILE. The original source
    **                               file is e4gl.g!
    */

    /*
    ** This program is free software: you can redistribute it and/or modify
    ** it under the terms of the GNU Affero General Public License as
    ** published by the Free Software Foundation, either version 3 of the
    ** License, or (at your option) any later version.
    **
    ** This program is distributed in the hope that it will be useful,
    ** but WITHOUT ANY WARRANTY; without even the implied warranty of
    ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    ** GNU Affero General Public License for more details.
    **
    ** You may find a copy of the GNU Affero GPL version 3 at the following
    ** location: https://www.gnu.org/licenses/agpl-3.0.en.html
    **
    ** Additional terms under GNU Affero GPL version 3 section 7:
    **
    **   Under Section 7 of the GNU Affero GPL version 3, the following additional
    **   terms apply to the works covered under the License.  These additional terms
    **   are non-permissive additional terms allowed under Section 7 of the GNU
    **   Affero GPL version 3 and may not be removed by you.
    **
    **   0. Attribution Requirement.
    **
    **     You must preserve all legal notices or author attributions in the covered
    **     work or Appropriate Legal Notices displayed by works containing the covered
    **     work.  You may not remove from the covered work any author or developer
    **     credit already included within the covered work.
    **
    **   1. No License To Use Trademarks.
    **
    **     This license does not grant any license or rights to use the trademarks
    **     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
    **     of Golden Code Development Corporation. You are not authorized to use the
    **     name Golden Code, FWD, or the names of any author or contributor, for
    **     publicity purposes without written authorization.
    **
    **   2. No Misrepresentation of Affiliation.
    **
    **     You may not represent yourself as Golden Code Development Corporation or FWD.
    **
    **     You may not represent yourself for publicity purposes as associated with
    **     Golden Code Development Corporation, FWD, or any author or contributor to
    **     the covered work, without written authorization.
    **
    **   3. No Misrepresentation of Source or Origin.
    **
    **     You may not represent the covered work as solely your work.  All modified
    **     versions of the covered work must be marked in a reasonable way to make it
    **     clear that the modified work is not originating from Golden Code Development
    **     Corporation or FWD.  All modified versions must contain the notices of
    **     attribution required in this license.
    */

    package com.goldencode.p2j.e4gl;

    import java.io.*;
    import java.util.logging.*;
    import com.goldencode.ast.*;
    import com.goldencode.p2j.convert.*;
    import antlr.*;

    import antlr.TokenBuffer;
    import antlr.TokenStreamException;
    import antlr.TokenStreamIOException;
    import antlr.ANTLRException;
    import antlr.LLkParser;
    import antlr.Token;
    import antlr.TokenStream;
    import antlr.RecognitionException;
    import antlr.NoViableAltException;
    import antlr.MismatchedTokenException;
    import antlr.SemanticException;
    import antlr.ParserSharedInputState;
    import antlr.collections.impl.BitSet;

    /**
     * Parses an HTML file that has embedded 4GL (E4GL) source code and acts like
     * a filter in writing the result out as a Progress 4GL program. Any pure
     * HTML is output as 4GL source code that duplicates this HTML via writes
     * to a stream.
     * <p>
     * This is NOT a general purpose HTML parser. In fact, it is "dumbed down"
     * from the pure HTML specification to a subset that is supported by the
     * very limited parsing that WebSpeed supports. That parsing ignores certain
     * features of HTML encoding that are valid, thus this parser can similarly
     * ignore those features.
     * <p>
     * The WebSpeed product supports 4 types of program:
     * <p>
     * <ol>
     *    <li> Static HTML - pure, valid HTML that has no embedded 4GL source
     *         code
     *    <li> E4GL - HTML with embedded 4GL source code in sections delineated
     *         by statement (multi-line arbitrary 4GL code) start/end escapes or
     *         by expression (a single 4GL expression) start/end escapes
     *    <li> CGI Wrapper - hand-coded Progress source code that emits HTML
     *    <li> HTML Mapping - static HTML combined with a separate hard coded 4GL
     *         procedure that uses a configuration file containing field offsets
     *         to map data to/from the static HTML (this merging and enhancement
     *         of the static HTML is done at runtime by the WebSpeed code in
     *         cooperation with the coded 4GL procedure)
     * </ol>
     * <p>
     * This preprocessor handles cases 1 and 2 above. Cases 3 and 4 do not have
     * any embedded 4GL to preprocess so they do not need to run through this
     * parser. On first glance, case 1 (static HTML with no E4GL) seems like it
     * can be ignored since turning it into 4GL is costly from a runtime
     * efficiency perspective. When run through this preprocessor, the output of
     * such files is still a 4GL procedure (or include file). Since this procedure
     * or include file can be itself included in other E4GL programs, it is
     * necessary to convert all static HTML and E4GL code into 4GL source code.
     * <p>
     * Interestingly, the 4GL source code result of this preprocessor is the same
     * as if one had coded a CGI Wrapper (case 3 above) instead of using static
     * HTML or E4GL. There is no difference between the 3 cases at runtime, it is
     * only a difference in whether this WebSpeed preprocessor is used first.
     * <p>
     * HTML Mapping (case 4) is not addressed by this preprocessor since the HTML
     * involved in that solution is processed at runtime.
     * <p>
     * The filtering that happens can be customized to match the output of a
     * specific E4GL implementation. At this time both WebSpeed and Blue Diamond
     * implementations are supported.
     * <p>
     * This parser is heavily dependent upon the following code:
     * <p>
     * <ul>
     *    <li> {@link Options} - stores configuration that can be shared from
     *         multiple modules
     *    <li> {@link CompatibilityHelper} - this hides the difference in modes
     *         between WebSpeed and Blue Diamond
     *    <li> {@link E4GLPreprocessor} - this provides the external interface
     *         for the parser
     * </ul>
     * <p>
     * There are 2 external entry points for the parser: {@link #preprocess} and
     * {@link #scan_options}.
     * <p>
     * Parser features:
     * <p>
     * <ul>
     *    <li> statement escapes (the "...4GL..." indicates where the embedded
     *         4GL code will be found)
     *    <ul>
     *       <li> &lt;SCRIPT LANGUAGE="SpeedScript"&gt; ...4GL... &lt;/SCRIPT&gt;
     *       <li> &lt;SCRIPT LANGUAGE="WebSpeed4GL"&gt; ...4GL... &lt;/SCRIPT&gt;
     *       <li> &lt;SCRIPT LANGUAGE="Progress"&gt; ...4GL... &lt;/SCRIPT&gt;
     *       <li> &lt;!--WSS ...4GL... --&gt;
     *       <li> &lt;!--WS4GL ...4GL... --&gt;
     *       <li> &lt;?WS&gt; ...4GL... &lt;/?WS&gt;
     *       <li> &lt;SERVER&gt; ...4GL... &lt;/SERVER&gt;
     *       <li> &lt;% ...4GL... %&gt;
     *    </ul>
     *    <li> expression escapes (the "...4GL..." indicates where the embedded
     *         4GL expression will be found)
     *    <ul>
     *       <li> &lt;!--WSE ...4GL... --&gt;
     *       <li> ` ...4GL... `
     *       <li> {= ...4GL... =}
     *       <li> &lt;%= ...4GL... %&gt;
     *    </ul>
     *    <li> parsing of a <code>META</code> or <code>WSMETA</code> elements
     *         with attributes of <code>NAME="wsoptions"</code> or
     *         <code>HTTP-EQUIV="content-type"</code>; in both cases the
     *         <code>CONTENT</code> attribute is read with the following options
     *         being honored
     *    <ul>
     *       <li> include
     *       <li> web-object
     *       <li> keep-meta-content-type
     *       <li> content-type
     *    </ul>
     *    <li> everything other than the above contructs is treated as raw HTML
     *         and is output with a line prefix (effectively the same as)
     *         <code>PUT Stream WebStream UNFORMATTED '</code>) and a line suffix
     *         <code>~n'.</code> (there are many variations on these depending on
     *         what is being output and in which order; in additions the actual
     *         text used is different depending on the compatibility helper that
     *         is in use, WebSpeed or BlueDiamond)
     *    <li> raw HTML is converted into 4GL strings and any characters that
     *         cannot be safely represented in 4GL source code is escaped
     *    <li> 4GL expressions and statements which have HTML entities encoded
     *         are decoded into the matching character
     *    <li> 4GL expressions used in HTML URLs that have the %XX character
     *         encoding for spaces and other special characters are decoded into
     *         the matching character (using the 2 hexidecimal digits that follow
     *         the percent sign)
     * </ul>
     * <p>
     * <b>TODO:</b> before this output can be optimally converted, it is likely
     * that the expansions, replacements and other state of the preprocessing
     * will need to be recorded by the parser into a hints file. Much of the
     * data to be stored will be in the form of a "section definition" which
     * stores the start line/column and end line/column of a section of either
     * the original source file or of the target file. The following will be
     * needed:
     * <p>
     * <ul>
     *    <li> original HTML source file name
     *    <li> any specified wsoptions
     *    <li> any specified content-type
     *    <li> include flag
     *    <li> keep content type flag
     *    <li> compatibility mode
     *    <li> for each raw HTML section that was converted to "PUT" statements
     *         there will be a section definition for both the source and target
     *         files (this will allow the 4GL source code to be removed and
     *         replaced by the original raw HTML from the source file should
     *         the conversion need it)
     *    <li> a section definition in the target file for the generated header
     *    <li> a section definition in the target file for the generated footer
     * </ul>
     */
    public class E4GLParser extends antlr.LLkParser       implements E4GLParserTokenTypes
     {

       /** Logger. */
       private static final ConversionStatus LOG = ConversionStatus.get(E4GLParser.class);

       /** Newline character to search for for line operations. */
       private static char NL = '\n';

       /** Configuration values to honor during preprocessing. */
       private Options cfg = null;

       /** Source for raw input. */
       private InputStream in = null;

       /** Destination for preprocessed output. */
       private PrintStream out = null;

       /** Helper to emit headers, footers, comments and other text. */
       private CompatibilityHelper hlp = null;

       /** Flag to denote that the output is starting a new line. */
       private boolean lineBegin = true;

       /** Flag to denote that the last output was HTML. */
       private boolean wasHtml = true;

       /** Flag to denote that the last output was an expression escape close. */
       private boolean wasExprClose = false;

       /** Flag to denote that the last output was an statement escape close. */
       private boolean wasStmtClose = false;

       static
       {
          // by default we search for '\n' which handles both "\n" and "\r\n"
          // cases, but if the platform newline is "\r" then we must search for
          // '\r' instead
          if ("\r".equals(CompatibilityHelper.NEWLINE))
          {
             NL = '\r';
          }
       }

       /**
        * Get the input stream. This is not used internally but is stored here
        * to allow the stream to be easily obtained by the user of this class.
        *
        * @return   Source stream.
        */
       public InputStream getInput()
       {
          return in;
       }

       /**
        * Set the input stream. This is not used internally but is stored here
        * to allow the stream to be easily obtained by the user of this class.
        *
        * @param    in
        *           Source stream.
        */
       public void setInput(InputStream in)
       {
          this.in = in;
       }

       /**
        * Close the input stream.
        */
       public void closeInput()
       {
          try
          {
             if (in != null)
                in.close();
          }

          catch (IOException ioe)
          {
             // ignore
          }
       }

       /**
        * Writes error data to logger, including a full stack trace.
        *
        * @param    re
        *           The error on which to report.
        */
       public void reportError(RecognitionException re)
       {
          LOG.log(Level.SEVERE, "", re);
       }

       /**
        * Output the given text to the stream while maintaining the new line
        * state. If requested, this method will also convert HTML entities into
        * the valid characters as they would appear in 4GL source code. This
        * occurs based on the <code>cvt</code> parameter. If the type of output
        * is <code>html</code>, then any unsafe characters are escaped before
        * being output as 4GL code.
        * <p>
        * This method is highly sensitive to the member state variables that
        * are maintained in cooperation with <code>outputOpenComment()</code> and
        * <code>outputCloseComment()</code>. Together these 3 methods handle all
        * output for the preprocessor.
        * <p>
        * Based on the current state variables, the parameters and the
        * {@link CompatibilityHelper} instance, this method handles all output
        * that isn't a start or end element of a statement or expression escape.
        * This means that all raw HTML and all (embedded 4GL source) content of
        * expression/statement escapes is handled here.
        * <p>
        * Of great importance is that each line of output is started and ended
        * with the proper text (in HTML mode). Likewise, when shifting into and
        * out of expression and statement escapes, any raw HTML must be properly
        * terminated and resumed as needed.  Some deferred suffix processing of
        * end elements for statement and expression escapes is handled here where
        * the following content is known such that the variance in results
        * can be determined.
        *
        * @param    txt
        *           Contents to write to the stream. Must be non-empty and
        *           not <code>null</code>.
        * @param    cvt
        *           <code>true</code> to force HTML entity conversion before the
        *           text is output.
        * @param    html
        *           <code>true</code> to add end of line and beginning of line
        *           output around new line characters in HTML. Since this
        *           preprocessor is converting this HTML into strings that are
        *           output via streams in the 4GL source, these strings need to
        *           be augmented at the beginning and end of each line.
        */
       private void output(String txt, boolean cvt, boolean html)
       {
          int last = txt.length() - 1;

          if (last == -1)
             return;

          txt = cvt  ? hlp.entityConvert(txt) : txt;
          // txt = html ? hlp.escapeHTML(txt)    : txt;

          if (lineBegin)
          {
             // if we are at the beginning of a line and in HTML mode, then we
             // need to output the line prefix
             if (html)
             {
                out.print(hlp.openHTML(true));
             }

             // clear the counter, since we are doing output
             lineBegin = false;
          }
          else
          {
             // check if we just exited an expression escape
             if (wasExprClose)
             {
                if (html && txt.indexOf(NL) != 0)
                {
                   // re-open our string for raw HTML output
                   out.print(hlp.closeExprEscape());
                }
                else
                {
                   // no more HTML so we need to close the last HTML output
                   out.print(hlp.closeHTML(false, false));
                }
             }
             else if (wasStmtClose)
             {
                // HTML text that follows a statement escape needs to be opened
                // if there is no newline char as the first character of our text
                if (html && txt.indexOf(NL) != 0)
                {
                   out.print(hlp.openHTML(true));
                }
             }
          }

          if (html)
          {
             StringBuilder sb = new StringBuilder();

             boolean found = false;
             int prev = 0;
             int next = txt.indexOf(NL);

             while (next >= 0)
             {
                if (found)
                {
                   // subsequent time through, act like the lineBegin flag is
                   // true and output the line prefix
                   sb.append(hlp.openHTML(true));
                }

                // if the text to be output ends in a newline, then we need to
                // reset the lineBegin flag to ensure that subsequent output will
                // honor the fact (if needed by context) that we haven't yet output
                // any line prefix; if this newline is in the middle of the text
                // there is no need to update the state of this flag since we are
                // about to reset its state again before this method returns...
                if (next == last)
                {
                   lineBegin = true;
                }

                // it is possible that there are blank lines and lines with only
                // whitespace that are output here, but these can't be dropped
                // in case we are inside a PRE block and the whitespace is
                // important; put the text and the line suffix and the new line
                sb.append(hlp.escapeHTML(txt.substring(prev, next)));

                // on the first pass, even though we are outputting HTML now, if
                // the newline is the first character and the previous mode was
                // not HTML, then we don't output the close HTML text
                boolean avoid = (!found && !wasHtml && next == 0);

                if (!avoid || found)
                  sb.append(hlp.closeHTML(true, true));

                sb.append(hlp.NEWLINE);

                prev = next + 1;
                next = txt.indexOf(NL, prev);

                // not the first time through
                found = true;
             }

             if (found)
             {
                // output the rest of the string if there is any
                if (prev < txt.length())
                {
                   sb.append(hlp.openHTML(true));
                   sb.append(hlp.escapeHTML(txt.substring(prev)));
                }

                // reset our output text to the modified version
                txt = sb.toString();
             }
             else
             {
                txt = hlp.escapeHTML(txt);
             }
          }
          else
          {
             // see the above comment regarding why we set this flag and why it
             // is only if the last character is a newline
             if (txt.lastIndexOf(NL) == last)
             {
                lineBegin = true;
             }
          }

          out.print(txt);

          // clear our indicators, any deferred output is complete
          wasExprClose = false;
          wasStmtClose = false;

          // save state
          wasHtml = html;
       }

       /**
        * Comment out the given text of an expression or statement open element
        * and output it to the stream.
        * <p>
        * This method is highly sensitive to the member state variables that
        * are maintained in cooperation with <code>output()</code> and
        * <code>outputCloseComment()</code>. Together these 3 methods handle all
        * output for the preprocessor.
        * <p>
        * Based on the current state variables, the parameters and the
        * {@link CompatibilityHelper} instance, this method handles all output
        * that is a start element of a statement of expression escape.
        * <p>
        * Of great importance is that, when shifting into expression and
        * statement escapes, any raw HTML must be properly terminated or
        * started as needed. Some deferred suffix processing of end elements
        * for statement and expression escapes is handled here where the
        * following content is known such that the variance in results
        * can be determined.
        *
        * @param    escape
        *           The token with the text to comment.
        * @param    expr
        *           <code>true</code> if this is an expression escape,
        *           <code>false</code> for a statement escape.
        */
       private void outputOpenComment(Token escape, boolean expr)
       {
          outputOpenComment(escape.getText(), expr);
       }

       /**
        * Comment out the given text of an expression or statement open element
        * and output it to the stream.
        * <p>
        * This method is highly sensitive to the member state variables that
        * are maintained in cooperation with <code>output()</code> and
        * <code>outputCloseComment()</code>. Together these 3 methods handle all
        * output for the preprocessor.
        * <p>
        * Based on the current state variables, the parameters and the
        * {@link CompatibilityHelper} instance, this method handles all output
        * that is a start element of a statement of expression escape.
        * <p>
        * Of great importance is that, when shifting into expression and
        * statement escapes, any raw HTML must be properly terminated or
        * started as needed. Some deferred suffix processing of end elements
        * for statement and expression escapes is handled here where the
        * following content is known such that the variance in results
        * can be determined.
        *
        * @param    escape
        *           The text to comment.
        * @param    expr
        *           <code>true</code> if this is an expression escape,
        *           <code>false</code> for a statement escape.
        */
       private void outputOpenComment(String escape, boolean expr)
       {
          String result = generateOpenComment(escape, expr);

          if (result != null)
          {
             out.print(result);
          }
       }

       /**
        * Comment out the given text of an expression or statement open element
        * and output it to the stream.
        * <p>
        * This method is highly sensitive to the member state variables that
        * are maintained in cooperation with <code>output()</code> and
        * <code>outputCloseComment()</code>. Together these 3 methods handle all
        * output for the preprocessor.
        * <p>
        * Based on the current state variables, the parameters and the
        * {@link CompatibilityHelper} instance, this method handles all output
        * that is a start element of a statement of expression escape.
        * <p>
        * Of great importance is that, when shifting into expression and
        * statement escapes, any raw HTML must be properly terminated or
        * started as needed. Some deferred suffix processing of end elements
        * for statement and expression escapes is handled here where the
        * following content is known such that the variance in results
        * can be determined.
        *
        * @param    escape
        *           The text to comment.
        * @param    expr
        *           <code>true</code> if this is an expression escape,
        *           <code>false</code> for a statement escape.
        *
        * @return   The generated open comment or {@code null} if there is nothing generated.
        */
       private String generateOpenComment(String escape, boolean expr)
       {
          String result = null;

          String prefix = "";

          if (expr)
          {
             if (lineBegin)
             {
                // no content to terminate, but we do need to start the line
                prefix = hlp.openHTML(false);
             }
             else
             {
                if (wasHtml)
                {
                   // content to terminate before the comment emits
                   prefix = hlp.openExprEscape();
                }
             }
          }
          else
          {
             // this is a statement escape (nothing to do unless this is in the middle of a line)
             if (!lineBegin)
             {
                if (wasHtml)
                {
                   // there is unterminated content on the line, terminate it properly, but note that it is
                   // not the end of the line
                   prefix = hlp.closeHTML(true, false);
                }
                else
                {
                   if (wasExprClose)
                   {
                      // close off the HTML mode BUT there is no content to terminate
                      prefix = hlp.closeHTML(false, false);
                   }
                }
             }
          }

          if (prefix.length() > 0)
          {
             result = prefix;
          }

          // reset our state vars
          lineBegin    = false;
          wasHtml      = false;
          wasExprClose = false;
          wasStmtClose = false;

          String cmt = generateComment(escape, expr);

          if (cmt != null)
          {
             result = (result == null) ? cmt : result + cmt;
          }

          return result;
       }

       /**
        * Comment out the given text of an expression or statement close element
        * and output it to the stream.
        * <p>
        * This method is highly sensitive to the member state variables that
        * are maintained in cooperation with <code>output()</code> and
        * <code>outputOpenComment()</code>. Together these 3 methods handle all
        * output for the preprocessor.
        * <p>
        * Based on the current state variables, the parameters and the
        * {@link CompatibilityHelper} instance, this method handles all output
        * that is an end element of a statement of expression escape.
        * <p>
        * Of great importance is that, when shifting into and out of expression
        * and statement escapes, any raw HTML must be properly
        * resumed and terminated as needed. Some suffix processing of end elements
        * for statement and expression escapes is also deferred to the
        * <code>output()</code> and <code>outputOpenComment()</code> methods
        * where the following content is known such that the variance in results
        * can be determined.
        *
        * @param    escape
        *           The token with the text to comment.
        * @param    expr
        *           <code>true</code> if this is an expression escape,
        *           <code>false</code> for a statement escape.
        */
       private void outputCloseComment(Token escape, boolean expr)
       {
          outputCloseComment(escape.getText(), expr);
       }

       /**
        * Comment out the given text of an expression or statement close element
        * and output it to the stream.
        * <p>
        * This method is highly sensitive to the member state variables that
        * are maintained in cooperation with <code>output()</code> and
        * <code>outputOpenComment()</code>. Together these 3 methods handle all
        * output for the preprocessor.
        * <p>
        * Based on the current state variables, the parameters and the
        * {@link CompatibilityHelper} instance, this method handles all output
        * that is an end element of a statement of expression escape.
        * <p>
        * Of great importance is that, when shifting into and out of expression
        * and statement escapes, any raw HTML must be properly
        * resumed and terminated as needed. Some suffix processing of end elements
        * for statement and expression escapes is also deferred to the
        * <code>output()</code> and <code>outputOpenComment()</code> methods
        * where the following content is known such that the variance in results
        * can be determined.
        *
        * @param    escape
        *           The text to comment.
        * @param    expr
        *           <code>true</code> if this is an expression escape,
        *           <code>false</code> for a statement escape.
        */
       private void outputCloseComment(String escape, boolean expr)
       {
          String cmt = generateCloseComment(escape, expr);

          if (cmt != null)
          {
             out.print(cmt);
          }
       }

       /**
        * Comment out the given text of an expression or statement close element
        * and return it.
        * <p>
        * This method is highly sensitive to the member state variables that
        * are maintained in cooperation with <code>output()</code> and
        * <code>generateOpenComment()</code>. Together these 3 methods handle all
        * state management for the preprocessor.
        * <p>
        * Based on the current state variables, the parameters and the
        * {@link CompatibilityHelper} instance, this method generates all text
        * that is an end element of a statement of expression escape.
        * <p>
        * Of great importance is that, when shifting into and out of expression
        * and statement escapes, any raw HTML must be properly
        * resumed and terminated as needed. Some suffix processing of end elements
        * for statement and expression escapes is also deferred to the
        * <code>output()</code> and <code>generateOpenComment()</code> methods
        * where the following content is known such that the variance in results
        * can be determined.
        *
        * @param    escape
        *           The text to comment.
        * @param    expr
        *           <code>true</code> if this is an expression escape,
        *           <code>false</code> for a statement escape.
        */
       private String generateCloseComment(String escape, boolean expr)
       {
          // reset our state vars
          lineBegin    = false;
          wasHtml      = false;

          // remember that we just exited an expression or statement escape so
          // that following output can terminate the stream output or start
          // another string of raw HTML, depending on the context
          wasExprClose = expr;
          wasStmtClose = !expr;

          return generateComment(escape, expr);
       }

       /**
        * Generate a comment out the given text of an escape and return it. The compatibility helper will be used
        * to create the open and close comment text. The compatibility helper may also specify that the escape is
        * to be silently dropped, in which case no text will be generated.
        *
        * @param    escape
        *           The text to comment.
        * @param    expr
        *           <code>true</code> if this is an expression escape,
        *           <code>false</code> for a statement escape.
        *
        * @return   The generated comment text or {@code null} if no text was generated.
        */
       private String generateComment(String escape, boolean expr)
       {
          String open = hlp.openComment(expr);

          // only output if the comment text is non-null, otherwise silently eat the escape
          return (open != null) ? String.format("%s%s%s", open, escape, hlp.closeComment(expr)) : null;
       }

       /**
        * Get the text of the token unless it is of type <code>ENCODED_CHAR</code>
        * in which case the contents will be converted from the '%XX' form into
        * the hexidecimal character that is being encoded.
        *
        * @param    next
        *           The token to potentially decode.
        *
        * @return   The text of the token or its encoded character as text.
        */
       private String getTokenText(Token next)
       {
          String txt = next.getText();

          if (next.getType() == ENCODED_CHAR)
          {
             char encoded = (char) Integer.parseInt(txt.substring(1, 3), 16);
             txt = Character.toString(encoded);
          }

          return txt;
       }

    protected E4GLParser(TokenBuffer tokenBuf, int k) {
      super(tokenBuf,k);
      tokenNames = _tokenNames;
    }

    public E4GLParser(TokenBuffer tokenBuf) {
      this(tokenBuf,2);
    }

    protected E4GLParser(TokenStream lexer, int k) {
      super(lexer,k);
      tokenNames = _tokenNames;
    }

    public E4GLParser(TokenStream lexer) {
      this(lexer,2);
    }

    public E4GLParser(ParserSharedInputState state) {
      super(state,2);
      tokenNames = _tokenNames;
    }

    /**
     * Top-level entry point that parses the input stream and preprocesses the
     * HTML and embedded 4GL into a valid 4GL program. All statement and
     * expression escapes are supported by calling a sub-rule for each type.
     * This sub-rule will not return until the entire escape has been parsed
     * and output. State is maintained such that transitions into and out of
     * escapes are prefixed or suffixed with the proper text. In some cases,
     * the suffix cannot be determined until following output is parsed, in which
     * case that suffix processing is deferred via member state variables.
     * <p>
     * Uses the following expression escape rules:
     * <p>
     * <ul>
     *    <li> {@link #backtick_escape}
     *    <li> {@link #percent_eq_escape}
     *    <li> {@link #curly_escape}
     *    <li> {@link #wse_escape}
     * </ul>
     * <p>
     * Uses the following statement escape rules:
     * <p>
     * <ul>
     *    <li> {@link #script_escape}
     *    <li> {@link #question_escape}
     *    <li> {@link #percent_escape}
     *    <li> {@link #server_escape}
     *    <li> {@link #wss_escape}
     * </ul>
     * <p>
     * This rule also processes the {@link #meta_tag} rule in the case where
     * <code>keep-meta-content-type</code> is not set as an option. In this
     * case, a <code>META</code> or <code>WSMETA</code> element with an attribute
     * of <code>HTTP-EQUIV</code> set to <code>CONTENT-TYPE</code> will be
     * removed from the output stream using comments.  Anything else will be
     * passed through a raw HTML.
     * <p>
     * Anything that is not handled by one of the above listed rules is considered
     * raw HTML and is output with little regard to the content. The exceptions to
     * this include newline processing (since the beginning and end of each line
     * must have text added) and the proper escaping of certain valid HTML
     * characters that cannot be directly included in 4GL programs.
     * <p>
     * Internally, all of the state management and output processing is
     * centralized in the following methods: <code>output()</code>,
     * <code>outputOpenComment()</code> and <code>outputCloseComment()</code>.
     * <p>
     * All rules are peers at this level to ensure that they do not cause
     * parser ambiguity.
     *
     * @param    cfg
     *           Storage container for the options that are found.
     */
    	public final void preprocess(
    		Options cfg, PrintStream out
    	) throws RecognitionException, TokenStreamException {

    		Token  txt = null;

    		this.cfg = cfg;
    		this.out = out;
    		hlp = cfg.getCompatibilityHelper();

    		boolean httpEquiv = false;
    		boolean keep      = cfg.isKeepContentType();
    		StringBuilder sb = new StringBuilder();

    		// print the file header
    		output(hlp.header(), false, false);
    		wasHtml = true;
    		lineBegin = true;

    		try {      // for error handling
    			{
    			_loop3:
    			do {
    				if ((LA(1)==BACK_TICK) && ((LA(2) >= OPEN_END_TAG && LA(2) <= JUNK))) {
    					backtick_escape();
    				}
    				else if ((LA(1)==OPEN_PCT_EQ) && ((LA(2) >= OPEN_END_TAG && LA(2) <= JUNK))) {
    					percent_eq_escape();
    				}
    				else if ((LA(1)==OPEN_CURLY_EQ) && ((LA(2) >= OPEN_END_TAG && LA(2) <= JUNK))) {
    					curly_escape();
    				}
    				else if ((LA(1)==OPEN_COMMENT) && (LA(2)==WSE)) {
    					wse_escape();
    				}
    				else if ((LA(1)==OPEN_START_TAG) && (LA(2)==SCRIPT)) {
    					script_escape();
    				}
    				else if ((LA(1)==OPEN_QUESTION) && (LA(2)==WSPEED)) {
    					question_escape();
    				}
    				else if ((LA(1)==OPEN_PCT) && ((LA(2) >= OPEN_END_TAG && LA(2) <= JUNK))) {
    					percent_escape();
    				}
    				else if ((LA(1)==OPEN_START_TAG) && (LA(2)==SERVER)) {
    					server_escape();
    				}
    				else if ((LA(1)==OPEN_COMMENT) && (LA(2)==WSS||LA(2)==WS4GL)) {
    					wss_escape();
    				}
    				else if (((LA(1)==OPEN_START_TAG||LA(1)==OPEN_COMMENT) && (LA(2)==META||LA(2)==WSMETA))&&( !keep )) {
    					httpEquiv=meta_tag(null, sb);

    					String open  = httpEquiv ? hlp.openContentTypeComment()  : "";
    					String close = httpEquiv ? hlp.closeContentTypeComment() : "";
    					String core  = sb.toString();

    					// are we supposed to remove the entry
    					if (open.length() > 0)
    					{
    					// remove the start and end character from the core buffer,
    					// which should correspond to the '<' and '>' that must
    					// always be present
    					core = core.substring(1, core.length() - 1);
    					}

    					output(String.format("%s%s%s", open, core, close), false, true);

    				}
    				else if ((((LA(1) >= OPEN_END_TAG && LA(1) <= JUNK)) && (LA(2)==EOF||LA(2)==OPEN_END_TAG||LA(2)==SCRIPT||LA(2)==CLOSE_TAG||LA(2)==OPEN_START_TAG||LA(2)==LANGUAGE||LA(2)==OPEN_QUESTION||LA(2)==WSPEED||LA(2)==CLOSE_QUESTION||LA(2)==OPEN_PCT||LA(2)==CLOSE_PCT||LA(2)==SERVER||LA(2)==OPEN_COMMENT||LA(2)==WSS||LA(2)==WS4GL||LA(2)==CLOSE_COMMENT||LA(2)==BACK_TICK||LA(2)==OPEN_PCT_EQ||LA(2)==OPEN_CURLY_EQ||LA(2)==CLOSE_CURLY_EQ||LA(2)==WSE||LA(2)==META||LA(2)==WSMETA||LA(2)==WS||LA(2)==NAME||LA(2)==HTTP_EQUIV||LA(2)==CONTENT||LA(2)==SYMBOL||LA(2)==EQUALS||LA(2)==DQUOTE||LA(2)==SQUOTE||LA(2)==ENCODED_CHAR||LA(2)==UNKNOWN||LA(2)==CLOSE_TAG_NO_CONTENT||LA(2)==GT||LA(2)==LT||LA(2)==SLASH||LA(2)==PERCENT||LA(2)==EXCLAIM||LA(2)==HYPHEN||LA(2)==UNDERSCORE||LA(2)==DOT||LA(2)==COLON||LA(2)==QUESTION||LA(2)==LEFT_CURLY||LA(2)==RIGHT_CURLY||LA(2)==LETTER||LA(2)==DIGIT||LA(2)==HEX_DIGIT||LA(2)==OTHER||LA(2)==JUNK))&&( LA(1) != EOF )) {
    					txt = LT(1);
    					matchNot(EOF);

    					output(txt.getText(), false, true);

    				}
    				else {
    					break _loop3;
    				}

    			} while (true);
    			}
    			match(Token.EOF_TYPE);

    			// print the file footer
    			output(hlp.footer(), false, false);

    		}
    		catch (RecognitionException ex) {
    			reportError(ex);
    			recover(ex,_tokenSet_0);
    		}
    	}

    /**
     * Match a starting <code>BACK_TICK</code>, arbitrary 4GL expression text and
     * a closing <code>BACK_TICK</code>.
     */
    	public final void backtick_escape() throws RecognitionException, TokenStreamException {

    		Token  bt1 = null;
    		Token  txt = null;
    		Token  bt2 = null;

    		StringBuilder sb = new StringBuilder();

    		try {      // for error handling
    			bt1 = LT(1);
    			match(BACK_TICK);

    			// comment out the open text
    			String open = generateOpenComment(bt1.getText(), true);

    			if (open != null)
    			{
    			out.print(open);
    			}

    			{
    			_loop25:
    			do {
    				if ((LA(1)==OPEN_END_TAG||LA(1)==SCRIPT||LA(1)==CLOSE_TAG||LA(1)==OPEN_START_TAG||LA(1)==LANGUAGE||LA(1)==OPEN_QUESTION||LA(1)==WSPEED||LA(1)==CLOSE_QUESTION||LA(1)==OPEN_PCT||LA(1)==CLOSE_PCT||LA(1)==SERVER||LA(1)==OPEN_COMMENT||LA(1)==WSS||LA(1)==WS4GL||LA(1)==CLOSE_COMMENT||LA(1)==OPEN_PCT_EQ||LA(1)==OPEN_CURLY_EQ||LA(1)==CLOSE_CURLY_EQ||LA(1)==WSE||LA(1)==META||LA(1)==WSMETA||LA(1)==WS||LA(1)==NAME||LA(1)==HTTP_EQUIV||LA(1)==CONTENT||LA(1)==SYMBOL||LA(1)==EQUALS||LA(1)==DQUOTE||LA(1)==SQUOTE||LA(1)==ENCODED_CHAR||LA(1)==UNKNOWN||LA(1)==CLOSE_TAG_NO_CONTENT||LA(1)==GT||LA(1)==LT||LA(1)==SLASH||LA(1)==PERCENT||LA(1)==EXCLAIM||LA(1)==HYPHEN||LA(1)==UNDERSCORE||LA(1)==DOT||LA(1)==COLON||LA(1)==QUESTION||LA(1)==LEFT_CURLY||LA(1)==RIGHT_CURLY||LA(1)==LETTER||LA(1)==DIGIT||LA(1)==HEX_DIGIT||LA(1)==OTHER||LA(1)==JUNK)) {
    					txt = LT(1);
    					matchNot(BACK_TICK);

    					sb.append(getTokenText(txt));

    				}
    				else {
    					break _loop25;
    				}

    			} while (true);
    			}

    			output(sb.toString(), true, false);

    			bt2 = LT(1);
    			match(BACK_TICK);

    			// comment out the close text
    			String close = generateCloseComment(bt2.getText(), true);

    			if (close != null)
    			{
    			out.print(close);
    			}

    		}
    		catch (RecognitionException ex) {
    			reportError(ex);
    			recover(ex,_tokenSet_1);
    		}
    	}

    /**
     * Match a starting <code>OPEN_PCT_EQ</code>, arbitrary 4GL expression text
     * and a closing <code>CLOSE_PCT</code>.
     */
    	public final void percent_eq_escape() throws RecognitionException, TokenStreamException {

    		Token  op = null;
    		Token  txt = null;
    		Token  cp = null;

    		StringBuilder sb = new StringBuilder();

    		try {      // for error handling
    			op = LT(1);
    			match(OPEN_PCT_EQ);

    			// comment out the open text
    			outputOpenComment(op, true);

    			{
    			_loop28:
    			do {
    				if ((LA(1)==OPEN_END_TAG||LA(1)==SCRIPT||LA(1)==CLOSE_TAG||LA(1)==OPEN_START_TAG||LA(1)==LANGUAGE||LA(1)==OPEN_QUESTION||LA(1)==WSPEED||LA(1)==CLOSE_QUESTION||LA(1)==OPEN_PCT||LA(1)==SERVER||LA(1)==OPEN_COMMENT||LA(1)==WSS||LA(1)==WS4GL||LA(1)==CLOSE_COMMENT||LA(1)==BACK_TICK||LA(1)==OPEN_PCT_EQ||LA(1)==OPEN_CURLY_EQ||LA(1)==CLOSE_CURLY_EQ||LA(1)==WSE||LA(1)==META||LA(1)==WSMETA||LA(1)==WS||LA(1)==NAME||LA(1)==HTTP_EQUIV||LA(1)==CONTENT||LA(1)==SYMBOL||LA(1)==EQUALS||LA(1)==DQUOTE||LA(1)==SQUOTE||LA(1)==ENCODED_CHAR||LA(1)==UNKNOWN||LA(1)==CLOSE_TAG_NO_CONTENT||LA(1)==GT||LA(1)==LT||LA(1)==SLASH||LA(1)==PERCENT||LA(1)==EXCLAIM||LA(1)==HYPHEN||LA(1)==UNDERSCORE||LA(1)==DOT||LA(1)==COLON||LA(1)==QUESTION||LA(1)==LEFT_CURLY||LA(1)==RIGHT_CURLY||LA(1)==LETTER||LA(1)==DIGIT||LA(1)==HEX_DIGIT||LA(1)==OTHER||LA(1)==JUNK)) {
    					txt = LT(1);
    					matchNot(CLOSE_PCT);

    					sb.append(getTokenText(txt));

    				}
    				else {
    					break _loop28;
    				}

    			} while (true);
    			}

    			output(sb.toString(), true, false);

    			cp = LT(1);
    			match(CLOSE_PCT);

    			// comment out the close text
    			outputCloseComment(cp, true);

    		}
    		catch (RecognitionException ex) {
    			reportError(ex);
    			recover(ex,_tokenSet_1);
    		}
    	}

    /**
     * Match a starting <code>OPEN_CURLY_EQ</code>, arbitrary 4GL expression text
     * and a closing <code>CLOSE_CURLY_EQ</code>.
     */
    	public final void curly_escape() throws RecognitionException, TokenStreamException {

    		Token  oc = null;
    		Token  txt = null;
    		Token  cc = null;

    		StringBuilder sb = new StringBuilder();

    		try {      // for error handling
    			oc = LT(1);
    			match(OPEN_CURLY_EQ);

    			// comment out the open text
    			outputOpenComment(oc, true);

    			{
    			_loop31:
    			do {
    				if ((LA(1)==OPEN_END_TAG||LA(1)==SCRIPT||LA(1)==CLOSE_TAG||LA(1)==OPEN_START_TAG||LA(1)==LANGUAGE||LA(1)==OPEN_QUESTION||LA(1)==WSPEED||LA(1)==CLOSE_QUESTION||LA(1)==OPEN_PCT||LA(1)==CLOSE_PCT||LA(1)==SERVER||LA(1)==OPEN_COMMENT||LA(1)==WSS||LA(1)==WS4GL||LA(1)==CLOSE_COMMENT||LA(1)==BACK_TICK||LA(1)==OPEN_PCT_EQ||LA(1)==OPEN_CURLY_EQ||LA(1)==WSE||LA(1)==META||LA(1)==WSMETA||LA(1)==WS||LA(1)==NAME||LA(1)==HTTP_EQUIV||LA(1)==CONTENT||LA(1)==SYMBOL||LA(1)==EQUALS||LA(1)==DQUOTE||LA(1)==SQUOTE||LA(1)==ENCODED_CHAR||LA(1)==UNKNOWN||LA(1)==CLOSE_TAG_NO_CONTENT||LA(1)==GT||LA(1)==LT||LA(1)==SLASH||LA(1)==PERCENT||LA(1)==EXCLAIM||LA(1)==HYPHEN||LA(1)==UNDERSCORE||LA(1)==DOT||LA(1)==COLON||LA(1)==QUESTION||LA(1)==LEFT_CURLY||LA(1)==RIGHT_CURLY||LA(1)==LETTER||LA(1)==DIGIT||LA(1)==HEX_DIGIT||LA(1)==OTHER||LA(1)==JUNK)) {
    					txt = LT(1);
    					matchNot(CLOSE_CURLY_EQ);

    					sb.append(getTokenText(txt));

    				}
    				else {
    					break _loop31;
    				}

    			} while (true);
    			}

    			output(sb.toString(), true, false);

    			cc = LT(1);
    			match(CLOSE_CURLY_EQ);

    			// comment out the close text
    			outputCloseComment(cc, true);

    		}
    		catch (RecognitionException ex) {
    			reportError(ex);
    			recover(ex,_tokenSet_1);
    		}
    	}

    /**
     * Match a starting <code>OPEN_COMMENT WSE</code>, arbitrary 4GL expression
     * text and a closing <code>CLOSE_COMMENT</code>.
     */
    	public final void wse_escape() throws RecognitionException, TokenStreamException {

    		Token  ow = null;
    		Token  w = null;
    		Token  txt = null;
    		Token  cc = null;

    		StringBuilder sb = new StringBuilder();

    		try {      // for error handling
    			{
    			ow = LT(1);
    			match(OPEN_COMMENT);
    			w = LT(1);
    			match(WSE);
    			}

    			// put the text back together as if it was a single token
    			ow.setText(String.format("%s%s", ow.getText(), w.getText()));

    			// comment out the open text
    			outputOpenComment(ow, true);

    			{
    			_loop35:
    			do {
    				if ((LA(1)==OPEN_END_TAG||LA(1)==SCRIPT||LA(1)==CLOSE_TAG||LA(1)==OPEN_START_TAG||LA(1)==LANGUAGE||LA(1)==OPEN_QUESTION||LA(1)==WSPEED||LA(1)==CLOSE_QUESTION||LA(1)==OPEN_PCT||LA(1)==CLOSE_PCT||LA(1)==SERVER||LA(1)==OPEN_COMMENT||LA(1)==WSS||LA(1)==WS4GL||LA(1)==BACK_TICK||LA(1)==OPEN_PCT_EQ||LA(1)==OPEN_CURLY_EQ||LA(1)==CLOSE_CURLY_EQ||LA(1)==WSE||LA(1)==META||LA(1)==WSMETA||LA(1)==WS||LA(1)==NAME||LA(1)==HTTP_EQUIV||LA(1)==CONTENT||LA(1)==SYMBOL||LA(1)==EQUALS||LA(1)==DQUOTE||LA(1)==SQUOTE||LA(1)==ENCODED_CHAR||LA(1)==UNKNOWN||LA(1)==CLOSE_TAG_NO_CONTENT||LA(1)==GT||LA(1)==LT||LA(1)==SLASH||LA(1)==PERCENT||LA(1)==EXCLAIM||LA(1)==HYPHEN||LA(1)==UNDERSCORE||LA(1)==DOT||LA(1)==COLON||LA(1)==QUESTION||LA(1)==LEFT_CURLY||LA(1)==RIGHT_CURLY||LA(1)==LETTER||LA(1)==DIGIT||LA(1)==HEX_DIGIT||LA(1)==OTHER||LA(1)==JUNK)) {
    					txt = LT(1);
    					matchNot(CLOSE_COMMENT);

    					sb.append(getTokenText(txt));

    				}
    				else {
    					break _loop35;
    				}

    			} while (true);
    			}

    			output(sb.toString(), true, false);

    			cc = LT(1);
    			match(CLOSE_COMMENT);

    			// comment out the close text
    			outputCloseComment(cc, true);

    		}
    		catch (RecognitionException ex) {
    			reportError(ex);
    			recover(ex,_tokenSet_1);
    		}
    	}

    /**
     * Match a starting <code>OPEN_START_TAG SCRIPT</code>, arbitrary
     * 4GL statement text and then <code>CLOSE_QUESTION WSPEED CLOSE_TAG</code>.
     */
    	public final void script_escape() throws RecognitionException, TokenStreamException {

    		Token  txt = null;
    		Token  oe = null;
    		Token  s = null;
    		Token  ct = null;

    		StringBuilder sb = new StringBuilder();
    		boolean e4gl = false;

    		try {      // for error handling
    			e4gl=script_tag(sb);

    			if (e4gl)
    			{
    			outputOpenComment(sb.toString(), false);
    			}
    			else
    			{
    			output(sb.toString(), false, true);
    			}

    			{
    			_loop6:
    			do {
    				if (((LA(1)==BACK_TICK) && ((LA(2) >= OPEN_END_TAG && LA(2) <= JUNK)))&&( !e4gl )) {
    					backtick_escape();
    				}
    				else if ((((LA(1) >= OPEN_END_TAG && LA(1) <= JUNK)) && ((LA(2) >= OPEN_END_TAG && LA(2) <= JUNK)))&&( !(LA(1) == OPEN_END_TAG && LA(2) == SCRIPT) )) {
    					txt = LT(1);
    					matchNot(EOF);

    					output(getTokenText(txt), e4gl, !e4gl);

    				}
    				else {
    					break _loop6;
    				}

    			} while (true);
    			}
    			oe = LT(1);
    			match(OPEN_END_TAG);
    			s = LT(1);
    			match(SCRIPT);
    			ct = LT(1);
    			match(CLOSE_TAG);

    			String combined = String.format("%s%s%s", oe.getText(), s.getText(), ct.getText());

    			if (e4gl)
    			{
    			// comment out the close text
    			outputCloseComment(combined, false);
    			}
    			else
    			{
    			// emit as raw HTML
    			output(combined, false, true);
    			}

    		}
    		catch (RecognitionException ex) {
    			reportError(ex);
    			recover(ex,_tokenSet_1);
    		}
    	}

    /**
     * Match a starting <code>OPEN_QUESTION WSPEED CLOSE_TAG</code>, arbitrary
     * 4GL statement text and then <code>CLOSE_QUESTION WSPEED CLOSE_TAG</code>.
     */
    	public final void question_escape() throws RecognitionException, TokenStreamException {

    		Token  oq = null;
    		Token  ws1 = null;
    		Token  ct1 = null;
    		Token  txt = null;
    		Token  cq = null;
    		Token  ws2 = null;
    		Token  ct2 = null;

    		StringBuilder sb = new StringBuilder();

    		try {      // for error handling
    			oq = LT(1);
    			match(OPEN_QUESTION);
    			ws1 = LT(1);
    			match(WSPEED);
    			ct1 = LT(1);
    			match(CLOSE_TAG);

    			oq.setText(String.format("%s%s%s",
    			oq.getText(),
    			ws1.getText(),
    			ct1.getText()));

    			// comment out the open text
    			outputOpenComment(oq, false);

    			{
    			_loop12:
    			do {
    				if ((LA(1)==OPEN_END_TAG||LA(1)==SCRIPT||LA(1)==CLOSE_TAG||LA(1)==OPEN_START_TAG||LA(1)==LANGUAGE||LA(1)==OPEN_QUESTION||LA(1)==WSPEED||LA(1)==OPEN_PCT||LA(1)==CLOSE_PCT||LA(1)==SERVER||LA(1)==OPEN_COMMENT||LA(1)==WSS||LA(1)==WS4GL||LA(1)==CLOSE_COMMENT||LA(1)==BACK_TICK||LA(1)==OPEN_PCT_EQ||LA(1)==OPEN_CURLY_EQ||LA(1)==CLOSE_CURLY_EQ||LA(1)==WSE||LA(1)==META||LA(1)==WSMETA||LA(1)==WS||LA(1)==NAME||LA(1)==HTTP_EQUIV||LA(1)==CONTENT||LA(1)==SYMBOL||LA(1)==EQUALS||LA(1)==DQUOTE||LA(1)==SQUOTE||LA(1)==ENCODED_CHAR||LA(1)==UNKNOWN||LA(1)==CLOSE_TAG_NO_CONTENT||LA(1)==GT||LA(1)==LT||LA(1)==SLASH||LA(1)==PERCENT||LA(1)==EXCLAIM||LA(1)==HYPHEN||LA(1)==UNDERSCORE||LA(1)==DOT||LA(1)==COLON||LA(1)==QUESTION||LA(1)==LEFT_CURLY||LA(1)==RIGHT_CURLY||LA(1)==LETTER||LA(1)==DIGIT||LA(1)==HEX_DIGIT||LA(1)==OTHER||LA(1)==JUNK)) {
    					txt = LT(1);
    					matchNot(CLOSE_QUESTION);

    					sb.append(getTokenText(txt));

    				}
    				else {
    					break _loop12;
    				}

    			} while (true);
    			}

    			output(sb.toString(), true, false);

    			cq = LT(1);
    			match(CLOSE_QUESTION);
    			ws2 = LT(1);
    			match(WSPEED);
    			ct2 = LT(1);
    			match(CLOSE_TAG);

    			cq.setText(String.format("%s%s%s",
    			cq.getText(),
    			ws2.getText(),
    			ct2.getText()));

    			// comment out the close text
    			outputCloseComment(cq, false);

    		}
    		catch (RecognitionException ex) {
    			reportError(ex);
    			recover(ex,_tokenSet_1);
    		}
    	}

    /**
     * Match a starting <code>OPEN_PCT</code>, arbitrary 4GL statement text
     * and then <code>CLOSE_PCT</code>.
     */
    	public final void percent_escape() throws RecognitionException, TokenStreamException {

    		Token  op = null;
    		Token  txt = null;
    		Token  cp = null;

    		StringBuilder sb = new StringBuilder();

    		try {      // for error handling
    			op = LT(1);
    			match(OPEN_PCT);

    			// comment out the open text
    			outputOpenComment(op, false);

    			{
    			_loop15:
    			do {
    				if ((LA(1)==OPEN_END_TAG||LA(1)==SCRIPT||LA(1)==CLOSE_TAG||LA(1)==OPEN_START_TAG||LA(1)==LANGUAGE||LA(1)==OPEN_QUESTION||LA(1)==WSPEED||LA(1)==CLOSE_QUESTION||LA(1)==OPEN_PCT||LA(1)==SERVER||LA(1)==OPEN_COMMENT||LA(1)==WSS||LA(1)==WS4GL||LA(1)==CLOSE_COMMENT||LA(1)==BACK_TICK||LA(1)==OPEN_PCT_EQ||LA(1)==OPEN_CURLY_EQ||LA(1)==CLOSE_CURLY_EQ||LA(1)==WSE||LA(1)==META||LA(1)==WSMETA||LA(1)==WS||LA(1)==NAME||LA(1)==HTTP_EQUIV||LA(1)==CONTENT||LA(1)==SYMBOL||LA(1)==EQUALS||LA(1)==DQUOTE||LA(1)==SQUOTE||LA(1)==ENCODED_CHAR||LA(1)==UNKNOWN||LA(1)==CLOSE_TAG_NO_CONTENT||LA(1)==GT||LA(1)==LT||LA(1)==SLASH||LA(1)==PERCENT||LA(1)==EXCLAIM||LA(1)==HYPHEN||LA(1)==UNDERSCORE||LA(1)==DOT||LA(1)==COLON||LA(1)==QUESTION||LA(1)==LEFT_CURLY||LA(1)==RIGHT_CURLY||LA(1)==LETTER||LA(1)==DIGIT||LA(1)==HEX_DIGIT||LA(1)==OTHER||LA(1)==JUNK)) {
    					txt = LT(1);
    					matchNot(CLOSE_PCT);

    					sb.append(getTokenText(txt));

    				}
    				else {
    					break _loop15;
    				}

    			} while (true);
    			}

    			output(sb.toString(), true, false);

    			cp = LT(1);
    			match(CLOSE_PCT);

    			// comment out the close text
    			outputCloseComment(cp, false);

    		}
    		catch (RecognitionException ex) {
    			reportError(ex);
    			recover(ex,_tokenSet_1);
    		}
    	}

    /**
     * Match a starting <code>OPEN_START_TAG SERVER CLOSE_TAG</code>, arbitrary
     * 4GL statement text and then <code>CLOSE_QUESTION WSPEED CLOSE_TAG</code>.
     */
    	public final void server_escape() throws RecognitionException, TokenStreamException {

    		Token  ot = null;
    		Token  s1 = null;
    		Token  ct1 = null;
    		Token  txt = null;
    		Token  oe = null;
    		Token  s2 = null;
    		Token  ct2 = null;

    		StringBuilder sb = new StringBuilder();

    		try {      // for error handling
    			ot = LT(1);
    			match(OPEN_START_TAG);
    			s1 = LT(1);
    			match(SERVER);
    			ct1 = LT(1);
    			match(CLOSE_TAG);

    			ot.setText(String.format("%s%s%s",
    			ot.getText(),
    			s1.getText(),
    			ct1.getText()));

    			// comment out the open text
    			outputOpenComment(ot, false);

    			{
    			_loop18:
    			do {
    				if (((LA(1) >= SCRIPT && LA(1) <= JUNK))) {
    					txt = LT(1);
    					matchNot(OPEN_END_TAG);

    					sb.append(getTokenText(txt));

    				}
    				else {
    					break _loop18;
    				}

    			} while (true);
    			}

    			output(sb.toString(), true, false);

    			oe = LT(1);
    			match(OPEN_END_TAG);
    			s2 = LT(1);
    			match(SERVER);
    			ct2 = LT(1);
    			match(CLOSE_TAG);

    			oe.setText(String.format("%s%s%s",
    			oe.getText(),
    			s2.getText(),
    			ct2.getText()));

    			// comment out the close text
    			outputCloseComment(oe, false);

    		}
    		catch (RecognitionException ex) {
    			reportError(ex);
    			recover(ex,_tokenSet_1);
    		}
    	}

    /**
     * Match a starting <code>OPEN_COMMENT</code> followed by a <code>WSS</code>
     * or <code>WS4GL</code>, arbitrary 4GL statement text and then
     * <code>CLOSE_COMMENT</code>.
     */
    	public final void wss_escape() throws RecognitionException, TokenStreamException {

    		Token  oc = null;
    		Token  wss = null;
    		Token  ws4gl = null;
    		Token  txt = null;
    		Token  cc = null;

    		StringBuilder sb = new StringBuilder();

    		try {      // for error handling
    			oc = LT(1);
    			match(OPEN_COMMENT);
    			{
    			switch ( LA(1)) {
    			case WSS:
    			{
    				wss = LT(1);
    				match(WSS);
    				break;
    			}
    			case WS4GL:
    			{
    				ws4gl = LT(1);
    				match(WS4GL);
    				break;
    			}
    			default:
    			{
    				throw new NoViableAltException(LT(1), getFilename());
    			}
    			}
    			}

    			Token word = (wss == null) ? ws4gl : wss;
    			oc.setText(String.format("%s%s", oc.getText(), word.getText()));

    			// comment out the open text
    			outputOpenComment(oc, false);

    			{
    			_loop22:
    			do {
    				if ((LA(1)==OPEN_END_TAG||LA(1)==SCRIPT||LA(1)==CLOSE_TAG||LA(1)==OPEN_START_TAG||LA(1)==LANGUAGE||LA(1)==OPEN_QUESTION||LA(1)==WSPEED||LA(1)==CLOSE_QUESTION||LA(1)==OPEN_PCT||LA(1)==CLOSE_PCT||LA(1)==SERVER||LA(1)==OPEN_COMMENT||LA(1)==WSS||LA(1)==WS4GL||LA(1)==BACK_TICK||LA(1)==OPEN_PCT_EQ||LA(1)==OPEN_CURLY_EQ||LA(1)==CLOSE_CURLY_EQ||LA(1)==WSE||LA(1)==META||LA(1)==WSMETA||LA(1)==WS||LA(1)==NAME||LA(1)==HTTP_EQUIV||LA(1)==CONTENT||LA(1)==SYMBOL||LA(1)==EQUALS||LA(1)==DQUOTE||LA(1)==SQUOTE||LA(1)==ENCODED_CHAR||LA(1)==UNKNOWN||LA(1)==CLOSE_TAG_NO_CONTENT||LA(1)==GT||LA(1)==LT||LA(1)==SLASH||LA(1)==PERCENT||LA(1)==EXCLAIM||LA(1)==HYPHEN||LA(1)==UNDERSCORE||LA(1)==DOT||LA(1)==COLON||LA(1)==QUESTION||LA(1)==LEFT_CURLY||LA(1)==RIGHT_CURLY||LA(1)==LETTER||LA(1)==DIGIT||LA(1)==HEX_DIGIT||LA(1)==OTHER||LA(1)==JUNK)) {
    					txt = LT(1);
    					matchNot(CLOSE_COMMENT);

    					sb.append(getTokenText(txt));

    				}
    				else {
    					break _loop22;
    				}

    			} while (true);
    			}

    			output(sb.toString(), true, false);

    			cc = LT(1);
    			match(CLOSE_COMMENT);

    			// comment out the close text
    			outputCloseComment(cc, false);

    		}
    		catch (RecognitionException ex) {
    			reportError(ex);
    			recover(ex,_tokenSet_1);
    		}
    	}

    /**
     * Match <code>OPEN_START_TAG META</code> or <code>OPEN_COMMENT WSMETA</code>,
     * the following <code>NAME</code> or <code>HTTP_EQUIV</code> and then the
     * <code>CONTENT</code> and a closing <code>CLOSE_TAG</code> or
     * <code>CLOSE_COMMENT</code>. This parses the meta tag processing and
     * may set option values that are embedded in the attributes. This is
     * called from {@link #scan_options} and {@link #preprocess}.
     *
     * @param    opts
     *           The options to update with the found values. If <code>null</code>
     *           then this rule matches the given text but does not update any
     *           options even if those attributes are present.
     * @param    sb
     *           The buffer in which to accumulate the parsed text. May be
     *           <code>null</code> to bypass text accumulation.
     *
     * @return   <code>true</code> if the parsed meta tag has an
     *           <code>HTTP-EQUIV</code> attribute with a value of
     *           "content-type".
     */
    	public final boolean  meta_tag(
    		Options opts, StringBuilder sb
    	) throws RecognitionException, TokenStreamException {
    		boolean contype;

    		Token  os = null;
    		Token  m = null;
    		Token  oc = null;
    		Token  wm = null;
    		Token  ws = null;
    		Token  n = null;
    		Token  he = null;
    		Token  c = null;
    		Token  s = null;
    		Token  ct = null;
    		Token  cc = null;

    		boolean wsmeta    = false;
    		boolean wsoptions = false;

    		String  prop      = null;
    		String  content   = null;

    		contype = false;

    		try {      // for error handling
    			{
    			switch ( LA(1)) {
    			case OPEN_START_TAG:
    			{
    				os = LT(1);
    				match(OPEN_START_TAG);
    				m = LT(1);
    				match(META);
    				break;
    			}
    			case OPEN_COMMENT:
    			{
    				oc = LT(1);
    				match(OPEN_COMMENT);
    				wm = LT(1);
    				match(WSMETA);
    				wsmeta = true;
    				break;
    			}
    			default:
    			{
    				throw new NoViableAltException(LT(1), getFilename());
    			}
    			}
    			}

    			if (sb != null)
    			{
    			if (os != null)
    			{
    			sb.append(os.getText()).append(m.getText());
    			}
    			else
    			{
    			sb.append(oc.getText()).append(wm.getText());
    			}
    			}

    			{
    			_loop42:
    			do {
    				switch ( LA(1)) {
    				case WS:
    				{
    					ws = LT(1);
    					match(WS);

    					if (sb != null)
    					{
    					sb.append(ws.getText());
    					}

    					break;
    				}
    				case NAME:
    				{
    					n = LT(1);
    					match(NAME);

    					if (sb != null)
    					{
    					sb.append(n.getText());
    					}

    					prop=attribute_value(sb);

    					if ("wsoptions".equalsIgnoreCase(prop))
    					{
    					wsoptions = true;
    					}

    					break;
    				}
    				case HTTP_EQUIV:
    				{
    					he = LT(1);
    					match(HTTP_EQUIV);

    					if (sb != null)
    					{
    					sb.append(he.getText());
    					}

    					prop=attribute_value(sb);

    					if ("content-type".equalsIgnoreCase(prop))
    					{
    					contype = true;
    					}

    					break;
    				}
    				case CONTENT:
    				{
    					c = LT(1);
    					match(CONTENT);

    					if (sb != null)
    					{
    					sb.append(c.getText());
    					}

    					content=attribute_value(sb);
    					break;
    				}
    				case SYMBOL:
    				{
    					s = LT(1);
    					match(SYMBOL);

    					if (sb != null)
    					{
    					sb.append(s.getText());
    					}

    					prop=attribute_value(sb);
    					break;
    				}
    				default:
    				{
    					break _loop42;
    				}
    				}
    			} while (true);
    			}
    			{
    			if (((LA(1)==CLOSE_TAG))&&( !wsmeta )) {
    				ct = LT(1);
    				match(CLOSE_TAG);
    			}
    			else if ((LA(1)==CLOSE_COMMENT)) {
    				cc = LT(1);
    				match(CLOSE_COMMENT);
    			}
    			else {
    				throw new NoViableAltException(LT(1), getFilename());
    			}

    			}

    			if (sb != null)
    			{
    			sb.append((ct != null) ? ct.getText() : cc.getText());
    			}

    			// only process if there is some content and we are in options
    			// processing mode
    			if (content != null && opts != null)
    			{
    			// only process specific matches to NAME = WSOPTIONS and
    			// to HTTP-EQUIV = CONTENT-TYPE, otherwise ignore
    			if (wsoptions)
    			{
    			opts.processWSOptions(content, true);
    			}
    			else if (contype)
    			{
    			opts.setContentType(content);
    			}
    			}

    		}
    		catch (RecognitionException ex) {
    			reportError(ex);
    			recover(ex,_tokenSet_1);
    		}
    		return contype;
    	}

    /**
     * Match a starting <code>OPEN_START_TAG SCRIPT</code>, arbitrary
     * attributes and then <code>CLOSE_TAG</code>. The attributes will be
     * scanned and if a <code>LANGUAGE</code> attribute with a value of
     * <code>SpeedScript</code>, <code>WebSpeed4GL</code> or <code>Progress</code>
     * is found then this rule will return <code>true</code>. Either way the text
     * of all matched tokens will be returned in the given buffer so that the
     * calling rule may handle the output however is needed.
     *
     * @param    sb
     *           Buffer which will contain all text associated with the parsed
     *           tokens.
     *
     * @return   <code>true</code> if this script element includes a language
     *           attribute that identifies the content as embedded 4GL.
     */
    	public final boolean  script_tag(
    		StringBuilder sb
    	) throws RecognitionException, TokenStreamException {
    		boolean e4gl;

    		Token  ot = null;
    		Token  s = null;
    		Token  l = null;
    		Token  other = null;
    		Token  ct = null;

    		String prop = null;
    		e4gl = false;

    		try {      // for error handling
    			ot = LT(1);
    			match(OPEN_START_TAG);
    			s = LT(1);
    			match(SCRIPT);

    			sb.append(ot.getText()).append(s.getText());

    			{
    			_loop9:
    			do {
    				switch ( LA(1)) {
    				case LANGUAGE:
    				{
    					l = LT(1);
    					match(LANGUAGE);

    					sb.append(l.getText());

    					prop=attribute_value(sb);

    					if ("speedscript".equalsIgnoreCase(prop) ||
    					"webspeed4gl".equalsIgnoreCase(prop) ||
    					"progress".equalsIgnoreCase(prop))
    					{
    					e4gl = true;
    					}

    					break;
    				}
    				case OPEN_END_TAG:
    				case SCRIPT:
    				case OPEN_START_TAG:
    				case OPEN_QUESTION:
    				case WSPEED:
    				case CLOSE_QUESTION:
    				case OPEN_PCT:
    				case CLOSE_PCT:
    				case SERVER:
    				case OPEN_COMMENT:
    				case WSS:
    				case WS4GL:
    				case CLOSE_COMMENT:
    				case BACK_TICK:
    				case OPEN_PCT_EQ:
    				case OPEN_CURLY_EQ:
    				case CLOSE_CURLY_EQ:
    				case WSE:
    				case META:
    				case WSMETA:
    				case WS:
    				case NAME:
    				case HTTP_EQUIV:
    				case CONTENT:
    				case SYMBOL:
    				case EQUALS:
    				case DQUOTE:
    				case SQUOTE:
    				case ENCODED_CHAR:
    				case UNKNOWN:
    				case CLOSE_TAG_NO_CONTENT:
    				case GT:
    				case LT:
    				case SLASH:
    				case PERCENT:
    				case EXCLAIM:
    				case HYPHEN:
    				case UNDERSCORE:
    				case DOT:
    				case COLON:
    				case QUESTION:
    				case LEFT_CURLY:
    				case RIGHT_CURLY:
    				case LETTER:
    				case DIGIT:
    				case HEX_DIGIT:
    				case OTHER:
    				case JUNK:
    				{
    					other = LT(1);
    					matchNot(CLOSE_TAG);

    					sb.append(other.getText());

    					break;
    				}
    				default:
    				{
    					break _loop9;
    				}
    				}
    			} while (true);
    			}
    			ct = LT(1);
    			match(CLOSE_TAG);

    			sb.append(ct.getText());

    		}
    		catch (RecognitionException ex) {
    			reportError(ex);
    			recover(ex,_tokenSet_2);
    		}
    		return e4gl;
    	}

    /**
     * Parse the <code>=</code> followed by a <code>SYMBOL</code> or
     * <code>STRING</code>. Whitespace on either side of the <code>EQUALS</code>
     * is tolerated.
     *
     * @param    sb
     *           Buffer in which to store all matched text if not
     *           <code>null</code>.
     *
     * @return   The text of the <code>SYMBOL</code> or <code>STRING</code>.
     */
    	public final String  attribute_value(
    		StringBuilder sb
    	) throws RecognitionException, TokenStreamException {
    		String txt;

    		Token  ws1 = null;
    		Token  eq = null;
    		Token  ws2 = null;
    		Token  s1 = null;

    		txt = null;

    		try {      // for error handling
    			{
    			switch ( LA(1)) {
    			case WS:
    			{
    				ws1 = LT(1);
    				match(WS);
    				break;
    			}
    			case EQUALS:
    			{
    				break;
    			}
    			default:
    			{
    				throw new NoViableAltException(LT(1), getFilename());
    			}
    			}
    			}
    			eq = LT(1);
    			match(EQUALS);
    			{
    			switch ( LA(1)) {
    			case WS:
    			{
    				ws2 = LT(1);
    				match(WS);
    				break;
    			}
    			case SYMBOL:
    			case DQUOTE:
    			case SQUOTE:
    			{
    				break;
    			}
    			default:
    			{
    				throw new NoViableAltException(LT(1), getFilename());
    			}
    			}
    			}
    			{
    			switch ( LA(1)) {
    			case SYMBOL:
    			{
    				s1 = LT(1);
    				match(SYMBOL);
    				break;
    			}
    			case DQUOTE:
    			case SQUOTE:
    			{
    				txt=string();
    				break;
    			}
    			default:
    			{
    				throw new NoViableAltException(LT(1), getFilename());
    			}
    			}
    			}

    			if (s1 != null)
    			txt = s1.getText();

    			// capture all the text if needed
    			if (sb != null)
    			{
    			if (ws1 != null)
    			sb.append(ws1.getText());

    			sb.append(eq.getText());

    			if (ws2 != null)
    			sb.append(ws2.getText());

    			sb.append(txt);
    			}

    			if (s1 == null)
    			{
    			// remove the enclosing quotes
    			txt = txt.substring(1, txt.length() - 1);
    			}

    			// no need for leading or trailing whitespace
    			txt = txt.trim();

    		}
    		catch (RecognitionException ex) {
    			reportError(ex);
    			recover(ex,_tokenSet_2);
    		}
    		return txt;
    	}

    /**
     * Top-level entry point that parses the input stream to read the E4GL
     * options embedded in any <code>META</code> or <code>WSMETA</code> elements.
     * <p>
     * Uses {@link #meta_tag} to parse the options themselves. Anything else
     * is simply ignored until <code>EOF</code>.
     *
     * @param    opts
     *           Storage container for the options that are found.
     */
    	public final void scan_options(
    		Options opts
    	) throws RecognitionException, TokenStreamException {

    		try {      // for error handling

    			boolean bogus;

    			{
    			_loop38:
    			do {
    				if ((LA(1)==OPEN_START_TAG||LA(1)==OPEN_COMMENT) && (LA(2)==META||LA(2)==WSMETA)) {
    					bogus=meta_tag(opts, null);
    				}
    				else if (((LA(1) >= OPEN_END_TAG && LA(1) <= JUNK)) && (LA(2)==EOF||LA(2)==OPEN_END_TAG||LA(2)==SCRIPT||LA(2)==CLOSE_TAG||LA(2)==OPEN_START_TAG||LA(2)==LANGUAGE||LA(2)==OPEN_QUESTION||LA(2)==WSPEED||LA(2)==CLOSE_QUESTION||LA(2)==OPEN_PCT||LA(2)==CLOSE_PCT||LA(2)==SERVER||LA(2)==OPEN_COMMENT||LA(2)==WSS||LA(2)==WS4GL||LA(2)==CLOSE_COMMENT||LA(2)==BACK_TICK||LA(2)==OPEN_PCT_EQ||LA(2)==OPEN_CURLY_EQ||LA(2)==CLOSE_CURLY_EQ||LA(2)==WSE||LA(2)==META||LA(2)==WSMETA||LA(2)==WS||LA(2)==NAME||LA(2)==HTTP_EQUIV||LA(2)==CONTENT||LA(2)==SYMBOL||LA(2)==EQUALS||LA(2)==DQUOTE||LA(2)==SQUOTE||LA(2)==ENCODED_CHAR||LA(2)==UNKNOWN||LA(2)==CLOSE_TAG_NO_CONTENT||LA(2)==GT||LA(2)==LT||LA(2)==SLASH||LA(2)==PERCENT||LA(2)==EXCLAIM||LA(2)==HYPHEN||LA(2)==UNDERSCORE||LA(2)==DOT||LA(2)==COLON||LA(2)==QUESTION||LA(2)==LEFT_CURLY||LA(2)==RIGHT_CURLY||LA(2)==LETTER||LA(2)==DIGIT||LA(2)==HEX_DIGIT||LA(2)==OTHER||LA(2)==JUNK)) {
    					matchNot(EOF);
    				}
    				else {
    					break _loop38;
    				}

    			} while (true);
    			}
    			match(Token.EOF_TYPE);
    		}
    		catch (RecognitionException ex) {
    			reportError(ex);
    			recover(ex,_tokenSet_0);
    		}
    	}

    /**
     * Matches various string types (data delimited by two matching single or
     * double quote characters). This is not implemented in the lexer since
     * there is no lookahead that can inform the lexer when it needs to match
     * paired quotes versus when it is acceptable for the quote characters to
     * stand alone. Since both are possible depending on parser context AND
     * since there is no reliable way to share state between the parser and
     * lexer, it was necessary to move the matching here.
     * <p>
     * Uses {@link #sstring} and {@link #dstring}.
     *
     * @return   The parsed string text.
     */
    	public final String  string() throws RecognitionException, TokenStreamException {
    		String txt;

    		txt = null;

    		try {      // for error handling
    			switch ( LA(1)) {
    			case DQUOTE:
    			{
    				txt=dstring();
    				break;
    			}
    			case SQUOTE:
    			{
    				txt=sstring();
    				break;
    			}
    			default:
    			{
    				throw new NoViableAltException(LT(1), getFilename());
    			}
    			}
    		}
    		catch (RecognitionException ex) {
    			reportError(ex);
    			recover(ex,_tokenSet_2);
    		}
    		return txt;
    	}

    /**
     * Matches any data delimited by two matching double quote characters.
     * <p>
     * See {@link #string}.
     *
     * @return   The parsed string text.
     */
    	public final String  dstring() throws RecognitionException, TokenStreamException {
    		String retstr;

    		Token  start = null;
    		Token  txt = null;
    		Token  end = null;

    		StringBuilder sb = new StringBuilder();
    		retstr = null;

    		try {      // for error handling
    			start = LT(1);
    			match(DQUOTE);
    			sb.append(start.getText());
    			{
    			_loop51:
    			do {
    				if ((LA(1)==OPEN_END_TAG||LA(1)==SCRIPT||LA(1)==CLOSE_TAG||LA(1)==OPEN_START_TAG||LA(1)==LANGUAGE||LA(1)==OPEN_QUESTION||LA(1)==WSPEED||LA(1)==CLOSE_QUESTION||LA(1)==OPEN_PCT||LA(1)==CLOSE_PCT||LA(1)==SERVER||LA(1)==OPEN_COMMENT||LA(1)==WSS||LA(1)==WS4GL||LA(1)==CLOSE_COMMENT||LA(1)==BACK_TICK||LA(1)==OPEN_PCT_EQ||LA(1)==OPEN_CURLY_EQ||LA(1)==CLOSE_CURLY_EQ||LA(1)==WSE||LA(1)==META||LA(1)==WSMETA||LA(1)==WS||LA(1)==NAME||LA(1)==HTTP_EQUIV||LA(1)==CONTENT||LA(1)==SYMBOL||LA(1)==EQUALS||LA(1)==SQUOTE||LA(1)==ENCODED_CHAR||LA(1)==UNKNOWN||LA(1)==CLOSE_TAG_NO_CONTENT||LA(1)==GT||LA(1)==LT||LA(1)==SLASH||LA(1)==PERCENT||LA(1)==EXCLAIM||LA(1)==HYPHEN||LA(1)==UNDERSCORE||LA(1)==DOT||LA(1)==COLON||LA(1)==QUESTION||LA(1)==LEFT_CURLY||LA(1)==RIGHT_CURLY||LA(1)==LETTER||LA(1)==DIGIT||LA(1)==HEX_DIGIT||LA(1)==OTHER||LA(1)==JUNK)) {
    					txt = LT(1);
    					matchNot(DQUOTE);
    					sb.append(txt.getText());
    				}
    				else {
    					break _loop51;
    				}

    			} while (true);
    			}
    			end = LT(1);
    			match(DQUOTE);

    			sb.append(start.getText());
    			retstr = sb.toString();

    		}
    		catch (RecognitionException ex) {
    			reportError(ex);
    			recover(ex,_tokenSet_2);
    		}
    		return retstr;
    	}

    /**
     * Matches any data delimited by two matching single quote characters.
     * <p>
     * See {@link #string}.
     *
     * @return   The parsed string text.
     */
    	public final String  sstring() throws RecognitionException, TokenStreamException {
    		String retstr;

    		Token  start = null;
    		Token  txt = null;
    		Token  end = null;

    		StringBuilder sb = new StringBuilder();
    		retstr = null;

    		try {      // for error handling
    			start = LT(1);
    			match(SQUOTE);
    			sb.append(start.getText());
    			{
    			_loop54:
    			do {
    				if ((LA(1)==OPEN_END_TAG||LA(1)==SCRIPT||LA(1)==CLOSE_TAG||LA(1)==OPEN_START_TAG||LA(1)==LANGUAGE||LA(1)==OPEN_QUESTION||LA(1)==WSPEED||LA(1)==CLOSE_QUESTION||LA(1)==OPEN_PCT||LA(1)==CLOSE_PCT||LA(1)==SERVER||LA(1)==OPEN_COMMENT||LA(1)==WSS||LA(1)==WS4GL||LA(1)==CLOSE_COMMENT||LA(1)==BACK_TICK||LA(1)==OPEN_PCT_EQ||LA(1)==OPEN_CURLY_EQ||LA(1)==CLOSE_CURLY_EQ||LA(1)==WSE||LA(1)==META||LA(1)==WSMETA||LA(1)==WS||LA(1)==NAME||LA(1)==HTTP_EQUIV||LA(1)==CONTENT||LA(1)==SYMBOL||LA(1)==EQUALS||LA(1)==DQUOTE||LA(1)==ENCODED_CHAR||LA(1)==UNKNOWN||LA(1)==CLOSE_TAG_NO_CONTENT||LA(1)==GT||LA(1)==LT||LA(1)==SLASH||LA(1)==PERCENT||LA(1)==EXCLAIM||LA(1)==HYPHEN||LA(1)==UNDERSCORE||LA(1)==DOT||LA(1)==COLON||LA(1)==QUESTION||LA(1)==LEFT_CURLY||LA(1)==RIGHT_CURLY||LA(1)==LETTER||LA(1)==DIGIT||LA(1)==HEX_DIGIT||LA(1)==OTHER||LA(1)==JUNK)) {
    					txt = LT(1);
    					matchNot(SQUOTE);
    					sb.append(txt.getText());
    				}
    				else {
    					break _loop54;
    				}

    			} while (true);
    			}
    			end = LT(1);
    			match(SQUOTE);

    			sb.append(start.getText());
    			retstr = sb.toString();

    		}
    		catch (RecognitionException ex) {
    			reportError(ex);
    			recover(ex,_tokenSet_2);
    		}
    		return retstr;
    	}

    	public static final String[] _tokenNames = {
    		"<0>",
    		"EOF",
    		"<2>",
    		"NULL_TREE_LOOKAHEAD",
    		"OPEN_END_TAG",
    		"\"script\"",
    		"CLOSE_TAG",
    		"OPEN_START_TAG",
    		"\"language\"",
    		"OPEN_QUESTION",
    		"\"ws\"",
    		"CLOSE_QUESTION",
    		"OPEN_PCT",
    		"CLOSE_PCT",
    		"\"server\"",
    		"OPEN_COMMENT",
    		"\"wss\"",
    		"\"ws4gl\"",
    		"CLOSE_COMMENT",
    		"BACK_TICK",
    		"OPEN_PCT_EQ",
    		"OPEN_CURLY_EQ",
    		"CLOSE_CURLY_EQ",
    		"\"wse\"",
    		"\"meta\"",
    		"\"wsmeta\"",
    		"WS",
    		"\"name\"",
    		"\"http-equiv\"",
    		"\"content\"",
    		"SYMBOL",
    		"EQUALS",
    		"DQUOTE",
    		"SQUOTE",
    		"ENCODED_CHAR",
    		"UNKNOWN",
    		"CLOSE_TAG_NO_CONTENT",
    		"GT",
    		"LT",
    		"SLASH",
    		"PERCENT",
    		"EXCLAIM",
    		"HYPHEN",
    		"UNDERSCORE",
    		"DOT",
    		"COLON",
    		"QUESTION",
    		"LEFT_CURLY",
    		"RIGHT_CURLY",
    		"LETTER",
    		"DIGIT",
    		"HEX_DIGIT",
    		"OTHER",
    		"JUNK"
    	};

    	private static final long[] mk_tokenSet_0() {
    		long[] data = { 2L, 0L};
    		return data;
    	}
    	public static final BitSet _tokenSet_0 = new BitSet(mk_tokenSet_0());
    	private static final long[] mk_tokenSet_1() {
    		long[] data = { 18014398509481970L, 0L, 0L, 0L};
    		return data;
    	}
    	public static final BitSet _tokenSet_1 = new BitSet(mk_tokenSet_1());
    	private static final long[] mk_tokenSet_2() {
    		long[] data = { 18014398509481968L, 0L, 0L, 0L};
    		return data;
    	}
    	public static final BitSet _tokenSet_2 = new BitSet(mk_tokenSet_2());

    	}