【问题标题】:Detect parenthesis in BinaryExpression检测 BinaryExpression 中的括号
【发布时间】:2011-09-04 19:42:03
【问题描述】:

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

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

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

我需要检测中间的“集合”并保留它们的分组,但在解析过程中我看不到表达式与普通 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 类正确地将括号部分与其他部分分开,但由于括号而没有表明它是一个集合。

【问题讨论】:

  • 我只是观察到这比人们想象的要难(已经做了几次),并且是许多“玩具”解析示例方便地没有解决的问题。
  • 递归体面的解析器很容易上手,任何关于编译器构造的大学水平的介绍性文本都会谈论它。括号由产生式 expr = "(" + expr + ")" 处理。不过,几乎不需要重新发明这种代码。甚至 .NET 也有一个:DataTable.Compute()。
  • 愿意分享您针对此问题所做的工作吗?我同意,这些例子是这个主题的基础......
  • Expression 类为您处理上述所有问题。它检索完整的、已实现的 AST。你能详细说明你的括号问题吗?或者你是用 Expression 类构建你的 AST 并且仍然手工编写词法分析器/解析器?

标签: c# .net expression-trees parentheses


【解决方案1】:

我自己没有使用过 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    
}

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

【讨论】:

  • 据我所知,没有“优先级”。然后递归地分析 AndAlso 和 OrElse 并在所有地方加上括号会更容易。
【解决方案2】:

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

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

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

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

【讨论】:

  • 嗯,不知道我明白你的意思。我正在使用标准的 .Net Expression 类(System.Linq.Expressions 命名空间),我现在正在查看的是 BinaryExpression...
  • @Adriaan:等等,你是从字符串到表达式树,还是从表达式树到字符串?如果生成一个字符串,你可以在每个子表达式周围加上括号。
  • @sixletter: 这么解释,我没注意到旧版本有这么大的不同......
  • @configurator:是的,我也输入了一个完整的玩具词法分析器/解析器组合:(
猜你喜欢
  • 2011-10-10
  • 2015-05-01
  • 1970-01-01
  • 2013-01-01
  • 1970-01-01
  • 2018-05-01
  • 2013-06-12
  • 2017-05-26
  • 2016-12-05
相关资源
最近更新 更多