自己写个JavaScript parser (分析器)系列 (1)
注:参考自http://dukeland.hk,本博客系列内容为自己解读的成果,以备将来自己回顾使用。所有版权归原作者所有,如有任何问题,请联系原作者。
写编程语言的分析器是一个较为困难的工作。按常规思路,遇到困难的工作我们首先要做的就是把它分解成数个模块,便于我们化解和定位问题,然后各个击破。那么为了完成编程语言的分析器:
1(字):将代码按字符读入,过滤掉空格、换行符、注释等内容。
2(词):在字符读入的过程中就将这些字符组装成编程语言关键字。比如不间断地读入了'v', 'a', 'r',那么就形成了'var’关键字,可以先行保存,以待后续分析使用。
3(句):关键字读入了之后,还需要根据一些符号或其它方式“断句”,把一堆关键字切分成一个个的语句。比如用‘\r\n'切或者用’;'切等等。当然,多个句子可以组成一个代码块,也需要在这里完成。经过这样的整理,读入的关键字之间的亲疏关系才有了依据。
4(意):只有到了这个层面,才真正涉及到大量的编程语言的语义规范。比如一个加减乘除四则运算的语句,又如用正则表达式替换字符串的语句等等。
*5(译):如果是编译器,在了解了输入代码的意思后,还需要把这个意思再翻译成另一种可用的语言来执行。
难点:
1(字):单字符读入不存在什么难点;
2(词):
a,因为读词是在读字符的基础上进行的,所以需要一个状态机来指示,什么时候是一个词的开始,什么时候是一个词的结束。
b,遇到二义性的词,还需要往前或往后多读一个词,看看这个词所在的上下文来做出判断。比如关键字'/',遇到它你不能判断这是一个除法符号还是行注释的第一个字符,需要继续往下读一个才能做出判断。类似的有'+'和'++',‘*’和‘/*’等。
3(句):断句不难,但是需要考虑以何种存储方式保存同属于一个语句或一个代码块的词,这样后续的语义分析才会更加容易处理。
4(意):
a,四则运算中运算符优先级问题。
b,语法规则宽松的语言里,同一个意义多种表达的问题。比如JS中,var a; var b; 和 var a, b;是等同的。function f() {} 和 f = function () {}也是等同的。
c,JS中变量类型的问题。
d,以何种方式存储语义分析结果的问题。
*5(译):如果第四步翻的好,到这里译起来就没多大问题了。以为这里是用另一种语言来译当前的语言,会涉及到你用来译的这种语言的技巧问题。往往在这里还会对第四步形成反馈,比如该怎么去翻才能更快速的译出来,这就是所谓的编译器优化问题了。