问题描述
|
我正在构建一个表达式分析器,我想从该表达式分析器生成数据库查询代码,虽然我已经走了很远,但仍无法准确地解析BinaryExpressions。将它们分为左和右是很容易的,但是我需要检测括号并相应地生成我的代码,而我看不到如何做到这一点。
一个例子[请忽略有缺陷的逻辑:)]:
a => a.Line2 != \"1\" && (a.Line2 == \"a\" || a.Line2 != \"b\") && !a.Line1.EndsWith(\"a\")
我需要检测中间的\'set \'并保留它们的分组,但是在解析期间我看不到表达式与普通BinaryExpression的任何区别(我不希望检查字符串表示形式的括号)
任何帮助,将不胜感激。
(我可能应该提到我正在使用C#)
- 编辑 -
我没有提到我正在使用标准的.Net Expression类来构建表达式(System.Linq.Expressions命名空间)
-编辑2--
好的,我不是将文本解析为代码,而是将代码解析为文本。所以我的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类正确地将括号部分与其他部分分开,但是由于括号的原因,没有给出任何表示该集合的信息。
解决方法
我自己还没有使用过Expression,但是如果它可以像其他AST一样工作,那么这个问题比您发现的要容易解决。正如另一位评论者指出的那样,只需在所有二进制表达式两边加上括号,就不必担心运算顺序问题。
或者,您可以检查所生成的表达式的优先级是否低于包含表达式的优先级,如果是,则在其周围加上括号。因此,如果您有一个像这样的树
[* 4 [+ 5 6]]
(树节点被递归表示为[node left-subtree right-subtree]
),您会在写出[+ 4 5]
树时知道它包含在*
运算中,它的优先级高于than8ѭ运算,因此要求它的任何直接子树都放在括号中。伪代码可能是这样的:
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
}
您将需要有一张针对各种运算符的优先级表,以及一种获取运算符本身的方法,以了解它是什么以及其优先级是什么。但是,我想您可以弄清楚那部分。
, 构建表达式分析器时,首先需要一个解析器,为此需要一个标记器。
标记器是一段代码,用于读取表达式,并为确定的语法生成标记(可以有效或无效)。
因此,解析器使用令牌生成器以已建立的顺序(从左到右,从右到左,从上到下,无论您选择什么)读取表达式,并创建一个映射表达式的树。
然后,分析器将树解释为表达式,给出其确定的含义。