解析數學表達式 代碼解析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

這個微軟的庫

相關文章
相關標籤/搜索