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

2019年2月20日09:18:22

AST语法树自己写代码解析的话就比较麻烦,有现成的库可以解析PHP,就像webpack就是自己解析js的语法代码,编译成各种版本的可用代码

github https://github.com/josdejong/mathjs

ExtensionDescription
mathstepsA 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‑parserThis 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-integralExtends Math.js to be able to compute simple integrals.
math.diff.jsSymbolic differentiation plugin for Math.js
postcss-mathPostCSS plugin for making calculations with math.js

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

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

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

http://mathjs.org   

PHP可用的库

composer require nikic/php-parser

一直在更新可以使用

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);

结果

我是使用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

这个微软的库

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值