Skip to content

Latest commit

 

History

History
2864 lines (2778 loc) · 103 KB

File metadata and controls

2864 lines (2778 loc) · 103 KB

PascalS源码阅读

program PASCALS(INPUT,OUTPUT,PRD,PRR);
{  author:N.Wirth, E.T.H. CH-8092 Zurich,1.3.76 }
{  modified by R.E.Berry
    Department of computer studies
    University of Lancaster

    Variants of this program are used on
    Data General Nova,Apple,and
    Western Digital Microengine machines. }
{   further modified by M.Z.Jin
    Department of Computer Science&Engineering BUAA,0ct.1989
}
const nkw = 27;    { no. of key words }{*保留字个数*}
      alng = 10;   { no. of significant chars in identifiers }{*标识符长度,名字取前10个字符*}
      llng = 121;  { input line length }{*输入行长度*}
      emax = 322;  { max exponent of real numbers }
      emin = -292; { min exponent }
      kmax = 15;   { max no. of significant digits }
      tmax = 100;  { size of table }{*符号表的最大长度*}
      bmax = 20;   { size of block-table }
      amax = 30;   { size of array-table }
      c2max = 20;  { size of real constant table }
      csmax = 30;  { max no. of cases }
      cmax = 800;  { size of code }
      lmax = 7;    { maximum level }{*嵌套层次最多7层,也是x域的边界*}
      smax = 600;  { size of string-table }
      ermax = 58;  { max error no. }
      omax = 63;   { highest order code }{*Pcode中f字段总共有63个值*}
      xmax = 32767;  { 2**15-1 }{*index上下界*}
      nmax = 32767;  { 2**15-1 }{*Pcode的y域边界*}
      lineleng = 132; { output line length }
      linelimit = 200;
      stacksize = 1450;{*数据栈大小*}
type symbol = ( intcon, realcon, charcon, stringcon,
                notsy, plus, minus, times, idiv, rdiv, imod, andsy, orsy,
                eql, neq, gtr, geq, lss, leq,
                lparent, rparent, lbrack, rbrack, comma, semicolon, period,
                colon, becomes, constsy, typesy, varsy, funcsy,
                procsy, arraysy, recordsy, programsy, ident,
                beginsy, ifsy, casesy, repeatsy, whilesy, forsy,
                endsy, elsesy, untilsy, ofsy, dosy, tosy, downtosy, thensy);
     index = -xmax..+xmax;
     alfa = packed array[1..alng]of char;{*packed是压缩的,方便查找*}
     objecttyp = (konstant, vvariable, typel, prozedure, funktion );{*标识符的种类:常量,变量,类型,过程,函数*}
     types = (notyp, ints, reals, bools, chars, arrays, records );{*标识符类型:notyp,整型,实型,布尔型,字符型,数组型,记录型*}
     symset = set of symbol;
     typset = set of types;
     item = record
               typ: types;
               ref: index;
            end;

     order = packed record
                f: -omax..+omax;
x: -lmax..+lmax;
                y: -nmax..+nmax
end;{*生成Pcode用的数据结构。见书458页*}
var   ch:         char; { last character read from source program }{*ch是从源程序中读到的最新的字符*}
      rnum:       real; { real number from insymbol }{*词法分析器得到的实数*}
inum:       integer;     { integer from insymbol }{*词法分析器得到的整数*}
sleng:      integer;     { string length }{*字符串的长度*}
      cc:         integer;     { character counter }{*行指针*}
      lc:         integer;     { program location counter }{*Pcode代码指针*}
      ll:         integer;     { length of current line }{*当前行长度*}
      errpos:     integer;{*记录错误位置*}
      t,a,b,sx,c1,c2:integer;  { indices to tables }{*表的索引:t符号表,a数组信息向量表,b分程序表,sx字符串常量表,c2实常量表,*}
      iflag, oflag, skipflag, stackdump, prtables: boolean;
      sy:         symbol;      { last symbol read by insymbol }{*词法分析器读到的最新的符号*}
      errs:       set of 0..ermax;{*记录错误*}
      id:         alfa;        { identifier from insymbol }{*符号表id*}
      progname:   alfa;{*程序名*}
      stantyps:   typset;{*标准类型*}
      constbegsys, typebegsys, blockbegsys, facbegsys, statbegsys: symset;{*各种begin symbol*}
      line:       array[1..llng] of char;{*读取一行代码*}
      key:        array[1..nkw] of alfa;{*保留字集合*}
      ksy:        array[1..nkw] of symbol;{*保留字对应的记忆符*}
      sps:        array[char]of symbol;  { special symbols }{*特殊符号,+-*/这样的*}
      display:    array[0..lmax] of integer;{*各层次分程序运行栈基地址索引表*}
      tab:        array[0..tmax] of      { indentifier lable }{*符号表一项的结构*}
                 packed record
                     name: alfa;{*标识符名字,取10个字符*}
                     link: index;{*同一分程序中,上一个标识符在符号表中的位置,每个分程序的第一个标识符link为0,记录变量当作分程序看*}
                     obj:  objecttyp;{*标识符种类*}
                     typ:  types;{*标识符类型*}
                     ref:  index;{*数组类型或数组变量则指向数组信息向量表,记录类型记录变量则指向分程序表,过程名函数名指向分程序表,否则为0*}
normal: boolean;{*变量形参时为0,值形参或其他变量为1*}
                     lev:  0..lmax;{*所在分程序的层次,主程序为1*}
                     adr: integer{*变量填入运行栈中分配存储空间的相对地址,记录域名填入相对记录变量起始地址的位移,过程名函数名填入目标代码入口地址,整数填入整数值,布尔值填入布尔值,字符常量名填入ASCII代码值,实常量填入实常量表的位置,类型填入所需存储单元的数目*}
end;
     atab:       array[1..amax] of    { array-table }{*数组信息向量表*}
                 packed record
                     inxtyp,eltyp: types;{*下标类型(整数、布尔、字符),数组元素类型*}
                     elref{*数组填入登记项位置,记录填入等级位置,否则0*},low,high{*上下界*},elsize{*数组元素大小*},size{*数组大小*}: index
                 end;
     btab:       array[1..bmax] of    { block-table }{*分程序表*}
                 packed record
                     last{*最后一个标识符在表中的位置*}, lastpar{*最后一个参数的位置*}, psize{*参数和运行栈内务信息区占的单元数*}, vsize{*局部变量、参数、内务信息区在运行栈中占的单元数*}: index
                 end;
     stab:       packed array[0..smax] of char; { string table }{*字符串变量表*}
     rconst:     array[1..c2max] of real;{*实常量表*}
     code:       array[0..cmax] of order;{*P代码表*}
     psin,psout,prr,prd:text;      { default in pascal p }
     inf, outf, fprr: string;{*代码输入,代码输出,结果输出的文件路径*}

procedure errormsg;{*打印错误信息*}
  var k : integer;
     msg: array[0..ermax] of alfa;{*设置错误信息表,总共ermax种错误*}
  begin
    msg[0] := 'undef id  ';    msg[1] := 'multi def ';
    msg[2] := 'identifier';    msg[3] := 'program   ';
msg[4] := ')         ';    msg[5] := ':         ';
    msg[6] := 'syntax    ';    msg[7] := 'ident,var '; 
msg[8] := 'of        ';    msg[9] := '(         ';
    msg[10] := 'id,array  ';    msg[11] := '(         ';
    msg[12] := ']         ';    msg[13] := '..        ';
    msg[14] := ';         ';    msg[15] := 'func. type';
    msg[16] := '=         ';    msg[17] := 'boolean   ';
    msg[18] := 'convar typ';    msg[19] := 'type      ';
    msg[20] := 'prog.param';    msg[21] := 'too big   ';
    msg[22] := '.         ';    msg[23] := 'type(case)';
    msg[24] := 'character ';    msg[25] := 'const id  ';
    msg[26] := 'index type';    msg[27] := 'indexbound';
    msg[28] := 'no array  ';    msg[29] := 'type id   ';
    msg[30] := 'undef type';    msg[31] := 'no record ';
    msg[32] := 'boole type';    msg[33] := 'arith type';
msg[34] := 'integer   ';    msg[35] := 'types     ';
    msg[36] := 'param type';    msg[37] := 'variab id ';
msg[38] := 'string    ';    msg[39] := 'no.of pars';
    msg[40] := 'real numbr';    msg[41] := 'type      ';
msg[42] := 'real type ';    msg[43] := 'integer   ';
    msg[44] := 'var,const ';    msg[45] := 'var,proc  ';
msg[46] := 'types(:=) ';    msg[47] := 'typ(case) ';
    msg[48] := 'type      ';    msg[49] := 'store ovfl';
    msg[50] := 'constant  ';    msg[51] := ':=        ';
    msg[52] := 'then      ';    msg[53] := 'until     ';
    msg[54] := 'do        ';    msg[55] := 'to downto ';
    msg[56] := 'begin     ';    msg[57] := 'end       ';
    msg[58] := 'factor';

    writeln(psout);{*向psout中输出一个空行*}
    writeln(psout,'key words');
    k := 0;
    while errs <> [] do{*如果errs还不为空*}
      begin
        while not( k in errs )do k := k + 1;{*如果k错误不存在k++*}
writeln(psout, k, ' ', msg[k] );
        errs := errs - [k]{*如果存在k错误,向文件输出错误编号和具体信息,从errs中删去这个错误*}
end { while errs }{*知道所有错误都被处理*}
  end { errormsg } ;

procedure endskip;{*在出错程序下画线*}
  begin                 { underline skipped part of input }
    while errpos < cc do
      begin
        write( psout, '-');
        errpos := errpos + 1
      end;{*只要错误位置在行指针之前就画线,错误位置指针后移*}
    skipflag := false
  end { endskip };


procedure nextch;  { read next character; process line end }{*读下一个字符*}
  begin
    if cc = ll{*行指针指向行末尾,说明一行读完了*}
    then begin
           if eof( psin ){*如果输入文件结束了*}
           then begin
                  writeln( psout );
                  writeln( psout, 'program incomplete' );
                  errormsg;{*输出信息到输出文件,报错*}
                  exit;
                end;
           if errpos <> 0{*如果位置不为0,则说明有错误*}
           then begin
                  if skipflag then endskip;{*跳过错误代码*}
                  writeln( psout );
                  errpos := 0{*错误位置置0*}
                end;
           write( psout, lc: 5, ' ');{*没有错误,则输出文件中按场宽为5的格式输出Pcode行数和一个空格,不换行*}
           ll := 0;
           cc := 0;{*行长度置0,行指针置0*}
           while not eoln( psin ) do{*如果输入文件没有读完*}
             begin
               ll := ll + 1;
               read( psin, ch );
               write( psout, ch );
               line[ll] := ch{*行长度++,读一个字符,输出到输出文件中,并将这个字符赋值到对应位置,这样循环读完一行*}
             end;
           ll := ll + 1;{*最后的行长度,留了一个位置*}
           readln( psin );
           line[ll] := ' ';{*留的位置赋一个空格*}
           writeln( psout );
         end;
         cc := cc + 1;
         ch := line[cc];{*行指针前移,取了一个字符,相当于预读了一个字符*}
  end { nextch };

procedure error( n: integer );{*打印出错位置*}
begin
  if errpos = 0
  then write ( psout, '****' );
  if cc > errpos
  then begin
         write( psout, ' ': cc-errpos, '^', n:2);{*在出错位置的下方输出一个尖*}
errpos := cc + 3;
         errs := errs +[n]{*错误集合中加入这个错误*}
end
end { error };

