1BSD/pcs/block.i

procedure block(fsys: symset; isfun: boolean; level: integer);
  
   type conrec = 
      record 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); 
      while not (sy in fsys) do insymbol 
   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: object); 
      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;
            if j <> 0 then error(1) else 
            begin t := t+1;
              with tab[t] do 
              begin name := id; link := l;
               obj := k; typ := notyp; ref := 0; lev := level; adr := 0 
              end ; 
              btab[display[level]].last := t
            end
         end 
   end (*enter*) ;  
     
   function loc(id: alfa): integer;
      var i,j: integer;     (*locate id 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,variable); insymbol
          end 
        else error(2) 
  end (*entervariable*) ; 
     
   procedure constant(fsys: symset; var c: conrec); 
     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 
         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 x: integer;
         eltp: types; elrf: 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 then insymbol else error(8); 
           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); 
     if sy in typebegsys then 
       begin 
         if sy = ident then
         begin x := loc(id);  
           if x <> 0 then 
           with tab[x] do 
             if obj <> type1 then error(29) else  
             begin tp := typ; rf := ref; sz := adr; 
               if tp = notyp then error(30) 
             end ;  
           insymbol 
         end else
         if sy = arraysy 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*) insymbol;
           enterblock; tp := records; rf := b;
           if level = lmax then fatal(5); 
           level := level+1; display[level] := b; offset := 0;
           while sy <> endsy do
           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 
               begin t0 := t0+1;
                 with tab[t0] do
                 begin typ := eltp; ref := elrf; normal := true;
                   adr := offset; offset := offset + elsz
                 end
               end 
             end ; 
             if sy <> endsy 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 ;
           btab[rf].vsize := offset; sz := offset; btab[rf].psize := 0; 
           insymbol; level := level-1
         end ;
         test(fsys, [], 6) 
       end 
   end (*typ*) ; 
 
   procedure parameterlist;     (*formal parameter list*)
      var tp: types; 
          rf, sz, x, t0: integer; 
          valpar: boolean; 
   begin insymbol; tp := notyp; rf := 0; sz := 0; 
     test([ident, varsy], fsys+[rparent], 7); 
     while sy in [ident,varsy] do 
       begin if sy <> varsy then valpar := true 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 <> type1 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; 
               normal := valpar; adr := dx; lev := level;
               dx := dx + sz 
           end
         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 constantdeclaration;
     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);
         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 (*constantdeclaration*) ; 
 
   procedure typedeclaration; 
     var tp: types; rf, sz, t1: integer;
   begin insymbol; 
     test([ident], blockbegsys, 2); 
     while sy = ident do 
       begin enter(id,type1); 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 t0, t1, rf, sz: integer; 
         tp: types; 
   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 = functionsy; 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*) ;
  
(*---------------------------------------------------------statement--*)
  
   procedure statement(fsys: symset);
      var i: integer;
      procedure expression(fsys: symset; var x: item); forward; 
  
      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); 
              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 then
              begin (*value parameter*) 
                expression(fsys+[comma,colon,rparent], 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 then 
                  begin if tab[k].obj <> variable then error(37);
                    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
            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);
        if tab[i].lev < level then emit2(3, tab[i].lev, level)
      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;
        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 then
                  begin expression(fsys+[rparent],x); 
                    case n of 
(*abs,sqr*)      0,2:  begin ts := [ints,reals]; tab[i].typ := x.typ; 
                         if x.typ = reals then n := n+1 
                       end ; 
(*odd,chr*)      4,5:  ts := [ints];
(*ord*)          6: begin
				if x.typ = ints then n := 19;
				ts := [ints,bools,chars];
			end;
(*succ,pred*)    7,8:  ts := [chars];
(*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 ; 
                    if x.typ in ts then emit1(8,n) else 
                    if x.typ <> notyp then error(48); 
                  end else
(*eof,eoln*)      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; 
			case x.typ of
				ints: emit1(24,adr);
				reals: emit1(25,adr);
				bools: emit1(64,adr);
				chars: emit1(65,adr);
			end;
                        end ; 
              variable: 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 ; 
              type1, 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 begin
				x.typ := chars;
				emit1(65, inum);
			end else begin
				x.typ := ints;
				emit1(24, inum);
			end;
                     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 
              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
          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
			if x.typ = reals then
				emit(66)
			else
				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
               end 
            end 
        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; 
         (*tab[i].obj in [variable,prozedure]*)
      begin 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 (*compoundstatemenet*) ;

      procedure ifstatement; 
         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;
        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; 
          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) 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;
        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; emit(10) 
          end 
        end (*onecase*) ; 
  
      begin 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; emit(12);  (*jmpx*) 
        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 code[exittab[k]].y := lc;
        if sy = endsy then insymbol else error(57)
      end (*casestatement*) ; 

      procedure repeatstatement;
         var x: item; lc1: integer; 
      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; 
         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; 
         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 = variable 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); 
        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); 
        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 <> variable 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(40)
                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 = string 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 ; 
        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, type1: error(45); 
                          variable: 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
                      end ;
            beginsy:  compoundstatement;
            ifsy:     ifstatement;
            casesy:   casestatement;
            whilesy:  whilestatement;
            repeatsy: repeatstatement; 
            forsy:    forstatement; 
          end;
        test(fsys, [], 14)
    end (*statement*) ; 

begin (*block*) dx := 5; prt := t;
  if level > lmax then fatal(5);
  test([lparent,colon,semicolon], fsys, 7); 
  enterblock; display[level] := b; prb := b;
  tab[prt].typ := notyp; tab[prt].ref := prb; 
  if sy = lparent 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].obj <> type1 then error(29) else 
            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 constantdeclaration; 
    if sy = typesy then typedeclaration;
    if sy = varsy then variabledeclaration; 
    btab[prb].vsize := dx;
    while sy in [proceduresy,functionsy] 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*) ;