标签:优先级 ast 运算符 token 引擎 构建 govaluate 解析 节点
序言
首先明确引入规则引擎的目的是, 从 if... else ...
中解放出来。规则引擎可依据不同项目进行选型,本次主要分享bsp中使用到的govaluate规则引擎。
其输入为规则表达式和k-v键值对条件对象,通过规则引擎执行表达式,得到表达式的结果。
AST
Abstract Syntax Tree简称AST,中文叫做抽象语法树。
govaluate首先将表达式构建出一颗ast。举个例子:比如规则表达式为 1+foo+4*boo>0
exp := "1+foo+4*boo>0"
expression, err := govaluate.NewEvaluableExpression(exp)
|
构建步骤
构建树时的流程图如下:
parseTokens
parserToken后,我们可以得到一堆token:
checkBalance
检查小括号是否成对出现
checkExpressionSyntax
check token之间是否符合预设规则,核心是函数getLexerStateForToken
check当前的token是否是上一个token的合法值,合法值是预设的,比如NUMERIC的合法值是后面这些:
optimizeTokens
优化token,主要是编译一下正则
planStages
构建ast、优化ast为avl tree、预计算。
planStages这个大步骤内部大概分成了planTokens、reorderStages、elideLiterals这三个小步骤
planTokens
给定一个规划器,创建一个函数来评估运算符的特定优先级,并将其链接到其他递归解析更高优先级的函数。
它用func做不同运算符的优先级计算,原理是func接收struct作为参数,而参数中的next为这个函数连接的下一个优先级的func。
其中核心函数为planPrecedenceLevel
这个func优先级打印出来是这样的:
有了运算符优先级之后,对于具体的节点,会继续看节点类型,比如是func,accesser还是valueType,valueType的节点对于不同的详细类型也有不同策略,比如数字节点会构建一个Node,而小括号节点会直接parser下一个token来构建优先级更高的树。
如valueType构建Node在planValue里具体体现为:
对于不同的运算符,在这个函数链上会下沉构建出优先级比较高的节点,保证符合数学计算的规律。
planToken执行完后,会变成这样一颗树:
例子体现为
reorderStages
这里主要把ast重排序,让ast由普通tree变成avl tree(Adelson-Velsky Landis Tree 自平衡二叉查找树)
重排序的过程是把相同优先级的节点进行旋转,第一步是交换左右节点:
第二步是LL左旋:
这样就平衡了
elideLiterals
这个步骤是看叶子节点是否为LITERAL(本例可以暂且理解为数字类型的值),遍历整个树中的所有运算符,省略两边都是LITERAL的运算符。比如这棵树:
在这个阶段,各个子节点会进行dfs(Depth First Search 深度优先搜索)预计算。
各符号对应的算子如下:
至此第一阶段的逻辑梳理完毕,即ast构建完成。
Evaluate
Evaluate的主要功能即把k-v键值对条件对象填入ast,进行计算,得到一个interface类型的结果。
不足
弱类型
govaluate所有数字类型都是被解析为float64进行计算的,这么玩写代码爽了,但是当你用1+2+9做表达式时,可能会得到一个类型为fload64的interface{}结果。
参数会去除转义符
比如这段代码:
理论上结果应该含有转义符,实际上结果是:
标签:优先级,ast,运算符,token,引擎,构建,govaluate,解析,节点 来源: https://www.cnblogs.com/apperception/p/16399821.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。