编译原理 | 实验任务一:在计算机上实现PL0语言的编译程序

代码及结果:task1

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


1 找到PASCAL编译系统

下载安装free pascal,设置环境变量,然后用vscode编辑。
参考资料:在windows命令行下编译运行Pascal程序


2 在PASCAL系统上运行PL0编译程序,需要对PL0编译程序作一些修改、调试

1.改格式(缩进、注释)

2.符号修改

~ -> not//~这个符号打不出来,反正就是非的意思

//procedure和object在pascal中是关键字,所以分别使用proceduree和objectt替代
object -> objectt;
procedure -> proceduree;

cc—1 -> cc-1;
↑ -> ^;
≤ -> <=;
≠ -> <>

3. 注释掉不必要的(其实是报错的)语句,如

在这里插入图片描述
直接注释掉(或删掉)
在这里插入图片描述

4.标号99原来是用于退出程序的,由于不支持跨过程的跳转,所以直接退出
在这里插入图片描述

//procedure  gen(x : fct; y, z : integer);
    	if cx > cxmax then 
        begin 
            write('PROGRAM TOO LONG'); 
            exit
            //goto 99
        end;
//procedure  getch ; 

        if eof(fin) then {如果已到文件尾}
        begin
            writeln('PROGRAM INCOMPLETE'); 
            exit;
            //goto 99
        end;

//主程序
//99 : writeln
    writeln;

5.现在暂时没有错误了
在这里插入图片描述


3 建立输入文件和输出文件

在输入文件中存放PL0源程序
在这里插入图片描述
在输出文件中存放PL0源程序被编译后产生的中间代码和运行数据
在这里插入图片描述


4 通过输入文件输入PL0源程序,在输出文件中产生源程序的中间代码, 然后运行该中间代码, 在输出文件中产生运行数据

1.增加变量fin和fout,以命令行形式读取和写入文件
在这里插入图片描述

//{全局变量定义}
//var
fin : text;       {源代码文件}
fout : text;      {输出文件}
...

begin  {主程序}
    assign(fin,paramstr(1));
    assign(fout,paramstr(2));	{将命令行参数str变量赋值给文件变量}
    reset(fin);
    rewrite(fout);	{打开输入输出文件}
    ...
    //99 : writeln
    writeln;
    close(fin);
    close(fout);

2.exit时关闭文件

//getch
		begin
            writeln('PROGRAM INCOMPLETE'); 
            close(fin);
            close(fout);
            exit;
            //goto 99
        end;

//gen
		begin 
            write('PROGRAM TOO LONG'); 
            close(fin);
            close(fout);
            exit
            //goto 99
        end;

3.将所有input改成fin,有read的地方都改成从fin文件读入,有write的地方都改成写到fout文件:

//getch
	if eof(fin) then {如果已到文件尾}
	...
	while not eoln(fin) do {如果不是行末}
        begin
            ll := ll + 1; {将行缓冲区的长度+1}
            read(fin, ch); {从源文件中读取一个字符到ch中}
            write(fout, ch);{输出ch到输出文件中}
            line[ll] := ch  {把这个字符放到当前行末尾}
        end;
        writeln(fout); {换行}
        readln(fin);{从源文件下一行开始读取}
        ll := ll + 1; {将行缓冲区的长度+1}
        line[ll] := ' ' { process end-line }	{行数组最后一个元素为空格}
    end;

//gen
	if cx > cxmax then 
        begin 
            write(fout, 'PROGRAM TOO LONG'); 
            close(fin);
            close(fout);
            exit
            //goto 99
        end;

//listcode
with code[i] do {打印第i条代码}
        {i: 代码序号; mnemonic[f]: 功能码的字符串; l: 相对层号(层差); a: 相对地址或运算号码} 
        {格式化输出}
        writeln(fout, i:5, mnemonic[f]:7, l:3, a:5)

//interpret
begin  
    writeln(fout, 'START PL/0');
...
sto :
	begin {当前指令是保存变量值(sto, l, a)指令}
	    s[base(l) + a] := s[t]; 
	    writeln(fout, s[t] : 4); 
	    {根据静态链SL,将栈顶的值存入层差为l,相对地址为a的变量中}
	    t := t-1 {栈顶指针减1}
	end;
