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}, {*}, {&*}, {&name}, {}</code>;
* <li>defined variable references <code>{&name}</code>;
* <li>preprocessor builtin variable references <code>{&name}</code>;
* <li>include file references <code>{file}, {file pos}, {file &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>{&*}</code> and returns
* its evaluation.
*
* @return The evaluated <code>{&*}</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 &name=value form)
* will be parsed as positional (so the &name= text will be part of the
* argument). If the first argument is named (prefixed with &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 &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());
}