/* Generated By:JavaCC: Do not edit this line. FMParser.java */
package freemarker.core;

import freemarker.template.*;
import freemarker.template.utility.StringUtil;
import freemarker.template.utility.DeepUnwrap;
import java.io.*;
import java.util.*;

/**
 * This class is generated by JavaCC from a grammar file.
 */
public class FMParser implements FMParserConstants {

// Necessary for adding macros and setting location info.
  Template template;
  private String templateName;

// variables that keep track of whether we are in a loop or a switch.
  private int loopNesting, switchNesting;
  private boolean inMacro, inFunction, stripWhitespace, stripText;
  private LinkedList escapes = new LinkedList();
  private int contentNesting; // for stripText

  /**
   * Create an FM expression parser using a string.
   */
  static public FMParser createExpressionParser(String s) {
      SimpleCharStream scs = new SimpleCharStream(new StringReader(s), 1, 1, s.length());
      FMParserTokenManager token_source = new FMParserTokenManager(scs);
      token_source.SwitchTo(FMParserConstants.FM_EXPRESSION);
      return new FMParser(token_source);
  }

  /**
   * Constructs a new parser object.
   * @param template The template associated with this parser.
   * @param reader The character stream to use as input
   * @param strictEscapeSyntax Whether FreeMarker directives must start with a #
   */
  public FMParser(Template template, Reader reader, boolean strictEscapeSyntax, boolean stripWhitespace) {
      this(reader);
      this.template = template;
      token_source.strictEscapeSyntax = strictEscapeSyntax;
      this.templateName = template != null ? template.getName() : "";
      token_source.templateName = templateName;
      this.stripWhitespace = stripWhitespace;
  }

  public FMParser(Template template, Reader reader, boolean strictEscapeSyntax, boolean stripWhitespace, int tagSyntax) {
      this(template, reader, strictEscapeSyntax, stripWhitespace, tagSyntax, Configuration.PARSED_DEFAULT_INCOMPATIBLE_ENHANCEMENTS);
  }

  public FMParser(Template template, Reader reader, boolean strictEscapeSyntax, boolean stripWhitespace, int tagSyntax, int incompatibleChanges) {
      this(template, reader, strictEscapeSyntax, stripWhitespace);
      switch (tagSyntax) {
          case Configuration.AUTO_DETECT_TAG_SYNTAX :
             token_source.autodetectTagSyntax = true;
             break;
          case Configuration.ANGLE_BRACKET_TAG_SYNTAX :
             token_source.altDirectiveSyntax = false;
             break;
          case Configuration.SQUARE_BRACKET_TAG_SYNTAX :
             token_source.altDirectiveSyntax = true;
             break;
          default : throw new IllegalArgumentException("Illegal argument for tagSyntax");
      }
      token_source.incompatibleChanges = incompatibleChanges;
  }

  public FMParser(String template) {
      this(null, new StringReader(template), true, true);
  }

  private String getErrorStart(Token t) {
      return "Error in template: " + template.getName()
            + "\non line " + t.beginLine + ", column " + t.beginColumn;
  }

  /**
   * Throw an exception if the expression passed in is a String
   * Literal
   */
  private void notStringLiteral(Expression exp, String expected) throws ParseException {
      if (exp instanceof StringLiteral) {
         String msg = "Error " + exp.getStartLocation()
                     + "\nFound string literal: " + exp
                     + "\nExpecting: " + expected;
         throw new ParseException(msg, exp);
      }
  }

  /**
   * Throw an exception if the expression passed in is a Number
   * Literal
   */
  private void notNumberLiteral(Expression exp, String expected) throws ParseException {
      if (exp instanceof NumberLiteral) {
         String msg = "Error " + exp.getStartLocation()
                     + "\nFound number literal: " + exp.getCanonicalForm()
                     + "\nExpecting " + expected;
         throw new ParseException(msg, exp);
      }
  }

  /**
   * Throw an exception if the expression passed in is a boolean
   * Literal
   */
  private void notBooleanLiteral(Expression exp, String expected) throws ParseException {
      if (exp instanceof BooleanLiteral) {
         String msg = "Error " + exp.getStartLocation()
                     + "\nFound: " + exp.getCanonicalForm()
                     + "\nExpecting " + expected;
         throw new ParseException(msg, exp);
      }
  }

  /**
   * Throw an exception if the expression passed in is a Hash
   * Literal
   */
  private void notHashLiteral(Expression exp, String expected) throws ParseException {
        if (exp instanceof HashLiteral) {
         String msg = "Error " + exp.getStartLocation()
                     + "\nFound hash literal: " + exp.getCanonicalForm()
                     + "\nExpecting " + expected;
         throw new ParseException(msg, exp);
      }
  }

  /**
   * Throw an exception if the expression passed in is a List
   * Literal
   */

  private void notListLiteral(Expression exp, String expected)
      throws ParseException
  {
        if (exp instanceof ListLiteral) {
         String msg = "Error " + exp.getStartLocation()
                     + "\nFound list literal: " + exp.getCanonicalForm()
                     + "\nExpecting " + expected;
         throw new ParseException(msg, exp);
      }
  }
  /**
   * Throw an exception if the expression passed in is a literal
   * other than of the numerical type
   */
  private void numberLiteralOnly(Expression exp) throws ParseException {
      notStringLiteral(exp, "number");
      notListLiteral(exp, "number");
      notHashLiteral(exp, "number");
      notBooleanLiteral(exp, "number");
  }

  /**
   * Throw an exception if the expression passed in is
   * not a string.
   */
  private void stringLiteralOnly(Expression exp) throws ParseException {
      notNumberLiteral(exp, "number");
      notListLiteral(exp, "number");
      notHashLiteral(exp, "number");
      notBooleanLiteral(exp, "number");
  }

  /**
   * Throw an exception if the expression passed in is a literal
   * other than of the boolean type
   */
  private void booleanLiteralOnly(Expression exp) throws ParseException {
      notStringLiteral(exp, "boolean (true/false)");
      notListLiteral(exp, "boolean (true/false)");
      notHashLiteral(exp, "boolean (true/false)");
      notNumberLiteral(exp, "boolean (true/false)");
  }

  private Expression escapedExpression(Expression exp) {
      if(!escapes.isEmpty()) {
          return ((EscapeBlock)escapes.getFirst()).doEscape(exp);
      }
      return exp;
  }

  private boolean getBoolean(Expression exp) throws ParseException {
      TemplateModel tm = null;
      try {
          tm = exp.getAsTemplateModel(null);
      } catch (Exception e) {
         throw new ParseException(e.getMessage()
                                  + "\nCould not evaluate expression: "
                                  + exp.getCanonicalForm()
                                  + exp.getStartLocation(), exp);
      }
      if (tm instanceof TemplateBooleanModel) {
          try {
             return ((TemplateBooleanModel) tm).getAsBoolean();
          } catch (TemplateModelException tme) {
          }
      }
      if (tm instanceof TemplateScalarModel) {
          try {
              return StringUtil.getYesNo(((TemplateScalarModel) tm).getAsString());
          } catch (Exception e) {
              throw new ParseException(e.getMessage()
                                       + "\nExpecting yes/no, found: " + exp.getCanonicalForm()
                                       + exp.getStartLocation(), exp);
          }
      }
      throw new ParseException("Expecting boolean (yes/no) parameter" + exp.getStartLocation(), exp);
  }

// Now the actual parsing code, starting
// with the productions for FreeMarker's
// expression syntax.

/**
 * This is the same as OrExpression, since
 * the OR is the operator with the lowest
 * precedence.
 */
  final public Expression Expression() throws ParseException {
   Expression exp;
    exp = OrExpression();
      {if (true) return exp;}
    throw new Error("Missing return statement in function");
  }

/**
 * Lowest level expression, a literal, a variable,
 * or a possibly more complex expression bounded
 * by parentheses.
 */
  final public Expression PrimaryExpression() throws ParseException {
   Expression exp;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case INTEGER:
    case DECIMAL:
      exp = NumberLiteral();
      break;
    case OPEN_BRACE:
      exp = HashLiteral();
      break;
    case STRING_LITERAL:
    case RAW_STRING:
      exp = StringLiteral(true);
      break;
    case FALSE:
    case TRUE:
      exp = BooleanLiteral();
      break;
    case OPEN_BRACKET:
      exp = ListLiteral();
      break;
    case ID:
      exp = Identifier();
      break;
    case OPEN_PAREN:
      exp = Parenthesis();
      break;
    case DOT:
      exp = BuiltinVariable();
      break;
    default:
      jj_la1[0] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
    label_1:
    while (true) {
      if (jj_2_1(2147483647)) {
        ;
      } else {
        break label_1;
      }
      exp = AddSubExpression(exp);
    }
     {if (true) return exp;}
    throw new Error("Missing return statement in function");
  }

