自定义标记符,带引号的迭代器

时间:2014-08-07 06:05:57

标签: java text iterator token

也许有人可以提供帮助? 如何修改此方法next()下一个标记可以是:' abc'带引号的文字。 现在,如果文本包含引用,则抛出ExpressionException Unknown operator''''在位置......

 @Override
    public String next() {
        StringBuilder token = new StringBuilder();
        if (pos >= input.length()) {
            return previousToken = null;
        }
        char ch = input.charAt(pos);
        while (Character.isWhitespace(ch) && pos < input.length()) {
            ch = input.charAt(++pos);
        }
        if (Character.isDigit(ch)) {
            while ((Character.isDigit(ch) || ch == decimalSeparator)
                    && (pos < input.length())) {
                token.append(input.charAt(pos++));
                ch = pos == input.length() ? 0 : input.charAt(pos);
            }
        } else if (ch == minusSign
                && Character.isDigit(peekNextChar())
                && ("(".equals(previousToken) || ",".equals(previousToken)
                        || previousToken == null || operators
                        .containsKey(previousToken))) {
            token.append(minusSign);
            pos++;
            token.append(next());
        } else if (Character.isLetter(ch)) {
            while ((Character.isLetter(ch) || Character.isDigit(ch) || (ch == '_')) && (pos < input.length())) {
                token.append(input.charAt(pos++));
                ch = pos == input.length() ? 0 : input.charAt(pos);
            }
            } else if (ch == '(' || ch == ')' || ch == ',') {
                token.append(ch);
                pos++;
                //FIXME
            else if (ch == '\''){

                pos++;
                String temp = "\'"+next()+"\'";
                token.append(temp);
                pos++;

            }
            //        

} else {
                while (!Character.isLetter(ch) && !Character.isDigit(ch)
                        && !Character.isWhitespace(ch) && ch != '('
                        && ch != ')' && ch != ',' && (pos < input.length())) {
                    token.append(input.charAt(pos));
                    pos++;
                    ch = pos == input.length() ? 0 : input.charAt(pos);
                    if (ch == minusSign) {
                        break;
                    }
                }
                if (!operators.containsKey(token.toString())) {
                    throw new ExpressionException("Unknown operator '" + token
                            + "' at position " + (pos - token.length() + 1));
                }
            }
            return previousToken = token.toString();
        }

EVAL

public Object eval() {

    Stack<Object> stack = new Stack<Object>();

    for (String token : getRPN()) {
        mylog.pl("Reverse polish notation TOKEN : " + token + " RPN size: " + getRPN().size() );
        if (operators.containsKey(token)) {
            Object v1 = stack.pop();
            Object v2 = stack.pop();
            stack.push(operators.get(token).eval(v2, v1));
        } else if (variables.containsKey(token)) {
            stack.push(variables.get(token).round(mc));
        } else if (functions.containsKey(token.toUpperCase())) {
            Function f = functions.get(token.toUpperCase());
            ArrayList<Object> p = new ArrayList<Object>(f.getNumParams());
            for (int i = 0; i < f.numParams; i++) {
                p.add(0, stack.pop());
            }
            Object fResult = f.eval(p);
            stack.push(fResult);
        } else if (isDate(token)) {
            Long date = null;
            try {
                date = SU.sdf.parse(token).getTime();
            } catch (ParseException e) {/* IGNORE! */
            }
            stack.push(new BigDecimal(date, mc));
        } else {
            if (BusinessStrategy.PREFIX_X.equals(Character.toString(token.charAt(0)))) {
                stack.push(token);
            } else {
                stack.push(new BigDecimal(token, mc));
            }
        }
    }
    return stack.pop();
}

反向表示法

    private List<String> getRPN() {
    if (rpn == null) {
        rpn = shuntingYard(this.expression);
    }
    return rpn;
}

堆场

    private List<String> shuntingYard(String expression) {
    List<String> outputQueue = new ArrayList<String>();
    Stack<String> stack = new Stack<String>();

    Tokenizer tokenizer = new Tokenizer(expression);

    String lastFunction = null;
    while (tokenizer.hasNext()) {
        String token = tokenizer.next();
        if (isNumber(token)) {
            outputQueue.add(token);                     
        } else if (variables.containsKey(token)) {
            outputQueue.add(token);
        } else if (functions.containsKey(token.toUpperCase())) {
            stack.push(token);
            lastFunction = token;
        } else if (Character.isLetter(token.charAt(0))) {
            if ("\'".equals(Character.toString(token.charAt(0)))){
                outputQueue.add(token);                    
            } else {
                stack.push(token);                    
            }
        } else if (",".equals(token)) {
            while (!stack.isEmpty() && !"(".equals(stack.peek())) {
                outputQueue.add(stack.pop());
            }
            if (stack.isEmpty()) {
                throw new ExpressionException("Parse error for function '"
                        + lastFunction + "'");
            }
        } else if (operators.containsKey(token)) {
            Operator o1 = operators.get(token);
            String token2 = stack.isEmpty() ? null : stack.peek();
            while (operators.containsKey(token2)
                    && ((o1.isLeftAssoc() && o1.getPrecedence() <= operators
                            .get(token2).getPrecedence()) || (o1
                            .getPrecedence() < operators.get(token2)
                            .getPrecedence()))) {
                outputQueue.add(stack.pop());
                token2 = stack.isEmpty() ? null : stack.peek();
            }
            stack.push(token);
        } else if ("(".equals(token)) {
            stack.push(token);
        } else if (")".equals(token)) {
            while (!stack.isEmpty() && !"(".equals(stack.peek())) {
                outputQueue.add(stack.pop());
            }
            if (stack.isEmpty()) {
                throw new RuntimeException("Mismatched parentheses");
            }
            stack.pop();
            if (!stack.isEmpty()
                    && functions.containsKey(stack.peek().toUpperCase())) {
                outputQueue.add(stack.pop());
            }
        }
    }
    while (!stack.isEmpty()) {
        String element = stack.pop();
        if ("(".equals(element) || ")".equals(element)) {
            throw new RuntimeException("Mismatched parentheses");
        }
        if (!operators.containsKey(element)) {
            throw new RuntimeException("Unknown operator or function: "
                    + element);
        }
        outputQueue.add(element);
    }
    return outputQueue;
}

错误

*java.util.EmptyStackException
    at java.util.Stack.peek(Unknown Source)
    at java.util.Stack.pop(Unknown Source)
    at com.business.Expression.eval(Expression.java:1033)*

它在eval方法Object v1 = stack.pop();行。

谢谢!

1 个答案:

答案 0 :(得分:1)

在方法next中,您可以在两个地方进行递归调用:

  1. 看到减号后
  2. 认识到一位被告后
  3. 第一种情况是构造令牌,其中一个减号后面跟一个数字(即一个不带数字的号码) - 好的。 (虽然没有标志但是一元减号运算符值得考虑。)

    第二种情况意味着麻烦。在超过最初的撇号后,预计会出现另一个下一个结果,就好像字符串文字只包含一个数字或一个标识符或单个运算符。无论如何,next()执行,让它说它返回一个数字:然后将一个apostroph添加到令牌中,但是没有努力检查是否有一个关闭撇号,也没有跳过它。 / p>

     else if (ch == '\''){
         token.append( '\'' );
         pos++;
         while( pos < input.length() &&
                (ch = input.charAt(pos++)) != '\'' ){
             token.append( ch );
         }
         token.append( '\'' );
    

    这不允许撇号成为字符串中的字符,并且它不会诊断未终止的字符串。但这可以很容易地添加。