代码之家  ›  专栏  ›  技术社区  ›  SuperJMN

展开数学表达式(展开括号)

  •  2
  • SuperJMN  · 技术社区  · 7 年前

    我有一个这样的表达 a*(b+c) 我已经成功解析成AST,所以它最终变成:

    enter image description here

    我试图扩展它最终变成的表达式 a*b + a*c ,但没有运气。

    我想知道一个算法来扩展表达式,或者是一个库来实现它,最好是用于。网

    5 回复  |  直到 7 年前
        1
  •  1
  •   axelclk    7 年前

    在里面 Symja 你可以使用 Distribute() Expand() 解决问题的功能:

    package org.matheclipse.core.examples;
    
    import org.matheclipse.core.eval.ExprEvaluator;
    import org.matheclipse.core.expression.F;
    import org.matheclipse.core.interfaces.IExpr;
    import org.matheclipse.parser.client.SyntaxError;
    import org.matheclipse.parser.client.math.MathException;
    
    public class ExpandSO54204637 {
    
        public static void main(String[] args) {
            try {
                ExprEvaluator util = new ExprEvaluator();
                IExpr expr = util.eval("a*(b+c)");
    
                IExpr result = util.eval(F.Distribute(expr));
                // print: a*b+a*c
                System.out.println(result.toString());
    
                result = util.eval(F.Expand(expr));
                // print: a*b+a*c
                System.out.println(result.toString());
    
            } catch (SyntaxError e) {
                // catch Symja parser errors here
                System.out.println(e.getMessage());
            } catch (MathException me) {
                // catch Symja math errors here
                System.out.println(me.getMessage());
            } catch (Exception e) {
                e.printStackTrace();
            } catch (final StackOverflowError soe) {
                System.out.println(soe.getMessage());
            } catch (final OutOfMemoryError oome) {
                System.out.println(oome.getMessage());
            }
        }
    }
    
        2
  •  1
  •   SCORP.io user9920519    7 年前

    如果你正在使用 shunting-yard algorithm 为了构造AST,每当在乘法运算符之后将左paren弹出到运算符堆栈上时,这就是分配和扩展表达式的信号。

    对于提供的图像,加法操作符移动为根节点,其子节点是当前树的副本,但加法节点被自己的子节点替换除外。

    希望这有助于创建解决方案。

    AST before and after distributive property

        3
  •  1
  •   SuperJMN    7 年前

    我发现了 Math.NET 有一个功能可以做到这一点:

    SymbolicExpression.Parse("a*(b+c)").Expand();
    
        4
  •  1
  •   Ira Baxter    7 年前

    您可以通过编写过程代码或使用源到源转换程序转换系统(PTS)来实现这一点。

    编写过程代码只需要调用支持函数来在树上下导航、删除节点之间的链接、删除节点、创建节点和链接节点。任何AST库都有(应该有!)这样的功能。

    因此,将“a*(b+c)”的程序解决方案改写为“a” b+a c“这是:

     Find tree root of "a*(b+c)".  That's the "*" node.
     Unlink the "a" child and the "b+c" child.
     Unlink the "b" and "c" children from the "+" node.
     Create a second "*" node.
     Link "a" and "b" nodes under the original "*" node, producing subtree "a*b*
     Copy the "a" node.
     Link the copyied-"a" and "c" under the second "*" node, producing subtree "a*c"
     Link the subtrees under the "+" node.
     Return "+" as the root of the tree.
    

    这并不是什么难事,只是调整链接而已。

    但是写起来很烦人,无助于从你可能想要操作的语言(“C#“?)解析表达式,不容易进行复杂的转换,也不能帮助您在更大的AST中找到这种可能要修改的子树。

    这就是为什么你想要一个PTS。一个好的PTS提供解析机器,以便为java、COBOL、C++或C语言等复杂语言构建解析器。 。如果它碰巧有经过严格验证的语法分析器,用于您想要操作的语言,它就会得到布朗尼分数(因为否则,您也会在树操作问题上获得编写语法分析器的权限)。

    例如,使用我们的DMS软件再工程工具包,您可以充分利用上述语言的经过充分验证的解析器。假设你想操纵C#, 然后,您可以编写这个DMS脚本,在任意大的C#AST上完成您的示例:

    domain CSharp~CSharp7_5; -- establishes which parser to use to read source code
    
    rule distribute_times_over_plus(a:multiplicative_expression,
                                    b:additive_expression,
                                    c:multiplicative_expression)
       :multiplicative_expression->multiplicative_expression
       = "\a*(\b+\c)"  -> "(\a*\b+\a*\c)";
    

    你可以把这个脚本交给DMS,它将解析一个C#源文件,并在找到模式的任何地方应用这个转换。(如果您想要对应用的位置/时间进行更多控制,您需要编写一个额外的元编程脚本来定义它,而不是依赖于内置的“apply everywhere”操作)。

    应该很清楚,这样写起来容易得多;不太清楚,但一个很大的好处是,DMS会检查它是否正常。你不能写一条违反语言语法的规则。(如果编写过程代码,可以以任何不合理的方式链接节点,然后进行调试)。如果你想写很多规则,这是一个巨大的帮助:有一整类错误你不能犯。最后,这些规则比您可能编写的程序代码更具可读性;这使它们更容易阅读、理解和修改。

    更多关于你可以在规则中写什么的详细信息,请访问 DMS Rewrite Rules .

    如果你想从定义一种语言(“大学微积分”)和将规则应用于该语言(“如何区分公式”)中详细了解这个例子,你可以在以下网站上看到: Algebra as a DMS Domain

    还有一个(巨大的)细节:如果普通AST代表编程语言,那么在它们上重写就不是非常有效,因为您不能忽略标识符的含义和范围。看见 Life After Parsing" 进行深入讨论。

    但归根结底,重写规则通常需要以要操作的编程语言的语义属性为条件。DMS规则通过允许额外的 如果条件 子句,可以调用为该语言定义的语义谓词。你可以在代数例子中看到一些简单的例子。

        5
  •  1
  •   Kintalken    7 年前

    这是prolog中的一行程序。 作为奖励,它是双向的。 i、 e.你设计它是为了“扩展”,你可以免费获得“未扩展”。下面是一个使用yap prolog的交互式REPL的示例。所有大写字母的标识符都是变量。

    $ yap
    YAP 6.2.2 (x86_64-linux): Sat Sep 17 13:59:03 UTC 2016
    
    ?- [user].
    
    /* consulting user_input... */
    
    rewrite(A * (B + C), (A * B + A * C)) .
    
    end_of_file .
    
    /* example usage from the REPL */
    
    ?- rewrite(3 * (4 + 5), REWRITTEN) .
    
    REWRITTEN = 3*4+3*5
    
    ?- rewrite(a * (b + c), REWRITTEN) .
    
    REWRITTEN = a*b+a*c
    
    /* example usage showing it work the opposite way */
    
    ?- rewrite(REWRITABLE,(3*4+3*5)) .
    
    REWRITABLE = 3*(4+5)