C# 中的自定义表达式解析器

Custom Expression Parser in C#

我正在为财务应用开发计算器程序。 我需要解析和评估如下所述的复杂财务表达式。

该表达式是自定义函数和算术表达式的混合体。 我正在使用 NCalc 来解析算术表达式。但是,我在解析自定义函数时遇到了问题。

IF((COALESCE(X1,X2)-X3+IF(X4<=0,0,X5))>0, CUSTOM_FUNCTION(X6), X7)

对最佳方法有什么建议吗?

我目前正在研究涉及递归调用和堆栈的复杂逻辑Push/Pop。但它不起作用。

这是一个老问题,很久以前就解决了。解决方案是使用解析器生成器,而不是从头开始编写您自己的解析器。有许多可用的选项,ANTLR 是最受欢迎的选项之一。

使用像 ANTLR 这样的解析器生成器,您可以使用易于理解的 EBNF 类生产规则来描述您的问题。解析器生成器将生成复杂的逻辑,看起来你现在正试图用你选择的语言手写,在你的例子中是 C#。可能您的语言的语法已经以这种格式提供,或者您已经使用这种格式向您的用户和您的开发团队描述该语言。

我认为你必须使用有限状态机。编译器基于它。 您必须逐个字母地解析字符串,并定义您的操作: 类似的东西:

Do { //your parser i++; } While(i

Mishax 是对的,你写规则的方式比直接用 C# 编码更清晰。如果您在使用 ANTLR 和 C# 时遇到问题(我遇到过),还有其他专用于 C# 的生成器 -- Irony, Coco/R, GOLD, ANTLR, LLLPG, Sprache, or my NLT

不要让你只是坚持信念(如果你只想要结果):

expr -> e1:expr "+" e2:expr { e1+e2 }
      | e1:expr "*" e2:expr { e1*e2 }
      ... and so on ...
      ;

原始 C# 中的等效部分会长得多。

我会推荐使用 JavaScript 解释器的替代方法。

https://github.com/sebastienros/jint

JInt 有一个强大的解析器,但是您需要更改的东西很少。

IF 和 COALESCE 在 JavaScript 中不存在,但是它们可以转换,例如。

IF 表达式

x = IF(CONDITION,THEN,ELSE) 

JavaScript等价于

x = CONDITION ? THEN : ELSE

COALESCE 表达式

x = COALESCE(x1,x2,x3)

JavaScript等价于

x = x1 != null ? x1 : 
        (x2 != null ? x2 : 
             (x3 != null ? x3 : null ))

JInt 会给你一个解析后的 AST,你可以操作 AST 并转换相应的 IF 和 COALESCE 运算符。

使用组织良好的 JInt 解析器并简单地 post 处理 AST 将比重新发明轮子容易得多。

通过使用 JInt,您还可以使用各种现有的 .NET 方法,并且可以轻松地注入您自己的 类 来表示上下文值。