  final public Expression Parenthesis() throws ParseException {
   Expression exp, result;
   Token start, end;
    start = jj_consume_token(OPEN_PAREN);
    exp = Expression();
    end = jj_consume_token(CLOSE_PAREN);
       result = new ParentheticalExpression(exp);
       result.setLocation(template, start, end);
       {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

/**
 * A primary expression preceded by zero or
 * more unary operators. (The only unary operator we
 * currently have is the NOT.)
 */
  final public Expression UnaryExpression() throws ParseException {
   Expression exp, result;
   boolean haveNot = false;
   Token t = null, start=null;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case PLUS:
    case MINUS:
      result = UnaryPlusMinusExpression();
      break;
    case EXCLAM:
      result = NotExpression();
      break;
    case STRING_LITERAL:
    case RAW_STRING:
    case FALSE:
    case TRUE:
    case INTEGER:
    case DECIMAL:
    case DOT:
    case OPEN_BRACKET:
    case OPEN_PAREN:
    case OPEN_BRACE:
    case ID:
      result = PrimaryExpression();
      break;
    default:
      jj_la1[1] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
     {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public Expression NotExpression() throws ParseException {
   Token t;
   Expression exp, result=null;
   ArrayList nots = new ArrayList();
    label_2:
    while (true) {
      t = jj_consume_token(EXCLAM);
                  nots.add(t);
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case EXCLAM:
        ;
        break;
      default:
        jj_la1[2] = jj_gen;
        break label_2;
      }
    }
    exp = PrimaryExpression();
      for (int i=0; i<nots.size(); i++) {
         result = new NotExpression(exp);
         Token tok = (Token) nots.get(nots.size() -i -1);
         result.setLocation(template, tok, exp);
         exp = result;
      }
      {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public Expression UnaryPlusMinusExpression() throws ParseException {
   Expression exp, result;
   boolean isMinus = false;
   Token t;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case PLUS:
      t = jj_consume_token(PLUS);
      break;
    case MINUS:
      t = jj_consume_token(MINUS);
                 isMinus = true;
      break;
    default:
      jj_la1[3] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
    exp = PrimaryExpression();
      result = new UnaryPlusMinusExpression(exp, isMinus);
      result.setLocation(template, t, exp);
      {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public Expression AdditiveExpression() throws ParseException {
   Expression lhs, rhs, result;
   boolean plus;
    lhs = MultiplicativeExpression();
                                   result = lhs;
    label_3:
    while (true) {
      if (jj_2_2(2147483647)) {
        ;
      } else {
        break label_3;
      }
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case PLUS:
        jj_consume_token(PLUS);
                 plus = true;
        break;
      case MINUS:
        jj_consume_token(MINUS);
                  plus = false;
        break;
      default:
        jj_la1[4] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
      rhs = MultiplicativeExpression();
         if (plus) {
           // plus is treated separately, since it is also
           // used for concatenation.
             result = new AddConcatExpression(lhs, rhs);
         }
         else {
             numberLiteralOnly(lhs);
             numberLiteralOnly(rhs);
             result = new ArithmeticExpression(lhs,
                                            rhs,
                                            ArithmeticExpression.SUBSTRACTION);
         }
         result.setLocation(template, lhs, rhs);
         lhs = result;
    }
      {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

/**
 * A unary expression followed by zero or more
 * unary expressions with operators in between.
 */
  final public Expression MultiplicativeExpression() throws ParseException {
   Expression lhs, rhs, result;
   int operation = ArithmeticExpression.MULTIPLICATION;
    lhs = UnaryExpression();
                          result = lhs;
    label_4:
    while (true) {
      if (jj_2_3(2147483647)) {
        ;
      } else {
        break label_4;
      }
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case TIMES:
        jj_consume_token(TIMES);
                  operation = ArithmeticExpression.MULTIPLICATION;
        break;
      case DIVIDE:
        jj_consume_token(DIVIDE);
                   operation = ArithmeticExpression.DIVISION;
        break;
      case PERCENT:
        jj_consume_token(PERCENT);
                   operation = ArithmeticExpression.MODULUS;
        break;
      default:
        jj_la1[5] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
      rhs = UnaryExpression();
         numberLiteralOnly(lhs);
         numberLiteralOnly(rhs);
         result = new ArithmeticExpression(lhs, rhs, operation);
         result.setLocation(template, lhs, rhs);
         lhs = result;
    }
      {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public Expression EqualityExpression() throws ParseException {
   Expression lhs, rhs, result;
   Token t;
    lhs = RelationalExpression();
                               result = lhs;
    if (jj_2_4(2147483647)) {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case NOT_EQUALS:
        t = jj_consume_token(NOT_EQUALS);
        break;
      case EQUALS:
        t = jj_consume_token(EQUALS);
        break;
      case DOUBLE_EQUALS:
        t = jj_consume_token(DOUBLE_EQUALS);
        break;
      default:
        jj_la1[6] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
      rhs = RelationalExpression();
        notHashLiteral(lhs, "scalar");
        notHashLiteral(rhs, "scalar");
        notListLiteral(lhs, "scalar");
        notListLiteral(rhs, "scalar");
        result = new ComparisonExpression(lhs, rhs, t.image);
        result.setLocation(template, lhs, rhs);
    } else {
      ;
    }
      {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public Expression RelationalExpression() throws ParseException {
   Expression lhs, rhs, result;
   Token t;
    lhs = RangeExpression();
                          result = lhs;
    if (jj_2_5(2147483647)) {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case NATURAL_GTE:
        t = jj_consume_token(NATURAL_GTE);
        break;
      case ESCAPED_GTE:
        t = jj_consume_token(ESCAPED_GTE);
        break;
      case NATURAL_GT:
        t = jj_consume_token(NATURAL_GT);
        break;
      case ESCAPED_GT:
        t = jj_consume_token(ESCAPED_GT);
        break;
      case LESS_THAN_EQUALS:
        t = jj_consume_token(LESS_THAN_EQUALS);
        break;
      case LESS_THAN:
        t = jj_consume_token(LESS_THAN);
        break;
      default:
        jj_la1[7] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
      rhs = RangeExpression();
        notHashLiteral(lhs, "scalar");
        notHashLiteral(rhs, "scalar");
        notListLiteral(lhs, "scalar");
        notListLiteral(rhs, "scalar");
        notStringLiteral(lhs, "number");
        notStringLiteral(rhs, "number");
        result = new ComparisonExpression(lhs, rhs, t.image);
        result.setLocation(template, lhs, rhs);
    } else {
      ;
    }
      {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public Expression RangeExpression() throws ParseException {
   Expression lhs, rhs=null, result;
    lhs = AdditiveExpression();
                              result = lhs;
    if (jj_2_7(2147483647)) {
      jj_consume_token(DOT_DOT);
      if (jj_2_6(2147483647)) {
        rhs = AdditiveExpression();
      } else {
        ;
      }
           numberLiteralOnly(lhs);
           if (rhs != null) {
               numberLiteralOnly(rhs);
           }
           Range range = new Range(lhs, rhs);
           if (rhs != null) {
               range.setLocation(template, lhs, rhs);
           } else {
              range.setLocation(template, lhs, lhs);
           }
           result = range;
    } else {
      ;
    }
        {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public Expression AndExpression() throws ParseException {
   Expression lhs, rhs, result;
    lhs = EqualityExpression();
                             result = lhs;
    label_5:
    while (true) {
      if (jj_2_8(2147483647)) {
        ;
      } else {
        break label_5;
      }
      jj_consume_token(AND);
      rhs = EqualityExpression();
         booleanLiteralOnly(lhs);
         booleanLiteralOnly(rhs);
         result = new AndExpression(lhs, rhs);
         result.setLocation(template, lhs, rhs);
         lhs = result;
    }
      {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public Expression OrExpression() throws ParseException {
   Expression lhs, rhs, result;
    lhs = AndExpression();
                        result = lhs;
    label_6:
    while (true) {
      if (jj_2_9(2147483647)) {
        ;
      } else {
        break label_6;
      }
      jj_consume_token(OR);
      rhs = AndExpression();
         booleanLiteralOnly(lhs);
         booleanLiteralOnly(rhs);
         result = new OrExpression(lhs, rhs);
         result.setLocation(template, lhs, rhs);
         lhs = result;
    }
      {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public ListLiteral ListLiteral() throws ParseException {
   ArrayList values = new ArrayList();
   Token begin, end;
    begin = jj_consume_token(OPEN_BRACKET);
    values = PositionalArgs();
    end = jj_consume_token(CLOSE_BRACKET);
        ListLiteral result = new ListLiteral(values);
        result.setLocation(template, begin, end);
        {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public Expression NumberLiteral() throws ParseException {
   Token op = null, t;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case INTEGER:
      t = jj_consume_token(INTEGER);
      break;
    case DECIMAL:
      t = jj_consume_token(DECIMAL);
      break;
    default:
      jj_la1[8] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
       String s = t.image;
       Expression result = new NumberLiteral(template.getArithmeticEngine().toNumber(s));
       Token startToken = (op != null) ? op : t;
       result.setLocation(template, startToken, t);
       {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public Identifier Identifier() throws ParseException {
    Token t;
    t = jj_consume_token(ID);
        Identifier id = new Identifier(t.image);
        id.setLocation(template, t, t);
        {if (true) return id;}
    throw new Error("Missing return statement in function");
  }

  final public Expression IdentifierOrStringLiteral() throws ParseException {
   Expression exp;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case ID:
      exp = Identifier();
      break;
    case STRING_LITERAL:
    case RAW_STRING:
      exp = StringLiteral(false);
      break;
    default:
      jj_la1[9] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
      {if (true) return exp;}
    throw new Error("Missing return statement in function");
  }

  final public BuiltinVariable BuiltinVariable() throws ParseException {
   Token dot, name;
    dot = jj_consume_token(DOT);
    name = jj_consume_token(ID);
      BuiltinVariable result = null;
      try {
          result = new BuiltinVariable(name.image);
      } catch (ParseException pe) {
          pe.lineNumber = dot.beginLine;
          pe.columnNumber = dot.beginColumn;
          {if (true) throw pe;}
      }
      result.setLocation(template, dot, name);
      {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

/**
 * Production that builds up an expression
 * using the dot or dynamic key name
 * or the args list if this is a method invocation.
 */
  final public Expression AddSubExpression(Expression exp) throws ParseException {
   Expression result = null;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case DOT:
      result = DotVariable(exp);
      break;
    case OPEN_BRACKET:
      result = DynamicKey(exp);
      break;
    case OPEN_PAREN:
      result = MethodArgs(exp);
      break;
    case BUILT_IN:
      result = BuiltIn(exp);
      break;
    case EXCLAM:
    case TERMINATING_EXCLAM:
      result = DefaultTo(exp);
      break;
    case EXISTS:
      result = Exists(exp);
      break;
    default:
      jj_la1[10] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
        {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public Expression DefaultTo(Expression exp) throws ParseException {
   Expression rhs = null;
   Token t;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case TERMINATING_EXCLAM:
      t = jj_consume_token(TERMINATING_EXCLAM);
      break;
    case EXCLAM:
      t = jj_consume_token(EXCLAM);
      if (jj_2_10(2147483647)) {
        rhs = Expression();
      } else {
        ;
      }
      break;
    default:
      jj_la1[11] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
      DefaultToExpression result = new DefaultToExpression(exp, rhs);
      if (rhs ==null) {
          result.setLocation(template, exp, t);
      }
      else {
          result.setLocation(template, exp, rhs);
      }
      {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public Expression Exists(Expression exp) throws ParseException {
   Token t;
    t = jj_consume_token(EXISTS);
       ExistsExpression result = new ExistsExpression(exp);
       result.setLocation(template, exp, t);
       {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public Expression BuiltIn(Expression exp) throws ParseException {
   Token t=null;
    jj_consume_token(BUILT_IN);
    t = jj_consume_token(ID);
       BuiltIn result = null;
       try {
           result = BuiltIn.newBuiltIn(exp, t.image, t, templateName);
       } catch (ParseException pe) {
           pe.lineNumber = t.beginLine;
           pe.columnNumber = t.beginColumn;
           {if (true) throw pe;}
       }
       result.setLocation(template, exp, t);
       {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

/**
 * production for when a key is specified by <DOT> + keyname
 */
  final public Expression DotVariable(Expression exp) throws ParseException {
  Token t;
    jj_consume_token(DOT);
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case ID:
      t = jj_consume_token(ID);
      break;
    case TIMES:
      t = jj_consume_token(TIMES);
      break;
    case DOUBLE_STAR:
      t = jj_consume_token(DOUBLE_STAR);
      break;
    case FALSE:
    case TRUE:
    case LESS_THAN:
    case LESS_THAN_EQUALS:
    case ESCAPED_GT:
    case ESCAPED_GTE:
    case IN:
    case AS:
    case USING:
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case LESS_THAN:
        t = jj_consume_token(LESS_THAN);
        break;
      case LESS_THAN_EQUALS:
        t = jj_consume_token(LESS_THAN_EQUALS);
        break;
      case ESCAPED_GT:
        t = jj_consume_token(ESCAPED_GT);
        break;
      case ESCAPED_GTE:
        t = jj_consume_token(ESCAPED_GTE);
        break;
      case FALSE:
        t = jj_consume_token(FALSE);
        break;
      case TRUE:
        t = jj_consume_token(TRUE);
        break;
      case IN:
        t = jj_consume_token(IN);
        break;
      case AS:
        t = jj_consume_token(AS);
        break;
      case USING:
        t = jj_consume_token(USING);
        break;
      default:
        jj_la1[12] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
            if (!Character.isLetter(t.image.charAt(0))) {
                String msg = getErrorStart(t)
                            + "\n" + t.image + " is not a valid identifier.";
                {if (true) throw new ParseException(msg, t.beginLine, t.beginColumn);}
            }
      break;
    default:
      jj_la1[13] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
         notListLiteral(exp, "hash");
         notStringLiteral(exp, "hash");
         notBooleanLiteral(exp, "hash");
         Dot dot = new Dot(exp, t.image);
         dot.setLocation(template, exp, t);
         {if (true) return dot;}
    throw new Error("Missing return statement in function");
  }

/**
 * production for when the key is specified
 * in brackets.
 */
  final public Expression DynamicKey(Expression exp) throws ParseException {
   Expression arg;
   Token t;
    jj_consume_token(OPEN_BRACKET);
    arg = Expression();
    t = jj_consume_token(CLOSE_BRACKET);
       notBooleanLiteral(exp, "list or hash");
       notNumberLiteral(exp, "list or hash");
       DynamicKeyName dkn = new DynamicKeyName(exp, arg);
       dkn.setLocation(template, exp, t);
       {if (true) return dkn;}
    throw new Error("Missing return statement in function");
  }

/**
 * production for an arglist part of a method invocation.
 */
  final public MethodCall MethodArgs(Expression exp) throws ParseException {
     ArrayList args = new ArrayList();
     Token end;
    jj_consume_token(OPEN_PAREN);
    args = PositionalArgs();
    end = jj_consume_token(CLOSE_PAREN);
        args.trimToSize();
        MethodCall result = new MethodCall(exp, args);
        result.setLocation(template, exp, end);
        {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public StringLiteral StringLiteral(boolean interpolate) throws ParseException {
  Token t;
  boolean raw = false;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case STRING_LITERAL:
      t = jj_consume_token(STRING_LITERAL);
      break;
    case RAW_STRING:
      t = jj_consume_token(RAW_STRING);
                     raw = true;
      break;
    default:
      jj_la1[14] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
       String s = t.image;
       // Get rid of the quotes.
       s = s.substring(1, s.length() -1);
       if (raw) {
           s=s.substring(1);
       }
       else try {
          s = StringUtil.FTLStringLiteralDec(s);
       } catch (ParseException pe) {
          pe.lineNumber = t.beginLine;
          pe.columnNumber = t.beginColumn;
          {if (true) throw pe;}
       }
       StringLiteral result = new StringLiteral(s);
       result.setLocation(template, t, t);
       if (interpolate && !raw) {
           if (t.image.indexOf("${") >=0 || t.image.indexOf("#{") >=0)
              result.checkInterpolation();
       }
       {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public Expression BooleanLiteral() throws ParseException {
   Token t;
   Expression result;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case FALSE:
      t = jj_consume_token(FALSE);
                  result = new BooleanLiteral(false);
      break;
    case TRUE:
      t = jj_consume_token(TRUE);
                 result = new BooleanLiteral(true);
      break;
    default:
      jj_la1[15] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
       result.setLocation(template, t, t);
       {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public HashLiteral HashLiteral() throws ParseException {
   Token begin, end;
   Expression key, value;
   ArrayList keys = new ArrayList();
   ArrayList values = new ArrayList();
    begin = jj_consume_token(OPEN_BRACE);
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case STRING_LITERAL:
    case RAW_STRING:
    case FALSE:
    case TRUE:
    case INTEGER:
    case DECIMAL:
    case DOT:
    case PLUS:
    case MINUS:
    case EXCLAM:
    case OPEN_BRACKET:
    case OPEN_PAREN:
    case OPEN_BRACE:
    case ID:
      key = Expression();
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case COMMA:
        jj_consume_token(COMMA);
        break;
      case COLON:
        jj_consume_token(COLON);
        break;
      default:
        jj_la1[16] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
      value = Expression();
          stringLiteralOnly(key);
          keys.add(key);
          values.add(value);
      label_7:
      while (true) {
        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
        case COMMA:
          ;
          break;
        default:
          jj_la1[17] = jj_gen;
          break label_7;
        }
        jj_consume_token(COMMA);
        key = Expression();
        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
        case COMMA:
          jj_consume_token(COMMA);
          break;
        case COLON:
          jj_consume_token(COLON);
          break;
        default:
          jj_la1[18] = jj_gen;
          jj_consume_token(-1);
          throw new ParseException();
        }
        value = Expression();
               stringLiteralOnly(key);
               keys.add(key);
               values.add(value);
      }
      break;
    default:
      jj_la1[19] = jj_gen;
      ;
    }
    end = jj_consume_token(CLOSE_BRACE);
      HashLiteral result = new HashLiteral(keys, values);
      result.setLocation(template, begin, end);
      {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

/**
 * A production representing the ${...}
 * that outputs a variable.
 */
  final public DollarVariable StringOutput() throws ParseException {
   Expression exp;
   Token begin, end;
    begin = jj_consume_token(OUTPUT_ESCAPE);
    exp = Expression();
      notHashLiteral(exp, "scalar");
      notListLiteral(exp, "scalar");
      notBooleanLiteral(exp, "scalar");
    end = jj_consume_token(CLOSE_BRACE);
      DollarVariable result = new DollarVariable(exp, escapedExpression(exp));
      result.setLocation(template, begin, end);
      {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public NumericalOutput NumericalOutput() throws ParseException {
   Expression exp;
   Token fmt = null, begin, end;
    begin = jj_consume_token(NUMERICAL_ESCAPE);
    exp = Expression();
                     numberLiteralOnly(exp);
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case SEMICOLON:
      jj_consume_token(SEMICOLON);
      fmt = jj_consume_token(ID);
      break;
    default:
      jj_la1[20] = jj_gen;
      ;
    }
    end = jj_consume_token(CLOSE_BRACE);
      NumericalOutput result;
      if (fmt != null) {
         int minFrac = -1;  // -1 indicates that the value has not been set
         int maxFrac = -1;

         StringTokenizer st = new StringTokenizer(fmt.image, "mM", true);
         char type = '-';
         while (st.hasMoreTokens()) {
             String token = st.nextToken();
             try {
                if (type != '-') {
                    switch (type) {
                    case 'm':
                       if (minFrac != -1) {if (true) throw new ParseException("invalid formatting string", fmt.beginLine, fmt.beginColumn);}
                       minFrac = Integer.parseInt(token);
                       break;
                    case 'M':
                       if (maxFrac != -1) {if (true) throw new ParseException("invalid formatting string", fmt.beginLine, fmt.beginColumn);}
                       maxFrac = Integer.parseInt(token);
                       break;
                    default:
                       {if (true) throw new ParseException();}
                    }
                    type = '-';
                } else if (token.equals("m")) {
                   type = 'm';
                } else if (token.equals("M")) {
                   type = 'M';
                } else {
                   {if (true) throw new ParseException();}
                }
             }
             catch (ParseException e) {
                String msg = getErrorStart(fmt)
                      + "\nInvalid format specifier "
                      + fmt.image;
                {if (true) throw new ParseException(msg, fmt.beginLine, fmt.beginColumn);}
             }
             catch (NumberFormatException e) {
                String msg = getErrorStart(fmt)
                      + "\nInvalid number in the format specifier "
                      + fmt.image;
                {if (true) throw new ParseException(msg, fmt.beginLine, fmt.beginColumn);}
             }
         }

         if (maxFrac == -1) {
            if (minFrac == -1) {
               String msg = getErrorStart(fmt)
                     + "\nInvalid format specification, at least one of m and M must be specified!";
               {if (true) throw new ParseException(msg, fmt.beginLine, fmt.beginColumn);}
            }
            maxFrac = minFrac;
         } else if (minFrac == -1) {
            minFrac = 0;
         }
         if (minFrac > maxFrac) {
            String msg = getErrorStart(fmt)
                  + "\nInvalid format specification, min cannot be greater than max!";
            {if (true) throw new ParseException(msg, fmt.beginLine, fmt.beginColumn);}
         }
         if (minFrac > 50 || maxFrac > 50) {// sanity check
               String msg = getErrorStart(fmt)
               + "\nCannot specify more than 50 fraction digits";
             {if (true) throw new ParseException(msg, fmt.beginLine, fmt.beginColumn);}
         }
         result = new NumericalOutput(exp, minFrac, maxFrac);
      } else {  // if format != null
         result = new NumericalOutput(exp);
      }
      result.setLocation(template, begin, end);
      {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public TemplateElement If() throws ParseException {
    Token start, end, t;
    Expression condition;
    TemplateElement block;
    IfBlock ifBlock;
    ConditionalBlock cblock;
    start = jj_consume_token(IF);
    condition = Expression();
    jj_consume_token(DIRECTIVE_END);
    block = OptionalBlock();
      cblock = new ConditionalBlock(condition, block, true);
      cblock.setLocation(template, start, block);
      ifBlock = new IfBlock(cblock);
    label_8:
    while (true) {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case ELSE_IF:
        ;
        break;
      default:
        jj_la1[21] = jj_gen;
        break label_8;
      }
      t = jj_consume_token(ELSE_IF);
      condition = Expression();
      LooseDirectiveEnd();
      block = OptionalBlock();
          cblock = new ConditionalBlock(condition, block, false);
          cblock.setLocation(template, t, block);
          ifBlock.addBlock(cblock);
    }
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case ELSE:
      t = jj_consume_token(ELSE);
      block = OptionalBlock();
            cblock = new ConditionalBlock(null, block, false);
            cblock.setLocation(template, t, block);
            ifBlock.addBlock(cblock);
      break;
    default:
      jj_la1[22] = jj_gen;
      ;
    }
    end = jj_consume_token(END_IF);
       ifBlock.setLocation(template, start, end);
       {if (true) return ifBlock;}
    throw new Error("Missing return statement in function");
  }

  final public AttemptBlock Attempt() throws ParseException {
   Token start, end;
   TemplateElement block, recoveryBlock;
    start = jj_consume_token(ATTEMPT);
    block = OptionalBlock();
    recoveryBlock = Recover();
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case END_RECOVER:
      end = jj_consume_token(END_RECOVER);
      break;
    case END_ATTEMPT:
      end = jj_consume_token(END_ATTEMPT);
      break;
    default:
      jj_la1[23] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
      AttemptBlock result = new AttemptBlock(block, recoveryBlock);
      result.setLocation(template, start, end);
      {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public RecoveryBlock Recover() throws ParseException {
   Token start;
   TemplateElement block;
    start = jj_consume_token(RECOVER);
    block = OptionalBlock();
      RecoveryBlock result = new RecoveryBlock(block);
      result.setLocation(template, start, block);
      {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public IteratorBlock List() throws ParseException {
    Expression exp;
    Token index, start, end;
    TemplateElement block;
    start = jj_consume_token(LIST);
                 ++loopNesting;
    exp = Expression();
    jj_consume_token(AS);
    index = jj_consume_token(ID);
    jj_consume_token(DIRECTIVE_END);
    block = OptionalBlock();
    end = jj_consume_token(END_LIST);
     --loopNesting;
     IteratorBlock result = new IteratorBlock(exp,
                                              index.image,
                                              block,
                                              false);
     result.setLocation(template, start, end);
     {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public IteratorBlock ForEach() throws ParseException {
     Expression exp;
     Token index, start, end;
     TemplateElement block;
    start = jj_consume_token(FOREACH);
                    ++loopNesting;
    index = jj_consume_token(ID);
    jj_consume_token(IN);
    exp = Expression();
    jj_consume_token(DIRECTIVE_END);
    block = OptionalBlock();
    end = jj_consume_token(END_FOREACH);
     --loopNesting;
     IteratorBlock result = new IteratorBlock(exp,
                                              index.image,
                                              block,
                                              true);
     result.setLocation(template, start, end);
     {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public VisitNode Visit() throws ParseException {
   Token start, end;
   Expression targetNode, namespaces=null;
    start = jj_consume_token(VISIT);
    targetNode = Expression();
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case USING:
      jj_consume_token(USING);
      namespaces = Expression();
      break;
    default:
      jj_la1[24] = jj_gen;
      ;
    }
    end = LooseDirectiveEnd();
       VisitNode result = new VisitNode(targetNode, namespaces);
       result.setLocation(template, start, end);
       {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public RecurseNode Recurse() throws ParseException {
   Token start, end = null;
   Expression node=null, namespaces=null;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case SIMPLE_RECURSE:
      start = jj_consume_token(SIMPLE_RECURSE);
      break;
    case RECURSE:
      start = jj_consume_token(RECURSE);
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case STRING_LITERAL:
      case RAW_STRING:
      case FALSE:
      case TRUE:
      case INTEGER:
      case DECIMAL:
      case DOT:
      case PLUS:
      case MINUS:
      case EXCLAM:
      case OPEN_BRACKET:
      case OPEN_PAREN:
      case OPEN_BRACE:
      case ID:
        node = Expression();
        break;
      default:
        jj_la1[25] = jj_gen;
        ;
      }
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case USING:
        jj_consume_token(USING);
        namespaces = Expression();
        break;
      default:
        jj_la1[26] = jj_gen;
        ;
      }
      end = LooseDirectiveEnd();
      break;
    default:
      jj_la1[27] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
       if (end == null) end = start;
       RecurseNode result = new RecurseNode(node, namespaces);
       result.setLocation(template, start, end);
       {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public FallbackInstruction FallBack() throws ParseException {
   Token tok;
    tok = jj_consume_token(FALLBACK);
      if (!inMacro) {
          {if (true) throw new ParseException(getErrorStart(tok)
                                   + "\nCannot fall back "
                                   + " outside a macro.",
                                   tok.beginLine, tok.beginColumn);}

      }
      FallbackInstruction result = new FallbackInstruction();
      result.setLocation(template, tok, tok);
      {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

/**
 * Production used to break out of a loop or a switch block.
 */
  final public BreakInstruction Break() throws ParseException {
   Token start;
    start = jj_consume_token(BREAK);
       if (loopNesting < 1 && switchNesting <1)
       {
          String msg = getErrorStart(start) + "\n"
                       + start.image
                       + " occurred outside a loop or a switch block.";
          {if (true) throw new ParseException(msg, start.beginLine, start.beginColumn);}
       }
       BreakInstruction result = new BreakInstruction();
       result.setLocation(template, start, start);
       {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

/**
 * Production used to jump out of a macro.
 * The stop instruction terminates the rendering of the template.
 */
  final public ReturnInstruction Return() throws ParseException {
   Token start, end=null;
   Expression exp = null;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case SIMPLE_RETURN:
      start = jj_consume_token(SIMPLE_RETURN);
                            end = start;
      break;
    case RETURN:
      start = jj_consume_token(RETURN);
      exp = Expression();
      end = LooseDirectiveEnd();
      break;
    default:
      jj_la1[28] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
      if (inMacro) {
         if (exp != null) {
            String msg = getErrorStart(start)
                         + "\nA macro cannot return a value";
            {if (true) throw new ParseException(msg, start.beginLine, start.beginColumn);}
         }
      }
      else if (inFunction) {
         if (exp == null) {
            String msg = getErrorStart(start)
                         + "\nA function must return a value";
            {if (true) throw new ParseException(msg, start.beginLine, start.beginColumn);}
         }
      }
      else {
         if (exp == null) {
            String msg = getErrorStart(start)
                         + "\nA return instruction can only occur inside a macro of function";
            {if (true) throw new ParseException(msg, start.beginLine, start.beginColumn);}
         }
      }
      ReturnInstruction result = new ReturnInstruction(exp);
      result.setLocation(template, start, end);
      {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public StopInstruction Stop() throws ParseException {
   Token start = null;
   Expression exp = null;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case HALT:
      start = jj_consume_token(HALT);
      break;
    case STOP:
      start = jj_consume_token(STOP);
      exp = Expression();
      LooseDirectiveEnd();
      break;
    default:
      jj_la1[29] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
       StopInstruction result = new StopInstruction(exp);
       result.setLocation(template, start, start);
       {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public TemplateElement Nested() throws ParseException {
  Token t, end;
  ArrayList bodyParameters;
  BodyInstruction result = null;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case SIMPLE_NESTED:
      t = jj_consume_token(SIMPLE_NESTED);
            result = new BodyInstruction(null);
            result.setLocation(template, t, t);
      break;
    case NESTED:
      t = jj_consume_token(NESTED);
      bodyParameters = PositionalArgs();
      end = LooseDirectiveEnd();
             result = new BodyInstruction(bodyParameters);
             result.setLocation(template, t, end);
      break;
    default:
      jj_la1[30] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
       if (!inMacro) {
          {if (true) throw new ParseException(getErrorStart(t)
                                   + "\nCannot use a "
                                   + t.image
                                   + " instruction outside a macro.",
                                   t.beginLine, t.beginColumn);}
       }
       {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public TemplateElement Flush() throws ParseException {
  Token t;
    t = jj_consume_token(FLUSH);
       FlushInstruction result = new FlushInstruction();
       result.setLocation(template, t, t);
       {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public TemplateElement Trim() throws ParseException {
  Token t;
  TrimInstruction result=null;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case TRIM:
      t = jj_consume_token(TRIM);
               result = new TrimInstruction(true, true);
      break;
    case LTRIM:
      t = jj_consume_token(LTRIM);
                result = new TrimInstruction(true, false);
      break;
    case RTRIM:
      t = jj_consume_token(RTRIM);
                result = new TrimInstruction(false, true);
      break;
    case NOTRIM:
      t = jj_consume_token(NOTRIM);
                 result = new TrimInstruction(false, false);
      break;
    default:
      jj_la1[31] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
       result.setLocation(template, t, t);
       {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public TemplateElement Assign() throws ParseException {
   Token start, end;
   int scope;
   Token id=null;
   Expression nameExp, exp, nsExp=null;
   String varName;
   ArrayList assignments = new ArrayList();
   Assignment ass;
   TemplateElement block;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case ASSIGN:
      start = jj_consume_token(ASSIGN);
                      scope = Assignment.NAMESPACE;
      break;
    case GLOBALASSIGN:
      start = jj_consume_token(GLOBALASSIGN);
                           scope = Assignment.GLOBAL;
      break;
    case LOCALASSIGN:
      start = jj_consume_token(LOCALASSIGN);
                           scope = Assignment.LOCAL;
          scope = Assignment.LOCAL;
          if (!inMacro && !inFunction) {
             String msg = getErrorStart(start)
                          + "\nLocal variable assigned outside a macro.";
             {if (true) throw new ParseException(msg, start.beginLine, start.beginColumn);}
          }
      break;
    default:
      jj_la1[32] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
    nameExp = IdentifierOrStringLiteral();
       varName = (nameExp instanceof StringLiteral) ? ((StringLiteral) nameExp).getAsString() : nameExp.toString();
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case EQUALS:
      jj_consume_token(EQUALS);
      exp = Expression();
          ass = new Assignment(varName, exp, scope);
          ass.setLocation(template, nameExp, exp);
          assignments.add(ass);
      label_9:
      while (true) {
        if (jj_2_11(2147483647)) {
          ;
        } else {
          break label_9;
        }
        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
        case COMMA:
          jj_consume_token(COMMA);
          break;
        default:
          jj_la1[33] = jj_gen;
          ;
        }
        nameExp = IdentifierOrStringLiteral();
               varName = (nameExp instanceof StringLiteral) ? ((StringLiteral) nameExp).getAsString() : nameExp.toString();
        jj_consume_token(EQUALS);
        exp = Expression();
               ass = new Assignment(varName, exp, scope);
               ass.setLocation(template, nameExp, exp);
               assignments.add(ass);
      }
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case IN:
        id = jj_consume_token(IN);
        nsExp = Expression();
                              if (scope != Assignment.NAMESPACE) {if (true) throw new ParseException(getErrorStart(id) + "\nCannot assign to namespace here.", id.beginLine, id.beginColumn);}
        break;
      default:
        jj_la1[34] = jj_gen;
        ;
      }
      end = LooseDirectiveEnd();
           AssignmentInstruction ai = new AssignmentInstruction(scope);
           for (int i = 0; i< assignments.size(); i++) {
                ai.addAssignment((Assignment) assignments.get(i));
           }
           ai.setNamespaceExp(nsExp);
           ai.setLocation(template, start, end);
           {if (true) return ai;}
      break;
    case IN:
    case DIRECTIVE_END:
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case IN:
        id = jj_consume_token(IN);
        nsExp = Expression();
                              if (scope != Assignment.NAMESPACE) {if (true) throw new ParseException(getErrorStart(id) + "\nCannot assign to namespace here.", id.beginLine, id.beginColumn);}
        break;
      default:
        jj_la1[35] = jj_gen;
        ;
      }
      jj_consume_token(DIRECTIVE_END);
      block = OptionalBlock();
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case END_LOCAL:
        end = jj_consume_token(END_LOCAL);
                           if (scope != Assignment.LOCAL) {if (true) throw new ParseException(getErrorStart(end) + "\nMismatched assignment tags.", end.beginLine, end.beginColumn);}
        break;
      case END_ASSIGN:
        end = jj_consume_token(END_ASSIGN);
                            if (scope != Assignment.NAMESPACE) {if (true) throw new ParseException(getErrorStart(end) + "\nMismatched assignment tags.", end.beginLine, end.beginColumn);}
        break;
      case END_GLOBAL:
        end = jj_consume_token(END_GLOBAL);
                            if (scope != Assignment.GLOBAL) {if (true) throw new ParseException(getErrorStart(end) + "\nMismatched assignment tags", end.beginLine, end.beginColumn);}
        break;
      default:
        jj_la1[36] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
          BlockAssignment ba = new BlockAssignment(block, varName, scope, nsExp);
          ba.setLocation(template, start, end);
          {if (true) return ba;}
      break;
    default:
      jj_la1[37] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
    throw new Error("Missing return statement in function");
  }

  final public Include Include() throws ParseException {
   Expression nameExp;
   Token att, start, end;
   Expression exp, parseExp = null, encodingExp = null;
    start = jj_consume_token(_INCLUDE);
    nameExp = Expression();
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case SEMICOLON:
      jj_consume_token(SEMICOLON);
      break;
    default:
      jj_la1[38] = jj_gen;
      ;
    }
    label_10:
    while (true) {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case ID:
        ;
        break;
      default:
        jj_la1[39] = jj_gen;
        break label_10;
      }
      att = jj_consume_token(ID);
      jj_consume_token(EQUALS);
      exp = Expression();
             String attString = att.image;
             if (attString.equalsIgnoreCase("parse")) {
                parseExp = exp;
             }
             else if (attString.equalsIgnoreCase("encoding")) {
                encodingExp = exp;
             }
             else {
                 String msg = getErrorStart(att)
                       + "\nexpecting parse= or encoding= to be specified.";
                 {if (true) throw new ParseException(msg, att.beginLine, att.beginColumn);}
             }
    }
    end = LooseDirectiveEnd();
       Include result = new Include(template, nameExp, encodingExp, parseExp);
       result.setLocation(template, start, end);
       {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public LibraryLoad Import() throws ParseException {
   Token start, end, ns;
   Expression nameExp;
    start = jj_consume_token(IMPORT);
    nameExp = Expression();
    jj_consume_token(AS);
    ns = jj_consume_token(ID);
    end = LooseDirectiveEnd();
       LibraryLoad result = new LibraryLoad(template, nameExp, ns.image);
       result.setLocation(template, start, end);
       template.addImport(result);
       {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public Macro Macro() throws ParseException {
   Token arg, start, end;
   Expression nameExp;
   String name;
   ArrayList argNames = new ArrayList();
   HashMap args = new HashMap();
   ArrayList defNames = new ArrayList();
   Expression defValue=null;
   TemplateElement block;
   boolean isFunction = false, hasDefaults=false;
   boolean isCatchAll = false;
   String catchAll = null;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case MACRO:
      start = jj_consume_token(MACRO);
      break;
    case FUNCTION:
      start = jj_consume_token(FUNCTION);
                          isFunction = true;
      break;
    default:
      jj_la1[40] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
       if (inMacro || inFunction) {
         {if (true) throw new ParseException(getErrorStart(start)
                     + "\nMacros cannot be nested.", start.beginLine, start.endLine);}
       }
       if (isFunction) inFunction = true; else inMacro = true;
    nameExp = IdentifierOrStringLiteral();
       name = (nameExp instanceof StringLiteral) ? ((StringLiteral) nameExp).getAsString() : nameExp.toString();
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case OPEN_PAREN:
      jj_consume_token(OPEN_PAREN);
      break;
    default:
      jj_la1[41] = jj_gen;
      ;
    }
    label_11:
    while (true) {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case ID:
        ;
        break;
      default:
        jj_la1[42] = jj_gen;
        break label_11;
      }
      arg = jj_consume_token(ID);
                    defValue = null;
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case ELLIPSIS:
        jj_consume_token(ELLIPSIS);
                        isCatchAll = true;
        break;
      default:
        jj_la1[43] = jj_gen;
        ;
      }
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case EQUALS:
        jj_consume_token(EQUALS);
        defValue = Expression();
              defNames.add(arg.image);
              hasDefaults = true;
        break;
      default:
        jj_la1[44] = jj_gen;
        ;
      }
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case COMMA:
        jj_consume_token(COMMA);
        break;
      default:
        jj_la1[45] = jj_gen;
        ;
      }
          if (catchAll != null) {
              {if (true) throw new ParseException(getErrorStart(arg)
                + "\nThere may only be one \"catch-all\" parameter in a macro declaration, "
                + "and it must be the last parameter.", arg.beginLine, arg.endLine);}
          }
          if (isCatchAll) {
              if (defValue != null) {
                  {if (true) throw new ParseException(getErrorStart(arg)
                    + "\n\"Catch-all\" macro parameter may not have a default value.",
                    arg.beginLine, arg.endLine);}
              }
              catchAll = arg.image;
          } else {
              argNames.add(arg.image);
              if (hasDefaults && defValue == null) {
                  {if (true) throw new ParseException(getErrorStart(arg)
                    + "\nIn a macro declaration, parameters without a default value "
                    + "must all occur before the parameters with default values.",
                    arg.beginLine, arg.endLine);}
              }
              args.put(arg.image, defValue);
          }
    }
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case CLOSE_PAREN:
      jj_consume_token(CLOSE_PAREN);
      break;
    default:
      jj_la1[46] = jj_gen;
      ;
    }
    jj_consume_token(DIRECTIVE_END);
    block = OptionalBlock();
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case END_MACRO:
      end = jj_consume_token(END_MACRO);
                          if(isFunction) {if (true) throw new ParseException(getErrorStart(start) + "\nExpected function end tag here.", start.beginLine, start.endLine);}
      break;
    case END_FUNCTION:
      end = jj_consume_token(END_FUNCTION);
                             if(!isFunction) {if (true) throw new ParseException(getErrorStart(start) + "\nExpected macro end tag here.", start.beginLine, start.endLine);}
      break;
    default:
      jj_la1[47] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
       inMacro = inFunction = false;
       Macro result = new Macro(name, argNames, args, block);
       result.setCatchAll(catchAll);
       result.isFunction = isFunction;
       result.setLocation(template, start, end);
       template.addMacro(result);
       {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public CompressedBlock Compress() throws ParseException {
   TemplateElement block;
   Token start, end;
    start = jj_consume_token(COMPRESS);
    block = OptionalBlock();
    end = jj_consume_token(END_COMPRESS);
       CompressedBlock cb = new CompressedBlock(block);
       cb.setLocation(template, start, end);
       {if (true) return cb;}
    throw new Error("Missing return statement in function");
  }

  final public TemplateElement UnifiedMacroTransform() throws ParseException {
   Token start=null, end, t;
   HashMap namedArgs = null;
   ArrayList positionalArgs = null, bodyParameters = null;
   String directiveName = null;
   TemplateElement nestedBlock = null;
   Expression exp;
    start = jj_consume_token(UNIFIED_CALL);
    exp = Expression();
        if (exp instanceof Identifier || (exp instanceof Dot && ((Dot) exp).onlyHasIdentifiers())) {
           directiveName = exp.getCanonicalForm();
        }
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case TERMINATING_WHITESPACE:
      jj_consume_token(TERMINATING_WHITESPACE);
      break;
    default:
      jj_la1[48] = jj_gen;
      ;
    }
    if (jj_2_12(2147483647)) {
      namedArgs = NamedArgs();
    } else {
      positionalArgs = PositionalArgs();
    }
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case SEMICOLON:
      jj_consume_token(SEMICOLON);
                   bodyParameters = new ArrayList();
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case ID:
      case TERMINATING_WHITESPACE:
        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
        case TERMINATING_WHITESPACE:
          jj_consume_token(TERMINATING_WHITESPACE);
          break;
        default:
          jj_la1[49] = jj_gen;
          ;
        }
        t = jj_consume_token(ID);
                                             bodyParameters.add(t.image);
        label_12:
        while (true) {
          switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
          case COMMA:
          case TERMINATING_WHITESPACE:
            ;
            break;
          default:
            jj_la1[50] = jj_gen;
            break label_12;
          }
          switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
          case TERMINATING_WHITESPACE:
            jj_consume_token(TERMINATING_WHITESPACE);
            break;
          default:
            jj_la1[51] = jj_gen;
            ;
          }
          jj_consume_token(COMMA);
          switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
          case TERMINATING_WHITESPACE:
            jj_consume_token(TERMINATING_WHITESPACE);
            break;
          default:
            jj_la1[52] = jj_gen;
            ;
          }
          t = jj_consume_token(ID);
                                                  bodyParameters.add(t.image);
        }
        break;
      default:
        jj_la1[53] = jj_gen;
        ;
      }
      break;
    default:
      jj_la1[54] = jj_gen;
      ;
    }
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case EMPTY_DIRECTIVE_END:
      end = jj_consume_token(EMPTY_DIRECTIVE_END);
      break;
    case DIRECTIVE_END:
      jj_consume_token(DIRECTIVE_END);
      nestedBlock = OptionalBlock();
      end = jj_consume_token(UNIFIED_CALL_END);
           String s = end.image.substring(3);
           s = s.substring(0, s.length() -1).trim();
           if (s.length() >0 && !s.equals(directiveName)) {
              String msg = getErrorStart(end);
              if (directiveName == null) {
                    {if (true) throw new ParseException(msg + "\nExpecting </@>", end.beginLine, end.beginColumn);}
              }
              else {
                  {if (true) throw new ParseException(msg + "\nExpecting </@> or </@" + directiveName + ">", end.beginLine, end.beginColumn);}
              }
           }
      break;
    default:
      jj_la1[55] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
       TemplateElement result = (positionalArgs != null) ? new UnifiedCall(exp, positionalArgs, nestedBlock, bodyParameters)
                                         : new UnifiedCall(exp, namedArgs, nestedBlock, bodyParameters);
       result.setLocation(template, start, end);
       {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public TemplateElement Call() throws ParseException {
   Token start, end, id;
   HashMap namedArgs = null;
   ArrayList positionalArgs = null;
   String macroName= null;
    start = jj_consume_token(CALL);
    id = jj_consume_token(ID);
             macroName = id.image;
    if (jj_2_14(2147483647)) {
      namedArgs = NamedArgs();
    } else {
      if (jj_2_13(2147483647)) {
        jj_consume_token(OPEN_PAREN);
      } else {
        ;
      }
      positionalArgs = PositionalArgs();
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case CLOSE_PAREN:
        jj_consume_token(CLOSE_PAREN);
        break;
      default:
        jj_la1[56] = jj_gen;
        ;
      }
    }
    end = LooseDirectiveEnd();
       UnifiedCall result = null;
       if (positionalArgs != null) {
          result = new UnifiedCall(new Identifier(macroName), positionalArgs, null, null);
       }
       else {
          result = new UnifiedCall(new Identifier(macroName), namedArgs, null, null);
       }
       result.legacySyntax = true;
       result.setLocation(template, start, end);
       {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public HashMap NamedArgs() throws ParseException {
    HashMap result = new HashMap();
    Token t;
    Expression exp;
    label_13:
    while (true) {
      t = jj_consume_token(ID);
      jj_consume_token(EQUALS);
         token_source.SwitchTo(token_source.NAMED_PARAMETER_EXPRESSION);
         token_source.inInvocation = true;
      exp = Expression();
        result.put(t.image, exp);
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case ID:
        ;
        break;
      default:
        jj_la1[57] = jj_gen;
        break label_13;
      }
    }
      token_source.inInvocation = false;
     {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public ArrayList PositionalArgs() throws ParseException {
  ArrayList result = new ArrayList();
  Expression arg;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case STRING_LITERAL:
    case RAW_STRING:
    case FALSE:
    case TRUE:
    case INTEGER:
    case DECIMAL:
    case DOT:
    case PLUS:
    case MINUS:
    case EXCLAM:
    case OPEN_BRACKET:
    case OPEN_PAREN:
    case OPEN_BRACE:
    case ID:
      arg = Expression();
                        result.add(arg);
      label_14:
      while (true) {
        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
        case STRING_LITERAL:
        case RAW_STRING:
        case FALSE:
        case TRUE:
        case INTEGER:
        case DECIMAL:
        case DOT:
        case PLUS:
        case MINUS:
        case EXCLAM:
        case COMMA:
        case OPEN_BRACKET:
        case OPEN_PAREN:
        case OPEN_BRACE:
        case ID:
          ;
          break;
        default:
          jj_la1[58] = jj_gen;
          break label_14;
        }
        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
        case COMMA:
          jj_consume_token(COMMA);
          break;
        default:
          jj_la1[59] = jj_gen;
          ;
        }
        arg = Expression();
                           result.add(arg);
      }
      break;
    default:
      jj_la1[60] = jj_gen;
      ;
    }
     {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public Comment Comment() throws ParseException {
   Token start, end;
   StringBuffer buf = new StringBuffer();
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case COMMENT:
      start = jj_consume_token(COMMENT);
      break;
    case TERSE_COMMENT:
      start = jj_consume_token(TERSE_COMMENT);
      break;
    default:
      jj_la1[61] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
    end = UnparsedContent(buf);
       Comment result = new Comment(buf.toString());
       result.setLocation(template, start, end);
       {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public TextBlock NoParse() throws ParseException {
   Token start, end;
   StringBuffer buf = new StringBuffer();
    start = jj_consume_token(NOPARSE);
    end = UnparsedContent(buf);
        TextBlock result = new TextBlock(buf.toString(), true);
        result.setLocation(template, start, end);
        {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public TransformBlock Transform() throws ParseException {
   Token start, end, argName;
   Expression exp, argExp;
   TemplateElement content = null;
   HashMap args = null;
    start = jj_consume_token(TRANSFORM);
    exp = Expression();
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case SEMICOLON:
      jj_consume_token(SEMICOLON);
      break;
    default:
      jj_la1[62] = jj_gen;
      ;
    }
    label_15:
    while (true) {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case ID:
        ;
        break;
      default:
        jj_la1[63] = jj_gen;
        break label_15;
      }
      argName = jj_consume_token(ID);
      jj_consume_token(EQUALS);
      argExp = Expression();
           if (args == null) args = new HashMap();
           args.put(argName.image, argExp);
    }
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case EMPTY_DIRECTIVE_END:
      end = jj_consume_token(EMPTY_DIRECTIVE_END);
      break;
    case DIRECTIVE_END:
      jj_consume_token(DIRECTIVE_END);
      content = OptionalBlock();
      end = jj_consume_token(END_TRANSFORM);
      break;
    default:
      jj_la1[64] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
       TransformBlock result = new TransformBlock(exp, args, content);
       result.setLocation(template, start, end);
       {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public SwitchBlock Switch() throws ParseException {
    SwitchBlock switchBlock;
    Case caseIns;
    Expression switchExp;
    Token start, end;
    boolean defaultFound = false;
    start = jj_consume_token(SWITCH);
    switchExp = Expression();
    jj_consume_token(DIRECTIVE_END);
      ++switchNesting;
      switchBlock = new SwitchBlock(switchExp);
    label_16:
    while (true) {
      if (jj_2_15(2)) {
        ;
      } else {
        break label_16;
      }
      caseIns = Case();
        if (caseIns.isDefault) {
           if (defaultFound) {
                String msg = getErrorStart(start)
                            + "\nYou can only have one default case in a switch statement";
                {if (true) throw new ParseException(msg, start.beginLine, start.beginColumn);}
           }
           defaultFound = true;
        }
        switchBlock.addCase(caseIns);
    }
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case WHITESPACE:
      jj_consume_token(WHITESPACE);
      break;
    default:
      jj_la1[65] = jj_gen;
      ;
    }
    end = jj_consume_token(END_SWITCH);
      --switchNesting;
      switchBlock.setLocation(template, start, end);
      {if (true) return switchBlock;}
    throw new Error("Missing return statement in function");
  }

  final public Case Case() throws ParseException {
    Expression exp = null;
    TemplateElement block;
    boolean isDefault = false;
    Token start;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case WHITESPACE:
      jj_consume_token(WHITESPACE);
      break;
    default:
      jj_la1[66] = jj_gen;
      ;
    }
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case CASE:
      start = jj_consume_token(CASE);
      exp = Expression();
      jj_consume_token(DIRECTIVE_END);
      break;
    case DEFAUL:
      start = jj_consume_token(DEFAUL);
                     isDefault = true;
      break;
    default:
      jj_la1[67] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
    block = OptionalBlock();
       Case result = new Case(exp, block, isDefault);
       result.setLocation(template, start, block);
       {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public EscapeBlock Escape() throws ParseException {
    Token variable, start, end;
    Expression escapeExpr;
    TemplateElement content;
    start = jj_consume_token(ESCAPE);
    variable = jj_consume_token(ID);
    jj_consume_token(AS);
    escapeExpr = Expression();
    jj_consume_token(DIRECTIVE_END);
        EscapeBlock result = new EscapeBlock(variable.image, escapeExpr, escapedExpression(escapeExpr));
        escapes.addFirst(result);
    content = OptionalBlock();
        result.setContent(content);
        escapes.removeFirst();
    end = jj_consume_token(END_ESCAPE);
       result.setLocation(template, start, end);
       {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

  final public NoEscapeBlock NoEscape() throws ParseException {
    Token start, end;
    TemplateElement content;
    start = jj_consume_token(NOESCAPE);
        if(escapes.isEmpty()) {
                String msg = getErrorStart(start)
                                  + "\nnoescape with no matching escape encountered.";
            {if (true) throw new ParseException(msg, start.beginLine, start.beginColumn);}
        }
        Object escape = escapes.removeFirst();
    content = OptionalBlock();
    end = jj_consume_token(END_NOESCAPE);
       escapes.addFirst(escape);
       NoEscapeBlock result = new NoEscapeBlock(content);
       result.setLocation(template, start, end);
       {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

/**
 * Production to terminate potentially empty elements. Either a ">" or "/>"
 */
  final public Token LooseDirectiveEnd() throws ParseException {
    Token t;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case DIRECTIVE_END:
      t = jj_consume_token(DIRECTIVE_END);
      break;
    case EMPTY_DIRECTIVE_END:
      t = jj_consume_token(EMPTY_DIRECTIVE_END);
      break;
    default:
      jj_la1[68] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
      {if (true) return t;}
    throw new Error("Missing return statement in function");
  }

  final public PropertySetting Setting() throws ParseException {
   Token start, end, key;
   Expression value;
    start = jj_consume_token(SETTING);
    key = jj_consume_token(ID);
    jj_consume_token(EQUALS);
    value = Expression();
    end = LooseDirectiveEnd();
      PropertySetting result = new PropertySetting(key.image, value);
      result.setLocation(template, start, end);
      {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

/**
 * A production for FreeMarker directives.
 */
  final public TemplateElement FreemarkerDirective() throws ParseException {
   TemplateElement tp;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case IF:
      tp = If();
      break;
    case LIST:
      tp = List();
      break;
    case FOREACH:
      tp = ForEach();
      break;
    case ASSIGN:
    case GLOBALASSIGN:
    case LOCALASSIGN:
      tp = Assign();
      break;
    case _INCLUDE:
      tp = Include();
      break;
    case IMPORT:
      tp = Import();
      break;
    case FUNCTION:
    case MACRO:
      tp = Macro();
      break;
    case COMPRESS:
      tp = Compress();
      break;
    case UNIFIED_CALL:
      tp = UnifiedMacroTransform();
      break;
    case CALL:
      tp = Call();
      break;
    case COMMENT:
    case TERSE_COMMENT:
      tp = Comment();
      break;
    case NOPARSE:
      tp = NoParse();
      break;
    case TRANSFORM:
      tp = Transform();
      break;
    case SWITCH:
      tp = Switch();
      break;
    case SETTING:
      tp = Setting();
      break;
    case BREAK:
      tp = Break();
      break;
    case RETURN:
    case SIMPLE_RETURN:
      tp = Return();
      break;
    case STOP:
    case HALT:
      tp = Stop();
      break;
    case FLUSH:
      tp = Flush();
      break;
    case TRIM:
    case LTRIM:
    case RTRIM:
    case NOTRIM:
      tp = Trim();
      break;
    case SIMPLE_NESTED:
    case NESTED:
      tp = Nested();
      break;
    case ESCAPE:
      tp = Escape();
      break;
    case NOESCAPE:
      tp = NoEscape();
      break;
    case VISIT:
      tp = Visit();
      break;
    case SIMPLE_RECURSE:
    case RECURSE:
      tp = Recurse();
      break;
    case FALLBACK:
      tp = FallBack();
      break;
    case ATTEMPT:
      tp = Attempt();
      break;
    default:
      jj_la1[69] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
      {if (true) return tp;}
    throw new Error("Missing return statement in function");
  }

/**
 * Production for a block of raw text
 * i.e. text that contains no
 * FreeMarker directives.
 */
  final public TextBlock PCData() throws ParseException {
    StringBuffer buf = new StringBuffer();
    Token t=null, start=null, prevToken = null;
    label_17:
    while (true) {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case WHITESPACE:
          prevToken = t;
        t = jj_consume_token(WHITESPACE);
        break;
      case PRINTABLE_CHARS:
        t = jj_consume_token(PRINTABLE_CHARS);
        break;
      case FALSE_ALERT:
        t = jj_consume_token(FALSE_ALERT);
        break;
      default:
        jj_la1[70] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
         buf.append(t.image);
         if (start == null) start = t;
         {if (prevToken != null) prevToken.next = null;}
      if (jj_2_16(2147483647)) {
        ;
      } else {
        break label_17;
      }
    }
         if (stripText && contentNesting == 1)
             {if (true) return TextBlock.EMPTY_BLOCK;}

         TextBlock result = new TextBlock(buf.toString(), false);
         result.setLocation(template, start, t);
         {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

/**
 * Production for dealing with unparsed content,
 * i.e. what is inside a comment or noparse tag.
 * It returns the ending token. The content
 * of the tag is put in buf.
 */
  final public Token UnparsedContent(StringBuffer buf) throws ParseException {
   Token t;
    label_18:
    while (true) {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case KEEP_GOING:
        t = jj_consume_token(KEEP_GOING);
        break;
      case MAYBE_END:
        t = jj_consume_token(MAYBE_END);
        break;
      case TERSE_COMMENT_END:
        t = jj_consume_token(TERSE_COMMENT_END);
        break;
      case LONE_LESS_THAN_OR_DASH:
        t = jj_consume_token(LONE_LESS_THAN_OR_DASH);
        break;
      default:
        jj_la1[71] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
       buf.append(t.image);
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case TERSE_COMMENT_END:
      case MAYBE_END:
      case KEEP_GOING:
      case LONE_LESS_THAN_OR_DASH:
        ;
        break;
      default:
        jj_la1[72] = jj_gen;
        break label_18;
      }
    }
      buf.setLength(buf.length() - t.image.length());
      {if (true) return t;}
    throw new Error("Missing return statement in function");
  }

  final public TemplateElement Content() throws ParseException {
    MixedContent nodes = new MixedContent();
    TemplateElement elem, begin=null;
    contentNesting++;
    label_19:
    while (true) {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case WHITESPACE:
      case PRINTABLE_CHARS:
      case FALSE_ALERT:
        elem = PCData();
        break;
      case OUTPUT_ESCAPE:
        elem = StringOutput();
        break;
      case NUMERICAL_ESCAPE:
        elem = NumericalOutput();
        break;
      case ATTEMPT:
      case IF:
      case LIST:
      case FOREACH:
      case SWITCH:
      case ASSIGN:
      case GLOBALASSIGN:
      case LOCALASSIGN:
      case _INCLUDE:
      case IMPORT:
      case FUNCTION:
      case MACRO:
      case TRANSFORM:
      case VISIT:
      case STOP:
      case RETURN:
      case CALL:
      case SETTING:
      case COMPRESS:
      case COMMENT:
      case TERSE_COMMENT:
      case NOPARSE:
      case BREAK:
      case SIMPLE_RETURN:
      case HALT:
      case FLUSH:
      case TRIM:
      case LTRIM:
      case RTRIM:
      case NOTRIM:
      case SIMPLE_NESTED:
      case NESTED:
      case SIMPLE_RECURSE:
      case RECURSE:
      case FALLBACK:
      case ESCAPE:
      case NOESCAPE:
      case UNIFIED_CALL:
        elem = FreemarkerDirective();
        break;
      default:
        jj_la1[73] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
            if (begin == null) {
               begin = elem;
            }
            nodes.addElement(elem);
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case ATTEMPT:
      case IF:
      case LIST:
      case FOREACH:
      case SWITCH:
      case ASSIGN:
      case GLOBALASSIGN:
      case LOCALASSIGN:
      case _INCLUDE:
      case IMPORT:
      case FUNCTION:
      case MACRO:
      case TRANSFORM:
      case VISIT:
      case STOP:
      case RETURN:
      case CALL:
      case SETTING:
      case COMPRESS:
      case COMMENT:
      case TERSE_COMMENT:
      case NOPARSE:
      case BREAK:
      case SIMPLE_RETURN:
      case HALT:
      case FLUSH:
      case TRIM:
      case LTRIM:
      case RTRIM:
      case NOTRIM:
      case SIMPLE_NESTED:
      case NESTED:
      case SIMPLE_RECURSE:
      case RECURSE:
      case FALLBACK:
      case ESCAPE:
      case NOESCAPE:
      case UNIFIED_CALL:
      case WHITESPACE:
      case PRINTABLE_CHARS:
      case FALSE_ALERT:
      case OUTPUT_ESCAPE:
      case NUMERICAL_ESCAPE:
        ;
        break;
      default:
        jj_la1[74] = jj_gen;
        break label_19;
      }
    }
        contentNesting--;
        nodes.setLocation(template, begin, elem);
        {if (true) return nodes;}
    throw new Error("Missing return statement in function");
  }

/**
 * A production freemarker text that may contain
 * ${...} and #{...} but no directives.
 */
  final public TemplateElement FreeMarkerText() throws ParseException {
     MixedContent nodes = new MixedContent();
     TemplateElement elem, begin = null;
    label_20:
    while (true) {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case WHITESPACE:
      case PRINTABLE_CHARS:
      case FALSE_ALERT:
        elem = PCData();
        break;
      case OUTPUT_ESCAPE:
        elem = StringOutput();
        break;
      case NUMERICAL_ESCAPE:
        elem = NumericalOutput();
        break;
      default:
        jj_la1[75] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
         if (begin == null) {
            begin = elem;
         }
         nodes.addElement(elem);
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case WHITESPACE:
      case PRINTABLE_CHARS:
      case FALSE_ALERT:
      case OUTPUT_ESCAPE:
      case NUMERICAL_ESCAPE:
        ;
        break;
      default:
        jj_la1[76] = jj_gen;
        break label_20;
      }
    }
       nodes.setLocation(template, begin, elem);
       {if (true) return nodes;}
    throw new Error("Missing return statement in function");
  }

/**
 * A production for a block of optional content.
 * Returns an empty Text block if there is no
 * content.
 */
  final public TemplateElement OptionalBlock() throws ParseException {
   TemplateElement tp = TextBlock.EMPTY_BLOCK;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case ATTEMPT:
    case IF:
    case LIST:
    case FOREACH:
    case SWITCH:
    case ASSIGN:
    case GLOBALASSIGN:
    case LOCALASSIGN:
    case _INCLUDE:
    case IMPORT:
    case FUNCTION:
    case MACRO:
    case TRANSFORM:
    case VISIT:
    case STOP:
    case RETURN:
    case CALL:
    case SETTING:
    case COMPRESS:
    case COMMENT:
    case TERSE_COMMENT:
    case NOPARSE:
    case BREAK:
    case SIMPLE_RETURN:
    case HALT:
    case FLUSH:
    case TRIM:
    case LTRIM:
    case RTRIM:
    case NOTRIM:
    case SIMPLE_NESTED:
    case NESTED:
    case SIMPLE_RECURSE:
    case RECURSE:
    case FALLBACK:
    case ESCAPE:
    case NOESCAPE:
    case UNIFIED_CALL:
    case WHITESPACE:
    case PRINTABLE_CHARS:
    case FALSE_ALERT:
    case OUTPUT_ESCAPE:
    case NUMERICAL_ESCAPE:
      // has no effect but to get rid of a spurious warning.
               tp = Content();
      break;
    default:
      jj_la1[77] = jj_gen;
      ;
    }
      {if (true) return tp;}
    throw new Error("Missing return statement in function");
  }

  final public void HeaderElement() throws ParseException {
   Token key;
   Expression exp = null;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case WHITESPACE:
      jj_consume_token(WHITESPACE);
      break;
    default:
      jj_la1[78] = jj_gen;
      ;
    }
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case TRIVIAL_FTL_HEADER:
      jj_consume_token(TRIVIAL_FTL_HEADER);
      break;
    case FTL_HEADER:
      jj_consume_token(FTL_HEADER);
      label_21:
      while (true) {
        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
        case ID:
          ;
          break;
        default:
          jj_la1[79] = jj_gen;
          break label_21;
        }
        key = jj_consume_token(ID);
        jj_consume_token(EQUALS);
        exp = Expression();
             String ks = key.image;
             TemplateModel value = null;
             try {
                value = exp.getAsTemplateModel(null);
             } catch (Exception e) {
                {if (true) throw new ParseException("Could not evaluate expression: "
                                         + exp.getCanonicalForm() + " "
                                         + exp.getStartLocation()
                                         + "\nUnderlying cause: " +
                                         e.getMessage(), exp);}
             }
             String vs = null;
             if (value instanceof TemplateScalarModel) {
                try {
                   vs = ((TemplateScalarModel) exp).getAsString();
                } catch (TemplateModelException tme) {}
             }
             if (template != null) {
                 if (ks.equalsIgnoreCase("encoding")) {
                     if (vs == null) {
                        {if (true) throw new ParseException("expecting encoding string here: "
                                                 + exp.getStartLocation(), exp);}
                     }
                     String encoding = template.getEncoding();
                     if (encoding != null && !encoding.equals(vs)) {
                         {if (true) throw new Template.WrongEncodingException(vs);}
                     }
                 }
                 else if (ks.equalsIgnoreCase("STRIP_WHITESPACE")) {
                     this.stripWhitespace = getBoolean(exp);
                 }
                 else if (ks.equalsIgnoreCase("STRIP_TEXT")) {
                     this.stripText = getBoolean(exp);
                 }
                 else if (ks.equalsIgnoreCase("STRICT_SYNTAX")) {
                     this.token_source.strictEscapeSyntax = getBoolean(exp);
                 }
                 else if (ks.equalsIgnoreCase("ns_prefixes")) {
                     if (!(value instanceof TemplateHashModelEx)) {
                         {if (true) throw new ParseException("Expecting a hash of prefixes to namespace URI's here. " + exp.getStartLocation(), exp);}
                     }
                     TemplateHashModelEx prefixMap = (TemplateHashModelEx) value;
                     try {
                         TemplateCollectionModel keys = prefixMap.keys();
                         for (TemplateModelIterator it = keys.iterator(); it.hasNext();) {
                             String prefix = ((TemplateScalarModel) it.next()).getAsString();
                             TemplateModel valueModel = prefixMap.get(prefix);
                             if (!(valueModel instanceof TemplateScalarModel)) {
                                 {if (true) throw new ParseException("Non-string value in prefix to namespace hash. " + exp.getStartLocation(), exp);}
                             }
                             String nsURI = ((TemplateScalarModel) valueModel).getAsString();
                             try {
                                 template.addPrefixNSMapping(prefix, nsURI);
                             } catch (IllegalArgumentException iae) {
                                 {if (true) throw new ParseException(iae.getMessage() + " " + exp.getStartLocation(), exp);}
                             }
                         }
                     } catch (TemplateModelException tme) {
                     }
                 }
                 else if (ks.equalsIgnoreCase("attributes")) {
                     if (!(value instanceof TemplateHashModelEx)) {
                         {if (true) throw new ParseException("Expecting a hash of attribute names to values here. " + exp.getStartLocation(), exp);}
                     }
                     TemplateHashModelEx attributeMap = (TemplateHashModelEx) value;
                     try {
                         TemplateCollectionModel keys = attributeMap.keys();
                         for (TemplateModelIterator it = keys.iterator(); it.hasNext();) {
                             String attName = ((TemplateScalarModel) it.next()).getAsString();
                             Object attValue = DeepUnwrap.unwrap(attributeMap.get(attName));
                             template.setCustomAttribute(attName, attValue);
                         }
                     } catch (TemplateModelException tme) {
                     }
                 }
                 else {
                     {if (true) throw new ParseException("Unknown FTL header parameter: " + key.image,
                                               key.beginLine, key.beginColumn);}
                 }
             }
      }
      LooseDirectiveEnd();
      break;
    default:
      jj_la1[80] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
  }

  final public Map ParamList() throws ParseException {
   Identifier id;
   Expression exp;
   Map result = new HashMap();
    label_22:
    while (true) {
      id = Identifier();
      jj_consume_token(EQUALS);
      exp = Expression();
                        result.put(id.toString(), exp);
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case COMMA:
        jj_consume_token(COMMA);
        break;
      default:
        jj_la1[81] = jj_gen;
        ;
      }
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case ID:
        ;
        break;
      default:
        jj_la1[82] = jj_gen;
        break label_22;
      }
    }
       {if (true) return result;}
    throw new Error("Missing return statement in function");
  }

/**
 * Root production to be used when parsing
 * an entire file.
 */
  final public TemplateElement Root() throws ParseException {
   TemplateElement doc;
    if (jj_2_17(2147483647)) {
      HeaderElement();
    } else {
      ;
    }
    doc = OptionalBlock();
    jj_consume_token(0);
       doc.setParentRecursively(null);
       {if (true) return doc.postParseCleanup(stripWhitespace);}
    throw new Error("Missing return statement in function");
  }

  final private boolean jj_2_1(int xla) {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_1(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(0, xla); }
  }

  final private boolean jj_2_2(int xla) {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_2(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(1, xla); }
  }

  final private boolean jj_2_3(int xla) {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_3(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(2, xla); }
  }

  final private boolean jj_2_4(int xla) {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_4(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(3, xla); }
  }

  final private boolean jj_2_5(int xla) {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_5(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(4, xla); }
  }

  final private boolean jj_2_6(int xla) {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_6(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(5, xla); }
  }

  final private boolean jj_2_7(int xla) {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_7(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(6, xla); }
  }

  final private boolean jj_2_8(int xla) {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_8(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(7, xla); }
  }

  final private boolean jj_2_9(int xla) {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_9(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(8, xla); }
  }

  final private boolean jj_2_10(int xla) {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_10(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(9, xla); }
  }

  final private boolean jj_2_11(int xla) {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_11(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(10, xla); }
  }

  final private boolean jj_2_12(int xla) {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_12(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(11, xla); }
  }

  final private boolean jj_2_13(int xla) {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_13(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(12, xla); }
  }

  final private boolean jj_2_14(int xla) {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_14(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(13, xla); }
  }

  final private boolean jj_2_15(int xla) {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_15(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(14, xla); }
  }

  final private boolean jj_2_16(int xla) {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_16(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(15, xla); }
  }

  final private boolean jj_2_17(int xla) {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_17(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(16, xla); }
  }

  final private boolean jj_3R_32() {
    if (jj_3R_35()) return true;
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_36()) jj_scanpos = xsp;
    return false;
  }

  final private boolean jj_3R_110() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(56)) {
    jj_scanpos = xsp;
    if (jj_3R_132()) return true;
    }
    return false;
  }

  final private boolean jj_3R_108() {
    if (jj_scan_token(NOESCAPE)) return true;
    return false;
  }

  final private boolean jj_3R_170() {
    if (jj_scan_token(OPEN_BRACKET)) return true;
    if (jj_3R_23()) return true;
    if (jj_scan_token(CLOSE_BRACKET)) return true;
    return false;
  }

  final private boolean jj_3R_122() {
    if (jj_scan_token(FUNCTION)) return true;
    return false;
  }

  final private boolean jj_3_3() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(100)) {
    jj_scanpos = xsp;
    if (jj_scan_token(103)) {
    jj_scanpos = xsp;
    if (jj_scan_token(104)) return true;
    }
    }
    return false;
  }

  final private boolean jj_3R_118() {
    if (jj_scan_token(PERCENT)) return true;
    return false;
  }

  final private boolean jj_3R_92() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(20)) {
    jj_scanpos = xsp;
    if (jj_3R_122()) return true;
    }
    return false;
  }

  final private boolean jj_3R_117() {
    if (jj_scan_token(DIVIDE)) return true;
    return false;
  }

  final private boolean jj_3R_109() {
    if (jj_scan_token(VISIT)) return true;
    return false;
  }

  final private boolean jj_3R_116() {
    if (jj_scan_token(TIMES)) return true;
    return false;
  }

  final private boolean jj_3R_82() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_116()) {
    jj_scanpos = xsp;
    if (jj_3R_117()) {
    jj_scanpos = xsp;
    if (jj_3R_118()) return true;
    }
    }
    if (jj_3R_81()) return true;
    return false;
  }

  final private boolean jj_3R_107() {
    if (jj_scan_token(ESCAPE)) return true;
    return false;
  }

  final private boolean jj_3R_50() {
    if (jj_3R_81()) return true;
    Token xsp;
    while (true) {
      xsp = jj_scanpos;
      if (jj_3R_82()) { jj_scanpos = xsp; break; }
    }
    return false;
  }

  final private boolean jj_3R_88() {
    if (jj_scan_token(FOREACH)) return true;
    return false;
  }

  final private boolean jj_3R_176() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(94)) {
    jj_scanpos = xsp;
    if (jj_scan_token(95)) {
    jj_scanpos = xsp;
    if (jj_scan_token(96)) {
    jj_scanpos = xsp;
    if (jj_scan_token(97)) {
    jj_scanpos = xsp;
    if (jj_scan_token(83)) {
    jj_scanpos = xsp;
    if (jj_scan_token(84)) {
    jj_scanpos = xsp;
    if (jj_scan_token(117)) {
    jj_scanpos = xsp;
    if (jj_scan_token(118)) {
    jj_scanpos = xsp;
    if (jj_scan_token(119)) return true;
    }
    }
    }
    }
    }
    }
    }
    }
    return false;
  }

  final private boolean jj_3R_27() {
    if (jj_scan_token(DEFAUL)) return true;
    return false;
  }

  final private boolean jj_3R_26() {
    if (jj_scan_token(CASE)) return true;
    if (jj_3R_23()) return true;
    return false;
  }

  final private boolean jj_3R_91() {
    if (jj_scan_token(IMPORT)) return true;
    return false;
  }

  final private boolean jj_3R_169() {
    if (jj_scan_token(DOT)) return true;
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(120)) {
    jj_scanpos = xsp;
    if (jj_scan_token(100)) {
    jj_scanpos = xsp;
    if (jj_scan_token(101)) {
    jj_scanpos = xsp;
    if (jj_3R_176()) return true;
    }
    }
    }
    return false;
  }

  final private boolean jj_3R_24() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(68)) jj_scanpos = xsp;
    xsp = jj_scanpos;
    if (jj_3R_26()) {
    jj_scanpos = xsp;
    if (jj_3R_27()) return true;
    }
    if (jj_3R_28()) return true;
    return false;
  }

  final private boolean jj_3_2() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(98)) {
    jj_scanpos = xsp;
    if (jj_scan_token(99)) return true;
    }
    return false;
  }

  final private boolean jj_3R_84() {
    if (jj_scan_token(MINUS)) return true;
    return false;
  }

  final private boolean jj_3R_83() {
    if (jj_scan_token(PLUS)) return true;
    return false;
  }

  final private boolean jj_3R_87() {
    if (jj_scan_token(LIST)) return true;
    return false;
  }

  final private boolean jj_3R_51() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_83()) {
    jj_scanpos = xsp;
    if (jj_3R_84()) return true;
    }
    if (jj_3R_50()) return true;
    return false;
  }

  final private boolean jj_3R_44() {
    if (jj_3R_50()) return true;
    Token xsp;
    while (true) {
      xsp = jj_scanpos;
      if (jj_3R_51()) { jj_scanpos = xsp; break; }
    }
    return false;
  }

  final private boolean jj_3R_172() {
    if (jj_scan_token(BUILT_IN)) return true;
    if (jj_scan_token(ID)) return true;
    return false;
  }

  final private boolean jj_3_15() {
    if (jj_3R_24()) return true;
    return false;
  }

  final private boolean jj_3R_90() {
    if (jj_scan_token(_INCLUDE)) return true;
    return false;
  }

  final private boolean jj_3R_136() {
    if (jj_scan_token(MINUS)) return true;
    return false;
  }

  final private boolean jj_3R_99() {
    if (jj_scan_token(SWITCH)) return true;
    return false;
  }

  final private boolean jj_3R_174() {
    if (jj_scan_token(EXISTS)) return true;
    return false;
  }

  final private boolean jj_3R_133() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(98)) {
    jj_scanpos = xsp;
    if (jj_3R_136()) return true;
    }
    if (jj_3R_135()) return true;
    return false;
  }

  final private boolean jj_3_10() {
    if (jj_3R_23()) return true;
    return false;
  }

  final private boolean jj_3R_112() {
    if (jj_scan_token(ATTEMPT)) return true;
    return false;
  }

  final private boolean jj_3R_178() {
    if (jj_3R_23()) return true;
    return false;
  }

  final private boolean jj_3R_137() {
    if (jj_scan_token(EXCLAM)) return true;
    return false;
  }

  final private boolean jj_3R_177() {
    if (jj_scan_token(EXCLAM)) return true;
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_178()) jj_scanpos = xsp;
    return false;
  }

  final private boolean jj_3R_134() {
    Token xsp;
    if (jj_3R_137()) return true;
    while (true) {
      xsp = jj_scanpos;
      if (jj_3R_137()) { jj_scanpos = xsp; break; }
    }
    if (jj_3R_135()) return true;
    return false;
  }

  final private boolean jj_3R_173() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(128)) {
    jj_scanpos = xsp;
    if (jj_3R_177()) return true;
    }
    return false;
  }

  final private boolean jj_3R_98() {
    if (jj_scan_token(TRANSFORM)) return true;
    return false;
  }

  final private boolean jj_3R_31() {
    if (jj_3R_34()) return true;
    return false;
  }

  final private boolean jj_3_11() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(108)) jj_scanpos = xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(120)) {
    jj_scanpos = xsp;
    if (jj_scan_token(81)) return true;
    }
    if (jj_scan_token(EQUALS)) return true;
    return false;
  }

  final private boolean jj_3R_28() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_31()) jj_scanpos = xsp;
    return false;
  }

  final private boolean jj_3R_166() {
    if (jj_3R_174()) return true;
    return false;
  }

  final private boolean jj_3R_165() {
    if (jj_3R_173()) return true;
    return false;
  }

  final private boolean jj_3R_164() {
    if (jj_3R_172()) return true;
    return false;
  }

  final private boolean jj_3R_163() {
    if (jj_3R_171()) return true;
    return false;
  }

  final private boolean jj_3R_162() {
    if (jj_3R_170()) return true;
    return false;
  }

  final private boolean jj_3R_161() {
    if (jj_3R_169()) return true;
    return false;
  }

  final private boolean jj_3R_97() {
    if (jj_scan_token(NOPARSE)) return true;
    return false;
  }

  final private boolean jj_3R_155() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_161()) {
    jj_scanpos = xsp;
    if (jj_3R_162()) {
    jj_scanpos = xsp;
    if (jj_3R_163()) {
    jj_scanpos = xsp;
    if (jj_3R_164()) {
    jj_scanpos = xsp;
    if (jj_3R_165()) {
    jj_scanpos = xsp;
    if (jj_3R_166()) return true;
    }
    }
    }
    }
    }
    return false;
  }

  final private boolean jj_3R_86() {
    if (jj_scan_token(IF)) return true;
    return false;
  }

  final private boolean jj_3R_115() {
    if (jj_3R_135()) return true;
    return false;
  }

  final private boolean jj_3R_114() {
    if (jj_3R_134()) return true;
    return false;
  }

  final private boolean jj_3R_113() {
    if (jj_3R_133()) return true;
    return false;
  }

  final private boolean jj_3R_81() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_113()) {
    jj_scanpos = xsp;
    if (jj_3R_114()) {
    jj_scanpos = xsp;
    if (jj_3R_115()) return true;
    }
    }
    return false;
  }

  final private boolean jj_3R_96() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(28)) {
    jj_scanpos = xsp;
    if (jj_scan_token(29)) return true;
    }
    return false;
  }

  final private boolean jj_3R_121() {
    if (jj_scan_token(LOCALASSIGN)) return true;
    return false;
  }

  final private boolean jj_3R_120() {
    if (jj_scan_token(GLOBALASSIGN)) return true;
    return false;
  }

  final private boolean jj_3R_119() {
    if (jj_scan_token(ASSIGN)) return true;
    return false;
  }

  final private boolean jj_3R_154() {
    if (jj_scan_token(DOT)) return true;
    if (jj_scan_token(ID)) return true;
    return false;
  }

  final private boolean jj_3R_89() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_119()) {
    jj_scanpos = xsp;
    if (jj_3R_120()) {
    jj_scanpos = xsp;
    if (jj_3R_121()) return true;
    }
    }
    return false;
  }

  final private boolean jj_3R_175() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(108)) jj_scanpos = xsp;
    if (jj_3R_23()) return true;
    return false;
  }

  final private boolean jj_3R_168() {
    if (jj_3R_23()) return true;
    Token xsp;
    while (true) {
      xsp = jj_scanpos;
      if (jj_3R_175()) { jj_scanpos = xsp; break; }
    }
    return false;
  }

  final private boolean jj_3R_153() {
    if (jj_scan_token(OPEN_PAREN)) return true;
    if (jj_3R_23()) return true;
    if (jj_scan_token(CLOSE_PAREN)) return true;
    return false;
  }

  final private boolean jj_3R_160() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_168()) jj_scanpos = xsp;
    return false;
  }

  final private boolean jj_3R_43() {
    if (jj_3R_49()) return true;
    return false;
  }

  final private boolean jj_3R_42() {
    if (jj_3R_48()) return true;
    return false;
  }

  final private boolean jj_3_1() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(87)) {
    jj_scanpos = xsp;
    if (jj_scan_token(111)) {
    jj_scanpos = xsp;
    if (jj_scan_token(113)) {
    jj_scanpos = xsp;
    if (jj_scan_token(89)) {
    jj_scanpos = xsp;
    if (jj_scan_token(107)) {
    jj_scanpos = xsp;
    if (jj_scan_token(128)) {
    jj_scanpos = xsp;
    if (jj_scan_token(90)) return true;
    }
    }
    }
    }
    }
    }
    return false;
  }

  final private boolean jj_3R_41() {
    if (jj_3R_47()) return true;
    return false;
  }

  final private boolean jj_3R_40() {
    if (jj_3R_46()) return true;
    return false;
  }

  final private boolean jj_3R_129() {
    if (jj_scan_token(NOTRIM)) return true;
    return false;
  }

  final private boolean jj_3R_37() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_40()) {
    jj_scanpos = xsp;
    if (jj_3R_41()) {
    jj_scanpos = xsp;
    if (jj_3R_42()) {
    jj_scanpos = xsp;
    if (jj_3R_43()) return true;
    }
    }
    }
    return false;
  }

  final private boolean jj_3R_128() {
    if (jj_scan_token(RTRIM)) return true;
    return false;
  }

  final private boolean jj_3R_127() {
    if (jj_scan_token(LTRIM)) return true;
    return false;
  }

  final private boolean jj_3R_146() {
    if (jj_3R_155()) return true;
    return false;
  }

  final private boolean jj_3R_34() {
    Token xsp;
    if (jj_3R_37()) return true;
    while (true) {
      xsp = jj_scanpos;
      if (jj_3R_37()) { jj_scanpos = xsp; break; }
    }
    return false;
  }

  final private boolean jj_3R_126() {
    if (jj_scan_token(TRIM)) return true;
    return false;
  }

  final private boolean jj_3R_152() {
    if (jj_scan_token(ID)) return true;
    return false;
  }

  final private boolean jj_3R_145() {
    if (jj_3R_154()) return true;
    return false;
  }

  final private boolean jj_3R_105() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_126()) {
    jj_scanpos = xsp;
    if (jj_3R_127()) {
    jj_scanpos = xsp;
    if (jj_3R_128()) {
    jj_scanpos = xsp;
    if (jj_3R_129()) return true;
    }
    }
    }
    return false;
  }

  final private boolean jj_3R_144() {
    if (jj_3R_153()) return true;
    return false;
  }

  final private boolean jj_3R_143() {
    if (jj_3R_152()) return true;
    return false;
  }

  final private boolean jj_3R_142() {
    if (jj_3R_151()) return true;
    return false;
  }

  final private boolean jj_3R_141() {
    if (jj_3R_150()) return true;
    return false;
  }

  final private boolean jj_3R_140() {
    if (jj_3R_149()) return true;
    return false;
  }

  final private boolean jj_3R_139() {
    if (jj_3R_148()) return true;
    return false;
  }

  final private boolean jj_3R_138() {
    if (jj_3R_147()) return true;
    return false;
  }

  final private boolean jj_3R_104() {
    if (jj_scan_token(FLUSH)) return true;
    return false;
  }

  final private boolean jj_3_13() {
    if (jj_scan_token(OPEN_PAREN)) return true;
    return false;
  }

  final private boolean jj_3R_135() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_138()) {
    jj_scanpos = xsp;
    if (jj_3R_139()) {
    jj_scanpos = xsp;
    if (jj_3R_140()) {
    jj_scanpos = xsp;
    if (jj_3R_141()) {
    jj_scanpos = xsp;
    if (jj_3R_142()) {
    jj_scanpos = xsp;
    if (jj_3R_143()) {
    jj_scanpos = xsp;
    if (jj_3R_144()) {
    jj_scanpos = xsp;
    if (jj_3R_145()) return true;
    }
    }
    }
    }
    }
    }
    }
    while (true) {
      xsp = jj_scanpos;
      if (jj_3R_146()) { jj_scanpos = xsp; break; }
    }
    return false;
  }

  final private boolean jj_3R_147() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(85)) {
    jj_scanpos = xsp;
    if (jj_scan_token(86)) return true;
    }
    return false;
  }

  final private boolean jj_3_14() {
    if (jj_scan_token(ID)) return true;
    if (jj_scan_token(EQUALS)) return true;
    return false;
  }

  final private boolean jj_3R_151() {
    if (jj_scan_token(OPEN_BRACKET)) return true;
    if (jj_3R_160()) return true;
    if (jj_scan_token(CLOSE_BRACKET)) return true;
    return false;
  }

  final private boolean jj_3R_23() {
    if (jj_3R_25()) return true;
    return false;
  }

  final private boolean jj_3R_131() {
    if (jj_scan_token(NESTED)) return true;
    return false;
  }

  final private boolean jj_3_16() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(68)) {
    jj_scanpos = xsp;
    if (jj_scan_token(69)) {
    jj_scanpos = xsp;
    if (jj_scan_token(70)) return true;
    }
    }
    return false;
  }

  final private boolean jj_3R_48() {
    if (jj_scan_token(NUMERICAL_ESCAPE)) return true;
    return false;
  }

  final private boolean jj_3R_95() {
    if (jj_scan_token(CALL)) return true;
    return false;
  }

  final private boolean jj_3_9() {
    if (jj_scan_token(OR)) return true;
    return false;
  }

  final private boolean jj_3R_85() {
    if (jj_scan_token(WHITESPACE)) return true;
    return false;
  }

  final private boolean jj_3R_130() {
    if (jj_scan_token(SIMPLE_NESTED)) return true;
    return false;
  }

  final private boolean jj_3R_53() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_85()) {
    jj_scanpos = xsp;
    if (jj_scan_token(69)) {
    jj_scanpos = xsp;
    if (jj_scan_token(70)) return true;
    }
    }
    return false;
  }

  final private boolean jj_3R_106() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_130()) {
    jj_scanpos = xsp;
    if (jj_3R_131()) return true;
    }
    return false;
  }

  final private boolean jj_3R_46() {
    Token xsp;
    if (jj_3R_53()) return true;
    while (true) {
      xsp = jj_scanpos;
      if (jj_3R_53()) { jj_scanpos = xsp; break; }
    }
    return false;
  }

  final private boolean jj_3R_30() {
    if (jj_scan_token(OR)) return true;
    if (jj_3R_29()) return true;
    return false;
  }

  final private boolean jj_3R_25() {
    if (jj_3R_29()) return true;
    Token xsp;
    while (true) {
      xsp = jj_scanpos;
      if (jj_3R_30()) { jj_scanpos = xsp; break; }
    }
    return false;
  }

  final private boolean jj_3R_47() {
    if (jj_scan_token(OUTPUT_ESCAPE)) return true;
    return false;
  }

  final private boolean jj_3R_125() {
    if (jj_scan_token(STOP)) return true;
    return false;
  }

  final private boolean jj_3_8() {
    if (jj_scan_token(AND)) return true;
    return false;
  }

  final private boolean jj_3R_103() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(47)) {
    jj_scanpos = xsp;
    if (jj_3R_125()) return true;
    }
    return false;
  }

  final private boolean jj_3R_80() {
    if (jj_3R_112()) return true;
    return false;
  }

  final private boolean jj_3R_79() {
    if (jj_3R_111()) return true;
    return false;
  }

  final private boolean jj_3R_78() {
    if (jj_3R_110()) return true;
    return false;
  }

  final private boolean jj_3R_33() {
    if (jj_scan_token(AND)) return true;
    if (jj_3R_32()) return true;
    return false;
  }

  final private boolean jj_3R_77() {
    if (jj_3R_109()) return true;
    return false;
  }

  final private boolean jj_3R_76() {
    if (jj_3R_108()) return true;
    return false;
  }

  final private boolean jj_3R_75() {
    if (jj_3R_107()) return true;
    return false;
  }

  final private boolean jj_3R_29() {
    if (jj_3R_32()) return true;
    Token xsp;
    while (true) {
      xsp = jj_scanpos;
      if (jj_3R_33()) { jj_scanpos = xsp; break; }
    }
    return false;
  }

  final private boolean jj_3_12() {
    if (jj_scan_token(ID)) return true;
    if (jj_scan_token(EQUALS)) return true;
    return false;
  }

  final private boolean jj_3R_74() {
    if (jj_3R_106()) return true;
    return false;
  }

  final private boolean jj_3R_73() {
    if (jj_3R_105()) return true;
    return false;
  }

  final private boolean jj_3R_167() {
    if (jj_scan_token(COMMA)) return true;
    if (jj_3R_23()) return true;
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(108)) {
    jj_scanpos = xsp;
    if (jj_scan_token(110)) return true;
    }
    if (jj_3R_23()) return true;
    return false;
  }

