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