home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / turbopas / tptc17sc.arc / TPCSTMT.INC < prev    next >
Text File  |  1988-03-25  |  24KB  |  1,136 lines

  1.  
  2. (*
  3.  * TPTC - Turbo Pascal to C translator
  4.  *
  5.  * (C) 1988 Samuel H. Smith (rev. 13-Feb-88)
  6.  *
  7.  *)
  8.  
  9. (********************************************************************)
  10. (*
  11.  * control statement processors
  12.  *    for, while, repeat, with, idents
  13.  *
  14.  * all expect tok to be keyword
  15.  * all exit at end of statement with ltok as ; or end
  16.  *
  17.  *)
  18.  
  19. procedure pfor;
  20. var
  21.    up:       boolean;
  22.    id:       string80;
  23.    low,high: string80;
  24.  
  25. begin
  26.    if debug_parse then write(' <for>');
  27.  
  28.    nospace := true;
  29.    puts('for (');
  30.    gettok;   {consume the FOR}
  31.  
  32.    id := plvalue;
  33.    gettok;   {consume the :=}
  34.  
  35.    low := pexpr;
  36.  
  37.    if tok = 'TO' then
  38.       up := true
  39.    else
  40.  
  41.    if tok = 'DOWNTO' then
  42.       up := false;
  43.  
  44.    gettok;
  45.    high := pexpr;
  46.  
  47.    if up then
  48.       puts(id+' = '+low+'; '+id+' <= '+high+'; '+id+'++) ')
  49.    else
  50.       puts(id+' = '+low+'; '+id+' >= '+high+'; '+id+'--) ');
  51.  
  52.    nospace := false;
  53.    gettok;   {consume the DO}
  54.    pstatement;
  55. end;
  56.  
  57.  
  58. (********************************************************************)
  59. procedure pwhile;
  60. begin
  61.    if debug_parse then write(' <while>');
  62.    gettok;   {consume the WHILE}
  63.  
  64.    nospace := true;
  65.    puts('while ('+pexpr+') ');
  66.    nospace := false;
  67.  
  68.    gettok;   {consume the DO}
  69.    pstatement;
  70. end;
  71.  
  72.  
  73. (********************************************************************)
  74. procedure pwith;
  75. var
  76.    prefix: string;
  77.    levels: integer;
  78.    
  79. begin
  80.    if debug_parse then write(' <with>');
  81.    gettok;   {consume the WITH}
  82.  
  83.    {warning('WITH not translated');}
  84.    levels := 0;
  85.    puts('{ ');
  86.    nospace := true;
  87.       
  88.    repeat
  89.       if tok[1] = ',' then 
  90.       begin
  91.          gettok;
  92.          newline;
  93.          puts('  ');
  94.       end;
  95.          
  96.       prefix := plvalue;
  97.       make_pointer(prefix);
  98.       
  99.       inc(levels);
  100.       inc(withlevel);
  101.       puts('void *with'+itoa(withlevel)+' = '+prefix+'; ');
  102.       
  103.    until tok[1] <> ',';
  104.    
  105.    nospace := false;
  106.    gettok;   {consume the DO}
  107.    
  108.    if tok[1] <> '{' then
  109.       pstatement
  110.    else
  111.  
  112.    begin
  113.       gettok;                 {consume the open brace}
  114.    
  115.       while (tok[1] <> '}') and not recovery do
  116.       begin
  117.          pstatement;          {process the statement}
  118.    
  119.          if tok[1] = ';' then
  120.          begin
  121.             puttok;
  122.             gettok;           {get first token of next statement}
  123.          end;
  124.       end;
  125.       
  126.       gettok;                 {consume the close brace}
  127.    end;
  128.  
  129.    puts('   } ');
  130.    newline;
  131.  
  132.    if tok[1] = ';' then
  133.       gettok;
  134.  
  135.    dec(withlevel,levels);
  136. end;
  137.  
  138.  
  139. (********************************************************************)
  140. procedure prepeat;
  141. begin
  142.    if debug_parse then write(' <repeat>');
  143.    puts('do { ');
  144.    gettok;
  145.  
  146.    while (tok <> 'UNTIL') and not recovery do
  147.    begin
  148.       pstatement;
  149.  
  150.       if tok[1] = ';' then
  151.       begin
  152.          puttok;
  153.          gettok;
  154.       end;
  155.    end;
  156.  
  157.    gettok;
  158.    nospace := true;
  159.    puts('}  while (!('+ pexpr+ '))');
  160.    nospace := false;
  161. end;
  162.  
  163.  
  164. (********************************************************************)
  165. procedure pcase;
  166. var
  167.    ex:  string80;
  168.    ex2: string80;   
  169.    i:   integer;
  170.    c:   char;
  171.  
  172. begin
  173.    if debug_parse then write(' <case>');
  174.    gettok;
  175.    ex := pexpr;
  176.    puts('switch ('+ex+') {');
  177.  
  178.    gettok;   {consume the OF}
  179.  
  180.    while (tok[1] <> '}') and (tok <> 'ELSE') and not recovery do
  181.    begin
  182.  
  183.       repeat
  184.          if tok[1] = ',' then
  185.             gettok;
  186.  
  187.          if tok = '..' then
  188.          begin
  189.             gettok;
  190.             ex2 := pexpr;
  191.             
  192.             if (ex2[1] = '''') or (ex2[1] = '"') then
  193.                for c := succ(ex[2]) to ex2[2] do
  194.                begin
  195.                   newline;
  196.                   puts('case '''+c+''':   ');
  197.                end
  198.             else
  199.             
  200.             if atoi(ex2) - atoi(ex) > 128 then
  201.             begin
  202.                ltok := ex+'..'+ex2;
  203.                warning('Gigantic case range');
  204.             end 
  205.             else
  206.             
  207.             for i := succ(atoi(ex)) to atoi(ex2) do
  208.             begin
  209.                newline;
  210.                write(ofd[unitlevel],'case ',i,':   ');
  211.             end;
  212.          end
  213.          else
  214.          
  215.          begin
  216.             ex := pexpr;
  217.             newline;
  218.             puts('case '+ex+':   ');
  219.          end;
  220.  
  221.       until (tok[1] = ':') or recovery;
  222.       gettok;
  223.  
  224.       if (tok[1] <> '}') and (tok <> 'ELSE') then
  225.          pstatement;
  226.       puts('break; ');
  227.       newline;
  228.  
  229.       if tok[1] = ';' then
  230.          gettok;
  231.    end;
  232.  
  233.    if tok = 'ELSE' then
  234.    begin
  235.       newline;
  236.       puts('default: ');
  237.       gettok;   {consume the else}
  238.  
  239.       while (tok[1] <> '}') and not recovery do
  240.       begin
  241.          if (tok[1] <> '}') and (tok <> 'ELSE') then
  242.             pstatement;
  243.          if tok[1] = ';' then
  244.             gettok;
  245.       end;
  246.    end;
  247.  
  248.    puttok;
  249.    gettok;
  250.  
  251.    if tok[1] = ';' then
  252.       gettok;
  253. end;
  254.  
  255.  
  256. (********************************************************************)
  257. procedure pif;
  258. var
  259.    pspace: integer;
  260. begin
  261.    if debug_parse then write(' <if>');
  262.    gettok;   {consume the IF}
  263.  
  264.    pspace := length(spaces);
  265.    nospace := true;
  266.    puts('if ('+ pexpr+ ') ');
  267.    nospace := false;
  268.    
  269.    gettok;   {consume the THEN}
  270.  
  271.    if (tok[1] <> '}') and (tok <> 'ELSE') then
  272.       pstatement;
  273.  
  274.    if tok = 'ELSE' then
  275.    begin
  276.       spaces := copy(spaces,1,pspace);
  277.       if not linestart then
  278.          newline;
  279.       puts('else ');
  280.  
  281.       gettok;
  282.       if tok[1] <> '}' then
  283.          pstatement;
  284.    end;
  285.  
  286. end;
  287.  
  288.  
  289. (********************************************************************)
  290. procedure pexit;
  291. begin
  292.    if debug_parse then write(' <exit>');
  293.    puts('return;');
  294.  
  295.    gettok;
  296.    if tok[1] = ';' then
  297.       gettok;
  298. end;
  299.  
  300.  
  301. (********************************************************************)
  302. procedure pgoto;
  303. var
  304.    ex:  anystring;
  305.  
  306. begin
  307.    gettok;                      {consume the goto}
  308.  
  309.    if toktype = number then
  310.       ltok := 'label_' + ltok;  {modify numeric labels}
  311.  
  312.    puts('goto '+ltok+';');
  313.  
  314.    gettok;                      {consume the label}
  315.  
  316.    if tok[1] = ';' then
  317.       gettok;
  318. end;
  319.  
  320.  
  321. (********************************************************************)
  322. procedure phalt;
  323. var
  324.    ex: anystring;
  325.  
  326. begin
  327.    if debug_parse then write(' <halt>');
  328.    gettok;
  329.  
  330.    if tok[1] = '(' then
  331.    begin
  332.       gettok;
  333.       ex := pexpr;
  334.       gettok;
  335.    end
  336.    else
  337.       ex := '0';     {default exit expression}
  338.  
  339.    puts('exit('+ex+');');
  340.  
  341.    if tok[1] = ';' then
  342.       gettok;
  343. end;
  344.  
  345.  
  346. (********************************************************************)
  347. procedure pread;
  348. var
  349.    ctl:  string;
  350.    func: anystring;
  351.    ex:   paramlist;
  352.    p:    string;
  353.    ln:   boolean;
  354.    ty:   string[2];
  355.    i:    integer;
  356.  
  357. begin
  358.    if debug_parse then write(' <read>');
  359.    
  360.    nospace := true;   {don't copy source whitespace to output during
  361.                        this processing.  this prevents spaces from
  362.                        getting moved around}
  363.  
  364.    ln := tok = 'READLN';
  365.    nospace := true;
  366.    func := 'scanv(';
  367.  
  368.    gettok;   {consume the read}
  369.  
  370.    if tok[1] = '(' then
  371.    begin
  372.       gettok;
  373.  
  374.       if ltok[1] = '[' then   {check for MT+ [addr(name)], form}
  375.       begin
  376.          gettok;   {consume the '[' }
  377.  
  378.          if tok[1] = ']' then
  379.             func := 'scanf('
  380.          else
  381.  
  382.          begin
  383.             gettok;   {consume the ADDR}
  384.             gettok;   {consume the '(' }
  385.             func := 'fiscanf(' + usetok + ',';
  386.             gettok;   {consume the ')'}
  387.          end;
  388.  
  389.          gettok;   {consume the ']'}
  390.          if tok[1] = ',' then
  391.             gettok;
  392.       end;
  393.  
  394.       ctl := '';
  395.       ex.n := 0;
  396.  
  397.       while (tok[1] <> ')') and not recovery do
  398.       begin
  399.          p := pexpr;
  400.          ty := exprtype;
  401.  
  402.          {convert to fprintf if first param is a file variable}
  403.          if (ex.n = 0) and (ty = '@') then
  404.             func := 'fscanv(' + p + ','
  405.          else
  406.  
  407.          {process a new expression; add expressions to ex.id table
  408.           and append proper control codes to the control string}
  409.          begin
  410.             if ty <> 's' then
  411.                if p[1] = '*' then
  412.                   delete(p,1,1)
  413.                else
  414.                   p := '&' + p;
  415.             inc(ex.n);
  416.             if ex.n > maxparam then
  417.                fatal('Too many params (pread)');
  418.             ex.id[ex.n] := p;
  419.             ctl := ctl + '%'+ty;
  420.          end;
  421.  
  422.          if tok[1] = ',' then
  423.             gettok;
  424.       end;
  425.  
  426.       gettok;   {consume the )}
  427.  
  428.       if ctl = '%s' then
  429.          ctl := '#';
  430.       if ln then
  431.          ctl := ctl + '\n';
  432.  
  433.       if func[1] <> 'f' then
  434.          func := 'f' + func + 'stdin,';
  435.  
  436.       puts(func+'"'+ctl+'"');
  437.       for i := 1 to ex.n do
  438.          puts(','+ex.id[i]);
  439.  
  440.       puts(')');
  441.    end
  442.  
  443.    else   {otherwise there is no param list}
  444.       if ln then
  445.          puts('scanf("\n")');
  446.  
  447.    nospace := false;
  448.  
  449.    if tok[1] = ';' then
  450.    begin
  451.       puttok;
  452.       gettok;
  453.    end
  454.    else
  455.  
  456.    begin
  457.       puts('; ');
  458.       newline;
  459.    end;
  460.  
  461. end;
  462.  
  463.  
  464. (********************************************************************)
  465. type
  466.    write_modes = (m_write, m_writeln, m_str);
  467.  
  468. procedure pwrite(mode: write_modes);
  469. var
  470.    ctl:  string;
  471.    func: anystring;
  472.    ex:   paramlist;
  473.    p:    string;
  474.    ty:   string[2];
  475.    i:    integer;
  476.  
  477.    procedure addform(f: anystring);
  478.       {add a form parameter, special handling for form expressions}
  479.    begin
  480.       if isnumber(f) then
  481.          ctl := ctl + f      {pass literal form}
  482.       else
  483.       begin                      {insert form expression in parlist}
  484.          ctl := ctl + '*';
  485.          inc(ex.n);
  486.          if ex.n > maxparam then
  487.             fatal('Too many params (pwrite.form)');
  488.          ex.id[ex.n] := ex.id[ex.n-1];
  489.          ex.id[ex.n-1] := f;
  490.       end;
  491.    end;
  492.    
  493. begin
  494.    if debug_parse then write(' <write>');
  495.    
  496.    nospace := true;   {don't copy source whitespace to output during
  497.                        this processing.  this prevents spaces from
  498.                        getting moved around}
  499.  
  500.    nospace := true;
  501.  
  502.    if mode = m_str then
  503.       func := 'sbld('
  504.    else
  505.       func := 'printf(';
  506.       
  507.    gettok;   {consume the write}
  508.    
  509.    if tok[1] = '(' then
  510.    begin
  511.       gettok;   {consume the (}
  512.  
  513.       if ltok[1] = '[' then   {check for MT+ [addr(name)], form}
  514.       begin
  515.          gettok;   {consume the '[' }
  516.  
  517.          if tok[1] <> ']' then
  518.          begin
  519.             gettok;   {consume the ADDR}
  520.             gettok;   {consume the '(' }
  521.             func := 'iprintf(' + usetok + ',';
  522.             gettok;   {consume the ')'}
  523.          end;
  524.  
  525.          gettok;   {consume the ']'}
  526.          if tok[1] = ',' then
  527.             gettok;
  528.       end;
  529.  
  530.       ctl := '';
  531.       ex.n := 0;
  532.  
  533.       while (tok[1] <> ')') and not recovery do
  534.       begin
  535.          p := pexpr;
  536.          ty := exprtype;
  537.  
  538.          {convert to fprintf if first param is a file variable}
  539.          if (ex.n = 0) and (ty = '@') then
  540.             func := 'fprintf(' + p + ','
  541.          else
  542.  
  543.          {process a new expression; add expressions to ex.id table
  544.           and append proper control codes to the control string}
  545.          begin
  546.             inc(ex.n);
  547.             if ex.n > maxparam then
  548.                fatal('Too many params (pwrite)');
  549.             ex.id[ex.n] := p;
  550.  
  551.             if ty = 'D' then
  552.                ty := 'ld';
  553.             if ty = 'b' then
  554.                ty := 'd';
  555.  
  556.             {decode optional form parameters}
  557.             if tok[1] = ':' then
  558.             begin
  559.                ctl := ctl + '%';
  560.                gettok;
  561.                addform(pexpr);               
  562.                
  563.                if tok[1] = ':' then
  564.                begin
  565.                   ctl := ctl + '.';
  566.                   gettok;
  567.                   addform(pexpr);
  568.                   ty := 'f';
  569.                end;
  570.                
  571.                ctl := ctl + ty;
  572.             end
  573.             else
  574.  
  575.             begin
  576.                {pass literals into the control string}
  577.                if (p[1] = '"') or (p[1] = '''') then
  578.                begin
  579.                   ctl := ctl + copy(p,2,length(p)-2);
  580.                   dec(ex.n);
  581.                end
  582.  
  583.                {otherwise put in the control string for this param}
  584.                else
  585.                   ctl := ctl + '%'+ty;
  586.             end;
  587.          end;
  588.  
  589.          if tok[1] = ',' then
  590.             gettok;
  591.       end;
  592.  
  593.       gettok;   {consume the )}
  594.  
  595.       {add newline in 'writeln' translation}
  596.       if mode = m_writeln then
  597.          ctl := ctl + '\n';
  598.  
  599.       {convert last parameter into destination in 'str' translation}
  600.       if mode = m_str then
  601.       begin
  602.          func := func + ex.id[ex.n] + ',';
  603.          dec(ex.n);
  604.          delete(ctl,length(ctl)-1,2);
  605.       end;
  606.  
  607.       {produce the translated statement}
  608.       puts(func+'"'+ctl+'"');
  609.       for i := 1 to ex.n do
  610.          puts(','+ex.id[i]);
  611.  
  612.       puts(')');
  613.    end
  614.  
  615.    else   {otherwise there is no param list}
  616.       if mode = m_writeln then
  617.          puts('printf("\n")');
  618.  
  619.    nospace := false;
  620.  
  621.    if tok[1] = ';' then
  622.    begin
  623.       puttok;
  624.       gettok;
  625.    end
  626.    else
  627.  
  628.    begin
  629.       puts('; ');
  630.       newline;
  631.    end;
  632.  
  633. end;
  634.  
  635.  
  636. (********************************************************************)
  637. procedure pnew;
  638. var
  639.    lv: string;
  640. begin
  641.    if debug_parse then write(' <new>');
  642.  
  643.    gettok;   {consume the new}
  644.    gettok;   {consume the (}
  645.  
  646.    lv := plvalue;
  647.    puts(lv+' = malloc(sizeof(*'+lv+'));');
  648.  
  649.    gettok;   {consume the )}
  650.    if tok[1] = ';' then
  651.       gettok;
  652. end;
  653.  
  654.  
  655. (********************************************************************)
  656. procedure pport(kw: string);
  657.    {translate port/portw/mem/memw}
  658. var
  659.    lv: string;
  660.  
  661. begin
  662.    if debug_parse then write(' <port>');
  663.    lv := kw + '(';
  664.  
  665.    gettok;     {consume the keyword}
  666.    gettok;     {consume the [ }
  667.  
  668.    repeat
  669.       lv := lv + pexpr;
  670.       if tok[1] = ':' then
  671.       begin
  672.          gettok;
  673.          lv := lv + ',';
  674.       end;
  675.    until (tok[1] = ']') or recovery;
  676.  
  677.    gettok;     {consume the ] }
  678.  
  679.    if tok = ':=' then
  680.    begin
  681.       gettok;       {consume :=, assignment statement}
  682.       lv := lv + ',' + pexpr;
  683.    end;
  684.  
  685.    puts(lv+');');
  686.  
  687.    if tok[1] = ';' then
  688.       gettok;
  689. end;
  690.  
  691.  
  692. (********************************************************************)
  693. procedure pinline;
  694.    {translate inline statements}
  695.  
  696. var
  697.    sixteen: boolean;
  698.  
  699. begin
  700.    if debug_parse then write(' <inline>');
  701.  
  702.    gettok;     {consume the keyword}
  703.    nospace := true;
  704.    gettok;
  705.  
  706.    while (tok[1] <> ')') and not recovery do
  707.    begin
  708.       if tok[1] = '/' then
  709.          gettok;
  710.  
  711.       if tok[1] = '>' then
  712.       begin
  713.          gettok;
  714.          sixteen := true;
  715.       end
  716.       else
  717.          sixteen := htoi(ltok) > $00ff;
  718.  
  719.       putline;
  720.       if sixteen then
  721.          puts('      asm DW '+ltok+'; ')
  722.       else
  723.          puts('      asm DB '+ltok+'; ');
  724.       gettok;
  725.    end;
  726.  
  727.    nospace := false;
  728.    gettok;     {consume the ) }
  729.  
  730.    if tok[1] = ';' then
  731.       gettok;
  732. end;
  733.  
  734.  
  735. (********************************************************************)
  736. procedure pident;
  737.    {parse statements starting with an identifier;  these are either
  738.     assignment statements, function calls, return-value assignments,
  739.     or label identifiers}
  740. var
  741.    ex: string;
  742.    lv: string;
  743.    lvt,ext: char;
  744.  
  745. begin
  746.    if debug_parse then write(' <ident>');
  747.  
  748.    nospace := true;   {don't copy source whitespace to output during
  749.                        this processing.  this prevents spaces from
  750.                        getting moved around}
  751.  
  752.    lv := plvalue;     {destination variable or function name}
  753.    lvt := exprtype;   {destination data type}
  754.  
  755.    if tok = ':=' then
  756.    begin
  757.       if debug_parse then write(' <assign>');
  758.       
  759.       gettok;       {consume :=, assignment statement}
  760.       ex := pexpr;
  761.       ext := exprtype;
  762.  
  763.       if iscall(lv) then      {assignment to function name}
  764.          puts('return '+ex)
  765.       else
  766.  
  767.       begin
  768.          if copy(ex,1,5) = 'scat(' then
  769.             puts('sbld('+lv+',' + copy(ex,6,255))
  770.          else
  771.  
  772.          if lvt = 's' then
  773.             if ext = 's' then
  774.                puts('strcpy('+lv+','+ex+')')
  775.             else
  776.                puts('sbld('+lv+',"%'+ext+'",'+ex+')')
  777.          else
  778.  
  779.          if lvt = 'c' then
  780.             if ext = 's' then
  781.                puts(lv+' = first('+ex+')')
  782.             else
  783.                puts(lv+' = '+ex)
  784.          else
  785.             puts(lv+' = '+ex);
  786.       end;
  787.    end
  788.    else
  789.  
  790.    if tok[1] = ':' then
  791.    begin
  792.       if debug_parse then write(' <label>');
  793.       
  794.       putline;
  795.       puts(lv+': ');
  796.  
  797.       gettok;       {label identifier}
  798.  
  799.       if tok[1] = ';' then
  800.          gettok;
  801.  
  802.       exit;
  803.    end
  804.    else
  805.  
  806.    begin   
  807.       if debug_parse then write(' <call>');
  808.  
  809.       if iscall(lv) then
  810.          puts(lv)
  811.       else
  812.          puts(lv+'()');
  813.    end;
  814.    
  815.    nospace := false;
  816.  
  817.    if tok[1] = ';' then
  818.    begin
  819.       puttok;
  820.       gettok;
  821.    end
  822.    else
  823.  
  824.    begin
  825.       puts('; ');
  826.       {newline;?}
  827.    end;
  828.  
  829. end;
  830.  
  831.  
  832.  
  833.  
  834. (********************************************************************)
  835. procedure pnumlabel;
  836.    {parse statements starting with an number;  these must be
  837.     numeric labels}
  838. begin
  839.    if debug_parse then write(' <numlabel>');
  840.    putline;
  841.    puts('label_'+tok+': ');
  842.  
  843.    gettok;      {consume the number}
  844.    gettok;      {consume the :}
  845. end;
  846.  
  847.  
  848. (********************************************************************)
  849. procedure plabel;
  850.    {parse (and throw away) a label section}
  851. begin
  852.    if debug_parse then write(' <label>');
  853.  
  854.    while tok[1] <> ';' do
  855.       gettok;
  856.  
  857.    gettok;
  858. end;
  859.  
  860.  
  861.  
  862.  
  863. (********************************************************************)
  864. (*
  865.  * process single statement
  866.  *
  867.  * expects tok to be first token of statement
  868.  * processes nested blocks
  869.  * exits with tok as end of statement
  870.  *
  871.  *)
  872.  
  873. procedure pstatement;
  874. var
  875.    builtin: boolean;
  876.    
  877. begin
  878.  
  879.    if recovery then
  880.    begin
  881.       while tok[1] <> ';' do
  882.          gettok;
  883.       gettok;
  884.       {warning('Error recovery (pstatement)');}
  885.       recovery := false;
  886.       exit;
  887.    end;
  888.    
  889.    if (toktype = identifier) and (cursym <> nil) then
  890.       builtin := cursym^.suptype = ss_builtin
  891.    else
  892.       builtin := false;
  893.  
  894.    if debug_parse then write(' <stmt>');
  895.  
  896.    if toktype = number then
  897.       pnumlabel
  898.    else
  899.    
  900.    case tok[1] of
  901.    '.':
  902.       exit;
  903.  
  904.    ';':
  905.       begin
  906.          puts('; ');
  907.          gettok;
  908.       end;
  909.       
  910.    '{':
  911.       pblock;
  912.  
  913.    'C':
  914.       if tok = 'CASE' then
  915.          pcase
  916.       else
  917.          pident;
  918.  
  919.    'E':
  920.       if builtin and (tok = 'EXIT') then
  921.          pexit
  922.       else
  923.          pident;
  924.  
  925.    'F':
  926.       if tok = 'FOR' then
  927.          pfor
  928.       else
  929.          pident;
  930.       
  931.    'G':
  932.       if tok = 'GOTO' then
  933.          pgoto
  934.       else
  935.          pident;
  936.          
  937.    'H':
  938.       if tok = 'HALT' then
  939.          phalt
  940.       else
  941.          pident;
  942.          
  943.    'I':
  944.       if tok = 'IF' then
  945.          pif
  946.       else
  947.       if tok = 'INLINE' then
  948.          pinline
  949.       else
  950.          pident;
  951.          
  952.    'M':
  953.       if builtin and (tok = 'MEM') then
  954.          pport('pokeb')
  955.       else
  956.       if builtin and (tok = 'MEMW') then
  957.          pport('poke')
  958.       else
  959.          pident;
  960.          
  961.    'N':
  962.       if tok = 'NEW' then
  963.          pnew
  964.       else
  965.          pident;
  966.          
  967.    'P':
  968.       if builtin and (tok = 'PORT') then
  969.          pport('outportb')
  970.       else
  971.       if builtin and (tok = 'PORTW') then
  972.          pport('outport')
  973.       else
  974.          pident;
  975.          
  976.    'R':
  977.       if tok = 'REPEAT' then
  978.          prepeat
  979.       else
  980.       if tok = 'READ' then
  981.          pread
  982.       else
  983.       if tok = 'READLN' then
  984.          pread
  985.       else
  986.          pident;
  987.  
  988.    'S':
  989.       if builtin and (tok = 'STR') then
  990.          pwrite(m_str)
  991.       else
  992.          pident;
  993.                   
  994.    'W':
  995.       if tok = 'WHILE' then
  996.          pwhile
  997.       else
  998.       if tok = 'WITH' then
  999.          pwith
  1000.       else
  1001.       if tok = 'WRITE' then
  1002.          pwrite(m_write)
  1003.       else
  1004.       if tok = 'WRITELN' then
  1005.          pwrite(m_writeln)
  1006.       else
  1007.          pident;
  1008.    else
  1009.       pident;
  1010.    end;
  1011. end;
  1012.  
  1013.  
  1014. (********************************************************************)
  1015. (*
  1016.  * process begin...end blocks
  1017.  *
  1018.  * expects tok to be begin
  1019.  * exits with tok = end
  1020.  *
  1021.  *)
  1022.  
  1023. procedure pblock;
  1024. begin
  1025.    if debug_parse then write(' <block>');
  1026.  
  1027.    puts('{ ');
  1028.    gettok;                 {get first token of first statement}
  1029.  
  1030.    while (tok[1] <> '}') and not recovery do
  1031.    begin
  1032.       pstatement;          {process the statement}
  1033.  
  1034.       if tok[1] = ';' then
  1035.       begin
  1036.          puttok;
  1037.          gettok;           {get first token of next statement}
  1038.       end;
  1039.    end;
  1040.  
  1041.    if not linestart then
  1042.       newline;
  1043.       
  1044.    puttok;                 {put the closing brace}
  1045.  
  1046.    gettok;
  1047.    if tok[1] = ';' then
  1048.       gettok;
  1049. end;
  1050.  
  1051.  
  1052. (********************************************************************)
  1053. (*
  1054.  * process interface, implementation and uses statements
  1055.  *
  1056.  *)
  1057.  
  1058. (********************************************************************)
  1059. procedure puses;
  1060.    {parse a uses clause}
  1061. begin
  1062.    if debug_parse then write(' <uses>');
  1063.  
  1064.    gettok;     {consume the USES}
  1065.    
  1066.    repeat
  1067.  
  1068.       {generate an include for the unit header file}
  1069.       puts('#include "'+ltok+'.UNH"');
  1070.       newline;                      
  1071.       
  1072.       {load the saved unit header symbol table}
  1073.       load_unitfile(ltok+'.UNS',globals);
  1074.  
  1075.       {move interface section to skip new entries}
  1076.       top_interface := globals;     
  1077.       
  1078.       gettok;                       {consume the unit name}
  1079.       if tok[1] = ',' then
  1080.          gettok;
  1081.    until (tok[1] = ';') or recovery;
  1082.    
  1083. end;
  1084.  
  1085.  
  1086. (********************************************************************)
  1087. procedure pinterface;
  1088. begin
  1089.    if debug_parse then write(' <interface>');
  1090.    gettok;
  1091.    if tok = 'USES' then
  1092.       puses;
  1093.       
  1094.    in_interface := true;
  1095.    top_interface := globals;
  1096.  
  1097.    putline;
  1098.    putln('#define extern /* globals defined here */');
  1099.    putln('#include "'+unitname+'.UNH"');
  1100.    putln('#undef extern');
  1101.    
  1102.    inc(unitlevel);
  1103.    assign(ofd[unitlevel],unitname+'.UNH');
  1104.    rewrite(ofd[unitlevel]);
  1105.    getmem(outbuf[unitlevel],inbufsiz);
  1106.    SetTextBuf(ofd[unitlevel],outbuf[unitlevel]^,inbufsiz);
  1107.  
  1108.    putline;
  1109.    putln('/* Unit header for: '+outname+' -- Made by '+version1+' */');
  1110.  
  1111.    if tok[1] = ';' then
  1112.       gettok;
  1113. end;
  1114.  
  1115.  
  1116. (********************************************************************)
  1117. procedure pimplementation;
  1118. begin
  1119.    if debug_parse then write(' <implementation>');
  1120.    if not in_interface then
  1121.       exit;
  1122.    in_interface := false;
  1123.  
  1124.    {terminate the .unh file being generated}
  1125.    close(ofd[unitlevel]);
  1126.    freemem(outbuf[unitlevel],inbufsiz);
  1127.    dec(unitlevel);
  1128.    
  1129.    {create the requested unit symbol file}
  1130.    create_unitfile(unitname+'.UNS',globals,top_interface);
  1131.  
  1132.    gettok;
  1133. end;
  1134.  
  1135.  
  1136.