怎么写一个js解释器( 二 )


我们不必将其想得过于高深!我们想想文本处理有什么工具?Regular expression!如今的编程语言 , 有哪个不支持regular expression呢?同样的 , 如今的程序员 , 哪个不用使用(没在代码里使用)regular expression呢?Regular expression也是一种文本处理工具 , 也是个DSL , 只不过 , 它处理不了复杂的语法 。我们知道 , 自动化理论(automata theory)里 , 有FSA(Finite State Automata)和PDA(PushDown Automata) , 前者可以用regular expression表述 , 而后者可以处理CFG(Context Free Grammar) 。
而CFG便是flex/bison要处理的对象!遗憾的是 , 大部分语言都没有内置对CFG的处理 , 一旦文本处理的复杂度超过了regular expression可以表述的复杂度 , 我们便无能为力 。举个例子 , 如果要你解析这样一段文本 , 你该怎么做?用regular expression自然是无能为力的 , 一个字符一个字符读入 , 按单词切分token , 然后处理大括号 , 分号这样的语法 , 你相当于自己写了个解析器 , 很难保证高效和可扩展 。
所以这种时候我们需要求助于第三方的flex/bison , 或者类似的工具 。flex是lex演进过来的 , 做词法分析 。
所谓的词法分析 , 说白了就是把文本切成一个个你认识的语法单元 , 比如上图里 , server 就是这样一个语法单元 , 我们管这个单元叫token 。在flex里 , 我们可以这样描述上面文本里出现的token:接下来就是语法分析的环节了 。
语法分析做的是pattern matching的事情 , 和regular expression的pattern matching不同 , 它允许你定义一系列可递归的规则 。标准的unix下 , 语法分析的工具是bison , 我们看看上述文本如何使用bison解析:其主体代码还是很清晰的 , 一个 server {…} 就用 SERVER OP({) exp_list CP(}) 这样一条规则匹配 , 当解析器碰到 exp_list 这样一个它无法认识的内容时 , 它会寻找名为 exp_list 的规则继续匹配 。
如果你经常使用函数式编程语言 , 你会发现 , 这种规则的撰写似曾相识 。bison使用的描述规则的语法是BNF的变体 。
以下是编译和执行的结果 , 作为展示 , 我仅仅把语法树中我感兴趣的内容打印出来了:从上面的编译过程里 , 你可以看到 , flex/bison是一个C语言的DSL 。因此 , 你可以在处理词法和语法的过程中嵌入C代码 , 处理(transform)你需要的结果 。
DSL和宿主语言之间必然要有一些约定俗成的接口 , 这也是 yytext,yyparser,yyterminate,yylex 等等变量和方法存在的原因 。它们看起来很奇怪 , 但如果你以一颗看待DSL的心去看待它们 , 变不那么别扭了 。
(二) 可惜 , 如今大部分文艺青年都已经不用C了 —— 虽说很多语言都提供了对C的FFI(Foreign Function Interface) , 比如Python , 你可以用flex/bison生成一个parser , 然后用FFI包装 。然而 , 这毕竟很麻烦 , 如果我能用我喜爱的语言做parser , 该多方便?嗯 , 有需求的地方便有产品 , 看这个wiki page吧:中的js代码中怎么写一个计算器的加减乘除<meta ; charset=utf-8" /> <body>