编制一个能够进行语法分析并生成三地址代码的微型编译程序。1、考虑给定的文法,消除左递归,提取左因子; 2、编制并化简语法图;3、编制各个递归子程序的算法; 4、编制各个递归子程序的函数; 5、连接实验一的词法分析函数scan( ),进行测试6、设计三地址代码生成的数据结构和算法.输入示例:while (a3+15)>0xa do if x2 = 07 then while y<z do y =x * y / z;7、将各个递归子程序函数改写为代码生成函数 8、编制测试程序(main函数)
时间: 2024-03-25 08:36:30 浏览: 75
好的,我会逐一回答你的问题。
1. 消除左递归,提取左因子
给定的文法如下:
```
S -> if E then S | if E then S else S | while E do S | { L }
L -> S | L S
E -> E + T | E - T | T
T -> T * F | T / F | F
F -> ( E ) | id | num
```
对于该文法,我们可以进行左递归消除和左因子提取得到如下文法:
```
S -> if E then S else S | if E then S | while E do S | { L }
L -> S L'
L' -> ε | L
E -> T E'
E' -> + T E' | - T E' | ε
T -> F T'
T' -> * F T' | / F T' | ε
F -> ( E ) | id | num
```
2. 编制并化简语法图
为了更好地理解语法,可以画出其语法图,如下所示:
```
S
/ | | \
if E th S wh E do S
\ | | /
if E th S el S
|
S
|
L
|
S
```
3. 编制各个递归子程序的算法
- S → if E then S else S
```
algorithm if_stmt():
match('if')
E()
match('then')
S()
match('else')
S()
```
- S → if E then S
```
algorithm if_stmt():
match('if')
E()
match('then')
S()
```
- S → while E do S
```
algorithm while_stmt():
match('while')
E()
match('do')
S()
```
- S → { L }
```
algorithm block_stmt():
match('{')
L()
match('}')
```
- L → S L'
```
algorithm stmt_list():
S()
L'()
```
- L' → ε
```
algorithm stmt_list_tail():
return
```
- L' → L
```
algorithm stmt_list_tail():
L()
```
- E → T E'
```
algorithm expr():
T()
E'()
```
- E' → + T E'
```
algorithm add_expr():
match('+')
T()
E'()
```
- E' → - T E'
```
algorithm sub_expr():
match('-')
T()
E'()
```
- E' → ε
```
algorithm expr_tail():
return
```
- T → F T'
```
algorithm term():
F()
T'()
```
- T' → * F T'
```
algorithm mul_term():
match('*')
F()
T'()
```
- T' → / F T'
```
algorithm div_term():
match('/')
F()
T'()
```
- T' → ε
```
algorithm term_tail():
return
```
- F → ( E )
```
algorithm paren_expr():
match('(')
E()
match(')')
```
- F → id
```
algorithm id():
match('id')
```
- F → num
```
algorithm num():
match('num')
```
4. 编制各个递归子程序的函数
为了实现上述算法,我们需要编写相应的递归子程序函数。这里只是给出伪代码,具体的实现需要根据具体的语言来实现。
```
function if_stmt():
match('if')
E()
match('then')
S()
if look_ahead() == 'else':
match('else')
S()
function while_stmt():
match('while')
E()
match('do')
S()
function block_stmt():
match('{')
L()
match('}')
function stmt_list():
S()
stmt_list_tail()
function stmt_list_tail():
if look_ahead() != '}':
L()
function expr():
T()
expr_tail()
function expr_tail():
if look_ahead() == '+':
match('+')
T()
expr_tail()
else if look_ahead() == '-':
match('-')
T()
expr_tail()
function term():
F()
term_tail()
function term_tail():
if look_ahead() == '*':
match('*')
F()
term_tail()
else if look_ahead() == '/':
match('/')
F()
term_tail()
function paren_expr():
match('(')
E()
match(')')
function id():
match('id')
function num():
match('num')
```
5. 连接实验一的词法分析函数scan(),进行测试
在编写测试程序前,我们需要先连接实验一的词法分析函数scan(),以便对输入的源代码进行词法分析。
```
function match(token):
if look_ahead() == token:
scan()
else:
error()
function look_ahead():
return scan()
function error():
// 抛出异常或打印错误信息等
function main():
scan()
S()
```
6. 设计三地址代码生成的数据结构和算法
为了生成三地址代码,我们可以使用一个三元组来表示每个指令,其中包含操作符和操作数。具体的代码如下:
```
class ThreeAddrCode:
def __init__(self, op, arg1, arg2, result):
self.op = op
self.arg1 = arg1
self.arg2 = arg2
self.result = result
def __str__(self):
return f"{self.result} = {self.arg1} {self.op} {self.arg2}"
```
生成三地址代码的算法可以通过在语法分析树上遍历来实现,对于树中的每个节点,我们需要生成相应的三地址代码。
7. 将各个递归子程序函数改写为代码生成函数
为了实现三地址代码生成,我们可以将每个递归子程序函数改写为代码生成函数。这里只是给出伪代码,具体的实现需要根据具体的语言来实现。
```
function if_stmt():
E()
t = new_temp()
emit(f"if {t} == 0 goto L1")
S()
emit(f"L1: nop")
if look_ahead() == 'else':
match('else')
S()
emit(f"L2: nop")
function while_stmt():
emit(f"L1: nop")
E()
t = new_temp()
emit(f"if {t} == 0 goto L2")
S()
emit(f"goto L1")
emit(f"L2: nop")
function block_stmt():
L()
function stmt_list():
S()
stmt_list_tail()
function stmt_list_tail():
if look_ahead() != '}':
L()
function expr():
T()
expr_tail()
function expr_tail():
if look_ahead() == '+':
match('+')
T()
t = new_temp()
emit(f"{t} = {t-1} + {t}")
expr_tail()
else if look_ahead() == '-':
match('-')
T()
t = new_temp()
emit(f"{t} = {t-1} - {t}")
expr_tail()
function term():
F()
term_tail()
function term_tail():
if look_ahead() == '*':
match('*')
F()
t = new_temp()
emit(f"{t} = {t-1} * {t}")
term_tail()
else if look_ahead() == '/':
match('/')
F()
t = new_temp()
emit(f"{t} = {t-1} / {t}")
term_tail()
function paren_expr():
match('(')
E()
match(')')
function id():
match('id')
function num():
match('num')
t = new_temp()
emit(f"{t} = {prev_token()}")
```
其中,new_temp() 函数用于生成新的临时变量,prev_token() 函数返回上一个扫描到的标记。
8. 编制测试程序(main函数)
最后,我们可以编写一个测试程序来测试我们的编译器是否可以正确地生成三地址代码。
```
function main():
scan()
S()
for code in three_addr_codes:
print(code)
```
注意,three_addr_codes 是一个列表,用于保存生成的三地址代码。在每个代码生成函数中,我们需要使用 emit() 函数将生成的三地址代码添加到该列表中。
希望这些信息对你有所帮助!
阅读全文