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


    2019年2月20日09:18:22

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

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

    ExtensionDescription
    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

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

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

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

    http://mathjs.org   

    PHP可用的库

    composer require nikic/php-parser

    一直在更新可以使用

    namespace AppHttpControllersDataV2;
    
    use AppHttpControllersDataV2BaseController as Base;
    
    use PhpParserError;
    use PhpParserNodeDumper;
    use PhpParserParserFactory;
    
    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()}
    ";
                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 AppService;
    
    use PhpParserNodeVisitorAbstract;
    use PhpParserNode;
    
    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 NodeExpr) {
                $this->operator->push($node->getType());
            }
            //所有运算符
    //        if ($node instanceof NodeExprBinaryOp) {
    //            $this->operator->push($node->getType());
    //        }
    //        $this->operator->push($node->getType());
            if ($node instanceof NodeScalar) {
                $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

    这个微软的库

  • 相关阅读:
    dotnetcore3.1 WPF 实现多语言
    dotnetcore3.1 WPF 中使用依赖注入
    [svc]打通mysql主从同步
    [svc]glusterfs的简单部署
    [svc]inotify+rsync解决nfs单点问题
    [svc]rsync简单部署
    [svc]linux文件权限
    [svc]ssh批量分发key/批量用户管理
    [svc]NFS存储企业场景及nfs最佳实战探究
    [svc]mount命令及解决因/etc/fstab错误导致系统不能启动故障
  • 原文地址:https://www.cnblogs.com/zx-admin/p/10404624.html
Copyright © 2020-2023  润新知