解析数学表达式 代码解析AST语法树

2019年2月20日09:18:22php

 

AST语法树本身写代码解析的话就比较麻烦,有现成的库能够解析PHP,就像webpack就是本身解析js的语法代码,编译成各类版本的可用代码css

github https://github.com/josdejong/mathjsjava

 

Extension Description
mathsteps A step-by-step math solver library that is focused on pedagogy (how best to teach). The math problems it focuses on are pre-algebra and algebra problems involving simplifying expressions.
mathjs‑expression‑parser This custom build of mathjs contains just the expression parser and basic arithmetic functions for numbers. About four times as small as the full mathjs library.
mathjs-simple-integral Extends Math.js to be able to compute simple integrals.
math.diff.js Symbolic differentiation plugin for Math.js
postcss-math PostCSS plugin for making calculations with math.js

 

 没有办法,本身去实现  前缀,中缀,后缀表达式来实现解析字符串,对于简单的加减乘除都是比较容易的,可是须要支持一些复杂一点逻辑的计算就比较麻烦,好比开方,乘方等node

 

其余一些解析工具基本都是java ,c,cpp的webpack

又尝试找了一些工具,发现JavaScript里面有一些,可是不符合个人我的需求,可是能够知足大部分,简单数学字符数解析和计算git

http://mathjs.org   github

PHP可用的库web

composer require nikic/php-parser

一直在更新可使用express

namespace App\Http\Controllers\Data\V2;

use App\Http\Controllers\Data\V2\BaseController as Base;

use PhpParser\Error;
use PhpParser\NodeDumper;
use PhpParser\ParserFactory;

class CommonController extends Base {

    public static function index(Request $Request) {
        $code = <<<CODE
<?php
((99 + 1)*4-1);
CODE;
        $parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
        try {
            $ast = $parser->parse($code);
        } catch (Error $error) {
            echo "Parse error: {$error->getMessage()}\n";
            return;
        }

        $dumper = new NodeDumper;
        echo $dumper->dump($ast);

结果markdown

我是使用pre打印的

array(
    0: Stmt_Expression(
        expr: Expr_BinaryOp_Minus(
            left: Expr_BinaryOp_Mul(
                left: Expr_BinaryOp_Plus(
                    left: Scalar_LNumber(
                        value: 99
                    )
                    right: Scalar_LNumber(
                        value: 1
                    )
                )
                right: Scalar_LNumber(
                    value: 4
                )
            )
            right: Expr_BinaryOp_Plus(
                left: Scalar_LNumber(
                    value: 1
                )
                right: Scalar_LNumber(
                    value: 2
                )
            )
        )
    )
)

 

基本就能够达到语法树解析,元素本身解析就能够了,可是支持的运算符只能支持官方已有的运算符,特殊的运算符或者自定义的运算符,得本身标记去解析,特别复杂的须要本身根据解析的ast去从新转换成本身实际业务的需求

若是你须要添加一个vistor 遍历真个ast树 ,并获取,修改数据 

 

<?php

namespace App\Service;

use PhpParser\NodeVisitorAbstract;
use PhpParser\Node;

class Visitor extends NodeVisitorAbstract {

    public $data;
    public $operator;

    public function __construct() {
        $this->data = new \SplStack();
        $this->operator = new \SplStack();
    }

    public function leaveNode(Node $node) {
        //全部的符号
        if ($node instanceof Node\Expr) {
            $this->operator->push($node->getType());
        }
        //全部运算符
//        if ($node instanceof Node\Expr\BinaryOp) {
//            $this->operator->push($node->getType());
//        }
//        $this->operator->push($node->getType());
        if ($node instanceof Node\Scalar) {
            $this->data->push((string) $node->value);
        }
    }

    public function getData() {
        return $this->data;
    }

    public function getOperator() {
        return $this->operator;
    }

}

而后在解析ast树的代码添加vistor

 

   public function TransformToAst($string = '') {
        try {
            if (empty($string)) {
                throw new \Exception('公式不能为空');
            }
            $code = <<<CODE
<?php
$string;
CODE;
            $ParserFactory = new ParserFactory();
            $parser = $ParserFactory->create(ParserFactory::PREFER_PHP7);
            $ast = $parser->parse($code);

            $traverser = new NodeTraverser;
            $Visitor = new Visitor();
            $traverser->addVisitor($Visitor);
            
            $modifiedStmts = $traverser->traverse($ast);
            p($Visitor->getOperator());
            pp($Visitor->getData());
//            pp($modifiedStmts);
//           
            die;


            if (empty($ast_object)) {
                throw new \Exception('解析表达式为空');
            }
            $ast_new = self::ParseAstToArray($ast_object['0']);
            return $ast_new;
        } catch (\Exception $e) {
            throw new \Exception($e->getMessage() . $e->getFile() . $e->getLine());
        }
    }

其余提供的不少工具类,可是缺乏demo实例,让处入手的人很难直接上手使用

 参考 https://github.com/nikic/PHP-Parser/blob/master/doc/component/Walking_the_AST.markdown 之后有时间在翻译一下文档

Microsoft/tolerant-php-parser

这个微软的库

相关文章
相关标签/搜索