procedure fatal( n: integer );{*表溢出时终止程序*}
  var msg : array[1..7] of alfa;
  begin
    writeln( psout );
    errormsg;
    msg[1] := 'identifier';   msg[2] := 'procedures';
    msg[3] := 'reals     ';   msg[4] := 'arrays    ';
msg[5] := 'levels    ';   msg[6] := 'code      ';
    msg[7] := 'strings   ';
writeln( psout, 'compiler table for ', msg[n], ' is too small');
    exit; {terminate compilation }{*输出哪个表溢出*}
  end { fatal };

procedure insymbol;  {reads next symbol}{*词法分析*}
label 1,2,3;{*定义了三个标签*}
  var  i,j,k,e: integer;
procedure readscale;{*处理实数的指数部分,根据文法指数只能是整数*}
    var s,sign: integer;
    begin
      nextch;{*读取下一个字符*}
      sign := 1;{*读到的数的正负*}
      s := 0;{*计算读到的数字*}
      if ch = '+'{*读到正号不处理,继续读*}
      then nextch
      else if ch = '-'
           then begin
                  nextch;
                  sign := -1{*设为负*}
                end;
      if not(( ch >= '0' )and (ch <= '9' ))
      then error( 40 ){*如果接着的不是数字就报错*}
      else repeat
           s := 10*s + ord( ord(ch)-ord('0'));
           nextch;
           until not(( ch >= '0' ) and ( ch <= '9' ));{*计算读到的数的值,知道读到一个不是0到9的字符*}
      e := s*sign + e{*带上符号,e就是有符号的指数部分*}
    end { readscale };

  procedure adjustscale;{*计算小数部分和指数*}
    var s : integer;
        d, t : real;
    begin
      if k + e > emax
      then error(21){*too big错误*}
      else if k + e < emin
           then rnum := 0{*精度不够,直接置0*}
           else begin
                  s := abs(e);{*e是负数,求绝对值*}
                  t := 1.0;
                  d := 10.0;
                  repeat
                    while not odd(s) do{*如果s不是偶数就重复*}
                      begin
                        s := s div 2;
                        d := sqr(d){*d自己平方,从10变成100变成10000这样,减少了*10的运算次数*}
                      end;{*先把偶数部分处理完*}
                    s := s - 1;
                    t := d * t
                  until s = 0;{*此时t=10^e*}
if e >= 0
                  then rnum := rnum * t{*e大于0就乘,否则就除*}
                  else rnum := rnum / t{*因为*10^e=/10^-e*}
end
    end { adjustscale };

  procedure options;{*处理编译选项*}
    procedure switch( var b: boolean );{*处理+-号*}
      begin
        b := ch = '+';{*判断ch是否是+号,存入b*}
        if not b
        then if not( ch = '-' ){*如果不是+号,而且也不是-号*}
             then begin { print error message }
                    while( ch <> '*' ) and ( ch <> ',' ) do
                      nextch;{*一直读到*号或者,号*}
                  end
             else nextch
        else nextch
      end { switch };
    begin { options  }
      repeat
        nextch;
        if ch <> '*'
        then begin
               if ch = 't'
               then begin
                      nextch;
                      switch( prtables ){*编译选项t*}
                    end
               else if ch = 's'
                  then begin
                          nextch;
                          switch( stackdump ){*编译选项s*}
                       end;

             end
      until ch <> ','
    end { options };
  begin { insymbol  }
  1: while( ch = ' ' ) or ( ch = chr(9) ) do
       nextch;    { space & htab }{*跳过所有的空格和制表符*}
    case ch of
      'a','b','c','d','e','f','g','h','i',
      'j','k','l','m','n','o','p','q','r',
      's','t','u','v','w','x','y','z':
        begin { identifier of wordsymbol }{*如果是字母,开始识别标识符*}
          k := 0;
          id := '          ';
          repeat
            if k < alng
            then begin
                   k := k + 1;
                   id[k] := ch
                 end;
            nextch
          until not((( ch >= 'a' ) and ( ch <= 'z' )) or (( ch >= '0') and (ch <= '9' )));{*一直读取字符,在10个字符的限制内,存入id中,直到遇到不是字母的字符*}
          i := 1;
          j := nkw; { binary search }{*二分查找当前id在表的位置,字典序*}
          repeat
            k := ( i + j ) div 2;
            if id <= key[k]
            then j := k - 1;
            if id >= key[k]
            then i := k + 1;
          until i > j;
          if i - 1 > j
          then sy := ksy[k]{*得到这个id对应的保留字的记忆符*}
          else sy := ident{*不是保留字,就是一个标识符*}
        end;
      '0','1','2','3','4','5','6','7','8','9':{*开始识别无符号数*}
        begin { number }
          k := 0;
          inum := 0;
          sy := intcon;{*判断这个数为整数*}
repeat
            inum := inum * 10 + ord(ch) - ord('0');{*计算数值*}
k := k + 1;{*统计整数部分的位数*}
            nextch
          until not (( ch >= '0' ) and ( ch <= '9' ));
          if( k > kmax ) or ( inum > nmax )
          then begin
                 error(21);
                 inum := 0;
                 k := 0
               end;{*如果位数超标或者数值大小超标报错,置0*}
          if ch = '.'{*读取小数部分*}
          then begin
                 nextch;
                 if ch = '.'
                 then ch := ':'{*连续两个.什么情况?没在文法里看到,试了一下运行会报错啊*}
                 else begin
                        sy := realcon;{*判断这个数为实数*}
                        rnum := inum;{*实数的整数部分就是之前得到的整数*}
                        e := 0;
                        while ( ch >= '0' ) and ( ch <= '9' ) do
begin
                            e := e - 1;
                            rnum := 10.0 * rnum + (ord(ch) - ord('0'));
nextch
                          end;{*e记录小数位数(负数),小数部分先当作整数计算*}
                        if e = 0
                        then error(40);{*小数点之后没有数字,报错*}
                        if ch = 'e'
                        then readscale;{*科学计数法,计算指数部分的整数值*}
                        if e <> 0 then adjustscale{*计算最终的数值*}
                      end
                end
          else if ch = 'e'{整数接着科学计数法}
               then begin
sy := realcon;
                      rnum := inum;
                      e := 0;
