home *** CD-ROM | disk | FTP | other *** search
/ The Education Master 1994 (4th Edition) / EDUCATIONS_MASTER_4TH_EDITION.bin / files / progscal / tinypasc / tuskel.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1986-02-17  |  24.1 KB  |  849 lines

  1. { Copyright (C) 1986 by QCAD Systems Incorporated, All Rights Reserved }
  2.  
  3. program TUPROG(input, output);
  4.  
  5.   { TUSKEL:
  6.  
  7.        A simple Compiler for Turbo }
  8.  
  9.   const
  10.     VERSION_STRING= 'version 1.0';
  11.     STACKSIZE = 60;   { maximum size of LR(1) parser stack }
  12.     EOS = 0;          { marks end of line in LINE }
  13.     EOFCH = 26;       { reader end-of-file character }
  14.     EOLCH = 12;       { end of line character }
  15.     CR = 13;          { carriage return }
  16.     MAXSTRCHARS = 1000;  { maximum string space/procedure }
  17.     MAXERRORS = 20;   { maximum errors before aborting }
  18.     HASHSIZE = 167;    { hash table size -- prime number! }
  19.     HLIMIT = 166;      { limit in hash table (hashsize minus one) }
  20.     MAXTOKLEN = 30;   { length of a token or symbol }
  21.     MERR_COUNT= 4;    {minimum tokens to scan before reporting errors
  22.                         again}
  23.  
  24. {#C -- constants defined by the parser generator go here }
  25.     IDENT_TOKLEN = #C;  { maximum user identifier length }
  26.     MAXRPLEN = #D;    { length of longest production right part }
  27.     TERM_TOKS = #E;   { number of terminal tokens }
  28.     NTERM_TOKS = #F;  { number of nonterminal tokens }
  29.     ALL_TOKS = #G;    { term_toks + nterm_toks }
  30.     IDENT_TOKX = #H;  { token number of <identifier> }
  31.     INT_TOKX = #I;    { token number of <integer> }
  32.     REAL_TOKX = #J;   { token number of <real> }
  33.     STR_TOKX = #K;    { token number of <string> }
  34.     STOP_TOKX = #L;   { token number of stopsign (end-of-file) }
  35.     GOAL_TOKX = #M;   { token number of goal }
  36.     EOL_TOKX = #N;    { token number of end-of-line }
  37.     READSTATE = #O;   { first READ state }
  38.     LOOKSTATE = #P;   { first LOOK state }
  39.     MAXSTATE = #Q;    { largest state number }
  40.     REDUCELEN = #R;   { number of productions }
  41.     RLTOKENS = #S;
  42.     SSTOKENS = #T;
  43.     PRODTOKS = #U;
  44.     TOKCHARS = #V;
  45.     START_STATE = #W;  { initial state }
  46.     STK_STATE_1 = #X;  { state initially pushed on stack }
  47. {#> -- end of constants }
  48.  
  49.   type
  50.     INT = -32767..32767;
  51.     STRING1= string[1];
  52.     STRING7 = string[7];
  53.     STRING8 = string[8];
  54.     STRING9 = string[9];
  55.     STRING15 = string[15];
  56.     STRING31 = string[31];
  57.     STRING80 = string[80];
  58.     LONGSTRING = string[255];
  59.     TOKRANGE = 1..term_toks;
  60.  
  61.    {$I tudecls}
  62.  
  63.   type
  64.     SYMTABLE= array [0..hlimit] of symtabp;
  65.     STATE_STACK = array [0..stacksize] of int;
  66.     { Types for parser tables.  NB:  These type names are used by
  67.       the typed constant generation. }
  68.     STATE_ARRAY = array [1..maxstate] of int;
  69.     REDUCE_ARRAY = array [1..reducelen] of int;
  70.     POP_ARRAY = array [1..reducelen] of byte;
  71.     TOKEN_ARRAY = array [0..rltokens] of byte;
  72.     TOSTATE_ARRAY = array [0..rltokens] of int;
  73.     SS_ARRAY = array [0..sstokens] of int;
  74.     PROD_ARRAY = array [1..prodtoks] of byte;
  75.     TOKX_ARRAY = array [1..all_toks] of int;
  76.     TOKCHAR_ARRAY = array [1..tokchars] of char;
  77.     INSYM_ARRAY = array [1..lookstate] of int;
  78.  
  79.   const
  80. {#<C -- put typed constants here, if they've been requested }
  81.     { Static parser data structures (parser tables). }
  82. {#IP}
  83. {#>}
  84.    {Flag constants}
  85. {#F   }
  86.     #N= #V;
  87.  
  88.   var
  89.     { Dynamic parser data structures }
  90.     STACK:  state_stack;  { the LR(1) state stack }
  91.     SEM:  array [0..stacksize] of semrecp;  { semantics stack }
  92.     TOS:  int;  { index of top of stack }
  93.  
  94. {#<~C -- the following are redundant if typed constants are used }
  95.     { Static parser data structures (parser tables). }
  96.     STATEX:  state_array;    { stack top index }
  97.     MAP:  reduce_array;      { mapping from state to apply numbers }
  98.     POPNO:  pop_array;       { reduce pop size }
  99.     TOKNUM:  token_array;    { token list }
  100.     TOSTATE:  tostate_array;  { read, look states }
  101.     STK_STATE:  ss_array;
  102.     STK_TOSTATE: ss_array;
  103. {#<D -- these are for parser stack dumps. }
  104.     PRODX:  reduce_array;    { prod index into ... }
  105.     PRODS:  prod_array;      { token number, index into ... }
  106.     INSYM:  insym_array;
  107. {#> -- end if for debugging. }
  108. {#> -- end if for typed constants. }
  109.  
  110. {#<D -- debugging (these cannot be typed constants.) }
  111.     { These guys are for printing tokens in parser stack dumps. }
  112.     TOKX:  tokx_array;       { token index, index into ... }
  113.     TOKCHAR:  tokchar_array;  { token characters }
  114. {#> -- end if for debugging. }
  115.  
  116.     { Lexical and token data }
  117.     LINE:  longstring;       { source line }
  118.     LX:  int;                { index of next character in LINE }
  119.     ERRPOS: int;             { current token position in LINE }
  120.     PROMPT: string8;         { prompt string }
  121.     PROMPTLEN: int;          { front-end length for error purposes }
  122.     IS_CONSOLE: boolean;     { TRUE if input from console }
  123.     CH:  char;               { next character from input file }
  124.     TOKEN:  int;             { Next token in input list }
  125.     LSEMP:  semrecp;         { current semantics assoc. with token }
  126.     TOKENX:  int;            { index into TOKARY, LSEMPARY }
  127.     TOKARY:  array [0..1] of int;  { token queue }
  128.     LSEMPARY:  array [0..1] of semrecp;
  129.     ERRSYM:  symbol;        { special symbol reserved for errors }
  130.     { The next table can be omitted if real numbers are not used. }
  131.     PWR10_2:  array [0..8] of real;  { Binary powers of ten. }
  132.  
  133.     { Symbol table data }
  134.     SYMTAB: symtable;
  135.  
  136.     { String table space }
  137.     STRTAB: packed array [0..maxstrchars] of char;
  138.     STRX: integer;   {next available character slot in STRTAB}
  139.  
  140.     SFILE, RFILE: text;      { source, report files }
  141.  
  142.     ERR_COUNT,
  143.     ERRORS: int;
  144.     DEBUG: int;              { >0 turns on some tracing }
  145.     TRACE: boolean;
  146.  
  147.     SFILENAME, RFILENAME: string80;  { file names }
  148.  
  149.   function NEW_SEM (SEMTYP: semtype): semrecp; forward;
  150.   procedure IDEBUG; forward;
  151.  
  152.   {$I tuutils}
  153.  
  154.   {$I tufiles}
  155.  
  156.   {******************}
  157.   procedure MORE(MSG: string80);
  158.     { print the string, and let the user type
  159.       any character to proceed. }
  160.     var FOO:  char;
  161.   begin
  162.     foo := resp(msg)
  163.     end;
  164.  
  165.   {******************}
  166.   procedure REPORT_ERR(MSG: string80);
  167.   begin
  168.     if err_count=0 then begin
  169.       if errpos+promptlen>1 then
  170.         write(rfile, ' ':errpos+promptlen-1);
  171.       writeln(rfile, '^');  { mark error point }
  172.       writeln(rfile, msg);
  173.       end
  174.     end;
  175.  
  176.   {*******************}
  177.   procedure ABORT(MSG: string80);
  178.   begin
  179.     report_err(concat('FATAL ERROR: ', msg));
  180.     writeln('... aborting');
  181.     halt;
  182.     end;
  183.  
  184.   {******************}
  185.   procedure ERROR(MSG: string80);
  186.   begin
  187.     if err_count=0 then begin
  188.       report_err(concat('ERROR: ', msg));
  189.       errors:=errors+1;
  190.       if errors>maxerrors then begin
  191.         err_count:=0;
  192.         abort('Error limit exceeded');
  193.         end
  194.       else
  195.       if (rfilename=default_rfile) then idebug;
  196.       end
  197.     end;
  198.  
  199.   {*******************}
  200.   procedure WARN(MSG: string80);
  201.   begin
  202.     report_err(concat('WARNING: ', msg));
  203.     end;
  204.  
  205.   {$I tusyms}
  206.  
  207.   {********************}
  208.   procedure SYMERROR(SYM: symbol; MSG: string80);
  209.   begin
  210.     error(concat(sym, concat(': ', msg)));
  211.     end;
  212.  
  213. {#<D -- debugging utilities. }
  214.   {$I tudbug}
  215.  
  216. {#> -- end debugging stuff. }
  217. { LEXICAL ANALYZER }
  218.  
  219.   {*******************}
  220.   procedure GETLINE;
  221.     { read the next source line, when nextch exhausts
  222.       the current one. }
  223.  
  224.     {.............}
  225.     procedure GENEOF;
  226.     begin
  227.       line := chr(eofch);
  228.       lx := 1
  229.     end;
  230.  
  231.     {............}
  232.     procedure GRABLINE;
  233.     begin
  234.       readln(sfile, line);
  235.       writeln(rfile, ' ; ', line);
  236.       lx := 1
  237.     end;
  238.  
  239.   begin { getline }
  240.     if is_console then begin
  241.       { prompt if from the console file }
  242.       write(prompt);
  243.       grabline;
  244.       if line = 'EOF' then geneof
  245.       end
  246.     else if eof(sfile) then
  247.       geneof
  248.     else
  249.       grabline;
  250.     { The appended eol character ensures that tokens are broken over
  251.       line endings; they would otherwise be invisible to the scanner.
  252.       eolch allows the string scanner to distinguish ends of lines. }
  253.     line := concat(line, '  ');
  254.     line[length(line)-1]:=chr(eolch);
  255.   end;
  256.  
  257.   {*******************}
  258.   procedure NEXTCH;
  259.     { gets next character from line }
  260.   begin
  261.     if lx > length(line) then
  262.       getline;
  263.     ch := line[lx];
  264.     { don't move past an eof mark }
  265.     if ch <> chr(eofch) then lx := lx+1
  266.   end;
  267.  
  268.   {********************}
  269.   function PEEKCH: char;
  270.   begin
  271.     if lx>length(line) then peekch:=chr(eolch)
  272.     else
  273.     peekch:=line[lx];
  274.     end;
  275.  
  276.   {********************}
  277.   procedure SKIPBLANKS;
  278.     label 1;
  279.  
  280.     {..................}
  281.     function END_COMMENT: boolean;
  282.     begin
  283.       if ch=chr(eofch) then begin
  284.         error('unclosed comment at file end');
  285.         end_comment:=true;
  286.         end
  287.       else
  288.       end_comment:=(ch='}');
  289.       end;
  290.  
  291.   begin  {comments open on { and close on close-brace }
  292.     1:
  293.     while ch=' ' do nextch;
  294.     if (ch='{') then begin
  295.       while not(end_comment) do nextch;
  296.       nextch;
  297.       goto 1;
  298.       end
  299.     end;
  300.  
  301.   {***********************}
  302.   procedure GET_SYMBOL;
  303.       {collects Pascal-style identifiers,
  304.           stuffed into symbol table under IDENT tag}
  305.     var SYM: symbol;
  306.         STP: symtabp;
  307.   begin
  308.     sym:='';
  309.     { Keep snarfing alphanumeric characters.  Up to the first
  310.       maxtoklen of them will be put in the symbol spelling. }
  311.     while ch in ['a'..'z', 'A'..'Z', '0'..'9', '_'] do begin
  312.       if length(sym) <= maxtoklen then begin
  313.         sym:=concat(sym, ' ');
  314.         sym[length(sym)] := upcase(ch);
  315.         end;
  316.       nextch;
  317.       end;
  318.     stp := makesym(symtab, sym, user, 0);  { the default level is 0 }
  319.     if (stp^.symt=reserved) then
  320.     token:=stp^.tokval
  321.     else begin
  322.       lsemp:=new_sem(ident);
  323.       with lsemp^ do begin
  324.         symp := stp;
  325.         token := ident_tokx;
  326.         end
  327.       end
  328.     end;
  329.  
  330.   {************************}
  331.   procedure GET_NUMBER;
  332.     var V: integer;
  333.   begin
  334.     v:=0;
  335.     while ch in ['0'..'9'] do begin
  336.       v:=10*v + ord(ch) - ord('0');
  337.       nextch;
  338.       end;
  339.     token:= int_tokx;
  340.     lsemp:=new_sem(fixed);
  341.     lsemp^.numval:=v;
  342.     end;
  343.  
  344.   {***********************}
  345.   procedure GET_STRING;
  346.     label 1, 99;
  347.   
  348.     {..................}
  349.     procedure PUTCH(CH: char);
  350.     begin
  351.       if strx<maxstrchars then begin
  352.         strtab[strx]:=ch;
  353.         strx:=strx+1;
  354.         end
  355.       else
  356.       if strx=maxstrchars then begin
  357.         error('too many string characters');
  358.         strtab[maxstrchars]:=chr(0);
  359.         strx:=strx+1;
  360.         end
  361.       end;
  362.         
  363.   begin
  364.     lsemp:=new_sem(strng);
  365.     lsemp^.stx:=strx;
  366.     1:
  367.     nextch;  {get over first quote mark}
  368.     while ch<>'''' do begin
  369.       if ch=chr(eolch) then begin
  370.         error('string runs over end of line');
  371.         goto 99;
  372.         end;
  373.       putch(ch);
  374.       nextch;
  375.       end;
  376.     nextch;  {get over last quote mark}
  377.     if ch='''' then begin  {repeated quote mark}
  378.       putch(ch);
  379.       goto 1;   {continue grabbing characters}
  380.       end;
  381.     99:
  382.     putch(chr(0));
  383.     token:=str_tokx;
  384.     end;
  385.     
  386.   {********************}
  387.   procedure GET_TOKEN;
  388.     { Pascal-style lexical analyzer -- sets TOKEN to token number }
  389.   begin
  390.     lsemp:= nil;  { default case }
  391.     skipblanks;
  392.     errpos:=lx-1;
  393.     case ch of
  394.       'a'..'z', 'A'..'Z': get_symbol;
  395.       '0'..'9': get_number;
  396.       '''': get_string;
  397. {#<D -- if debugging, invoke idebug on a bang (or other char). }
  398.       '!':  begin
  399.               idebug;
  400.               nextch;
  401.               get_token
  402.             end;
  403. {#>}
  404. {#G   special symbol cases go here }
  405.       ELSE  begin
  406.         if ch=chr(eofch) then
  407.           token := stop_tokx
  408.         else if ch=chr(eolch) then begin
  409.           nextch;
  410. {#<E            end-of-line token dealt with here }
  411.           token := eol_tokx  { accept an end-of-line token }
  412. {#:}
  413.           get_token  { go find another (significant) character }
  414. {#>}
  415.           end
  416.         else begin
  417.           error('invalid character');
  418.           nextch;
  419.           get_token;
  420.           end
  421.         end { case alternatives }
  422.       end; { case }
  423.     if err_count>0 then err_count:=err_count-1;
  424.     end { get_token };
  425.  
  426.   {*******************}
  427.   procedure NEXT_TOKEN;
  428.   begin
  429.     if tokenx>1 then begin
  430.       tokenx := 1;
  431.       get_token;  { goes into token, lsemp }
  432.       tokary[1] := token;
  433.       lsempary[1] := lsemp;
  434.       end
  435.     else begin
  436.       { is in tokary }
  437.       token := tokary[tokenx];
  438.       lsemp := lsempary[tokenx];
  439.       end
  440.     end;
  441.  
  442.   {*****************}
  443.   procedure TOKENREAD;
  444.   begin
  445.     tokenx := tokenx+1;
  446.     end;
  447.  
  448.   {$I tusems}
  449.  
  450.   { LR(1) PARSER procedures }
  451.  
  452.   {****************}
  453.   function ERROR_RECOVERY(var MSTACK: state_stack;
  454.                           var MSTACKX: int; MCSTATE: int): int;
  455.     label 99, 100;
  456.     var STACK: state_stack;  { local copy of stack }
  457.         TOS,              { local stack pointer }
  458.         CSTATE,              { local state }
  459.         JSTX,                { temporary stack limit }
  460.         RX, TL: int;         { index into TOKNUM table }
  461.  
  462.     {...............}
  463.     procedure COPY_STACK;
  464.       var STX: int;
  465.     begin
  466.       if (jstx<0) or (jstx>mstackx) then abort('ERROR RECOVERY BUG');
  467.       for stx := 0 to jstx do
  468.         stack[stx] := mstack[stx];
  469.       tos := jstx;
  470.       if jstx=mstackx then
  471.         cstate := mcstate
  472.       else
  473.         cstate := mstack[jstx+1];
  474.     end;
  475.  
  476.     {...............}
  477.     procedure PUSHREAD(CSTATE: int);
  478.       { adjusts the state stack }
  479.     begin
  480.       tos := tos+1;
  481.       if tos>stacksize then
  482.         abort('stack overflow');
  483.       stack[tos] := cstate;
  484.     end;
  485.  
  486.     {...............}
  487.     function TRIAL_PARSE: boolean;
  488.       { parses from current read state through the inserted and the
  489.         error token; if successful, returns TRUE. }
  490.       label 99;
  491.       var RX: int;
  492.     begin
  493.       trial_parse := true;  { until proven otherwise }
  494.       while cstate<>0 do begin
  495.         if cstate < readstate then begin
  496.           { a reduce state }
  497. {#<D      dump if debugging enabled. }
  498.           if debug > 3 then stk_dump('E*Reduce', stack,
  499.                                      tos, cstate);
  500. {#>       end conditional. }
  501.           if popno[cstate]=0 then begin
  502.             { empty production }
  503.             pushread(stk_state[statex[cstate]]);
  504.             cstate := stk_tostate[statex[cstate]];
  505.           end
  506.           else begin
  507.             { non-empty production }
  508.             tos := tos - popno[cstate] + 1;
  509.             rx := statex[cstate];   { compute the GOTO state }
  510.             cstate := stack[tos];
  511.             while (stk_state[rx]<>cstate) and
  512.                   (stk_state[rx]<>0) do rx := rx+1;
  513.             cstate := stk_tostate[rx];
  514.           end
  515.         end
  516.         else if cstate < lookstate then begin
  517.           { a read state }
  518.           next_token;  { need a token now }
  519. {#<D      dump if debugging enabled. }
  520.           if debug > 3 then stk_dump('E*Read', stack, tos, cstate);
  521. {#>       end conditional. }
  522.           rx := statex[cstate];
  523.           while (toknum[rx]<>0) and
  524.                 (toknum[rx]<>token) do rx := rx+1;
  525.           if toknum[rx]=0 then begin
  526.             { failure }
  527.             trial_parse := false;
  528.             goto 99;
  529.           end
  530.           else begin
  531.             { did read something }
  532.             pushread(cstate);
  533.             cstate := tostate[rx];
  534.             tokenread;  { scan the token }
  535.             if tokenx>1 then goto 99 { successful }
  536.           end
  537.         end
  538.         else begin
  539.           { lookahead state }
  540.           next_token;  { need a token now }
  541. {#<D      dump if debugging enabled. }
  542.           if debug > 3 then stk_dump('E*Look', stack, tos, cstate);
  543. {#>       end conditional. }
  544.           rx := statex[cstate];
  545.           while (toknum[rx]<>0) and
  546.                 (toknum[rx]<>token) do rx := rx+1;
  547.           cstate := tostate[rx];
  548.         end
  549.       end;
  550.     99:
  551.     end;
  552.  
  553.     {.................}
  554.     procedure INCR_ERRSYM;
  555.       { Note that this procedure assumes ASCII. }
  556.     begin
  557.       if errsym[6]='Z' then begin
  558.         errsym[5] := succ(errsym[5]);
  559.         errsym[6] := 'A';
  560.       end
  561.       else
  562.         errsym[6] := succ(errsym[6]);
  563.     end;
  564.  
  565.     {.................}
  566.     procedure MAKE_DEFAULT(TOKX: int; var SEMP: semrecp);
  567.       { creates a default token data structure }
  568.       var SYM: symbol; TSYMP: symtabp;
  569.     begin
  570.       case tokx of
  571.         ident_tokx: begin
  572.           tsymp := makesym(symtab, errsym, symerr, 0);
  573.           semp:=new_sem(ident);
  574.           with semp^ do begin
  575.             symp:=tsymp;
  576.             incr_errsym;
  577.             end
  578.           end;
  579.         int_tokx: begin 
  580.           semp:=new_sem(fixed);
  581.           semp^.numval:=1;
  582.           end;
  583.         ELSE
  584.           semp:=nil;
  585.       end { case tokx }
  586.     end;
  587.  
  588.   begin  { ERROR_RECOVERY }
  589.     if debug > 3 then writeln(rfile, 'Going into ERROR RECOVERY');
  590.     while true do begin
  591.       jstx := mstackx;
  592.       while jstx>=0 do begin
  593.         copy_stack;
  594.         rx := statex[cstate];
  595.         while toknum[rx]<>0 do begin
  596.           { scan through legal next tokens }
  597.           if debug > 3 then writeln(rfile, '...starting trial parse');
  598.           tokary[0] := toknum[rx];  { the insertion }
  599.           tokenx := 0;
  600.           if trial_parse then goto 99;  { it clicked! }
  601.           rx := rx+1;
  602.           if toknum[rx]<>0 then
  603.             copy_stack;
  604.         end;
  605.         jstx := jstx-1;  { reduce stack }
  606.       end;
  607.       if token=stop_tokx then begin
  608.         { empty stack, no more tokens }
  609.         cstate := 0;  { halt state }
  610.         tokenx := 2;
  611.         jstx := 0;  { bottom of stack }
  612.         goto 100;
  613.       end;
  614. {#<D}
  615.       if debug > 3 then begin
  616.         write(rfile, '...dropping token ');
  617.         tl := wrtok(tokary[1]);
  618.         writeln(rfile);
  619.       end;
  620. {#>}
  621.       tokenx := 2;
  622.       next_token;
  623. {#<D}
  624.       if debug > 3 then begin
  625.         write(rfile, 'New token ');
  626.         tl := wrtok(token);
  627.         writeln(rfile);
  628.       end
  629. {#>}
  630.     end;
  631.   99:  { found a solution }
  632.     copy_stack;
  633. {#<D}
  634.     if debug > 3 then begin
  635.       write(rfile, 'insertion of ');
  636.       tl := wrtok(tokary[0]);
  637.       writeln(rfile, ' succeeded');
  638.     end;
  639. {#>}
  640.     make_default(tokary[0], lsempary[0]);
  641.     tokenx := 0;  { forces a `real' rescan of the insertion }
  642.     if jstx<mstackx then
  643.       cstate := stack[jstx+1]
  644.     else
  645.       cstate := mcstate;  { cstate returned }
  646.   100:
  647.     error_recovery := cstate;
  648.     mstackx := jstx;
  649.     if debug > 3 then writeln(rfile, 'Ending error recovery');
  650.   end;
  651.  
  652.   {****************}
  653.   procedure PARSER;
  654.     { Carries out a complete parse, until
  655.       the halt state is seen -- same as empty stack}
  656.     var CSTATE, RX: int;
  657.         TSEMP: semrecp;
  658.  
  659.     {...............}
  660.     procedure PUSHREAD(CSTATE: int; SEMP: semrecp);
  661.       { do the push part of a readstate. }
  662.     begin
  663.       tos := tos+1;
  664.       if tos>stacksize then
  665.         abort('stack overflow');
  666.       sem[tos] := semp;
  667.       stack[tos] := cstate;
  668.     end;
  669.  
  670.   begin
  671.     cstate := start_state;
  672.     tos := -1;
  673.     pushread(stk_state_1, nil);
  674.     while cstate<>0 do begin
  675.       tsemp:=nil;
  676.       if cstate < readstate then begin
  677.         { a reduce state }
  678. {#<D    dump if debugging enabled. }
  679.         if debug > 0 then stk_dump('Reduce', stack, tos, cstate);
  680. {#>     end conditional. }
  681.         if map[cstate] <> 0 then
  682.           { the semantics action }
  683.           apply(map[cstate], tsemp);
  684.         if popno[cstate]=0 then begin
  685.           { empty production }
  686.           pushread(stk_state[statex[cstate]], tsemp);
  687.           cstate := stk_tostate[statex[cstate]];
  688.         end
  689.         else begin
  690.           { non-empty production:
  691.             semantics is preserved on a unit production A --> w,
  692.             where |w| = 1, unless something is in TSEMP.  Note that
  693.             if w is nonterminal, the production may be bypassed. }
  694.           tos := tos - popno[cstate] + 1;
  695.           if (tsemp<>nil) or (popno[cstate]<>1) then
  696.             sem[tos] := tsemp;
  697.           { compute the GOTO state }
  698.           rx := statex[cstate];
  699.           cstate := stack[tos];
  700.           while (stk_state[rx]<>cstate) and (stk_state[rx]<>0) do
  701.             rx := rx+1;
  702.           cstate := stk_tostate[rx];
  703.         end
  704.       end
  705.       else if cstate < lookstate then begin
  706.         { a read state }
  707.         next_token;  { need next token now }
  708. {#<D    dump if debugging enabled. }
  709.         if debug > 2 then stk_dump('Read', stack, tos, cstate);
  710. {#>     end conditional. }
  711.         rx := statex[cstate];
  712.         while (toknum[rx]<>0) and (toknum[rx]<>token) do
  713.           rx := rx+1;
  714.         if toknum[rx]=0 then begin
  715.           error('syntax error');
  716.           cstate := error_recovery(stack, tos, cstate);
  717.           err_count:=merr_count;
  718.         end
  719.         else begin
  720.           pushread(cstate, lsemp);
  721.           cstate := tostate[rx];
  722.           tokenread;  { token has been scanned }
  723.         end
  724.       end
  725.       else begin
  726.         { lookahead state }
  727.         next_token;  { need another token now }
  728. {#<D    dump if debugging enabled. }
  729.         if debug > 2 then stk_dump('Look', stack, tos, cstate);
  730. {#>     end conditional. }
  731.         rx := statex[cstate];
  732.         while (toknum[rx]<>0) and (toknum[rx]<>token) do
  733.           rx := rx+1;
  734.         cstate := tostate[rx];
  735.       end
  736.     end;
  737.     end_sem;
  738.   end;
  739.  
  740.   { PARSE INITIALIZATION }
  741.  
  742.   {*****************}
  743.   procedure INITTABLES;
  744.     var SX: int;
  745.         CODE_SYMP: symtabp;
  746.  
  747.     {................}
  748.     procedure PUTSYM(TSYM: symbol; TV: int);
  749.       var SYMP: symtabp;
  750.           I: int;
  751.     begin
  752.       symp:=makesym(symtab, tsym, reserved, -1);
  753.       symp^.tokval:=tv;
  754.     end;
  755.  
  756. {#<D   also need to init debugging tables? }
  757.     {................}
  758.     procedure PUTTOK(PRINTVAL: string80;  TOKNUM, START: int);
  759.       { this procedure is used to initialize the token tables.
  760.         toknum is the number of the token to be initialized, and
  761.         start is where it should start in the tokchar array. }
  762.       var OFFSET:  int;
  763.     begin
  764.       tokx[toknum] := start;
  765.       for offset := 0 to length(printval)-1 do
  766.         tokchar[start+offset] := printval[offset+1];
  767.       tokchar[start+length(printval)] := chr(0)
  768.     end;
  769. {#>    end puttok insertion. }
  770.  
  771.     {................}
  772.     procedure INIT_PARSER_TABLES;
  773.       { initialize the parser tables }
  774.     begin
  775. {#IS    inline symbol table inits. }
  776. {#<A    assignment style inits? }
  777. {#IP      do the parser tables inline. }
  778. {#>     end assignment inits. }
  779. {#<D    debugging? }
  780. {#IT      do the token tables inline. }
  781. {#>     end debugging }
  782.     end { init_parser_tables };
  783.  
  784.   begin { inittables }
  785.     pwr10_2[0] := 1E1;  {10^(2^0)}
  786.     pwr10_2[1] := 1E2;  {10^(2^1)}
  787.     pwr10_2[2] := 1E4;
  788.     pwr10_2[3] := 1E8;
  789.     pwr10_2[4] := 1E16;
  790.     pwr10_2[5] := 1E32;
  791.     lsempary[0]:=nil;
  792.     lsempary[1]:=nil;
  793.     lsemp := nil;
  794.     tokenx := 2;  { no token queue }
  795.     for sx := 0 to hlimit do begin
  796.       symtab[sx] := nil;  { initialize symbol tables }
  797.       end;
  798.     for sx := 0 to stacksize do begin
  799.       sem[sx]:=nil;
  800.     end;
  801.     init_parser_tables;
  802.     init_sem;
  803.     errsym:='ERR#AA';
  804.     strx:=0;
  805.     line := '';  { fake a new line }
  806.     lx := 1;
  807.     errpos:=1;
  808.     err_count:=0;
  809.     nextch;  { fetch the first character, forcing a line read }
  810.   end;
  811.  
  812.   {**********************}
  813.   function OPENFILES: boolean;
  814.   begin
  815.     openfiles:=false;
  816.     write('Source file? ');
  817.     readln(sfilename);
  818.     prompt:='';
  819.     promptlen:=3;  {length of ` ; '}
  820.     if sfilename='' then begin
  821.       prompt:='> ';
  822.       sfilename:=default_sfile;
  823.       is_console:=true;
  824.       promptlen:=promptlen+2;
  825.       end
  826.     else is_console:=false;
  827.     if openfile(sfile, sfilename, false) then begin
  828.       write('Target file? ');
  829.       readln(rfilename);
  830.       if rfilename='' then rfilename:=default_rfile;
  831.       openfiles:=openfile(rfile, rfilename, true);
  832.       end
  833.     end;
  834.     
  835. begin
  836.   writeln('Tiny Pascal Compiler, ', version_string);
  837.   writeln;
  838.   errors := 0;
  839.   debug := 0;
  840.   trace := false;
  841.   if openfiles then begin
  842.     inittables;
  843.     parser;  { does it all }
  844.     closefiles;
  845.     end
  846.   end.
  847.  
  848.  
  849.