home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / sigm / vol162 / pl0.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1984-04-29  |  14.0 KB  |  491 lines

  1. {$S+}     { recursion on }
  2.  
  3. program pl0(input,output,h,o);
  4.  
  5. label 99;
  6.  
  7. const norw = 13;
  8.       txmax=100;
  9.       nmax=14;
  10.       al=10;
  11.       chsetsize=128;
  12.      maxerr=30;
  13.      amax=2048;
  14.      levmax=3;
  15.      cxmax=200;
  16.      version='PL/0-Compiler';
  17.  
  18. type symbol=(nul,ident,number,plus,minus,times,slash,oddsym,eql,
  19.             neq,lss,leq,gtr,geq,lparen,rparen,comma,semicolon,period,
  20.             becomes,beginsym,endsym,ifsym,thensym,whilesym,dosym,
  21.             readsym,writesym,callsym,constsym,varsym,procsym);
  22.      alfa=packed array[1..al]of char;
  23.      object=(constant,variable,prozedure);
  24.      symset=set of symbol;
  25.      fct = (nix,lit,opr,lod,sto,cal,int,jmp,jpc,inp,out);
  26.      instruction=packed record f:fct;
  27.                                l: 0..levmax;
  28.                                a: 0..amax;
  29.                          end;
  30.  
  31. var h,o:text;ch:char;
  32.     sym:symbol; id:alfa;
  33.     num,cc,ll,kk,err,cx,rc:integer;
  34.     line: array[1..81] of char; a: alfa;
  35.     code :array[0..cxmax] of instruction;
  36.     word :array[1..norw] of alfa;
  37.     wsym :array[1..norw] of symbol;
  38.     ssym :array[char] of symbol;
  39.     fname,txtname,lstname : string[16];
  40.     mnemonic:array[fct]of packed array[1..5] of char;                       
  41.     declbegsys,statbegsys,facbegsys:symset;
  42.     table:array[0..txmax] of record name: alfa;
  43.                case kind: object of
  44.                constant: (val:integer);
  45.                variable,prozedure:(level,adr,size:integer) end;
  46.  
  47. procedure error(n:integer);
  48.  begin writeln('**',' ':cc-2,'^ ',n:2);                     
  49.        err:=err +1; {if err>maxerr then goto 99}
  50.  end;
  51.  
  52. procedure getsym;
  53.   var i,j,k :integer;
  54.  
  55.  procedure getch;
  56.    begin if cc =ll then
  57.       begin if eof(h) then
  58.           begin  write(' program incomplete '); goto 99  end;
  59.         ll:=0;cc:= 0;write(' ');
  60.         while not eoln(h) do
  61.           begin ll:=ll+1; read(h,ch); write(ch);line[ll]:=ch
  62.           end;
  63.         writeln; ll:=ll+1;read(h,line[ll])
  64.       end;
  65.       cc:=cc+1;ch:=line[cc]
  66.  end{ getch };
  67.  
  68. begin { getsym }
  69.    while ch= ' ' do getch;
  70.    if ch in ['a'..'z'] then
  71.      begin { id oder res. wort } k:=0;
  72.        repeat if k <al then
  73.          begin k:=k+1;a[k]:= ch
  74.          end;
  75.          getch;
  76.        until not (ch in ['a'..'z','0'..'9']);
  77.        if k >= kk then kk:=k else
  78.          repeat a[kk]:=' ';kk:=kk-1
  79.          until kk=k;
  80.        id:=a;i:=1;j:=norw;
  81.        repeat k:=(i+j)div 2;
  82.         if id <= word[k] then j:=k-1;
  83.         if id >= word[k] then i:=k+1;
  84.        until i>j;
  85.        if i-1 >j then sym :=wsym[k] else sym:=ident
  86.      end else
  87.      if ch in ['0'..'9'] then
  88.      begin { number } k:=0;num:=0;sym:=number;
  89.        repeat num := 10* num + (ord(ch)-ord('0'));
  90.          k:=k+1;getch
  91.        until not (ch in ['0'..'9']);
  92.        if k> nmax then error(30)
  93.      end else
  94.      if ch =':' then
  95.        begin getch;if ch='=' then
  96.          begin sym:=becomes; getch
  97.          end else sym:= nul;
  98.        end else
  99.      if ch = '<' then
  100.        begin getch; if ch='='then
  101.          begin sym :=leq; getch
  102.          end else sym:=lss;
  103.        end else
  104.      if ch = '>' then
  105.        begin getch; if ch='='then
  106.          begin sym :=geq; getch
  107.          end else sym:=gtr;
  108.        end else
  109.      begin sym:=ssym[ch]; getch
  110.      end
  111. end{ getsym };
  112.  
  113. procedure gen(x:fct;y,z:integer);
  114. begin if cx > cxmax then
  115.          begin write(' program too long'); goto 99
  116.          end;
  117.    with code[cx] do
  118.      begin f:=x; l:=y; a:=z
  119.      end;
  120.    cx:=cx+1;
  121. end { gen };
  122.  
  123. procedure test(s1,s2:symset; n:integer);
  124. begin if not(sym in s1) then
  125.       begin error(n); s1:=s1+s2;
  126.          while not (sym in s1) do getsym;
  127.       end
  128. end { test };
  129.  
  130. procedure block(lev,tx: integer; fsys: symset);
  131. var dx, tx0, cx0: integer;
  132.   procedure enter(k:object);
  133.   begin tx:=tx+1;
  134.      with table[tx] do
  135.      begin name:=id; kind:=k;
  136.         case k of
  137.         constant: begin if num > amax then
  138.                         begin error(31); num:=0 end;
  139.                      val:=num
  140.                   end;
  141.         variable: begin level:=lev; adr:=dx; dx:=dx+1
  142.                   end;
  143.         prozedure: level:=lev;
  144.         end
  145.      end
  146.   end { enter };
  147.  
  148.   function position(id: alfa): integer;
  149.   var i: integer;
  150.   begin table[0].name:=id; i:=tx;
  151.      while table[i].name <> id do i:=i-1;
  152.      position:=i
  153.   end { position };
  154.  
  155.   procedure constdeclaration;
  156.   begin if sym = ident then
  157.         begin getsym;
  158.            if sym in [eql,becomes] then
  159.            begin if sym = becomes then error(1);
  160.               getsym;
  161.               if sym = number then
  162.                 begin enter(constant); getsym
  163.                 end else error(2)
  164.            end else error(3)
  165.         end else error(4);
  166.   end { constantdeclaration };
  167.  
  168.   procedure vardeclaration;
  169.   begin if sym = ident then
  170.         begin enter(variable); getsym;
  171.         end else error(4);
  172.   end { vardeclaration };
  173.  
  174.   procedure listcode;
  175.   var i: integer;
  176.   begin for i:= cx0 to cx-1 do
  177.         with code[i] do
  178.         begin
  179.           writeln(mnemonic[f],l:3,a:6);
  180.           writeln(o, mnemonic[f],l:3,',',a:6)
  181.         end
  182.   end { listcode };
  183.  
  184.   procedure statement(fsys: symset);
  185.   var i,cx1,cx2: integer;
  186.  
  187.     procedure expression(fsys: symset);
  188.     var addop: symbol;
  189.  
  190.       procedure term(fsys: symset);
  191.       var mulop: symbol;
  192.  
  193.         procedure factor(fsys: symset);
  194.         var i: integer;
  195.  
  196.         begin test(facbegsys,fsys,24);
  197.            while sym in facbegsys do
  198.            begin
  199.               if sym = ident then
  200.               begin i:=position(id);
  201.                  if i=0 then error(11) else
  202.                  with table[i] do
  203.                  case kind of
  204.                    constant: gen(lit,0,val);
  205.                    variable: gen(lod,lev-level,adr);
  206.                    prozedure: error(21)
  207.                  end;
  208.                  getsym
  209.               end else
  210.               if sym = number then
  211.               begin if num > amax then
  212.                     begin error(31); num:=0
  213.                     end;
  214.                  gen(lit,0,num); getsym
  215.               end else
  216.               if sym = lparen then
  217.               begin getsym; expression([rparen]+fsys);
  218.                  if sym = rparen then getsym else error(22)
  219.               end;
  220.               test(fsys,[lparen],23)
  221.            end
  222.         end { factor };
  223.  
  224.       begin { term }
  225.          factor(fsys+[times,slash]);
  226.          while sym in [times,slash] do
  227.          begin mulop:=sym; getsym; factor(fsys+[times,slash]);
  228.             if mulop = times then gen(opr,0,4) else gen(opr,0,5)
  229.          end
  230.       end { term };
  231.  
  232.     begin { expression }
  233.        if sym in [plus,minus] then
  234.        begin addop:=sym; getsym; term(fsys+[plus,minus]);
  235.           if addop = minus then gen(opr,0,1)
  236.        end else term(fsys+[plus,minus]);
  237.        while sym in [plus,minus] do
  238.        begin addop:=sym; getsym; term(fsys+[plus,minus]);
  239.           if addop = plus then gen(opr,0,2) else gen(opr,0,3)
  240.        end
  241.     end { expression };
  242.  
  243.   procedure condition(fsys:symset);
  244.   var relop: symbol;
  245.   begin
  246.      if sym = oddsym then
  247.      begin getsym; expression(fsys); gen(opr,0,6)
  248.      end else
  249.      begin expression([eql,neq,lss,gtr,leq,geq]+fsys);
  250.         if not (sym in [eql,neq,lss,gtr,leq,geq]) then error(20) else
  251.         begin relop:=sym; getsym; expression(fsys);
  252.            case relop of
  253.              eql: gen(opr,0,8);
  254.              neq: gen(opr,0,9);
  255.              lss: gen(opr,0,10);
  256.              geq: gen(opr,0,11);
  257.              gtr: gen(opr,0,12);
  258.              leq: gen(opr,0,13);
  259.            end
  260.         end
  261.      end
  262.   end { condition };
  263.  
  264.   begin{ statement }
  265.    if not( sym in fsys+[ident]) then
  266.    begin error (10);
  267.      repeat getsym until sym in fsys
  268.    end;
  269.    if sym=ident then
  270.    begin i:=position(id);
  271.      if i=0 then error(11) else
  272.      if table[i].kind <> variable then
  273.      begin error (12);i:=0
  274.      end;
  275.      getsym;if sym= becomes then getsym else error(13);
  276.      expression(fsys);
  277.      if i<> 0 then
  278.        with table[i] do gen(sto,lev-level,adr)
  279.    end else
  280.    if sym = callsym then
  281.    begin getsym;
  282.      if sym<> ident then error(14) else
  283.      begin i:= position(id);
  284.        if i=0 then error(11) else
  285.        with table[i] do
  286.        if kind = prozedure then gen(cal,lev-level,adr)
  287.        else error(15);
  288.        getsym
  289.      end
  290.    end else
  291.    if sym = ifsym then
  292.    begin getsym; condition([thensym,dosym]+fsys);
  293.      if sym= thensym then getsym else error(16);
  294.      cx1:=cx; gen(jpc,0,0);
  295.      statement(fsys);code[cx1].a:=cx
  296.    end else
  297.    if sym = beginsym then
  298.    begin getsym; statement([semicolon,endsym]+fsys);
  299.      while sym in [semicolon] + statbegsys do
  300.      begin if sym= semicolon then getsym else error(10);
  301.        statement([semicolon,endsym]+fsys)
  302.      end;
  303.      if sym= endsym then getsym else error(17)
  304.    end else
  305.    if sym= whilesym then
  306.    begin cx1:= cx; getsym; condition([dosym]+fsys);
  307.      cx2:=cx;gen(jpc,0,0);
  308.      if sym= dosym then getsym else error(18);
  309.      statement(fsys);gen(jmp,0,cx1);
  310.      code[cx2].a:=cx
  311.    end else
  312.    if sym = writesym then
  313.    begin getsym;
  314.      if sym =lparen then getsym else error(33);
  315.      while sym <> rparen do
  316.        begin
  317.          expression(fsys+[comma,rparen]);gen(out,0,0);
  318.          if sym = comma then getsym
  319.        end;
  320.      getsym;
  321.    end else
  322.    if sym = readsym then
  323.    begin getsym;
  324.      if sym = lparen then
  325.      begin getsym;
  326.        if sym = ident then
  327.        begin i:=position(id);
  328.          if i=0 then error(11) else
  329.          if table[i].kind <> variable then
  330.          begin error(12); i:=0
  331.          end else
  332.          begin gen(inp,0,0);
  333.            with table[i] do gen(sto,lev-level,adr)
  334.          end
  335.        end;
  336.        getsym; if sym=rparen then getsym else error(22);
  337.      end else error(33)
  338.    end;
  339.    test(fsys,[],19)
  340.  end{ statement };
  341.  
  342.  
  343. begin { block }
  344.   dx:=3;tx0:=tx;table[tx].adr:=cx;gen(jmp,0,0);
  345.   if lev > levmax then error(32);
  346.   repeat
  347.     if sym = constsym then
  348.     begin getsym;
  349.       repeat constdeclaration;
  350.         while sym=comma do
  351.           begin getsym;constdeclaration
  352.           end;
  353.         if sym =semicolon then getsym else error(5)
  354.       until sym<> ident
  355.     end;
  356.     if sym= varsym then
  357.     begin getsym;
  358.       repeat vardeclaration;
  359.         while sym = comma do
  360.           begin getsym; vardeclaration;
  361.           end;
  362.         if sym = semicolon then getsym else error(5)
  363.       until sym <> ident
  364.     end;
  365.     while sym= procsym do
  366.     begin getsym;
  367.       if sym =ident then
  368.       begin enter(prozedure);getsym
  369.       end else error(4);
  370.       if sym = semicolon then getsym else error(5);
  371.       block(lev+1,tx,[semicolon]+fsys);
  372.       if sym = semicolon then
  373.       begin getsym; test(statbegsys+[ident,procsym],fsys,6)
  374.       end else error(5)
  375.     end;
  376.     test(fsys-declbegsys+[ident],declbegsys,7)
  377.   until not(sym in declbegsys);
  378.   code[table[tx0].adr].a:=cx;
  379.   with table[tx0] do
  380.     begin adr:=cx;{ start of code }
  381.           size:=dx;{ size of data segm. }
  382.     end;
  383.   cx0:=cx;gen(int,0,dx);
  384.   statement([semicolon,endsym]+fsys);
  385.   gen(opr,0,0);{ return }
  386.   test(fsys,[],8);
  387.   listcode;
  388. end { block };
  389.  
  390. procedure interpret;
  391. const stacksize =500;
  392.   var p,b,t:integer;
  393.       i:instruction;
  394.       s:array[1..stacksize] of integer;
  395.   function base(l: integer):integer;
  396.     var b1: integer;
  397.   begin b1:=b; { find base l levels down }
  398.     while l > 0 do
  399.       begin b1:=s[b1];l:=l-1
  400.       end;
  401.     base:=b1
  402.   end { base };
  403.  
  404. begin writeln('start pl/0');
  405.   t:=0;b:=1;p:=0;
  406.   s[1]:=0;s[2]:=0;s[3]:=0;
  407.   repeat i:=code[p];p:=p+1;
  408.     with i do
  409.     case f of
  410.   lit: begin t:=t+1;s[t]:=a end;
  411.   opr: case a of
  412.        0:begin { return } t:=b-1;p:=s[t+3];b:=s[t+2] end;
  413.        1:s[t]:=-s[t];
  414.        2:begin t:=t-1;s[t]:=s[t]+s[t+1] end;
  415.        3:begin t:=t-1;s[t]:=s[t]-s[t+1] end;
  416.        4:begin t:=t-1;s[t]:=s[t]*s[t+1] end;
  417.        5:begin t:=t-1;s[t]:=s[t] div s[t+1] end;
  418.        6:s[t]:= ord(odd(s[t]));
  419.        8:begin t:=t-1;s[t]:=ord(s[t] = s[t+1]) end;
  420.        9:begin t:=t-1;s[t]:=ord(s[t] <>s[t+1]) end;
  421.       10:begin t:=t-1;s[t]:=ord(s[t] < s[t+1]) end;
  422.       11:begin t:=t-1;s[t]:=ord(s[t] >=s[t+1]) end;
  423.       12:begin t:=t-1;s[t]:=ord(s[t] > s[t+1]) end;
  424.       13:begin t:=t-1;s[t]:=ord(s[t] <=s[t+1]) end;
  425.       end;
  426.   lod: begin t:=t+1; s[t]:=s[base(l)+a] end;
  427.   sto: begin s[base(l)+a]:= s[t];t:=t-1 end;
  428.   cal: begin s[t+1]:=base(l);s[t+2]:=b;s[t+3]:=p;b:=t+1;p:=a end;
  429.   int: t:=t+a;
  430.   jmp: p:= a;
  431.   jpc: begin if s[t]=0 then p:=a; t:=t-1 end;
  432.   inp: begin t:=t+1;read(s[t]);writeln end;
  433.   out: begin writeln(s[t]);t:=t-1 end;
  434.     end { with,case }
  435.   until p=0;
  436.  writeln(' end pl/0 ');
  437. end { interpret };
  438.  
  439. procedure init_tables;
  440. var ch : char;
  441. begin
  442.   for ch:= chr(0) to chr(chsetsize-1) do ssym[ch]:=nul;
  443.   word[ 1]:='begin     '; word[ 2]:='call      ';
  444.   word[ 3]:='const     '; word[ 4]:='do        ';
  445.   word[ 5]:='end       '; word[ 6]:='if        ';
  446.   word[ 7]:='odd       '; word[ 8]:='procedure ';
  447.   word[10]:='then      '; word[11]:='var       ';
  448.   word[12]:='while     '; word[ 9]:='read      ';
  449.   word[13]:='write     ';
  450.   wsym[ 1]:=beginsym; wsym[ 2]:=callsym;
  451.   wsym[ 3]:=constsym; wsym[ 4]:=dosym;
  452.   wsym[ 5]:=endsym; wsym[ 6]:=ifsym;
  453.   wsym[ 7]:=oddsym; wsym[ 8]:=procsym;
  454.   wsym[10]:=thensym; wsym[11]:=varsym;
  455.   wsym[12]:=whilesym;
  456.   wsym[ 9]:=readsym; wsym[13]:=writesym;
  457.   ssym['+']:=plus     ;ssym['-']:=minus;
  458.   ssym['*']:=times    ;ssym['/']:=slash;
  459.   ssym['(']:=lparen   ;ssym[')']:=rparen;
  460.   ssym['=']:=eql      ;ssym[',']:=comma ;
  461.   ssym['.']:=period   ;ssym['#']:=neq   ;
  462.   ssym['<']:=lss      ;ssym['>']:=gtr   ;
  463.   ssym[';']:=semicolon;
  464.   mnemonic[lit]:=' lit ';mnemonic[opr]:=' opr ';
  465.   mnemonic[lod]:=' lod ';mnemonic[sto]:=' sto ';
  466.   mnemonic[cal]:=' cal ';mnemonic[int]:=' int ';
  467.   mnemonic[jmp]:=' jmp ';mnemonic[jpc]:=' jpc ';
  468.   mnemonic[inp]:=' inp ';mnemonic[out]:=' out ';
  469. end;
  470.  
  471. begin { main program }
  472.   init_tables; 
  473.   declbegsys:=[constsym,varsym,procsym];
  474.   statbegsys:=[beginsym,callsym,ifsym,whilesym,writesym,readsym];
  475.   facbegsys:=[ident,number,lparen];
  476.  
  477.   writeln(version);
  478.   writeln;write('filename :');readln(fname);
  479.   assign(h,fname);
  480.   reset(h);err:=0;
  481.   txtname := concat(fname,'.mac');
  482.   assign(o,txtname);
  483.   rewrite(o);
  484.   cc:=0;cx:=0;ll:=0;ch:=' ';kk:=al;getsym;
  485.   block(0,0,[period]+declbegsys+statbegsys);
  486.   if sym<> period then error(9);
  487.   close(o,rc);
  488.   if err= 0 then interpret
  489.         else writeln(err:3,' errors in pl/0 program');
  490. 99: writeln
  491. end.