编译原理 | 实验任务二:扩展Read和Write语句

代码及结果: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)
在这里插入图片描述
在这里插入图片描述

结果正确。


参考资料

hansenbeast的github
xwy27的github

猜你喜欢

转载自blog.csdn.net/cat_xing/article/details/85257676