Classic Expression Grammar :
0.Goal → Expr1.Assign → ident = Expr; //making Assign node
2.Expr → Expr + Term //making plus node3. | Expr - Term //making minus node
4. | Term
5.Term → Term * Factor //making Mult node
6. | Term / Factor //making div node
7. | Factor
8.Factor → ident //making ident node
9. | num //making num node
10. | ( Expr )
x = a * 3 + b ;
parsing tree
AST目的生成代码 所以本质上就是在parsing tree上剔除了多余的信息 但保留了原有的token信息和结构
AST:
load a → r1
load 3 → r2
Mult r1,r2 → r3
load b → r4
Add r3,r4 → r5
store r5 → x
yacc(Yet Another Compiler Compiler),是一个经典的生成语法分析器的工具。yacc生成的编译器主要是用C语言写成的语法解析器(Parser),需要与词法解析器Lex一起使用,再把两部份产生出来的C程序一并编译
GNU Bison 是一个通用的解析器生成器,它可以将注释的无上下文语法转换为使用 LALR (1) 解析表的确定性 LR 或广义 LR (GLR) 解析器。Bison 还可以生成 IELR (1) 或规范 LR (1) 解析表。一旦您熟练使用 Bison,您可以使用它开发广泛的语言解析器,从简单的桌面计算器中使用的解析器到复杂的编程语言。
Bison 与 Yacc 向上兼容:所有正确编写的 Yacc 语法都可以在 Bison 上正常使用。熟悉 Yacc 的任何人都应该可以轻松使用 Bison。
说白了 Yacc和Bison做的工作就是从一个语法和相关行为 即 生成了closure ActionTable GotoTable 并最终生成了c code
所以他们是comilper-compiler 他们编译语法 生成的c code成了编译器的一个前端部分
在Yacc和Bison中 使用$$表达左边 $num表达右边 比如上面的第五行 表示为
$$ → $1 $2 $3
$$ = MakingMultNode($1,$3)
这一行只是把Term替换成Factor 不生成新的node
$$ = $1
$本质上一个指向node的指针
MakingMultNode(Node * n1, Node * n2)
createNewNode n
n.left = n1
n.right = n2
return &n
也就是说 每次在LR(1)文法中执行reduce 7的时候 执行的其实是$$ = $1来生成AST
对于8 9 行这种置换成terminal的
MakingIdentNode(token)
MakingNumNode(num)
cost(add) = 1
cost(sub) = 1
cost(mult) = 3
cost(div) = 7
cost(loadident) = 4
cost(store) = 3
cost(loadnum) = 1
0.Goal → Expr //$$ = $1
1.Assign → ident = Expr; //$$ = $3 + cost(store)
2.Expr → Expr + Term //$$ =$1 +cost(add) + $33. | Expr - Term //$$ =$1 +cost(sub) + $3
4. | Term //$$ = $1
5.Term → Term * Factor //$$ = $1 +cost(mult) + $3
6. | Term / Factor //$$ = $1 + cost(div) + $3
7. | Factor //$$ = $1
8.Factor → ident //$$ = cost(loadident)
9. | num //$$ = cost(loadnum)
10. | ( Expr ) //$$ = $2
可以看到 cost of ident 是4 置换到Factor并不会再次cost 它们之间只是链接link的关系 最后传到Term也是4 同理num传到Factor是cost 1
最后Term作为$1 mult作为$2 Factor作为$3 它们的cost分别为 4 3 1 加起来是8 传给上面的$$
其他分支同理