readscale;
                      if e <> 0
                      then adjustscale
                    end;
        end;
      ':':{*如果读到的是:*}
        begin
          nextch;
          if ch = '='
          then begin
                 sy := becomes;{*读到的是赋值符号*}
                 nextch
               end
          else  sy := colon{*否则就是个冒号*}
         end;
      '<':
        begin
          nextch;
          if ch = '='
          then begin
                 sy := leq;{*小于等于*}
                 nextch
               end
          else
            if ch = '>'
            then begin
                   sy := neq;{*不等于*}
                   nextch
                 end
            else  sy := lss{*小于*}
        end;
      '>':
        begin
          nextch;
          if ch = '='
          then begin
                 sy := geq;{*大于等于*}
                 nextch
               end
          else  sy := gtr{*大于*}
        end;
      '.':
        begin
          nextch;
          if ch = '.'
          then begin
                 sy := colon;{*竟然把两个点当作冒号处理..神奇的操作*}
                 nextch
               end
          else sy := period{*否则就是个句号*}
        end;
      '''':{*两个连续的单引号,表示的是一个单引号字符*}
        begin
          k := 0;
   2:     nextch;
          if ch = ''''
          then begin
                 nextch;
                 if ch <> ''''
                 then goto 3
               end;
          if sx + k = smax
          then fatal(7);
          stab[sx+k] := ch;
          k := k + 1;
          if cc = 1
          then begin { end of line }{*行结束*}
                 k := 0;
               end
          else goto 2;
   3:     if k = 1
          then begin
                 sy := charcon;{*双引号之间只有一个字符,那就是字符型*}
                 inum := ord( stab[sx] ){*inum存储的是ascii值*}
               end
          else if k = 0
               then begin
                      error(38);
                      sy := charcon;
                      inum := 0{*双引号之间是空的报错*}
                    end
               else begin
                      sy := stringcon;{*否则是字符串*}
                      inum := sx;
                      sleng := k;{*字符串长度*}
                      sx := sx + k
                    end
        end;
      '(':
        begin
          nextch;
          if ch <> '*'
          then sy := lparent{*不是注释符,是左括号*}
          else begin { comment }{}{*是注释*}
                 nextch;
                 if ch = '$'
                 then options;{*是编译选项*}
                 repeat
                   while ch <> '*' do nextch;
                   nextch
                 until ch = ')';{*直到读到*)*}
                 nextch;
                 goto 1
               end
        end;
      '{':
        begin
          nextch;
          if ch = '$'
          then options;{*处理编译选项*}
          while ch <> '}' do
            nextch;
          nextch;
          goto 1
        end;
      '+', '-', '*', '/', ')', '=', ',', '[', ']', ';':
        begin
          sy := sps[ch];{*直接处理*}
          nextch
        end;
      '$','"' ,'@', '?', '&', '^', '!':
        begin
          error(24);{*单独出现报错*}
          nextch;
          goto 1
        end
      end { case }
    end { insymbol };

procedure enter(x0:alfa; x1:objecttyp; x2:types; x3:integer );{*将系统预定义的标识符插入符号表中*}
  begin
    t := t + 1;    { enter standard identifier }
    with tab[t] do
      begin
        name := x0;
        link := t - 1;
        obj := x1;
        typ := x2;
        ref := 0;
        normal := true;
        lev := 0;
        adr := x3;
      end
  end; { enter }

procedure enterarray( tp: types; l,h: integer );{*将数组信息录入到数组信息向量表*}
  begin
    if l > h{*low>high,下界大于上界,报错*}
    then error(27);
    if( abs(l) > xmax ) or ( abs(h) > xmax )
    then begin
           error(27);{*上下界越界,报错*}
           l := 0;
           h := 0;
         end;
    if a = amax
    then fatal(4){*表满了*}
    else begin
           a := a + 1;
           with atab[a] do
             begin
               inxtyp := tp;
               low := l;
               high := h
             end
         end
  end { enterarray };

procedure enterblock;{*将分程序的信息录入到分程序索引表*}
  begin
    if b = bmax{*表满了*}
    then fatal(2)
    else begin
           b := b + 1;
           btab[b].last := 0;{*指向分程序中说明的最后一个标识符的位置*}
           btab[b].lastpar := 0;{*指向过程或函数的最后一个参数在表中的位置*}
         end
  end { enterblock };

procedure enterreal( x: real );{*信息录入到实常量表*}
  begin
    if c2 = c2max - 1
    then fatal(3)
    else begin
           rconst[c2+1] := x;
           c1 := 1;
           while rconst[c1] <> x do
             c1 := c1 + 1;
           if c1 > c2
           then  c2 := c1
         end
  end { enterreal };

procedure emit( fct: integer );{*这几个都是生成Pcode的函数,参数个数不同*}
  begin
    if lc = cmax
    then fatal(6);
code[lc].f := fct;
    lc := lc + 1
end { emit };


procedure emit1( fct, b: integer );
  begin
    if lc = cmax
    then fatal(6);
    with code[lc] do
      begin
        f := fct;
        y := b;
      end;
    lc := lc + 1
  end { emit1 };

procedure emit2( fct, a, b: integer );
  begin
    if lc = cmax then fatal(6);
    with code[lc] do
      begin
        f := fct;
        x := a;
        y := b
      end;
    lc := lc + 1;
end { emit2 };

procedure printtables;{*打印表*}
  var  i: integer;
o: order;
      mne: array[0..omax] of
           packed array[1..5] of char;
  begin{*定义Pcode的指令助记符*}
    mne[0] := 'LDA  ';   mne[1] := 'LOD  ';  mne[2] := 'LDI  ';
mne[3] := 'DIS  ';   mne[8] := 'FCT  ';  mne[9] := 'INT  ';
    mne[10] := 'JMP  ';   mne[11] := 'JPC  ';  mne[12] := 'SWT  ';
    mne[13] := 'CAS  ';   mne[14] := 'F1U  ';  mne[15] := 'F2U  ';
    mne[16] := 'F1D  ';   mne[17] := 'F2D  ';  mne[18] := 'MKS  ';
    mne[19] := 'CAL  ';   mne[20] := 'IDX  ';  mne[21] := 'IXX  ';
    mne[22] := 'LDB  ';   mne[23] := 'CPB  ';  mne[24] := 'LDC  ';
mne[25] := 'LDR  ';   mne[26] := 'FLT  ';  mne[27] := 'RED  ';
mne[28] := 'WRS  ';   mne[29] := 'WRW  ';  mne[30] := 'WRU  ';
    mne[31] := 'HLT  ';   mne[32] := 'EXP  ';  mne[33] := 'EXF  ';
    mne[34] := 'LDT  ';   mne[35] := 'NOT  ';  mne[36] := 'MUS  ';
mne[37] := 'WRR  ';   mne[38] := 'STO  ';  mne[39] := 'EQR  ';
mne[40] := 'NER  ';   mne[41] := 'LSR  ';  mne[42] := 'LER  ';
    mne[43] := 'GTR  ';   mne[44] := 'GER  ';  mne[45] := 'EQL  ';
mne[46] := 'NEQ  ';   mne[47] := 'LSS  ';  mne[48] := 'LEQ  ';
    mne[49] := 'GRT  ';   mne[50] := 'GEQ  ';  mne[51] := 'ORR  ';
    mne[52] := 'ADD  ';   mne[53] := 'SUB  ';  mne[54] := 'ADR  ';
    mne[55] := 'SUR  ';   mne[56] := 'AND  ';  mne[57] := 'MUL  ';
    mne[58] := 'DIV  ';   mne[59] := 'MOD  ';  mne[60] := 'MUR  ';
    mne[61] := 'DIR  ';   mne[62] := 'RDL  ';  mne[63] := 'WRL  ';

writeln(psout);
    writeln(psout);
    writeln(psout);
    writeln(psout,'   identifiers  link  obj  typ  ref  nrm  lev  adr');
    writeln(psout);
    for i := btab[1].last to t do
      with tab[i] do
        writeln( psout, i,' ', name, link:5, ord(obj):5, ord(typ):5,ref:5, ord(normal):5,lev:5,adr:5);
    writeln( psout );
    writeln( psout );
    writeln( psout );
    writeln( psout, 'blocks   last  lpar  psze  vsze' );
    writeln( psout );
    for i := 1 to b do
       with btab[i] do
         writeln( psout, i:4, last:9, lastpar:5, psize:5, vsize:5 );
    writeln( psout );
    writeln( psout );
    writeln( psout );
    writeln( psout, 'arrays xtyp etyp eref low high elsz size');
    writeln( psout );
    for i := 1 to a do
      with atab[i] do
        writeln( psout, i:4, ord(inxtyp):9, ord(eltyp):5, elref:5, low:5, high:5, elsize:5, size:5);
    writeln( psout );
    writeln( psout );
    writeln( psout );
    writeln( psout, 'code:');
    writeln( psout );
    for i := 0 to lc-1 do
      begin
write( psout, i:5 );
        o := code[i];
write( psout, mne[o.f]:8, o.f:5 );
        if o.f < 31
        then if o.f < 4
             then write( psout, o.x:5, o.y:5 )
             else write( psout, o.y:10 )
        else write( psout, '          ' );
        writeln( psout, ',' )
      end;
    writeln( psout );
    writeln( psout, 'Starting address is ', tab[btab[1].last].adr:5 )
  end { printtables };


procedure block( fsys: symset; isfun: boolean; level: integer );{*分析处理分程序*}
  type conrec = record{*定义一个记录变量,根据不同的type保存不同格式的数据*}
                  case tp: types of
                    ints, chars, bools : ( i:integer );
                    reals :( r:real )
                end;
  var dx : integer ;  { data allocation index }
      prt: integer ;  { t-index of this procedure }{*符号表索引*}
      prb: integer ;  { b-index of this procedure }{*分程序表索引*}
x  : integer ;

  procedure skip( fsys:symset; n:integer);{*跳过错误的代码*}
begin
      error(n);
      skipflag := true;
      while not ( sy in fsys ) do
        insymbol;
      if skipflag then endskip
    end { skip };

  procedure test( s1,s2: symset; n:integer );{*检测当前的符号是否合法*}
    begin
      if not( sy in s1 )
      then skip( s1 + s2, n ){*不合法就跳过*}
    end { test };

  procedure testsemicolon;{*检测分号是否合法*}
    begin
      if sy = semicolon
      then insymbol
      else begin
             error(14);
             if sy in [comma, colon]
             then insymbol
           end;
      test( [ident] + blockbegsys, fsys, 6 )
    end { testsemicolon };


  procedure enter( id: alfa; k:objecttyp );{*将分程序的符号录入分程序表*}
    var j,l : integer;
    begin
      if t = tmax
      then fatal(1){*表满了*}
      else begin
             tab[0].name := id;
             j := btab[display[level]].last;{*获取指向当前层次的最后一个标识符在符号表中的位置*}
             l := j;
             while tab[j].name <> id do
               j := tab[j].link;{*按照id找位置*}
             if j <> 0
             then error(1){*如果j不为0,说明找了这个定义,已经出现过一次,重复定义报错*}
             else begin{*没有定义就可以录入*}
                    t := t + 1;
                    with tab[t] do
                      begin
                        name := id;
                        link := l;
                        obj := k;
                        typ := notyp;
                        ref := 0;
                        lev := level;
                        adr := 0;
                        normal := false { initial value }
                      end;
                    btab[display[level]].last := t{*更新当前层次最后一个标识符的位置*}
                  end
           end
    end { enter };

  function loc( id: alfa ):integer;{*定位标识符在符号表的位置*}
    var i,j : integer;        { locate if in table }
    begin
      i := level;
      tab[0].name := id;  { sentinel }
      repeat
        j := btab[display[i]].last;
        while tab[j].name <> id do
j := tab[j].link;
        i := i - 1;
until ( i < 0 ) or ( j <> 0 );
      if j = 0
      then error(0);
      loc := j
    end { loc } ;

  procedure entervariable;{将变量信息录入表中}
    begin
      if sy = ident
      then begin
             enter( id, vvariable );
             insymbol
           end
      else error(2)
    end { entervariable };

  procedure constant( fsys: symset; var c: conrec );{*处理常量,常量的类型和值通过c返回*}
var x, sign : integer;
    begin
      c.tp := notyp;
c.i := 0;
      test( constbegsys, fsys, 50 );
      if sy in constbegsys{*如果第一个符号是常量开始的符号*}
      then begin
             if sy = charcon
             then begin
                    c.tp := chars;
                    c.i := inum;
                    insymbol
                  end{*字符常量,记为字符型,存储ascii码值,继续读*}
             else begin
                  sign := 1;
                  if sy in [plus, minus]
                  then begin
                         if sy = minus
                         then sign := -1;{*如果是减号,符号变负,乘号为正*}
                         insymbol
                       end;
                  if sy = ident{*如果是标识符*}
                  then begin
                         x := loc(id);{*找表中的位置*}
                         if x <> 0
                         then
                           if tab[x].obj <> konstant
                           then error(25){*找到了但不是常量,报错*}
                           else begin
                                  c.tp := tab[x].typ;
                                  if c.tp = reals{*如果是实数*}
                                  then c.r := sign*rconst[tab[x].adr]
                                  else c.i := sign*tab[x].adr{*如果是整数*}
                                end;
                         insymbol
                       end
                  else if sy = intcon{*如果是整数*}
                       then begin
                              c.tp := ints;
                              c.i := sign*inum;
                              insymbol
                            end
                       else if sy = realcon{*如果是实数*}
                            then begin
                                   c.tp := reals;
                                   c.r := sign*rnum;
                                   insymbol
                                 end
                            else skip(fsys,50){*跳过无用的符号*}
                end;
                test(fsys,[],6)
           end
    end { constant };

procedure typ( fsys: symset; var tp: types; var rf,sz:integer );{*处理类型说明,返回当前关键词的类型,在符号表中的位置,以及占据的空间大小*}
    var eltp : types;
        elrf, x : integer;
elsz, offset, t0, t1 : integer;

procedure arraytyp( var aref, arsz: integer );{*处理数组类型*}
var eltp : types;
      low, high : conrec;
      elrf, elsz: integer;
      begin
        constant( [colon, rbrack, rparent, ofsy] + fsys, low );{*获取数组下标的下界*}
        if low.tp = reals{*如果下界类型是实型,报错,设为整型*}
        then begin
               error(27);
               low.tp := ints;
               low.i := 0
             end;
        if sy = colon
        then insymbol
        else error(13);
        constant( [rbrack, comma, rparent, ofsy ] + fsys, high );{*获取数组下标的上界*}
        if high.tp <> low.tp{*上下界类型不一致报错*}
        then begin
               error(27);
               high.i := low.i{*与下界相同*}
             end;
        enterarray( low.tp, low.i, high.i );{*录入*}
        aref := a;
        if sy = comma{*如果读到了逗号,说明要声明多维数组*}
        then begin
               insymbol;
               eltp := arrays;
               arraytyp( elrf, elsz ){*递归调用处理数组元素*}
             end
        else begin
               if sy = rbrack{*读到],说明声明结束*}
               then insymbol
               else begin
                      error(12);{*缺少右中括号*}
                      if sy = rparent{*右括号容错*}
                      then insymbol
                    end;
               if sy = ofsy{*读of关键字*}
               then insymbol
               else error(8);{*没有of报错*}
               typ( fsys, eltp, elrf, elsz ){*处理当前的符号类型*}
             end;
             with atab[aref] do{*记录当前数组的信息*}
               begin
                 arsz := (high-low+1) * elsz;
                 size := arsz;
                 eltyp := eltp;
                 elref := elrf;
                 elsize := elsz
               end
      end { arraytyp };
    begin { typ  }{*类型的处理过程*}
      tp := notyp;
      rf := 0;
      sz := 0;
      test( typebegsys, fsys, 10 );{*判断当前符号是否是类型的开始符号,不是报10号错*}
      if sy in typebegsys{*如果是则继续*}
      then begin
             if sy = ident{*如果当前符号是标识符*}
             then begin
                    x := loc(id);{*查找id在符号表的地址*}
                    if x <> 0{*地址不为0说明找到了*}
                    then with tab[x] do
                           if obj <> typel{*如果找到了但是种类不是不是类型,报错*}
                           then error(29)
                           else begin
                                  tp := typ;
                                  rf := ref;
                                  sz := adr;
                                  if tp = notyp
                                  then error(30){*如果没有定义类型就报错*}
                                end;
                    insymbol
                  end
             else if sy = arraysy{*如果当前是数组元素,即声明开始符号是array*}
                  then begin
                         insymbol;
                         if sy = lbrack{*首先应该读到一个[*}
                         then insymbol
                         else begin
                                error(11);{*否则报错*}
                                if sy = lparent{*如果是一个左括号,容错*}
                                then insymbol
                              end;
                         tp := arrays;{*设置为数组类型*}
                         arraytyp(rf,sz){*获取数组在数组信息向量表中的记录位置,和数组的大小*}
                         end
             else begin { records }{*由于typebesys中只有ident,arraysy,recordsy,所以这里只能是记录型*}
                    insymbol;
                    enterblock;{*当作分程序登记到分程序表*}
                    tp := records;{*设置为记录型变量*}
                    rf := b;{*rf指向在表中的位置*}
                    if level = lmax
                    then fatal(5);{*如果层次数达到最大了,报错终止程序*}
                    level := level + 1;{*如果没有达到最大,层次数++*}
                    display[level] := b;{*设置当前层次的display区,建立分层次索引*}
                    offset := 0;
                    while not ( sy in fsys - [semicolon,comma,ident]+ [endsy] ) do{*end之前都是记录变量中的变量*}
                      begin { field section }
                        if sy = ident{*如果读到了一个标识符*}
                        then begin
                               t0 := t;{*获取当前符号表指针的位置*}
                               entervariable;{*将这个变量录入符号表*}
                               while sy = comma do{*读到逗号说明还有同类型的变量,继续录入符号表*}
                                 begin
                                   insymbol;
                                   entervariable
                                 end;
                               if sy = colon{*读到了冒号,说明变量名结束了,后面应该是变量的类型*}
                               then insymbol
                               else error(5);{没读到冒号报错}
                               t1 := t;{*记录当前符号表栈顶的位置,由于此时录入的变量都没有填类型等信息,需要反填*}
                               typ( fsys + [semicolon, endsy, comma,ident], eltp, elrf, elsz );{*处理记录变量各成员的类型说明*}
                               while t0 < t1 do{*t0到t1之间的变量反填信息*}
                               begin
                                 t0 := t0 + 1;
                                 with tab[t0] do
                                   begin
                                     typ := eltp;
                                     ref := elrf;
                                     normal := true;
                                     adr := offset;
                                     offset := offset + elsz{*获得下一个变量的地址*}
                                   end
                               end
                             end; { sy = ident }
                        if sy <> endsy{*如果没有读到end,说明还有其他成员,不过要先读分号*}
                        then begin
                               if sy = semicolon
                               then insymbol{*读到分号,继续读下一个成员,没有读到分号就报错*}
                               else begin
                                      error(14);
                                      if sy = comma{*如果错写成了逗号,容错*}
                                      then insymbol
                                    end;
                                    test( [ident,endsy, semicolon],fsys,6 ){*检验当前符号是否合法*}
                             end
                      end; { field section }
                    btab[rf].vsize := offset;{*offset记录了当前的局部变量,参数,和display区所占的空间总大小,记录在分程序表中*}
                    sz := offset;
                    btab[rf].psize := 0;{*因为记录变量不是实际的分程序,所以参数占用的空间设置为0*}
                    insymbol;
                    level := level - 1{*记录变量声明结束后层次-1*}
                  end; { record }
             test( fsys, [],6 )
           end;
      end { typ };

  procedure parameterlist; { formal parameter list  }{*处理过程或者函数声明中的形参表,将形参和有关信息登录到符号表中*}
    var tp : types;
        valpar : boolean;
        rf, sz, x, t0 : integer;
    begin
      insymbol;
      tp := notyp;
      rf := 0;
      sz := 0;
      test( [ident, varsy], fsys+[rparent], 7 );{*检测当前符号是否合法*}
      while sy in [ident, varsy] do{*如果当前符号是标识符或者var关键字*}
        begin
          if sy <> varsy
          then valpar := true{*为啥?不是var关键字就设置是var?应该是if sy=varsy吧*}
          else begin
                 insymbol;
                 valpar := false
               end;
          t0 := t;{*记录当前符号表栈顶的位置*}
          entervariable;{*将参数符号放入符号表*}
          while sy = comma do{*如果有逗号,说明还有同类型的参数,继续录入到符号表*}
            begin
              insymbol;
              entervariable;
            end;
          if sy = colon{*读到冒号说明要声明类型*}
          then begin
                 insymbol;
                 if sy <> ident
                 then error(2){*不是标识符报错*}
                 else begin
                        x := loc(id);
                        insymbol;
                        if x <> 0
                        then with tab[x] do
                          if obj <> typel
                          then error(29)
                          else begin
                                 tp := typ;
                                 rf := ref;
                                 if valpar{*如果是值形参*}
                                 then sz := adr
                                 else sz := 1
                               end;
                      end;
                 test( [semicolon, rparent], [comma,ident]+fsys, 14 )
                 end
          else error(5);{*不是分号报错*}
          while t0 < t do
            begin
              t0 := t0 + 1;
              with tab[t0] do
                begin
                  typ := tp;
                  ref := rf;
adr := dx;
                  lev := level;
                  normal := valpar;
dx := dx + sz
                end{*t0到t之间都是需要反填的*}
            end;
            if sy <> rparent{*如果不是右括号*}
            then begin
                   if sy = semicolon{*如果是分号,说明还有参数*}
                   then insymbol
                   else begin
                          error(14);
                          if sy = comma
                          then insymbol
                        end;
                        test( [ident, varsy],[rparent]+fsys,6)
                 end
        end { while };
      if sy = rparent{*参数声明结束后用右括号结束*}
      then begin
             insymbol;
             test( [semicolon, colon],fsys,6 ){*应该用分号结束这一行,或者用冒号声明返回值类型,如果不是这两种就报错*}
           end
      else error(4)
    end { parameterlist };


procedure constdec;{*处理常量声明*}
    var c : conrec;
begin
      insymbol;
      test([ident], blockbegsys, 2 );
      while sy = ident do
        begin
          enter(id, konstant);{*入表*}
          insymbol;
          if sy = eql
          then insymbol
          else begin
                 error(16);
                 if sy = becomes{*容错*}
                 then insymbol
               end;
          constant([semicolon,comma,ident]+fsys,c);{*调用分析程序,通过c返回类型和数值,并填表*}
          tab[t].typ := c.tp;
          tab[t].ref := 0;
          if c.tp = reals{*如果是实数*}
          then begin
enterreal(c.r);
                tab[t].adr := c1;{*在实常量表中的位置*}
end
          else tab[t].adr := c.i;{*如果是整型*}
          testsemicolon
        end
    end { constdec };

  procedure typedeclaration;{*处理类型声明*}
var tp: types;
        rf, sz, t1 : integer;
begin
      insymbol;
      test([ident], blockbegsys,2 );{*检查是不是标识符*}
      while sy = ident do
        begin
          enter(id, typel);{*类型入表*}
          t1 := t;
          insymbol;
          if sy = eql{*读等号*}
          then insymbol
          else begin
                 error(16);
                 if sy = becomes{*如果是赋值符号容错*}
                 then insymbol
               end;
          typ( [semicolon,comma,ident]+fsys, tp,rf,sz );{*获取类型变量的类型,在符号表中的位置,和占空间的大小*}
          with tab[t1] do
            begin
              typ := tp;
              ref := rf;
              adr := sz
            end;
          testsemicolon
        end
    end { typedeclaration };

  procedure variabledeclaration;{*处理变量声明*}
var tp : types;
        t0, t1, rf, sz : integer;
    begin
      insymbol;
while sy = ident do
        begin
          t0 := t;
          entervariable;{*如果是标识符,变量入表*}
          while sy = comma do
            begin
              insymbol;
              entervariable;
            end;
          if sy = colon
          then insymbol{*读到冒号继续,否则报错*}
          else error(5);
          t1 := t;
          typ([semicolon,comma,ident]+fsys, tp,rf,sz );{*获取类型,地址,占用空间*}
          while t0 < t1 do
            begin
              t0 := t0 + 1;
              with tab[t0] do
                begin
                  typ := tp;
                  ref := rf;
                  lev := level;
                  adr := dx;
                  normal := true;
                  dx := dx + sz
                end
            end;
          testsemicolon
        end
    end { variabledeclaration };

  procedure procdeclaration;{*处理过程声明*}
    var isfun : boolean;
    begin
      isfun := sy = funcsy;{*如果读到的符号是function,那么设置函数标志*}
      insymbol;
      if sy <> ident
      then begin
             error(2);{*不是标识符报错*}
             id :='          '
           end;
      if isfun
      then enter(id,funktion)
      else enter(id,prozedure);{*根据是函数还是过程记录不同的信息到表中*}
      tab[t].normal := true;
      insymbol;
      block([semicolon]+fsys, isfun, level+1 );
      if sy = semicolon
      then insymbol
      else error(14);
      emit(32+ord(isfun)) {exit}{*退出过程/函数*}
    end { proceduredeclaration };


procedure statement( fsys:symset );
    var i : integer;

procedure expression(fsys:symset; var x:item); forward;{*表达式处理子程序,通过x返回结果。forward使得selector能够调用expression*}
    procedure selector(fsys:symset; var v:item);{*处理结构变量*}
    var x : item;
        a,j : integer;
    begin { sy in [lparent, lbrack, period] }{*当前符号应该是左括号,或者左中括号,或者句号*}
      repeat
        if sy = period{*如果当前符号是句号,开始处理后面的结构*}
        then begin
               insymbol; { field selector }
               if sy <> ident
               then error(2){*不是标识符报错*}
               else begin
                      if v.typ <> records{*如果不是记录类型报错*}
                      then error(31)
                      else begin { search field identifier }{*在符号表中寻找类型标识符*}
                             j := btab[v.ref].last;{*得到结构体在符号表中最后一个符号的位置*}
                             tab[0].name := id;
                             while tab[j].name <> id do
                               j := tab[j].link;
                             if j = 0
                             then error(0);{*在符号表中寻找当前符号,没找到就继续找,如果当前层次不存在这个符号报错*}
                             v.typ := tab[j].typ;
                             v.ref := tab[j].ref;
                             a := tab[j].adr;{*记录这个成员变量相对于记录变量起始地址的位移*}
                             if a <> 0
                             then emit1(9,a)
                           end;
                      insymbol
                    end
             end
        else begin { array selector }{*处理数组下标*}
               if sy <> lbrack
               then error(11);{*没有读到左中括号报错*}
               repeat
                 insymbol;
                 expression( fsys+[comma,rbrack],x);{*递归调用表达式处理程序,将结果保存到x中*}
                 if v.typ <> arrays{*如果传入的类型不是数组报错*}
                 then error(28)
                 else begin
                        a := v.ref;{*得到数组在数组信息向量表的地址*}
                        if atab[a].inxtyp <> x.typ{*如果数组下标和数组规定的类型不符,报错*}
                        then error(26)
                        else if atab[a].elsize = 1{*如果是变量形参*}
                             then emit1(20,a){*寻址*}
                             else emit1(21,a);{*值形参也寻址*}
                        v.typ := atab[a].eltyp;{*获得当前数组元素的类型*}
                        v.ref := atab[a].elref{*和在数组信息向量表中的位置*}
                      end
               until sy <> comma;{*如果不是逗号,说明还有*}
               if sy = rbrack{*读取右中括号*}
               then insymbol
               else begin
                      error(12);
                      if sy = rparent{*读到右括号报错*}
                      then insymbol
                    end
             end
      until not( sy in[lbrack, lparent, period]);{*直到读完所有的子结构*}
      test( fsys,[],6)
    end { selector };

    procedure call( fsys: symset; i:integer );{*处理非标准的过程或函数调用*}
var x : item;
          lastp,cp,k : integer;
begin
        emit1(18,i); { mark stack }{*标记栈,传入被调用的过程或函数在符号表中的位置,建立新的内务信息区*}
        lastp := btab[tab[i].ref].lastpar;{*记录最后一个参数在符号表的位置*}
        cp := i;
        if sy = lparent
        then begin { actual parameter list }{*如果是左括号开始识别参数*}
               repeat
                 insymbol;
                 if cp >= lastp
                 then error(39){*如果当前符号位置超过了最后一个参数的位置,报错;否则一直读参数*}
                 else begin
                        cp := cp + 1;
                        if tab[cp].normal{*normal为1说明是值形参*}
                        then begin { value parameter }
                               expression( fsys+[comma, colon,rparent],x);{*调用表达式处理程序,结果保存在x*}
                               if x.typ = tab[cp].typ{*检查,如果表达式结果的类型和符号表中的类型相同*}
                               then begin
                                      if x.ref <> tab[cp].ref
                                      then error(36){*如果表达式地址和符号表中当前符号的地址不相同则报错*}
                                      else if x.typ = arrays
                                           then emit1(22,atab[x.ref].size){*如果是数组,生成装载指令,将实参表达式的值或地址存在预留的参数区*}
                                           else if x.typ = records
                                                then emit1(22,btab[x.ref].vsize){*如果是记录,生成装载指令等*}
                                    end
                               else if ( x.typ = ints ) and ( tab[cp].typ = reals ){*如果是整型或者实型*}
                                    then emit1(26,0){*类型转换*}
                                    else if x.typ <> notyp
                                         then error(36);
                             end
                        else begin { variable parameter }
                               if sy <> ident{*先识别标识符,没识别到就报错*}
                               then error(2)
                               else begin
                                      k := loc(id);
                                      insymbol;
                                      if k <> 0{*如果在符号表中找到了当前id*}
                                      then begin
                                             if tab[k].obj <> vvariable
                                             then error(37);{*种类不是var报错*}
                                             x.typ := tab[k].typ;
                                             x.ref := tab[k].ref;
                                             if tab[k].normal{*如果是值形参*}
                                             then emit2(0,tab[k].lev,tab[k].adr){*变量地址入栈*}
else emit2(1,tab[k].lev,tab[k].adr);{*否则变量的值入栈*}
if sy in [lbrack, lparent, period]{*如果是左中括号,左括号,或者句号*}
                                             then selector(fsys+[comma,colon,rparent],x);{*调用分程序*}
                                             if ( x.typ <> tab[cp].typ ) or ( x.ref <> tab[cp].ref ){*类型不同或者地址不同报错*}
                                             then error(36)
                                           end
                                    end
                             end {variable parameter }
                      end;
                 test( [comma, rparent],fsys,6)
               until sy <> comma;{*不是逗号了,说明没有参数了*}
               if sy = rparent{*读到右括号结束*}
               then insymbol
               else error(4)
             end;
        if cp < lastp
        then error(39); { too few actual parameters }
        emit1(19,btab[tab[i].ref].psize-1 );{*生成CALL,调用*}
        if tab[i].lev < level
        then emit2(3,tab[i].lev, level ){*如果符号层次小于当前层次更新display区*}
      end { call };

    function resulttype( a, b : types) :types;{*处理整型实型的类型转换*}
      begin
        if ( a > reals ) or ( b > reals )
        then begin
               error(33);
               resulttype := notyp{*超过上限报错,设置为无类型*}
             end
        else if ( a = notyp ) or ( b = notyp )
             then resulttype := notyp{*两个操作数都是无类型,那结果设置为无类型*}
             else if a = ints
                  then if b = ints
                       then resulttype := ints{*两个操作数都是整型,结果就是整型*}
                       else begin
                              resulttype := reals;{*一个整型,一个实型,结果是实型*}
                              emit1(26,1){*对整型进行类型转化*}
                            end
                  else begin
                         resulttype := reals;
                         if b = ints
                         then emit1(26,0)
                       end
      end { resulttype } ;

    procedure expression( fsys: symset; var x: item );
var y : item;
          op : symbol;

      procedure simpleexpression( fsys: symset; var x: item );
        var y : item;
            op : symbol;

        procedure term( fsys: symset; var x: item );
          var y : item;
              op : symbol;

          procedure factor( fsys: symset; var x: item );
            var i,f : integer;

            procedure standfct( n: integer );{*处理标准函数,传入标准函数的编号,执行不同的操作*}
              var ts : typset;
begin  { standard function no. n }
                if sy = lparent{*读左括号*}
                then insymbol
                else error(9);
                if n < 17{*如果编号小于17*}
                then begin
                       expression( fsys+[rparent], x );{*处理参数*}
                       case n of
                       { abs, sqr } 0,2: begin{*0、2:求绝对值,平方*}
                                           ts := [ints, reals];
                                           tab[i].typ := x.typ;
                                           if x.typ = reals
                                           then n := n + 1{*如果参数类型是实型,函数标号++*}
                                         end;
                       { odd, chr } 4,5: ts := [ints];{*判断基数,转ascii*}
                       { odr }        6: ts := [ints,bools,chars];
                       { succ,pred } 7,8 : begin
                                             ts := [ints, bools,chars];
                                             tab[i].typ := x.typ
                                           end;
                       { round,trunc } 9,10,11,12,13,14,15,16:{*数学运算*}
                       { sin,cos,... }     begin
                                             ts := [ints,reals];
                                             if x.typ = ints
                                             then emit1(26,0)
                                           end;
                     end; { case }
                     if x.typ in ts
                     then emit1(8,n){*如果类型符合,生成标准函数*}
                     else if x.typ <> notyp
                          then error(48);
                   end
                else begin { n in [17,18] }{*判断输入是否结束*}
                       if sy <> ident
                       then error(2)
                       else if id <> 'input    '
                            then error(0)
                            else insymbol;
                       emit1(8,n);
                     end;
x.typ := tab[i].typ;
if sy = rparent
                then insymbol
                else error(4)
              end { standfct } ;
            begin { factor }{*分析因子*}
              x.typ := notyp;
              x.ref := 0;
              test( facbegsys, fsys,58 );
              while sy in facbegsys do
                begin
                  if sy = ident
                  then begin
                         i := loc(id);
                         insymbol;
                         with tab[i] do
                           case obj of
                             konstant: begin
                                         x.typ := typ;
                                         x.ref := 0;
                                         if x.typ = reals
then emit1(25,adr)
                                         else emit1(24,adr)
end;
                             vvariable:begin
                                         x.typ := typ;
                                         x.ref := ref;
                                         if sy in [lbrack, lparent,period]
                                         then begin
                                                if normal
                                                then f := 0
else f := 1;
                                                emit2(f,lev,adr);
selector(fsys,x);
                                                if x.typ in stantyps
                                                then emit(34)
                                              end
                                         else begin{*没有层次结构*}
                                                if x.typ in stantyps
                                                then if normal
                                                     then f := 1{*取值*}
                                                     else f := 2{*间接取值*}
                                                else if normal
                                                     then f := 0{*取地址*}
else f := 1;
                                                emit2(f,lev,adr)
end
                                       end;
                             typel,prozedure: error(44);
                             funktion: begin
                                         x.typ := typ;
                                         if lev <> 0{*不是标准函数*}
                                         then call(fsys,i)
                                         else standfct(adr)
                                       end
                           end { case,with }
                       end
                  else if sy in [ charcon,intcon,realcon ]
                       then begin
                              if sy = realcon
                              then begin
x.typ := reals;
                                     enterreal(rnum);
emit1(25,c1)
                                   end
                              else begin
                                     if sy = charcon
                                     then x.typ := chars
                                     else x.typ := ints;
                                     emit1(24,inum)
                                   end;
                              x.ref := 0;
                              insymbol
                            end
                       else if sy = lparent
                            then begin
                                   insymbol;
                                   expression(fsys + [rparent],x);{*表达式处理程序处理括号中的表达式*}
                                   if sy = rparent
                                   then insymbol
                                   else error(4)
                                 end
                             else if sy = notsy
                                  then begin
                                         insymbol;
                                         factor(fsys,x);
                                         if x.typ = bools
                                         then emit(35)
                                         else if x.typ <> notyp
                                              then error(32)
                                       end;
                  test(fsys,facbegsys,6)
                end { while }
            end { factor };
          begin { term   }
            factor( fsys + [times,rdiv,idiv,imod,andsy],x);
            while sy in [times,rdiv,idiv,imod,andsy] do{*如果出现*,/,div,mod,and,说明还有因子*}
              begin
                op := sy;
                insymbol;
                factor(fsys+[times,rdiv,idiv,imod,andsy],y );
                if op = times
                then begin
                       x.typ := resulttype(x.typ, y.typ);
                       case x.typ of
                         notyp: ;
                         ints : emit(57);
                         reals: emit(60);
                       end
                     end
                else if op = rdiv
                     then begin
                            if x.typ = ints
                            then begin
                                   emit1(26,1);{*整型转换为实型*}
                                   x.typ := reals;
                                 end;
                            if y.typ = ints
                            then begin
                                   emit1(26,0);
                                   y.typ := reals;
                                 end;
                            if (x.typ = reals) and (y.typ = reals)
                            then emit(61)
                            else begin
                                   if( x.typ <> notyp ) and (y.typ <> notyp)
                                   then error(33);
                                   x.typ := notyp
                                 end
                          end
                     else if op = andsy
                          then begin
                                 if( x.typ = bools )and(y.typ = bools)
                                 then emit(56)
                                 else begin
                                        if( x.typ <> notyp ) and (y.typ <> notyp)
                                        then error(32);
                                        x.typ := notyp
                                      end
                               end
                          else begin { op in [idiv,imod] }
                                 if (x.typ = ints) and (y.typ = ints)
                                 then if op = idiv
                                      then emit(58)
                                      else emit(59)
                                 else begin
                                        if ( x.typ <> notyp ) and (y.typ <> notyp)
                                        then error(34);
                                        x.typ := notyp
                                      end
                               end
              end { while }
          end { term };
        begin { simpleexpression }{*处理简单表达式*}
          if sy in [plus,minus]
          then begin
                 op := sy;
                 insymbol;
                 term( fsys+[plus,minus],x);{*处理项*}
                 if x.typ > reals
                 then error(33)
                 else if op = minus
                      then emit(36)
               end
          else term(fsys+[plus,minus,orsy],x);
          while sy in [plus,minus,orsy] do
            begin
              op := sy;
              insymbol;
              term(fsys+[plus,minus,orsy],y);
              if op = orsy
              then begin
                     if ( x.typ = bools )and(y.typ = bools)
                     then emit(51)
                     else begin
                            if( x.typ <> notyp) and (y.typ <> notyp)
                            then error(32);
                            x.typ := notyp
                          end
                   end
              else begin
                     x.typ := resulttype(x.typ,y.typ);
                     case x.typ of
                       notyp: ;
                       ints: if op = plus
                             then emit(52)
                             else emit(53);
                       reals:if op = plus
                             then emit(54)
                             else emit(55)
                     end { case }
                   end
            end { while }
          end { simpleexpression };
      begin { expression  }
        simpleexpression(fsys+[eql,neq,lss,leq,gtr,geq],x);
        if sy in [ eql,neq,lss,leq,gtr,geq]
        then begin
               op := sy;
               insymbol;
               simpleexpression(fsys,y);{*获取第二个简单表达式的值*}
               if(x.typ in [notyp,ints,bools,chars]) and (x.typ = y.typ)
               then case op of
                      eql: emit(45);
                      neq: emit(46);
                      lss: emit(47);
                      leq: emit(48);
                      gtr: emit(49);
                      geq: emit(50);
                    end
               else begin
                      if x.typ = ints
                      then begin
                             x.typ := reals;
                             emit1(26,1)
                           end
                      else if y.typ = ints
                           then begin
                                  y.typ := reals;
                                  emit1(26,0)
                                end;
                      if ( x.typ = reals)and(y.typ=reals)
                      then case op of
                             eql: emit(39);
                             neq: emit(40);
                             lss: emit(41);
                             leq: emit(42);
                             gtr: emit(43);
                             geq: emit(44);
                           end
                      else error(35)
                    end;
               x.typ := bools
             end
      end { expression };

    procedure assignment( lv, ad: integer );{*处理赋值语句*}
      var x,y: item;
          f  : integer;
      begin   { tab[i].obj in [variable,prozedure] }{*条件:当前符号的类型是变量或者过程*}
x.typ := tab[i].typ;
x.ref := tab[i].ref;
        if tab[i].normal
        then f := 0
        else f := 1;
        emit2(f,lv,ad);
        if sy in [lbrack,lparent,period]
        then selector([becomes,eql]+fsys,x);{*处理下标*}
        if sy = becomes
        then insymbol
        else begin
               error(51);
               if sy = eql{*容错*}
               then insymbol
             end;
        expression(fsys,y);{*计算赋值符号右边的值*}
        if x.typ = y.typ
        then if x.typ in stantyps
             then emit(38)
             else if x.ref <> y.ref
                  then error(46){*类型相同赋值,否则报错*}
                  else if x.typ = arrays{*数组类型需要一块一块拷贝*}
                       then emit1(23,atab[x.ref].size)
                       else emit1(23,btab[x.ref].vsize)
        else if(x.typ = reals )and (y.typ = ints)
        then begin
               emit1(26,0);
               emit(38)
             end
        else if ( x.typ <> notyp ) and ( y.typ <> notyp )
             then error(46)
      end { assignment };

    procedure compoundstatement;{*处理复合语句*}
      begin
        insymbol;
        statement([semicolon,endsy]+fsys);
        while sy in [semicolon]+statbegsys do
          begin
            if sy = semicolon
            then insymbol
            else error(14);
            statement([semicolon,endsy]+fsys)
          end;
        if sy = endsy
        then insymbol
        else error(57)
      end { compoundstatement };

    procedure ifstatement;{*处理if语句*}
var x : item;
          lc1,lc2: integer;
begin
        insymbol;
        expression( fsys+[thensy,dosy],x);
        if not ( x.typ in [bools,notyp])
        then error(17);
        lc1 := lc;
        emit(11);  { jmpc }
        if sy = thensy
        then insymbol
        else begin
               error(52);
               if sy = dosy
               then insymbol
             end;
        statement( fsys+[elsesy]);
        if sy = elsesy
        then begin
               insymbol;
               lc2 := lc;
emit(10);
               code[lc1].y := lc;
               statement(fsys);
               code[lc2].y := lc
             end
        else code[lc1].y := lc
end { ifstatement };

    procedure casestatement;{*处理case语句*}
      var x : item;
i,j,k,lc1 : integer;
casetab : array[1..csmax]of
                     packed record
                       val,lc : index
                     end;
        exittab : array[1..csmax] of integer;

procedure caselabel;{*处理case语句的标号,将各标号对应的目标代码的入口地址存到casetab表中,检查标号有没有重复定义*}
        var lab : conrec;
k : integer;
        begin
          constant( fsys+[comma,colon],lab );{*标签都是常量*}
          if lab.tp <> x.typ
          then error(47)
          else if i = csmax
               then fatal(6){*啊case个数还有限制*}
               else begin
                      i := i+1;
k := 0;
                      casetab[i].val := lab.i;
                      casetab[i].lc := lc;
repeat
                        k := k+1
                      until casetab[k].val = lab.i;{*有没有重复声明*}
                      if k < i
                      then error(1); { multiple definition }
                    end
        end { caselabel };

      procedure onecase;{*用来处理case语句的一个分支*}
        begin
          if sy in constbegsys
          then begin
                 caselabel;
                 while sy = comma do
                   begin
                     insymbol;
                     caselabel
                   end;
                 if sy = colon
                 then insymbol
                 else error(5);
                 statement([semicolon,endsy]+fsys);
j := j+1;
                 exittab[j] := lc;{*记录当前case分支结束的位置,用于生成跳转指令的位置*}
emit(10)
               end
          end { onecase };
      begin  { casestatement  }
        insymbol;
        i := 0;
        j := 0;
        expression( fsys + [ofsy,comma,colon],x );
        if not( x.typ in [ints,bools,chars,notyp ])
then error(23);
        lc1 := lc;{*记录当前Pcode的位置*}
        emit(12); {jmpx}{*SWT*}
if sy = ofsy
        then insymbol
        else error(8);
        onecase;
        while sy = semicolon do{*遇到分号说明还有更多的分支*}
          begin
            insymbol;
            onecase
          end;
        code[lc1].y := lc;{*反填*}
        for k := 1 to i do
          begin
            emit1( 13,casetab[k].val);
            emit1( 13,casetab[k].lc);
          end;
        emit1(10,0);
        for k := 1 to j do{*给定每个vase退出之后的跳转地址*}
code[exittab[k]].y := lc;
if sy = endsy
        then insymbol
        else error(57)
      end { casestatement };

    procedure repeatstatement;{*repeat语句的处理过程*}
      var x : item;{*记录返回值*}
          lc1: integer;{*用来记录repeat的开始位置*}
      begin
        lc1 := lc;{*记录开始的位置*}
        insymbol;
        statement( [semicolon,untilsy]+fsys);{*处理循环体中的语句*}
        while sy in [semicolon]+statbegsys do{*还有语句没有处理完*}
          begin
            if sy = semicolon
            then insymbol
            else error(14);
            statement([semicolon,untilsy]+fsys)
          end;
        if sy = untilsy
        then begin
               insymbol;
               expression(fsys,x);
               if not(x.typ in [bools,notyp] )
               then error(17);
               emit1(11,lc1);
             end
        else error(53)
      end { repeatstatement };

    procedure whilestatement;{*处理while循环*}
      var x : item;
          lc1,lc2 : integer;
      begin
        insymbol;
        lc1 := lc;
        expression( fsys+[dosy],x);
        if not( x.typ in [bools, notyp] )
then error(17);
        lc2 := lc;
        emit(11);
if sy = dosy
        then insymbol
        else error(54);
statement(fsys);
        emit1(10,lc1);
        code[lc2].y := lc
end { whilestatement };

    procedure forstatement;{*处理for循环*}
      var  cvt : types;
x :  item;
          i,f,lc1,lc2 : integer;
begin
        insymbol;
        if sy = ident
        then begin
               i := loc(id);
               insymbol;
               if i = 0
               then cvt := ints
               else if tab[i].obj = vvariable
                    then begin
                           cvt := tab[i].typ;
                           if not tab[i].normal
                           then error(37)
else emit2(0,tab[i].lev, tab[i].adr );
if not ( cvt in [notyp, ints, bools, chars])
                           then error(18)
                         end
                    else begin
                           error(37);
                           cvt := ints
                         end
             end
        else skip([becomes,tosy,downtosy,dosy]+fsys,2);
        if sy = becomes
        then begin
               insymbol;
               expression( [tosy, downtosy,dosy]+fsys,x);
               if x.typ <> cvt
               then error(19);
             end
        else skip([tosy, downtosy,dosy]+fsys,51);{*downto是递减*}
        f := 14;
        if sy in [tosy,downtosy]
        then begin
               if sy = downtosy
               then f := 16;
               insymbol;
               expression([dosy]+fsys,x);
               if x.typ <> cvt
               then error(19)
             end
        else skip([dosy]+fsys,55);{*跳过直到do之前的代码*}
        lc1 := lc;{*记录指令位置*}
        emit(f);
        if sy = dosy
        then insymbol
        else error(54);
        lc2 := lc;{*循环开始的位置*}
statement(fsys);
        emit1(f+1,lc2);
        code[lc1].y := lc
end { forstatement };

    procedure standproc( n: integer );{*处理标准输入输出过程调用*}
      var i,f : integer;
x,y : item;
      begin
        case n of
          1,2 : begin { read }
                  if not iflag
                  then begin
                         error(20);
                         iflag := true
                       end;
                  if sy = lparent
                  then begin
                         repeat
                           insymbol;
                           if sy <> ident
                           then error(2)
                           else begin
                                  i := loc(id);
                                  insymbol;
                                  if i <> 0
                                  then if tab[i].obj <> vvariable
                                       then error(37)
                                       else begin
                                              x.typ := tab[i].typ;
                                              x.ref := tab[i].ref;
                                              if tab[i].normal
then f := 0
                                              else f := 1;
                                              emit2(f,tab[i].lev,tab[i].adr);
if sy in [lbrack,lparent,period]
                                              then selector( fsys+[comma,rparent],x);
                                              if x.typ in [ints,reals,chars,notyp]
then emit1(27,ord(x.typ))
else error(41)
                                            end
                                end;
                           test([comma,rparent],fsys,6);
                         until sy <> comma;
                         if sy = rparent
                         then insymbol
                         else error(4)
                       end;
                  if n = 2
                  then emit(62)
                end;
          3,4 : begin { write }
                  if sy = lparent
                  then begin
                         repeat
                           insymbol;
                           if sy = stringcon
                           then begin
                                  emit1(24,sleng);
                                  emit1(28,inum);
                                  insymbol
                                end
                           else begin
expression(fsys+[comma,colon,rparent],x);
if not( x.typ in stantyps )
                                  then error(41);
                                  if sy = colon
                                  then begin
insymbol;
                                         expression( fsys+[comma,colon,rparent],y);
if y.typ <> ints
                                         then error(43);
                                         if sy = colon
                                         then begin
                                                if x.typ <> reals
                                                then error(42);
                                                insymbol;
                                                expression(fsys+[comma,rparent],y);
                                                if y.typ <> ints
                                                then error(43);
                                                emit(37)
                                              end
                                         else emit1(30,ord(x.typ))
                                       end
else emit1(29,ord(x.typ))
end
                         until sy <> comma;
                         if sy = rparent
                         then insymbol
                         else error(4)
                       end;
                  if n = 4
                  then emit(63)
                end; { write }
        end { case };
      end { standproc } ;
    begin { statement }
      if sy in statbegsys+[ident]
      then case sy of
             ident : begin
                       i := loc(id);
                       insymbol;
                       if i <> 0
                       then case tab[i].obj of
konstant,typel : error(45);
                              vvariable:       assignment( tab[i].lev,tab[i].adr);
prozedure:       if tab[i].lev <> 0
                                               then call(fsys,i)
                                               else standproc(tab[i].adr);
                              funktion:        if tab[i].ref = display[level]
                                               then assignment(tab[i].lev+1,0)
                                               else error(45)
                            end { case }
                     end;
             beginsy : compoundstatement;
             ifsy    : ifstatement;
             casesy  : casestatement;
             whilesy : whilestatement;
             repeatsy: repeatstatement;
             forsy   : forstatement;
           end;  { case }
      test( fsys, [],14);
    end { statement };
  begin  { block }
    dx := 5;{*预设5,为内务信息区留出空间*}
    prt := t;
    if level > lmax
    then fatal(5);
    test([lparent,colon,semicolon],fsys,14);
    enterblock;
    prb := b;
    display[level] := b;
    tab[prt].typ := notyp;
    tab[prt].ref := prb;
    if ( sy = lparent ) and ( level > 1 )
    then parameterlist;
    btab[prb].lastpar := t;
    btab[prb].psize := dx;
    if isfun
    then if sy = colon
         then begin
                insymbol; { function type }
                if sy = ident
                then begin
                       x := loc(id);
                       insymbol;
                       if x <> 0
                       then if tab[x].typ in stantyps
                            then tab[prt].typ := tab[x].typ
                            else error(15)
                     end
                else skip( [semicolon]+fsys,2 )
              end
         else error(5);
    if sy = semicolon
    then insymbol
    else error(14);
    repeat
      if sy = constsy
      then constdec;
      if sy = typesy
      then typedeclaration;
      if sy = varsy
      then variabledeclaration;
      btab[prb].vsize := dx;
      while sy in [procsy,funcsy] do
        procdeclaration;
      test([beginsy],blockbegsys+statbegsys,56)
    until sy in statbegsys;
    tab[prt].adr := lc;
    insymbol;
    statement([semicolon,endsy]+fsys);
    while sy in [semicolon]+statbegsys do
      begin
        if sy = semicolon
        then insymbol
        else error(14);
        statement([semicolon,endsy]+fsys);
      end;
    if sy = endsy
    then insymbol
    else error(57);
    test( fsys+[period],[],6 )
  end { block };



procedure interpret;{*解释执行程序*}
  var ir : order ;         { instruction buffer }
      pc : integer;        { program counter }
      t  : integer;        { top stack index }
b  : integer;        { base index }
      h1,h2,h3: integer;
      lncnt,ocnt,blkcnt,chrcnt: integer;     { counters }
      ps : ( run,fin,caschk,divchk,inxchk,stkchk,linchk,lngchk,redchk );
fld: array [1..4] of integer;  { default field widths }
      display : array[0..lmax] of integer;
      s  : array[1..stacksize] of   { blockmark:     }
            record
              case cn : types of        { s[b+0] = fct result }
                ints : (i: integer );   { s[b+1] = return adr }
                reals :(r: real );      { s[b+2] = static link }
                bools :(b: boolean );   { s[b+3] = dynamic link }
                chars :(c: char )       { s[b+4] = table index }
end;

  procedure dump;
    var p,h3 : integer;
begin
      h3 := tab[h2].lev;
      writeln(psout);
      writeln(psout);
      writeln(psout,'       calling ', tab[h2].name );
      writeln(psout,'         level ',h3:4);
      writeln(psout,' start of code ',pc:4);
      writeln(psout);
      writeln(psout);
      writeln(psout,' contents of display ');
      writeln(psout);
      for p := h3 downto 0 do
        writeln(psout,p:4,display[p]:6);
      writeln(psout);
      writeln(psout);
      writeln(psout,' top of stack  ',t:4,' frame base ':14,b:4);
      writeln(psout);
      writeln(psout);
      writeln(psout,' stack contents ':20);
      writeln(psout);
      for p := t downto 1 do
        writeln( psout, p:14, s[p].i:8);
      writeln(psout,'< = = = >':22)
    end; {dump }

  procedure inter0;
    begin
      case ir.f of
        0 : begin { load addrss }
              t := t + 1;
              if t > stacksize
              then ps := stkchk
              else s[t].i := display[ir.x]+ir.y
            end;
        1 : begin  { load value }
              t := t + 1;
              if t > stacksize
              then ps := stkchk
              else s[t] := s[display[ir.x]+ir.y]
            end;
        2 : begin  { load indirect }
              t := t + 1;
              if t > stacksize
              then ps := stkchk
              else s[t] := s[s[display[ir.x]+ir.y].i]
            end;
        3 : begin  { update display }
              h1 := ir.y;
              h2 := ir.x;
              h3 := b;
              repeat
                display[h1] := h3;
                h1 := h1-1;
                h3 := s[h3+2].i
              until h1 = h2
            end;
        8 : case ir.y of
              0 : s[t].i := abs(s[t].i);
              1 : s[t].r := abs(s[t].r);
              2 : s[t].i := sqr(s[t].i);
              3 : s[t].r := sqr(s[t].r);
              4 : s[t].b := odd(s[t].i);
              5 : s[t].c := chr(s[t].i);
              6 : s[t].i := ord(s[t].c);
              7 : s[t].c := succ(s[t].c);
              8 : s[t].c := pred(s[t].c);
              9 : s[t].i := round(s[t].r);
              10 : s[t].i := trunc(s[t].r);
              11 : s[t].r := sin(s[t].r);
              12 : s[t].r := cos(s[t].r);
              13 : s[t].r := exp(s[t].r);
              14 : s[t].r := ln(s[t].r);
              15 : s[t].r := sqrt(s[t].r);
              16 : s[t].r := arcTan(s[t].r);
              17 : begin
                     t := t+1;
                     if t > stacksize
                     then ps := stkchk
                     else s[t].b := eof(prd)
                   end;
              18 : begin
                     t := t+1;
                     if t > stacksize
                     then ps := stkchk
                     else s[t].b := eoln(prd)
                   end;
            end;
        9 : s[t].i := s[t].i + ir.y; { offset }
      end { case ir.y }
    end; { inter0 }

procedure inter1;
    var h3, h4: integer;
begin
      case ir.f of
        10 : pc := ir.y ; { jump }
        11 : begin  { conditional jump }
               if not s[t].b
then pc := ir.y;
               t := t - 1
end;
        12 : begin { switch }
               h1 := s[t].i;
               t := t-1;
               h2 := ir.y;
               h3 := 0;
               repeat
                 if code[h2].f <> 13
                 then begin
                        h3 := 1;
                        ps := caschk
                      end
                 else if code[h2].y = h1
                      then begin
                             h3 := 1;
                             pc := code[h2+1].y
                           end
                      else h2 := h2 + 2
               until h3 <> 0
             end;
        14 : begin { for1up }
               h1 := s[t-1].i;
               if h1 <= s[t].i
               then s[s[t-2].i].i := h1
               else begin
                      t := t - 3;
                      pc := ir.y
                    end
             end;
        15 : begin { for2up }
               h2 := s[t-2].i;
               h1 := s[h2].i+1;
               if h1 <= s[t].i
               then begin
                      s[h2].i := h1;
                      pc := ir.y
                    end
               else t := t-3;
             end;
        16 : begin  { for1down }
               h1 := s[t-1].i;
               if h1 >= s[t].i
               then s[s[t-2].i].i := h1
               else begin
                      pc := ir.y;
                      t := t - 3
                    end
             end;
        17 : begin  { for2down }
               h2 := s[t-2].i;
               h1 := s[h2].i-1;
               if h1 >= s[t].i
               then begin
                      s[h2].i := h1;
                      pc := ir.y
                    end
               else t := t-3;
             end;
        18 : begin  { mark stack }
               h1 := btab[tab[ir.y].ref].vsize;
               if t+h1 > stacksize
               then ps := stkchk
               else begin
                      t := t+5;
                      s[t-1].i := h1-1;
                      s[t].i := ir.y
                    end
             end;
        19 : begin  { call }
               h1 := t-ir.y;  { h1 points to base }
               h2 := s[h1+4].i;  { h2 points to tab }
               h3 := tab[h2].lev;
               display[h3+1] := h1;
               h4 := s[h1+3].i+h1;
               s[h1+1].i := pc;
               s[h1+2].i := display[h3];
               s[h1+3].i := b;
               for h3 := t+1 to h4 do
                 s[h3].i := 0;
               b := h1;
               t := h4;
               pc := tab[h2].adr;
               if stackdump
               then dump
             end;
      end { case }
    end; { inter1 }

  procedure inter2;
    begin
      case ir.f of
        20 : begin   { index1 }
               h1 := ir.y;  { h1 points to atab }
               h2 := atab[h1].low;
               h3 := s[t].i;
               if h3 < h2
               then ps := inxchk
               else if h3 > atab[h1].high
                    then ps := inxchk
                    else begin
                           t := t-1;
                           s[t].i := s[t].i+(h3-h2)
                         end
             end;
        21 : begin  { index }
               h1 := ir.y ; { h1 points to atab }
               h2 := atab[h1].low;
               h3 := s[t].i;
               if h3 < h2
               then ps := inxchk
               else if h3 > atab[h1].high
                    then ps := inxchk
                    else begin
                           t := t-1;
                           s[t].i := s[t].i + (h3-h2)*atab[h1].elsize
                         end
             end;
        22 : begin  { load block }
               h1 := s[t].i;
               t := t-1;
               h2 := ir.y+t;
               if h2 > stacksize
               then ps := stkchk
               else while t < h2 do
                      begin
                        t := t+1;
                        s[t] := s[h1];
                        h1 := h1+1
                      end
             end;
        23 : begin  { copy block }
               h1 := s[t-1].i;
               h2 := s[t].i;
               h3 := h1+ir.y;
               while h1 < h3 do
                 begin
                   s[h1] := s[h2];
                   h1 := h1+1;
                   h2 := h2+1
                 end;
               t := t-2
             end;
        24 : begin  { literal }
               t := t+1;
               if t > stacksize
               then ps := stkchk
               else s[t].i := ir.y
             end;
        25 : begin  { load real }
               t := t+1;
               if t > stacksize
               then ps := stkchk
               else s[t].r := rconst[ir.y]
             end;
        26 : begin  { float }
               h1 := t-ir.y;
               s[h1].r := s[h1].i
             end;
        27 : begin  { read }
               if eof(prd)
               then ps := redchk
               else case ir.y of
                      1 : read(prd, s[s[t].i].i);
                      2 : read(prd, s[s[t].i].r);
                      4 : read(prd, s[s[t].i].c);
                    end;
               t := t-1
             end;
        28 : begin   { write string }
h1 := s[t].i;
               h2 := ir.y;
               t := t-1;
               chrcnt := chrcnt+h1;
if chrcnt > lineleng
               then ps := lngchk;
               repeat
                 write(prr,stab[h2]);
                 h1 := h1-1;
                 h2 := h2+1
               until h1 = 0
             end;
        29 : begin  { write1 }
               chrcnt := chrcnt + fld[ir.y];
               if chrcnt > lineleng
               then ps := lngchk
               else case ir.y of
                      1 : write(prr,s[t].i:fld[1]);
                      2 : write(prr,s[t].r:fld[2]);
                      3 : if s[t].b
                          then write('true')
                          else write('false');
                      4 : write(prr,chr(s[t].i));
                    end;
               t := t-1
             end;
      end { case }
    end; { inter2 }

  procedure inter3;
    begin
      case ir.f of
        30 : begin { write2 }
               chrcnt := chrcnt+s[t].i;
               if chrcnt > lineleng
               then ps := lngchk
               else case ir.y of
                      1 : write(prr,s[t-1].i:s[t].i);
                      2 : write(prr,s[t-1].r:s[t].i);
                      3 : if s[t-1].b
                          then write('true')
                          else write('false');
                    end;
               t := t-2
             end;
        31 : ps := fin;
        32 : begin  { exit procedure }
               t := b-1;
               pc := s[b+1].i;
               b := s[b+3].i
             end;
        33 : begin  { exit function }
               t := b;
               pc := s[b+1].i;
               b := s[b+3].i
             end;
        34 : s[t] := s[s[t].i];
        35 : s[t].b := not s[t].b;
        36 : s[t].i := -s[t].i;
        37 : begin
               chrcnt := chrcnt + s[t-1].i;
               if chrcnt > lineleng
               then ps := lngchk
               else write(prr,s[t-2].r:s[t-1].i:s[t].i);
               t := t-3
             end;
        38 : begin  { store }
               s[s[t-1].i] := s[t];
               t := t-2
             end;
        39 : begin
               t := t-1;
               s[t].b := s[t].r=s[t+1].r
             end;
      end { case }
    end; { inter3 }

  procedure inter4;
    begin
      case ir.f of
        40 : begin
               t := t-1;
               s[t].b := s[t].r <> s[t+1].r
             end;
        41 : begin
               t := t-1;
               s[t].b := s[t].r < s[t+1].r
             end;
        42 : begin
               t := t-1;
               s[t].b := s[t].r <= s[t+1].r
             end;
        43 : begin
               t := t-1;
               s[t].b := s[t].r > s[t+1].r
             end;
        44 : begin
               t := t-1;
               s[t].b := s[t].r >= s[t+1].r
             end;
        45 : begin
               t := t-1;
               s[t].b := s[t].i = s[t+1].i
             end;
        46 : begin
               t := t-1;
               s[t].b := s[t].i <> s[t+1].i
             end;
        47 : begin
               t := t-1;
               s[t].b := s[t].i < s[t+1].i
             end;
        48 : begin
               t := t-1;
               s[t].b := s[t].i <= s[t+1].i
             end;
        49 : begin
               t := t-1;
               s[t].b := s[t].i > s[t+1].i
             end;
      end { case }
    end; { inter4 }

  procedure inter5;
    begin
      case ir.f of
        50 : begin
               t := t-1;
               s[t].b := s[t].i >= s[t+1].i
             end;
        51 : begin
               t := t-1;
               s[t].b := s[t].b or s[t+1].b
             end;
        52 : begin
               t := t-1;
               s[t].i := s[t].i+s[t+1].i
             end;
        53 : begin
               t := t-1;
               s[t].i := s[t].i-s[t+1].i
             end;
        54 : begin
               t := t-1;
               s[t].r := s[t].r+s[t+1].r;
             end;
        55 : begin
               t := t-1;
               s[t].r := s[t].r-s[t+1].r;
             end;
        56 : begin
               t := t-1;
               s[t].b := s[t].b and s[t+1].b
             end;
        57 : begin
               t := t-1;
               s[t].i := s[t].i*s[t+1].i
             end;
        58 : begin
               t := t-1;
               if s[t+1].i = 0
               then ps := divchk
               else s[t].i := s[t].i div s[t+1].i
             end;
        59 : begin
               t := t-1;
               if s[t+1].i = 0
               then ps := divchk
               else s[t].i := s[t].i mod s[t+1].i
             end;
      end { case }
    end; { inter5 }

  procedure inter6;
    begin
      case ir.f of
        60 : begin
               t := t-1;
               s[t].r := s[t].r*s[t+1].r;
             end;
        61 : begin
               t := t-1;
               s[t].r := s[t].r/s[t+1].r;
             end;
        62 : if eof(prd)
             then ps := redchk
             else readln;
        63 : begin
               writeln(prr);
               lncnt := lncnt+1;
               chrcnt := 0;
               if lncnt > linelimit
               then ps := linchk
             end
      end { case };
    end; { inter6 }
  begin { interpret }
    s[1].i := 0;
    s[2].i := 0;
    s[3].i := -1;
    s[4].i := btab[1].last;
    display[0] := 0;
    display[1] := 0;
    t := btab[2].vsize-1;
    b := 0;
    pc := tab[s[4].i].adr;
    lncnt := 0;
    ocnt := 0;
    chrcnt := 0;
    ps := run;
    fld[1] := 10;
    fld[2] := 22;
    fld[3] := 10;
    fld[4] := 1;
    repeat
      ir := code[pc];
      pc := pc+1;
      ocnt := ocnt+1;
      case ir.f div 10 of
0 : inter0;
        1 : inter1;
        2 : inter2;
        3 : inter3;
        4 : inter4;
5 : inter5;
        6 : inter6;
      end; { case }
    until ps <> run;

    if ps <> fin
    then begin
           writeln(prr);
           write(prr, ' halt at', pc :5, ' because of ');
           case ps of
             caschk  : writeln(prr,'undefined case');
             divchk  : writeln(prr,'division by 0');
             inxchk  : writeln(prr,'invalid index');
             stkchk  : writeln(prr,'storage overflow');
             linchk  : writeln(prr,'too much output');
             lngchk  : writeln(prr,'line too long');
             redchk  : writeln(prr,'reading past end or file');
           end;
           h1 := b;
           blkcnt := 10;    { post mortem dump }
           repeat
             writeln( prr );
             blkcnt := blkcnt-1;
             if blkcnt = 0
             then h1 := 0;
             h2 := s[h1+4].i;
             if h1 <> 0
             then writeln( prr, '',tab[h2].name, 'called at', s[h1+1].i:5);
             h2 := btab[tab[h2].ref].last;
             while h2 <> 0 do
               with tab[h2] do
                 begin
                   if obj = vvariable
                   then if typ in stantyps
                        then begin
                               write(prr,'',name,'=');
                               if normal
                               then h3 := h1+adr
                               else h3 := s[h1+adr].i;
                               case typ of
                                 ints : writeln(prr,s[h3].i);
                                 reals: writeln(prr,s[h3].r);
                                 bools: if s[h3].b
                                        then writeln(prr,'true')
                                        else writeln(prr,'false');
                                 chars: writeln(prr,chr(s[h3].i mod 64 ))
                               end
                             end;
                   h2 := link
                 end;
             h1 := s[h1+3].i
           until h1 < 0
         end;
    writeln(prr);
    writeln(prr,ocnt,' steps');
  end; { interpret }



procedure setup;{*程序运行之前的准备过程,赋初值*}
  begin
    key[1] := 'and       ';
    key[2] := 'array     ';
    key[3] := 'begin     ';
    key[4] := 'case      ';
    key[5] := 'const     ';
    key[6] := 'div       ';
    key[7] := 'do        ';
    key[8] := 'downto    ';
    key[9] := 'else      ';
    key[10] := 'end       ';
    key[11] := 'for       ';
    key[12] := 'function  ';
    key[13] := 'if        ';
    key[14] := 'mod       ';
    key[15] := 'not       ';
    key[16] := 'of        ';
    key[17] := 'or        ';
    key[18] := 'procedure ';
    key[19] := 'program   ';
    key[20] := 'record    ';
    key[21] := 'repeat    ';
    key[22] := 'then      ';
    key[23] := 'to        ';
    key[24] := 'type      ';
    key[25] := 'until     ';
    key[26] := 'var       ';
    key[27] := 'while     ';

    ksy[1] := andsy;
    ksy[2] := arraysy;
    ksy[3] := beginsy;
    ksy[4] := casesy;
    ksy[5] := constsy;
    ksy[6] := idiv;
    ksy[7] := dosy;
    ksy[8] := downtosy;
    ksy[9] := elsesy;
    ksy[10] := endsy;
    ksy[11] := forsy;
    ksy[12] := funcsy;
    ksy[13] := ifsy;
    ksy[14] := imod;
    ksy[15] := notsy;
    ksy[16] := ofsy;
    ksy[17] := orsy;
    ksy[18] := procsy;
    ksy[19] := programsy;
    ksy[20] := recordsy;
    ksy[21] := repeatsy;
    ksy[22] := thensy;
    ksy[23] := tosy;
    ksy[24] := typesy;
    ksy[25] := untilsy;
    ksy[26] := varsy;
    ksy[27] := whilesy;


    sps['+'] := plus;
    sps['-'] := minus;
    sps['*'] := times;
    sps['/'] := rdiv;
    sps['('] := lparent;
    sps[')'] := rparent;
    sps['='] := eql;
    sps[','] := comma;
    sps['['] := lbrack;
    sps[']'] := rbrack;
    sps[''''] := neq;
    sps['!'] := andsy;
    sps[';'] := semicolon;
  end { setup };

