代码及结果:task2
任务一博客:编译原理 | 实验任务一:在计算机上实现PL0语言的编译程序
任务描述:
1.在PL0语言中增加Read和Write语句;
2.修改PL0编译程序, 使得PL0源程序可以使用Read和Write语句, 从文件(或键盘)输入数据,并可以向文件(或屏幕)写数据.
1.在保留字表中增加read和write条目(按ASCII码的顺序)
//type
symbol = (..., readsym, writesym);
//主程序
//按ASCII码顺序
word[1] := 'begin ';
word[2] := 'call ';
word[3] := 'const ';
word[4] := 'do ';
word[5] := 'end ';
word[6] := 'if ';
word[7] := 'odd ';
word[8] := 'procedure ';
word[9] := 'read ';
word[10] := 'then ';
word[11] := 'var ';
word[12] := 'while ';
word[13] := 'write ';
2.在主程序中增加read和write保留字对应的记号
//{常量定义}
const
norw = 13; {保留字的个数}
//主程序
wsym[1] := beginsym;
wsym[2] := callsym;
wsym[3] := constsym;
wsym[4] := dosym;
wsym[5] := endsym;
wsym[6] := ifsym;
wsym[7] := oddsym;
wsym[8] := procsym;
wsym[9] := readsym;
wsym[10] := thensym;
wsym[11] := varsym;
wsym[12] := whilesym;
wsym[13] := writesym;
3.使pl0中的语句可以以read或者write开始
statbegsys := [beginsym, callsym, ifsym, whilesym, writesym, readsym];{表达式开始集合}
4.增加中间代码RED和WRT
//type
fct = (lit, opr, lod, sto, cal, int, jmp, jpc, red, wrt); {functions}
//主程序
//类 PCODE 指令助记符表
mnemonic[lit] := 'LIT ';
mnemonic[opr] := 'OPR ';
mnemonic[lod] := 'LOD ';
mnemonic[sto] := 'STO ';
mnemonic[cal] := 'CAL ';
mnemonic[int] := 'INT ';
mnemonic[jmp] := 'JMP ';
mnemonic[jpc] := 'JPC ';
mnemonic[red] := 'RED ';
mnemonic[wrt] := 'WRT ';
5.增加语法分析程序中statement procedure对保留字read和write的处理
//begin {statement}
{处理read关键字}
else if sym = readsym then
begin
getsym; {获取下一个sym类型}
{read的后面应该接左括号}
if sym = lparen then
begin
{循环开始,直到符号不是逗号}
repeat
getsym;
{如果第一个sym是标识符}
if sym = ident then
begin
i := position(id); {记录当前符号在符号表中的位置}
if i = 0 then error(11) {如果i为0,说明符号表中没有找到id对应的符号,报11错误}
{如果找到了,但该符号的类型不是变量}
else if table[i].kind <> variable then
begin
error(12);
i := 0
end
{如果是变量类型, 生成一条red指令,读取数据}
else with table[i] do
gen(red, lev-level, adr)
end
{如果左括号后面跟的不是标识符,报4号错误}
else error(4);
getsym;
until sym <> comma
end
else error(40);
if sym <> rparen then error(22);
getsym
end
{处理write关键字}
else if sym = writesym then
begin
getsym;
if sym = lparen then
begin
{循环开始,直到读取到的sym不是逗号}
repeat
getsym;
expression([rparen, comma]+fsys);{分析括号中的表达式}
gen(wrt, 0, 0);{生成应wrt, 用来输出内容}
until sym <> comma;
if sym <> rparen then error(22);
getsym
end
else error(40)
end;
6.在interpret解释执行程序中加入对red和wrt指令的输入输出操作,并且取消sto指令中的输出语句
//procedure interpret;
sto :
begin {当前指令是保存变量值(sto, l, a)指令}
s[base(l) + a] := s[t];
//writeln(fout, s[t] : 4);
{根据静态链SL,将栈顶的值存入层差为l,相对地址为a的变量中}
t := t-1 {栈顶指针减1}
end;
...
red :
begin
writeln('please input:');
readln(s[base(l)+a]);{读一行数据,读入到相差l层,层内偏移为a的数据栈中的数据的信息}
end;
wrt :
begin
writeln(fout, s[t]); {输出栈顶的信息}
t := t + 1 {栈顶上移}
end
7.为PL0源程序增加输入输出语句
程序将依次输出z1,q,r,z,(q+r)*z1/z
const m = 7, n = 85;
var x, y, z, q, r, z1;
...
begin
read(x,y);
call multiply;
z1 := z;
read(x,y);
call divide;
read(x,y);
call gcd;
write(z1,q,r,z);
write((q+r)*z1/z);
end.
8.运行结果
START PL/0
21
4
8
4
63
END PL/0
手算一下,可知结果是正确的。
中间代码:
0 const m = 7, n = 85;
1
1 var x, y, z, q, r, z1;
1
1 procedure multiply;
1 var a, b;
2 begin
3 a := x;
5 b := y;
7 z := 0;
9 while b > 0 do
13 begin
13 if odd b then
15 z := z + a;
20 a := 2*a ;
24 b := b/2 ;
28 end
28 end;
2 INT 0 5
3 LOD 1 3
4 STO 0 3
5 LOD 1 4
6 STO 0 4
7 LIT 0 0
8 STO 1 5
9 LOD 0 4
10 LIT 0 0
11 OPR 0 12
12 JPC 0 29
13 LOD 0 4
14 OPR 0 6
15 JPC 0 20
16 LOD 1 5
17 LOD 0 3
18 OPR 0 2
19 STO 1 5
20 LIT 0 2
21 LOD 0 3
22 OPR 0 4
23 STO 0 3
24 LOD 0 4
25 LIT 0 2
26 OPR 0 5
27 STO 0 4
28 JMP 0 9
29 OPR 0 0
30
30 procedure divide;
30 var w;
31 begin
32 r := x;
34 q := 0;
36 w := y;
38 while w <= r do w := 2*w ;
47 while w > y do
51 begin
51 q := 2*q;
55 w := w/2;
59 if w <= r then
62 begin
63 r := r-w;
67 q := q+1
69 end
71 end
71 end;
31 INT 0 4
32 LOD 1 3
33 STO 1 7
34 LIT 0 0
35 STO 1 6
36 LOD 1 4
37 STO 0 3
38 LOD 0 3
39 LOD 1 7
40 OPR 0 13
41 JPC 0 47
42 LIT 0 2
43 LOD 0 3
44 OPR 0 4
45 STO 0 3
46 JMP 0 38
47 LOD 0 3
48 LOD 1 4
49 OPR 0 12
50 JPC 0 72
51 LIT 0 2
52 LOD 1 6
53 OPR 0 4
54 STO 1 6
55 LOD 0 3
56 LIT 0 2
57 OPR 0 5
58 STO 0 3
59 LOD 0 3
60 LOD 1 7
61 OPR 0 13
62 JPC 0 71
63 LOD 1 7
64 LOD 0 3
65 OPR 0 3
66 STO 1 7
67 LOD 1 6
68 LIT 0 1
69 OPR 0 2
70 STO 1 6
71 JMP 0 47
72 OPR 0 0
73
73 procedure gcd;
73 var f, g ;
74 begin
75 f := x;
77 g := y;
79 while f <> g do
83 begin
83 if f < g then g := g-f;
91 if g < f then f := f-g;
99 end;
100 z := f
101 end;
74 INT 0 5
75 LOD 1 3
76 STO 0 3
77 LOD 1 4
78 STO 0 4
79 LOD 0 3
80 LOD 0 4
81 OPR 0 9
82 JPC 0 100
83 LOD 0 3
84 LOD 0 4
85 OPR 0 10
86 JPC 0 91
87 LOD 0 4
88 LOD 0 3
89 OPR 0 3
90 STO 0 4
91 LOD 0 4
92 LOD 0 3
93 OPR 0 10
94 JPC 0 99
95 LOD 0 3
96 LOD 0 4
97 OPR 0 3
98 STO 0 3
99 JMP 0 79
100 LOD 0 3
101 STO 1 5
102 OPR 0 0
103
103 begin
104 read(x,y);
106 call multiply;
107 z1 := z;
109 read(x,y);
111 call divide;
112 read(x,y);
114 call gcd;
115 write(z1,q,r,z);
123 write((q+r)*z1/z);
131 end.
103 INT 0 9
104 RED 0 3
105 RED 0 4
106 CAL 0 2
107 LOD 0 5
108 STO 0 8
109 RED 0 3
110 RED 0 4
111 CAL 0 31
112 RED 0 3
113 RED 0 4
114 CAL 0 74
115 LOD 0 8
116 WRT 0 0
117 LOD 0 6
118 WRT 0 0
119 LOD 0 7
120 WRT 0 0
121 LOD 0 5
122 WRT 0 0
123 LOD 0 6
124 LOD 0 7
125 OPR 0 2
126 LOD 0 8
127 OPR 0 4
128 LOD 0 5
129 OPR 0 5
130 WRT 0 0
131 OPR 0 0
9.写个程序验证一下
(test1)
(test2)
结果正确。