解析数学表达式

3
给定一个包含数学表达式的字符串,给定一组函数/命令和一组分配的变量,是否有.NET提供的工具可以快速构建解析器?我想构建一个简单的解析器来分析表达式并将其分解为其最简单的组成部分,例如:d *(abs(a-b)+ sqrt(c)),变成f = abs(a-b)和g = sqrt(c),e = f + g,d * e。
4个回答

6

你是想构建一个解析器还是只需要解决方案呢?

无论哪种情况,都可以查看nCalc。如果只需要解决问题,请获取二进制文件。如果需要查看它们如何解析表达式树,请获取源代码。


好的,我想要构建一个简单的解析器:效率不重要,但其可扩展性很重要,可以轻松添加新的命令。我将阅读nCalc源代码,因此我会学到一些新知识。谢谢! - enzom83

4
我听说过 Grammatica 解析器生成器很不错。ANTLR 也被广泛使用(特别是在Java中)。
我假设你知道如何定义BNF语法并且之前已经学习或构建了解析器。

现在我需要更简单的东西。但是在未来几个月里,你的链接可能对我有用。谢谢! - enzom83

1

同时也可以查看veparser。这里有一个示例代码,展示了如何构建表达式求值器(该代码解析表达式并直接计算输出)。可以修改此示例以存储评估树而不是运行它。

using System;
using VeParser;

public class MathEvaluator : CharParser
{
    protected override Parser GetRootParser()
    {
        Func<double, double, double> productFunc = (value1, value2) => value1 * value2;
        Func<double, double, double> divideFunc = (value1, value2) => value1 / value2;
        Func<double, double, double> sumFunc = (value1, value2) => value1 + value2;
        Func<double, double, double> subtractFunc = (value1, value2) => value1 - value2;
        Func<double, double> negativeFunc = value => -value;
        Func<double, double> posititveFunc = value => value;


        var dot = token('.');
        var op = token('(');
        var cp = token(')');
        var sumOp = create(sumFunc, token('+'));
        var subtractOp = create(subtractFunc, token('-'));
        var positiveOp = create(posititveFunc, token('+'));
        var negativeOp = create(negativeFunc, token('-'));
        var productOp = create(productFunc, token('*'));
        var divideOp = create(divideFunc, token('/'));

        // Numbers
        var deciamlPlaceValue = 1M;
        var decimalDot = run(() => { deciamlPlaceValue = 1; }, dot);
        var digit = consume((n, d) => n * 10 + char.GetNumericValue(d), keep(Digit));
        var decimalDigit = consume((n, d) => { deciamlPlaceValue = deciamlPlaceValue * 10; return (double)((decimal)n + ((decimal)char.GetNumericValue(d)) / deciamlPlaceValue); }, keep(Digit));
        var number = any(
            /* float */  create(0, seq(zeroOrMore(digit), decimalDot, oneOrMore(decimalDigit))),
            /* int   */  create(0, oneOrMore(digit))
        );

        var expression = createReference();
        var simpleExpression = createReference();
        // Unary
        var unaryOp = any(positiveOp, negativeOp);
        var unaryExpression = update(d => d.action(d.value),
                    createNew(seq(set("action", unaryOp), set("value", expression))));
        // Binary
        var binaryOp = any(sumOp, subtractOp, productOp, divideOp);

        var binaryExpressinoTree = update(x => x.value1, createNew(
            seq(
                set("value1", simpleExpression),
                zeroOrMore(
                    update(d => { var r = base.CreateDynamicObject(); r.value1 = d.action(d.value1, d.value2); return r; },
                        seq(
                            set("action", binaryOp),
                            set("value2", simpleExpression))))
            )));


        var privilegedExpressoin = seq(op, expression, cp);

        setReference(simpleExpression, any(privilegedExpressoin, unaryExpression, number));

        setReference(expression, any(binaryExpressinoTree, simpleExpression));

        return seq(expression, endOfFile());
    }

    public static object Eval(string expression)
    {
        MathEvaluator me = new MathEvaluator();
        var result = me.Parse(expression.ToCharArray());
        return result;
    }
}

0

另一种方法

class Program
{
    static void Main(string[] args)
    {
        var a = 1;
        var b = 2;
        Console.WriteLine(FN_ParseSnippet($"{a} + {b} * 2"));
        Console.ReadKey();
    }

    public static object FN_ParseSnippet(string snippet)
    {
        object ret = null;

        var usingList = new List<string>();
        usingList.Add("System");
        usingList.Add("System.Collections.Generic");
        usingList.Add("System.Text");
        usingList.Add("Microsoft.CSharp");


        //Create method
        CodeMemberMethod pMethod = new CodeMemberMethod();
        pMethod.Name = "Execute";
        pMethod.Attributes = MemberAttributes.Public;
        pMethod.ReturnType = new CodeTypeReference(typeof(object));
        pMethod.Statements.Add(new CodeSnippetExpression(" return " + snippet));

        //Create Class
        CodeTypeDeclaration pClass = new System.CodeDom.CodeTypeDeclaration("Compilator");
        pClass.Attributes = MemberAttributes.Public;
        pClass.Members.Add(pMethod);
        //Create Namespace
        CodeNamespace pNamespace = new CodeNamespace("MyNamespace");
        pNamespace.Types.Add(pClass);
        foreach (string sUsing in usingList)
            pNamespace.Imports.Add(new CodeNamespaceImport(sUsing));

        //Create compile unit
        CodeCompileUnit pUnit = new CodeCompileUnit();
        pUnit.Namespaces.Add(pNamespace);


        CompilerParameters param = new CompilerParameters();
        param.GenerateInMemory = true;
        List<AssemblyName> pReferencedAssemblys = new List<AssemblyName>();
        pReferencedAssemblys = Assembly.GetExecutingAssembly().GetReferencedAssemblies().ToList();
        pReferencedAssemblys.Add(Assembly.GetExecutingAssembly().GetName());
        pReferencedAssemblys.Add(Assembly.GetCallingAssembly().GetName());
        foreach (AssemblyName asmName in pReferencedAssemblys)
        {
            Assembly asm = Assembly.Load(asmName);
            param.ReferencedAssemblies.Add(asm.Location);
        }

        //Compile
        CompilerResults pResults = (new CSharpCodeProvider()).CreateCompiler().CompileAssemblyFromDom(param, pUnit);

        if (pResults.Errors != null && pResults.Errors.Count > 0)
        {
            //foreach (CompilerError pError in pResults.Errors)
            //    MessageBox.Show(pError.ToString());

        }

        var instance = pResults.CompiledAssembly.CreateInstance("MyNamespace.Compilator");
        ret = instance.GetType().InvokeMember("Execute", BindingFlags.InvokeMethod, null, instance, null);

        return ret;
    }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接