procedure enterids;{*登记标准类型的信息*}
  begin
    enter('          ',vvariable,notyp,0); { sentinel }
    enter('false     ',konstant,bools,0);
    enter('true      ',konstant,bools,1);
    enter('real      ',typel,reals,1);
    enter('char      ',typel,chars,1);
    enter('boolean   ',typel,bools,1);
    enter('integer   ',typel,ints,1);
    enter('abs       ',funktion,reals,0);
    enter('sqr       ',funktion,reals,2);
    enter('odd       ',funktion,bools,4);
    enter('chr       ',funktion,chars,5);
    enter('ord       ',funktion,ints,6);
    enter('succ      ',funktion,chars,7);
    enter('pred      ',funktion,chars,8);
    enter('round     ',funktion,ints,9);
    enter('trunc     ',funktion,ints,10);
    enter('sin       ',funktion,reals,11);
    enter('cos       ',funktion,reals,12);
    enter('exp       ',funktion,reals,13);
    enter('ln        ',funktion,reals,14);
    enter('sqrt      ',funktion,reals,15);
    enter('arctan    ',funktion,reals,16);
    enter('eof       ',funktion,bools,17);
    enter('eoln      ',funktion,bools,18);
    enter('read      ',prozedure,notyp,1);
    enter('readln    ',prozedure,notyp,2);
    enter('write     ',prozedure,notyp,3);
    enter('writeln   ',prozedure,notyp,4);
    enter('          ',prozedure,notyp,0);
  end;