...
write(fout, 'END PL/0');
end {interpret};

4.在getsym词法分析程序中增加对">","<",">=","<=","<>"记号的识别

    {处理'<'}
    else if ch = '<' then 
    begin	
        getch;	
        {'<='}
        if ch = '=' then 
        begin
            sym := leq;	{表示小于等于}
            getch	{读下一个字符}
        end
        {'<>'}
        else if ch = '>' then 
        begin
            sym := neq;	{表示不等于}
            getch
        end
        {'<'}
        else sym := lss	{表示小于}
    end

    {处理'<'}
    else if ch = '>' then 
    begin	
        getch;	
        {'>='}
        if ch = '=' then 
        begin
            sym := geq;	{表示大于等于}
            getch	{读下一个字符}
        end
        {'>'}
        else sym := gtr	{表示大于}
    end

5.保留字表改为小写字母,所有字符都预留的相同的长度

    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] := 'then         ';
    word[10] := 'var          ';
    word[11] := 'while        ';

getsym里面的‘A’…'Z’也改成‘a’…‘z’:

    {标识符或保留字} 
    if ch in ['a'..'z'] then 
    begin 
        k := 0;
        repeat {处理字母开头的字母﹑数字串}
            if k < al then
                begin 
                    k:= k + 1; 
                    a[k] := ch
                end;
            getch
        until  not (ch in ['a'..'z', '0'..'9']);

6.第一步基本完成:
在这里插入图片描述

7.输出结果,包括:

  • 输入pl0源文件的字符
  • 生成的中间代码(栈机器代码)
  • 数据栈顶的运行结果(START PL/0和END PL/0之间的interpret,其中sto指令会输出栈顶数据)
    0 const m = 7, n = 85;
    1 
    1 var x, y, z, q, r;
    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   48
    8  STO    1    5
    9  LOD    0    4
   10  LIT    0   48
   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   50
   21  LOD    0    3
   22  OPR    0    4
   23  STO    0    3
   24  LOD    0    4
   25  LIT    0   50
   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   48
   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   50
   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   50
   52  LOD    1    6
   53  OPR    0    4
   54  STO    1    6
   55  LOD    0    3
   56  LIT    0   50
   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   49
   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     x := m;  
  106     y := n;  
  108     call multiply;
  109     x := 25;  
  111     y:= 3;  
  113     call divide;
  114     x := 84;  
  116     y := 36;  
  118     call gcd;
  119 end.
  103  INT    0    8
  104  LIT    0   55
  105  STO    0    3
  106  LIT    0  613
  107  STO    0    4
  108  CAL    0    2
  109  LIT    0  553
  110  STO    0    3
  111  LIT    0   51
  112  STO    0    4
  113  CAL    0   31
  114  LIT    0  612
  115  STO    0    3
  116  LIT    0  564
  117  STO    0    4
  118  CAL    0   74
  119  OPR    0    0
START PL/0
  55
 613
  55
 613
  48
 103
2750
  12
 553
  51
 553
  48
  51
2550
2400
  51
 502
2449
 612
 564
 612
 564
  48
 516
 468
 420
 372
 324
 276
 228
 180
 132
  84
  36
  12
  24
  12
  12
END PL/0

8.emmm??发现这个结果不对,LIT的第二项怎么那么大呢?找了好久,发现是getsym判断数字里面写错了:
在这里插入图片描述
应该把ord(0)改成ord(‘0’):

//getsym

    else if ch in ['0'..'9'] then
    begin
        k := 0;  
        num := 0;  
        sym := number; {当前记号sym为数字}
        repeat {计算数字串的值}
            num := 10*num + (ord(ch)-ord('0'));
            {ord(ch)和ord(0)是ch和0ASCII码中的序号}
            k := k + 1;  
            getch;
        until not(ch in ['0'..'9']);
        {当前数字串的长度超过上界,则报告错误}
        if k > nmax then error(30)
    end 

参考资料

hansenbeast的github
xwy27的github

猜你喜欢

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