2019年2月20日09:18:22
AST语法树自己写代码解析的话就比较麻烦,有现成的库可以解析PHP,就像webpack就是自己解析js的语法代码,编译成各种版本的可用代码
github https://github.com/josdejong/mathjs
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 |
没有办法,自己去实现 前缀,中缀,后缀表达式来实现解析字符串,对于简单的加减乘除都是比较容易的,但是需要支持一些复杂一点逻辑的计算就比较麻烦,比如开方,乘方等
其他一些解析工具基本都是java ,c,cpp的
又尝试找了一些工具,发现JavaScript里面有一些,但是不符合我的个人需求,但是可以满足大部分,简单数学字符数解析和计算
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
这个微软的库