Packrat Parsing
前言
最近看Scala的Parser Generator库的实现,发现其支持记忆化的回溯解析,因为以前没有了解过这方面的知识,所以我就找到了其算法:Packrat Parsing好好研究了下。
What
Packrat Parsing是实现线性时间复杂度的回溯解析算法。
Why
很多递归下降时的算法有两种实现:
- 回溯法, 理论能力更强,但是最差时间复杂度为指数级别。
- 预测分析,通过peek等偷看后面的token,能达到线性的复杂度。
Packrat让回溯解析也能做到线性时间复杂度了。
How
记忆化是动态规划算法的本质,因为CFG属于无状态的解析过程,所以完全可以使用记忆化的策略来进行保存中间的计算结果。
1 2 3 4 5 6 7 8
| var dv = { 'Additive': ExprAdditive(dv), 'Multitive': ExprMultitive(dv), 'Primary': ExprPrimary(dv), 'Number': ExprNumber(dv), 'Char': next_dv, 'str': str, };
|
定义一个类似链表的结构,每个结构结点为类似dv的结构,每个key为当前字符串位置进行解析的非终止符,不难想到,对于一个长度为m的字符串,假定有n个非终止符,最多有O(mn)个状态,所以能够达到O(n)的时间复杂度。
Packrat对回溯解析本身并没有太大的改动,仅仅是增加了记忆化的查询、添加,就成功达到了O(n)。
2*(3 + 4)的解析结果 。
js解析数值表达式的demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
| function dvAdditive(dv){ if(!('Additive' in dv)){ dv.Additive=ExprAdditive(dv); } return dv.Additive; } function ExprAdditive(dv){ try{ var mul=dvMultitive(dv); if(dvChar(mul.dv).value=='+'){ var add=dvAdditive(dvChar(mul.dv).dv); return { 'value': mul.value+add.value, 'dv': add.dv, }; } else { throw {}; } } catch(e) { return dvMultitive(dv); } } function dvMultitive(dv){ if(!('Multitive' in dv)){ dv.Multitive=ExprMultitive(dv); } return dv.Multitive; } function ExprMultitive(dv){ try{ var primary=dvPrimary(dv); if(dvChar(primary.dv).value=='*'){ var mul=dvMultitive(dvChar(primary.dv).dv); return { 'value': primary.value*mul.value, 'dv': mul.dv, }; } else { throw {}; } } catch(e) { return dvPrimary(dv); } } function dvPrimary(dv){ if(!('Primary' in dv)){ dv.Primary=ExprPrimary(dv); } return dv.Primary; } function ExprPrimary(dv){ try{ if(dvChar(dv).value=='('){ var add=dvAdditive(dvChar(dv).dv); if(dvChar(add.dv).value==')') { return { 'value': add.value, 'dv': dvChar(add.dv).dv, }; } else { throw {}; } } else { throw {}; } } catch(e) { return dvNumber(dv); } } function dvNumber(dv){ if(!('Number' in dv)){ dv.Number=ExprNumber(dv); } return dv.Number; } function ExprNumber(dv){ var value=0; while(!isNaN(dvChar(dv).value)){ value=value*10+parseInt(dvChar(dv).value); dv=dvChar(dv).dv; } return { 'value': value, 'dv': dv, }; } function dvChar(dv){ if(!('Char' in dv)){ dv.Char={ 'value': dv.str[0], 'dv': { 'str': dv.str.slice(1), }, } } return dv.Char; }; function Expr(str){ return ExprAdditive({ 'str': str, }).value; }
|
Ref: https://zhuanlan.zhihu.com/p/25260077