private Ref unaryOp() throws PageException {
    Ref ref = negateMinusOp();

    if (cfml.forwardIfCurrent("--")) ref = _unaryOp(ref, false);
    else if (cfml.forwardIfCurrent("++")) ref = _unaryOp(ref, true);
    return ref;
  }
  /**
   * Transfomiert einen numerische Wert. Die L¦nge des numerischen Wertes interessiert nicht zu
   * ᅵbersetzungszeit, ein "Overflow" fhrt zu einem Laufzeitfehler. Da die zu erstellende CFXD,
   * bzw. dieser Transfomer, keine Vorwegnahme des Laufzeitsystems vornimmt. <br>
   * EBNF:<br>
   * <code>["+"|"-"] digit {digit} {"." digit {digit}};</code>
   *
   * @return CFXD Element
   * @throws PageException
   */
  private Ref number() throws PageException {
    // check first character is a number literal representation
    // if(!cfml.isCurrentDigit()) return null;

    StringBuffer rtn = new StringBuffer(6);

    // get digit on the left site of the dot
    if (cfml.isCurrent('.')) rtn.append('0');
    else digit(rtn);
    // read dot if exist
    if (cfml.forwardIfCurrent('.')) {
      rtn.append('.');
      int before = cfml.getPos();
      digit(rtn);

      if (before < cfml.getPos() && cfml.forwardIfCurrent('e')) {
        if (cfml.isCurrentDigit()) {
          rtn.append('e');
          digit(rtn);
        } else {
          cfml.previous();
        }
      }

      // read right side of the dot
      if (before == cfml.getPos()) throw new ExpressionException("Number can't end with [.]");
      // rtn.append(rightSite);
    }
    cfml.removeSpace();
    mode = STATIC;
    return new LNumber(rtn.toString());
  }
 /**
  * Transfomiert eine Or (or) Operation. Im Gegensatz zu CFMX , werden "||" Zeichen auch als Or
  * Operatoren anerkannt. <br>
  * EBNF:<br>
  * <code>andOp {("or" | "||") spaces andOp}; (* "||" Existiert in CFMX nicht *)</code>
  *
  * @return CFXD Element
  * @throws PageException
  */
 private Ref orOp() throws PageException {
   Ref ref = andOp();
   while (cfml.isValidIndex() && (cfml.forwardIfCurrent("||") || cfml.forwardIfCurrent("or"))) {
     cfml.removeSpace();
     ref = new Or(ref, andOp());
   }
   return ref;
 }
 /**
  * Liest einen gelableten Funktionsparamter ein <br>
  * EBNF:<br>
  * <code>assignOp [":" spaces assignOp];</code>
  *
  * @return CFXD Element
  * @throws PageException
  */
 private Ref functionArgDeclaration() throws PageException {
   Ref ref = impOp();
   if (cfml.forwardIfCurrent(':') || cfml.forwardIfCurrent('=')) {
     cfml.removeSpace();
     ref = new LFunctionValue(ref, assignOp());
   }
   return ref;
 }
 /**
  * Transfomiert eine And (and) Operation. Im Gegensatz zu CFMX , werden "&&" Zeichen auch als And
  * Operatoren anerkannt. <br>
  * EBNF:<br>
  * <code>notOp {("and" | "&&") spaces notOp}; (* "&&" Existiert in CFMX nicht *)</code>
  *
  * @return CFXD Element
  * @throws PageException
  */
 private Ref andOp() throws PageException {
   Ref ref = notOp();
   while (cfml.isValidIndex() && (cfml.forwardIfCurrent("&&") || cfml.forwardIfCurrent("and"))) {
     cfml.removeSpace();
     ref = new And(ref, notOp());
   }
   return ref;
 }
  /**
   * Transfomiert den Exponent Operator (^,exp). Im Gegensatz zu CFMX , werden die Zeichen " exp "
   * auch als Exponent anerkannt. <br>
   * EBNF:<br>
   * <code>clip {("exp"|"^") spaces clip};</code>
   *
   * @return CFXD Element
   * @throws PageException
   */
  private Ref expoOp() throws PageException {
    Ref ref = unaryOp();

    while (cfml.isValidIndex() && (cfml.forwardIfCurrent('^') || cfml.forwardIfCurrent("exp"))) {
      cfml.removeSpace();
      ref = new Exp(ref, unaryOp());
    }
    return ref;
  }
 /**
  * Sharps (#) die innerhalb von Expressions auftauchen haben in CFML keine weitere Beteutung und
  * werden durch diese Methode einfach entfernt. <br>
  * Beispiel:<br>
  * <code>arrayLen(#arr#)</code> und <code>arrayLen(arr)</code> sind identisch. EBNF:<br>
  * <code>"#" checker "#";</code>
  *
  * @return CFXD Element
  * @throws PageException
  */
 private Ref sharp() throws PageException {
   if (!cfml.forwardIfCurrent('#')) return null;
   Ref ref;
   cfml.removeSpace();
   ref = assignOp();
   cfml.removeSpace();
   if (!cfml.forwardIfCurrent('#'))
     throw new ExpressionException("Syntax Error, Invalid Construct");
   cfml.removeSpace();
   return ref;
 }
  /**
   * Transfomiert eine Modulus Operation. Im Gegensatz zu CFMX , wird das "%" Zeichen auch als
   * Modulus Operator anerkannt. <br>
   * EBNF:<br>
   * <code>
   * divMultiOp {("mod" | "%") spaces divMultiOp}; (* modulus operator , "%" Existiert in CFMX nicht *)
   * </code>
   *
   * @return CFXD Element
   * @throws PageException
   */
  private Ref modOp() throws PageException {
    Ref ref = divMultiOp();

    while (cfml.isValidIndex() && (cfml.forwardIfCurrent('%') || cfml.forwardIfCurrent("mod"))) {
      ref = _mod(ref);

      // cfml.removeSpace();
      // ref=new Mod(ref,divMultiOp());
    }
    return ref;
  }
 private Ref contOp() throws PageException {
   Ref ref = impOp();
   while (cfml.forwardIfCurrent('?')) {
     cfml.removeSpace();
     Ref left = assignOp();
     if (!cfml.forwardIfCurrent(':'))
       throw new ExpressionException(
           "Syntax Error, invalid conditional operator [" + cfml.toString() + "]");
     cfml.removeSpace();
     Ref right = assignOp();
     ref = new Cont(ref, left, right);
   }
   return ref;
 }
  /**
   * Liest den folgenden idetifier ein und prft ob dieser ein boolscher Wert ist. Im Gegensatz zu
   * CFMX wird auch "yes" und "no" als bolscher <wert akzeptiert, was bei CFMX nur beim Umwandeln
   * einer Zeichenkette zu einem boolschen Wert der Fall ist.<br>
   * Wenn es sich um keinen bolschen Wert handelt wird der folgende Wert eingelesen mit seiner
   * ganzen Hirarchie. <br>
   * EBNF:<br>
   * <code>"true" | "false" | "yes" | "no" | startElement
   * {("." identifier | "[" structElement "]" )[function] };</code>
   *
   * @return CFXD Element
   * @throws PageException
   */
  private Ref dynamic() throws PageException {
    // Die Implementation weicht ein wenig von der Grammatik ab,
    // aber nicht in der Logik sondern rein wie es umgesetzt wurde.

    // get First Element of the Variable
    String name = identifier(false);
    if (name == null) {
      if (!cfml.forwardIfCurrent('(')) return null;
      cfml.removeSpace();
      Ref ref = assignOp();

      if (!cfml.forwardIfCurrent(')'))
        throw new ExpressionException("Invalid Syntax Closing [)] not found");
      cfml.removeSpace();
      return subDynamic(ref);
    }

    // Element el;
    cfml.removeSpace();
    char first = name.charAt(0);

    // Boolean constant
    if (first == 'T' && name.equals("TRUE")) {
      cfml.removeSpace();
      return LBoolean.TRUE;
    } else if (first == 'F' && name.equals("FALSE")) {
      cfml.removeSpace();
      return LBoolean.FALSE;
    } else if (first == 'Y' && name.equals("YES")) {
      cfml.removeSpace();
      return LBoolean.TRUE;
    } else if (first == 'N') {
      if (name.equals("NO")) {
        cfml.removeSpace();
        return LBoolean.FALSE;
      } else if (allowNullConstant && name.equals("NULL")) {
        cfml.removeSpace();
        return new LString(null);
      } else if (name.equals("NEW")) {
        Ref res = newOp();
        if (res != null) return res;
      }
    }

    // Extract Scope from the Variable

    // Object value = startElement(name);
    return subDynamic(startElement(name));
  }
  /**
   * Transfomiert die mathematischen Operatoren Mal und Durch (*,/). <br>
   * EBNF:<br>
   * <code>expoOp {("*"|"/") spaces expoOp};</code>
   *
   * @return CFXD Element
   * @throws PageException
   */
  private Ref divMultiOp() throws PageException {
    Ref ref = expoOp();

    while (!cfml.isLast()) {
      // Multiply Operation
      if (cfml.forwardIfCurrent('*')) {
        ref = _multi(ref);
        // cfml.removeSpace();
        // ref=new Multi(ref,expoOp());
      }
      // Divide Operation
      else if (cfml.isCurrent('/') && (!cfml.isCurrent("/>"))) {
        cfml.next();
        ref = _div(ref);
        // cfml.removeSpace();
        // ref=new Div(ref,expoOp());
      }
      // Divide Operation
      else if (cfml.isCurrent('\\')) {
        cfml.next();
        ref = _intdiv(ref);
        // cfml.removeSpace();
        // ref=new IntDiv(ref,expoOp());
      } else {
        break;
      }
    }
    return ref;
  }
  private Ref subDynamic(Ref ref) throws PageException {
    String name = null;

    // Loop over nested Variables
    while (cfml.isValidIndex()) {
      // .
      if (cfml.forwardIfCurrent('.')) {
        // Extract next Var String
        cfml.removeSpace();
        name = identifier(true);
        if (name == null) throw new ExpressionException("Invalid identifier");
        cfml.removeSpace();
        ref = new Variable(pc, ref, name);
      }
      // []
      else if (cfml.forwardIfCurrent('[')) {
        cfml.removeSpace();
        ref = new Variable(pc, ref, assignOp());
        cfml.removeSpace();
        if (!cfml.forwardIfCurrent(']'))
          throw new ExpressionException("Invalid Syntax Closing []] not found");
      }
      // finish
      else {
        break;
      }

      cfml.removeSpace();

      if (cfml.isCurrent('(')) {
        if (!(ref instanceof Set))
          throw new ExpressionException(
              "invalid syntax " + ref.getTypeName() + " can't called as function");
        Set set = (Set) ref;
        ref = new UDFCall(pc, set.getParent(), set.getKey(), functionArg(name, false, null, ')'));
      }
    }
    if (ref instanceof railo.runtime.interpreter.ref.var.Scope) {
      railo.runtime.interpreter.ref.var.Scope s = (railo.runtime.interpreter.ref.var.Scope) ref;
      if (s.getScope() == Scope.SCOPE_ARGUMENTS
          || s.getScope() == Scope.SCOPE_LOCAL
          || s.getScope() == ScopeSupport.SCOPE_VAR) {
        ref = new Bind(s);
      }
    }
    return ref;
  }
 /**
  * Transfomiert eine Xor (xor) Operation. <br>
  * EBNF:<br>
  * <code>orOp {"xor" spaces  orOp};</code>
  *
  * @return CFXD Element
  * @throws PageException
  */
 private Ref xorOp() throws PageException {
   Ref ref = orOp();
   while (cfml.forwardIfCurrent("xor")) {
     cfml.removeSpace();
     ref = new Xor(ref, orOp());
   }
   return ref;
 }
 /**
  * Transfomiert eine Equivalence (eqv) Operation. <br>
  * EBNF:<br>
  * <code>xorOp {"eqv" spaces xorOp};</code>
  *
  * @return CFXD Element
  * @throws PageException
  */
 private Ref eqvOp() throws PageException {
   Ref ref = xorOp();
   while (cfml.forwardIfCurrent("eqv")) {
     cfml.removeSpace();
     ref = new EQV(ref, xorOp());
   }
   return ref;
 }
  /**
   * Transfomiert die mathematischen Operatoren Plus und Minus (1,-). <br>
   * EBNF:<br>
   * <code>modOp [("-"|"+") spaces plusMinusOp];</code>
   *
   * @return CFXD Element
   * @throws PageException
   */
  private Ref plusMinusOp() throws PageException {
    Ref ref = modOp();

    while (!cfml.isLast()) {
      // Plus Operation
      if (cfml.forwardIfCurrent('+')) {
        ref = _plus(ref);
        // cfml.removeSpace();
        // ref=new Plus(ref,modOp());
      }
      // Minus Operation
      else if (cfml.forwardIfCurrent('-')) {
        ref = _minus(ref);
        // cfml.removeSpace();
        // ref=new Minus(ref,modOp());
      } else break;
    }
    return ref;
  }
 private Ref _multi(Ref ref) throws PageException {
   // \=
   if (cfml.forwardIfCurrent('=')) {
     cfml.removeSpace();
     Ref right = assignOp();
     Ref res = new Multi(ref, right);
     ref = new Assign(ref, res);
   } else {
     cfml.removeSpace();
     ref = new Multi(ref, expoOp());
   }
   return ref;
 }
 private Ref _concat(Ref ref) throws PageException {
   // &=
   if (cfml.forwardIfCurrent('=')) {
     cfml.removeSpace();
     Ref right = assignOp();
     Ref res = new Concat(pc, ref, right);
     ref = new Assign(ref, res);
   } else {
     cfml.removeSpace();
     ref = new Concat(pc, ref, plusMinusOp());
   }
   return ref;
 }
  /**
   * Transfomiert Zuweisungs Operation. <br>
   * EBNF:<br>
   * <code>eqvOp ["=" spaces assignOp];</code>
   *
   * @return CFXD Element
   * @throws PageException
   */
  protected Ref assignOp() throws PageException {
    Ref ref = contOp();

    if (cfml.forwardIfCurrent('=')) {
      cfml.removeSpace();
      if (mode == STATIC || ref instanceof Literal) {
        ref = new DynAssign(pc, ref, assignOp());
      } else {
        ref = new Assign(ref, assignOp());
      }
    }
    return ref;
  }
  /**
   * Transfomiert einen lierale Zeichenkette. <br>
   * EBNF:<br>
   * <code>("'" {"##"|"''"|"#" impOp "#"| ?-"#"-"'" } "'") |
   * (""" {"##"|""""|"#" impOp "#"| ?-"#"-""" } """);</code>
   *
   * @return CFXD Element
   * @throws PageException
   */
  protected Ref string() throws PageException {

    // Init Parameter
    char quoter = cfml.getCurrentLower();
    // String str="";
    LStringBuffer str = new LStringBuffer();
    Ref value = null;

    while (cfml.hasNext()) {
      cfml.next();
      // check sharp
      if (cfml.isCurrent('#')) {
        if (cfml.isNext('#')) {
          cfml.next();
          str.append('#');
        } else {
          cfml.next();
          cfml.removeSpace();
          if (!str.isEmpty() || value != null) str.append(assignOp());
          else value = assignOp();
          cfml.removeSpace();
          if (!cfml.isCurrent('#'))
            throw new ExpressionException("Invalid Syntax Closing [#] not found");
        }
      } else if (cfml.isCurrent(quoter)) {
        if (cfml.isNext(quoter)) {
          cfml.next();
          str.append(quoter);
        } else {
          break;
        }
      }
      // all other character
      else {
        str.append(cfml.getCurrent());
      }
    }
    if (!cfml.forwardIfCurrent(quoter))
      throw new ExpressionException(
          "Invalid String Literal Syntax Closing [" + quoter + "] not found");

    cfml.removeSpace();
    mode = STATIC;
    if (value != null) {
      if (str.isEmpty()) return value;
      return new Concat(pc, value, str);
    }
    return str;
  }
 /**
  * Liest die Vordlobe einer Zahl ein
  *
  * @return CFXD Element
  * @throws PageException
  */
 private Ref negateMinusOp() throws PageException {
   // And Operation
   if (cfml.forwardIfCurrent('-')) {
     if (cfml.forwardIfCurrent('-')) {
       cfml.removeSpace();
       Ref expr = clip();
       Minus res = new Minus(expr, new LNumber(new Double(1)));
       return new Assign(expr, res);
     }
     cfml.removeSpace();
     return new Negate(clip());
   }
   if (cfml.forwardIfCurrent('+')) {
     if (cfml.forwardIfCurrent('+')) {
       cfml.removeSpace();
       Ref expr = clip();
       Plus res = new Plus(expr, new LNumber(new Double(1)));
       return new Assign(expr, res);
     }
     cfml.removeSpace();
     return new Casting(pc, "numeric", CFTypes.TYPE_NUMERIC, clip());
   }
   return clip();
 }
  private Ref newOp() throws PageException {

    int start = cfml.getPos();
    String name = null;
    cfml.removeSpace();

    // first identifier
    name = identifier(true);
    Ref refName = null;
    if (name != null) {
      StringBuilder fullName = new StringBuilder();
      fullName.append(name);
      // Loop over addional identifier
      while (cfml.isValidIndex()) {
        if (cfml.forwardIfCurrent('.')) {
          cfml.removeSpace();
          name = identifier(true);
          if (name == null) throw new ExpressionException("invalid Component declaration");
          cfml.removeSpace();
          fullName.append('.');
          fullName.append(name);
        } else break;
      }
      refName = new LString(fullName.toString());
    } else {
      if (cfml.isCurrentQuoter()) refName = string();
      if (refName == null) {
        cfml.setPos(start);
        return null;
      }
    }
    cfml.removeSpace();

    if (cfml.isCurrent('(')) {
      FunctionLibFunction function = fld.getFunction("_createComponent");
      Ref[] arguments = functionArg("_createComponent", true, function, ')');
      Ref[] args = new Ref[arguments.length + 1];
      for (int i = 0; i < arguments.length; i++) {
        args[i] = arguments[i];
      }
      args[args.length - 1] = refName;
      BIFCall bif = new BIFCall(pc, function, args);
      cfml.removeSpace();
      return bif;
    }
    throw new ExpressionException("invalid Component declaration ");
  }
  /**
   * Liest einen gelableten Funktionsparamter ein <br>
   * EBNF:<br>
   * <code>assignOp [":" spaces assignOp];</code>
   *
   * @return CFXD Element
   * @throws PageException
   */
  private Ref functionArgDeclarationVarString() throws PageException {

    cfml.removeSpace();
    StringBuffer str = new StringBuffer();
    String id = null;
    while ((id = identifier(false)) != null) {
      if (str.length() > 0) str.append('.');
      str.append(id);
      cfml.removeSpace();
      if (!cfml.forwardIfCurrent('.')) break;
      cfml.removeSpace();
    }
    cfml.removeSpace();
    if (str.length() > 0 && cfml.charAt(cfml.getPos() - 1) != '.')
      return new LString(str.toString());

    throw new ExpressionException("invalid variable name definition");
  }
  /**
   * Liest die Argumente eines Funktonsaufruf ein und prft ob die Funktion innerhalb der FLD
   * (Function Library Descriptor) definiert ist. Falls sie existiert wird die Funktion gegen diese
   * geprft und ein build-in-function CFXD Element generiert, ansonsten ein normales funcion-call
   * Element. <br>
   * EBNF:<br>
   * <code>[impOp{"," impOp}];</code>
   *
   * @param name Identifier der Funktion als Zeichenkette
   * @param checkLibrary Soll geprft werden ob die Funktion innerhalb der Library existiert.
   * @param flf FLD Function definition .
   * @return CFXD Element
   * @throws PageException
   */
  private Ref[] functionArg(String name, boolean checkLibrary, FunctionLibFunction flf, char end)
      throws PageException {

    // get Function Library
    checkLibrary = checkLibrary && flf != null;

    // Function Attributes
    ArrayList arr = new ArrayList();

    ArrayList arrFuncLibAtt = null;
    int libLen = 0;
    if (checkLibrary) {
      arrFuncLibAtt = flf.getArg();
      libLen = arrFuncLibAtt.size();
    }
    int count = 0;
    do {
      cfml.next();
      cfml.removeSpace();

      // finish
      if (cfml.isCurrent(end)) break;

      // too many Attributes
      boolean isDynamic = false;
      int max = -1;
      if (checkLibrary) {
        isDynamic = isDynamic(flf);
        max = flf.getArgMax();
        // Dynamic
        if (isDynamic) {
          if (max != -1 && max <= count)
            throw new ExpressionException("too many Attributes in function [" + name + "]");
        }
        // Fix
        else {
          if (libLen <= count)
            throw new ExpressionException("too many Attributes in function [" + name + "]");
        }
      }

      if (checkLibrary && !isDynamic) {
        // current attribues from library
        FunctionLibFunctionArg funcLibAtt = (FunctionLibFunctionArg) arrFuncLibAtt.get(count);
        short type = CFTypes.toShort(funcLibAtt.getType(), CFTypes.TYPE_UNKNOW);
        if (type == CFTypes.TYPE_VARIABLE_STRING) {
          arr.add(functionArgDeclarationVarString());
        } else {
          arr.add(new Casting(pc, funcLibAtt.getTypeAsString(), type, functionArgDeclaration()));
        }
      } else {
        arr.add(functionArgDeclaration());
      }

      // obj=andOrXor();
      cfml.removeSpace();
      count++;
    } while (cfml.isCurrent(','));

    // end with ) ??
    if (!cfml.forwardIfCurrent(end)) {
      if (name.startsWith("_json"))
        throw new ExpressionException("Invalid Syntax Closing [" + end + "] not found");
      throw new ExpressionException(
          "Invalid Syntax Closing [" + end + "] for function [" + name + "] not found");
    }

    // check min attributes
    if (checkLibrary && flf.getArgMin() > count)
      throw new ExpressionException("to less Attributes in function [" + name + "]");

    cfml.removeSpace();
    return (Ref[]) arr.toArray(new Ref[arr.size()]);
  }
  /**
   * <font f>Transfomiert eine Vergleichs Operation. <br>
   * EBNF:<br>
   * <code>concatOp {("neq"|"eq"|"gte"|"gt"|"lte"|"lt"|"ct"|
   * "contains"|"nct"|"does not contain") spaces concatOp};
   * (* "ct"=conatains und "nct"=does not contain; Existiert in CFMX nicht *)</code>
   *
   * @return CFXD Element
   * @throws PageException
   */
  private Ref decsionOp() throws PageException {

    Ref ref = concatOp();
    boolean hasChanged = false;
    // ct, contains
    if (cfml.isValidIndex()) {
      do {
        hasChanged = false;
        if (cfml.isCurrent('c')) {
          if (cfml.forwardIfCurrent("ct")) {
            cfml.removeSpace();
            ref = new CT(ref, concatOp());
            hasChanged = true;
          } else if (cfml.forwardIfCurrent("contains")) {
            cfml.removeSpace();
            ref = new CT(ref, concatOp());
            hasChanged = true;
          }
        }
        // does not contain
        else if (cfml.forwardIfCurrent("does", "not", "contain")) {
          cfml.removeSpace();
          ref = new NCT(ref, concatOp());
          hasChanged = true;
        }

        // equal, eq
        else if (cfml.isCurrent("eq") && !cfml.isCurrent("eqv")) {
          cfml.setPos(cfml.getPos() + 2);
          cfml.forwardIfCurrent("ual");
          cfml.removeSpace();
          ref = new EQ(ref, concatOp());
          hasChanged = true;
        }
        // ==
        else if (cfml.forwardIfCurrent("==")) {
          if (cfml.forwardIfCurrent('=')) {
            cfml.removeSpace();
            ref = new EEQ(ref, concatOp());
          } else {
            cfml.removeSpace();
            ref = new EQ(ref, concatOp());
          }
          hasChanged = true;
        }

        // !=
        else if (cfml.forwardIfCurrent("!=")) {
          if (cfml.forwardIfCurrent('=')) {
            cfml.removeSpace();
            ref = new NEEQ(ref, concatOp());
          } else {
            cfml.removeSpace();
            ref = new NEQ(ref, concatOp());
          }
          hasChanged = true;
        }

        // <=/</<>
        else if (cfml.forwardIfCurrent('<')) {
          if (cfml.forwardIfCurrent('=')) {
            cfml.removeSpace();
            ref = new LTE(ref, concatOp());
          } else if (cfml.forwardIfCurrent('>')) {
            cfml.removeSpace();
            ref = new NEQ(ref, concatOp());
          } else {
            cfml.removeSpace();
            ref = new LT(ref, concatOp());
          }
          hasChanged = true;
        }
        // >/>=
        else if (cfml.forwardIfCurrent('>')) {
          if (cfml.forwardIfCurrent('=')) {
            cfml.removeSpace();
            ref = new GTE(ref, concatOp());
          } else {
            cfml.removeSpace();
            ref = new GT(ref, concatOp());
          }
          hasChanged = true;
        }

        // gt, gte, greater than or equal to, greater than
        else if (cfml.isCurrent('g')) {
          if (cfml.forwardIfCurrent("gt")) {
            if (cfml.forwardIfCurrent('e')) {
              cfml.removeSpace();
              ref = new GTE(ref, concatOp());
            } else {
              cfml.removeSpace();
              ref = new GT(ref, concatOp());
            }
            hasChanged = true;
          } else if (cfml.forwardIfCurrent("greater", "than")) {
            if (cfml.forwardIfCurrent("or", "equal", "to", true)) {
              cfml.removeSpace();
              ref = new GTE(ref, concatOp());
            } else {
              cfml.removeSpace();
              ref = new GT(ref, concatOp());
            }
            hasChanged = true;
          } else if (cfml.forwardIfCurrent("ge")) {
            cfml.removeSpace();
            ref = new GTE(ref, concatOp());
            hasChanged = true;
          }
        }

        // is, is not
        else if (cfml.forwardIfCurrent("is")) {
          if (cfml.forwardIfCurrent("not", true)) {
            cfml.removeSpace();
            ref = new NEQ(ref, concatOp());
          } else {
            cfml.removeSpace();
            ref = new EQ(ref, concatOp());
          }
          hasChanged = true;
        }

        // lt, lte, less than, less than or equal to
        else if (cfml.isCurrent('l')) {
          if (cfml.forwardIfCurrent("lt")) {
            if (cfml.forwardIfCurrent('e')) {
              cfml.removeSpace();
              ref = new LTE(ref, concatOp());
            } else {
              cfml.removeSpace();
              ref = new LT(ref, concatOp());
            }
            hasChanged = true;
          } else if (cfml.forwardIfCurrent("less", "than")) {
            if (cfml.forwardIfCurrent("or", "equal", "to", true)) {
              cfml.removeSpace();
              ref = new LTE(ref, concatOp());
            } else {
              cfml.removeSpace();
              ref = new LT(ref, concatOp());
            }
            hasChanged = true;
          } else if (cfml.forwardIfCurrent("le")) {
            cfml.removeSpace();
            ref = new LTE(ref, concatOp());
            hasChanged = true;
          }
        }

        // neq, not equal, nct
        else if (cfml.isCurrent('n')) {
          // Not Equal
          if (cfml.forwardIfCurrent("neq")) {
            cfml.removeSpace();
            ref = new NEQ(ref, concatOp());
            hasChanged = true;
          }
          // Not Equal (Alias)
          else if (cfml.forwardIfCurrent("not", "equal")) {
            cfml.removeSpace();
            ref = new NEQ(ref, concatOp());
            hasChanged = true;
          }
          // nct
          else if (cfml.forwardIfCurrent("nct")) {
            cfml.removeSpace();
            ref = new NCT(ref, concatOp());
            hasChanged = true;
          }
        }
      } while (hasChanged);
    }
    return ref;
  }