项目的完整代码在 C2j-Compilerhtml
在以前完成了词法分析以后,获得了Token流,那么接下来就是实现语法分析器来输入Token流获得抽象语法树 (Abstract Syntax Tree,AST)。可是在完成这个语法分析器不像词法分析器,直接手撸就行了,仍是须要一些前置的知识。git
这些前置知识在以前的博文都有提起过github
以前的博文目录算法
项目的完整代码在 C2j-Compiler学习
若是咱们把词法分析当作是组合单词,输出单词流,那么语法分析就能够看做是检查这些单词是否是符合语法的过程。在词法分析的时候用正则或者手工比对来验证单词,语法分析则是用上下文无关文法 (context-free grammar,CFG)。code
若一个形式文法 G = (N, Σ, P, S) 的产生式规则都取以下的形式:V -> w,则谓之。其中 V∈N ,w∈(N∪Σ) 。上下文无关文法取名为“上下文无关”的缘由就是由于字符 V 总能够被字符串 w 自由替换,而无需考虑字符 V 出现的上下文。一个形式语言是上下文无关的,若是它是由上下文无关文法生成的*orm
巴科斯范式(英语:Backus Normal Form,BNF)是一种用于表示上下文无关文法的语言。htm
看一个例子:递归
S –> AB A –> aA | ε B –> b | bB
其中S A B叫做非终结符,表明能够经过推导产生新的符号,以前在Token类里定义的也有这些非终结符;a b ε叫做终结符,表示其没法再经过推导产生新的符号了,ε则表示空;token
上面的每一行就是一个产生式规则,也叫推导式,表明了一种非终结符的转移方式;
S就是开始符号。
只有终结符的符号串称为句子 (sentence)。
好比经过这三个产生式,就能够判定bbb符合语法规则。
和以前讲的同样,主要分为自顶向上和自底向下两种
以前在学习的时候稍微记录了一下这几种方法,在这里就不说了
在这里稍微的再说一下此次语法分析使用的方法,LALR(1),它也属于自底向上的分析算法。
一个自底向上的语法分析过程对应为一个输入串构造语法分析书的过程,它从叶子节点开始,经过shift和reduce操做逐渐向上到达根节点
自底向上的语法分析须要一个堆栈来存放解析的符号,例如对于以下语法:
0. statement -> expr 1. expr -> expr + factor 2. | factor 3. factor -> ( expr ) 4. | NUM
来解析1+2
stack | input | |
---|---|---|
null | 1 + 2 | |
NUM | + 2 | 开始读入一个字符,并把对应的token放入解析堆栈,称为shift操做 |
factor | + 2 | 根据语法推导式,factor -> NUM,将NUM出栈,factor入栈,这个操做称为reduce |
expr | + 2 | 这里继续作reduce操做,可是因为语法推导式有两个产生式,因此须要向前看一个符合才能判断是进行shift仍是reduce,也就是语法解析的LA |
expr + | 2 | shift操做 |
expr + NUM | null | shift操做 |
expr + factor | null | 根据fator的产生式进行reduce |
expr | null | reduce操做 |
statement | null | reduce操做 |
此时规约到开始符号,而且输入串也为空,表明语法解析成功
因此实现自底向上的语法解析关键就是识别堆栈上是应该进行shift仍是reduce操做。
因此接下来的任务天然就是构建一个有限状态自动机来可以指导语法分析器来进行操做。
所谓的前置知识其实也就是了解语法分析在干什么,和大概要怎么干。
语法分析就是检查输入的Token流是否是符合语法的过程,而完成这一步骤的语法分析算法,拿自底向上来讲,也就是从叶子节点向上推导成树顶端的过程。
另外个人github博客:https://dejavudwh.cn/