本节内容依旧非常抽象,因此这里给出三道完整例题 ,对应以下3个重要知识点/题型:
1.0「自顶向下」构造LL(1)翻译程序
2.0「自底向上」构造LR(1)语义栈
3.0 「自顶向下/自底向上」中缀转后缀
▍1.0「自顶向下」构造LL(1)翻译程序
下面的翻译模式可用于将二进制无符号小数转化为十进制小数。请构造相应的递归下降翻译程序:
N → p {S.f := 1} S {print(S.val)} |
S → {B.f := S.f} B {S₁.f := S.f + 1} S₁ {S.val := B.val + S₁.val} |
S → ε {S.val := 0} |
B → 0 {B.val := 0} |
B → 1 {B.val := 2 ^ (-B₁.f)} |
先说明一个MatchToken函数:
// MatchToken用于判别【正在处理的终结符】与【当前扫描的输入符号】是否匹配
void MatchToken(int expected) {
if(lookahead != excepted) { // lookahead为当前扫描的输入符号
printf("语法错误!");
exit(0); // 若不匹配:报告出错,跳出
} else {
lookahead = getToken(); // 若匹配:则向词法分析程序申请读入下一个输入符号
}
}
下面,为每个非终结符构造翻译程序:
>>> 小技巧(>_<):
>>> 写解析非终结符的函数时,"综合属性"没有自变量;"继承属性"才有自变量
void ParseN(){
MatchToken('p');
Sf := 1;
Sv := ParseS(Sf);
print(Sv);
}
float ParseS(int f){
if(lookahead == '0' || lookahead == '1') {
Bf := f;
Bv := parseB(Bf);
S1f := f + 1;
S1v := parseS(S1f);
Sv := Bv + S1v;
} else if(lookahead == '#') {
Sv := 0;
} else {
printf("语法错误!");
exit(0);
}
return Sv;
}
float ParseB(int f){
if(lookahead == '0'){
MatchToken('0');
Bv := 0;
} else if(lookahead == '1'){
MatchToken('1');
Bv := 2 ^ (-f);
} else {
printf("语法错误!");
exit(0);
}
return Bv;
}
▍2.0「自底向上」构造LR(1)语义栈
下面给出G[S]文法及其LR分析表,请写出其匹配(a,(a))#
的语义栈(栈+语义栈+串+串)
0 | S’ → S | |
---|---|---|
1 | S →( L ) | {S.num := L.num + 1;} |
2 | S → a | {S.num := 0;} |
3 | L → L₁, S | {L.num := L₁.num + S.num;} |
4 | L → S | {L.num := S.num} |
a | , | ( | ) | # | S | L | |
---|---|---|---|---|---|---|---|
0 | s3 | s2 | 1 | ||||
1 | acc | ||||||
2 | s3 | s2 | 5 | 4 | |||
3 | r2 | r2 | r2 | ||||
4 | s7 | s6 | |||||
5 | r4 | r4 | |||||
6 | r1 | r1 | r1 | ||||
7 | s3 | s2 | 8 | ||||
8 | r3 | r3 |
语义栈(其实就是在LR分析栈的基础上又加了一个栈,表示语义)
栈 | 语义栈 | 串 | 串 | 操作 |
---|---|---|---|---|
0 | - | |||
02 | - - | |||
023 | - - - | |||
025 | - - 0 | |||
024 | - - 0 | |||
0247 | - - 0 - | |||
02472 | - - 0 - - | |||
024723 | - - 0 - - - | |||
024725 | - - 0 - - 0 | |||
024724 | - - 0 - - 0 | |||
0247246 | - - 0 - - 0 - | |||
02478 | - - 0 - 1 | |||
024 | - - 1 | |||
0246 | - - 1 - | |||
01 | - 2 | Accept |
▍3.1「自顶向下」中缀转后缀
▍3.2「自底向上」中缀转后缀
E → TR |
R → +TR₁ |
R → -TR₁ |
R → ε |
T → num |
将3 + 4
转换为3 4 +
>>> 自顶向下(左图):增加枝叶,增加的枝叶就是动作
>>> 自底向上(右图):增加非终结符,由非终结符生成'ε'和动作
本文题目引用/改编自: 《编译原理(第三版)》清华大学出版社
对应页码/题号(按顺序): P175 例7.9,P190 T5,原创
E N D END END