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());
	
	}