# TextParser.java

    // $ANTLR 2.7.7 (20060906): "text.g" -> "TextParser.java"$

    /*
    ** Module   : TextLexer.java
    **            TextParser.java
    **            PreprocTokenTypes.java
    ** Abstract : This grammar is the top level recognizer of the Progress
    **            language preprocessor input. It recognizes tabs, nested
    **            comments, single and double quoted multiline strings and
    **            the code.
    **
    ** Copyright (c) 2004-2019, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- -T- --JPRM-- ----------------Description-----------------
    ** 001 GES 20041116 ADD   @18832 WARNING, THIS IS A GENERATED FILE!!!
    **                               DO NOT EDIT THIS FILE. The original source
    **                               file is text.g!
    */

    package com.goldencode.p2j.preproc;

    import java.io.*;
    import java.util.*;
    import java.util.logging.*;
    import antlr.collections.AST;
    import antlr.collections.impl.*;
    import antlr.debug.misc.*;
    import antlr.*;
    import com.goldencode.util.*;
    import com.goldencode.p2j.convert.*;
    import com.goldencode.p2j.util.*;

    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;

    /**
     * Declares the entry point class of this grammar.
     * This grammar takes a Progress source file and starts parsing it
     * to a degree necessary for performing the preprocessing only.
     * The preprocessing is done on the go without creating an AST tree
     * first. This is possible due to a limited amount of transformations
     * that has to be done to the input.
     * <p>
     * The parsing starts when a driving code calls the
     * <code>{@link #text()}</code>
     * method of this class. The processed output is written to an output
     * stream as the parsing progresses. As soon as the parser reaches
     * the end of file, the preprocessor is done.
     * <p>
     * The parser calls the lexer's <code>nextToken</code> method and works
     * with the stream of <code>Token</code> objects. So, all the details
     * of tokenizations are hidden in the lexer. The lexer, in turn, reads
     * its input character by character from an input stream. The input
     * stream is an instance of the <code>{@link ClearStream}</code> class
     * that hides from the lexer some essential complexity of the preprocessing
     * like handling the alternative codings, escape sequences and substitutions
     * for braces.
     * <p>
     * The parser recognizes and properly handles the following constructs:
     * <ul>
     *   <li>regular Progress code on input is copied to output according
     *       to the conditional generation currently in effect;
     *   <li>tabs are expanded on output;
     *   <li>other white spaces are preserved on output;
     *   <li>Progress language strings and comments are recognized because
     *       they affect the workings of the preprocessor;
     *   <li>preprocessor statements are recognized and processed;
     * </ul>
     * @see  TextLexer
     * @see  BracesParser
     * @see  BracesLexer
     */
    public class TextParser extends antlr.LLkParser       implements PreprocTokenTypes
     {

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

       /** Keeps a reference to the shared environment. */
       private Environment env = null;

       /** Nesting level for text block processing. */
       private int nested = 0;

       /** Tracks nesting level for conditional preproc directives. */
       private int condNesting = 0;

       /**
        * Constructor. Creates a parser attached to the token stream
        * selector taken from the environment. Saves the environment
        * for future needs.
        *
        * @param    lexer
        *           The lexer for this instance.
        * @param    env
        *           The shared preprocessor environment.
        */
       public TextParser(TokenStream lexer, Environment env)
       {
          this(lexer);
          this.env = env;
          this.env.setPsi(this.getInputState());
       }

       /**
        * 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);
       }

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

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

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

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

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

    /**
     * Matches any interpretable block of text from the Progress source
     * file. This can be either the top level source text or any block
     * of text following <code>&amp;THEN</code> or <code>&amp;ELSE</code>
     * statements when their appropriate preprocessor expressions evaluate
     * to those clauses.
     *
     * @throws      antlr.RecognitionException
     * @throws      antlr.TokenStreamException
     * @throws      IOException
     */
    	public final void text() throws RecognitionException, TokenStreamException, IOException {

    		try {      // for error handling
    			textBlock();
    			match(Token.EOF_TYPE);
    		}
    		catch (RecognitionException ex) {
    			reportError(ex);
    			recover(ex,_tokenSet_0);
    		}
    	}

    /**
     * Matches any interpretable block of text from the Progress source
     * file. This can be either the top level source text or any block
     * of text following <code>&amp;THEN</code> or <code>&amp;ELSE</code>
     * statements when their appropriate preprocessor expressions evaluate
     * to those clauses.
     *
     * @throws      antlr.RecognitionException
     * @throws      antlr.TokenStreamException
     * @throws      IOException
     */
    	public final void textBlock() throws RecognitionException, TokenStreamException, IOException {

    		Token  t = null;

    		try {      // for error handling

    			// track our nesting level
    			nested++;

    			// cache off the in stmt flag
    			boolean inStmt = env.isInStatement();

    			// are we nested? (this can only happen due to an &IF)
    			if (nested > 1 && inStmt)
    			{
    			// disable while here
    			env.setInStatement(false);
    			env.clearDeferred();
    			}

    			{
    			_loop5:
    			do {
    				if ((_tokenSet_1.member(LA(1))) && (_tokenSet_2.member(LA(2)))) {
    					ppstatement();
    				}
    				else if ((_tokenSet_3.member(LA(1))) && (_tokenSet_2.member(LA(2)))) {

    					// cache off the in stmt flag (again, at this nested level)
    					boolean stillInStmt = env.isInStatement();

    					// are we nested? (this can only happen due to an &IF)
    					if (nested > 1 && stillInStmt)
    					{
    					// disable while here
    					env.setInStatement(false);
    					env.clearDeferred();
    					}

    					{
    					t = LT(1);
    					match(_tokenSet_3);
    					}

    					env.print(t.getText());

    					// need to reset inStatement at bottom of alternative if we
    					// turned it off at top
    					if (nested > 1 && stillInStmt)
    					{
    					env.setInStatement(true);
    					}

    				}
    				else {
    					break _loop5;
    				}

    			} while (true);
    			}

    			// if we are in a nested block
    			if (nested > 1)
    			{
    			// restore our saved state
    			env.setInStatement(inStmt);
    			}

    			// clear our nesting level
    			nested--;

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

    /**
     * Matches any Progress preprocessor statement, even mistyped one.
     *
     * @throws      antlr.RecognitionException
     * @throws      antlr.TokenStreamException
     * @throws      IOException
     */
    	public final void ppstatement() throws RecognitionException, TokenStreamException, IOException {

    		try {      // for error handling

    			// the lexer should already have setInStatement(true) during
    			// lookahead processing, but this is here as safety code
    			if (!env.isInStatement())
    			{
    			// should never trigger
    			env.setInStatement(true);
    			}

    			{
    			switch ( LA(1)) {
    			case AGLOBAL:
    			{
    				globdef();
    				break;
    			}
    			case ASCOPED:
    			{
    				scopdef();
    				break;
    			}
    			case AUNDEFINE:
    			{
    				undefine();
    				break;
    			}
    			case AMESSAGE:
    			{
    				message();
    				break;
    			}
    			case ASUSPEND:
    			case ARESUME:
    			{
    				noop();
    				break;
    			}
    			case AIF:
    			{
    				aif();
    				break;
    			}
    			case ASTMT:
    			{
    				astmt();
    				break;
    			}
    			default:
    			{
    				throw new NoViableAltException(LT(1), getFilename());
    			}
    			}
    			}

    			env.setInStatement(false);
    			env.clearDeferred();

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

    /**
     * Matches the <code>&amp;GLOBAL-DEFINE</code> Progress preprocessor statement.
     */
    	public final void globdef() throws RecognitionException, TokenStreamException, IOException {

    		try {      // for error handling
    			match(AGLOBAL);
    			define(true);
    		}
    		catch (RecognitionException ex) {
    			reportError(ex);
    			recover(ex,_tokenSet_2);
    		}
    	}

    /**
     * Matches the <code>&amp;SCOPED-DEFINE</code> Progress preprocessor statement.
     */
    	public final void scopdef() throws RecognitionException, TokenStreamException, IOException {

    		try {      // for error handling
    			match(ASCOPED);
    			define(false);
    		}
    		catch (RecognitionException ex) {
    			reportError(ex);
    			recover(ex,_tokenSet_2);
    		}
    	}

    /**
      * Matches <code>&amp;UNDEFINE</code> preprocessor statement and removes
      * the first found definition of the preprocessor variable in the nearest
      * scope. Contrary to the parsing of {@link #define} which consumes all
      * text up to the end of the line, this directive only consumes whitespace
      * followed by a single preprocessor name.
      */
    	public final void undefine() throws RecognitionException, TokenStreamException, IOException {

    		Token  c = null;

    		String name   = null;
    		int    line   = 0;
    		int    column = 0;

    		// after the ppname rule is called, the ClearStream may have already
    		// popped our scope, so we cache the possible names here so that we can
    		// check if the name was already removed because the scope was popped;
    		// this occurs when the UNDEFINE directive is the very last text in
    		// an include file, which causes the popping to occur before the name
    		// is parsed here
    		ScopedSymbolDictionary ssd = env.getSym();
    		Set<String> poppedNames = ssd.keySet(0);

    		try {      // for error handling
    			match(AUNDEFINE);
    			{
    			int _cnt18=0;
    			_loop18:
    			do {
    				if ((LA(1)==WS)) {
    					match(WS);
    				}
    				else if ((LA(1)==STAR_COMMENT) && (_tokenSet_4.member(LA(2)))) {
    					c = LT(1);
    					match(STAR_COMMENT);
    					env.print(c.getText());
    				}
    				else {
    					if ( _cnt18>=1 ) { break _loop18; } else {throw new NoViableAltException(LT(1), getFilename());}
    				}

    				_cnt18++;
    			} while (true);
    			}

    			line   = env.getLex().getLine();
    			column = env.getLex().getColumn();

    			name=ppname();

    			// undefine the nearest definition of the symbol, if not defined,
    			// issue an error message
    			if (!ssd.deleteSymbol(name) && !poppedNames.contains(name))
    			{
    			env.eprint("symbol '" + name + "' not defined.", line, column);
    			}

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

    /**
      * Matches <code>&amp;MESSAGE</code> preprocessor statement and prints
      * the message text into the error stream without incrementing the errors
      * count.
      */
    	public final void message() throws RecognitionException, TokenStreamException, IOException {

    		Token  c2 = null;
    		Token  rst = null;
    		Token  nl = null;

    		StringBuffer rest = new StringBuffer();

    		try {      // for error handling
    			match(AMESSAGE);
    			{
    			_loop21:
    			do {
    				switch ( LA(1)) {
    				case STAR_COMMENT:
    				{
    					c2 = LT(1);
    					match(STAR_COMMENT);
    					env.print(c2.getText());
    					break;
    				}
    				case TAB:
    				case WS:
    				case COMMENT:
    				case COMM_OPEN:
    				case CODE:
    				case COMM_CLOSE:
    				case LBRACE:
    				case RBRACE:
    				case APOST:
    				case QUOTE:
    				case XAPOST:
    				case XQUOTE:
    				case AGLOBAL:
    				case ASCOPED:
    				case AMESSAGE:
    				case AUNDEFINE:
    				case AIF:
    				case ATHEN:
    				case AELSEIF:
    				case AELSE:
    				case AENDIF:
    				case ASUSPEND:
    				case ARESUME:
    				case ASTMT:
    				case STAR:
    				case AMPER:
    				case PPNAME:
    				case ALPHA:
    				case SPECIAL:
    				case DIGIT:
    				case EQUALS:
    				case ASTRING:
    				case QSTRING:
    				case STRING:
    				case SLASH_SLASH:
    				case BREAK_CODE_CHUNKS:
    				{
    					rst = LT(1);
    					matchNot(NL);

    					String content = rst.getText();

    					if (rst.getType() == STRING)
    					{
    					// Progress has a weird behavior here where it drops comments out of the
    					// message output even when the comments are inside a string!
    					// WARNING: This suggests they ignore strings in this mode so we probably
    					//          have a future bug here where there are unmatched quotes in a
    					//          compile-time message and it hoses up the preprocessing for us.
    					content = StringHelper.stripMatchedComments(content);
    					}

    					rest.append(content);

    					break;
    				}
    				default:
    				{
    					break _loop21;
    				}
    				}
    			} while (true);
    			}
    			nl = LT(1);
    			match(NL);

    			env.mprint(StringHelper.safeTrimLeading(rest.toString()), nl.getLine());

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

    /**
      * Matches the <code>&amp;ANALYZE-SUSPEND</code> and <code>&amp;ANALYZE-RESUME</code>
      * preprocessor statements.  Everything is parsed to the end of the line
      * and is dropped.  The newline is preserved in the output.
      */
    	public final void noop() throws RecognitionException, TokenStreamException, IOException {

    		Token  c = null;
    		Token  junk = null;

    		try {      // for error handling
    			{
    			switch ( LA(1)) {
    			case ASUSPEND:
    			{
    				match(ASUSPEND);
    				break;
    			}
    			case ARESUME:
    			{
    				match(ARESUME);
    				break;
    			}
    			default:
    			{
    				throw new NoViableAltException(LT(1), getFilename());
    			}
    			}
    			}
    			{
    			_loop25:
    			do {
    				if ((LA(1)==STAR_COMMENT) && (_tokenSet_2.member(LA(2)))) {
    					c = LT(1);
    					match(STAR_COMMENT);
    					env.print(c.getText());
    				}
    				else if (((_tokenSet_5.member(LA(1))) && (_tokenSet_2.member(LA(2))))&&( LA(1) != EOF )) {
    					junk = LT(1);
    					matchNot(NL);

    					StringBuffer sb = new StringBuffer(junk.getText());

    					// if we are placed at the end of an include file, then the closing
    					// include marker sequence will be placed here in front of EOF so
    					// we need to process the markers
    					env.filter(sb, false);

    				}
    				else {
    					break _loop25;
    				}

    			} while (true);
    			}
    			{
    			if ((LA(1)==NL) && (_tokenSet_2.member(LA(2)))) {
    				match(NL);

    				env.print("\n");

    			}
    			else if (((_tokenSet_2.member(LA(1))) && (_tokenSet_2.member(LA(2))))&&( LA(1) == EOF )) {
    			}
    			else {
    				throw new NoViableAltException(LT(1), getFilename());
    			}

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

    /**
     * Matches the <code>&amp;IF</code> Progress preprocessor statement.
     *
     * @throws      antlr.RecognitionException
     * @throws      antlr.TokenStreamException
     * @throws      IOException
     */
    	public final void aif() throws RecognitionException, TokenStreamException, IOException {

    		Token  tmp = null;

    		try {      // for error handling
    			tmp = LT(1);
    			match(AIF);

    			condNesting++;
    			// String filename = ((FileScope)(env.getSym().getScope())).getFileName();
    			// System.out.printf("&IF level %d, filename %s, line %d, col %d\n", condNesting, filename, tmp.getLine(), tmp.getColumn());

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

    /**
     * Matches any mistyped or unrecognized Progress preprocessor statement.
     *
     * @throws      antlr.RecognitionException
     * @throws      antlr.TokenStreamException
     */
    	public final void astmt() throws RecognitionException, TokenStreamException {

    		Token  s = null;

    		try {      // for error handling
    			s = LT(1);
    			match(ASTMT);

    			env.eprint("unrecognized statement '" + s.getText() + "'", s.getLine(), s.getColumn());

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

    /**
     * Matches <code>&amp;GLOBAL-DEFINE</code> and <code>&amp;SCOPED-DEFINE</code>
     * preprocessor directives and creates newly defined preprocessor variable
     * in the corresponding scope. This consumes everything up to the end of
     * the line and uses the text (trimmed of spaces at the front and back) as
     * the value of the preprocessor variable.
     *
     * @param    global
     *           <code>true</code> if this is a <code>&amp;GLOBAL-DEFINE</code> and
     *           <code>false</code> for <code>&amp;SCOPED-DEFINE</code>.
     */
    	public final void define(
    		boolean global
    	) throws RecognitionException, TokenStreamException, IOException {

    		Token  c = null;
    		Token  def = null;

    		String name = null;
    		StringBuilder definition = new StringBuilder();
    		int line = 0;
    		int column = 0;

    		env.setInDefine(true);

    		try {      // for error handling
    			{
    			int _cnt12=0;
    			_loop12:
    			do {
    				if ((LA(1)==WS)) {
    					match(WS);
    				}
    				else {
    					if ( _cnt12>=1 ) { break _loop12; } else {throw new NoViableAltException(LT(1), getFilename());}
    				}

    				_cnt12++;
    			} while (true);
    			}

    			line   = env.getLex().getLine();
    			column = env.getLex().getColumn();

    			name=ppname();
    			{
    			_loop15:
    			do {
    				if ((LA(1)==STAR_COMMENT) && ((LA(2) >= TAB && LA(2) <= BREAK_CODE_CHUNKS))) {
    					c = LT(1);
    					match(STAR_COMMENT);
    					env.print(c.getText());
    				}
    				else if ((_tokenSet_4.member(LA(1))) && ((LA(2) >= TAB && LA(2) <= BREAK_CODE_CHUNKS))) {
    					{
    					def = LT(1);
    					match(_tokenSet_4);
    					}
    					definition.append(def.getText());
    				}
    				else {
    					break _loop15;
    				}

    			} while (true);
    			}
    			match(NL);

    			env.setInDefine(false);

    			// the definition may have pending markers, process them
    			StringBuffer unclean = new StringBuffer(definition);
    			definition = new StringBuilder(env.filter(unclean, false));

    			// remove any leading blanks
    			while (definition.length() > 0 && definition.charAt(0) == ' ')
    			{
    			definition.deleteCharAt(0);
    			}

    			// remove any trailing blanks
    			while (definition.length() > 0 && definition.charAt(definition.length() - 1) == ' ')
    			{
    			definition.setLength(definition.length() - 1);
    			}

    			// remove any tildes that may have been left in '~{' pairs
    			// while(definition.length() > 0 && definition.indexOf("~{") >= 0)
    			//    definition.deleteCharAt(definition.indexOf("~{"));

    			// as far as we know, there are no real syntax rules for the name
    			// so there is no known checks that need to be applied here

    			// lookup the name to see if it already exists
    			ScopedSymbolDictionary sym = env.getSym();
    			Symbol cur = (Symbol) sym.lookupSymbol(name);

    			// check to see if the name is for a builtin variable
    			if (cur != null && cur.getOrigin() == Symbol.BUILTIN)
    			{
    			env.eprint("cannot redefine builtin variable " + name,
    			line,
    			column);
    			return;
    			}

    			if (global)
    			{
    			// global definitions can be added if they don't already exist
    			// and they can be overridden if they only exist as global defs
    			// (but the override will fail if the name already exists as
    			// a scoped definition or as an argument); builtins can't be
    			// overridden either but they are handled above
    			if (cur == null || cur.getOrigin() == Symbol.GLOBAL)
    			{
    			sym.addSymbol(true,
    			name,
    			new Symbol(Symbol.GLOBAL, definition));
    			}
    			else
    			{
    			// TODO: Check if this "silent bypass if the values are the
    			//       same" logic is actually how the 4GL preproc works.
    			//       This behavior was found in a customer app and this is
    			//       just a theory.
    			if (!cur.getValue().equals(definition.toString()))
    			{
    			String spec =
    			"Invalid global redefinition of preprocessor name '%s'." +
    			" (2967)";

    			env.eprint(String.format(spec, name), line, column);
    			}
    			}
    			}
    			else
    			{
    			// put the symbol definition into the locally scoped dictionary
    			sym.addSymbol(false,
    			name,
    			new Symbol(Symbol.SCOPED, definition));
    			}

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

    /**
      * Matches sequence of tokens that make a preprocessor variable name.
      *
      * @return  the gathered variable name as a string
      *
      * @throws      antlr.RecognitionException
      * @throws      antlr.TokenStreamException
      * @throws      IOException
      */
    	public final String  ppname() throws RecognitionException, TokenStreamException, IOException {
    		String s;

    		Token  c = null;
    		Token  t = null;

    		StringBuilder buf = new StringBuilder();
    		s = null;

    		try {      // for error handling
    			{
    			int _cnt30=0;
    			_loop30:
    			do {
    				if ((LA(1)==STAR_COMMENT) && (_tokenSet_2.member(LA(2)))) {
    					c = LT(1);
    					match(STAR_COMMENT);
    					env.print(c.getText());
    				}
    				else if ((_tokenSet_6.member(LA(1))) && (_tokenSet_2.member(LA(2)))) {
    					{
    					t = LT(1);
    					match(_tokenSet_6);
    					}
    					buf.append(t.getText());
    				}
    				else {
    					if ( _cnt30>=1 ) { break _loop30; } else {throw new NoViableAltException(LT(1), getFilename());}
    				}

    				_cnt30++;
    			} while (true);
    			}

    			s = buf.toString();

    			// in some extreme cases of stupid pp tricks, ppname references can have their own meta-references
    			// inside them; these can happen before we set the inStatement flag which means they can appear
    			// in our name; we must remove them now
    			if (s.indexOf(env.getOpt().getMarker()) != -1)
    			{
    			// LOG.log(Level.WARNING, String.format("PPNAME contains marker sequence '%s'\n", s));
    			s = env.filter(new StringBuffer(s), false);
    			}

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

    /**
     * Concludes the conditional input parsing for <code>&amp;IF &amp;ENDIF</code>
     * preprocessor statements. Due to the nested nature of conditional
     * statements, this method may be called recursively.
     * <p>
     * The preprocessor expression evaluation is done in two steps.
     * Firstly, the entire expression is gathered from multiple lexer tokens
     * into a string by calling the <code>expression</code> method.
     * Secondly, if the expression has to be evaluated, the
     * <code>{@link Preprocessor#evaluate(Environment,String)}</code> method
     * is called to do the job.
     *
     * @throws      antlr.RecognitionException
     * @throws      antlr.TokenStreamException
     * @throws      IOException
     */
    	public final void condtext() throws RecognitionException, TokenStreamException, IOException {

    		Token  tmp0 = null;
    		Token  tmp1 = null;
    		Token  tmp4 = null;
    		Token  tmp2 = null;
    		Token  tmp3 = null;

    		int emit = 0;
    		String x = null;
    		String filename = null;

    		boolean lastIfCondValue = env.isIfCondValue();

    		try {      // for error handling
    			x=expression(emit);

    			// evaluate the expression
    			if (Preprocessor.evaluate(env, x))
    			{
    			// force the following block to emit
    			emit = 1;

    			env.setIfCondValue(true);
    			}
    			else
    			{
    			// disable include expansion; must be done here BEFORE any
    			// matching may inadvertantly access lookahead and trigger
    			// an expansion; this is OK as long as it is above the &THEN
    			env.setExpandBraces(false);

    			env.setIfCondValue(false);
    			}

    			tmp0 = LT(1);
    			match(ATHEN);

    			// filename = ((FileScope)(env.getSym().getScope())).getFileName();
    			// System.out.printf("&THEN1 level %d, filename %s, line %d, col %d\n", condNesting, filename, tmp0.getLine(), tmp0.getColumn());

    			{
    			if (((_tokenSet_2.member(LA(1))) && (_tokenSet_2.member(LA(2))))&&( emit == 1 )) {
    				textBlock();
    			}
    			else if ((_tokenSet_2.member(LA(1))) && (_tokenSet_2.member(LA(2)))) {
    				skipBlock();
    			}
    			else {
    				throw new NoViableAltException(LT(1), getFilename());
    			}

    			}
    			{
    			_loop36:
    			do {
    				if ((LA(1)==AELSEIF) && (_tokenSet_7.member(LA(2)))) {
    					tmp1 = LT(1);
    					match(AELSEIF);

    					// filename = ((FileScope)(env.getSym().getScope())).getFileName();
    					// System.out.printf("&ELSEIF level %d, filename %s, line %d, col %d\n", condNesting, filename, tmp1.getLine(), tmp1.getColumn());

    					if (emit == 1)
    					emit = 2;

    					x=expression(emit);

    					// did the IF portion emit?
    					if (emit == 0)
    					{
    					// no emit yet, so evaluate the expression
    					if (Preprocessor.evaluate(env, x))
    					{
    					// force the following block to emit
    					emit = 1;

    					env.setIfCondValue(true);
    					}
    					else
    					{
    					// disable include expansion; must be done here BEFORE any
    					// matching may inadvertantly access lookahead and trigger
    					// an expansion; this is OK as long as it is above the
    					// &THEN
    					env.setExpandBraces(false);

    					env.setIfCondValue(false);
    					}
    					}
    					else
    					{
    					// disable include expansion; must be done here BEFORE any
    					// matching may inadvertantly access lookahead and trigger
    					// an expansion; this is OK as long as it is above the
    					// &THEN
    					env.setExpandBraces(false);

    					env.setIfCondValue(false);
    					}

    					tmp4 = LT(1);
    					match(ATHEN);

    					// filename = ((FileScope)(env.getSym().getScope())).getFileName();
    					// System.out.printf("&THEN2 level %d, filename %s, line %d, col %d\n", condNesting, filename, tmp4.getLine(), tmp4.getColumn());

    					{
    					if (((_tokenSet_2.member(LA(1))) && (_tokenSet_2.member(LA(2))))&&( emit == 1 )) {
    						textBlock();
    					}
    					else if ((_tokenSet_2.member(LA(1))) && (_tokenSet_2.member(LA(2)))) {
    						skipBlock();
    					}
    					else {
    						throw new NoViableAltException(LT(1), getFilename());
    					}

    					}
    				}
    				else {
    					break _loop36;
    				}

    			} while (true);
    			}
    			{
    			if ((LA(1)==AELSE) && (_tokenSet_2.member(LA(2)))) {

    				// will we be dropping the block?
    				if (emit != 0)
    				{
    				// disable include expansion; must be done here BEFORE any
    				// matching may inadvertantly access lookahead and trigger
    				// an expansion; this is OK as long as it is above the
    				// &ELSE
    				env.setExpandBraces(false);
    				}

    				tmp2 = LT(1);
    				match(AELSE);

    				// filename = ((FileScope)(env.getSym().getScope())).getFileName();
    				// System.out.printf("&ELSE level %d, filename %s, line %d, col %d\n", condNesting, filename, tmp2.getLine(), tmp2.getColumn());

    				{
    				if (((_tokenSet_2.member(LA(1))) && (_tokenSet_2.member(LA(2))))&&( emit == 0 )) {
    					textBlock();
    				}
    				else if ((_tokenSet_2.member(LA(1))) && (_tokenSet_2.member(LA(2)))) {
    					skipBlock();
    				}
    				else {
    					throw new NoViableAltException(LT(1), getFilename());
    				}

    				}
    			}
    			else if ((_tokenSet_2.member(LA(1))) && (_tokenSet_2.member(LA(2)))) {
    			}
    			else {
    				throw new NoViableAltException(LT(1), getFilename());
    			}

    			}
    			{
    			if ((LA(1)==AENDIF) && (_tokenSet_2.member(LA(2)))) {
    				tmp3 = LT(1);
    				match(AENDIF);
    			}
    			else if (((_tokenSet_2.member(LA(1))) && (_tokenSet_2.member(LA(2))))&&( LA(1) == EOF )) {
    			}
    			else {
    				throw new NoViableAltException(LT(1), getFilename());
    			}

    			}

    			// filename = ((FileScope)(env.getSym().getScope())).getFileName();
    			// System.out.printf("&ENDIF level %d, filename %s, line %d, col %d\n", condNesting, filename, tmp3.getLine(), tmp3.getColumn());
    			condNesting--;

    			env.setIfCondValue(lastIfCondValue);

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

    /**
     * Gathers the preprocessor expression into a string
     * or ignores it.
     *
     * @param   emit
     *          if 0, instructs the method to gather expression tokens
     *          into a string, otherwise the expression is ignored.
     * @return  the whole expression as a string if <code>emit</code>
     *          is 0, or "".
     *
     * @throws  IOException
     */
    	public final String  expression(
    		int emit
    	) throws RecognitionException, TokenStreamException, IOException {
    		String x;

    		Token  t = null;

    		StringBuilder buf = new StringBuilder();
    		x = null;

    		try {      // for error handling
    			{
    			int _cnt42=0;
    			_loop42:
    			do {
    				if ((_tokenSet_7.member(LA(1)))) {
    					t = LT(1);
    					matchNot(ATHEN);

    					if (emit == 0)
    					{
    					buf.append(t.getText());
    					}

    				}
    				else {
    					if ( _cnt42>=1 ) { break _loop42; } else {throw new NoViableAltException(LT(1), getFilename());}
    				}

    				_cnt42++;
    			} while (true);
    			}

    			x = buf.toString();

    			if (env.isInStatement())
    			{
    			// we need to process any nested include files now
    			env.clearDeferred();
    			x = env.filter(new StringBuffer(x), false);
    			}

    			// if (emit == 0)
    			//   System.out.printf("EXPRESSION: %s\n", x);

    		}
    		catch (RecognitionException ex) {
    			reportError(ex);
    			recover(ex,_tokenSet_8);
    		}
    		return x;
    	}

    /**
     * Matches any non-interpretable block of text from the Progress source
     * file, including those containing nested <code>&amp;IF &amp;ENDIF</code>
     * statements. Non-interpretable blocks are the result of the preprocessor
     * expressions evaluated so they cause bypassing of corresponding
     * clauses of <code>&amp;IF...&amp;ENDIF</code> statements.
     * <p>
     * It is not possible to take the simple approach of matching everything
     * until the next <code>&amp;ELSEIF, &amp;ELSE or &amp;ENDIF</code> because there may be
     * a nested <code>&amp;IF</code> inside this block. In such a case, the
     * <code>&amp;IF</code> block will definitely have its own <code>&amp;ENDIF</code>
     * (and may also have its own <code>&amp;ELSEIF or &amp;ELSE</code>) which should
     * not cause the termination of this loop since the entire
     * <code>&amp;IF...&amp;ENDIF</code> is dead code. The matching loop can only
     * terminate when it reaches an <code>&amp;ELSEIF, &amp;ELSE or &amp;ENDIF</code> that
     * is at the same level (no nesting) as the current block being skipped. The
     * {@link #skipIf} rule handles matching any nested <code>&amp;IF</code>
     * constructs and uses recursion to handle any nested blocks that are
     * nested inside of the nested block and so on.
     * <p>
     * Note that braces expansion must be disabled before entering this rule
     * since the lookahead processing may trigger expansion of includes or
     * argument references before this rule can be executed. Since braces are
     * not expanded inside skipped conditional blocks in Progress, this is
     * valid. This behavior also enables include files to include themselves
     * recursively (so long as the <code>&amp;IF</code>) blocks are VERY carefully
     * crafted.  This rule will always re-enable braces expansions before it
     * returns.
     *
     * @throws      antlr.RecognitionException
     * @throws      antlr.TokenStreamException
     */
    	public final void skipBlock() throws RecognitionException, TokenStreamException {

    		try {      // for error handling

    			env.setInSkipBlock(true);

    			// cache off the in stmt flag
    			boolean inStmt = env.isInStatement();

    			// this should always be true
    			if (inStmt)
    			{
    			// disable while here
    			env.setInStatement(false);
    			env.clearDeferred();
    			}

    			{
    			_loop51:
    			do {
    				if ((LA(1)==AIF) && (_tokenSet_2.member(LA(2)))) {
    					skipIf();
    				}
    				else if ((_tokenSet_9.member(LA(1))) && (_tokenSet_2.member(LA(2)))) {
    					{
    					match(_tokenSet_9);
    					}
    				}
    				else {
    					break _loop51;
    				}

    			} while (true);
    			}

    			// re-enable include expansions
    			env.setExpandBraces(true);

    			env.setInSkipBlock(false);

    			// restore state if needed
    			if (inStmt)
    			{
    			env.setInStatement(true);
    			}

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

    /**
     * Matches non-interpretable block of text from the Progress source
     * file which is a fully coded <code>&amp;IF &amp;ENDIF</code> statement, possibly
     * recursive. Non-interpretable blocks are the result of the preprocessor
     * expressions evaluated so they cause bypassing of corresponding
     * clauses of <code>&amp;IF...&amp;ENDIF</code> statements.
     * <p>
     * This is a simple replacement for the {@link #aif} rule which discards
     * any content and uses recursion to drop any nested conditional blocks.
     * See {@link #skipBlock} which is the only user of this rule.
     *
     * @throws      antlr.RecognitionException
     * @throws      antlr.TokenStreamException
     */
    	public final void skipIf() throws RecognitionException, TokenStreamException {

    		Token  tmp = null;
    		Token  tmp2 = null;

    		try {      // for error handling
    			tmp = LT(1);
    			match(AIF);

    			condNesting++;
    			// String filename = ((FileScope)(env.getSym().getScope())).getFileName();
    			// System.out.printf("&IF (SKIPPING) level %d, filename %s, line %d, col %d\n", condNesting, filename, tmp.getLine(), tmp.getColumn());

    			{
    			_loop46:
    			do {
    				if ((LA(1)==AIF) && (_tokenSet_2.member(LA(2)))) {
    					skipIf();
    				}
    				else if ((_tokenSet_10.member(LA(1))) && (_tokenSet_2.member(LA(2)))) {
    					{
    					match(_tokenSet_10);
    					}
    				}
    				else {
    					break _loop46;
    				}

    			} while (true);
    			}
    			{
    			if ((LA(1)==AENDIF) && (_tokenSet_2.member(LA(2)))) {
    				tmp2 = LT(1);
    				match(AENDIF);
    			}
    			else if (((_tokenSet_2.member(LA(1))) && (_tokenSet_2.member(LA(2))))&&( LA(1) == EOF )) {
    			}
    			else {
    				throw new NoViableAltException(LT(1), getFilename());
    			}

    			}

    			// filename = ((FileScope)(env.getSym().getScope())).getFileName();
    			// System.out.printf("&ENDIF (SKIPPING) level %d, filename %s, line %d, col %d\n", condNesting, filename, tmp2.getLine(), tmp2.getColumn());
    			condNesting--;

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

    	public static final String[] _tokenNames = {
    		"<0>",
    		"EOF",
    		"<2>",
    		"NULL_TREE_LOOKAHEAD",
    		"TAB",
    		"WS",
    		"COMMENT",
    		"COMM_OPEN",
    		"CODE",
    		"COMM_CLOSE",
    		"LBRACE",
    		"RBRACE",
    		"APOST",
    		"QUOTE",
    		"XAPOST",
    		"XQUOTE",
    		"AGLOBAL",
    		"ASCOPED",
    		"AMESSAGE",
    		"AUNDEFINE",
    		"AIF",
    		"ATHEN",
    		"AELSEIF",
    		"AELSE",
    		"AENDIF",
    		"ASUSPEND",
    		"ARESUME",
    		"ASTMT",
    		"NL",
    		"STAR",
    		"AMPER",
    		"PPNAME",
    		"ALPHA",
    		"SPECIAL",
    		"DIGIT",
    		"EQUALS",
    		"ASTRING",
    		"QSTRING",
    		"STRING",
    		"STAR_COMMENT",
    		"SLASH_SLASH",
    		"BREAK_CODE_CHUNKS"
    	};

    	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 = { 236912640L, 0L};
    		return data;
    	}
    	public static final BitSet _tokenSet_1 = new BitSet(mk_tokenSet_1());
    	private static final long[] mk_tokenSet_2() {
    		long[] data = { 4398046511090L, 0L, 0L, 0L};
    		return data;
    	}
    	public static final BitSet _tokenSet_2 = new BitSet(mk_tokenSet_2());
    	private static final long[] mk_tokenSet_3() {
    		long[] data = { 4398017150960L, 0L, 0L, 0L};
    		return data;
    	}
    	public static final BitSet _tokenSet_3 = new BitSet(mk_tokenSet_3());
    	private static final long[] mk_tokenSet_4() {
    		long[] data = { 4397778075632L, 0L, 0L, 0L};
    		return data;
    	}
    	public static final BitSet _tokenSet_4 = new BitSet(mk_tokenSet_4());
    	private static final long[] mk_tokenSet_5() {
    		long[] data = { 3848022261744L, 0L, 0L, 0L};
    		return data;
    	}
    	public static final BitSet _tokenSet_5 = new BitSet(mk_tokenSet_5());
    	private static final long[] mk_tokenSet_6() {
    		long[] data = { 4397778075600L, 0L, 0L, 0L};
    		return data;
    	}
    	public static final BitSet _tokenSet_6 = new BitSet(mk_tokenSet_6());
    	private static final long[] mk_tokenSet_7() {
    		long[] data = { 4398044413936L, 0L, 0L, 0L};
    		return data;
    	}
    	public static final BitSet _tokenSet_7 = new BitSet(mk_tokenSet_7());
    	private static final long[] mk_tokenSet_8() {
    		long[] data = { 2097152L, 0L};
    		return data;
    	}
    	public static final BitSet _tokenSet_8 = new BitSet(mk_tokenSet_8());
    	private static final long[] mk_tokenSet_9() {
    		long[] data = { 4398016102386L, 0L, 0L, 0L};
    		return data;
    	}
    	public static final BitSet _tokenSet_9 = new BitSet(mk_tokenSet_9());
    	private static final long[] mk_tokenSet_10() {
    		long[] data = { 4398029733874L, 0L, 0L, 0L};
    		return data;
    	}
    	public static final BitSet _tokenSet_10 = new BitSet(mk_tokenSet_10());

    	}