/**
  * 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 Not (not) Operation. Im Gegensatz zu CFMX , wird das "!" Zeichen auch als Not
  * Operator anerkannt. <br>
  * EBNF:<br>
  * <code>[("not"|"!") spaces] decsionOp; (* "!" Existiert in CFMX nicht *)</code>
  *
  * @return CFXD Element
  * @throws PageException
  */
 private Ref notOp() throws PageException {
   if (cfml.isValidIndex()) {
     if (cfml.isCurrent('!') && !cfml.isCurrent("!=")) {
       cfml.next();
       cfml.removeSpace();
       return new Not(decsionOp());
     } else if (cfml.forwardIfCurrentAndNoWordAfter("not")) {
       cfml.removeSpace();
       return new Not(decsionOp());
     }
   }
   return decsionOp();
 }
 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;
 }
 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 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;
 }
  /**
   * 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;
  }
  /**
   * 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());
  }
  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;
  }
  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 functionArgDeclaration() throws PageException {
   Ref ref = impOp();
   if (cfml.forwardIfCurrent(':') || cfml.forwardIfCurrent('=')) {
     cfml.removeSpace();
     ref = new LFunctionValue(ref, assignOp());
   }
   return ref;
 }
  protected Object interpretPart(PageContext pc, ParserString cfml) throws PageException {
    this.cfml = cfml;
    this.pc = pc;
    if (pc != null) fld = ((ConfigImpl) pc.getConfig()).getCombinedFLDs();

    cfml.removeSpace();
    return assignOp().getValue();
  }
 /**
  * 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;
 }
 /**
  * Transfomiert eine Implication (imp) Operation. <br>
  * EBNF:<br>
  * <code>eqvOp {"imp" spaces eqvOp};</code>
  *
  * @return CFXD Element
  * @throws PageException
  */
 private Ref impOp() throws PageException {
   Ref ref = eqvOp();
   while (cfml.forwardIfCurrentAndNoWordAfter("imp")) {
     cfml.removeSpace();
     ref = new Imp(ref, eqvOp());
   }
   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;
 }
  /**
   * Wird aufgerufen um aus dem bergebenen CFMLString einen Ausdruck auszulesen und diese zu
   * interpretieren. <br>
   * Beispiel eines bergebenen String:<br>
   * <code>session.firstName</code> oder <code>trim(left('test'&var1,3))</code> <br>
   * EBNF:<br>
   * <code>spaces impOp;</code>
   *
   * @param pc
   * @param cfml
   * @return
   * @throws PageException
   */
  public Object interpret(PageContext pc, ParserString cfml) throws PageException {
    this.cfml = cfml;
    this.pc = pc;
    if (pc != null) fld = ((ConfigImpl) pc.getConfig()).getCombinedFLDs();

    if (JSON_ARRAY == null) JSON_ARRAY = fld.getFunction("_jsonArray");
    if (JSON_STRUCT == null) JSON_STRUCT = fld.getFunction("_jsonStruct");

    cfml.removeSpace();
    Ref ref = assignOp();
    cfml.removeSpace();

    if (cfml.isAfterLast()) {
      return ref.getValue();
    }
    throw new ExpressionException("Syntax Error, invalid Expression [" + cfml.toString() + "]");
  }
 /**
  * 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 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;
  }
  /**
   * 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");
  }
  /**
   * 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;
  }
  /**
   * 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));
  }
 private Ref _minus(Ref ref) throws PageException {
   // -=
   if (cfml.isCurrent('=')) {
     cfml.next();
     cfml.removeSpace();
     Ref right = assignOp();
     Ref res = new Minus(ref, right);
     ref = new Assign(ref, res);
   }
   /*/ --
   else if (cfml.isCurrent('-')) {
   	cfml.next();
   	cfml.removeSpace();
   	Ref res = new Minus(ref,new LNumber(new Double(1)));
   	ref=new Assign(ref,res);
   	ref=new Plus(ref,new LNumber(new Double(1)));
   }*/
   else {
     cfml.removeSpace();
     ref = new Minus(ref, modOp());
   }
   return ref;
 }
 /**
  * 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();
 }
 /**
  * Liest einen CFML Scope aus, falls der folgende identifier keinem Scope entspricht, gibt die
  * Variable null zurck. <br>
  * EBNF:<br>
  * <code>
  * "variable" | "cgi" | "url" | "form" | "session" | "application" | "arguments" | "cookie" | " client";
  * </code>
  *
  * @param idStr String identifier, wird aus Optimierungszwechen nicht innerhalb dieser Funktion
  *     ausgelsen.
  * @return CFXD Variable Element oder null
  */
 private Ref scope(String idStr) {
   if (idStr.equals("var")) {
     String name = identifier(false);
     if (name != null) {
       cfml.removeSpace();
       return new Variable(
           pc, new railo.runtime.interpreter.ref.var.Scope(pc, ScopeSupport.SCOPE_VAR), name);
     }
   }
   int scope = VariableInterpreter.scopeString2Int(idStr);
   if (scope == Scope.SCOPE_UNDEFINED) {
     return new Variable(
         pc, new railo.runtime.interpreter.ref.var.Scope(pc, Scope.SCOPE_UNDEFINED), idStr);
   }
   return new railo.runtime.interpreter.ref.var.Scope(pc, scope);
 }
  /**
   * 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()]);
  }
 private Ref _unaryOp(Ref ref, boolean isPlus) throws PageException {
   cfml.removeSpace();
   Ref res = new Plus(ref, isPlus ? PLUS_ONE : MINUS_ONE);
   ref = new Assign(ref, res);
   return new Plus(ref, isPlus ? MINUS_ONE : PLUS_ONE);
 }
  /**
   * <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;
  }
 /**
  * Transfomiert ein Collection Element das in eckigen Klammern aufgerufen wird. <br>
  * EBNF:<br>
  * <code>"[" impOp "]"</code>
  *
  * @return CFXD Element
  * @throws PageException
  */
 private Ref structElement() throws PageException {
   cfml.removeSpace();
   Ref ref = new Casting(pc, "string", CFTypes.TYPE_STRING, assignOp());
   cfml.removeSpace();
   return ref;
 }