PL/0與Pascal-S編譯器程序詳細註釋

  學校編譯課的做業之一,要求閱讀兩個較爲簡單的編譯器的代碼並作註釋, 我的感受是一次挺有意義的鍛鍊, 將本身的心得分享出來與一同在進步的同窗們分享. 從此有時間再作進一步的更新和總結,其中可能有很多錯誤,也請各位大佬不吝指正. 代碼能夠經過使用Lazarus等pascal環境執行。git

源碼倉庫:https://github.com/luxiaodou/Pascal-S-and-PL0-complier-commentsgithub

PL0編譯器源碼express

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編譯器ide

比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號字符,即跳過全部的空格和\t}
 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
相關文章
相關標籤/搜索