zoukankan      html  css  js  c++  java
  • PL/0与Pascal-S编译器程序详细注释

      学校编译课的作业之一,要求阅读两个较为简单的编译器的代码并做注释, 个人感觉是一次挺有意义的锻炼, 将自己的心得分享出来与一同在进步的同学们分享. 今后有时间再做进一步的更新和总结,其中可能有不少错误,也请各位大佬不吝指正. 代码可以通过使用Lazarus等pascal环境执行。

    源码仓库:https://github.com/luxiaodou/Pascal-S-and-PL0-complier-comments

    PL0编译器源码

    PL0语言是Pascal的一个子集,编译器也比较简单,逐行注释

    program pl0 ;  { version 1.0 oct.1989 }
    { PL/0 compiler with code generation }    
    {    comment by Song Lu
        Department of Computer Science&Engineering BUAA,Nov.2016
    }
    {常量定义}
    const norw = 13;          { no. of reserved words }    {保留字的数目}
          txmax = 100;        { length of identifier table }    {符号表长度}
          nmax = 14;          { max. no. of digits in numbers }    {数字的最大长度}
          al = 10;            { length of identifiers }    {标识符的最大长度}
          amax = 2047;        { maximum address }    {相对地址最大值}
          levmax = 3;         { maximum depth of block nesting }     {最大嵌套层数}
          cxmax = 200;        { size of code array }    {生成目标代码数组最大长度}
    
    {类型变量定义}
    type symbol =
         ( nul,ident,number,plus,minus,times,slash,oddsym,eql,neq,lss,
           leq,gtr,geq,lparen,rparen,comma,semicolon,period,becomes,
           beginsym,endsym,ifsym,thensym,whilesym,dosym,callsym,constsym,
           varsym,procsym,readsym,writesym );    {symbol的宏定义为一个枚举}
         alfa = packed array[1..al] of char;    {alfa宏定义为含有a1个元素的合并数组,为标识符的类型}
         objecttyp = (constant,variable,prosedure);        {objecttyp的宏定义为一个枚举}
         symset = set of symbol;    {symset为symbol的集合}
         fct = ( lit,opr,lod,sto,cal,int,jmp,jpc,red,wrt ); { functions }    {fct为一个枚举,其实是PCODE的各条指令}
         instruction = packed record    {instruction声明为一个记录类型}
                         f : fct;            { function code }    {函数代码}
                         l : 0..levmax;      { level }    {嵌套层次}
                         a : 0..amax;        { displacement address }    {相对位移地址}
                       end;
                      {   lit 0, a : load constant a    读取常量a到数据栈栈顶
                          opr 0, a : execute operation a    执行a运算
                          lod l, a : load variable l,a    读取变量放到数据栈栈顶,变量的相对地址为a,层次差为1
                          sto l, a : store variable l,a    将数据栈栈顶内容存入变量,变量的相对地址为a,层次差为1
                          cal l, a : call procedure a at level l    调用过程,过程入口指令为a,层次差为1
                          int 0, a : increment t-register by a    数据栈栈顶指针增加a
                          jmp 0, a : jump to a    无条件跳转到指令地址a
                          jpc 0, a : jump conditional to a    条件转移到指令地址a
                          red l, a : read variable l,a    读数据并存入变量,
                          wrt 0, 0 : write stack-top    将栈顶内容输出
                      }
    
    {全局变量定义}
    var   ch : char;      { last character read }    {最后读出的字符}
          sym: symbol;    { last symbol read }    {最近识别出来符号类型}
          id : alfa;      { last identifier read }    {最后读出来的识别符}
          num: integer;   { last number read }    {最后读出来的数字}
          cc : integer;   { character count }    {行缓冲区指针}
          ll : integer;   { line length }    {行缓冲区长度}
          kk,err: integer;    
          cx : integer;   { code allocation index }    {代码分配指针}
          line: array[1..81] of char;    {缓冲一行代码}
          a : alfa;    {用来存储symbol的变量}
          code : array[0..cxmax] of instruction;    {用来保存编译后的PCODE代码,最大容量为cxmax}
          word : array[1..norw] of alfa;    {保留字表}
          wsym : array[1..norw] of symbol;    {保留字表中每个保留字对应的symbol类型}
          ssym : array[char] of symbol;        {符号对应的symbol类型}
          mnemonic : array[fct] of    {助记符}
                       packed array[1..5] of char;
          declbegsys, statbegsys, facbegsys : symset;    {声明开始,表达式开始、项开始的符号集合}
          table : array[0..txmax] of    {定义符号表}
                    record    {表中的元素类型是记录类型}
                      name : alfa;    {元素名}
                      case kind: objecttyp of    {根据符号的类型保存相应的信息}
                        constant : (val:integer );    {如果是常量,val中保存常量的值}
                        variable,prosedure: (level,adr: integer )    {如果是变量或过程,保存存放层数和偏移地址}
                    end;
          fin : text;     { source program file }    {源代码文件}
          sfile: string;  { source program file name }    {源程序文件名}
    
    procedure error( n : integer );  {错误处理程序}
      begin
        writeln( '****', ' ':cc-1, '^', n:2 );    {报错提示信息,'^'指向出错位置,并提示错误类型}
        err := err+1 {错误次数+1}
      end; { error }
    
    procedure getsym;    {词法分析程序}
    var i,j,k : integer;    {声明计数变量}
    procedure getch;
        begin
          if cc = ll  { get character to end of line }    {如果读完了一行(行指针与该行长度相等)}
          then begin { read next line }    {开始读取下一行}
                 if eof(fin)    {如果到达文件末尾}
                 then begin
                       writeln('program incomplete');    {报错}
                       close(fin);    {关闭文件}
                       exit;    {退出}
                      end;
                 ll := 0;    {将行长度重置}
                 cc := 0;    {将行指针重置}
                 write(cx:4,' ');  { print code address }    {输出代码地址,宽度为4}
                 while not eoln(fin) do    {当没有到行末时}
                   begin
                     ll := ll+1;    {将行缓冲区的长度+1}
                     read(fin,ch);    {从文件中读取一个字符到ch中}
                     write(ch);    {控制台输出ch}
                     line[ll] := ch    {把这个字符放到当前行末尾}
                   end;
                 writeln;    {换行}
                 readln(fin);    {源文件读取从下一行开始}
                 ll := ll+1;    {行长度计数加一}
                 line[ll] := ' ' { process end-line }    {行数组最后一个元素为空格}
               end;
          cc := cc+1;    {行指针+1}
          ch := line[cc]    {读取下一个字符,将字符放进全局变量ch}
        end; { getch }
      begin { procedure getsym;   }    {标识符识别开始}
        while ch = ' ' do    {去除空字符}
          getch;    {调用上面的getch过程}
        if ch in ['a'..'z']    {如果识别到字母,那么有可能是保留字或标识符}
        then begin  { identifier of reserved word }    {开始识别}
               k := 0;    {标识符指针置零,这个量用来统计标识符长度}
               repeat    {循环}
                 if k < al    {如果k的大小小于标识符的最大长度}
                 then begin
                       k := k+1;    {k++}
                       a[k] := ch    {将ch写入标识符暂存变量a}
                     end;
                 getch    {获取下一个字符}
               until not( ch in ['a'..'z','0'..'9']);    {直到读出的不是数字或字母的时候,标识符结束}
               if k >= kk        { kk : last identifier length }    {若k比kk大}
               then kk := k    {kk记录当前标识符的长度k}
               else repeat    {循环}
                      a[kk] := ' ';        {标识符最后一位为空格}
                      kk := kk-1    {k--}
                   until kk = k;    {直到kk等于当前标识符的长度,这样做的意义是防止上一个标识符存在a中的内容影响到当前标识符,比如上一个标识符为“qwerty”,现在的标识符为“abcd”,如果不清后几位则a中会保存"abcdty",这显然是错误的}
               id := a;    {id保存标识符名}
               i := 1;    {i指向第一个保留字}
               j := norw;   { binary search reserved word table }    {二分查找保留字表,将j设为保留字的最大数目}
               repeat
                 k := (i+j) div 2;    {再次用到k,但这里只是作为二分查找的中间变量}
                 if id <= word[k]    {若当前标识符小于或等于保留字表中的第k个,这里的判断依据的是字典序,那么我们可以推测符号表是按照字典序保存的}
                 then j := k-1;        {j = k-1}
                 if id >= word[k]    {若当前标识符大于或等于保留字表中的第k个}
                 then i := k+1        {i = k+1}
               until i > j;        {查找结束条件}
               if i-1 > j    {找到了}
               then sym := wsym[k]    {将找到的保留字类型赋给sym}
               else sym := ident    {未找到则把sym置为ident类型,表示是标识符}
             end
        else if ch in ['0'..'9']    {如果字符是数字}
             then begin  { number }
                    k := 0;    {这里的k用来记录数字的位数}
                    num := 0;    {num保存数字}
                    sym := number;    {将标识符设置为数字}
                    repeat    {循环开始}
                      num := 10*num+(ord(ch)-ord('0'));    {将数字字符转换为数字并拼接起来赋给num}
                      k := k+1;    {k++}
                      getch    {继续读字符}
                    until not( ch in ['0'..'9']);    {直到输入的不再是数字}
                    if k > nmax    {如果数字的位数超过了数字允许的最大长度}
                    then error(30)    {报错}
                  end
        else if ch = ':'    {当字符不是数字或字母,而是':'时}
             then begin
                    getch;    {读下一个字符}
                    if ch = '='    {如果下一个字符是'='}
                    then begin
                          sym := becomes;    {将标识符sym设置为becomes,表示复制}
                          getch    {读下一个字符}
                        end
                    else sym := nul {否则,将标识符设置为nul,表示非法}
                   end
        else if ch = '<'    {当读到的字符是'<'时}
               then begin    
                      getch;    {读下一个字符}
                      if ch = '='    {若读到的字符是'='}
                      then begin
                             sym := leq;    {则sym为leq,表示小于等于}
                             getch    {读下一个字符}
                           end
                      else if ch = '>'    {若读到的字符是'>'}
                           then begin
                                 sym := neq;    {则sym为neq,表示不等于}
                                 getch    {读下一个字符}
                               end
                      else sym := lss    {否则,sym设为lss,表示小于}
                    end
        else if ch = '>'    {若读到的是'>'}
                then begin
                       getch;    {读下一个字符}
                       if ch = '='    {若读到的是'='}
                       then begin
                              sym := geq;    {sym设为geq,表示大于等于}
                              getch    {读下一个字符}
                            end
                       else sym := gtr    {否则,sym设为gtr,表示大于}
                     end
        else begin    {若非上述几种符号}
               sym := ssym[ch];    {从ssym表中查到此字符对应的类型,赋给sym}
               getch    {读下一个字符}
             end
        end; { getsym }
    
    procedure gen( x: fct; y,z : integer );    {目标代码生成过程,x表示PCODE指令,y,z是指令的两个操作数}
      begin
        if cx > cxmax    {如果当前生成代码的行数cx大于允许的最大长度cxmax}
        then begin
               writeln('program too long');    {输出报错信息}
               close(fin);    {关闭文件}
               exit    {退出程序}
             end;
        with code[cx] do    {如果没有超出,对目标代码cx}
          begin
            f := x;    {令其f为x}
            l := y;    {令其l为y}
            a := z    {令其a为z}    {这三句对应着code身为instruction类型的三个属性}
          end;
        cx := cx+1    {将当前代码行数之计数加一}
      end; { gen }
    
    procedure test( s1,s2 :symset; n: integer );    {测试当前字符合法性过程,用于错误语法处理,若不合法则跳过单词值只读到合法单词为止}
      begin
        if not ( sym in s1 )    {如果当前符号不在s1中}
        then begin
               error(n);    {报n号错误}
               s1 := s1+s2;    {将s1赋值为s1和s2的集合}
               while not( sym in s1) do    {这个while的本质是pass掉所有不合法的符号,以恢复语法分析工作}
                 getsym    {获得下一个标识符}
               end
      end; { test }
    
    procedure block( lev,tx : integer; fsys : symset );    {进行语法分析的主程序,lev表示语法分析所在层次,tx是当前符号表指针,fsys是用来恢复错误的单词集合}
      var  dx : integer;  { data allocation index }    {数据地址索引}
           tx0: integer;  { initial table index }    {符号表初始索引}
           cx0: integer;  { initial code index }    {初始代码索引}
    
      procedure enter( k : objecttyp );     {将对象插入到符号表中}
        begin  { enter object into table }    
          tx := tx+1;    {符号表序号加一,指向一个空表项}
          with table[tx] do    {改变tx序号对应表的内容}
            begin
              name := id;    {name记录object k的id,从getsym获得}
              kind := k;    {kind记录k的类型,为传入参数}
              case k of    {根据类型不同会进行不同的操作}
                constant : begin    {对常量}
                          if num > amax    {如果常量的数值大于约定的最大值}
                          then begin    
                                error(30);    {报30号错误}
                                num := 0    {将常量置零}
                               end;
                          val := num    {val保存该常量的值,结合上句可以看出,如果超过限制则保存0}
                        end;
                variable : begin    {对变量}
                          level := lev;    {记录所属层次}
                          adr := dx;    {记录变量在当前层中的偏移量}
                          dx := dx+1    {偏移量+1,位下一次插入做准备}
                        end;
                prosedure: level := lev;    {对过程,记录所属层次}
              end
            end
        end; { enter }
    
    function position ( id : alfa ): integer;    {查找符号表的函数,输入id为需要寻找的符号,}
      var i : integer;    {声明记录变量}
      begin
        table[0].name := id;    {把id放到符号表0号位置}
        i := tx;    {将i设置为符号表的最后一个位置,因为符号表是栈式结构,因此按层次逆序查找}
        while table[i].name <> id do    {如果当前表项的name和id不同}
           i := i-1;    {再向前找}
        position := i    {找到了,把位置赋值给position返回}
      end;  { position }
    
    procedure constdeclaration;     {处理常量声明的过程}
        begin
          if sym = ident    {如果sym是ident说明是标识符}
          then begin
                 getsym;    {获取下一个sym类型}
                 if sym in [eql,becomes]    {如果sym是等号或者赋值符号}
                 then begin
                        if sym = becomes    {若是赋值符号}
                        then error(1);    {报一号错误,因为声明应该使用等号}
                        getsym;  {获取下一个sym类型}
                        if sym = number    {如果读到的是数字}
                        then begin
                               enter(constant);    {将该常量入表}
                               getsym    {获取下一个sym类型}
                             end
                        else error(2)    {如果等号后面不是数字,报2号错误}
                      end
                 else error(3)    {如果常量标识符后面接的不是等号或赋值符号,报三号错误}
               end
          else error(4)    {如果常量声明第一个符号不是标识符,报4号错误}
        end; { constdeclaration }    {常量声明结束}
    
      procedure vardeclaration;     {变量声明过程}
        begin
          if sym = ident    {变量声明要求第一个sym为标识符}
          then begin
                 enter(variable);    {将该变量入表}
                 getsym    {获取下一个sym类型}
               end
          else error(4)    {如果第一个sym不是标识符,抛出4号错误}
        end; { vardeclaration }
    
      procedure listcode;    {列出PCODE的过程}
        var i : integer;    {声明计数变量}
        begin
          for i := cx0 to cx-1 do    {所有生成的代码}
            with code[i] do    {对于每一行代码}
              writeln( i:4, mnemonic[f]:7,l:3, a:5)    {格式化输出,分别输出序号,指令的助记符,层次,地址.实际的输出效果和我们实际的PCODE相同}
        end; { listcode }
    
    procedure statement( fsys : symset );    {语句处理的过程}
    var i,cx1,cx2: integer;    {定义参数}
    procedure expression( fsys: symset);    {处理表达式的过程}
          var addop : symbol;    {定义参数}
            procedure term( fsys : symset);  {处理项的过程}
              var mulop: symbol ;    {定义参数}
              procedure factor( fsys : symset );    {处理因子的处理程序}
                var i : integer;    {定义参数}
                begin
                  test( facbegsys, fsys, 24 );    {测试单词的合法性,判别当前sym是否在facbegsys中,后者在main中定义,如果不在报24号错误}
                  while sym in facbegsys do    {循环处理因子}
                    begin
                      if sym = ident    {如果识别到标识符}
                      then begin
                             i := position(id);    {查表,记录其在符号表中的位置,保存至i}
                             if i= 0    {如果i为0,表示没查到}
                             then error(11)    {报11号错误}
                             else
                               with table[i] do    {对第i个表项的内容}
                                 case kind of        {按照表项的类型执行不同的操作}
                                   constant : gen(lit,0,val);    {如果是常量类型,生成lit指令,操作数为0,val}
                                   variable : gen(lod,lev-level,adr);    {如果是变量类型,生成lod指令,操作数为lev-level,adr}
                                   prosedure: error(21)    {如果因子处理中识别到了过程标识符,报21号错误}
                                 end;
                             getsym    {获取下一个sym类型}
                           end
                      else if sym = number    {如果识别到数字}
                           then begin
                                if num > amax    {判别数字是否超过规定上限}
                                then begin
                                       error(30);    {超过上限,报30号错误}
                                       num := 0    {将数字重置为0}
                                     end;
                                gen(lit,0,num);    {生成lit指令,将num的值放到栈顶}
                                getsym    {获取下一个sym类型}
                                end
                           else if sym = lparen    {如果识别到左括号}
                                then begin
                                     getsym;    {获取下一个sym类型}
                                     expression([rparen]+fsys);    {调用表达式的过程来处理,递归下降子程序方法}
                                     if sym = rparen    {如果识别到右括号}
                                     then getsym    {获取下一个sym类型}
                                     else error(22)    {报22号错误}
                                   end;
                    test(fsys,[lparen],23)    {测试结合是否在fsys中,若不是,抛出23号错误}
                  end
              end; { factor }
            begin { procedure term( fsys : symset);   
                    var mulop: symbol ;    }    {项的分析过程开始}
              factor( fsys+[times,slash]);    {项的第一个符号应该是因子,调用因子分析程序}
              while sym in [times,slash] do    {如果因子后面是乘/除号}
                begin
                  mulop := sym;    {使用mulop保存当前的运算符}
                  getsym;    {获取下一个sym类型}
                  factor( fsys+[times,slash] );    {调用因子分析程序分析运算符后的因子}
                  if mulop = times    {如果运算符是称号}
                  then gen( opr,0,4 )    {生成opr指令,乘法指令}
                  else gen( opr,0,5)    {生成opr指令,除法指令}
                end
            end; { term }
          begin { procedure expression( fsys: symset);  
                  var addop : symbol; }    {表达式的分析过程开始}
            if sym in [plus, minus]    {如果表达式的第一个符号是+/-符号}
            then begin
                   addop := sym;    {保存当前符号}
                   getsym;    {获取下一个sym类型}
                   term( fsys+[plus,minus]);    {正负号后面接项,调用项的分析过程}
                   if addop = minus    {如果符号开头}
                   then gen(opr,0,1)    {生成opr指令,完成取反运算}
                 end
            else term( fsys+[plus,minus]);    {如果不是符号开头,直接调用项的分析过程}
            while sym in [plus,minus] do    {向后面可以接若干个term,使用操作符+-相连,因此此处用while}
              begin
                addop := sym;    {记录运算符类型}
                getsym;    {获取下一个sym类型}
                term( fsys+[plus,minus] );    {调用项的分析过程}
                if addop = plus    {如果是加号}
                then gen( opr,0,2)    {生成opr指令,完成加法运算}
                else gen( opr,0,3)    {否则生成减法指令}
              end
          end; { expression }
    
        procedure condition( fsys : symset );     {条件处理过程}
          var relop : symbol;    {临时变量}
          begin
            if sym = oddsym    {如果当天符号是odd运算符}
            then begin
                   getsym;    {获取下一个sym类型}
                   expression(fsys);    {调用表达式分析过程}
                   gen(opr,0,6)    {生成opr6号指令,完成奇偶判断运算}
                 end
            else begin
                 expression( [eql,neq,lss,gtr,leq,geq]+fsys);    {调用表达式分析过程对表达式进行计算}
                 if not( sym in [eql,neq,lss,leq,gtr,geq])    {如果存在集合之外的符号}
                   then error(20)    {报20号错误}
                   else begin
                          relop := sym;    {记录当前符号类型}
                          getsym;    {获取下一个sym类型}
                          expression(fsys);    {调用表达式分析过程对表达式进行分析}
                          case relop of    {根据当前符号类型不同完成不同的操作}
                            eql : gen(opr,0,8);    {如果是等号,生成opr8号指令,判断是否相等}
                            neq : gen(opr,0,9);    {如果是不等号,生成opr9号指令,判断是否不等}
                            lss : gen(opr,0,10);    {如果是小于号,生成opr10号指令,判断是否小于}
                            geq : gen(opr,0,11);    {如果是大于等于号,生成opr11号指令,判断是否大于等于}
                            gtr : gen(opr,0,12);    {如果是大于号,生成opr12号指令,判断是否大于}
                            leq : gen(opr,0,13);    {如果是小于等于号,生成opr13号指令,判断是否小于等于}
                          end
                        end
                 end
          end; { condition }
        begin { procedure statement( fsys : symset );  
          var i,cx1,cx2: integer; }    {声明处理过程}
          if sym = ident    {如果以标识符开始}
          then begin
                 i := position(id);    {i记录该标识符在符号表中的位置}
                 if i= 0    {如果返回0则是没找到}
                 then error(11)    {抛出11号错误}
                 else if table[i].kind <> variable    {如果在符号表中找到了该符号,但该符号的类型不是变量}
                      then begin { giving value to non-variation }    {那么现在的操作属于给非变量赋值}
                             error(12);    {报12号错误}
                             i := 0    {将符号表标号置零}
                           end;
                 getsym;    {获取下一个sym类型}
                 if sym = becomes    {如果读到的是赋值符号}
                 then getsym    {获取下一个sym类型}
                 else error(13);    {如果读到的不是赋值符号,报13号错误}
                 expression(fsys);    {赋值符号的后面可以跟表达式,因此调用表达式处理子程序}
                 if i <> 0    {如果符号表中找到了合法的符号}
                 then
                   with table[i] do    {使用该表项的内容来进行操作}
                      gen(sto,lev-level,adr)    {生成一条sto指令用来将表达式的值写入到相应变量的地址}
              end
          else if sym = callsym    {如果读到的符号是call关键字}
          then begin
                 getsym;    {获取下一个sym类型}
                 if sym <> ident    {如果call后面跟的不是标识符}
                 then error(14)    {报14号错误}
                 else begin    {如果没有报错}
                        i := position(id);    {记录当前符号在符号表中的位置}
                        if i = 0    {如果没有找到}
                        then error(11)    {报11号错误}
                        else    {如果找到了}
                          with table[i] do    {对第i个表项做如下操作}
                            if kind = prosedure    {如果该表项的种类为过程}
                            then gen(cal,lev-level,adr)    {生成cal代码用来实现call操作}
                            else error(15);    {如果种类不为过程类型,报15号错误}
                        getsym    {获取下一个sym类型}
                      end
               end
          else if sym = ifsym    {如果读到的符号是if关键字}
               then begin
                      getsym;    {获取下一个sym类型}
                      condition([thensym,dosym]+fsys);    {if后面跟的应该是条件语句,调用条件分析过程}
                      if sym = thensym    {如果条件语句后面跟的是then关键字的话}
                      then getsym    {获取下一个sym类型}
                      else error(16);    {如果条件后面接的不是then,报16号错误}
                      cx1 := cx;    {记录当前的生成代码位置}
                      gen(jpc,0,0);    {生成条件跳转指令,跳转位置暂填0}
                      statement(fsys);    {分析then语句后面的语句}
                      code[cx1].a := cx    {将之前记录的代码的位移地址改写到现在的生成代码位置(参考instruction类型的结构)}
                    end
               else if sym = beginsym    {如果读到了begin关键字}
                    then begin
                           getsym;    {获取下一个sym类型}
                           statement([semicolon,endsym]+fsys); {begin后面默认接语句,递归下降分析}
                           while sym in ([semicolon]+statbegsys) do    {在分析的过程中}
                             begin
                               if sym = semicolon    {如果当前的符号是分好}
                               then getsym    {获取下一个sym类型}
                               else error(10);    {否则报10号错误}
                               statement([semicolon,endsym]+fsys)    {继续分析}
                             end;
                           if sym = endsym    {如果读到了end关键字}
                           then getsym    {获取下一个sym类型}
                           else error(17)    {报17号错误}
                         end
                    else if sym = whilesym    {如果读到了while关键字}
                         then begin
                                cx1 := cx;    {记录当前生成代码的行数指针}
                                getsym;    {获取下一个sym类型}
                                condition([dosym]+fsys);    {因为while后需要添加循环条件,因此调用条件语句的分析过程}
                                cx2 := cx;    {记录在分析完条件之后的生成代码的位置,也是do开始的位置}
                                gen(jpc,0,0);    {生成一个条件跳转指令,但是跳转位置(a)置零}
                                if sym = dosym    {条件后应该接do关键字}
                                then getsym    {获取下一个sym类型}    
                                else error(18);    {如果没接do,报18号错误}
                                statement(fsys);    {分析处理循环节中的语句}
                                gen(jmp,0,cx1);        {生成跳转到cx1的地址,既是重新判断一遍当前条件是否满足}
                                code[cx2].a := cx    {给之前生成的跳转指令设定跳转的位置为当前位置}
                              end
                     else if sym = readsym    {如果读到的符号是read关键字}
                          then begin
                                 getsym;    {获取下一个sym类型}
                                 if sym = lparen    {read的后面应该接左括号}
                                 then
                                   repeat    {循环开始}
                                     getsym;    {获取下一个sym类型}
                                     if sym = ident    {如果第一个sym标识符}
                                     then begin    
                                            i := position(id);    {记录当前符号在符号表中的位置}
                                            if i = 0    {如果i为0,说明符号表中没有找到id对应的符号}
                                            then error(11)    {报11号错误}
                                            else if table[i].kind <> variable {如果找到了,但该符号的类型不是变量}
                                                 then begin
                                                        error(12);    {报12号错误,不能像常量和过程赋值}
                                                        i := 0    {将i置零}
                                                      end
                                                 else with table[i] do    {如果是变量类型}
                                                       gen(red,lev-level,adr)    {生成一条red指令,读取数据}
                                         end
                                     else error(4);    {如果左括号后面跟的不是标识符,报4号错误}
                                     getsym;    {获取下一个sym类型}
                                   until sym <> comma    {知道现在的符号不是都好,循环结束}
                                 else error(40);    {如果read后面跟的不是左括号,报40号错误}
                                 if sym <> rparen    {如果上述内容之后接的不是右括号}
                                 then error(22);    {报22号错误}
                                 getsym    {获取下一个sym类型}
                               end
                    else if sym = writesym    {如果读到的符号是write关键字}
                         then begin
                                getsym;    {获取下一个sym类型}
                              if sym = lparen    {默认write右边应该加一个左括号}
                              then begin
                                     repeat    {循环开始}
                                       getsym;    {获取下一个sym类型}
                                       expression([rparen,comma]+fsys);    {分析括号中的表达式}
                                       gen(wrt,0,0);    {生成一个wrt海曙,用来输出内容}
                                     until sym <> comma;    {知道读取到的sym不是逗号}
                                     if sym <> rparen    {如果内容结束没有右括号}
                                     then error(22);    {报22号错误}
                                     getsym    {获取下一个sym类型}
                                   end
                              else error(40)    {如果write后面没有跟左括号}
                            end;
          test(fsys,[],19)    {测试当前字符是否合法,如果没有出现在fsys中,报19号错}
        end; { statement }
      begin  {   procedure block( lev,tx : integer; fsys : symset );   
        var  dx : integer;  /* data allocation index */
        tx0: integer;  /*initial table index */
        cx0: integer;  /* initial code index */              }    {分程序处理过程开始}
        dx := 3;    {记录运行栈空间的栈顶位置,设置为3是因为需要预留SL,DL,RA的空间}
        tx0 := tx;    {记录当前符号表的栈顶位置}
        table[tx].adr := cx;    {符号表当前位置的偏移地址记录下一条生成代码开始的位置}
        gen(jmp,0,0); { jump from declaration part to statement part }    {产生一条jmp类型的无条件跳转指令,跳转位置未知}
        if lev > levmax    {当前过程所处的层次大于允许的最大嵌套层次}
        then error(32);    {报32号错误}
    
        repeat    {循环开始}
          if sym = constsym    {如果符号类型是const保留字}
          then begin
                 getsym;    {获取下一个sym类型}
                 repeat    {循环开始}
                   constdeclaration;    {处理常量声明}
                   while sym = comma do    {如果声明常量后接的是逗号,说明常量声明没有结束,进入下一循环}
                     begin
                       getsym;    {获取下一个sym类型}
                       constdeclaration    {处理常量声明}
                     end;
                   if sym = semicolon    {如果读到了分号,说明常量声明已经结束了}
                   then getsym    {获取下一个sym类型}
                   else error(5)    {如果没有分号,报5号错误}
                 until sym <> ident    {循环直到遇到下一个标志符}
               end;
          if sym = varsym    {如果读到的是var保留字}
          then begin
                 getsym;    {获取下一个sym类型}
                 repeat        {循环开始}
                   vardeclaration;    {处理变量声明}
                   while sym = comma do    {如果读到了逗号,说明声明未结束,进入循环}
                     begin
                       getsym;    {获取下一个sym类型}
                       vardeclaration    {处理变量声明}
                     end;
                   if sym = semicolon    {如果读到了分号,说明所有声明已经结束}
                   then getsym    {获取下一个sym类型}
                   else error(5)    {如果未读到分号,则报5号错误}
                 until sym <> ident;    {循环直到读到下一个标识符为止}
               end;
          while sym = procsym do    {如果读到proc关键字}
            begin
              getsym;    {获取下一个sym类型}
              if sym = ident    {第一个符号应该是标识符类型}
              then begin
                     enter(prosedure);    {将该符号录入符号表,类型为过程,因为跟在proc后面的一定是过程名}
                     getsym    {获取下一个sym类型}
                   end
              else error(4);    {如果第一个符号不是标识符类型,报4号错误}
              if sym = semicolon    {如果读到了分号,说明proc声明结束}
              then getsym    {获取下一个sym类型}
              else error(5);    {如果声明过程之后没有跟分号,报5号错误}
              block(lev+1,tx,[semicolon]+fsys);    {执行分程序的分析过程}
              if sym = semicolon    {递归调用返回后应该接分号}
              then begin    {如果接的是分号}
                     getsym;    {获取下一个sym类型}
                     test( statbegsys+[ident,procsym],fsys,6)    {测试当前的sym是否合法}
                   end
              else error(5)    {如果接的不是分号,报5号错误}
            end;
          test( statbegsys+[ident],declbegsys,7)    {测试当前的sym是否合法}
        until not ( sym in declbegsys );    {一直循环到sym不在声明符号集中为止}
        code[table[tx0].adr].a := cx;  { back enter statement code's start adr. }    {将之前生成无条件跳转指令的目标地址指向当前位置}
        with table[tx0] do    {对符号表新加记录}
          begin
            adr := cx; { code's start address }    {记录当前代码的分配为止}
          end;
        cx0 := cx;    {记录当前代码分配的地址}
        gen(int,0,dx); { topstack point to operation area }    {生成int指令,分配dx个空间}
        statement( [semicolon,endsym]+fsys);    {调用语法分析程序}
        gen(opr,0,0); { return }    {生成0号gen程序,完成返回操作}
        test( fsys, [],8 );    {测试当前状态是否合法,有问题报8号错误}
        listcode;    {列出该block所生成的PCODE}
    end { block };
    
    procedure interpret;  {解释执行程序}
      const stacksize = 500;    {设置栈大小为常量500}
      var p,b,t: integer; { program-,base-,topstack-register }    {设置三个寄存器,分别记录下一条指令,基址地址和栈顶指针}
         i : instruction;{ instruction register }    {指令寄存器,类型为instruction,显然是为了存放当前指令}
         s : array[1..stacksize] of integer; { data store }    {数据栈,大小为stacksize=500个integer}
      function base( l : integer ): integer;    {声明计算基地址的函数}
        var b1 : integer;    {声明计数变量}
        begin { find base l levels down }    {目标是找到相对于现在层次之差为l的层次基址}
          b1 := b;    {记录当前层的基地址}
          while l > 0 do    {如果层数大于0,即寻找的不是本层}
            begin
              b1 := s[b1];    {记录当前层数据基址的内容}
              l := l-1    {层数--}
            end;
          base := b1    {将找到的基地址保存起来}
        end; { base }
      begin  
        writeln( 'START PL/0' );    {输出程序开始运行的提示语句}
        t := 0;    {将栈顶指针置零}
        b := 1;    {将基址地址置为1}
        p := 0;    {将指令寄存器置零}
        s[1] := 0;    {将数据栈的第一层置零,对应SL}
        s[2] := 0;    {将数据栈的第二层置零,对应DL}
        s[3] := 0;    {将数据栈的第三层置零,对应RA}
        repeat    {循环开始}
          i := code[p];    {获取当前需要执行的代码}
          p := p+1;        {将指令寄存器+1,以指向下一条置零}
          with i do    {针对当前指令}
            case f of    {不同类型的指令执行不同操作}
              lit : begin    {对lit类型}
                      t := t+1;    {栈顶指针加1}
                      s[t]:= a;    {将a操作数的值放入栈顶}
                  end;
              opr : case a of { operator }    {针对opr类型的指令}
                      0 : begin { return }    {0对应return操作}
                            t := b-1;    {t取到该层数据栈SL-1的位置,意味着将该层的数据栈全部清空(因为要返回了嘛)}
                            p := s[t+3];    {将指令指针指向RA的值,即获得return address}
                            b := s[t+2];    {将基址指针指向DL的值,即获得了return之后的基址,因为被调用层次的DL指向调用层次的基址}
                         end;
                      1 : s[t] := -s[t];    {1对应取反操作}
                      2 : begin        {2对应求和操作}
                            t := t-1;    {栈顶指针退一格}
                            s[t] := s[t]+s[t+1]    {将栈顶和次栈顶中的数值求和放入新的栈顶,注意运算后的栈顶是下降一格的,下面的运算亦如此}
                         end;
                      3 : begin        {3对应做差操作}
                            t := t-1;    {栈顶指针退格}
                            s[t] := s[t]-s[t+1]    {次栈顶减栈顶,结果放入新的栈顶}
                         end;
                      4 : begin        {4对应乘积操作}
                            t := t-1;    {栈顶退格}
                            s[t] := s[t]*s[t+1]    {栈顶和次栈顶相乘,结果放入新的栈顶}
                         end;
                      5 : begin        {5对应相除}
                            t := t-1;    {栈顶退格}
                            s[t] := s[t]div s[t+1]    {次栈顶除以栈顶,结果放入新的栈顶}
                         end;
                      6 : s[t] := ord(odd(s[t]));    {6对应判断是否栈顶数值为奇数}
                      8 : begin    {8号对应等值判断}
                            t := t-1;    {栈顶退格}
                            s[t] := ord(s[t]=s[t+1])    {如果栈顶和次栈顶数值相同,栈顶置一,否则置零}
                        end;
                      9 : begin    {9号对应不等判断}
                            t := t-1;    {栈顶退格}
                            s[t] := ord(s[t]<>s[t+1])    {如果栈顶和次栈顶数值不同,栈顶置一,否则置零}
                         end;
                      10: begin    {10号对应小于判断}
                            t := t-1;    {栈顶退格}
                            s[t] := ord(s[t]< s[t+1])    {如果次栈顶的数值小于栈顶的数值,栈顶置一,否则置零}
                         end;
                      11: begin    {11号对应大于等于判断}
                            t := t-1;    {栈顶退格}
                            s[t] := ord(s[t] >= s[t+1]) {如果次栈顶的数值大于等于栈顶的数值,栈顶置一,否则置零}
                         end;
                      12: begin    {12号对应着大于判断}
                            t := t-1;    {栈顶退格}    
                            s[t] := ord(s[t] > s[t+1])    {如果次栈顶的数值大于栈顶的数值,栈顶置一,否则置零}
                         end;
                      13: begin    {13号对应着小于等于判断}
                            t := t-1;    {栈顶退格}
                            s[t] := ord(s[t] <= s[t+1])    {如果次栈顶的数值小于等于栈顶的数值,栈顶置一,否则置零}
                         end;
                    end;
              lod : begin    {如果是lod指令}
                      t := t+1;    {栈顶指针指向新栈}
                      s[t] := s[base(l)+a]    {将与当前数据层层次差为l,层内偏移为a的栈中的数据存到栈顶}
                  end;
              sto : begin    {对于sto指令}
                      s[base(l)+a] := s[t];  { writeln(s[t]); }    {将当前栈顶的数据保存到与当前层层差为l,层内偏移为a的数据栈中}
                      t := t-1    {栈顶退栈}
                  end;
              cal : begin  { generate new block mark }    {对于指令}
                      s[t+1] := base(l);    {由于要生成新的block,因此栈顶压入SL的值}
                      s[t+2] := b;    {在SL之上压入当前数据区的基址,作为DL}
                      s[t+3] := p;    {在DL之上压入指令指针,即是指令的断点,作为RA}
                      b := t+1;    {把当前的数据区基址指向新的SL}
                      p := a;    {从a的位置继续执行程序,a来自instruction结构体}
                  end;
              int : t := t+a;    {对int指令,将栈顶指针上移a个位置}
              jmp : p := a;    {对jmp指令,将指令指针指向a}
              jpc : begin    {对于jpc指令}
                      if s[t] = 0    {如果栈顶数据为零}
                      then p := a;    {则将指令指针指向a}
                      t := t-1;    {栈顶向下移动}
                  end;
              red : begin    {对red指令}
                      writeln('??:');    {输出提示信息}
                      readln(s[base(l)+a]); {读一行数据,读入到相差l层,层内偏移为a的数据栈中的数据的信息}
                  end;
              wrt : begin    {对wrt指令}
                      writeln(s[t]);    {输出栈顶的信息}
                      t := t+1    {栈顶上移}
                  end
            end { with,case }
        until p = 0;    {直到当前指令的指针为0,这意味着主程序返回了,即整个程序已经结束运行了}
        writeln('END PL/0');    {PL/0执行结束}
      end; { interpret }
    
    begin { main }    { 主函数 }
      writeln('please input source program file name : ');    {提示信息,要求用户输入源码的地址}
      readln(sfile);    {读入一行保存至sfile}
      assign(fin,sfile);    {将文件名字符串变量str付给文件变量fin}
      reset(fin);    {打开fin}
      for ch := 'A' to ';' do    
        ssym[ch] := nul;    {将从'A'到';'的符号的ssym都设置为nul,表示不合法}
      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        ';    {填写保留字表,注意这里所有字符都预留的相同的长度}
    
      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;    {填写保留字对应的标识符sym的值}
    
      ssym['+'] := plus;        ssym['-'] := minus;
      ssym['*'] := times;       ssym['/'] := slash;
      ssym['('] := lparen;      ssym[')'] := rparen;
      ssym['='] := eql;         ssym[','] := comma;
      ssym['.'] := period;
      ssym['<'] := lss;         ssym['>'] := gtr;
      ssym[';'] := semicolon;    {填写对应符号对应的标识符sym的值}
    
      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  ';    {填写助记符表,与PCODE指令一一对应}
    
      declbegsys := [ constsym, varsym, procsym ];    {表达式开始的符号集合}
      statbegsys := [ beginsym, callsym, ifsym, whilesym];    {语句开始的符号集合}
      facbegsys := [ ident, number, lparen ];    {项开始的符号集合}
      err := 0;    {将出错的标识符置零}
      cc := 0;    {行缓冲指针置零}
      cx := 0;    {生成代码行数计数置零}
      ll := 0;    {词法分析行缓冲区长度置零}
      ch := ' ';    {当前字符设为' '}
      kk := al;    {kk的值初始化为0}
      getsym;    {获取第一个词的标识符}
      block( 0,0,[period]+declbegsys+statbegsys );    {执行主程序block}
      if sym <> period    {如果符号不是句号}
      then error(9);    {报⑨号错误}
      if err = 0    {如果err为0表示没有错误}
      then interpret    {开始解释执行生成的PCODE代码}
      else write('ERRORS IN PL/0 PROGRAM');    {否则出现了错误,报错}
      writeln;    {换行}
      close(fin);    {关闭源文件程序}
      readln(sfile);    {读取PL/0源程序}
    end.           

    Pascal-S编译器

    比PL0的代码多不少,同样是Pascal的子集,选择重要函数注释,将来有时间的话继续补全

       1 program PASCALS(INPUT,OUTPUT,PRD,PRR);
       2 {  author:N.Wirth, E.T.H. CH-8092 Zurich,1.3.76 }
       3 {  modified by R.E.Berry
       4     Department of computer studies
       5     UniversitY of Lancaster
       6 
       7     Variants ot this program are used on
       8     Data General Nova,Apple,and
       9     Western Digital Microengine machines. }
      10 {   further modified by M.Z.Jin
      11     Department of Computer Science&Engineering BUAA,0ct.1989
      12 }
      13 {    comment by Song Lu
      14     Department of Computer Science&Engineering BUAA,Nov.2016
      15 }
      16 const nkw = 27;    { no. of key words }    {key word应当理解为保留字}
      17       alng = 10;   { no. of significant chars in identifiers }
      18       llng = 121;  { input line length }
      19       emax = 322;  { max exponent of real numbers }
      20       emin = -292; { min exponent }
      21       kmax = 15;   { max no. of significant digits }
      22       tmax = 100;  { size of table }
      23       bmax = 20;   { size of block-talbe }
      24       amax = 30;   { size of array-table }
      25       c2max = 20;  { size of real constant table }
      26       csmax = 30;  { max no. of cases }
      27       cmax = 800;  { size of code }
      28       lmax = 7;    { maximum level }
      29       smax = 600;  { size of string-table }
      30       ermax = 58;  { max error no. }    {最大错误数量}
      31       omax = 63;   { highest order code }
      32       xmax = 32767;  { 2**15-1 }    {index的范围}
      33       nmax = 32767;  { 2**15-1 }    {数字的范围}
      34       lineleng = 132; { output line length }
      35       linelimit = 200;    {行数限制}
      36       stacksize = 1450;    {数据栈大小}
      37 type symbol = ( intcon, realcon, charcon, stringcon,
      38                 notsy, plus, minus, times, idiv, rdiv, imod, andsy, orsy,
      39                 eql, neq, gtr, geq, lss, leq,
      40                 lparent, rparent, lbrack, rbrack, comma, semicolon, period,
      41                 colon, becomes, constsy, typesy, varsy, funcsy,
      42                 procsy, arraysy, recordsy, programsy, ident,
      43                 beginsy, ifsy, casesy, repeatsy, whilesy, forsy,
      44                 endsy, elsesy, untilsy, ofsy, dosy, tosy, downtosy, thensy);
      45      index = -xmax..+xmax;
      46      alfa = packed array[1..alng]of char;
      47      objecttyp = (konstant, vvariable, typel, prozedure, funktion );
      48      types = (notyp, ints, reals, bools, chars, arrays, records );
      49      symset = set of symbol;
      50      typset = set of types;
      51      item = record
      52                typ: types;
      53                ref: index;
      54             end;
      55 
      56      order = packed record
      57                f: -omax..+omax;
      58                x: -lmax..+lmax;
      59                y: -nmax..+nmax
      60             end;
      61 var  ch:         char; { last character read from source program }
      62      rnum:       real; { real number from insymbol }
      63      inum:       integer;     { integer from insymbol }
      64      sleng:      integer;     { string length }
      65      cc:         integer;     { character counter }
      66      lc:         integer;     { program location counter }
      67      ll:         integer;     { length of current line }
      68      errpos:     integer;
      69      t,a,b,sx,c1,c2:integer;  { indices to tables }
      70      iflag, oflag, skipflag, stackdump, prtables: boolean;
      71      sy:         symbol;      { last symbol read by insymbol }
      72      errs:       set of 0..ermax;    {记录错误的集合}
      73      id:         alfa;        { identifier from insymbol }
      74      progname:   alfa;
      75      stantyps:   typset;
      76      constbegsys, typebegsys, blockbegsys, facbegsys, statbegsys: symset;
      77      line:       array[1..llng] of char;
      78      key:        array[1..nkw] of alfa;        {保留字集合}
      79      ksy:        array[1..nkw] of symbol;    {保留字对应的sym集合}
      80      sps:        array[char]of symbol;  { special symbols }
      81      display:    array[0..lmax] of integer;
      82      tab:        array[0..tmax] of      { indentifier lable }    {符号表}
      83                  packed record
      84                      name: alfa;
      85                      link: index;
      86                      obj:  objecttyp;
      87                      typ:  types;
      88                      ref:  index;
      89                      normal: boolean;
      90                      lev:  0..lmax;
      91                      adr: integer
      92                  end;
      93      atab:       array[1..amax] of    { array-table }    {数组信息向量表}
      94                  packed record
      95                      inxtyp,eltyp: types;
      96                      elref,low,high,elsize,size: index
      97                  end;
      98      btab:       array[1..bmax] of    { block-table }    {分符号表}
      99                  packed record
     100                      last, lastpar, psize, vsize: index
     101                  end;
     102      stab:       packed array[0..smax] of char; { string table }    {字符串常量表}
     103      rconst:     array[1..c2max] of real;    {实常量表}
     104      code:       array[0..cmax] of order;    {P代码表}
     105      psin,psout,prr,prd:text;      { default in pascal p }    {写入inf,outf,fppr文件的文本}
     106      inf, outf, fprr: string;    {代码输入,代码输出,结果输出的文件路径}
     107 
     108 procedure errormsg;    {打印错误信息摘要的过程}
     109   var k : integer;
     110      msg: array[0..ermax] of alfa;    {给定错误信息表,最多ermax种错误}
     111   begin
     112     msg[0] := 'undef id  ';    msg[1] := 'multi def ';    {给定错误类型'k',及其提示信息}
     113     msg[2] := 'identifier';    msg[3] := 'program   ';
     114     msg[4] := ')         ';    msg[5] := ':         ';
     115     msg[6] := 'syntax    ';    msg[7] := 'ident,var ';
     116     msg[8] := 'of        ';    msg[9] := '(         ';
     117     msg[10] := 'id,array  ';    msg[11] := '(         ';
     118     msg[12] := ']         ';    msg[13] := '..        ';
     119     msg[14] := ';         ';    msg[15] := 'func. type';
     120     msg[16] := '=         ';    msg[17] := 'boolean   ';
     121     msg[18] := 'convar typ';    msg[19] := 'type      ';
     122     msg[20] := 'prog.param';    msg[21] := 'too big   ';
     123     msg[22] := '.         ';    msg[23] := 'type(case)';
     124     msg[24] := 'character ';    msg[25] := 'const id  ';
     125     msg[26] := 'index type';    msg[27] := 'indexbound';
     126     msg[28] := 'no array  ';    msg[29] := 'type id   ';
     127     msg[30] := 'undef type';    msg[31] := 'no record ';
     128     msg[32] := 'boole type';    msg[33] := 'arith type';
     129     msg[34] := 'integer   ';    msg[35] := 'types     ';
     130     msg[36] := 'param type';    msg[37] := 'variab id ';
     131     msg[38] := 'string    ';    msg[39] := 'no.of pars';
     132     msg[40] := 'real numbr';    msg[41] := 'type      ';
     133     msg[42] := 'real type ';    msg[43] := 'integer   ';
     134     msg[44] := 'var,const ';    msg[45] := 'var,proc  ';
     135     msg[46] := 'types(:=) ';    msg[47] := 'typ(case) ';
     136     msg[48] := 'type      ';    msg[49] := 'store ovfl';
     137     msg[50] := 'constant  ';    msg[51] := ':=        ';
     138     msg[52] := 'then      ';    msg[53] := 'until     ';
     139     msg[54] := 'do        ';    msg[55] := 'to downto ';
     140     msg[56] := 'begin     ';    msg[57] := 'end       ';
     141     msg[58] := 'factor';
     142 
     143     writeln(psout);    {向文件中打印一个空行}
     144     writeln(psout,'key words');    {向psout文件中输出'key words',并换行}
     145     k := 0;
     146     while errs <> [] do    {如果还有错误信息没有处理}
     147       begin
     148         while not( k in errs )do k := k + 1;    {如果不存在第k种错误,则判断是否存在地k+1中}
     149         writeln(psout, k, ' ', msg[k] );    {在文件中输出错误的编号及其信息}
     150         errs := errs - [k]    {将错误集合中的该类错误去除(因为已经处理过)}
     151     end { while errs }    {循环直到所有错误被处理}
     152   end { errormsg } ;
     153 
     154 procedure endskip;    {源程序出错后再整个跳过部分代码下面画下划线}
     155   begin                 { underline skipped part of input }
     156     while errpos < cc do
     157       begin
     158         write( psout, '-');
     159         errpos := errpos + 1
     160       end;
     161     skipflag := false
     162   end { endskip };
     163 
     164 
     165 procedure nextch;  { read next character; process line end }
     166   begin
     167     if cc = ll    {如果读到了一行的末尾}
     168     then begin
     169            if eof( psin )    {文件读完了}
     170            then begin
     171                   writeln( psout );    {写输出文件}
     172                   writeln( psout, 'program incomplete' );    {提示信息}
     173                   errormsg;    {输出错误提示信息到list文件}
     174                   exit;
     175                 end;
     176            if errpos <> 0    {说明有错误,开始错误处理}
     177            then begin
     178                   if skipflag then endskip;    {跳过错误代码}
     179                   writeln( psout );
     180                   errpos := 0
     181                 end;
     182            write( psout, lc: 5, ' ');    {没有错误执行的操作,在list文件中输出当前PCODE的行数以及一个空格,不换行}
     183            ll := 0;    {将行长度和行指针置零}
     184            cc := 0;
     185            while not eoln( psin ) do    {如果文件没有读完,读下一行}
     186              begin
     187                ll := ll + 1;    {统计行的长度}
     188                read( psin, ch );    {读取下一个字符}
     189                write( psout, ch );    {输出到list文件中}
     190                line[ll] := ch    {将ch保存到line中,循环结束line保存下一行代码的所有信息}
     191              end;
     192            ll := ll + 1;
     193            readln( psin );
     194            line[ll] := ' ';    {一行的末尾置为空格}
     195            writeln( psout );
     196          end;
     197      cc := cc + 1;    {行指针前移}
     198      ch := line[cc];    {取词}
     199   end { nextch };
     200 
     201 procedure error( n: integer );    {打印出错位置和出错编号}
     202 begin
     203   if errpos = 0
     204   then write ( psout, '****' );
     205   if cc > errpos
     206   then begin
     207          write( psout, ' ': cc-errpos, '^', n:2);
     208          errpos := cc + 3;
     209          errs := errs +[n]
     210       end
     211 end { error };
     212 
     213 procedure fatal( n: integer );    {打印表格溢出信息,写入数据多于表大小时会终止程序}
     214   var msg : array[1..7] of alfa;
     215   begin
     216     writeln( psout );
     217     errormsg;
     218     msg[1] := 'identifier';   msg[2] := 'procedures';
     219     msg[3] := 'reals     ';   msg[4] := 'arrays    ';
     220     msg[5] := 'levels    ';   msg[6] := 'code      ';
     221     msg[7] := 'strings   ';
     222     writeln( psout, 'compiler table for ', msg[n], ' is too small');
     223     exit; {terminate compilation }
     224   end { fatal };
     225 
     226 procedure insymbol;  {reads next symbol}    {取符号方法}
     227 label 1,2,3;    {定义label,为goto的使用做准备}
     228   var  i,j,k,e: integer;    
     229   procedure readscale;    {处理实数的指数部分}
     230     var s,sign: integer;
     231     begin
     232       nextch;
     233       sign := 1;    {符号}
     234       s := 0;        {数字}
     235       if ch = '+'    {如果读到'+',不作处理}
     236       then nextch
     237       else if ch = '-'    {如果是'-',符号设为负}
     238            then begin
     239                   nextch;
     240                   sign := -1
     241                 end;
     242       if not(( ch >= '0' )and (ch <= '9' ))    {如果符号后面跟的不是数字,报错}
     243       then error( 40 )
     244       else repeat
     245            s := 10*s + ord( ord(ch)-ord('0'));    {把数字存到s中}
     246            nextch;
     247           until not(( ch >= '0' ) and ( ch <= '9' ));
     248       e := s*sign + e    {和下面计算中的e结合得到真的e}
     249     end { readscale };
     250 
     251   procedure adjustscale;    {根据小数位数和指数大小求出数字数值的大小}
     252     var s : integer;
     253         d, t : real;
     254     begin
     255       if k + e > emax    {当前的位数加上指数如果超上限报错}
     256       then error(21)
     257       else if k + e < emin    {小于最小值}
     258            then rnum := 0    {精度不够了,直接记为零}
     259       else begin
     260             s := abs(e);
     261             t := 1.0;
     262             d := 10.0;
     263             repeat
     264                 while not odd(s) do    {把偶次幂先用平方处理完}
     265                   begin
     266                     s := s div 2;
     267                     d := sqr(d)    {sqr表示平方}
     268                   end;
     269                 s := s - 1;
     270                 t := d * t    {在乘一下自己,完成1次,即将e分解为2N+1或2N的形式}
     271             until s = 0;    {t此时为10的e次方}
     272             if e >= 0    
     273             then rnum := rnum * t    {e大于零就乘10的e次方}
     274             else rnum := rnum / t    {反之除}
     275            end
     276      end { adjustscale };
     277 
     278   procedure options;    {编译选项}
     279     procedure switch( var b: boolean );    {处理编译选项中的'+''-'号}
     280       begin
     281         b := ch = '+';    {判断当前符号是否为'+'并存入b中返回,注意pascal中变量形参传的是地址}
     282         if not b    {如果不是加号}
     283         then if not( ch = '-' )    {如果也不是减号}
     284              then begin { print error message }    {输出错误信息}
     285                     while( ch <> '*' ) and ( ch <> ',' ) do    {跳过无用符号}
     286                       nextch;
     287                   end
     288              else nextch
     289         else nextch
     290       end { switch };
     291     begin { options  }    {处理编译选项}
     292       repeat
     293         nextch;
     294         if ch <> '*'    {编译选项为*$t+,s+*的形式}
     295         then begin
     296                if ch = 't'    {字母t表示与打印相关的操作}
     297                then begin
     298                       nextch;
     299                       switch( prtables )    {根据符号判断是否打印表格}
     300                     end
     301                else if ch = 's'    {s表示卸出打印}
     302                   then begin
     303                           nextch;
     304                           switch( stackdump )    
     305                        end;
     306              end
     307       until ch <> ','
     308     end { options };
     309   begin { insymbol  }
     310   1: while( ch = ' ' ) or ( ch = chr(9) ) do    {第一个flag立起来了! chr可以获得9号字符,即跳过所有的空格和	}
     311        nextch;    { space & htab }
     312     case ch of
     313       'a','b','c','d','e','f','g','h','i',
     314       'j','k','l','m','n','o','p','q','r',
     315       's','t','u','v','w','x','y','z':
     316         begin { identifier of wordsymbol }    {如果是字母,开始识别单词}
     317           k := 0;
     318           id := '          ';
     319           repeat
     320             if k < alng    {alng是限定的关键词长度}
     321             then begin
     322                    k := k + 1;
     323                    id[k] := ch
     324                  end;
     325             nextch
     326           until not((( ch >= 'a' ) and ( ch <= 'z' )) or (( ch >= '0') and (ch <= '9' )));
     327           i := 1;
     328           j := nkw; { binary search }    {二分查表,找到当前id在表中的位置}
     329           repeat
     330             k := ( i + j ) div 2;
     331             if id <= key[k]
     332             then j := k - 1;
     333             if id >= key[k]
     334             then i := k + 1;
     335           until i > j;
     336           if i - 1 > j
     337           then sy := ksy[k]    {获取当前ID对应的sym}
     338           else sy := ident    {没有找到即为标识符}
     339         end;
     340       '0','1','2','3','4','5','6','7','8','9':    {数字开始当做数字识别}
     341         begin { number }
     342           k := 0;
     343           inum := 0;
     344           sy := intcon;    {sy设为intcon表示数字}
     345           repeat
     346             inum := inum * 10 + ord(ch) - ord('0');    {把整数部分读完,存到inum}
     347             k := k + 1;    {k统计当前数字位数}
     348             nextch
     349           until not (( ch >= '0' ) and ( ch <= '9' ));    
     350           if( k > kmax ) or ( inum > nmax )    {超上限报错}
     351           then begin
     352                  error(21);
     353                  inum := 0;
     354                  k := 0
     355                end;
     356           if ch = '.'    {开始读小数}
     357           then begin
     358                  nextch;
     359                  if ch = '.'
     360                  then ch := ':'
     361                  else begin
     362                         sy := realcon;    {sym为实数}
     363                         rnum := inum;    {rnum存实数的值}
     364                         e := 0;    {指数}
     365                         while ( ch >= '0' ) and ( ch <= '9' ) do    {把数字读完}
     366                           begin
     367                             e := e - 1;
     368                             rnum := 10.0 * rnum + (ord(ch) - ord('0'));    {暂时当做整数存}
     369                             nextch
     370                           end;
     371                         if e = 0    {小数点后没数字,40号error}
     372                         then error(40);
     373                         if ch = 'e'    {如果是科学计数法}
     374                         then readscale;    {算e}
     375                         if e <> 0 then adjustscale    {算数,rnum存数}
     376                       end
     377                 end
     378           else if ch = 'e'
     379                then begin
     380                       sy := realcon;
     381                       rnum := inum;
     382                       e := 0;
     383                       readscale;
     384                       if e <> 0
     385                       then adjustscale
     386                     end;
     387         end;
     388       ':':
     389         begin
     390           nextch;
     391           if ch = '='
     392           then begin
     393                  sy := becomes;
     394                  nextch
     395                end
     396           else  sy := colon
     397          end;
     398       '<':
     399         begin
     400           nextch;
     401           if ch = '='
     402           then begin
     403                  sy := leq;
     404                  nextch
     405                end
     406           else
     407             if ch = '>'
     408             then begin
     409                    sy := neq;
     410                    nextch
     411                  end
     412             else  sy := lss
     413         end;
     414       '>':
     415         begin
     416           nextch;
     417           if ch = '='
     418           then begin
     419                  sy := geq;
     420                  nextch
     421                end
     422           else  sy := gtr
     423         end;
     424       '.':
     425         begin
     426           nextch;
     427           if ch = '.'
     428           then begin
     429                  sy := colon;    {..居然算作colon冒号}
     430                  nextch
     431                end
     432           else sy := period
     433         end;
     434       '''':    {当前字符是否单引号}
     435         begin
     436           k := 0;
     437    2:     nextch;
     438           if ch = ''''
     439           then begin
     440                  nextch;
     441                  if ch <> ''''
     442                  then goto 3
     443                end;
     444           if sx + k = smax
     445           then fatal(7);
     446           stab[sx+k] := ch;
     447           k := k + 1;
     448           if cc = 1
     449           then begin { end of line }
     450                  k := 0;
     451                end
     452           else goto 2;
     453    3:     if k = 1    {双引号中间只有一个字符}
     454           then begin
     455                  sy := charcon;    {sym类型为字符类型}
     456                  inum := ord( stab[sx] )    {inum存储该字符的ascii码值}
     457                end
     458           else if k = 0    {空引号,中间没东西}
     459                then begin
     460                       error(38);    {报错}
     461                       sy := charcon;    {类型字符常量}
     462                       inum := 0    {asc为0}
     463                     end
     464           else begin
     465                   sy := stringcon;    {否则就是一个字符串类型}
     466                   inum := sx;
     467                   sleng := k;
     468                   sx := sx + k
     469                end
     470         end;
     471       '(':
     472         begin
     473           nextch;
     474           if ch <> '*'
     475           then sy := lparent
     476           else begin { comment }
     477                  nextch;
     478                  if ch = '$'
     479                  then options;
     480                  repeat
     481                    while ch <> '*' do nextch;
     482                    nextch
     483                  until ch = ')';
     484                  nextch;
     485                  goto 1
     486                end
     487         end;
     488       '{':
     489         begin
     490           nextch;
     491           if ch = '$'    {左括号加$是进行编译选项的设置}
     492           then options;
     493           while ch <> '}' do
     494             nextch;
     495           nextch;
     496           goto 1
     497         end;
     498       '+', '-', '*', '/', ')', '=', ',', '[', ']', ';':    {操作符直接处理}
     499         begin
     500           sy := sps[ch];
     501           nextch
     502         end;
     503       '$','"' ,'@', '?', '&', '^', '!':    {单独出现算错}
     504         begin
     505           error(24);
     506           nextch;
     507           goto 1
     508         end
     509       end { case }
     510     end { insymbol };
     511 
     512 procedure enter(x0:alfa; x1:objecttyp; x2:types; x3:integer );    {将当前符号(分程序外的)录入符号表}
     513   begin
     514     t := t + 1;    { enter standard identifier }
     515     with tab[t] do
     516       begin
     517         name := x0;
     518         link := t - 1;
     519         obj := x1;
     520         typ := x2;
     521         ref := 0;
     522         normal := true;
     523         lev := 0;
     524         adr := x3;
     525       end
     526   end; { enter }
     527 
     528 procedure enterarray( tp: types; l,h: integer );    {将数组信息录入数组表atab}
     529   begin
     530     if l > h    {下界大于上界,错误}
     531     then error(27);
     532     if( abs(l) > xmax ) or ( abs(h) > xmax )
     533     then begin
     534            error(27);
     535            l := 0;
     536            h := 0;
     537          end;
     538     if a = amax    {表满了}
     539     then fatal(4)    
     540     else begin
     541            a := a + 1;
     542            with atab[a] do
     543              begin
     544                inxtyp := tp;    {下标类型}
     545                low := l;    {上界和下界}
     546                high := h
     547              end
     548          end
     549   end { enterarray };
     550 
     551 procedure enterblock;    {将分程序登录到分程序表}
     552   begin
     553     if b = bmax    {表满了}
     554     then fatal(2)    {报错退出}
     555     else begin
     556            b := b + 1;
     557            btab[b].last := 0;        {指向过程或函数最后一个符号在表中的位置,建表用}
     558            btab[b].lastpar := 0;    {指向过程或者函数的最后一个'参数'符号在tab中的位置,退栈用}
     559          end
     560   end { enterblock };
     561 
     562 procedure enterreal( x: real );    {登陆实常量表}
     563   begin
     564     if c2 = c2max - 1
     565     then fatal(3)
     566     else begin
     567            rconst[c2+1] := x;
     568            c1 := 1;
     569            while rconst[c1] <> x do
     570              c1 := c1 + 1;
     571            if c1 > c2
     572            then  c2 := c1
     573          end
     574   end { enterreal };
     575 
     576 procedure emit( fct: integer );    {emit和下面两个方法都是用来生成PCODE的,后面接的数字是代表有几个操作数}
     577   begin
     578     if lc = cmax
     579     then fatal(6);
     580     code[lc].f := fct; 
     581     lc := lc + 1
     582 end { emit };
     583 
     584 
     585 procedure emit1( fct, b: integer );
     586   begin
     587     if lc = cmax
     588     then fatal(6);
     589     with code[lc] do
     590       begin
     591         f := fct;
     592         y := b;
     593       end;
     594     lc := lc + 1
     595   end { emit1 };
     596 
     597 procedure emit2( fct, a, b: integer );
     598   begin
     599     if lc = cmax then fatal(6);
     600     with code[lc] do
     601       begin
     602         f := fct;
     603         x := a;
     604         y := b
     605       end;
     606     lc := lc + 1;
     607 end { emit2 };
     608 
     609 procedure printtables;    {打印表的过程}
     610   var i: integer;
     611   o: order;
     612       mne: array[0..omax] of
     613            packed array[1..5] of char;
     614   begin
     615     mne[0] := 'LDA  ';   mne[1] := 'LOD  ';  mne[2] := 'LDI  ';    {定义PCODE指令符}
     616     mne[3] := 'DIS  ';   mne[8] := 'FCT  ';  mne[9] := 'INT  ';
     617     mne[10] := 'JMP  ';   mne[11] := 'JPC  ';  mne[12] := 'SWT  ';
     618     mne[13] := 'CAS  ';   mne[14] := 'F1U  ';  mne[15] := 'F2U  ';
     619     mne[16] := 'F1D  ';   mne[17] := 'F2D  ';  mne[18] := 'MKS  ';
     620     mne[19] := 'CAL  ';   mne[20] := 'IDX  ';  mne[21] := 'IXX  ';
     621     mne[22] := 'LDB  ';   mne[23] := 'CPB  ';  mne[24] := 'LDC  ';
     622     mne[25] := 'LDR  ';   mne[26] := 'FLT  ';  mne[27] := 'RED  ';
     623     mne[28] := 'WRS  ';   mne[29] := 'WRW  ';  mne[30] := 'WRU  ';
     624     mne[31] := 'HLT  ';   mne[32] := 'EXP  ';  mne[33] := 'EXF  ';
     625     mne[34] := 'LDT  ';   mne[35] := 'NOT  ';  mne[36] := 'MUS  ';
     626     mne[37] := 'WRR  ';   mne[38] := 'STO  ';  mne[39] := 'EQR  ';
     627     mne[40] := 'NER  ';   mne[41] := 'LSR  ';  mne[42] := 'LER  ';
     628     mne[43] := 'GTR  ';   mne[44] := 'GER  ';  mne[45] := 'EQL  ';
     629     mne[46] := 'NEQ  ';   mne[47] := 'LSS  ';  mne[48] := 'LEQ  ';
     630     mne[49] := 'GRT  ';   mne[50] := 'GEQ  ';  mne[51] := 'ORR  ';
     631     mne[52] := 'ADD  ';   mne[53] := 'SUB  ';  mne[54] := 'ADR  ';
     632     mne[55] := 'SUR  ';   mne[56] := 'AND  ';  mne[57] := 'MUL  ';
     633     mne[58] := 'DIV  ';   mne[59] := 'MOD  ';  mne[60] := 'MUR  ';
     634     mne[61] := 'DIR  ';   mne[62] := 'RDL  ';  mne[63] := 'WRL  ';
     635 
     636     writeln(psout);
     637     writeln(psout);
     638     writeln(psout);
     639     writeln(psout,'   identifiers  link  obj  typ  ref  nrm  lev  adr');
     640     writeln(psout);
     641     for i := btab[1].last to t do    {}
     642       with tab[i] do
     643         writeln( psout, i,' ', name, link:5, ord(obj):5, ord(typ):5,ref:5, ord(normal):5,lev:5,adr:5);
     644     writeln( psout );
     645     writeln( psout );
     646     writeln( psout );
     647     writeln( psout, 'blocks   last  lpar  psze  vsze' );
     648     writeln( psout );
     649     for i := 1 to b do
     650        with btab[i] do
     651          writeln( psout, i:4, last:9, lastpar:5, psize:5, vsize:5 );
     652     writeln( psout );
     653     writeln( psout );
     654     writeln( psout );
     655     writeln( psout, 'arrays xtyp etyp eref low high elsz size');
     656     writeln( psout );
     657     for i := 1 to a do
     658       with atab[i] do
     659         writeln( psout, i:4, ord(inxtyp):9, ord(eltyp):5, elref:5, low:5, high:5, elsize:5, size:5);
     660     writeln( psout );
     661     writeln( psout );
     662     writeln( psout );
     663     writeln( psout, 'code:');
     664     writeln( psout );
     665     for i := 0 to lc-1 do
     666       begin
     667         write( psout, i:5 );
     668         o := code[i];
     669         write( psout, mne[o.f]:8, o.f:5 );
     670         if o.f < 31
     671         then if o.f < 4
     672              then write( psout, o.x:5, o.y:5 )
     673              else write( psout, o.y:10 )
     674         else write( psout, '          ' );
     675         writeln( psout, ',' )
     676       end;
     677     writeln( psout );
     678     writeln( psout, 'Starting address is ', tab[btab[1].last].adr:5 )
     679   end { printtables };
     680 
     681 
     682 procedure block( fsys: symset; isfun: boolean; level: integer );    {程序分析过程}
     683   type conrec = record    {这种结构体可以根据不同的type类型来保存不同样式的数据}
     684                   case tp: types of
     685                     ints, chars, bools : ( i:integer );
     686                     reals :( r:real )
     687               end;
     688   var dx : integer ;  { data allocation index }
     689       prt: integer ;  { t-index of this procedure }
     690       prb: integer ;  { b-index of this procedure }
     691       x  : integer ;
     692 
     693 
     694   procedure skip( fsys:symset; n:integer);    {跳过错误的代码段}
     695     begin
     696       error(n);
     697       skipflag := true;
     698       while not ( sy in fsys ) do
     699         insymbol;
     700       if skipflag then endskip
     701     end { skip };
     702 
     703   procedure test( s1,s2: symset; n:integer );    {检查当前sym是否合法}
     704     begin
     705       if not( sy in s1 )
     706       then skip( s1 + s2, n )
     707     end { test };
     708 
     709   procedure testsemicolon;    {检查分号是否合法}
     710     begin
     711       if sy = semicolon
     712       then insymbol
     713       else begin
     714              error(14);
     715              if sy in [comma, colon]
     716              then insymbol
     717            end;
     718       test( [ident] + blockbegsys, fsys, 6 )
     719     end { testsemicolon };
     720 
     721 
     722   procedure enter( id: alfa; k:objecttyp );    {将分程序中的某一符号入符号表}
     723     var j,l : integer;
     724     begin
     725       if t = tmax    {表满了报错退出}
     726       then fatal(1)
     727       else begin
     728              tab[0].name := id;    
     729              j := btab[display[level]].last;    {获取指向当前层最后一个标识符在tab表中的位置}    
     730              l := j;    
     731              while tab[j].name <> id do    
     732                j := tab[j].link;
     733              if j <> 0    {j不等于0说明此符号已经在符号表中出现过,报1号错误,意味着重复定义了}
     734              then error(1)
     735              else begin    {没重复定义就正常入栈}
     736                     t := t + 1;
     737                     with tab[t] do    {将符号放入符号表,注意这里并没有给定符号的typ,ref和adr,这三个变量在procedure typ中被处理}
     738                       begin
     739                         name := id;    {输入参数之一,符号的名字}
     740                         link := l;
     741                         obj := k;    {输入参数之一,符号代表的目标种类(大类)}
     742                         typ := notyp;
     743                         ref := 0;
     744                         lev := level;
     745                         adr := 0;
     746                         normal := false { initial value }
     747                       end;
     748                     btab[display[level]].last := t    {更新当前层最后一个标识符}
     749                   end
     750            end
     751     end { enter };
     752 
     753   function loc( id: alfa ):integer;    {查找id在符号表中的位置}
     754     var i,j : integer;        { locate if in table }
     755     begin
     756       i := level;
     757       tab[0].name := id;  { sentinel }
     758       repeat
     759         j := btab[display[i]].last;
     760         while tab[j].name <> id do
     761           j := tab[j].link;
     762         i := i - 1;
     763       until ( i < 0 ) or ( j <> 0 );
     764       if j = 0    {符号没找到,说明之前没声明,报0号错误}
     765       then error(0);
     766       loc := j
     767     end { loc } ;
     768 
     769   procedure entervariable;    {变量登陆符号表的过程}
     770     begin
     771       if sy = ident
     772       then begin
     773              enter( id, vvariable );
     774              insymbol
     775            end
     776       else error(2)
     777     end { entervariable };
     778 
     779   procedure constant( fsys: symset; var c: conrec );    {处理程序中出现的常量,变量c负责返回该常量的类型和值}
     780     var x, sign : integer;
     781     begin
     782       c.tp := notyp;
     783       c.i := 0;
     784       test( constbegsys, fsys, 50 );
     785       if sy in constbegsys    {如果第一个sym是常量开始的符号,才往下继续分析}
     786       then begin    {根据不同的符号执行不同的操作,目的就是返回正确的c}
     787              if sy = charcon    {对字符常量}
     788              then begin
     789                     c.tp := chars;    {类型是char}
     790                     c.i := inum;    {inum存储该字符的ascii码值}
     791                     insymbol    {获取下一个sym}
     792                   end
     793              else begin
     794                   sign := 1;    {不是符号常量}
     795                   if sy in [plus, minus]
     796                   then begin
     797                          if sy = minus    
     798                          then sign := -1;    {负号变符号}
     799                          insymbol
     800                        end;
     801                   if sy = ident    {遇到了标识符}
     802                   then begin
     803                          x := loc(id);    {找到当前id在表中的位置}
     804                          if x <> 0    {找到了}
     805                          then
     806                            if tab[x].obj <> konstant    {如果id对应的符号种类不是常量,报错}
     807                            then error(25)
     808                            else begin
     809                                   c.tp := tab[x].typ;    {获得常量类型}
     810                                   if c.tp = reals    {对实数和整数采取不同的赋值方法}
     811                                   then c.r := sign*rconst[tab[x].adr]
     812                                   else c.i := sign*tab[x].adr
     813                                 end;
     814                          insymbol
     815                        end
     816                   else if sy = intcon    {遇到整数}
     817                        then begin
     818                               c.tp := ints;    {存type存值}
     819                               c.i := sign*inum;
     820                               insymbol
     821                             end
     822                   else if sy = realcon    {遇到实数}
     823                         then begin
     824                                c.tp := reals;
     825                                c.r := sign*rnum;
     826                                insymbol
     827                              end
     828                   else skip(fsys,50)    {跳过无用符号}
     829                 end;
     830                 test(fsys,[],6)
     831            end
     832     end { constant };
     833 
     834 procedure typ( fsys: symset; var tp: types; var rf,sz:integer );    {处理类型说明,返回当前关键词的类型,在符号表中的位置,以及需要占用存储空间的大小}
     835     var eltp : types;    {元素类型}
     836         elrf, x : integer;    
     837         elsz, offset, t0, t1 : integer;
     838 
     839     procedure arraytyp( var aref, arsz: integer );    {处理数组类型的子过程}
     840       var eltp : types;        {记录元素的类型,pascal中一个数组的所有元素的类型必须相同}
     841          low, high : conrec;    {记录数组编号(index)的上下界}
     842          elrf, elsz: integer;    {记录ref和size方便返回}
     843       begin
     844         constant( [colon, rbrack, rparent, ofsy] + fsys, low );    {获得数组编号的下界}
     845         if low.tp = reals    {如果下界类型为实型}
     846         then begin
     847                error(27);    {报27号错误}
     848                low.tp := ints;    {类型为整型}
     849                low.i := 0    {数值设为0}
     850              end;
     851         if sy = colon    {下界后面跟'..',类型是colon,constant结束后读入了下一个sym}
     852         then insymbol    {获得下一个sym}
     853         else error(13);    {如果后面跟的不是..,报13号错误}
     854         constant( [rbrack, comma, rparent, ofsy ] + fsys, high );    {获取数组下表上界}
     855         if high.tp <> low.tp    {上下界类型不同报错,也就是说上界也必须是整型}
     856         then begin
     857                error(27);    {报27号错误}
     858                high.i := low.i    {容错,是使得上界等于下界}
     859              end;
     860         enterarray( low.tp, low.i, high.i );    {将数组的信息录入到atab中}
     861         aref := a;    {获取当前数组在atab中的位置}
     862         if sy = comma    {后面接逗号,说明需要建立多维数组}
     863         then begin
     864                insymbol;    {读取下一个字符}
     865                eltp := arrays;    {数组中的每个元素类型都是数组}
     866                arraytyp( elrf, elsz )    {递归调用arraytyp处理数组元素}
     867              end
     868         else begin
     869                if sy = rbrack    {遇到右中括号,则index部分声明完毕}
     870                then insymbol    {获取下一个sym}
     871                else begin
     872                       error(12);    {缺少右中括号}
     873                       if sy = rparent    {如果是右括号}
     874                       then insymbol        {容错}
     875                     end;
     876                if sy = ofsy        {获取到了of关键字}
     877                then insymbol    {获取下一个sym}
     878                else error(8);    {没有of报8号错}
     879                typ( fsys, eltp, elrf, elsz )    {处理当前的符号类型}
     880              end;
     881              with atab[aref] do    {记录当前数组的信息}
     882                begin
     883                  arsz := (high-low+1) * elsz;    {计算该数组需要占用的存储空间}
     884                  size := arsz;    {记录该数组需要占用的存储空间}
     885                  eltyp := eltp;    {记录数组的元素类型}
     886                  elref := elrf;    {记录数组在atab中登陆的位置}
     887                  elsize := elsz        {记录每个元素的大小}
     888                end
     889       end { arraytyp };
     890     begin { typ  }    {类型处理过程开始}
     891       tp := notyp;    {用以存储变量的类型}
     892       rf := 0;    {用以记录符号在符号表中的位置}
     893       sz := 0;    {用以储存该类型的大小}
     894       test( typebegsys, fsys, 10 );    {测试当前符号是否是数组声明的开始符号,如果不是则报10号错误}
     895       if sy in typebegsys    {如果是数组声明的开始符号}
     896       then begin
     897              if sy = ident    {如果现在的符号是标识符}
     898              then begin
     899                     x := loc(id);    {查找id在符号表中的位置}
     900                     if x <> 0        {如果找到了}
     901                     then with tab[x] do    {对其对应表项进行操作}
     902                            if obj <> typel    {标识符的种类不是'种类'(typel)}
     903                            then error(29)    {报29号错,因为声明一个变量需要先标明其类型}
     904                            else begin
     905                                   tp := typ;    {获得其代表的类型(char,int,real..)}
     906                                   rf := ref;    {获得其在符号表中的位置}
     907                                   sz := adr;    {获得其在运行栈中分配的储存单元的相对地址}
     908                                   if tp = notyp    {如果未定义类型}
     909                                   then error(30)    {报30号错}
     910                                 end;
     911                     insymbol    {获得下一个sym}
     912                   end
     913              else if sy = arraysy    {如果遇到的是数组元素,即声明开头为'array'}
     914                   then begin
     915                          insymbol;    {获得下一个sym}
     916                          if sy = lbrack    {数组元素声明应该从左中括号开始,即表明数组的大小/维度}
     917                          then insymbol    {获取下一个sym}
     918                          else begin    {如果不是左中括号开始}
     919                                 error(11);    {报11号错误,说明左括号发生错误}
     920                                 if sy = lparent    {如果找到了左括号,可能是用户输入错误,报错后做容错处理}
     921                                 then insymbol    {获取下一个sym}
     922                               end;
     923                          tp := arrays;    {当前类型设置为数组类型}
     924                          arraytyp(rf,sz)    {获得数组在atab表中的登陆位置,和数组的大小}
     925                          end
     926              else begin { records }    {否则一定是record的类型,因为typebegsys中只包含ident,arraysy和recordsy三种类型}
     927                     insymbol;    {获取下一个sym}
     928                     enterblock;    {登陆子程序}
     929                     tp := records;    {当前类型设置为records类型}
     930                     rf := b;    {rf指向当前过程在block表中的位置}
     931                     if level = lmax    {如果当前嵌套层次已经是最大层次了,即不能产生更深的嵌套}
     932                     then fatal(5);    {报5号严重错误并终止程序}
     933                     level := level + 1;    {如果还能嵌套,声明程序成功,block的层次是当前层次+1}
     934                     display[level] := b;    {设置当前层次的display区.建立分层次索引}
     935                     offset := 0;
     936                     while not ( sy in fsys - [semicolon,comma,ident]+ [endsy] ) do    {end之前都是记录类型变量内的变量声明}
     937                       begin { field section }    {开始处理record内部的成员变量}
     938                         if sy = ident    {如果遇到的是标识符}
     939                         then begin
     940                                t0 := t;    {获得当前tab指针的位置}
     941                                entervariable;    {变量入表}
     942                                while sy = comma do    {同种变量之间通过逗号分隔,未遇到分号则继续读入}
     943                                  begin
     944                                    insymbol;    {获得下一个sym}
     945                                    entervariable    {继续变量入表的过程}
     946                                  end;
     947                                if sy = colon    {遇到了冒号,说明这类的变量声明结束了,冒号后面跟变量的类型}
     948                                then insymbol    {获取sym}
     949                                else error(5);    {如果没有遇到逗号或者冒号,则抛出5号错误}
     950                                t1 := t;        {记录当前tab栈顶符号的位置,至此t0到t1的符号表中并没有填写typ,ref和adr}
     951                                typ( fsys + [semicolon, endsy, comma,ident], eltp, elrf,elsz );    {递归调用typ来处理记录类型的成员变量,确定各成员的类型,ref和adr(注意对于不同的类型,ref和adr可能表示不同的意义)}
     952                                while t0 < t1 do    {填写t0到t1中信息缺失的部分,需要注意的是t0~t1都是同一类型的变量,因此size大小是相同的}
     953                                begin
     954                                  t0 := t0 + 1;    {指针上移}
     955                                  with tab[t0] do    {修改当前表项}
     956                                    begin
     957                                      typ := eltp;    {给typ赋值,eltp来之上面递归调用的typ语句}
     958                                      ref := elrf;    {给ref赋值}
     959                                      normal := true;    {给normal标记赋值,所有normal的初值都是false}
     960                                      adr := offset;    {记录该变量相对于起始地址的位移}
     961                                      offset := offset + elsz    {获得下一变量的其实地址}
     962                                    end
     963                                end
     964                              end; { sy = ident }
     965                         if sy <> endsy    {遇到end说明成员声明已经结束了}
     966                         then begin
     967                                if sy = semicolon    {end后面需要接分号}
     968                                then insymbol    {获取下一个sym}
     969                                else begin    {如果接的不是分号}
     970                                       error(14);    {先报个错}
     971                                       if sy = comma    {如果是逗号做容错处理}
     972                                       then insymbol    {然后获取下一个sym类型}
     973                                     end;
     974                                     test( [ident,endsy, semicolon],fsys,6 )    {检验当前符号是否合法}
     975                              end
     976                       end; { field section }
     977                     btab[rf].vsize := offset;    {offset存储了当前的局部变量,参数以及display区所占的空间总数,将其记录下来}
     978                     sz := offset;    {储存其占用空间总数}
     979                     btab[rf].psize := 0;    {该程序块的参数占用空间设为0,因为record类型并不是真正的过程变量,没有参数}
     980                     insymbol;    {后去下一个sym}
     981                     level := level - 1    {record声明结束后退出当前层次}
     982                   end; { record }
     983              test( fsys, [],6 )    {检查当前sym是否合法}
     984            end;
     985       end { typ };
     986 
     987   procedure parameterlist; { formal parameter list }    {处理过程或函数说明中的形参,将形参登陆到符号表}
     988     var tp : types;    {记录类型}
     989         valpar : boolean;    {记录当前参数是否为值形参(valueparameter)}
     990         rf, sz, x, t0 : integer;
     991     begin
     992       insymbol;    {获得下一个sym}
     993       tp := notyp;    {初始化类型}
     994       rf := 0;    {初始化符号表位置}
     995       sz := 0;    {初始化元素大小}
     996       test( [ident, varsy], fsys+[rparent], 7 );    {检验当前符号是否合法}
     997       while sy in [ident, varsy] do    {如果当前的符号是标识符或者var关键字}
     998         begin
     999           if sy <> varsy    {如果是var关键字}
    1000           then valpar := true    {将valpar标识符设置为真}
    1001           else begin
    1002                  insymbol;    {如果不是标识符,获取下一个sym}
    1003                  valpar := false    {将valpar设置为假}
    1004                end;
    1005           t0 := t;    {记录当前符号表栈顶位置}
    1006           entervariable;    {调用变量入表的子过程,将参数符号放入符号表}
    1007           while sy = comma do    {如果识别到逗号,说明还有同类型的参数,继续放入符号表}
    1008             begin
    1009               insymbol;    {获取下一个sym}
    1010               entervariable;    {将当前sym放入符号表}
    1011             end;
    1012           if sy = colon    {如果识别到冒号,开始处理类型}
    1013           then begin
    1014                  insymbol;    {获取下一个sym,这里应当是类型}
    1015                  if sy <> ident    {如果不是标识符}
    1016                  then error(2)    {报2号错误}
    1017                  else begin
    1018                         x := loc(id);    {如果是标识符,则寻找其在符号表中的位置}
    1019                         insymbol;    {获取下一个sym}
    1020                         if x <> 0    {如果在符号表中找到了sym}
    1021                         then with tab[x] do    {对当前表项做操作}
    1022                           if obj <> typel    {如果当前的符号不是类型标识符}
    1023                           then error(29)    {报29号错误}
    1024                           else begin
    1025                                  tp := typ;    {获取参数的类型}
    1026                                  rf := ref;    {获取参数在当前符号表的位置}
    1027                                  if valpar    {如果是值形参}
    1028                                  then sz := adr    {sz获得当前形参在符号表中的位置}
    1029                                  else sz := 1    {否则将sz置为1}
    1030                                end;
    1031                       end;
    1032                  test( [semicolon, rparent], [comma,ident]+fsys, 14 )    {检验当前符号是否合法,不合法报14号错误}
    1033                  end
    1034           else error(5);    {如果不是分号,报5号错误}
    1035           while t0 < t do    {t0~t都是同一类型将上面处理的符号中的属性填写完整}
    1036             begin
    1037               t0 := t0 + 1;    {获得刚才读到的第一个参数}
    1038               with tab[t0] do    {对当前符号表中的符号做操作}
    1039                 begin
    1040                   typ := tp;    {设置当前符号的类型}
    1041                   ref := rf;    {设置当前符号在符号表中的位置}
    1042                   adr := dx;    {设置形参的相对地址}
    1043                   lev := level;    {设置形参的level}
    1044                   normal := valpar;    {设置当前变量的normal标记}
    1045                   dx := dx + sz    {更新位移量}
    1046                 end
    1047             end;
    1048             if sy <> rparent    {如果声明结束之后不是右括号}
    1049             then begin
    1050                    if sy = semicolon    {而是分号,说明还有需要声明的参数}
    1051                    then insymbol    {获取下一个sym}
    1052                    else begin
    1053                           error(14);    {否则报14号错误}
    1054                           if sy = comma    {如果是逗号,做容错处理}
    1055                           then insymbol    {接受下一个sym}
    1056                         end;
    1057                         test( [ident, varsy],[rparent]+fsys,6)    {检查下面的符号是否是标识符或者变量声明,均不是则报6号错误}
    1058                  end
    1059         end { while };
    1060       if sy = rparent    {参数声明结束后应当用右括号结尾}
    1061       then begin
    1062              insymbol;    {获取下一个符号}
    1063              test( [semicolon, colon],fsys,6 )    {声明结束后用分号结束或使用冒号声明返回值类型,如果不是这两种符号,报6号错误}
    1064            end
    1065       else error(4)    {不是右括号结尾,报错}
    1066     end { parameterlist };
    1067 
    1068 
    1069   procedure constdec;    {常量声明的处理过程}
    1070     var c : conrec;
    1071     begin
    1072       insymbol;    {获取下一个sym}
    1073       test([ident], blockbegsys, 2 );    {检查是不是标识符}
    1074       while sy = ident do    {当获得的是标志符的是否做循环}
    1075         begin
    1076           enter(id, konstant);    {入表,类型为konstant表示常量}
    1077           insymbol;
    1078           if sy = eql    {等号}
    1079           then insymbol
    1080           else begin
    1081                  error(16);
    1082                  if sy = becomes    {赋值符号容错}
    1083                  then insymbol
    1084                end;
    1085           constant([semicolon,comma,ident]+fsys,c);    {获得常量的类型和数值}
    1086           tab[t].typ := c.tp;    {填表}
    1087           tab[t].ref := 0;        {常量ref为0}
    1088           if c.tp = reals
    1089           then begin    {实型和整型的操作不同}
    1090                  enterreal(c.r);
    1091                  tab[t].adr := c1;    {实常量的adr保存了其在rconst表中的登陆的位置}
    1092               end
    1093           else tab[t].adr := c.i;
    1094           testsemicolon
    1095         end
    1096     end { constdec };
    1097 
    1098   procedure typedeclaration;    {处理类型声明}
    1099     var tp: types;
    1100         rf, sz, t1 : integer;
    1101     begin
    1102       insymbol;
    1103       test([ident], blockbegsys,2 );    {检查获取到的是不是标识符}
    1104       while sy = ident do    {对于是标识符的情况进行操作}
    1105         begin
    1106           enter(id, typel);    {类型的名称的类型入表}
    1107           t1 := t;        {获得符号表顶部指针}
    1108           insymbol;    
    1109           if sy = eql    {获取等号}
    1110           then insymbol
    1111           else begin
    1112                  error(16);
    1113                  if sy = becomes    {赋值符号容错}
    1114                  then insymbol    
    1115                end;
    1116           typ( [semicolon,comma,ident]+fsys, tp,rf,sz );    {获得类型变量的类型,在符号表中的位置以及占用空间的大小}
    1117           with tab[t1] do    {将返回值填表}
    1118             begin
    1119               typ := tp;    
    1120               ref := rf;
    1121               adr := sz
    1122             end;
    1123           testsemicolon
    1124         end
    1125     end { typedeclaration };
    1126 
    1127   procedure variabledeclaration;    {处理变量声明}
    1128     var tp : types;
    1129         t0, t1, rf, sz : integer;
    1130     begin
    1131       insymbol;
    1132       while sy = ident do
    1133         begin
    1134           t0 := t;
    1135           entervariable;
    1136           while sy = comma do
    1137             begin
    1138               insymbol;
    1139               entervariable;    {调用变量入表的程序}
    1140             end;
    1141           if sy = colon
    1142           then insymbol
    1143           else error(5);
    1144           t1 := t;
    1145           typ([semicolon,comma,ident]+fsys, tp,rf,sz );    {获得类型,地址和大小}
    1146           while t0 < t1 do
    1147             begin
    1148               t0 := t0 + 1;
    1149               with tab[t0] do    {填表}
    1150                 begin
    1151                   typ := tp;
    1152                   ref := rf;
    1153                   lev := level;
    1154                   adr := dx;
    1155                   normal := true;
    1156                   dx := dx + sz
    1157                 end
    1158             end;
    1159           testsemicolon
    1160         end
    1161     end { variabledeclaration };
    1162 
    1163   procedure procdeclaration;    {处理过程声明}
    1164     var isfun : boolean;
    1165     begin
    1166       isfun := sy = funcsy;
    1167       insymbol;
    1168       if sy <> ident
    1169       then begin
    1170              error(2);
    1171              id :='          '
    1172            end;
    1173       if isfun    {函数和过程使用不同的kind类型}
    1174       then enter(id,funktion)
    1175       else enter(id,prozedure);
    1176       tab[t].normal := true;
    1177       insymbol;
    1178       block([semicolon]+fsys, isfun, level+1 );    {过程的处理直接调用block}
    1179       if sy = semicolon
    1180       then insymbol
    1181       else error(14);
    1182       emit(32+ord(isfun)) {exit}    {推出过程/函数}
    1183     end { proceduredeclaration };
    1184 
    1185 
    1186 procedure statement( fsys:symset );
    1187     var i : integer;
    1188 
    1189   procedure expression(fsys:symset; var x:item); forward;    {处理表达式的子程序,由x返回结果,forward使得selector可以调用expression}
    1190     procedure selector(fsys:symset; var v:item);    {处理结构变量:数组下标或记录成员变量}
    1191     var x : item;
    1192         a,j : integer;
    1193     begin { sy in [lparent, lbrack, period] }    {当前的符号应该是左括号,做分号或句号之一}
    1194       repeat
    1195         if sy = period    {如果当前的符号是句号,因为引用成员变量的方式为'记录名.成员名',因此识别到'.'之后应该开始处理后面的结构名称}
    1196         then begin
    1197                insymbol; { field selector }    {处理成员变量}
    1198                if sy <> ident    {如果获取到的不是标识符}
    1199                then error(2)    {报2号错误}
    1200                else begin    
    1201                       if v.typ <> records    {如果处理的不是记录类型}
    1202                       then error(31)    {报31号错误}
    1203                       else begin { search field identifier }    {在符号表中寻找类型标识符}
    1204                              j := btab[v.ref].last;        {获得该结构体在符号表中最后一个符号的位置}
    1205                              tab[0].name := id;    {暂存当前符号的id}
    1206                              while tab[j].name <> id do    {在符号表中寻找当前符号}
    1207                                j := tab[j].link;    {没对应上则继续向前找}
    1208                              if j = 0    {在当前层(记录中)没找到对应的符号,符号未声明}
    1209                              then error(0);    {报0号错误}
    1210                              v.typ := tab[j].typ;    {找到了则获取属性}
    1211                              v.ref := tab[j].ref;    {记录其所在的btab位置}
    1212                              a := tab[j].adr;    {记录该成员变量相对于记录变量起始地址的位移}
    1213                              if a <> 0    {如果位移不为零}
    1214                              then emit1(9,a)    {生成一条指令来计算此位移}
    1215                            end;
    1216                       insymbol    {获取下一个sym}
    1217                     end
    1218              end
    1219         else begin { array selector }    {处理数组下表}
    1220                if sy <> lbrack    {如果下表不是左括号开头}
    1221                then error(11);    {报11号错误}
    1222                repeat    {循环,针对多维数组}
    1223                  insymbol;    {获取下一个sym}
    1224                  expression( fsys+[comma,rbrack],x);    {递归调用处理表达式的过程处理数组下标,获得返回结果保存到x中}
    1225                  if v.typ <> arrays    {如果传入的类型不是数组}
    1226                  then error(28)    {报22号错误}
    1227                  else begin    
    1228                         a := v.ref;    {获得该数组在atab中的位置}
    1229                         if atab[a].inxtyp <> x.typ    {如果传入的下标和数组规定的下标类型不符}
    1230                         then error(26)    {报26号错误}
    1231                         else if atab[a].elsize = 1    {如果是变量形参}
    1232                              then emit1(20,a)    {进行寻址操作}
    1233                         else emit1(21,a);    {对值形参也进行寻址操作}
    1234                         v.typ := atab[a].eltyp;    {获得当前数组元素的类型}
    1235                         v.ref := atab[a].elref    {获得数组元素在atab中的位置}
    1236                       end
    1237                until sy <> comma;    {如果读到的不是逗号,说明没有更高维的数组}
    1238                if sy = rbrack    {如果读到右中括号}
    1239                then insymbol    {读取下一个sym}
    1240                else begin
    1241                       error(12);    {没读到右中括号则报12号错误}
    1242                       if sy = rparent    {如果读到了右括号,做容错处理}
    1243                       then insymbol    {读取下一个sym}
    1244                    end
    1245              end
    1246       until not( sy in[lbrack, lparent, period]);    {循环直到所有子结构(数组下标或者记录)都被识别完位置}
    1247       test( fsys,[],6)    {检测当前的符号是否合法}
    1248     end { selector };
    1249 
    1250     procedure call( fsys: symset; i:integer );    {处理非标准过程和函数调用的方法,其中i表示需要调用的过程或函数名在符号表中的位置}
    1251        var x : item;    
    1252           lastp,cp,k : integer;
    1253        begin
    1254         emit1(18,i); { mark stack }    {生成标记栈指令,传入被调用过程或函数在tab表中的位置,建立新的内务信息区}
    1255         lastp := btab[tab[i].ref].lastpar;    {记录当前过程或函数最后一个参数在符号表中的位置}
    1256         cp := i;    {记录被调用过程在符号表中的位置}
    1257         if sy = lparent    {如果是识别到左括号}
    1258         then begin { actual parameter list }    {开始处理参数}
    1259                repeat    {开始循环}
    1260                  insymbol;    {获取参数的sym}
    1261                  if cp >= lastp    {如果当前符号的位置小于最后一个符号的位置,说明还有参数没有处理,反之是错误的}
    1262                  then error(39)    {报39号错误}
    1263                  else begin    {开始处理参数}
    1264                         cp := cp + 1;    {将cp指针向上移动一格}
    1265                         if tab[cp].normal    {如果normal的值为真,即如果传入的是值形参或者其他参数}
    1266                         then begin { value parameter }    {开始处理值形参}
    1267                                expression( fsys+[comma, colon,rparent],x);    {递归调用处理表达式的过程处理参数}
    1268                                if x.typ = tab[cp].typ    {如果参数的类型和符号表中规定的类型相同}
    1269                                then begin
    1270                                       if x.ref <> tab[cp].ref    {如果表达式指向的btab和符号表中所记录的btab不同}
    1271                                       then error(36)    {报36号错误}
    1272                                       else if x.typ = arrays    {如果遇到了数组类型}
    1273                                            then emit1(22,atab[x.ref].size)    {生成装入块指令,将实参表达式的值或地址放到预留的参数单元中}
    1274                                       else if x.typ = records    {如果遇到了记录类型}
    1275                                            then emit1(22,btab[x.ref].vsize)    {同样生成装入块指令完成操作,只是细节有所不同}
    1276                                     end
    1277                                else if ( x.typ = ints ) and ( tab[cp].typ = reals )    {如果表达式的类型是整型,但是要求是输入的是实型参数}
    1278                                     then emit1(26,0)    {生成26号指令,进行类型转换}
    1279                                else if x.typ <> notyp    {如果没有获取到表达式的类型}
    1280                                     then error(36);    {报36号错,参数类型异常}
    1281                              end
    1282                         else begin { variable parameter }    {如果是变量形参}
    1283                                if sy <> ident    {变量形参应该先识别到标识符}
    1284                                then error(2)    {若不是标识符开头,报2号错}
    1285                                else begin    {如果是标识符开头}
    1286                                       k := loc(id);    {找到当前id在表中的位置}
    1287                                       insymbol;    {获取下一个符号}
    1288                                       if k <> 0        {在符号表中找到了id}
    1289                                       then begin
    1290                                              if tab[k].obj <> vvariable    {如果获取到的形参类型不是变量类型}
    1291                                              then error(37);    {报37号错}
    1292                                              x.typ := tab[k].typ;    {否则记录当前的符号类型}
    1293                                              x.ref := tab[k].ref;    {记录当前参数指向的btab的位置}
    1294                                              if tab[k].normal    {如果是值形参}
    1295                                              then emit2(0,tab[k].lev,tab[k].adr)    {将变量地址装入栈顶}
    1296                                              else emit2(1,tab[k].lev,tab[k].adr);    {将变量的值装入栈顶(对应变量形参)}
    1297                                              if sy in [lbrack, lparent, period]    {如果后面跟的可以是做中括号(数组下标),左括号(容错)或句号(对应记录)}
    1298                                              then 
    1299                                               selector(fsys+[comma,colon,rparent],x);    {调用分析子结构的过程来处理}
    1300                                              if ( x.typ <> tab[cp].typ ) or ( x.ref <> tab[cp].ref )    {如果参数的符号类型或所在表中的位置和符号表中记录的不同}
    1301                                              then error(36)    {报36号错误}
    1302                                           end
    1303                                    end
    1304                             end {variable parameter }
    1305                       end;
    1306                  test( [comma, rparent],fsys,6)    {检查当前sym是否合法}
    1307                until sy <> comma;    {直到出现的不是都好,说明参数声明结束了}
    1308                if sy = rparent    {补齐右括号}
    1309                then insymbol    {获取下一个sym}
    1310                else error(4)    {没有右括号,报4号错误}
    1311              end;
    1312         if cp < lastp    {如果当前符号的位置没有到达最后一个符号的位置}
    1313         then error(39); { too few actual parameters }    {报39号错误,说明符号没有处理完}
    1314         emit1(19,btab[tab[i].ref].psize-1 );    {生成19号CAL指令,正式开始过程或函数调用}
    1315         if tab[i].lev < level    {如果符号所在层次小于当前层次}
    1316         then emit2(3,tab[i].lev, level )    {更新display区}
    1317       end { call };
    1318 
    1319     function resulttype( a, b : types) :types;    {处理整型或实型两个操作数运算时的类型转换}
    1320       begin
    1321         if ( a > reals ) or ( b > reals )    {如果有操作数超过上限报33号错误}
    1322         then begin
    1323                error(33);
    1324                resulttype := notyp    {返回nottype}
    1325              end
    1326         else if ( a = notyp ) or ( b = notyp )    {两个操作数中有一个nottype}
    1327              then resulttype := notyp    {结果返回nottype}
    1328              else if a = ints    {第一个是int}
    1329                   then if b = ints    {第二个也是int}
    1330                        then resulttype := ints    {返回int类型}
    1331                        else begin
    1332                               resulttype := reals;    {否则结果为real}
    1333                               emit1(26,1)    {并对a进行类型转化}
    1334                            end
    1335                   else begin
    1336                          resulttype := reals;    {第一个是real,则返回real}
    1337                          if b = ints    {如果第二个是int}
    1338                          then emit1(26,0)    {对b进行转化}
    1339                       end
    1340       end { resulttype } ;
    1341 
    1342     procedure expression( fsys: symset; var x: item );    {处理表达式的过程,返回类型和在表中的位置}
    1343       var y : item;
    1344          op : symbol;
    1345 
    1346       procedure simpleexpression( fsys: symset; var x: item );
    1347         var y : item;
    1348             op : symbol;
    1349 
    1350         procedure term( fsys: symset; var x: item );
    1351           var y : item;
    1352               op : symbol;
    1353 
    1354           procedure factor( fsys: symset; var x: item );{处理因子的子过程}
    1355             var i,f : integer;
    1356 
    1357             procedure standfct( n: integer );    {处理标准函数的子过程,传入标准函数的编号n,执行不同的操作}
    1358               var ts : typset;    {类型集合}
    1359               begin  { standard function no. n }
    1360                 if sy = lparent    {如果当前的符号是左括号}
    1361                 then insymbol    {获取下一个sym}
    1362                 else error(9);    {如果当前符号不是左括号,报9号错误提示左括号出错}
    1363                 if n < 17    {如果标准函数的编号小于17}
    1364                 then begin
    1365                        expression( fsys+[rparent], x );    {递归调用处理表达式的过程来处理参数,x是获取的参数的信息}
    1366                        case n of    {根据不同的函数编号来进行操作}
    1367                        { abs, sqr } 0,2: begin    {如果是0,2号操作,完成求绝对值和平方}
    1368                                            ts := [ints, reals];    {定义符号集合为整型和实型}
    1369                                            tab[i].typ := x.typ;    {函数的返回值类型}
    1370                                            if x.typ = reals    {如果参数类型是实数}
    1371                                            then n := n + 1    {对应的函数标号+1}
    1372                                      end;
    1373                        { odd, chr } 4,5: ts := [ints];    {如果是4,5号操作,那么完成判奇和ascii码转化成字符的操作,要求传入的是脏呢挂车能}
    1374                        { odr }        6: ts := [ints,bools,chars];    {6号操作允许类型是整型,布尔型或者字符型}
    1375                        { succ,pred } 7,8 : begin    {对于7,8号操作}
    1376                                              ts := [ints, bools,chars];    {允许参数类型是整型,布尔型或者字符型}
    1377                                              tab[i].typ := x.typ    {记录类型}
    1378                                        end;
    1379                        { round,trunc } 9,10,11,12,13,14,15,16:    {数学运算}
    1380                        { sin,cos,... }     begin
    1381                                              ts := [ints,reals];    {允许参数类型为整型,实型}
    1382                                              if x.typ = ints    {如果为整型}
    1383                                              then emit1(26,0)    {先将整型转成实型}
    1384                                        end;
    1385                      end; { case }
    1386                      if x.typ in ts    {如果函数的类型符合要求的符号集}
    1387                      then emit1(8,n)    {调用8号指令,生成标准函数}
    1388                      else if x.typ <> notyp    {如果x的类型未定义}
    1389                           then error(48);    {报48号错误,类型错误}
    1390                    end
    1391                 else begin { n in [17,18] }    {如果编号是17或者18,即判断输入是否结束}
    1392                        if sy <> ident    {传入的首先应当是标识符}
    1393                        then error(2)    {不是标识符报错}
    1394                        else if id <> 'input    '    {如果对应的id不是'input    '}
    1395                             then error(0)    {报0号错误,未知id}
    1396                             else insymbol;    {没错的话读取下一个sym}
    1397                        emit1(8,n);    {生成标准函数}
    1398                      end;
    1399                 x.typ := tab[i].typ;    {记录返回值类型}
    1400                 if sy = rparent    {识别是否遇到右括号}
    1401                 then insymbol    {获取下一个sym,标准函数处理过程结束}
    1402                 else error(4)    {如果没有识别到右括号,报4号错误}
    1403               end { standfct } ;
    1404             begin { factor }    {因子分析程序开始}
    1405               x.typ := notyp;    {初始化返回值类型}
    1406               x.ref := 0;        {初始化返回的位置指针}
    1407               test( facbegsys, fsys,58 );    {检查当前的符号是否是合法的因子开始符号}
    1408               while sy in facbegsys do    {当当前的符号是因子的开始符号时}
    1409                 begin
    1410                   if sy = ident    {如果识别到标识符}
    1411                   then begin
    1412                          i := loc(id);    {获取当前标识符在符号表中的位置保存到i}
    1413                          insymbol;        {获取下一个sym}
    1414                          with tab[i] do    {对当前符号对应的表项进行操作}
    1415                            case obj of    {对于不同的obj属性执行不同的操作}
    1416                              konstant: begin    {如果是常量类型}
    1417                                          x.typ := typ;    {返回值的类型就设置为表中记录的typ}
    1418                                          x.ref := 0;    {索引值设置为0}
    1419                                          if x.typ = reals    {如果是实数类型的常量}
    1420                                          then emit1(25,adr)    {将实数装入数据栈,注意实数常量的adr对应着其在rconst实常量表中的位置}
    1421                                          else emit1(24,adr)    {如果是整型直接存入栈顶即可}
    1422                                      end;
    1423                              vvariable:begin    {如果换成变量类型}
    1424                                              x.typ := typ;    {获得需要返回类型}
    1425                                              x.ref := ref;    {获得需要返回地址}
    1426                                          if sy in [lbrack, lparent,period]    {如果标识符后面跟的是左方括号,左括号或者是句号,说明该变量存在子结构}
    1427                                          then begin
    1428                                                 if normal    {如果是实形参}
    1429                                                 then f := 0    {取地址}
    1430                                                 else f := 1;    {否则是变量形参,取值并放到栈顶}
    1431                                                 emit2(f,lev,adr);    {生成对应的代码}
    1432                                                 selector(fsys,x);    {处理子结构}
    1433                                                 if x.typ in stantyps    {如果是标准类型}    {存疑}
    1434                                                 then emit(34)    {将该值放到栈顶}
    1435                                               end
    1436                                          else begin    {如果变量没有层次结构}
    1437                                                 if x.typ in stantyps    {如果是标准类型}
    1438                                                 then if normal    {如果是值形参}
    1439                                                      then f := 1    {执行取值操作}
    1440                                                      else f := 2    {否则间接取值}
    1441                                                 else if normal    {如果不是标准类型但是是值形参}
    1442                                                      then f := 0    {取地址操作}
    1443                                                 else f := 1;    {如果既不是标准类型又不是值形参,执行取值操作}
    1444                                                 emit2(f,lev,adr)    {生成对应指令}
    1445                                              end
    1446                                        end;
    1447                              typel,prozedure: error(44);    {如果是类型类型或者过程类型,报44号类型错误}
    1448                              funktion: begin    {如果是函数符号}
    1449                                          x.typ := typ;    {记录类型}
    1450                                          if lev <> 0    {如果层次不为0,即不是标准函数}
    1451                                          then call(fsys,i)    {调用call函数来处理函数调用}
    1452                                          else standfct(adr)    {如果层次为零,调用标准函数}
    1453                                        end
    1454                            end { case,with }
    1455                        end
    1456                   else if sy in [ charcon,intcon,realcon ]    {如果符号的类型是字符类型,整数类型或者实数类型}
    1457                        then begin
    1458                               if sy = realcon    {对于实数类型}
    1459                               then begin
    1460                                      x.typ := reals;    {将返回的type设置为实型}
    1461                                      enterreal(rnum);    {将该实数放入实数表,rnum存有实数的值}
    1462                                      emit1(25,c1)    {将实常量表中第c1个(也就是刚刚放进去的)元素放入栈顶}
    1463                                    end
    1464                               else begin
    1465                                      if sy = charcon    {对于字符类型}
    1466                                      then x.typ := chars    {记录返回的类型是字符型}
    1467                                      else x.typ := ints;    {否则肯定是整形啦,要不进不来这个分支}
    1468                                      emit1(24,inum)    {装入字面变量,可以看出字符型装的是ascii码值}
    1469                                    end;
    1470                               x.ref := 0;    {返回的ref设置为0}
    1471                               insymbol    {获取下一个sym}
    1472                             end
    1473                    else if sy = lparent        {如果符号的类型是左括号}
    1474                         then begin
    1475                                insymbol;    {获取下一个sym}
    1476                                expression(fsys + [rparent],x);    {调用处理表达式的递归子程序处理括号中的表达式}
    1477                                if sy = rparent    {如果遇到了右括号}    
    1478                                then insymbol    {获取下一个sym}
    1479                                else error(4)    {没有右括号报4号错误}
    1480                              end
    1481                    else if sy = notsy    {如果符号的类型未定义}
    1482                        then begin
    1483                               insymbol;    {获取下一个sym}
    1484                               factor(fsys,x);    {递归调用因子的分析子程序}
    1485                               if x.typ = bools    {如果返回的类型是布尔型}
    1486                               then emit(35)        {生成逻辑非指令}
    1487                               else if x.typ <> notyp    {如果因子的类型依旧未定义}
    1488                                    then error(32)    {生成32指令,退出过程}
    1489                            end;
    1490                   test(fsys,facbegsys,6)    {检查当前符号是否合法}
    1491                 end { while }
    1492             end { factor };
    1493           begin { term   }    {开始处理项(term)}
    1494             factor( fsys + [times,rdiv,idiv,imod,andsy],x);    {调用因子的分析程序开分析每一个因子项}
    1495             while sy in [times,rdiv,idiv,imod,andsy] do    {如果因子后面跟符号'*''/''div''mod''and',说明后面还有因子,进入循环}
    1496               begin
    1497                 op := sy;    {运算符是sy所代表的类型}
    1498                 insymbol;    {获取下一个sym}
    1499                 factor(fsys+[times,rdiv,idiv,imod,andsy],y );    {继续调用因子分析程序来分析因子,获得第二个运算数存为y}
    1500                 if op = times    {如果遇到了乘号}
    1501                 then begin
    1502                        x.typ := resulttype(x.typ, y.typ);    {求出计算之后结果的类型}
    1503                        case x.typ of
    1504                          notyp: ;    {未定义类型不干事儿}
    1505                          ints : emit(57);    {整数生成整数乘指令}
    1506                          reals: emit(60);    {实数生成实数乘指令}
    1507                        end
    1508                      end
    1509                 else if op = rdiv    {除法运算}
    1510                      then begin
    1511                             if x.typ = ints
    1512                             then begin
    1513                                    emit1(26,1);    {整型转实型}
    1514                                    x.typ := reals;
    1515                                  end;
    1516                             if y.typ = ints
    1517                             then begin
    1518                                    emit1(26,0);    {整型转实型}
    1519                                    y.typ := reals;
    1520                                  end;
    1521                             if (x.typ = reals) and (y.typ = reals)
    1522                             then emit(61)    {实型除法}
    1523                             else begin
    1524                                    if( x.typ <> notyp ) and (y.typ <> notyp)
    1525                                    then error(33);
    1526                                    x.typ := notyp
    1527                                  end
    1528                           end
    1529                      else if op = andsy    {与运算}
    1530                           then begin
    1531                                  if( x.typ = bools )and(y.typ = bools)    {必须两个运算数都是布尔类型}
    1532                                  then emit(56)    {生成逻辑与运算}
    1533                                  else begin
    1534                                         if( x.typ <> notyp ) and (y.typ <> notyp)    {类型不对报错,提示应该是布尔值}
    1535                                         then error(32);
    1536                                         x.typ := notyp
    1537                                       end
    1538                                end
    1539                           else begin { op in [idiv,imod] }
    1540                                  if (x.typ = ints) and (y.typ = ints)
    1541                                  then if op = idiv    {如果是除法}
    1542                                         then emit(58)    {生成除法运算的代码}
    1543                                       else emit(59)    {否则生成取模运算的代码}
    1544                                  else begin
    1545                                         if ( x.typ <> notyp ) and (y.typ <> notyp)
    1546                                         then error(34);    {类型出错报错}
    1547                                         x.typ := notyp
    1548                                       end
    1549                                end
    1550               end { while }
    1551           end { term };
    1552         begin { simpleexpression }    {开始处理简单表达式}
    1553           if sy in [plus,minus]    {获得的是加减号}
    1554           then begin
    1555                  op := sy;    {记录运算符}
    1556                  insymbol;
    1557                  term( fsys+[plus,minus],x);    {处理项}
    1558                  if x.typ > reals    {类型是 bools, chars, arrays, records}
    1559                  then error(33)        {由于不是算数运算类型,报错}
    1560                  else if op = minus    {如果是减号}
    1561                       then emit(36)    {去相反数}
    1562                end
    1563           else term(fsys+[plus,minus,orsy],x);    
    1564           while sy in [plus,minus,orsy] do
    1565             begin
    1566               op := sy;
    1567               insymbol;
    1568               term(fsys+[plus,minus,orsy],y);
    1569               if op = orsy    {如果是or关键字}
    1570               then begin
    1571                      if ( x.typ = bools )and(y.typ = bools)    {操作数限定为bool}
    1572                      then emit(51)    {生成OR指令}
    1573                      else begin
    1574                             if( x.typ <> notyp) and (y.typ <> notyp)    {类型不对报错}
    1575                             then error(32);
    1576                             x.typ := notyp
    1577                           end
    1578                    end
    1579               else begin
    1580                      x.typ := resulttype(x.typ,y.typ);    
    1581                      case x.typ of
    1582                        notyp: ;
    1583                        ints: if op = plus    {整数加减}
    1584                              then emit(52)
    1585                              else emit(53);
    1586                        reals:if op = plus    {实数加减}
    1587                              then emit(54)
    1588                              else emit(55)
    1589                      end { case }
    1590                    end
    1591             end { while }
    1592           end { simpleexpression };
    1593       begin { expression  }
    1594         simpleexpression(fsys+[eql,neq,lss,leq,gtr,geq],x);
    1595         if sy in [ eql,neq,lss,leq,gtr,geq]    {判别多种数值比较符号}
    1596         then begin
    1597                op := sy;
    1598                insymbol;
    1599                simpleexpression(fsys,y);    {获得第二个简单表达式的值}
    1600                if(x.typ in [notyp,ints,bools,chars]) and (x.typ = y.typ)    {整型,布尔和字符都可以借用整型的运算}{notyp为什么出现?}
    1601                then case op of    {根据不同的符号来生成不同的PCODE}
    1602                       eql: emit(45);
    1603                       neq: emit(46);
    1604                       lss: emit(47);
    1605                       leq: emit(48);
    1606                       gtr: emit(49);
    1607                       geq: emit(50);
    1608                     end
    1609                else begin
    1610                       if x.typ = ints
    1611                       then begin
    1612                              x.typ := reals;
    1613                              emit1(26,1)
    1614                            end
    1615                       else if y.typ = ints
    1616                            then begin
    1617                                   y.typ := reals;
    1618                                   emit1(26,0)
    1619                                 end;
    1620                       if ( x.typ = reals)and(y.typ=reals)    {对于实数同样生成不同的PCODE}
    1621                       then case op of
    1622                              eql: emit(39);
    1623                              neq: emit(40);
    1624                              lss: emit(41);
    1625                              leq: emit(42);
    1626                              gtr: emit(43);
    1627                              geq: emit(44);
    1628                            end
    1629                       else error(35)
    1630                     end;
    1631                x.typ := bools
    1632              end
    1633       end { expression };
    1634 
    1635     procedure assignment( lv, ad: integer );    {处理赋值语句的过程}
    1636       var x,y: item;
    1637           f  : integer;
    1638       begin   { tab[i].obj in [variable,prozedure] }    {当且仅当当前符号表的目标类型为变量或者过程型时}
    1639         x.typ := tab[i].typ;    
    1640         x.ref := tab[i].ref;
    1641         if tab[i].normal
    1642         then f := 0
    1643         else f := 1;
    1644         emit2(f,lv,ad);
    1645         if sy in [lbrack,lparent,period]
    1646         then selector([becomes,eql]+fsys,x);    {处理下标}
    1647         if sy = becomes    {赋值符号}
    1648         then insymbol
    1649         else begin
    1650                error(51);
    1651                if sy = eql    {等号容错}
    1652                then insymbol
    1653              end;
    1654         expression(fsys,y);    {获得赋值符号右边的值}
    1655         if x.typ = y.typ
    1656         then if x.typ in stantyps
    1657              then emit(38)    {完成赋值操作}
    1658              else if x.ref <> y.ref
    1659                   then error(46)
    1660              else if x.typ = arrays    {数组类型需要拷贝块}
    1661                   then emit1(23,atab[x.ref].size)    {拷贝atab中的项}
    1662                   else emit1(23,btab[x.ref].vsize)    {拷贝btab中的记录项}
    1663         else if(x.typ = reals )and (y.typ = ints)
    1664         then begin
    1665                emit1(26,0);
    1666                emit(38)
    1667              end
    1668         else if ( x.typ <> notyp ) and ( y.typ <> notyp )
    1669              then error(46)
    1670       end { assignment };
    1671 
    1672     procedure compoundstatement;
    1673       begin
    1674         insymbol;
    1675         statement([semicolon,endsy]+fsys);
    1676         while sy in [semicolon]+statbegsys do
    1677           begin
    1678             if sy = semicolon
    1679             then insymbol
    1680             else error(14);
    1681             statement([semicolon,endsy]+fsys)
    1682           end;
    1683         if sy = endsy
    1684         then insymbol
    1685         else error(57)
    1686       end { compoundstatement };
    1687 
    1688     procedure ifstatement;
    1689       var x : item;
    1690           lc1,lc2: integer;
    1691       begin
    1692         insymbol;
    1693         expression( fsys+[thensy,dosy],x);
    1694         if not ( x.typ in [bools,notyp])
    1695         then error(17);
    1696         lc1 := lc;
    1697         emit(11);  { jmpc }
    1698         if sy = thensy
    1699         then insymbol
    1700         else begin
    1701                error(52);
    1702                if sy = dosy
    1703                then insymbol
    1704              end;
    1705         statement( fsys+[elsesy]);
    1706         if sy = elsesy
    1707         then begin
    1708                insymbol;
    1709                lc2 := lc;
    1710                emit(10);
    1711                code[lc1].y := lc;
    1712                statement(fsys);
    1713                code[lc2].y := lc
    1714              end
    1715         else code[lc1].y := lc
    1716       end { ifstatement };
    1717 
    1718     procedure casestatement;{case语句的处理过程}
    1719       var x : item;
    1720       i,j,k,lc1 : integer;    {定义一系列临时变量}
    1721       casetab : array[1..csmax]of    {csmax表示case个数的最大限度}
    1722                      packed record
    1723                        val,lc : index    {index表示}
    1724                      end;
    1725           exittab : array[1..csmax] of integer;
    1726 
    1727       procedure caselabel;    {处理case语句中的标号,将各标号对应的目标代码入口地址填入casetab表中,并检查标号有无重复定义}
    1728         var lab : conrec;
    1729          k : integer;
    1730         begin
    1731           constant( fsys+[comma,colon],lab );    {因为标签都是常量,这里调用处理常量的过程来获得常量的值,存于lab}
    1732           if lab.tp <> x.typ    {如果获得的标签类型和变量的类型不同}
    1733           then error(47)    {报label类型错误}
    1734           else if i = csmax    {如果可以声明的case达到了最大限度}
    1735                then fatal(6)    {报6号严重错误,程序终止}
    1736                else begin
    1737                       i := i+1;    {移动case表的指针,声明新的case}
    1738                        k := 0;    {用来检查标号是否重复定义的变量}
    1739                       casetab[i].val := lab.i;    {保存新case的值}
    1740                       casetab[i].lc := lc;        {记录新case生成代码的位置}
    1741                       repeat
    1742                         k := k+1
    1743                       until casetab[k].val = lab.i;    {扫一遍已经声明的label,看有没有重复声明}
    1744                       if k < i    {重复声明}
    1745                       then error(1); { multiple definition }    {报1号错误}
    1746                     end
    1747         end { caselabel };
    1748 
    1749       procedure onecase;    {用来处理case语句的一个分支}
    1750         begin
    1751           if sy in constbegsys    {确定当前符号是常量的类型集合}
    1752           then begin
    1753                  caselabel;    {获取一个标签}
    1754                  while sy = comma do    {如果有逗号说明是一个case对应多个标签的情况}
    1755                    begin
    1756                      insymbol;    {继续获取标签的label}
    1757                      caselabel    {继续处理}
    1758                    end;
    1759                  if sy = colon    {读到冒号,说明label声明结束了}
    1760                  then insymbol    {获取下一个sym}
    1761                  else error(5);    {没读到冒号,报5号错误}
    1762                  statement([semicolon,endsy]+fsys);    {递归调用statement来处理冒号之后需要执行的程序}
    1763                  j := j+1;    {用来记录当前case对应exittab的位置}
    1764                  exittab[j] := lc;    {记录当前case分支结束的代码位置,即下面将要生成的跳转指令的位置}
    1765                  emit(10)    {生成一条跳转指令来结束这一case分支}
    1766                end
    1767           end { onecase };
    1768       begin  { casestatement  }
    1769         insymbol;    {获取下一个sym}
    1770         i := 0;
    1771         j := 0;
    1772         expression( fsys + [ofsy,comma,colon],x );    {递归调用处理表达式的方式先获得当前表达式的属性,即case后面变量的类型}
    1773         if not( x.typ in [ints,bools,chars,notyp ])    {如果当前的表达式不是整数,布尔型,字符型或未定义类型}
    1774         then error(23);    {报23号错误,case类型错误}
    1775         lc1 := lc;    {记录当前PCODE代码的位置指针}
    1776         emit(12); {jmpx}    {生成SWT代码,查找情况表,注意这里暂时没有给定跳转的地址}
    1777         if sy = ofsy    {如果接着读到了of关键字}
    1778         then insymbol    {获取下一个sym}
    1779         else error(8);    {丢失of关键字的情况报8号错}
    1780         onecase;    {调用onecase方法处理}
    1781         while sy = semicolon do    {遇到了分号,说明还有更多的case分支}
    1782           begin
    1783             insymbol;    {获取下一个sym}
    1784             onecase        {处理下一个sym}
    1785           end;
    1786         code[lc1].y := lc;    {此时确定了情况表的开始地址,回填给之前声明的SWT代码,确保其能够成功跳转}
    1787         for k := 1 to i do    {便利所有case分支}
    1788           begin    {建立情况表}
    1789             emit1( 13,casetab[k].val);    {建立查找的值}
    1790             emit1( 13,casetab[k].lc);    {给出对应的跳转地址}
    1791           end;
    1792         emit1(10,0);    {生成JMP代码,说明情况表结束}
    1793         for k := 1 to j do    {给定每个case分支退出之后的跳转地址}
    1794           code[exittab[k]].y := lc;    {现在的lc指向情况表结束之后的位置,将各分支的结束跳转地址指向这里}
    1795         if sy = endsy    {如果遇到了end关键字}
    1796         then insymbol    {读取下一个sym,case处理完毕}
    1797         else error(57)    {否则报57号错误}
    1798       end { casestatement };
    1799 
    1800     procedure repeatstatement;{处理repeat语句的处理过程}
    1801       var x : item;        {用来获取返回值}
    1802           lc1: integer;    {用来记录repeat的开始位置}
    1803       begin
    1804         lc1 := lc;    {保存repeat当开始时的代码地址}
    1805         insymbol;    {获取下一个sym}
    1806         statement( [semicolon,untilsy]+fsys);    {调用statement递归子程序来处理循环体中的语句}
    1807         while sy in [semicolon]+statbegsys do    {如果遇到了分号或者statement的开始符号,则说明循环体中还有语句没有处理完}
    1808           begin
    1809             if sy = semicolon    {如果确实是分号}
    1810             then insymbol    {获取下一个sym}
    1811             else error(14);    {报14号错,提示分号错误}
    1812             statement([semicolon,untilsy]+fsys)    {处理循环体中的下一条语句}
    1813           end;
    1814         if sy = untilsy    {如果遇到了until关键字}
    1815         then begin
    1816                insymbol;    {获取下一个sym,即循环条件}
    1817                expression(fsys,x);    {处理该表达式,获得其类型}
    1818                if not(x.typ in [bools,notyp] )    {如果不是未定义类型或者布尔型的表达式}
    1819                then error(17);    {报17号错误,提示需要布尔型表达式}
    1820                emit1(11,lc1);    {生成一条条件跳转指令,如果表达式的值是假的,则跳转回repeat开始的位置重新执行一遍}
    1821              end
    1822         else error(53)    {没找到until,报53号错}
    1823       end { repeatstatement };
    1824 
    1825     procedure whilestatement;    {处理while循环的过程}
    1826       var x : item;        
    1827           lc1,lc2 : integer;
    1828       begin
    1829         insymbol;
    1830         lc1 := lc;
    1831         expression( fsys+[dosy],x);
    1832         if not( x.typ in [bools, notyp] )
    1833         then error(17);
    1834         lc2 := lc;
    1835         emit(11);
    1836         if sy = dosy
    1837         then insymbol
    1838         else error(54);
    1839         statement(fsys);
    1840         emit1(10,lc1);
    1841         code[lc2].y := lc
    1842      end { whilestatement };
    1843 
    1844     procedure forstatement;    {处理for循环语句}
    1845       var   cvt : types;
    1846             x :  item;
    1847             i,f,lc1,lc2 : integer;
    1848      begin
    1849         insymbol;    {获取下一个sym}
    1850         if sy = ident    {如果获取到的是标识符}
    1851         then begin
    1852                i := loc(id);    {找到这个标识符在符号表中登陆的位置,实际上是计数变量}
    1853                insymbol;    {获取下一个sym}
    1854                if i = 0    {如果没有找到这个标识符}
    1855                then cvt := ints    {计数变量类型默认为整形}
    1856                else if tab[i].obj = vvariable    {如果对应的这个标识符对应符号的大类是变量类型}
    1857                     then begin
    1858                            cvt := tab[i].typ;    {计数变量类型就设置为这个变量的类型}
    1859                            if not tab[i].normal    {如果是变量形参,即变量存储的是值而非地址}
    1860                            then error(37)        {报37号错}
    1861                            else emit2(0,tab[i].lev, tab[i].adr );    {如果不是变量类型, 获取该符号的地址}
    1862                            if not ( cvt in [notyp, ints, bools, chars])    {如果获取到计数变量的类型不是未定义,整型,布尔型,字符型}
    1863                                    then error(18)    {报18号错误}
    1864                          end
    1865                     else begin    {如果符号的类型也不是变量}
    1866                            error(37);    {报37号错误}
    1867                            cvt := ints    {将计数变量类型设置为整型}    {仅仅是给个值,还是有什么意义?}
    1868                          end
    1869              end
    1870         else skip([becomes,tosy,downtosy,dosy]+fsys,2);    {跳过无用符号}
    1871         if sy = becomes    {如果识别到了赋值符号}
    1872         then begin
    1873                insymbol;    {获取下一个sym}
    1874                expression( [tosy, downtosy,dosy]+fsys,x);    {递归调用处理表达式的方式来获得表达式的值和类型}
    1875                if x.typ <> cvt    {如果获取到的表达式类型和计数变量的符号类型不相同}
    1876                then error(19);    {报19号错误}
    1877              end
    1878         else skip([tosy, downtosy,dosy]+fsys,51);    {未识别到赋值符号,则继续执行}
    1879         f := 14;    {生成指令的编号,暂存14号}
    1880         if sy in [tosy,downtosy]    {如果当前符号是to关键字或者downto关键字,其中to是每次循环变量自加一,downto是每次循环变量自减一}
    1881         then begin
    1882                if sy = downtosy    {如果是down}
    1883                then f := 16;    {}
    1884                insymbol;        {获取下一个sym}
    1885                expression([dosy]+fsys,x);    {调用处理表达式的递归子程序处理括号中的表达式}
    1886                if x.typ <> cvt    {如果表达式的类型和左边的计数变量不同}
    1887                then error(19)    {报19号错误}
    1888              end
    1889         else skip([dosy]+fsys,55);    {跳过直到do之前的代码段}
    1890         lc1 := lc;    {记录下句F1U指令的位置}
    1891         emit(f);    {生成F1U或F1D指令,进行循环体的入口测试}
    1892         if sy = dosy    {如果当前符号是do关键字}
    1893         then insymbol    {获取下一个sym}
    1894         else error(54);    {没找到do,报54号错误}
    1895         lc2 := lc;    {获取循环体开始代码的位置}
    1896         statement(fsys);    {递归调用statement来处理循环体语句}
    1897         emit1(f+1,lc2);        {结束时生成F2U或F2D指令}
    1898         code[lc1].y := lc    {将之前产生的F1U的跳转地址回传回去}
    1899      end { forstatement };
    1900 
    1901     procedure standproc( n: integer );
    1902       var i,f : integer;
    1903       x,y : item;
    1904       begin
    1905         case n of
    1906           1,2 : begin { read }
    1907                   if not iflag
    1908                   then begin
    1909                          error(20);
    1910                          iflag := true
    1911                        end;
    1912                   if sy = lparent
    1913                   then begin
    1914                          repeat
    1915                            insymbol;
    1916                            if sy <> ident
    1917                            then error(2)
    1918                            else begin
    1919                                   i := loc(id);
    1920                                   insymbol;
    1921                                   if i <> 0
    1922                                   then if tab[i].obj <> vvariable
    1923                                        then error(37)
    1924                                        else begin
    1925                                               x.typ := tab[i].typ;
    1926                                               x.ref := tab[i].ref;
    1927                                               if tab[i].normal
    1928                                               then f := 0
    1929                                               else f := 1;
    1930                                               emit2(f,tab[i].lev,tab[i].adr);
    1931                                               if sy in [lbrack,lparent,period]
    1932                                               then selector( fsys+[comma,rparent],x);
    1933                                               if x.typ in [ints,reals,chars,notyp]
    1934                                               then emit1(27,ord(x.typ))
    1935                                               else error(41)
    1936                                            end
    1937                                end;
    1938                            test([comma,rparent],fsys,6);
    1939                          until sy <> comma;
    1940                          if sy = rparent
    1941                          then insymbol
    1942                          else error(4)
    1943                        end;
    1944                   if n = 2
    1945                   then emit(62)
    1946                 end;
    1947           3,4 : begin { write }
    1948                   if sy = lparent
    1949                   then begin
    1950                          repeat
    1951                            insymbol;
    1952                            if sy = stringcon
    1953                            then begin
    1954                                   emit1(24,sleng);
    1955                                   emit1(28,inum);
    1956                                   insymbol
    1957                                 end
    1958                            else begin
    1959                                   expression(fsys+[comma,colon,rparent],x);
    1960                                   if not( x.typ in stantyps )
    1961                                   then error(41);
    1962                                   if sy = colon
    1963                                   then begin
    1964                                          insymbol;
    1965                                          expression( fsys+[comma,colon,rparent],y);
    1966                                          if y.typ <> ints
    1967                                          then error(43);
    1968                                          if sy = colon
    1969                                          then begin
    1970                                                 if x.typ <> reals
    1971                                                 then error(42);
    1972                                                 insymbol;
    1973                                                 expression(fsys+[comma,rparent],y);
    1974                                                 if y.typ <> ints
    1975                                                 then error(43);
    1976                                                 emit(37)
    1977                                               end
    1978                                          else emit1(30,ord(x.typ))
    1979                                        end
    1980                              else emit1(29,ord(x.typ))
    1981                            end
    1982                          until sy <> comma;
    1983                          if sy = rparent
    1984                          then insymbol
    1985                          else error(4)
    1986                        end;
    1987                   if n = 4
    1988                   then emit(63)
    1989                 end; { write }
    1990         end { case };
    1991       end { standproc } ;
    1992     begin { statement }
    1993       if sy in statbegsys+[ident]
    1994       then case sy of
    1995              ident : begin
    1996                        i := loc(id);
    1997                        insymbol;
    1998                        if i <> 0
    1999                        then case tab[i].obj of
    2000                               konstant,typel : error(45);
    2001                               vvariable:       assignment( tab[i].lev,tab[i].adr);
    2002                               prozedure:       if tab[i].lev <> 0
    2003                                                then call(fsys,i)
    2004                                                else standproc(tab[i].adr);
    2005                               funktion:        if tab[i].ref = display[level]
    2006                                                then assignment(tab[i].lev+1,0)
    2007                                                else error(45)
    2008                             end { case }
    2009                      end;
    2010              beginsy : compoundstatement;
    2011              ifsy    : ifstatement;
    2012              casesy  : casestatement;
    2013              whilesy : whilestatement;
    2014              repeatsy: repeatstatement;
    2015              forsy   : forstatement;
    2016            end;  { case }
    2017       test( fsys, [],14);
    2018     end { statement };
    2019   begin  { block }
    2020     dx := 5;    {dx是变量存储分配的索引,预设为5是为了给内务信息区留出空间}
    2021     prt := t;    {获取当前符号表的位置}
    2022     if level > lmax    {如果当前子程序的层次已经超过了允许的最大层次}
    2023     then fatal(5);    {报5号错误}
    2024     test([lparent,colon,semicolon],fsys,14);    {检查当前的符号是否是左括号,冒号,分号中的一个,不是报14号错误}
    2025     enterblock;
    2026     prb := b;
    2027     display[level] := b;
    2028     tab[prt].typ := notyp;
    2029     tab[prt].ref := prb;
    2030     if ( sy = lparent ) and ( level > 1 )
    2031     then parameterlist;
    2032     btab[prb].lastpar := t;
    2033     btab[prb].psize := dx;
    2034     if isfun
    2035     then if sy = colon
    2036          then begin
    2037                 insymbol; { function type }
    2038                 if sy = ident
    2039                 then begin
    2040                        x := loc(id);
    2041                        insymbol;
    2042                        if x <> 0
    2043                        then if tab[x].typ in stantyps
    2044                             then tab[prt].typ := tab[x].typ
    2045                             else error(15)
    2046                      end
    2047                 else skip( [semicolon]+fsys,2 )
    2048               end
    2049          else error(5);
    2050     if sy = semicolon
    2051     then insymbol
    2052     else error(14);
    2053     repeat
    2054       if sy = constsy
    2055       then constdec;
    2056       if sy = typesy
    2057       then typedeclaration;
    2058       if sy = varsy
    2059       then variabledeclaration;
    2060       btab[prb].vsize := dx;
    2061       while sy in [procsy,funcsy] do
    2062         procdeclaration;
    2063       test([beginsy],blockbegsys+statbegsys,56)
    2064     until sy in statbegsys;
    2065     tab[prt].adr := lc;
    2066     insymbol;
    2067     statement([semicolon,endsy]+fsys);
    2068     while sy in [semicolon]+statbegsys do
    2069       begin
    2070         if sy = semicolon
    2071         then insymbol
    2072         else error(14);
    2073         statement([semicolon,endsy]+fsys);
    2074       end;
    2075     if sy = endsy
    2076     then insymbol
    2077     else error(57);
    2078     test( fsys+[period],[],6 )
    2079   end { block };
    2080 
    2081 
    2082 
    2083 procedure interpret;
    2084   var ir : order ;         { instruction buffer }    {当前的指令}
    2085       pc : integer;        { program counter }    {类似于指令寄存器}
    2086       t  : integer;        { top stack index }    {栈顶指针}
    2087       b  : integer;        { base index }    {基址地址}
    2088       h1,h2,h3: integer;    {临时变量}
    2089       lncnt,ocnt,blkcnt,chrcnt: integer;     { counters }
    2090       ps : ( run,fin,caschk,divchk,inxchk,stkchk,linchk,lngchk,redchk );    {各种错误信息标志}
    2091            fld: array [1..4] of integer;  { default field widths }
    2092            display : array[0..lmax] of integer;
    2093            s  : array[1..stacksize] of   { blockmark:     }
    2094             record
    2095               case cn : types of        { s[b+0] = fct result }
    2096                 ints : (i: integer );   { s[b+1] = return adr }
    2097                 reals :(r: real );      { s[b+2] = static link }
    2098                 bools :(b: boolean );   { s[b+3] = dynamic link }
    2099                 chars :(c: char )       { s[b+4] = table index }
    2100             end;
    2101 
    2102   procedure dump;
    2103     var p,h3 : integer;
    2104     begin
    2105       h3 := tab[h2].lev;
    2106       writeln(psout);
    2107       writeln(psout);
    2108       writeln(psout,'       calling ', tab[h2].name );
    2109       writeln(psout,'         level ',h3:4);
    2110       writeln(psout,' start of code ',pc:4);
    2111       writeln(psout);
    2112       writeln(psout);
    2113       writeln(psout,' contents of display ');
    2114       writeln(psout);
    2115       for p := h3 downto 0 do
    2116         writeln(psout,p:4,display[p]:6);
    2117       writeln(psout);
    2118       writeln(psout);
    2119       writeln(psout,' top of stack  ',t:4,' frame base ':14,b:4);
    2120       writeln(psout);
    2121       writeln(psout);
    2122       writeln(psout,' stack contents ':20);
    2123       writeln(psout);
    2124       for p := t downto 1 do
    2125         writeln( psout, p:14, s[p].i:8);
    2126       writeln(psout,'< = = = >':22)
    2127     end; {dump }
    2128     {以下为不同PCODE所对应的操作}
    2129   procedure inter0;
    2130     begin
    2131       case ir.f of
    2132         0 : begin { load addrss }    {取地址操作,LDA}
    2133               t := t + 1;    {栈顶指针上移}
    2134               if t > stacksize    {如果超过了栈的大小上限}
    2135               then ps := stkchk    {将ps设置为stkchk,以记录错误类型}
    2136               else s[t].i := display[ir.x]+ir.y    {完成取值, 实际地址 = level起始地址+位移地址,放到栈顶}
    2137             end;
    2138         1 : begin  { load value }    {取值操作,LOD}
    2139               t := t + 1;    
    2140               if t > stacksize    {检查栈是否溢出,溢出则报错}
    2141               then ps := stkchk
    2142               else s[t] := s[display[ir.x]+ir.y]    {由于传入的是地址,完成取值后将值放到栈顶}
    2143             end;
    2144         2 : begin  { load indirect }    {间接取值,LDI}
    2145               t := t + 1;
    2146               if t > stacksize
    2147               then ps := stkchk
    2148               else s[t] := s[s[display[ir.x]+ir.y].i]
    2149             end;
    2150         3 : begin  { update display }    {更新display,DIS}
    2151               h1 := ir.y;
    2152               h2 := ir.x;
    2153               h3 := b;
    2154               repeat
    2155                 display[h1] := h3;    
    2156                 h1 := h1-1;    {level-1}
    2157                 h3 := s[h3+2].i
    2158               until h1 = h2
    2159             end;
    2160         8 : case ir.y of    {标准函数,ir.y是函数的编号,FCT}
    2161               0 : s[t].i := abs(s[t].i);    {整数x求绝对值}
    2162               1 : s[t].r := abs(s[t].r);    {实数x求绝对值}
    2163               2 : s[t].i := sqr(s[t].i);    {整数x求平方}
    2164               3 : s[t].r := sqr(s[t].r);    {实数x求平方}
    2165               4 : s[t].b := odd(s[t].i);    {整数x判奇偶性,计数返回1}
    2166               5 : s[t].c := chr(s[t].i);    {ascii码x转化为字符char}
    2167               6 : s[t].i := ord(s[t].c);    {字符x转化为ascii码}
    2168               7 : s[t].c := succ(s[t].c);    {求字符x的后继字符,比如'a'的后继是'b'}
    2169               8 : s[t].c := pred(s[t].c);    {求字符x的前导字符}
    2170               9 : s[t].i := round(s[t].r);    {求x的四舍五入}
    2171               10 : s[t].i := trunc(s[t].r);    {求实数x的整数部分}
    2172               11 : s[t].r := sin(s[t].r);    {求正弦sin(x),注意x为实数弧度}
    2173               12 : s[t].r := cos(s[t].r);    {求余弦sin(x),注意x为实数弧度}
    2174               13 : s[t].r := exp(s[t].r);    {求e^x,x为实数}
    2175               14 : s[t].r := ln(s[t].r);    {求自然对数ln(x),x为实数}
    2176               15 : s[t].r := sqrt(s[t].r);    {实数x开方}
    2177               16 : s[t].r := arcTan(s[t].r);    {反三角函数arctan(x)}
    2178               17 : begin
    2179                      t := t+1;    {}
    2180                      if t > stacksize
    2181                      then ps := stkchk
    2182                      else s[t].b := eof(prd)    {判断输入有没有读完}
    2183                    end;
    2184               18 : begin
    2185                      t := t+1;
    2186                      if t > stacksize
    2187                      then ps := stkchk
    2188                      else s[t].b := eoln(prd)    {判断该行有没有读完}
    2189                    end;
    2190             end;
    2191         9 : s[t].i := s[t].i + ir.y; { offset }    {将栈顶元素加上y,INT}
    2192       end { case ir.y }
    2193     end; { inter0 }
    2194 
    2195 procedure inter1;
    2196     var h3, h4: integer;
    2197 begin
    2198       case ir.f of
    2199         10 : pc := ir.y ; { jump }    {调到第y条指令代码,JMP}
    2200         11 : begin  { conditional jump }    {条件跳转语句,JPC}
    2201                if not s[t].b    {如果栈顶值为假}
    2202                then pc := ir.y;    {跳转到y指令}
    2203                t := t - 1    {退栈}
    2204             end;
    2205         12 : begin { switch }    {转移到y的地址,查找情况表,情况表由一系列f为13的指令构成}
    2206                h1 := s[t].i;    {记录栈顶值}
    2207                t := t-1;    {退栈}
    2208                h2 := ir.y;    {记录需要跳转到的地址}
    2209                h3 := 0;
    2210                repeat
    2211                  if code[h2].f <> 13    {如果操作码不是13,证明跳转到的不是情况表}
    2212                  then begin
    2213                         h3 := 1;
    2214                         ps := caschk
    2215                       end
    2216                  else if code[h2].y = h1
    2217                       then begin
    2218                              h3 := 1;
    2219                              pc := code[h2+1].y
    2220                            end
    2221                       else h2 := h2 + 2
    2222                until h3 <> 0
    2223              end;
    2224         14 : begin { for1up }    {增量步长for循环的初始判断,F1U}
    2225                h1 := s[t-1].i;    {for循环之前需要储存计数变量的地址,初值和终值,这里h1获取的是初值}
    2226                if h1 <= s[t].i    {如果初值小于等于终值}
    2227                then s[s[t-2].i].i := h1    {开始循环,将技术变量的值赋为初值}
    2228                else begin    {否则循环完毕}
    2229                       t := t - 3;    {退栈3格,退去计数变量的地址,初值和终值所占用的空间}
    2230                       pc := ir.y    {跳出循环,注意这里的y是由后方语句回传得到的}
    2231                     end
    2232              end;
    2233         15 : begin { for2up }    {增量步长的结束判断,F2U}
    2234                h2 := s[t-2].i;    {获得计数变量的地址}
    2235                h1 := s[h2].i+1;    {h1为计数变量的值自增一}
    2236                if h1 <= s[t].i    {判断是否还满足循环条件}
    2237                then begin
    2238                       s[h2].i := h1;    {如果满足,将h1赋给计数变量}
    2239                       pc := ir.y    {跳转到循环的开始位置}
    2240                     end
    2241                else t := t-3;    {不满足的情况不做跳转(执行下一条),退栈3格}
    2242              end;
    2243         16 : begin  { for1down }    {减量步长for循环的初始判断,F1U}
    2244                h1 := s[t-1].i;
    2245                if h1 >= s[t].i
    2246                then s[s[t-2].i].i := h1
    2247                else begin
    2248                       pc := ir.y;
    2249                       t := t - 3
    2250                     end
    2251              end;
    2252         17 : begin  { for2down }    {减量步长的结束判断,F2U}
    2253                h2 := s[t-2].i;
    2254                h1 := s[h2].i-1;
    2255                if h1 >= s[t].i
    2256                then begin
    2257                       s[h2].i := h1;
    2258                       pc := ir.y
    2259                     end
    2260                else t := t-3;
    2261              end;
    2262         18 : begin  { mark stack }    {标记栈}
    2263                h1 := btab[tab[ir.y].ref].vsize;    {获得当前过程所需要的栈空间的大小}
    2264                if t+h1 > stacksize    {如果超过上限报错}
    2265                then ps := stkchk
    2266                else begin
    2267                       t := t+5;    {预留内务信息区}
    2268                       s[t-1].i := h1-1;    {次栈顶存放vsize-1}
    2269                       s[t].i := ir.y    {栈顶存放被调用过程在tab表中的位置}
    2270                     end
    2271              end;
    2272         19 : begin  { call }    {过程或函数调用过程}
    2273                h1 := t-ir.y;  { h1 points to base }    {h1指向基址}
    2274                h2 := s[h1+4].i;  { h2 points to tab }    {h2指向过程名在tab表中的位置}
    2275                h3 := tab[h2].lev;    {h3记录当前过程或函数的层次}
    2276                display[h3+1] := h1;    {新建一个层次,并将该层次基址指向当前层次基址}
    2277                h4 := s[h1+3].i+h1;    {DL的值}
    2278                s[h1+1].i := pc;    
    2279                s[h1+2].i := display[h3];
    2280                s[h1+3].i := b;
    2281                for h3 := t+1 to h4 do
    2282                  s[h3].i := 0;
    2283                b := h1;
    2284                t := h4;
    2285                pc := tab[h2].adr;
    2286                if stackdump
    2287                then dump
    2288              end;
    2289       end { case }
    2290     end; { inter1 }
    2291 
    2292   procedure inter2;
    2293     begin
    2294       case ir.f of
    2295         20 : begin   { index1 }
    2296                h1 := ir.y;  { h1 points to atab }
    2297                h2 := atab[h1].low;
    2298                h3 := s[t].i;
    2299                if h3 < h2
    2300                then ps := inxchk
    2301                else if h3 > atab[h1].high
    2302                     then ps := inxchk
    2303                     else begin
    2304                            t := t-1;
    2305                            s[t].i := s[t].i+(h3-h2)
    2306                          end
    2307              end;
    2308         21 : begin  { index }
    2309                h1 := ir.y ; { h1 points to atab }
    2310                h2 := atab[h1].low;
    2311                h3 := s[t].i;
    2312                if h3 < h2
    2313                then ps := inxchk
    2314                else if h3 > atab[h1].high
    2315                     then ps := inxchk
    2316                     else begin
    2317                            t := t-1;
    2318                            s[t].i := s[t].i + (h3-h2)*atab[h1].elsize
    2319                          end
    2320              end;
    2321         22 : begin  { load block }    {装入块,LDB}
    2322                h1 := s[t].i;    {获取栈顶值}
    2323                t := t-1;
    2324                h2 := ir.y+t;    {获取需要分配到的空间位置}
    2325                if h2 > stacksize    {栈空间不足,报错}
    2326                then ps := stkchk
    2327                else while t < h2 do    {将h1指向的块的值装入栈顶}
    2328                       begin
    2329                         t := t+1;
    2330                         s[t] := s[h1];
    2331                         h1 := h1+1
    2332                       end
    2333              end;
    2334         23 : begin  { copy block }
    2335                h1 := s[t-1].i;
    2336                h2 := s[t].i;
    2337                h3 := h1+ir.y;
    2338                while h1 < h3 do
    2339                  begin
    2340                    s[h1] := s[h2];
    2341                    h1 := h1+1;
    2342                    h2 := h2+1
    2343                  end;
    2344                t := t-2
    2345              end;
    2346         24 : begin  { literal }        {装入字面变量,LDC}
    2347                t := t+1;
    2348                if t > stacksize
    2349                then ps := stkchk
    2350                else s[t].i := ir.y    {对于整型变量y直接装入栈顶}
    2351              end;
    2352         25 : begin  { load real }    {读取实数,LDR}
    2353                t := t+1;
    2354                if t > stacksize
    2355                then ps := stkchk
    2356                else s[t].r := rconst[ir.y]    {将实常量表中第i个元素放到数据栈的栈顶}
    2357              end;
    2358         26 : begin  { float }    {整型转实型,FLT}
    2359                h1 := t-ir.y;    {获得符号的地址}
    2360                s[h1].r := s[h1].i    {令实型等于整数部分}
    2361              end;
    2362         27 : begin  { read }
    2363                if eof(prd)
    2364                then ps := redchk
    2365                else case ir.y of
    2366                       1 : read(prd, s[s[t].i].i);
    2367                       2 : read(prd, s[s[t].i].r);
    2368                       4 : read(prd, s[s[t].i].c);
    2369                     end;
    2370                t := t-1
    2371              end;
    2372         28 : begin   { write string }
    2373                h1 := s[t].i;
    2374                h2 := ir.y;
    2375                t := t-1;
    2376                chrcnt := chrcnt+h1;
    2377                if chrcnt > lineleng
    2378                then ps := lngchk;
    2379                repeat
    2380                  write(prr,stab[h2]);
    2381                  h1 := h1-1;
    2382                  h2 := h2+1
    2383                until h1 = 0
    2384              end;
    2385         29 : begin  { write1 }
    2386                chrcnt := chrcnt + fld[ir.y];
    2387                if chrcnt > lineleng
    2388                then ps := lngchk
    2389                else case ir.y of
    2390                       1 : write(prr,s[t].i:fld[1]);
    2391                       2 : write(prr,s[t].r:fld[2]);
    2392                       3 : if s[t].b
    2393                           then write('true')
    2394                           else write('false');
    2395                       4 : write(prr,chr(s[t].i));
    2396                     end;
    2397                t := t-1
    2398              end;
    2399       end { case }
    2400     end; { inter2 }
    2401 
    2402   procedure inter3;
    2403     begin
    2404       case ir.f of
    2405         30 : begin { write2 }
    2406                chrcnt := chrcnt+s[t].i;
    2407                if chrcnt > lineleng
    2408                then ps := lngchk
    2409                else case ir.y of
    2410                       1 : write(prr,s[t-1].i:s[t].i);
    2411                       2 : write(prr,s[t-1].r:s[t].i);
    2412                       3 : if s[t-1].b
    2413                           then write('true')
    2414                           else write('false');
    2415                     end;
    2416                t := t-2
    2417              end;
    2418         31 : ps := fin;
    2419         32 : begin  { exit procedure }    {退出过程,EXP}
    2420                t := b-1;    {退栈}
    2421                pc := s[b+1].i;    {PC指向RA}
    2422                b := s[b+3].i    {获得返回后的base基址,s[b+3]指向DL}
    2423              end;
    2424         33 : begin  { exit function }    {退出函数,EXF}
    2425                t := b;    {退栈,注意要保留函数名}
    2426                pc := s[b+1].i;    {PC指向RA}
    2427                b := s[b+3].i    {获得返回后的base基址,s[b+3]指向DL}
    2428              end;
    2429         34 : s[t] := s[s[t].i];
    2430         35 : s[t].b := not s[t].b;    {逻辑非运算,将栈顶布尔值取反,NOT}
    2431         36 : s[t].i := -s[t].i;        {取整数的相反数操作,MUS}
    2432         37 : begin
    2433                chrcnt := chrcnt + s[t-1].i;
    2434                if chrcnt > lineleng
    2435                then ps := lngchk
    2436                else write(prr,s[t-2].r:s[t-1].i:s[t].i);
    2437                t := t-3
    2438              end;
    2439         38 : begin  { store }    {将栈顶内容存入以次栈顶为地址的单元,STO}
    2440                s[s[t-1].i] := s[t];
    2441                t := t-2
    2442              end;
    2443         39 : begin    {实数相等,EQR}
    2444                t := t-1;
    2445                s[t].b := s[t].r=s[t+1].r
    2446              end;
    2447       end { case }
    2448     end; { inter3 }
    2449 
    2450   procedure inter4;
    2451     begin
    2452       case ir.f of
    2453         40 : begin    {实数不等,NER}
    2454                t := t-1;
    2455                s[t].b := s[t].r <> s[t+1].r
    2456              end;
    2457         41 : begin    {实数小于,LSR}
    2458                t := t-1;
    2459                s[t].b := s[t].r < s[t+1].r
    2460              end;
    2461         42 : begin    {实数小于等于,LER}
    2462                t := t-1;
    2463                s[t].b := s[t].r <= s[t+1].r
    2464              end;
    2465         43 : begin    {实数大于,GTR}
    2466                t := t-1;
    2467                s[t].b := s[t].r > s[t+1].r
    2468              end;
    2469         44 : begin    {实数大于等于,GER}
    2470                t := t-1;
    2471                s[t].b := s[t].r >= s[t+1].r
    2472              end;
    2473         45 : begin    {整数相等,EQL}
    2474                t := t-1;
    2475                s[t].b := s[t].i = s[t+1].i
    2476              end;
    2477         46 : begin    {整型不等,NEQ}
    2478                t := t-1;
    2479                s[t].b := s[t].i <> s[t+1].i
    2480              end;
    2481         47 : begin    {整型小于,LSS}
    2482                t := t-1;
    2483                s[t].b := s[t].i < s[t+1].i
    2484              end;
    2485         48 : begin    {整型小于等于,LEQ}
    2486                t := t-1;
    2487                s[t].b := s[t].i <= s[t+1].i
    2488              end;
    2489         49 : begin    {整型大于,GRT}
    2490                t := t-1;
    2491                s[t].b := s[t].i > s[t+1].i
    2492              end;
    2493       end { case }
    2494     end; { inter4 }
    2495 
    2496   procedure inter5;
    2497     begin
    2498       case ir.f of
    2499         50 : begin    {整型大于等于,GEQ}
    2500                t := t-1;
    2501                s[t].b := s[t].i >= s[t+1].i
    2502              end;
    2503         51 : begin    {OR指令,ORR}
    2504                t := t-1;
    2505                s[t].b := s[t].b or s[t+1].b
    2506              end;
    2507         52 : begin    {整数加,ADD}
    2508                t := t-1;
    2509                s[t].i := s[t].i+s[t+1].i
    2510              end;
    2511         53 : begin    {整数减,SUB}
    2512                t := t-1;
    2513                s[t].i := s[t].i-s[t+1].i
    2514              end;
    2515         54 : begin    {实数加,ADR}
    2516                t := t-1;
    2517                s[t].r := s[t].r+s[t+1].r;
    2518              end;    
    2519         55 : begin    {实数减,SUR}
    2520                t := t-1;
    2521                s[t].r := s[t].r-s[t+1].r;
    2522              end;
    2523         56 : begin    {与运算,AND}
    2524                t := t-1;
    2525                s[t].b := s[t].b and s[t+1].b
    2526              end;
    2527         57 : begin    {整数乘,MUL}
    2528                t := t-1;
    2529                s[t].i := s[t].i*s[t+1].i
    2530              end;
    2531         58 : begin    {整数除法,DIV}
    2532                t := t-1;
    2533                if s[t+1].i = 0
    2534                then ps := divchk
    2535                else s[t].i := s[t].i div s[t+1].i
    2536              end;
    2537         59 : begin    {取模运算,MOD}
    2538                t := t-1;
    2539                if s[t+1].i = 0
    2540                then ps := divchk
    2541                else s[t].i := s[t].i mod s[t+1].i
    2542              end;
    2543       end { case }
    2544     end; { inter5 }
    2545 
    2546   procedure inter6;
    2547     begin
    2548       case ir.f of
    2549         60 : begin    {实数乘}
    2550                t := t-1;
    2551                s[t].r := s[t].r*s[t+1].r;
    2552              end;
    2553         61 : begin    {实数除}
    2554                t := t-1;
    2555                s[t].r := s[t].r/s[t+1].r;
    2556              end;
    2557         62 : if eof(prd)
    2558              then ps := redchk
    2559              else readln;
    2560         63 : begin
    2561                writeln(prr);
    2562                lncnt := lncnt+1;
    2563                chrcnt := 0;
    2564                if lncnt > linelimit
    2565                then ps := linchk
    2566              end
    2567       end { case };
    2568     end; { inter6 }
    2569   begin { interpret }
    2570     s[1].i := 0;
    2571     s[2].i := 0;
    2572     s[3].i := -1;
    2573     s[4].i := btab[1].last;
    2574     display[0] := 0;
    2575     display[1] := 0;
    2576     t := btab[2].vsize-1;
    2577     b := 0;
    2578     pc := tab[s[4].i].adr;
    2579     lncnt := 0;
    2580     ocnt := 0;
    2581     chrcnt := 0;
    2582     ps := run;
    2583     fld[1] := 10;
    2584     fld[2] := 22;
    2585     fld[3] := 10;
    2586     fld[4] := 1;
    2587     repeat
    2588       ir := code[pc];
    2589       pc := pc+1;
    2590       ocnt := ocnt+1;
    2591       case ir.f div 10 of
    2592         0 : inter0;
    2593         1 : inter1;
    2594         2 : inter2;
    2595         3 : inter3;
    2596         4 : inter4;
    2597         5 : inter5;
    2598         6 : inter6;
    2599       end; { case }
    2600     until ps <> run;
    2601 
    2602     if ps <> fin
    2603     then begin
    2604            writeln(prr);
    2605            write(prr, ' halt at', pc :5, ' because of ');
    2606            case ps of    {根据不同的错误信息来进行报错}
    2607              caschk  : writeln(prr,'undefined case');
    2608              divchk  : writeln(prr,'division by 0');
    2609              inxchk  : writeln(prr,'invalid index');
    2610              stkchk  : writeln(prr,'storage overflow');
    2611              linchk  : writeln(prr,'too much output');
    2612              lngchk  : writeln(prr,'line too long');
    2613              redchk  : writeln(prr,'reading past end or file');
    2614            end;
    2615            h1 := b;
    2616            blkcnt := 10;    { post mortem dump }
    2617            repeat
    2618              writeln( prr );
    2619              blkcnt := blkcnt-1;
    2620              if blkcnt = 0
    2621              then h1 := 0;
    2622              h2 := s[h1+4].i;
    2623              if h1 <> 0
    2624              then writeln( prr, '',tab[h2].name, 'called at', s[h1+1].i:5);
    2625              h2 := btab[tab[h2].ref].last;
    2626              while h2 <> 0 do
    2627                with tab[h2] do
    2628                  begin
    2629                    if obj = vvariable
    2630                    then if typ in stantyps
    2631                         then begin
    2632                                write(prr,'',name,'=');
    2633                                if normal
    2634                                then h3 := h1+adr
    2635                                else h3 := s[h1+adr].i;
    2636                                case typ of
    2637                                  ints : writeln(prr,s[h3].i);
    2638                                  reals: writeln(prr,s[h3].r);
    2639                                  bools: if s[h3].b
    2640                                         then writeln(prr,'true')
    2641                                         else writeln(prr,'false');
    2642                                  chars: writeln(prr,chr(s[h3].i mod 64 ))
    2643                                end
    2644                              end;
    2645                    h2 := link
    2646                  end;
    2647              h1 := s[h1+3].i
    2648            until h1 < 0
    2649          end;
    2650     writeln(prr);
    2651     writeln(prr,ocnt,' steps');
    2652   end; { interpret }
    2653 
    2654 
    2655 
    2656 procedure setup;    {程序运行前的准备过程}
    2657   begin
    2658     key[1] := 'and       ';    {定义一系列保留字}
    2659     key[2] := 'array     ';
    2660     key[3] := 'begin     ';
    2661     key[4] := 'case      ';
    2662     key[5] := 'const     ';
    2663     key[6] := 'div       ';
    2664     key[7] := 'do        ';
    2665     key[8] := 'downto    ';
    2666     key[9] := 'else      ';
    2667     key[10] := 'end       ';
    2668     key[11] := 'for       ';
    2669     key[12] := 'function  ';
    2670     key[13] := 'if        ';
    2671     key[14] := 'mod       ';
    2672     key[15] := 'not       ';
    2673     key[16] := 'of        ';
    2674     key[17] := 'or        ';
    2675     key[18] := 'procedure ';
    2676     key[19] := 'program   ';
    2677     key[20] := 'record    ';
    2678     key[21] := 'repeat    ';
    2679     key[22] := 'then      ';
    2680     key[23] := 'to        ';
    2681     key[24] := 'type      ';
    2682     key[25] := 'until     ';
    2683     key[26] := 'var       ';
    2684     key[27] := 'while     ';
    2685 
    2686     ksy[1] := andsy;    {定义保留字对应的符号}
    2687     ksy[2] := arraysy;
    2688     ksy[3] := beginsy;
    2689     ksy[4] := casesy;
    2690     ksy[5] := constsy;
    2691     ksy[6] := idiv;
    2692     ksy[7] := dosy;
    2693     ksy[8] := downtosy;
    2694     ksy[9] := elsesy;
    2695     ksy[10] := endsy;
    2696     ksy[11] := forsy;
    2697     ksy[12] := funcsy;
    2698     ksy[13] := ifsy;
    2699     ksy[14] := imod;
    2700     ksy[15] := notsy;
    2701     ksy[16] := ofsy;
    2702     ksy[17] := orsy;
    2703     ksy[18] := procsy;
    2704     ksy[19] := programsy;
    2705     ksy[20] := recordsy;
    2706     ksy[21] := repeatsy;
    2707     ksy[22] := thensy;
    2708     ksy[23] := tosy;
    2709     ksy[24] := typesy;
    2710     ksy[25] := untilsy;
    2711     ksy[26] := varsy;
    2712     ksy[27] := whilesy;
    2713 
    2714 
    2715     sps['+'] := plus;    {定义特殊字符对应的sym}
    2716     sps['-'] := minus;
    2717     sps['*'] := times;
    2718     sps['/'] := rdiv;
    2719     sps['('] := lparent;
    2720     sps[')'] := rparent;
    2721     sps['='] := eql;
    2722     sps[','] := comma;
    2723     sps['['] := lbrack;
    2724     sps[']'] := rbrack;
    2725     sps[''''] := neq;
    2726     sps['!'] := andsy;
    2727     sps[';'] := semicolon;
    2728   end { setup };
    2729 
    2730 procedure enterids;    {这个过程负责将全部标准类型的信息登陆到table中}
    2731   begin    
    2732     enter('          ',vvariable,notyp,0); { sentinel }
    2733     enter('false     ',konstant,bools,0);
    2734     enter('true      ',konstant,bools,1);
    2735     enter('real      ',typel,reals,1);
    2736     enter('char      ',typel,chars,1);
    2737     enter('boolean   ',typel,bools,1);
    2738     enter('integer   ',typel,ints,1);
    2739     enter('abs       ',funktion,reals,0);
    2740     enter('sqr       ',funktion,reals,2);
    2741     enter('odd       ',funktion,bools,4);
    2742     enter('chr       ',funktion,chars,5);
    2743     enter('ord       ',funktion,ints,6);
    2744     enter('succ      ',funktion,chars,7);
    2745     enter('pred      ',funktion,chars,8);
    2746     enter('round     ',funktion,ints,9);
    2747     enter('trunc     ',funktion,ints,10);
    2748     enter('sin       ',funktion,reals,11);
    2749     enter('cos       ',funktion,reals,12);
    2750     enter('exp       ',funktion,reals,13);
    2751     enter('ln        ',funktion,reals,14);
    2752     enter('sqrt      ',funktion,reals,15);
    2753     enter('arctan    ',funktion,reals,16);
    2754     enter('eof       ',funktion,bools,17);
    2755     enter('eoln      ',funktion,bools,18);
    2756     enter('read      ',prozedure,notyp,1);
    2757     enter('readln    ',prozedure,notyp,2);
    2758     enter('write     ',prozedure,notyp,3);
    2759     enter('writeln   ',prozedure,notyp,4);
    2760     enter('          ',prozedure,notyp,0);
    2761   end;
    2762 
    2763 
    2764 begin  { main }    
    2765   setup;    {初始化变量}
    2766   constbegsys := [ plus, minus, intcon, realcon, charcon, ident ];    {常量的开始符号集合}
    2767   typebegsys := [ ident, arraysy, recordsy ];    {类型的开始符号集合}
    2768   blockbegsys := [ constsy, typesy, varsy, procsy, funcsy, beginsy ];    {分语句的开始符号集合}
    2769   facbegsys := [ intcon, realcon, charcon, ident, lparent, notsy ];        {因子的开始符号集合}
    2770   statbegsys := [ beginsy, ifsy, whilesy, repeatsy, forsy, casesy ];    {statement开始的符号集合}
    2771   stantyps := [ notyp, ints, reals, bools, chars ];    
    2772   lc := 0;        {重置pc}
    2773   ll := 0;        {重置当前行的长度}
    2774   cc := 0;        {重置当前行位置指针}
    2775   ch := ' ';    {重置当前符号}
    2776   errpos := 0;    {重置错误位置}
    2777   errs := [];    {重置错误集合}
    2778   writeln( 'NOTE input/output for users program is console : ' );
    2779   writeln;
    2780   write( 'Source input file ?');    {代码输入文件}
    2781   readln( inf );
    2782   assign( psin, inf );
    2783   reset( psin );
    2784   write( 'Source listing file ?');    {代码输出文件}
    2785   readln( outf );
    2786   assign( psout, outf );
    2787   rewrite( psout );
    2788   assign ( prd, 'con' );
    2789   write( 'result file : ' );    {结果输出文件}
    2790   readln( fprr );
    2791   assign( prr, fprr );
    2792   reset ( prd );
    2793   rewrite( prr );
    2794 
    2795   t := -1;    {设置tab栈顶初值}
    2796   a := 0;    {设置atab栈顶初值}
    2797   b := 1;    {设置btab栈顶初始值}
    2798   sx := 0;    {设置stab栈顶初值}
    2799   c2 := 0;    {设置rconst栈顶初值}
    2800   display[0] := 1;    {设置display初值}
    2801   iflag := false;    {初始化一系列flag的值}
    2802   oflag := false;
    2803   skipflag := false;
    2804   prtables := false;
    2805   stackdump := false;
    2806 
    2807   insymbol;    {获得第一个sym}
    2808 
    2809   if sy <> programsy    {要求第一个符号是program关键字,不是的话就报错}
    2810   then error(3)
    2811   else begin
    2812          insymbol;    {获取下一个符号}
    2813          if sy <> ident    {应该是程序名,不是则报错}
    2814          then error(2)
    2815          else begin
    2816                 progname := id;
    2817                 insymbol;
    2818                 if sy <> lparent
    2819                 then error(9)
    2820                 else repeat
    2821                        insymbol;
    2822                        if sy <> ident
    2823                        then error(2)
    2824                        else begin
    2825                               if id = 'input     '
    2826                               then iflag := true
    2827                               else if id = 'output    '
    2828                                    then oflag := true
    2829                                    else error(0);
    2830                               insymbol
    2831                             end
    2832                      until sy <> comma;
    2833                 if sy = rparent
    2834                 then insymbol
    2835                 else error(4);
    2836                 if not oflag then error(20)
    2837               end
    2838        end;
    2839   enterids;
    2840   with btab[1] do
    2841     begin
    2842       last := t;
    2843       lastpar := 1;
    2844       psize := 0;
    2845       vsize := 0;
    2846     end;
    2847   block( blockbegsys + statbegsys, false, 1 );
    2848   if sy <> period
    2849   then error(2);
    2850   emit(31);  { halt }
    2851   if prtables
    2852   then printtables;
    2853   if errs = []
    2854   then interpret
    2855   else begin
    2856          writeln( psout );
    2857          writeln( psout, 'compiled with errors' );
    2858          writeln( psout );
    2859          errormsg;
    2860        end;
    2861   writeln( psout );
    2862   close( psout );
    2863   close( prr )
    2864 end.   
    View Code
  • 相关阅读:
    我来教你用AWS IoT.Part1--配置和接入
    Netty进行文件传输
    Spring Security-利用URL地址进行权限控制
    Java开发工作中常见问题
    java进阶学习计划
    spring cloud常用注解及关键类
    系统设计-电商排名
    java实现十大经典算法
    JDK8如何写出优雅代码
    Java实现迷宫和八皇后
  • 原文地址:https://www.cnblogs.com/luxiaodou/p/6025124.html
Copyright © 2011-2022 走看看