验证表达式

时间:2017-01-05 03:24:29

标签: java parsing expression lexical-analysis

给定一个带有运算符,函数和操作数的表达式,例如:

2 + sin ( max ( 2, 3 ) / 3 * 3.1415 )

如何以编程方式验证表达式,以便任何函数必须具有正确数量的参数?例如,abs,sin,cos必须有1个参数,而sum,avg,max,min有2个或更多。

鉴于每个参数本身都是一个非常复杂的表达式,以编程方式确定这一点似乎并非易事。我已经编写了一个词法标记器(lexer),我已经设法将表达式转换为postfix / RPN。 (这是:2 3 max 3 / 3.1415 * sin 2 +)。我仍然没有接近解决方案。

我会很感激一些代码或伪代码,它们将指导我从头开始编写代码。 Java会很棒。

以下是我的词法分析器代码:

    public static List<Token> shunt(List<Token> tokens) throws Exception {
    List<Token> rpn = new ArrayList<Token>();
    Iterator<Token> it = tokens.iterator();
    Stack<Token> stack = new Stack<Token>();
    while (it.hasNext()) {
        Token token = it.next();
        if (Type.NUMBER.equals(token.type))
            rpn.add(token);
        if (Type.FUNCTION.equals(token.type) || Type.LPAREN.equals(token.type)) 
            stack.push(token);
        if (Type.COMMA.equals(token.type)) {
            while (!stack.isEmpty() && !Type.LPAREN.equals(stack.peek().type))
                rpn.add(stack.pop());
            if (stack.isEmpty()) 
                throw new Exception("Missing left parenthesis!");
        }
        if (Type.OPERATOR.equals(token.type)) {
            while (!stack.isEmpty() && Type.OPERATOR.equals(stack.peek().type))
                rpn.add(stack.pop());
            stack.add(token);
        }
        if (Type.RPAREN.equals(token.type)) {
            while (!stack.isEmpty() && !Type.LPAREN.equals(stack.peek().type))
                rpn.add(stack.pop());
            if (stack.isEmpty()) 
                throw new Exception("Missing left parenthesis!");
            stack.pop();
            if (!stack.isEmpty() && Type.FUNCTION.equals(stack.peek().type))
                rpn.add(stack.pop());
        }
    }
    while (!stack.isEmpty()) {
        if (Type.LPAREN.equals(stack.peek().type) || Type.RPAREN.equals(stack.peek().type))
            throw new Exception("Mismatched parenthesis!");
        rpn.add(stack.pop());
    }

    return rpn;
}

2 个答案:

答案 0 :(得分:1)

你想要做的是实现一个精确的解析器,它知道你的语言的确切语法(包括“函数有多少运算符”)。

为表达式编写这样的解析器很容易。见https://stackoverflow.com/a/2336769/120163

答案 1 :(得分:0)

您需要在调车场中检测它。一个快速的想法是在操作员堆栈上,对每个元素保持反击。计算检测到的逗号数。然后在闭括号或最后,检查每个函数条目的参数数量。

另一种方法可能是将更多信息作为RPN的附加值。例如保留逗号,然后得到:

2 , 3 max 3 / 3.1415 * sin 2 +

处理函数时,它不仅必须从堆栈中获取值,还必须使用正确数量的, s。太多人会在以后表现出来。

我担心这种方式有一些边缘情况,但是这样;所以可能更好的精确解析器。

sin(1,2) * max (3)

1 , 2 sin 3 max *