BracesParser.java

// $ANTLR 2.7.7 (20060906): "braces.g" -> "BracesParser.java"$
             
/*
** Module   : BracesLexer.java
**            BracesParser.java
**            PreprocTokenTypes.java
** Abstract : This grammar parses the Progress Preprocessor {...} language
**            elements and replaces them with evaluations on the input
**            stream. Unlike the other grammars, this one works independently
**            from the main line.
**
** Copyright (c) 2004-2016, Golden Code Development Corporation.
**
** -#- -I- --Date-- -T- --JPRM-- ----------------Description-----------------
** 001 GES 20041116 ADD   @18834 WARNING, THIS IS A GENERATED FILE!!!
**                               DO NOT EDIT THIS FILE. The original source
**                               file is braces.g!
*/
package com.goldencode.p2j.preproc;

import java.io.*;
import java.util.*;
import java.util.logging.*;
import com.goldencode.p2j.util.*;
import com.goldencode.p2j.convert.*;
import antlr.collections.AST;
import antlr.collections.impl.*;
import antlr.debug.misc.*;
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 all the preprocessor constructs coded in braces which are
 * argument references, preprocessor builtin variable references,
 * defined variable references and the include files.
 * <p>
 * This grammar is not a top level grammar for parsing the Progress
 * source files. The <code>text.g</code> is such a grammar. This grammar
 * is supposed to be used from the <code>{@link ClearStream}</code> class
 * internally.
 * <p>
 * The parsing starts when the driving code calls the {@link #braces} method
 * of this class.
 * <p>
 * No output is written to the output stream during parsing of braces.
 * Everything inside and the braces themselves are dropped from the source
 * and a substitution string is pushed back into the input stream so that
 * the contents of the substitution will be read and interpreted (rescanned)
 * next.
 * <p>
 * As soon as this parser reaches the closing brace token, the parser is
 * done and the calling code resumes execution.
 * <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>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. That automatically means that the nested braces are
 * processed recursively in the <code>ClearStream</code>, so any single
 * instance of the <code>BracesParser</code> has to deal with the non-nested
 * braces exclusively.
 * <p>
 * This parser recognizes and properly handles the following constructs:
 * <ul>
 *   <li>argument references <code>{0}, {n}, {*}, {&amp;*}, {&amp;name}, {}</code>;
 *   <li>defined variable references <code>{&amp;name}</code>;
 *   <li>preprocessor builtin variable references <code>{&amp;name}</code>;
 *   <li>include file references <code>{file}, {file pos}, {file &amp;name=value}
 *       </code> etc;
 * </ul>
 * As the result of an include file reference parsing, no immediate
 * substitute string is produced. Rather, another <code>FileScope</code>
 * instance is created and chained to the new dictionary scope by calling
 * <code>{@link Preprocessor#includeFile}</code> method.
 *
 * @see  ClearStream
 * @see  BracesLexer
 * @see  FileScope
 * @see  TextParser
 */
public class BracesParser extends antlr.LLkParser       implements PreprocTokenTypes
 {

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

   /** Shared state for multiple lexers, parsers and the input stream. */
   private Environment env = null;
   
   /** Token source. */
   private BracesLexer lexer = null;
   
   /** Deferred parser lookahead that must be pushed back. */
   private String parserLookahead = null;

   /**
    * Constructor. Creates a parser attached to the token stream
    * selector taken from the environment. Saves the environment
    * for future needs.
    *
    * @param    env
    *           instance of the preprocessor environment
    * @param    lexer
    *           instance of the lexer to be the source of tokens
    *           for this parser
    */
   public BracesParser(Environment env, BracesLexer lexer)
   {
      this(lexer);
      this.env   = env;
      this.lexer = lexer; 
   }
   
   /**
    * 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 BracesParser(TokenBuffer tokenBuf, int k) {
  super(tokenBuf,k);
  tokenNames = _tokenNames;
}

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

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

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

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

/**
 * Matches all the preprocessor constructs in braces and substitutes
 * them with their evaluations or activates new input files for the
 * include file references. These curley braces must always come in matching
 * pairs.
 * <p>
 * Valid alternatives include empty braces, braces with only whitespace
 * inside, braces containing an argument reference (named or positional) and
 * braces with an include file reference.  The core processing is handled
 * by {@link #argref} and {@link #incref}.
 * <p>
 * The expansion of braces can be disabled or enabled by using the
 * {@link Environment#setExpandBraces}. Note that no matter the state of the
 * expand flag, the braces and contained text will still be matched. 
 * <p>
 * This is the top level recognizer for all braces.
 */
	public final void braces() throws RecognitionException, TokenStreamException, IOException {
		
		
		// this must be initialized to null to bypass argument processing
		// in the exit action if this is an include or empty braces case
		String str = null;
		
		boolean bypass = false;
		
		
		try {      // for error handling
			{
			if ((LA(1)==WS) && (LA(2)==RBRACE)) {
				match(WS);
			}
			else if (((LA(1)==STAR||LA(1)==AMPER||LA(1)==DIGITS) && (_tokenSet_0.member(LA(2))))&&( !(LA(1) == DIGITS && LA(2) != RBRACE) )) {
				str=argref();
			}
			else if ((_tokenSet_1.member(LA(1))) && (_tokenSet_0.member(LA(2)))) {
				incref();
				bypass = true;
			}
			else if ((LA(1)==RBRACE)) {
			}
			else {
				throw new NoViableAltException(LT(1), getFilename());
			}
			
			}
			match(RBRACE);
			
			// we don't honor isExpandBraces() here because it is possible for
			// an &ENDIF or other preproc directive to be encountered by the
			// expansion of a preproc name or arg reference; so braces expansion
			// flag only disables include file processing (see incref)
			
			StringBuilder sb = new StringBuilder();
			
			// the output from our expansion needs to be pushed back onto the
			// input stream so that when we return from this method (and this
			// instance of the braces parser/lexer pop off the stack), that
			// the braces that we have parsed have been replaced with the
			// proper content (so long as there actually is any content to
			// expand)
			if (str != null)
			{
			// was there any text to expand or was the expansion an empty
			// string?
			if (str.length() > 0)
			{
			sb.append(str);
			}
			}
			
			// include files handle pushback of the lookahead differently to
			// get the ordering of output correct, so bypass this processing
			// in that case, but by default this lookahead pushback is done and
			// this is independent of whether the braces are being expanded or
			// not since in either case the matching may have lookahead that
			// will be lost and which is not part of the braces processing
			if (!bypass)
			{
			// the lexer may have used lookahead in a hard to predict manner
			// which will potentially change with each rebuild, so there may
			// or may not be any characters read from the stream and buffered
			// in the lexer; get any that are there and push them back
			// otherwise they will be lost when we return and the lexer is
			// popped off the stack
			String buffered = env.lookahead(lexer);
			
			if (buffered.length() > 0)
			{
			sb.append(buffered);
			}
			}
			
			// if there is anything to push back, do so
			if (sb.length() > 0)
			{
			env.pushBack(sb.toString());
			}
			
		}
		catch (RecognitionException ex) {
			reportError(ex);
			recover(ex,_tokenSet_2);
		}
	}
	
/**
 * Matches all the argument references, even misformed ones and returns
 * their evaluations.
 * <p>
 * This is the top level recognizer for all references that produce a
 * substitution (not include files).
 *
 * @return   The argument reference evaluation as a string.
 */
	public final String  argref() throws RecognitionException, TokenStreamException, IOException {
		String str;
		
		
		str = null;
		
		
		try {      // for error handling
			{
			switch ( LA(1)) {
			case DIGITS:
			{
				str=posargref();
				break;
			}
			case STAR:
			{
				str=posallref();
				break;
			}
			default:
				if ((LA(1)==AMPER) && (LA(2)==STAR)) {
					str=keyallref();
				}
				else if ((LA(1)==AMPER) && (_tokenSet_0.member(LA(2)))) {
					str=nameref();
				}
				else if ((LA(1)==AMPER) && (LA(2)==WS)) {
					misformed();
				}
			else {
				throw new NoViableAltException(LT(1), getFilename());
			}
			}
			}
		}
		catch (RecognitionException ex) {
			reportError(ex);
			recover(ex,_tokenSet_3);
		}
		return str;
	}
	
/**
 * Matches all the include file references and arranges their inclusion
 * into the input stream. The rules {@link #filename} and {@link #arguments}
 * are used to handle the core parsing.
 * <p>
 * This is the top level recognizer for all references that resolve into
 * include files versus substitutions.
 */
	public final void incref() throws RecognitionException, TokenStreamException {
		
		
		String fname = "";
		Map    args  = new LinkedHashMap();
		
		
		try {      // for error handling
			fname=filename();
			{
			if ((LA(1)==WS) && (LA(2)==RBRACE)) {
				match(WS);
			}
			else if ((_tokenSet_4.member(LA(1))) && ((LA(2) >= TAB && LA(2) <= DIGITS))) {
				arguments(args);
			}
			else if ((LA(1)==RBRACE)) {
			}
			else {
				throw new NoViableAltException(LT(1), getFilename());
			}
			
			}
			
			String buffered = null;
			
			// the lexer may have used lookahead in a hard to predict manner
			// which will potentially change with each rebuild, so there may
			// or may not be any characters read from the stream and buffered
			// in the lexer; get any that are there and push them back
			// otherwise they will be lost when we return and the lexer is
			// popped off the stack
			
			try
			{
			StringBuffer sb = new StringBuffer();
			
			// we know that LA(1) == RBRACE at this point, but certain
			// use cases of the arguments rule above may have preloaded
			// LA(2); this means that some of the lookahead is no longer
			// in the lexer, but is now in the parser; one case where this
			// happens for sure is when there is a named argument that
			// ends in a QUOTE character (just before the RBRACE)
			if (parserLookahead != null)
			{
			sb.append(parserLookahead);
			parserLookahead = null;
			}
			
			// now add any pending lexer lookahead
			sb.append(env.lookahead(lexer));
			
			// remove any markers
			buffered = env.filter(sb, false);
			
			if (!env.isExpandBraces())
			{
			// push this back, if we are not expanding the braces
			env.pushBack(buffered);
			}
			}
			
			catch (IOException ioe)
			{
			LOG.log(Level.SEVERE, "", ioe);
			}
			
			// there is a mode where we must parse a given set of braces to
			// know where they end but we do not implement include processing
			// because we are in a skipped conditional block; to do otherwise
			// causes major problems with recursive inclusion (which is allowed
			// in Progress)
			if (env.isExpandBraces())
			{
			Preprocessor.includeFile(env, fname, args, buffered);
			}
			
		}
		catch (RecognitionException ex) {
			reportError(ex);
			recover(ex,_tokenSet_3);
		}
	}
	
/**
 * Matches positional argument references and returns their evaluations.
 *
 * @return   The positional argument reference evaluation as a string.
 */
	public final String  posargref() throws RecognitionException, TokenStreamException, IOException {
		String str;
		
		Token  n = null;
		
		str = null;
		
		
		try {      // for error handling
			n = LT(1);
			match(DIGITS);
			
			str = Preprocessor.getPosArg(env, n.getText());
			
		}
		catch (RecognitionException ex) {
			reportError(ex);
			recover(ex,_tokenSet_3);
		}
		return str;
	}
	
/**
 * Matches the all positional argument reference <code>{*}</code>
 * and returns its evaluation.
 *
 * @return   The evaluated <code>{*}</code> as a string.
 */
	public final String  posallref() throws RecognitionException, TokenStreamException {
		String str;
		
		
		str = null;
		
		
		try {      // for error handling
			match(STAR);
			{
			switch ( LA(1)) {
			case WS:
			case CODE:
			case QUOTE:
			case STAR:
			case AMPER:
			case EQUALS:
			case DIGITS:
			{
				anything();
				break;
			}
			case RBRACE:
			{
				break;
			}
			default:
			{
				throw new NoViableAltException(LT(1), getFilename());
			}
			}
			}
			
			str = Preprocessor.getAllPos(env);
			
		}
		catch (RecognitionException ex) {
			reportError(ex);
			recover(ex,_tokenSet_3);
		}
		return str;
	}
	
/**
 * Matches the all named argument reference <code>{&amp;*}</code> and returns
 * its evaluation.
 *
 * @return   The evaluated <code>{&amp;*}</code> as a string.
 */
	public final String  keyallref() throws RecognitionException, TokenStreamException {
		String str;
		
		
		str = null;
		
		
		try {      // for error handling
			match(AMPER);
			match(STAR);
			{
			switch ( LA(1)) {
			case WS:
			case CODE:
			case QUOTE:
			case STAR:
			case AMPER:
			case EQUALS:
			case DIGITS:
			{
				anything();
				break;
			}
			case RBRACE:
			{
				break;
			}
			default:
			{
				throw new NoViableAltException(LT(1), getFilename());
			}
			}
			}
			
			str = Preprocessor.getAllNamed(env);
			
		}
		catch (RecognitionException ex) {
			reportError(ex);
			recover(ex,_tokenSet_3);
		}
		return str;
	}
	
/**
 * Matches a named argument or variable reference and returns their
 * evaluation.
 *
 * @return   The reference evaluation as a string.
 */
	public final String  nameref() throws RecognitionException, TokenStreamException, IOException {
		String str;
		
		
		str = null;
		
		
		try {      // for error handling
			match(AMPER);
			str=anythingButSpace(false);
			{
			switch ( LA(1)) {
			case WS:
			case CODE:
			case QUOTE:
			case STAR:
			case AMPER:
			case EQUALS:
			case DIGITS:
			{
				anything();
				break;
			}
			case RBRACE:
			{
				break;
			}
			default:
			{
				throw new NoViableAltException(LT(1), getFilename());
			}
			}
			}
			
			str = Preprocessor.getVariable(env, str);
			
		}
		catch (RecognitionException ex) {
			reportError(ex);
			recover(ex,_tokenSet_3);
		}
		return str;
	}
	
/**
 * Matches misformed named argument references so they don't break
 * the parsing process and discards them.
 */
	public final void misformed() throws RecognitionException, TokenStreamException {
		
		
		try {      // for error handling
			match(AMPER);
			match(WS);
			{
			switch ( LA(1)) {
			case WS:
			case CODE:
			case QUOTE:
			case STAR:
			case AMPER:
			case EQUALS:
			case DIGITS:
			{
				anything();
				break;
			}
			case RBRACE:
			{
				break;
			}
			default:
			{
				throw new NoViableAltException(LT(1), getFilename());
			}
			}
			}
			
			env.eprint("misformed variable reference ignored", 0);
			
		}
		catch (RecognitionException ex) {
			reportError(ex);
			recover(ex,_tokenSet_3);
		}
	}
	
/**
 * Matches any sequence of characters except the closing brace
 * so they don't break the parsing process and discards them.
 */
	public final void anything() throws RecognitionException, TokenStreamException {
		
		
		try {      // for error handling
			{
			int _cnt16=0;
			_loop16:
			do {
				switch ( LA(1)) {
				case EQUALS:
				{
					match(EQUALS);
					break;
				}
				case STAR:
				{
					match(STAR);
					break;
				}
				case AMPER:
				{
					match(AMPER);
					break;
				}
				case DIGITS:
				{
					match(DIGITS);
					break;
				}
				case CODE:
				{
					match(CODE);
					break;
				}
				case QUOTE:
				{
					match(QUOTE);
					break;
				}
				case WS:
				{
					match(WS);
					break;
				}
				default:
				{
					if ( _cnt16>=1 ) { break _loop16; } else {throw new NoViableAltException(LT(1), getFilename());}
				}
				}
				_cnt16++;
			} while (true);
			}
		}
		catch (RecognitionException ex) {
			reportError(ex);
			recover(ex,_tokenSet_3);
		}
	}
	
/**
 * Matches a sequence of characters until encountering a closing brace or
 * space and returns the sequence.
 *
 * @param    dropQuotes
 *           {@code true} if quote characters should be dropped from the text output.
 *
 * @return   The matching sequence of characters as a string.
 */
	public final String  anythingButSpace(
		boolean dropQuotes
	) throws RecognitionException, TokenStreamException {
		String str;
		
		Token  s1 = null;
		Token  s2 = null;
		Token  s3 = null;
		Token  s4 = null;
		Token  s5 = null;
		Token  s6 = null;
		
		StringBuilder sb = new StringBuilder();
		str = "";
		
		
		try {      // for error handling
			{
			_loop33:
			do {
				if ((LA(1)==EQUALS) && (_tokenSet_0.member(LA(2)))) {
					s1 = LT(1);
					match(EQUALS);
					sb.append(s1.getText());
				}
				else if ((LA(1)==STAR) && (_tokenSet_0.member(LA(2)))) {
					s2 = LT(1);
					match(STAR);
					sb.append(s2.getText());
				}
				else if ((LA(1)==AMPER) && (_tokenSet_0.member(LA(2)))) {
					s3 = LT(1);
					match(AMPER);
					sb.append(s3.getText());
				}
				else if ((LA(1)==DIGITS) && (_tokenSet_0.member(LA(2)))) {
					s4 = LT(1);
					match(DIGITS);
					sb.append(s4.getText());
				}
				else if ((LA(1)==CODE) && (_tokenSet_0.member(LA(2)))) {
					s5 = LT(1);
					match(CODE);
					sb.append(s5.getText());
				}
				else if ((LA(1)==QUOTE) && (_tokenSet_0.member(LA(2)))) {
					s6 = LT(1);
					match(QUOTE);
					
					if (!dropQuotes)
					{
					sb.append(s6.getText());
					}
					
				}
				else {
					break _loop33;
				}
				
			} while (true);
			}
			
			str = sb.toString();
			
		}
		catch (RecognitionException ex) {
			reportError(ex);
			recover(ex,_tokenSet_0);
		}
		return str;
	}
	
/**
 * Matches include file name portion of the include file references
 * and returns the file name.
 *
 * @return   The referenced file name as a string.
 */
	public final String  filename() throws RecognitionException, TokenStreamException {
		String str;
		
		
		StringBuilder sb = new StringBuilder();
		String txt1 = "";
		String txt2 = "";
		
		str = "";
		
		
		try {      // for error handling
			{
			if ((LA(1)==WS) && (LA(2)==STAR)) {
				match(WS);
				match(STAR);
				txt1=anythingButSpace(false);
				
				sb.append("*").append(txt1);
				
			}
			else if ((LA(1)==WS) && (LA(2)==AMPER)) {
				match(WS);
				match(AMPER);
				txt1=anythingButSpace(false);
				
				sb.append("&").append(txt1);
				
			}
			else if ((_tokenSet_1.member(LA(1))) && (_tokenSet_0.member(LA(2)))) {
				{
				switch ( LA(1)) {
				case WS:
				{
					match(WS);
					break;
				}
				case CODE:
				case QUOTE:
				case EQUALS:
				case DIGITS:
				{
					break;
				}
				default:
				{
					throw new NoViableAltException(LT(1), getFilename());
				}
				}
				}
				{
				switch ( LA(1)) {
				case QUOTE:
				{
					match(QUOTE);
					txt1=anythingButQuote();
					match(QUOTE);
					
					sb.append(txt1);
					
					break;
				}
				case CODE:
				case EQUALS:
				case DIGITS:
				{
					txt1=anyfile();
					txt2=anythingButSpace(true);
					
					sb.append(txt1).append(txt2);
					
					break;
				}
				default:
				{
					throw new NoViableAltException(LT(1), getFilename());
				}
				}
				}
			}
			else {
				throw new NoViableAltException(LT(1), getFilename());
			}
			
			}
			
			str = sb.toString();
			
		}
		catch (RecognitionException ex) {
			reportError(ex);
			recover(ex,_tokenSet_0);
		}
		return str;
	}
	
/**
 * Matches arguments portion of the include file references and puts the
 * parsed arguments into a container.
 * <p>
 * The first argument determines the parsing strategy. If positional, then
 * all subsequent arguments (even if they have the &amp;name=value form)
 * will be parsed as positional (so the &amp;name= text will be part of the
 * argument). If the first argument is named (prefixed with &amp;name=),
 * then any stray text in between properly formatted named arguments will
 * be parsed as positional arguments and discarded as trash. See the rule
 * {@link #argvalue} for details on how the discard mode works.
 * <p>
 * Core parsing subroutines are {@link #keyarg} and {@link #posarg}.
 *
 * @param    args
 *           Container for arguments.
 */
	public final void arguments(
		Map args
	) throws RecognitionException, TokenStreamException {
		
		
		int     npos       = 1;
		boolean first      = true;
		boolean positional = false;
		boolean ignore     = false;
		String argName = null;
		
		
		try {      // for error handling
			{
			int _cnt38=0;
			_loop38:
			do {
				if (((_tokenSet_4.member(LA(1))) && ((LA(2) >= TAB && LA(2) <= DIGITS)))&&(
            (LA(1) == WS && LA(2) != RBRACE) ||
            (LA(1) != WS && LA(1) != RBRACE)
         )) {
					{
					switch ( LA(1)) {
					case WS:
					{
						match(WS);
						break;
					}
					case CODE:
					case QUOTE:
					case STAR:
					case AMPER:
					case EQUALS:
					case DIGITS:
					{
						break;
					}
					default:
					{
						throw new NoViableAltException(LT(1), getFilename());
					}
					}
					}
					{
					if (((LA(1)==AMPER) && ((LA(2) >= TAB && LA(2) <= DIGITS)))&&( !positional )) {
						argName=keyarg(args, npos);
						
						// if we are in named mode, then every named argument
						// found is valid and we need to increment our argument
						// index
						npos++;
						
					}
					else if ((_tokenSet_5.member(LA(1))) && (_tokenSet_0.member(LA(2)))) {
						posarg(args, npos, ignore);
						
						// track if we should be parsing in positional mode
						// (only allowed if the first arg is positional and
						// not named), if so we can never parse the named form
						// and any argument that has the named format is really
						// just a positional argument and the resulting text
						// will include the &name= portion as part of the text
						if (first)
						positional = true;
						
						// if we are not discarding the arguments then we must
						// increment our argument index
						if (!ignore)
						npos++;
						
					}
					else {
						throw new NoViableAltException(LT(1), getFilename());
					}
					
					}
					
					// no longer the first pass through this loop
					first = false;
					
					// determines if positional arguments (those that are 
					// not prefixed by an &name=) should be honored or
					// discarded (discard if ignore == true); we never
					// discard if this is the first time through or if on
					// the first pass through the loop that first argument
					// was found to be positional
					ignore = !positional;
					
				}
				else {
					if ( _cnt38>=1 ) { break _loop38; } else {throw new NoViableAltException(LT(1), getFilename());}
				}
				
				_cnt38++;
			} while (true);
			}
			{
			switch ( LA(1)) {
			case WS:
			{
				match(WS);
				break;
			}
			case RBRACE:
			{
				break;
			}
			default:
			{
				throw new NoViableAltException(LT(1), getFilename());
			}
			}
			}
			
			// this is intentionally only processed for the last named argument; it will only
			// be executed for malformed named arguments because properly formed args will
			// have already been added to the map; this is needed because of a quirk in the 4GL
			// malformed arguments processing which allows the last malformed arg to be "seen"
			// using DEFINED()
			if (argName != null && args.get(argName) == null)
			{
			args.put(argName, "");
			}
			
			if (!env.isExpandBraces())
			{
			Token la2 = LT(2);
			parserLookahead = la2.getText();
			}
			
		}
		catch (RecognitionException ex) {
			reportError(ex);
			recover(ex,_tokenSet_3);
		}
	}
	
/**
 * Matches a sequence of characters until encountering a closing brace or
 * quote and returns the sequence.
 *
 * @return   The matching sequence of characters as a string.
 */
	public final String  anythingButQuote() throws RecognitionException, TokenStreamException {
		String str;
		
		Token  s1 = null;
		Token  s2 = null;
		Token  s3 = null;
		Token  s4 = null;
		Token  s5 = null;
		Token  s6 = null;
		
		StringBuilder sb = new StringBuilder();
		str = "";
		
		
		try {      // for error handling
			{
			_loop25:
			do {
				switch ( LA(1)) {
				case EQUALS:
				{
					s1 = LT(1);
					match(EQUALS);
					sb.append(s1.getText());
					break;
				}
				case STAR:
				{
					s2 = LT(1);
					match(STAR);
					sb.append(s2.getText());
					break;
				}
				case AMPER:
				{
					s3 = LT(1);
					match(AMPER);
					sb.append(s3.getText());
					break;
				}
				case DIGITS:
				{
					s4 = LT(1);
					match(DIGITS);
					sb.append(s4.getText());
					break;
				}
				case CODE:
				{
					s5 = LT(1);
					match(CODE);
					sb.append(s5.getText());
					break;
				}
				case WS:
				{
					s6 = LT(1);
					match(WS);
					sb.append(s6.getText());
					break;
				}
				default:
				{
					break _loop25;
				}
				}
			} while (true);
			}
			
			str = sb.toString();
			
		}
		catch (RecognitionException ex) {
			reportError(ex);
			recover(ex,_tokenSet_6);
		}
		return str;
	}
	
/**
 * Matches a sequence of characters that is distinguishable from an argument
 * reference and returns the sequence.
 *
 * @return   The matching sequence of characters as a string.
 */
	public final String  anyfile() throws RecognitionException, TokenStreamException {
		String str;
		
		Token  s1 = null;
		Token  s2 = null;
		Token  s3 = null;
		
		StringBuilder sb = new StringBuilder();
		str = "";
		
		
		try {      // for error handling
			{
			switch ( LA(1)) {
			case EQUALS:
			{
				s1 = LT(1);
				match(EQUALS);
				sb.append(s1.getText());
				break;
			}
			case CODE:
			{
				s2 = LT(1);
				match(CODE);
				sb.append(s2.getText());
				break;
			}
			case DIGITS:
			{
				s3 = LT(1);
				match(DIGITS);
				sb.append(s3.getText());
				break;
			}
			default:
			{
				throw new NoViableAltException(LT(1), getFilename());
			}
			}
			}
			
			str = sb.toString();
			
		}
		catch (RecognitionException ex) {
			reportError(ex);
			recover(ex,_tokenSet_0);
		}
		return str;
	}
	
/**
 * Matches a sequence of characters (including two sequential double quote
 * characters which is an escaping mechanism) until encountering a closing brace
 * or unescaped double quote and returns the sequence.
 *
 * @return   The matching sequence of characters as a string.
 */
	public final String  anythingButUnescapedQuote() throws RecognitionException, TokenStreamException {
		String str;
		
		Token  s1 = null;
		Token  s2 = null;
		Token  s3 = null;
		Token  s4 = null;
		Token  s5 = null;
		Token  s6 = null;
		
		StringBuilder sb = new StringBuilder();
		str = "";
		
		
		try {      // for error handling
			{
			_loop28:
			do {
				if ((LA(1)==EQUALS) && (_tokenSet_0.member(LA(2)))) {
					s1 = LT(1);
					match(EQUALS);
					sb.append(s1.getText());
				}
				else if ((LA(1)==STAR) && (_tokenSet_0.member(LA(2)))) {
					s2 = LT(1);
					match(STAR);
					sb.append(s2.getText());
				}
				else if ((LA(1)==AMPER) && (_tokenSet_0.member(LA(2)))) {
					s3 = LT(1);
					match(AMPER);
					sb.append(s3.getText());
				}
				else if ((LA(1)==DIGITS) && (_tokenSet_0.member(LA(2)))) {
					s4 = LT(1);
					match(DIGITS);
					sb.append(s4.getText());
				}
				else if ((LA(1)==CODE) && (_tokenSet_0.member(LA(2)))) {
					s5 = LT(1);
					match(CODE);
					sb.append(s5.getText());
				}
				else if ((LA(1)==WS) && (_tokenSet_0.member(LA(2)))) {
					s6 = LT(1);
					match(WS);
					sb.append(s6.getText());
				}
				else if ((LA(1)==QUOTE) && (LA(2)==QUOTE)) {
					match(QUOTE);
					match(QUOTE);
					sb.append("\"");
				}
				else {
					break _loop28;
				}
				
			} while (true);
			}
			
			str = sb.toString();
			
		}
		catch (RecognitionException ex) {
			reportError(ex);
			recover(ex,_tokenSet_0);
		}
		return str;
	}
	
/**
 * Matches a named argument and puts the parsed argument name and value
 * into a container. The first token encountered must always be an
 * <code>AMPER</code>.  The argument name must follow this and the
 * {@link #anythingButEquals} rule parses that name.  The resulting text has
 * all spaces removed before the name is stored.
 * <p>
 * For a valid value to be found, following the name must be an
 * <code>EQUALS</code> token. Finally, the value is parsed by the rule
 * {@link #argvalue}.  The resulting name and value pair is stored in the
 * given container.
 * <p>
 * If no <code>EQUALS</code> token is found after the name, then this named
 * argument and all other text until the closing <code>RBRACE</code> is
 * dropped.  In such a case, even if there are properly formed named
 * arguments following the malformed one, these are all discarded.
 * <p>
 * If a named argument is matched that is a duplicate of a previously matched
 * named argument, then the previously matched value will be honored and all
 * subsequent instances of same name are discarded. 
 *
 * @param    args
 *           The container where the argument is put.
 * @param    npos
 *           The position of this argument in the argument list.
 *
 * @return   The argument's name.
 */
	public final String  keyarg(
		Map args, int npos
	) throws RecognitionException, TokenStreamException {
		String argName;
		
		
		String  name   = null;
		String  value  = null;
		boolean equals = false;
		boolean bypass = false;
		argName = null;
		
		
		try {      // for error handling
			match(AMPER);
			name=anythingButEquals(true);
			{
			if (((LA(1)==EQUALS) && (_tokenSet_4.member(LA(2))))&&(
              (LA(2) == WS && LA(3) != RBRACE) ||
              (LA(2) != WS && LA(2) != RBRACE)
           )) {
				match(EQUALS);
				equals = true;
				{
				switch ( LA(1)) {
				case WS:
				{
					match(WS);
					break;
				}
				case CODE:
				case QUOTE:
				case STAR:
				case AMPER:
				case EQUALS:
				case DIGITS:
				{
					break;
				}
				default:
				{
					throw new NoViableAltException(LT(1), getFilename());
				}
				}
				}
				value=argvalue(false);
			}
			else if (((LA(1) >= TAB && LA(1) <= DIGITS)) && (_tokenSet_7.member(LA(2)))) {
				{
				_loop44:
				do {
					if ((_tokenSet_8.member(LA(1))) && ((LA(2) >= TAB && LA(2) <= DIGITS))) {
						matchNot(RBRACE);
						bypass = true;
					}
					else {
						break _loop44;
					}
					
				} while (true);
				}
			}
			else {
				throw new NoViableAltException(LT(1), getFilename());
			}
			
			}
			
			// check if this was properly formed 
			if (equals)
			{
			// the first instance of this given name is a valid named arg
			if (args.get(name) == null)
			{
			// add our mapping
			args.put(name, value);
			}
			else
			{
			// duplicate names are "dropped" as named arguments but must
			// still be available as a positional argument and as part of
			// the {*} expansion; we create a placeholder here for this
			// case and the argument normalization downstream is smart
			// about handling this edge case
			args.put("{" + npos, value);
			}
			}
			else
			{
			if (!bypass)
			{
			// in the malformed args case we must push back our lookahead because
			// we have looked deeper than in the normal case
			Token la2 = LT(2);
			parserLookahead = la2.getText();
			}
			}
			
			argName = name;
			
		}
		catch (RecognitionException ex) {
			reportError(ex);
			recover(ex,_tokenSet_0);
		}
		return argName;
	}
	
/**
 * Matches a positional argument and puts the parsed argument name and
 * value into a container. The core parsing is handled by {@link #argvalue}.
 * <p>
 * Names for the positional arguments are special combinations made of
 * the opening brace character and the position number. This rule creates
 * a separate namespace for the positional arguments.
 *
 * @param    args
 *           The container where the argument is put.
 * @param    npos
 *           The position of this argument in the argument list.
 * @param    ignore
 *           <code>true</code> to force any matched argument to be discarded
 *           instead of added to the container. This is needed to support
 *           "trash" (that look like positional args) intermixed with named
 *           argument processing.
 */
	public final void posarg(
		Map args, int npos, boolean ignore
	) throws RecognitionException, TokenStreamException {
		
		
		String name  = "{" + npos;
		String value = null;
		
		
		try {      // for error handling
			value=argvalue(ignore);
			
			if (!ignore && value.length() > 0)
			args.put(name, value);
			
		}
		catch (RecognitionException ex) {
			reportError(ex);
			recover(ex,_tokenSet_0);
		}
	}
	
/**
 * Matches a sequence of characters until encountering a closing brace or
 * '=' and returns the sequence.
 *
 * @param    drop
 *           <code>true</code> to drop whitespace from the returned text.
 *
 * @return   The matching sequence of characters as a string.
 */
	public final String  anythingButEquals(
		boolean drop
	) throws RecognitionException, TokenStreamException {
		String str;
		
		Token  s1 = null;
		Token  s2 = null;
		Token  s3 = null;
		Token  s4 = null;
		Token  s5 = null;
		Token  s6 = null;
		
		StringBuilder sb = new StringBuilder();
		str = "";
		
		
		try {      // for error handling
			{
			_loop48:
			do {
				if ((LA(1)==WS) && ((LA(2) >= TAB && LA(2) <= DIGITS))) {
					s1 = LT(1);
					match(WS);
					if (!drop) sb.append(s1.getText());
				}
				else if ((LA(1)==STAR) && ((LA(2) >= TAB && LA(2) <= DIGITS))) {
					s2 = LT(1);
					match(STAR);
					sb.append(s2.getText());
				}
				else if ((LA(1)==AMPER) && ((LA(2) >= TAB && LA(2) <= DIGITS))) {
					s3 = LT(1);
					match(AMPER);
					sb.append(s3.getText());
				}
				else if ((LA(1)==DIGITS) && ((LA(2) >= TAB && LA(2) <= DIGITS))) {
					s4 = LT(1);
					match(DIGITS);
					sb.append(s4.getText());
				}
				else if ((LA(1)==CODE) && ((LA(2) >= TAB && LA(2) <= DIGITS))) {
					s5 = LT(1);
					match(CODE);
					sb.append(s5.getText());
				}
				else if ((LA(1)==QUOTE) && ((LA(2) >= TAB && LA(2) <= DIGITS))) {
					s6 = LT(1);
					match(QUOTE);
					sb.append(s6.getText());
				}
				else {
					break _loop48;
				}
				
			} while (true);
			}
			
			str = sb.toString();
			
		}
		catch (RecognitionException ex) {
			reportError(ex);
			recover(ex,_tokenSet_9);
		}
		return str;
	}
	
/**
 * Matches the argument value portion of either positional or named argument
 * and returns the value. The value of a valid argument extends to (but does
 * not include) the first unquoted whitespace or to the next right brace
 * character.
 * <p>
 * When parsing an argument's value any preceding whitespace is dropped
 * though it is not required to have preceding whitespace. At that point,
 * normal parsing of the value occurs.  In this parsing, a double quote
 * character will cause a special sub-parsing mode to occur where ampersands,
 * equal signs and white space (characters that normally can't be part of
 * an argument value) can be inserted into the argument value. This mode 
 * continues until a closing double quote is encountered OR until the right
 * brace is encountered. This does mean that the closing double quote is
 * optional, but in such a case it will consume everything up to the end
 * of the include specification.
 * <p>
 * If not in the special quoted mode, the normal value parsing will continue
 * until encountering whitespace or a double quote.  Whitespace ends the
 * parsing of a value and the captured text is returned. A double quote  
 * character will drop into the special quoted sub-parsing mode described
 * above. Sequences of quoted "strings" and random characters can be
 * freely intermixed to create the value for an argument. The only issue is
 * that any whitespace that exists outside of the double quoted section will
 * mark the end of the value.
 * <p>
 * It is valid to match nothing in this rule (no whitespace and no value) or
 * to only match whitespace.  In such a case, the parsing will end if an
 * <code>RBRACE</code> is encountered. This is like having a value that is
 * an empty string. 
 * <p>
 * In named parsing mode (if the first argument matched was a named
 * argument in the form &amp;name=value), this method is also used to match  
 * and discard any text in between valid named arguments. To mark this case,
 * the <code>discard</code> will be <code>true</code>. This changes the
 * parsing to process the so called "discard region". This region occurs 
 * after the first unquoted whitespace which marks the end of the last valid
 * named argument. Anything after this point that is not an ampersand or
 * right brace will be discarded.  There is no discard region if positional
 * parsing mode is active (the first argument matched was a positional
 * argument). This means that this discard mode will never be enabled for
 * positional parsing mode.  This means that <code>discard</code> should
 * only be <code>true</code> if this is named parsing mode AND ALSO the
 * parser has entered the discard region.
 * <p>
 * In the discard region (between valid named arguments), double quotes lose
 * their special behavior.  Specifically, in the discard region the double
 * quote character is treated as any other and cannot be used to "hide"
 * ampersands or whitespace as it normally would.  There is no concept of
 * paired sets of double quotes in this part of the parsing.    
 * <p>
 * Once encountering the discard region, whitespace is not required in the 
 * character immediately preceding the next ampersand, but rather as soon as
 * the ampersand is encountered, the discard region is exited and the
 * ampersand is treated as the beginning of the next valid named argument.
 *
 * @param    discard
 *           If <code>true</code>, enter the special discard processing
 *           mode.  This should only be <code>true</code> if the parser is
 *           in both named arguments mode AND a valid named argument value 
 *           has just been parsed.
 *
 * @return   The argument value as a string.
 */
	public final String  argvalue(
		boolean discard
	) throws RecognitionException, TokenStreamException {
		String str;
		
		
		StringBuilder sb           = new StringBuilder();
		String        txt1         = "";
		boolean       noCloseQuote = false;
		str = "";
		
		
		try {      // for error handling
			{
			if (((_tokenSet_10.member(LA(1))) && (_tokenSet_0.member(LA(2))))&&( discard )) {
				{
				int _cnt52=0;
				_loop52:
				do {
					if ((_tokenSet_10.member(LA(1))) && (_tokenSet_0.member(LA(2)))) {
						txt1=anythingButSpaceOrAmpersand();
					}
					else {
						if ( _cnt52>=1 ) { break _loop52; } else {throw new NoViableAltException(LT(1), getFilename());}
					}
					
					_cnt52++;
				} while (true);
				}
			}
			else if (((_tokenSet_5.member(LA(1))) && (_tokenSet_0.member(LA(2))))&&( !discard )) {
				{
				int _cnt56=0;
				_loop56:
				do {
					if ((LA(1)==QUOTE) && (LA(2)==QUOTE)) {
						match(QUOTE);
						match(QUOTE);
						sb.append("\"");
					}
					else if ((LA(1)==QUOTE) && (_tokenSet_0.member(LA(2)))) {
						{
						match(QUOTE);
						txt1=anythingButUnescapedQuote();
						noCloseQuote = true;
						}
						{
						if ((LA(1)==QUOTE) && (_tokenSet_0.member(LA(2)))) {
							match(QUOTE);
							noCloseQuote = false;
						}
						else if ((_tokenSet_0.member(LA(1))) && (_tokenSet_7.member(LA(2)))) {
						}
						else {
							throw new NoViableAltException(LT(1), getFilename());
						}
						
						}
						
						sb.append(txt1);
						
						// TODO: At least 1 case has been found where this is
						//       deficient. This was an inclref inside an &ELSE block
						//       whose end looked something like this:
						//
						//    &the_arg_name   = "some_text}
						// &ENDIF
						//
						// The some_text parsed fine and we see the RBRACE as the LA(1). The problem
						// is that in the lexer, the next 2 characters (lexer LA1 and LA2) are \n
						// (correct) and E (incorrect). The & (ampersand) is missing. Adding parser
						// LA(3) text to the parserLookahead did not change it because the char that
						// is missing is the one between LA1 and LA2. The result is that the &ENDIF
						// is not parsed properly because it is right after the RBRACE and so the
						// text.g condtext rule just reads to the end of the file until it decides
						// to die.
						if (noCloseQuote && LA(1) == RBRACE)
						{
						// we only matched a single quote char but in order
						// to get here we unfortunately loaded LA(2) with
						// content from the stream which needs to be pushed
						// back
						Token la2 = LT(2);
						parserLookahead = la2.getText();
						}
						
					}
					else if ((_tokenSet_11.member(LA(1))) && (_tokenSet_0.member(LA(2)))) {
						txt1=anythingButSpaceOrQuote();
						sb.append(txt1);
					}
					else {
						if ( _cnt56>=1 ) { break _loop56; } else {throw new NoViableAltException(LT(1), getFilename());}
					}
					
					_cnt56++;
				} while (true);
				}
			}
			else {
				throw new NoViableAltException(LT(1), getFilename());
			}
			
			}
			
			if (sb.length() > 0)
			str = sb.toString();
			
		}
		catch (RecognitionException ex) {
			reportError(ex);
			recover(ex,_tokenSet_0);
		}
		return str;
	}
	
/**
 * Matches a sequence of characters until encountering a closing brace,
 * ampersand, space or quote and returns the sequence.
 *
 * @return   The matching sequence of characters as a string.
 */
	public final String  anythingButSpaceOrAmpersand() throws RecognitionException, TokenStreamException {
		String str;
		
		Token  s1 = null;
		Token  s2 = null;
		Token  s3 = null;
		Token  s4 = null;
		Token  s5 = null;
		
		StringBuilder sb = new StringBuilder();
		str = "";
		
		
		try {      // for error handling
			{
			switch ( LA(1)) {
			case EQUALS:
			{
				s1 = LT(1);
				match(EQUALS);
				sb.append(s1.getText());
				break;
			}
			case STAR:
			{
				s2 = LT(1);
				match(STAR);
				sb.append(s2.getText());
				break;
			}
			case DIGITS:
			{
				s3 = LT(1);
				match(DIGITS);
				sb.append(s3.getText());
				break;
			}
			case CODE:
			{
				s4 = LT(1);
				match(CODE);
				sb.append(s4.getText());
				break;
			}
			case QUOTE:
			{
				s5 = LT(1);
				match(QUOTE);
				sb.append(s5.getText());
				break;
			}
			default:
			{
				throw new NoViableAltException(LT(1), getFilename());
			}
			}
			}
			
			str = sb.toString();
			
		}
		catch (RecognitionException ex) {
			reportError(ex);
			recover(ex,_tokenSet_0);
		}
		return str;
	}
	
/**
 * Matches a sequence of characters until encountering a closing brace,
 * space or double quote character and returns the sequence.
 *
 * @return   The matching sequence of characters as a string.
 */
	public final String  anythingButSpaceOrQuote() throws RecognitionException, TokenStreamException {
		String str;
		
		Token  s1 = null;
		Token  s2 = null;
		Token  s3 = null;
		Token  s4 = null;
		Token  s5 = null;
		
		StringBuilder sb = new StringBuilder();
		str = "";
		
		
		try {      // for error handling
			{
			switch ( LA(1)) {
			case EQUALS:
			{
				s1 = LT(1);
				match(EQUALS);
				sb.append(s1.getText());
				break;
			}
			case STAR:
			{
				s2 = LT(1);
				match(STAR);
				sb.append(s2.getText());
				break;
			}
			case AMPER:
			{
				s3 = LT(1);
				match(AMPER);
				sb.append(s3.getText());
				break;
			}
			case DIGITS:
			{
				s4 = LT(1);
				match(DIGITS);
				sb.append(s4.getText());
				break;
			}
			case CODE:
			{
				s5 = LT(1);
				match(CODE);
				sb.append(s5.getText());
				break;
			}
			default:
			{
				throw new NoViableAltException(LT(1), getFilename());
			}
			}
			}
			
			str = sb.toString();
			
		}
		catch (RecognitionException ex) {
			reportError(ex);
			recover(ex,_tokenSet_0);
		}
		return str;
	}
	
	
	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",
		"DIGITS"
	};
	
	private static final long[] mk_tokenSet_0() {
		long[] data = { 4434016872736L, 0L};
		return data;
	}
	public static final BitSet _tokenSet_0 = new BitSet(mk_tokenSet_0());
	private static final long[] mk_tokenSet_1() {
		long[] data = { 4432406257952L, 0L};
		return data;
	}
	public static final BitSet _tokenSet_1 = new BitSet(mk_tokenSet_1());
	private static final long[] mk_tokenSet_2() {
		long[] data = { 2L, 0L};
		return data;
	}
	public static final BitSet _tokenSet_2 = new BitSet(mk_tokenSet_2());
	private static final long[] mk_tokenSet_3() {
		long[] data = { 2048L, 0L};
		return data;
	}
	public static final BitSet _tokenSet_3 = new BitSet(mk_tokenSet_3());
	private static final long[] mk_tokenSet_4() {
		long[] data = { 4434016870688L, 0L};
		return data;
	}
	public static final BitSet _tokenSet_4 = new BitSet(mk_tokenSet_4());
	private static final long[] mk_tokenSet_5() {
		long[] data = { 4434016870656L, 0L};
		return data;
	}
	public static final BitSet _tokenSet_5 = new BitSet(mk_tokenSet_5());
	private static final long[] mk_tokenSet_6() {
		long[] data = { 8192L, 0L};
		return data;
	}
	public static final BitSet _tokenSet_6 = new BitSet(mk_tokenSet_6());
	private static final long[] mk_tokenSet_7() {
		long[] data = { 8796093022194L, 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 = { 8796093020144L, 0L, 0L, 0L};
		return data;
	}
	public static final BitSet _tokenSet_8 = new BitSet(mk_tokenSet_8());
	private static final long[] mk_tokenSet_9() {
		long[] data = { 8796093022192L, 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 = { 4432943128832L, 0L};
		return data;
	}
	public static final BitSet _tokenSet_10 = new BitSet(mk_tokenSet_10());
	private static final long[] mk_tokenSet_11() {
		long[] data = { 4434016862464L, 0L};
		return data;
	}
	public static final BitSet _tokenSet_11 = new BitSet(mk_tokenSet_11());
	
	}