begin  { main }      
setup;{*初始化*}
  constbegsys := [ plus, minus, intcon, realcon, charcon, ident ];
  typebegsys := [ ident, arraysy, recordsy ];
  blockbegsys := [ constsy, typesy, varsy, procsy, funcsy, beginsy ];
  facbegsys := [ intcon, realcon, charcon, ident, lparent, notsy ];
  statbegsys := [ beginsy, ifsy, whilesy, repeatsy, forsy, casesy ];
  stantyps := [ notyp, ints, reals, bools, chars ];
  lc := 0;
  ll := 0;
  cc := 0;
  ch := ' ';
  errpos := 0;
  errs := [];
  writeln( 'NOTE input/output for users program is console : ' );
  writeln;
  write( 'Source input file ?');
  readln( inf );
  assign( psin, inf );
  reset( psin );
  write( 'Source listing file ?');
  readln( outf );
  assign( psout, outf );
  rewrite( psout );
  assign ( prd, 'con' );
  write( 'result file : ' );
  readln( fprr );
  assign( prr, fprr );
  reset ( prd );
  rewrite( prr );

  t := -1;
  a := 0;
  b := 1;
  sx := 0;
  c2 := 0;
  display[0] := 1;
  iflag := false;
  oflag := false;
  skipflag := false;
  prtables := false;
  stackdump := false;

  insymbol;

  if sy <> programsy
  then error(3)
  else begin
         insymbol;
         if sy <> ident
         then error(2)
         else begin
                progname := id;
                insymbol;
                if sy <> lparent
                then error(9)
                else repeat
                       insymbol;
                       if sy <> ident
                       then error(2)
                       else begin
                              if id = 'input     '
                              then iflag := true
                              else if id = 'output    '
                                   then oflag := true
                                   else error(0);
                              insymbol
                            end
                     until sy <> comma;
                if sy = rparent
                then insymbol
                else error(4);
                if not oflag then error(20)
              end
       end;
  enterids;
  with btab[1] do
    begin
      last := t;
      lastpar := 1;
      psize := 0;
      vsize := 0;
    end;
  block( blockbegsys + statbegsys, false, 1 );
  if sy <> period
  then error(2);
  emit(31);  { halt }
  if prtables
  then printtables;
  if errs = []
  then interpret
  else begin
         writeln( psout );
         writeln( psout, 'compiled with errors' );
         writeln( psout );
         errormsg;
       end;
  writeln( psout );
  close( psout );
  close( prr )
end.