  final private boolean jj_3R_72() {
    if (jj_3R_104()) return true;
    return false;
  }

  final private boolean jj_3R_71() {
    if (jj_3R_103()) return true;
    return false;
  }

  final private boolean jj_3R_70() {
    if (jj_3R_102()) return true;
    return false;
  }

  final private boolean jj_3R_69() {
    if (jj_3R_101()) return true;
    return false;
  }

  final private boolean jj_3R_68() {
    if (jj_3R_100()) return true;
    return false;
  }

  final private boolean jj_3_6() {
    if (jj_3R_23()) return true;
    return false;
  }

  final private boolean jj_3R_67() {
    if (jj_3R_99()) return true;
    return false;
  }

  final private boolean jj_3R_156() {
    if (jj_3R_23()) return true;
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(108)) {
    jj_scanpos = xsp;
    if (jj_scan_token(110)) return true;
    }
    if (jj_3R_23()) return true;
    while (true) {
      xsp = jj_scanpos;
      if (jj_3R_167()) { jj_scanpos = xsp; break; }
    }
    return false;
  }

  final private boolean jj_3R_66() {
    if (jj_3R_98()) return true;
    return false;
  }

  final private boolean jj_3R_65() {
    if (jj_3R_97()) return true;
    return false;
  }

  final private boolean jj_3_7() {
    if (jj_scan_token(DOT_DOT)) return true;
    return false;
  }

  final private boolean jj_3R_64() {
    if (jj_3R_96()) return true;
    return false;
  }

  final private boolean jj_3R_148() {
    if (jj_scan_token(OPEN_BRACE)) return true;
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_156()) jj_scanpos = xsp;
    if (jj_scan_token(CLOSE_BRACE)) return true;
    return false;
  }

  final private boolean jj_3R_124() {
    if (jj_scan_token(RETURN)) return true;
    return false;
  }

  final private boolean jj_3R_94() {
    if (jj_scan_token(UNIFIED_CALL)) return true;
    return false;
  }

  final private boolean jj_3R_63() {
    if (jj_3R_95()) return true;
    return false;
  }

  final private boolean jj_3R_123() {
    if (jj_scan_token(SIMPLE_RETURN)) return true;
    return false;
  }

  final private boolean jj_3R_52() {
    if (jj_3R_44()) return true;
    return false;
  }

  final private boolean jj_3R_62() {
    if (jj_3R_94()) return true;
    return false;
  }

  final private boolean jj_3R_61() {
    if (jj_3R_93()) return true;
    return false;
  }

  final private boolean jj_3R_102() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_123()) {
    jj_scanpos = xsp;
    if (jj_3R_124()) return true;
    }
    return false;
  }

  final private boolean jj_3R_60() {
    if (jj_3R_92()) return true;
    return false;
  }

  final private boolean jj_3R_45() {
    if (jj_scan_token(DOT_DOT)) return true;
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_52()) jj_scanpos = xsp;
    return false;
  }

  final private boolean jj_3R_59() {
    if (jj_3R_91()) return true;
    return false;
  }

  final private boolean jj_3R_58() {
    if (jj_3R_90()) return true;
    return false;
  }

  final private boolean jj_3R_38() {
    if (jj_3R_44()) return true;
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_45()) jj_scanpos = xsp;
    return false;
  }

  final private boolean jj_3R_159() {
    if (jj_scan_token(TRUE)) return true;
    return false;
  }

  final private boolean jj_3R_57() {
    if (jj_3R_89()) return true;
    return false;
  }

  final private boolean jj_3R_158() {
    if (jj_scan_token(FALSE)) return true;
    return false;
  }

  final private boolean jj_3R_56() {
    if (jj_3R_88()) return true;
    return false;
  }

  final private boolean jj_3R_55() {
    if (jj_3R_87()) return true;
    return false;
  }

  final private boolean jj_3R_54() {
    if (jj_3R_86()) return true;
    return false;
  }

  final private boolean jj_3R_150() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_158()) {
    jj_scanpos = xsp;
    if (jj_3R_159()) return true;
    }
    return false;
  }

  final private boolean jj_3R_93() {
    if (jj_scan_token(COMPRESS)) return true;
    return false;
  }

  final private boolean jj_3R_49() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_54()) {
    jj_scanpos = xsp;
    if (jj_3R_55()) {
    jj_scanpos = xsp;
    if (jj_3R_56()) {
    jj_scanpos = xsp;
    if (jj_3R_57()) {
    jj_scanpos = xsp;
    if (jj_3R_58()) {
    jj_scanpos = xsp;
    if (jj_3R_59()) {
    jj_scanpos = xsp;
    if (jj_3R_60()) {
    jj_scanpos = xsp;
    if (jj_3R_61()) {
    jj_scanpos = xsp;
    if (jj_3R_62()) {
    jj_scanpos = xsp;
    if (jj_3R_63()) {
    jj_scanpos = xsp;
    if (jj_3R_64()) {
    jj_scanpos = xsp;
    if (jj_3R_65()) {
    jj_scanpos = xsp;
    if (jj_3R_66()) {
    jj_scanpos = xsp;
    if (jj_3R_67()) {
    jj_scanpos = xsp;
    if (jj_3R_68()) {
    jj_scanpos = xsp;
    if (jj_3R_69()) {
    jj_scanpos = xsp;
    if (jj_3R_70()) {
    jj_scanpos = xsp;
    if (jj_3R_71()) {
    jj_scanpos = xsp;
    if (jj_3R_72()) {
    jj_scanpos = xsp;
    if (jj_3R_73()) {
    jj_scanpos = xsp;
    if (jj_3R_74()) {
    jj_scanpos = xsp;
    if (jj_3R_75()) {
    jj_scanpos = xsp;
    if (jj_3R_76()) {
    jj_scanpos = xsp;
    if (jj_3R_77()) {
    jj_scanpos = xsp;
    if (jj_3R_78()) {
    jj_scanpos = xsp;
    if (jj_3R_79()) {
    jj_scanpos = xsp;
    if (jj_3R_80()) return true;
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    return false;
  }

  final private boolean jj_3R_101() {
    if (jj_scan_token(BREAK)) return true;
    return false;
  }

  final private boolean jj_3_5() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(126)) {
    jj_scanpos = xsp;
    if (jj_scan_token(97)) {
    jj_scanpos = xsp;
    if (jj_scan_token(125)) {
    jj_scanpos = xsp;
    if (jj_scan_token(96)) {
    jj_scanpos = xsp;
    if (jj_scan_token(95)) {
    jj_scanpos = xsp;
    if (jj_scan_token(95)) {
    jj_scanpos = xsp;
    if (jj_scan_token(94)) return true;
    }
    }
    }
    }
    }
    }
    return false;
  }

  final private boolean jj_3R_100() {
    if (jj_scan_token(SETTING)) return true;
    return false;
  }

  final private boolean jj_3R_39() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(126)) {
    jj_scanpos = xsp;
    if (jj_scan_token(97)) {
    jj_scanpos = xsp;
    if (jj_scan_token(125)) {
    jj_scanpos = xsp;
    if (jj_scan_token(96)) {
    jj_scanpos = xsp;
    if (jj_scan_token(95)) {
    jj_scanpos = xsp;
    if (jj_scan_token(94)) return true;
    }
    }
    }
    }
    }
    if (jj_3R_38()) return true;
    return false;
  }

  final private boolean jj_3R_157() {
    if (jj_scan_token(RAW_STRING)) return true;
    return false;
  }

  final private boolean jj_3R_35() {
    if (jj_3R_38()) return true;
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_39()) jj_scanpos = xsp;
    return false;
  }

  final private boolean jj_3R_111() {
    if (jj_scan_token(FALLBACK)) return true;
    return false;
  }

  final private boolean jj_3R_149() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(81)) {
    jj_scanpos = xsp;
    if (jj_3R_157()) return true;
    }
    return false;
  }

  final private boolean jj_3_17() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(68)) jj_scanpos = xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(66)) {
    jj_scanpos = xsp;
    if (jj_scan_token(65)) return true;
    }
    return false;
  }

  final private boolean jj_3_4() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(93)) {
    jj_scanpos = xsp;
    if (jj_scan_token(91)) {
    jj_scanpos = xsp;
    if (jj_scan_token(92)) return true;
    }
    }
    return false;
  }

  final private boolean jj_3R_171() {
    if (jj_scan_token(OPEN_PAREN)) return true;
    if (jj_3R_160()) return true;
    if (jj_scan_token(CLOSE_PAREN)) return true;
    return false;
  }

  final private boolean jj_3R_36() {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(93)) {
    jj_scanpos = xsp;
    if (jj_scan_token(91)) {
    jj_scanpos = xsp;
    if (jj_scan_token(92)) return true;
    }
    }
    if (jj_3R_35()) return true;
    return false;
  }

  final private boolean jj_3R_132() {
    if (jj_scan_token(RECURSE)) return true;
    return false;
  }

  public FMParserTokenManager token_source;
  SimpleCharStream jj_input_stream;
  public Token token, jj_nt;
  private int jj_ntk;
  private Token jj_scanpos, jj_lastpos;
  private int jj_la;
  public boolean lookingAhead = false;
  private boolean jj_semLA;
  private int jj_gen;
  final private int[] jj_la1 = new int[83];
  static private int[] jj_la1_0;
  static private int[] jj_la1_1;
  static private int[] jj_la1_2;
  static private int[] jj_la1_3;
  static private int[] jj_la1_4;
  static {
      jj_la1_0();
      jj_la1_1();
      jj_la1_2();
      jj_la1_3();
      jj_la1_4();
   }
   private static void jj_la1_0() {
      jj_la1_0 = new int[] {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200,0x0,0x0,0x0,0x0,0x0,0x0,0x1000000,0x800000,0x0,0x0,0x1c000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0x0,0x0,0x0,0x2000,0x0,0x7fffdd40,0x0,0x0,0x0,0x7fffdd40,0x7fffdd40,0x0,0x0,0x7fffdd40,0x0,0x0,0x0,0x0,0x0,};
   }
   private static void jj_la1_1() {
      jj_la1_1 = new int[] {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000,0x6,0x0,0x0,0x0,0x3000000,0x4000,0x8000,0xc00000,0x1e0000,0x0,0x0,0x0,0x0,0x70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0xafdfe000,0x0,0x0,0x0,0xafdfe000,0xafdfe000,0x0,0x0,0xafdfe000,0x0,0x0,0x0,0x0,0x0,};
   }
   private static void jj_la1_2() {
      jj_la1_2 = new int[] {0xfe0000,0xfe0000,0x0,0x0,0x0,0x0,0x38000000,0xc0000000,0x600000,0x60000,0x6800000,0x0,0xc0180000,0xc0180000,0x60000,0x180000,0x0,0x0,0x0,0xfe0000,0x0,0x0,0x0,0x0,0x0,0xfe0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfe0000,0x0,0xfe0000,0x0,0x0,0x0,0x0,0x10,0x10,0x0,0x0,0x0,0x70,0x0,0x0,0x1f0,0x1f0,0x1f0,0x1f0,0x1f0,0x10,0x0,0x6,0x0,0x0,};
   }
   private static void jj_la1_3() {
      jj_la1_3 = new int[] {0x10a8000,0x10a880c,0x800,0xc,0xc,0x190,0x0,0x60000003,0x0,0x1000000,0x28800,0x800,0xe00003,0x1e00033,0x0,0x0,0x5000,0x1000,0x5000,0x10a880c,0x2000,0x0,0x0,0x0,0x800000,0x10a880c,0x800000,0x0,0x0,0x0,0x0,0x0,0x0,0x1000,0x200000,0x200000,0x0,0x8200000,0x2000,0x1000000,0x0,0x20000,0x1000000,0x40,0x0,0x1000,0x40000,0x0,0x80000000,0x80000000,0x80001000,0x80000000,0x80000000,0x81000000,0x2000,0x18000000,0x40000,0x1000000,0x10a980c,0x1000,0x10a880c,0x0,0x2000,0x1000000,0x18000000,0x0,0x0,0x0,0x18000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000000,0x0,0x1000,0x1000000,};
   }
   private static void jj_la1_4() {
      jj_la1_4 = new int[] {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e,0x1e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,};
   }
  final private JJCalls[] jj_2_rtns = new JJCalls[17];
  private boolean jj_rescan = false;
  private int jj_gc = 0;

  public FMParser(java.io.InputStream stream) {
    jj_input_stream = new SimpleCharStream(stream, 1, 1);
    token_source = new FMParserTokenManager(jj_input_stream);
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 83; i++) jj_la1[i] = -1;
    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
  }

  public void ReInit(java.io.InputStream stream) {
    jj_input_stream.ReInit(stream, 1, 1);
    token_source.ReInit(jj_input_stream);
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 83; i++) jj_la1[i] = -1;
    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
  }

  public FMParser(java.io.Reader stream) {
    jj_input_stream = new SimpleCharStream(stream, 1, 1);
    token_source = new FMParserTokenManager(jj_input_stream);
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 83; i++) jj_la1[i] = -1;
    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
  }

  public void ReInit(java.io.Reader stream) {
    jj_input_stream.ReInit(stream, 1, 1);
    token_source.ReInit(jj_input_stream);
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 83; i++) jj_la1[i] = -1;
    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
  }

  public FMParser(FMParserTokenManager tm) {
    token_source = tm;
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 83; i++) jj_la1[i] = -1;
    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
  }

  public void ReInit(FMParserTokenManager tm) {
    token_source = tm;
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 83; i++) jj_la1[i] = -1;
    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
  }

  final private Token jj_consume_token(int kind) throws ParseException {
    Token oldToken;
    if ((oldToken = token).next != null) token = token.next;
    else token = token.next = token_source.getNextToken();
    jj_ntk = -1;
    if (token.kind == kind) {
      jj_gen++;
      if (++jj_gc > 100) {
        jj_gc = 0;
        for (int i = 0; i < jj_2_rtns.length; i++) {
          JJCalls c = jj_2_rtns[i];
          while (c != null) {
            if (c.gen < jj_gen) c.first = null;
            c = c.next;
          }
        }
      }
      return token;
    }
    token = oldToken;
    jj_kind = kind;
    throw generateParseException();
  }

  static private final class LookaheadSuccess extends java.lang.Error { }
  final private LookaheadSuccess jj_ls = new LookaheadSuccess();
  final private boolean jj_scan_token(int kind) {
    if (jj_scanpos == jj_lastpos) {
      jj_la--;
      if (jj_scanpos.next == null) {
        jj_lastpos = jj_scanpos = jj_scanpos.next = token_source.getNextToken();
      } else {
        jj_lastpos = jj_scanpos = jj_scanpos.next;
      }
    } else {
      jj_scanpos = jj_scanpos.next;
    }
    if (jj_rescan) {
      int i = 0; Token tok = token;
      while (tok != null && tok != jj_scanpos) { i++; tok = tok.next; }
      if (tok != null) jj_add_error_token(kind, i);
    }
    if (jj_scanpos.kind != kind) return true;
    if (jj_la == 0 && jj_scanpos == jj_lastpos) throw jj_ls;
    return false;
  }

  final public Token getNextToken() {
    if (token.next != null) token = token.next;
    else token = token.next = token_source.getNextToken();
    jj_ntk = -1;
    jj_gen++;
    return token;
  }

  final public Token getToken(int index) {
    Token t = lookingAhead ? jj_scanpos : token;
    for (int i = 0; i < index; i++) {
      if (t.next != null) t = t.next;
      else t = t.next = token_source.getNextToken();
    }
    return t;
  }

  final private int jj_ntk() {
    if ((jj_nt=token.next) == null)
      return (jj_ntk = (token.next=token_source.getNextToken()).kind);
    else
      return (jj_ntk = jj_nt.kind);
  }

  private java.util.Vector jj_expentries = new java.util.Vector();
  private int[] jj_expentry;
  private int jj_kind = -1;
  private int[] jj_lasttokens = new int[100];
  private int jj_endpos;

  private void jj_add_error_token(int kind, int pos) {
    if (pos >= 100) return;
    if (pos == jj_endpos + 1) {
      jj_lasttokens[jj_endpos++] = kind;
    } else if (jj_endpos != 0) {
      jj_expentry = new int[jj_endpos];
      for (int i = 0; i < jj_endpos; i++) {
        jj_expentry[i] = jj_lasttokens[i];
      }
      boolean exists = false;
      for (java.util.Enumeration e = jj_expentries.elements(); e.hasMoreElements();) {
        int[] oldentry = (int[])(e.nextElement());
        if (oldentry.length == jj_expentry.length) {
          exists = true;
          for (int i = 0; i < jj_expentry.length; i++) {
            if (oldentry[i] != jj_expentry[i]) {
              exists = false;
              break;
            }
          }
          if (exists) break;
        }
      }
      if (!exists) jj_expentries.addElement(jj_expentry);
      if (pos != 0) jj_lasttokens[(jj_endpos = pos) - 1] = kind;
    }
  }

  public ParseException generateParseException() {
    jj_expentries.removeAllElements();
    boolean[] la1tokens = new boolean[133];
    for (int i = 0; i < 133; i++) {
      la1tokens[i] = false;
    }
    if (jj_kind >= 0) {
      la1tokens[jj_kind] = true;
      jj_kind = -1;
    }
    for (int i = 0; i < 83; i++) {
      if (jj_la1[i] == jj_gen) {
        for (int j = 0; j < 32; j++) {
          if ((jj_la1_0[i] & (1<<j)) != 0) {
            la1tokens[j] = true;
          }
          if ((jj_la1_1[i] & (1<<j)) != 0) {
            la1tokens[32+j] = true;
          }
          if ((jj_la1_2[i] & (1<<j)) != 0) {
            la1tokens[64+j] = true;
          }
          if ((jj_la1_3[i] & (1<<j)) != 0) {
            la1tokens[96+j] = true;
          }
          if ((jj_la1_4[i] & (1<<j)) != 0) {
            la1tokens[128+j] = true;
          }
        }
      }
    }
    for (int i = 0; i < 133; i++) {
      if (la1tokens[i]) {
        jj_expentry = new int[1];
        jj_expentry[0] = i;
        jj_expentries.addElement(jj_expentry);
      }
    }
    jj_endpos = 0;
    jj_rescan_token();
    jj_add_error_token(0, 0);
    int[][] exptokseq = new int[jj_expentries.size()][];
    for (int i = 0; i < jj_expentries.size(); i++) {
      exptokseq[i] = (int[])jj_expentries.elementAt(i);
    }
    return new ParseException(token, exptokseq, tokenImage);
  }

  final public void enable_tracing() {
  }

  final public void disable_tracing() {
  }

  final private void jj_rescan_token() {
    jj_rescan = true;
    for (int i = 0; i < 17; i++) {
      JJCalls p = jj_2_rtns[i];
      do {
        if (p.gen > jj_gen) {
          jj_la = p.arg; jj_lastpos = jj_scanpos = p.first;
          switch (i) {
            case 0: jj_3_1(); break;
            case 1: jj_3_2(); break;
            case 2: jj_3_3(); break;
            case 3: jj_3_4(); break;
            case 4: jj_3_5(); break;
            case 5: jj_3_6(); break;
            case 6: jj_3_7(); break;
            case 7: jj_3_8(); break;
            case 8: jj_3_9(); break;
            case 9: jj_3_10(); break;
            case 10: jj_3_11(); break;
            case 11: jj_3_12(); break;
            case 12: jj_3_13(); break;
            case 13: jj_3_14(); break;
            case 14: jj_3_15(); break;
            case 15: jj_3_16(); break;
            case 16: jj_3_17(); break;
          }
        }
        p = p.next;
      } while (p != null);
    }
    jj_rescan = false;
  }

  final private void jj_save(int index, int xla) {
    JJCalls p = jj_2_rtns[index];
    while (p.gen > jj_gen) {
      if (p.next == null) { p = p.next = new JJCalls(); break; }
      p = p.next;
    }
    p.gen = jj_gen + xla - jj_la; p.first = token; p.arg = xla;
  }

  static final class JJCalls {
    int gen;
    Token first;
    int arg;
    JJCalls next;
  }

}
