解析表达式和检索解析树的最简单方法是什么?

时间:2012-06-08 10:47:01

标签: c# vb.net parsing .net-2.0 expression-trees

我只想解析像

这样的简单表达式
IIF(FVAL(PFC) = TRUE, (IIF((ORGVAL(BAS, "2012/12/31") + ORGVAL(DA)) < 6500, (FVAL(BAS)  + FVAL(DA)) * 12%, 780)), 0)`

解析后,我应该能够知道哪些函数包含哪些参数。

|-FVAL
       |-PFC
|-ORGVAL 
       |-BAS
       |-"2012/12/31"

我坚持使用.Net Framework 2.0,所以没有Linq或lambda表达对我好。此外,我想将代码包含在我的自定义库中,而不仅仅是引用它。任何人都可以给我一些好的图书馆或代码。

我只需要解析而不是评估表达式并找到正在使用的令牌。在找到令牌之后,我需要在解析之前更改表达式字符串,就像使用函数ORGVAL一样,传递的参数必须以下划线为前缀。与ORGVAL(BAS)一样,我们会转换为ORGVAL(_BAS)。某些功能可以包含两个参数,例如ORGVAL(BAS, "2012/12/31"),这将转换为ORGVAL(_BAS, "2012/12/31")

注意:如果还有其他方式,请让我知道。我很乐意避免使用助手和词霸。

3 个答案:

答案 0 :(得分:1)

这看起来像一个未经修改但完整的表达式解析器(尚未对其进行测试,但可能是一个起点)。

http://gbacon.blogspot.it/2005/09/simple-expression-parser-in-c.html

它已经过时了,但你提到了C#2.0,所以无论如何它都可能没问题。我不确定它的目标是哪个版本的C#。

答案 1 :(得分:1)

如果您不介意使用其中一种.NET语言代码,可以使用CodeDom动态编译代码,然后将其作为仅内存中的程序集执行。例如,这将是您显示的示例表达式的最接近的近似值:

private abstract class Logic
{
    protected double FVAL(object arg)
    {
        // put code here
        return 0;
    }

    protected double ORGVAL(object arg)
    {
        // put code here
        return 0;
    }

    protected double ORGVAL(object arg, string date)
    {
        // put code here
        return 0;
    }

    public abstract double GetValue(object PFC, object BAS, object DA);
}

private class DynamicLogic : Logic
{
    public override double GetValue(object PFC, object BAS, object DA)
    {
        return (FVAL(PFC) = true ? ((ORGVAL(BAS, "2012/12/31") + ORGVAL(DA)) < 6500 ? (FVAL(BAS) + FVAL(DA)) * .12 : 780) : 0);
    }
}


private Logic GenerateLogic(string code)
{
    using (CSharpCodeProvider provider = new CSharpCodeProvider())
    {
        StringBuilder classCode = new StringBuilder();
        classCode.AppendLine("private class DynamicLogic : Logic");
        classCode.AppendLine("    {");
        classCode.AppendLine("        public override int GetValue(object PFC, object BAS, object DA)");
        classCode.AppendLine("        {");
        classCode.AppendLine("            return (" + code + ");");
        classCode.AppendLine("        }");
        classCode.AppendLine("    }");
        CompilerParameters p = new CompilerParameters();
        p.GenerateInMemory = true;
        p.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);
        CompilerResults results = provider.CompileAssemblyFromSource(p, code);
        return (Logic)Activator.CreateInstance(type);
        if (results.Errors.HasErrors)
        {
            throw new Exception("Failed to compile DynamicLogic class");
        }
        return (Logic)results.CompiledAssembly.CreateInstance("DynamicLogic");
    }
}

private double evaluate(object PFC, object BAS, object DA)
{
    Logic logic = GenerateLogic("FVAL(PFC) = true ? ((ORGVAL(BAS, \"2012/12/31\") + ORGVAL(DA)) < 6500 ? (FVAL(BAS) + FVAL(DA)) * .12  : 780) : 0");
    return logic.GetValue(PFC, BAS, DA);
}

编辑:我知道你说你需要实际获得表达式三,本身,不只是评估它,但我编写代码,所以我想我会继续发布它适合未来的路人。

答案 2 :(得分:1)

你想要做的事情听起来很像解析,所以我认为找到一个不涉及解析的解决方案会有很多好运。如果您想说的是您不想自己编写解析器,那么可以使用几个数学表达式解析库。

我是Jep.Net(http://www.singularsys.com/jep.net)的作者之一,它是一个可能满足您需求的表达式解析组件。它具有良好的文档记录,可高度自定义,绝对可以让您跳过实现自定义解析器的繁琐且容易出错的过程。如果它不适合你,谷歌搜索“.net表达式解析库”将获得其他库。

祝你好运!