我正在构建一个表达式分析器,我想从中生成数据库查询代码,我已经走得很远,但是我很难准确地解析BinaryExpressions。将它们分解为Left和Right非常容易,但我需要检测括号并相应地生成我的代码,我看不到如何执行此操作。
一个例子[请忽略有缺陷的逻辑:)]:
a => a.Line2 != "1" && (a.Line2 == "a" || a.Line2 != "b") && !a.Line1.EndsWith("a")
我需要在中间检测'set'并保留它们的分组但是在解析期间我看不出表达式与正常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类正确地将括号部分与其他部分分开,但由于括号,没有表明它是一个集合。
答案 0 :(得分:6)
我自己没有使用过Expression,但是如果它可以像任何其他AST那样工作,那么这个问题比你想要的更容易解决。正如另一位评论员指出的那样,只需在括号中加上所有的二进制表达式,然后就不必担心操作顺序问题了。
或者,您可以检查您生成的表达式的优先级是否低于包含表达式的优先级,如果是,则在其周围加上括号。因此,如果你有一个像这样的[* 4 [+ 5 6]]
树(其中树节点以递归方式表示为[node left-subtree right-subtree]
),你会知道何时写出它包含在{{1} [+ 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
}
您需要为各种运算符设置一个优先级表,以及一种获取运算符本身以查明它是什么以及它的优先级的方法。但是,我想你可以想出那部分。
答案 1 :(得分:0)
构建表达式分析器时,首先需要一个解析器,为此你需要一个tokenizer。
tokenizer是一段代码,用于读取表达式,生成令牌(可以是有效的或无效的),用于确定的语法。
因此,您的解析器使用tokenizer以已建立的顺序(从左到右,从右到左,从上到下,无论您选择的方式)读取表达式,并创建一个映射表达式的树。 / p>
然后,分析器将树解释为表达式,赋予其明确的含义。