7

我正在构建一个表达式分析器,我想从中生成数据库查询代码,我已经走了很长一段路,但我无法准确地解析 BinaryExpressions。将它们分成左右很容易,但我需要检测括号并相应地生成我的代码,我看不出如何做到这一点。

一个例子[请忽略有缺陷的逻辑:)]:

a => a.Line2 != "1" && (a.Line2 == "a" || a.Line2 != "b") && !a.Line1.EndsWith("a")

我需要检测中间的“集合”并保留它们的分组,但在解析过程中我看不到表达式与正常 BinaryExpression 的任何差异(我不想检查括号中的字符串表示)

任何帮助,将不胜感激。

(我可能应该提到我正在使用 C#)

--Edit-- 我没有提到我正在使用标准的 .Net Expression 类来构建表达式(System.Linq.Expressions 命名空间)

--Edit2-- 好的,我不是将文本解析为代码,而是将代码解析为文本。所以我的 Parser 类有一个这样的方法:

void FilterWith<T>(Expression<Func<T, bool>> filterExpression);

它允许您编写如下代码:

FilterWith<Customer>(c => c.Name =="asd" && c.Surname == "qwe");

使用标准的 .Net 类很容易解析,我的挑战是解析这个表达式:

FilterWith<Customer>(c => c.Name == "asd" && (c.Surname == "qwe" && c.Status == 1) && !c.Disabled)

我的挑战是将括号之间的表达式保持为一个集合。.Net 类正确地将括号部分与其他部分分开,但由于括号而没有表明它是一个集合。

4

2 回答 2

7

我自己没有使用过 Expression,但如果它像任何其他 AST 一样工作,那么问题比你想象的更容易解决。正如另一位评论员指出的那样,只需在所有二进制表达式周围加上括号,然后您就不必担心运算顺序问题。

或者,您可以检查您正在生成的表达式的优先级是否低于包含表达式,如果是,请在其周围加上括号。因此,如果您有这样的树(其中树节点[* 4 [+ 5 6]]递归表示为放在括号里。伪代码可能是这样的:[node left-subtree right-subtree][+ 4 5]*+

function parseBinary(node) {
    if(node.left.operator.precedence < node.operator.precedence)
        write "(" + parseBinary(node.left) + ")"
    else
        write parseBinary(node.left)
    write node.operator
    // and now do the same thing for node.right as you did for node.left above    
}

您需要有一个各种运算符的优先级表,以及一种获取运算符本身以找出它是什么以及它的优先级是什么的方法。但是,我想您可以弄清楚那部分。

于 2011-05-30T17:17:28.690 回答
0

在构建表达式分析器时,您首先需要一个解析器,为此您需要一个分词器。

分词器是一段代码,它读取表达式,为确定的语法生成令牌(可以是有效的或无效的)。

因此,您的解析器使用标记器以既定顺序(从左到右、从右到左、从上到下,无论您选择什么)读取表达式,并创建一个映射表达式的树。

然后分析器将树解释为一个表达式,给出它的明确含义。

于 2011-05-30T13:53:17.507 回答