home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 December / simtel1292_SIMTEL_1292_Walnut_Creek.iso / msdos / pascal / qparser.arc / CALCSKEL.PAS < prev    next >
Pascal/Delphi Source File  |  1985-07-26  |  29KB  |  918 lines

  1. { Copyright (C) 1984 by QCAD Systems, Inc., All Rights Reserved. }
  2.  
  3. {#P -- program line goes here }
  4. program #(input, output);
  5.  
  6.   { Calcskel:
  7.  
  8.     This is the skeleton file for a four-function calculator run
  9.     by an LALR(1) table-driven parser.  It is based on LR1SKEL, but
  10.     doesn't have all the file opening options, and doesn't use
  11.     a report file. }
  12.  
  13.   const
  14.     STACKSIZE = 60;   { maximum size of LR(1) parser stack }
  15.     EOS = 0;          { marks end of line in LINE }
  16.     EOFCH = 26;       { reader end-of-file character }
  17.     EOLCH = 12;       { end of line character }
  18.     LINELEN = 80;     { maximum length of a line }
  19.     STRTABLEN = 500;  { maximum number of chars in string table }
  20.     STRING_QUOTE = '''';  { character delimiting quoted strings }
  21.     MAXERRORS = 20;   { maximum errors before aborting }
  22.     HASHSIZE = 67;    { hash table size -- prime number! }
  23.     HLIMIT = 66;      { limit in hash table (hashsize minus one) }
  24.     MAXTOKLEN = 15;   { length of a token or symbol }
  25.  
  26. {#C -- constants defined by the parser generator go here }
  27.     IDENT_TOKLEN = #C;  { maximum user identifier length }
  28.     MAXRPLEN = #D;    { length of longest production right part }
  29.     TERM_TOKS = #E;   { number of terminal tokens }
  30.     NTERM_TOKS = #F;  { number of nonterminal tokens }
  31.     ALL_TOKS = #G;    { term_toks + nterm_toks }
  32.     IDENT_TOKX = #H;  { token number of <identifier> }
  33.     INT_TOKX = #I;    { token number of <integer> }
  34.     REAL_TOKX = #J;   { token number of <real> }
  35.     STR_TOKX = #K;    { token number of <string> }
  36.     STOP_TOKX = #L;   { token number of stopsign (end-of-file) }
  37.     GOAL_TOKX = #M;   { token number of goal }
  38.     EOL_TOKX = #N;    { token number of end-of-line }
  39.     READSTATE = #O;   { first READ state }
  40.     LOOKSTATE = #P;   { first LOOK state }
  41.     MAXSTATE = #Q;    { largest state number }
  42.     REDUCELEN = #R;   { number of productions }
  43.     RLTOKENS = #S;
  44.     SSTOKENS = #T;
  45.     PRODTOKS = #U;
  46.     TOKCHARS = #V;
  47.     START_STATE = #W;  { initial state }
  48.     STK_STATE_1 = #X;  { state initially pushed on stack }
  49. {#> -- end of constants }
  50. {#F -- form for FLAG constants }
  51.     #N = #V;
  52.  
  53.   type
  54.     INT = -32767..32767;
  55.     STRING8 = string[8];
  56.     STRING80 = string[80];
  57.     TOKRANGE = 1..term_toks;
  58.     {================== added operator for calcskel ==================}
  59.     OPERATOR = int;  { same type as the flags }
  60.  
  61.     SYMBOL = packed array [1..maxtoklen] of char;
  62.     {================ added real_variable for calcskel ===============}
  63.     SYMTYPE = (RESERVED, SYMERR, USER, REAL_VARIABLE);
  64.     SYMTABP = ^symtabtype;
  65.     SYMTABTYPE = record
  66.                    { structure for <identifier>s and keywords }
  67.                    NEXT: symtabp;
  68.                    LEVEL: int;
  69.                    SYM: symbol;
  70.                    case SYMT: symtype of
  71.                      reserved: (TOKVAL: tokrange);
  72.                      {=========== added for calcskel ==============}
  73.                      real_variable: (RVAL:  real);
  74.                  end;
  75.     SYMTABNAMES = array [symtype] of string[8];
  76.   const SYMTYPENAME: symtabnames =
  77.                   ('reserved', 'symerr  ', 'user    ', 'real var');
  78.  
  79.   type
  80.     SEMTYPE = (OTHER, IDENT, FIXED, FLOAT, STRNG);
  81.     SEMRECP = ^semrec;
  82.     SEMREC = record   { semantic stack structure }
  83.                case SEMT: semtype of
  84.                  ident: (SYMP: symtabp);
  85.                  fixed: (NUMVAL: integer);  { fixed point }
  86.                  float: (RVAL: real);   { floating point }
  87.                  strng: (STX: int);  { position in strtab }
  88.                  { Add more options as needed }
  89.              end;
  90.     SEMTABNAMES = array [semtype] of string[5];
  91.   const SEMTYPENAME: semtabnames =
  92.                   ('other', 'ident', 'fixed', 'float', 'strng');
  93.  
  94.   type
  95.     STATE_STACK = array [0..stacksize] of int;
  96.     { Types for parser tables.  NB:  These type names are used by
  97.       the typed constant generation. }
  98.     STATE_ARRAY = array [1..maxstate] of int;
  99.     REDUCE_ARRAY = array [1..reducelen] of int;
  100.     POP_ARRAY = array [1..reducelen] of byte;
  101.     TOKEN_ARRAY = array [0..rltokens] of byte;
  102.     TOSTATE_ARRAY = array [0..rltokens] of int;
  103.     SS_ARRAY = array [0..sstokens] of int;
  104.     PROD_ARRAY = array [1..prodtoks] of byte;
  105.     TOKX_ARRAY = array [1..all_toks] of int;
  106.     TOKCHAR_ARRAY = array [1..tokchars] of char;
  107.     INSYM_ARRAY = array [1..lookstate] of int;
  108.  
  109. {#<C -- put typed constants here, if they've been requested }
  110.   const
  111.     { Static parser data structures (parser tables). }
  112. {#IP}
  113. {#>}
  114.  
  115.   var
  116.     { Dynamic parser data structures }
  117.     STACK:  state_stack;  { the LR(1) state stack }
  118.     SEMSTACK:  array [0..stacksize] of semrecp;  { semantics stack }
  119.     STACKX:  int;  { index of top of stack }
  120.  
  121. {#<~C -- the following are redundant if typed constants are used }
  122.     { Static parser data structures (parser tables). }
  123.     STATEX:  state_array;    { stack top index }
  124.     MAP:  reduce_array;      { mapping from state to apply numbers }
  125.     POPNO:  pop_array;       { reduce pop size }
  126.     TOKNUM:  token_array;    { token list }
  127.     TOSTATE:  tostate_array;  { read, look states }
  128.     STK_STATE:  ss_array;
  129.     STK_TOSTATE: ss_array;
  130. {#<D -- these are for parser stack dumps. }
  131.     PRODX:  reduce_array;    { prod index into ... }
  132.     PRODS:  prod_array;      { token number, index into ... }
  133.     INSYM:  insym_array;
  134. {#> -- end if for debugging. }
  135. {#> -- end if for typed constants. }
  136.  
  137. {#<D -- debugging (these cannot be typed constants.) }
  138.     { These guys are for printing tokens in parser stack dumps. }
  139.     TOKX:  tokx_array;       { token index, index into ... }
  140.     TOKCHAR:  tokchar_array;  { token characters }
  141. {#> -- end if for debugging. }
  142.  
  143.     { Lexical and token data }
  144.     LINE:  string[linelen];  { source line }
  145.     LX:  int;                { index of next character in LINE }
  146.     ERRPOS:int;              { current token position in LINE }
  147.     PROMPT_LEN:int;          { number of prompt characters }
  148.     CH:  char;               { next character from input file }
  149.     TOKEN:  int;             { Next token in input list }
  150.     LSEMP:  semrecp;         { current semantics assoc. with token }
  151.     TOKENX:  int;            { index into TOKARY, LSEMPARY }
  152.     TOKARY:  array [0..1] of int;  { token queue }
  153.     LSEMPARY:  array [0..1] of semrecp;
  154.     ERRSYM:  symbol;        { special symbol reserved for errors }
  155.     { The next table can be omitted if real numbers are not used. }
  156.     PWR10_2:  array [0..8] of real;  { Binary powers of ten. }
  157.  
  158.     { Symbol table data }
  159.     SYMTAB: array [0..hlimit] of symtabp;
  160.     STRTAB: packed array [0..strtablen] of char;
  161.     STRTABX: int;
  162.  
  163.     SFILE, RFILE: text;      { source, report files }
  164.     SFILENAME, RFILENAME: string80;  { source, report file name }
  165.     TFILE: file of int;      { sometimes used for table inits }
  166.     
  167.     ERRORS: int;
  168.     DEBUG: int;              { >0 turns on some tracing }
  169.     
  170. { GENERAL UTILITIES }
  171.  
  172.   {*********************}
  173.   function RESP(MSG: string80):  char;
  174.     { print a message and return a single character response. }
  175.     var CH: char;
  176.   begin
  177.     write(msg);
  178.     read(kbd, ch);
  179.     writeln(ch);
  180.     resp := ch
  181.   end;
  182.  
  183.   {*********************}
  184.   function YESRESP (MSG: string80): boolean;
  185.     { query with a Y or N reply }
  186.     var CH: char;
  187.   begin
  188.     ch := resp(msg);
  189.     yesresp := (ch='y') or (ch='Y');
  190.   end;
  191.  
  192.   {******************}
  193.   procedure MORE(MSG: string80);
  194.     { print the string, and let the user type
  195.       any character to proceed. }
  196.     var FOO:  char;
  197.   begin
  198.     foo := resp(msg)
  199.   end;
  200.  
  201.   {******************}
  202.   procedure REPORT_ERR(MSG: string80);
  203.   begin
  204.     if errpos+prompt_len>1 then
  205.       write(rfile, ' ':errpos+prompt_len-1);
  206.     writeln(rfile, '^');  { mark error point }
  207.     writeln(rfile, 'ERROR: ', msg);
  208.     errors := errors+1;
  209.   end;
  210.  
  211.   {*******************}
  212.   procedure ABORT(MSG: string80);
  213.   begin
  214.     report_err(msg);
  215.     while true do more('FATAL -- PLEASE ABORT:')
  216.   end;
  217.  
  218.   {******************}
  219.   procedure ERROR(MSG: string80);
  220.   begin
  221.     report_err(msg);
  222.     if errors>maxerrors then abort('Error limit exceeded');
  223.     more('Type any character to continue:')
  224.   end;
  225.  
  226.   {*****************}
  227.   function UPSHIFT(CH: char): char;
  228.   begin
  229.     if (ch>='a') and (ch<='z') then
  230.       upshift := chr(ord(ch) - ord('a') + ord('A'))
  231.     else
  232.       upshift := ch
  233.   end;
  234.  
  235.   {$I skelsyms.pas}
  236.  
  237. {#<D -- debugging utilities. }
  238.   {=========== changed for calcskel ==============}
  239.   {$I calcdbug.pas}
  240.  
  241. {#> -- end debugging stuff. }
  242. { LEXICAL ANALYZER }
  243.  
  244.   {*******************}
  245.   procedure GETLINE;
  246.     { read the next source line, when nextch exhausts
  247.       the current one. }
  248.  
  249.     {.............}
  250.     procedure GENEOF;
  251.     begin
  252.       line := chr(eofch);
  253.       lx := 1
  254.     end;
  255.  
  256.     {............}
  257.     procedure GRABLINE;
  258.       var TX: int;
  259.     begin
  260.       readln(sfile, line);
  261.       {======================== not needed in calcskel ===============}
  262.       { writeln(rfile, line); }
  263.       lx := 1
  264.     end;
  265.  
  266.   begin { getline }
  267.     if sfilename='' then begin
  268.       { prompt if from the console file }
  269.       write('> ');
  270.       grabline;
  271.       if line = 'EOF' then geneof
  272.       end
  273.     else if eof(sfile) then
  274.       geneof
  275.     else
  276.       grabline;
  277. {#<E -- the line ending gets treated differently here. }
  278.     { The appended blank allows a reduction containing <EOL> to take
  279.       place before reading another line.  This behavior is essential
  280.       for interactive systems, and makes no difference in batch. }
  281.     line := line+chr(eolch)+' '
  282. {#: -- case where <EOL> is not significant. }
  283.     { The appended eol character ensures that tokens are broken over
  284.       line endings; they would otherwise be invisible to the scanner.
  285.       eolch allows the string scanner to distinguish ends of lines. }
  286.     line := line+chr(eolch)
  287. {#> -- end of eol business. }
  288.   end;
  289.  
  290.   {*******************}
  291.   procedure NEXTCH;
  292.     { gets next character from line }
  293.   begin
  294.     if lx > length(line) then
  295.       getline;
  296.     ch := line[lx];
  297.     { don't move past an eof mark }
  298.     if ch <> chr(eofch) then lx := lx+1
  299.   end;
  300.  
  301. {#<~E -- Pick a blank skipper, depending on appearance of <eol> }
  302.   {********************}
  303.   procedure SKIPBLANKS;  { when <eol> has NOT appeared }
  304.     { This considers left brace as an open comment and right brace
  305.       as a close-comment; comments may run over multiple lines. }
  306.   begin
  307.     repeat
  308.       while ch = ' ' do nextch;
  309.       if ch='{' then begin  { open a comment }
  310.         while (ch <> '}') and (ch <> chr(eofch)) do nextch;
  311.         if ch=chr(eofch) then
  312.           error('unclosed comment')
  313.         else
  314.           nextch
  315.       end
  316.     until ch <> ' '
  317.   end;
  318.  
  319. {#: -- the second choice}
  320.   {********************}
  321.   procedure SKIPBLANKS;  { when <eol> HAS appeared }
  322.     { This version of skipblanks treats everything from OC to the
  323.       end of a line as a comment. }
  324.     const OC= ';';
  325.   begin
  326.     while ch=' ' do nextch;
  327.     if ch=oc then while ch<>chr(eolch) do nextch
  328.   end;
  329.  
  330. {#> -- end of the selection}
  331.   {********************}
  332.   procedure PUTSTRCH(CH: char);
  333.   begin
  334.     if strtabx>strtablen then
  335.       abort('String table overflow ... please abort');
  336.     strtab[strtabx] := ch;
  337.     strtabx := strtabx+1;
  338.   end;
  339.  
  340.   {******************}
  341.   procedure PUTSTR(STR: string80);
  342.     var SX: int;
  343.   begin
  344.     for sx := 1 to length(str) do putstrch(str[sx]);
  345.     putstrch(chr(eos));
  346.   end;
  347.   
  348.   {****************}
  349.   procedure GET_SYMBOL;
  350.     var SX: int;
  351.         SYM: symbol;
  352.         STP: symtabp;
  353.   begin
  354.     fillchar(sym, maxtoklen, ' ');
  355.     sx := 1;
  356.     { keep snarfing alphanumeric characters.  up to the first
  357.       maxtoklen of them will be put in the symbol spelling. }
  358.     while ((ch>='a') and (ch<='z')) or
  359.           ((ch>='A') and (ch<='Z')) or
  360.           ((ch>='0') and (ch<='9')) or
  361.           (ch='_') do begin
  362.       if sx <= maxtoklen then
  363.         sym[sx] := upshift(ch);
  364.       sx := sx+1;
  365.       nextch;
  366.     end;
  367.     stp := makesym(sym, user, 0);  { the default level is 0 }
  368.     with lsemp^ do begin
  369.       if stp^.symt=reserved then begin
  370.         { a reserved keyword }
  371.         semt := other;
  372.         token := stp^.tokval;
  373.       end
  374.       else begin
  375.         semt := ident;
  376.         symp := stp;
  377.         token := ident_tokx;
  378.       end
  379.     end
  380.   end;
  381.  
  382.   {$I skelnum.pas}   { Number scanning }
  383.  
  384.   {*****************}
  385.   procedure GET_STRING;
  386.     { Scans a string, putting it into the string table, and setting
  387.       up the semantic record for it correctly.  Removing the "and
  388.       (ch <> chr(eolch))" clause in the WHILE loop below will allow
  389.       strings to run over the end of a line by storing embedded
  390.       eolch's.  However, this could have unpleasant consequences for
  391.       languages with <eol> in the grammar.  See the comments at the
  392.       end of getline. }
  393.     var END_OF_STRING:  boolean;
  394.   begin
  395.     nextch;  { get past the first quote mark }
  396.     lsemp^.semt := strng;
  397.     lsemp^.stx := strtabx;
  398.     repeat
  399.       while (ch <> chr(eofch)) and (ch <> chr(eolch))
  400.             and (ch <> string_quote) do begin
  401.         putstrch(ch);
  402.         nextch
  403.       end;
  404.       end_of_string := true;
  405.       { peek ahead a bit to see if there's a doubled quote }
  406.       if ch = string_quote then begin
  407.         nextch;
  408.         if ch = string_quote then begin
  409.           end_of_string := false;
  410.           putstrch(ch);
  411.           nextch
  412.         end
  413.       end
  414.       else if (ch = chr(eofch)) or (ch = chr(eolch)) then begin
  415.         error('unterminated string')
  416.       end
  417.     until end_of_string;
  418.     putstrch(chr(eos));
  419.     token := str_tokx;
  420.   end;
  421.  
  422.   {********************}
  423.   procedure GET_TOKEN;
  424.     { Pascal-style lexical analyzer -- sets TOKEN to token number }
  425.   begin
  426.     lsemp^.semt := other;  { default case }
  427.     skipblanks;
  428.     errpos:=lx-1;
  429.     case ch of
  430.       'a'..'z', 'A'..'Z': get_symbol;
  431.       '0'..'9':           get_number;
  432.       string_quote:       get_string;
  433. {#<D -- if debugging, invoke idebug on a bang (or other char). }
  434.       '!':  begin
  435.               idebug;
  436.               nextch;
  437.               get_token
  438.             end;
  439. {#>}
  440. {#G   special symbol cases go here }
  441.       ELSE  begin
  442.               if ch=chr(eofch) then
  443.                 token := stop_tokx
  444.               else if ch=chr(eolch) then begin
  445.                 nextch;
  446. {#<E            end-of-line token dealt with here }
  447.                 token := eol_tokx  { accept an end-of-line token }
  448. {#:}
  449.                 get_token  { go find another (significant) character }
  450. {#>}
  451.               end
  452.               else begin
  453.                 error('illegal character');
  454.                 nextch;
  455.                 get_token  { try again }
  456.               end
  457.             end { case alternatives }
  458.     end { case }
  459.   end { get_token };
  460.  
  461.   {*******************}
  462.   procedure NEXT_TOKEN;
  463.   begin
  464.     if tokenx>1 then begin
  465.       tokenx := 1;
  466.       get_token;  { goes into token, lsemp }
  467.       tokary[1] := token;
  468.       lsempary[1] := lsemp;
  469.     end
  470.     else begin
  471.       { is in tokary }
  472.       token := tokary[tokenx];
  473.       lsemp := lsempary[tokenx];
  474.     end
  475.   end;
  476.  
  477.   {*****************}
  478.   procedure TOKENREAD;
  479.   begin
  480.     tokenx := tokenx+1;
  481.   end;
  482.  
  483.   { LR(1) PARSER procedures }
  484.  
  485.   {======================= calculator semantics ======================}
  486.   {$I calcutil.pas}        { utility routines }
  487.   {$I calcsem.pas}         { the apply procedure }
  488.  
  489.   {****************}
  490.   function ERROR_RECOVERY(var MSTACK: state_stack;
  491.                           var MSTACKX: int; MCSTATE: int): int;
  492.     label 99, 100;
  493.     var STACK: state_stack;  { local copy of stack }
  494.         STACKX,              { local stack pointer }
  495.         CSTATE,              { local state }
  496.         JSTX,                { temporary stack limit }
  497.         RX, TL: int;         { index into TOKNUM table }
  498.         
  499.     {...............}
  500.     procedure COPY_STACK;
  501.       var STX: int;
  502.     begin
  503.       if (jstx<0) or (jstx>mstackx) then abort('ERROR RECOVERY BUG');
  504.       for stx := 0 to jstx do
  505.         stack[stx] := mstack[stx];
  506.       stackx := jstx;
  507.       if jstx=mstackx then
  508.         cstate := mcstate
  509.       else
  510.         cstate := mstack[jstx+1];
  511.     end;
  512.     
  513.     {...............}
  514.     procedure PUSHREAD(CSTATE: int);
  515.       { adjusts the state stack }
  516.     begin
  517.       stackx := stackx+1;
  518.       if stackx>stacksize then
  519.         abort('stack overflow');
  520.       stack[stackx] := cstate;
  521.     end;
  522.     
  523.     {...............}
  524.     function TRIAL_PARSE: boolean;
  525.       { parses from current read state through the inserted and the
  526.         error token; if successful, returns TRUE. }
  527.       label 99;
  528.       var RX: int;
  529.     begin
  530.       trial_parse := true;  { until proven otherwise }
  531.       while cstate<>0 do begin
  532.         if cstate < readstate then begin
  533.           { a reduce state }
  534. {#<D      dump if debugging enabled. }
  535.           if debug > 3 then stk_dump('E*Reduce', stack,
  536.                                      stackx, cstate);
  537. {#>       end conditional. }
  538.           if popno[cstate]=0 then begin
  539.             { empty production }
  540.             pushread(stk_state[statex[cstate]]);
  541.             cstate := stk_tostate[statex[cstate]];
  542.           end
  543.           else begin
  544.             { non-empty production }
  545.             stackx := stackx - popno[cstate] + 1;
  546.             rx := statex[cstate];   { compute the GOTO state }
  547.             cstate := stack[stackx];
  548.             while (stk_state[rx]<>cstate) and
  549.                   (stk_state[rx]<>0) do rx := rx+1;
  550.             cstate := stk_tostate[rx];
  551.           end
  552.         end
  553.         else if cstate < lookstate then begin
  554.           { a read state }
  555.           next_token;  { need a token now }
  556. {#<D      dump if debugging enabled. }
  557.           if debug > 3 then stk_dump('E*Read', stack, stackx, cstate);
  558. {#>       end conditional. }
  559.           rx := statex[cstate];
  560.           while (toknum[rx]<>0) and
  561.                 (toknum[rx]<>token) do rx := rx+1;
  562.           if toknum[rx]=0 then begin
  563.             { failure }
  564.             trial_parse := false;
  565.             goto 99;
  566.           end
  567.           else begin
  568.             { did read something }
  569.             pushread(cstate);
  570.             cstate := tostate[rx];
  571.             tokenread;  { scan the token }
  572.             if tokenx>1 then goto 99 { successful }
  573.           end
  574.         end
  575.         else begin
  576.           { lookahead state }
  577.           next_token;  { need a token now }
  578. {#<D      dump if debugging enabled. }
  579.           if debug > 3 then stk_dump('E*Look', stack, stackx, cstate);
  580. {#>       end conditional. }
  581.           rx := statex[cstate];
  582.           while (toknum[rx]<>0) and
  583.                 (toknum[rx]<>token) do rx := rx+1;
  584.           cstate := tostate[rx];
  585.         end
  586.       end;
  587.     99:
  588.     end;
  589.       
  590.     {.................}
  591.     procedure INCR_ERRSYM;
  592.       { Note that this procedure assumes ASCII. }
  593.     begin
  594.       if errsym[6]='Z' then begin
  595.         errsym[5] := succ(errsym[5]);
  596.         errsym[6] := 'A';
  597.       end
  598.       else
  599.         errsym[6] := succ(errsym[6]);
  600.     end;
  601.  
  602.     {.................}
  603.     procedure MAKE_DEFAULT(TOKX: int; SEMP: semrecp);
  604.       { creates a default token data structure }
  605.       var SYM: symbol;
  606.     begin
  607.       with semp^ do begin
  608.         case tokx of
  609.           int_tokx:
  610.             begin
  611.               semt := fixed;
  612.               numval := 1;
  613.             end;
  614.           real_tokx:
  615.             begin
  616.               semt := float;
  617.               rval := 1.0;
  618.             end;
  619.           ident_tokx:
  620.             begin
  621.               semt := ident;
  622.               symp := makesym(errsym, symerr, 0);
  623.               incr_errsym;
  624.             end;
  625.           str_tokx:
  626.             begin
  627.               semt := strng;
  628.               stx := 0;  { default string at origin }
  629.             end;
  630.           ELSE
  631.             semt := other;
  632.         end { case tokx }
  633.       end
  634.     end;
  635.  
  636.   begin  { ERROR_RECOVERY }
  637.     if debug > 3 then writeln(rfile, 'Going into ERROR RECOVERY');
  638.     while true do begin
  639.       jstx := mstackx;
  640.       while jstx>=0 do begin
  641.         copy_stack;
  642.         rx := statex[cstate];
  643.         while toknum[rx]<>0 do begin
  644.           { scan through legal next tokens }
  645.           if debug > 3 then writeln(rfile, '...starting trial parse');
  646.           tokary[0] := toknum[rx];  { the insertion }
  647.           tokenx := 0;
  648.           if trial_parse then goto 99;  { it clicked! }
  649.           rx := rx+1;
  650.           if toknum[rx]<>0 then
  651.             copy_stack;
  652.         end;
  653.         jstx := jstx-1;  { reduce stack }
  654.       end;
  655.       if token=stop_tokx then begin
  656.         { empty stack, no more tokens }
  657.         cstate := 0;  { halt state }
  658.         tokenx := 2;
  659.         jstx := 0;  { bottom of stack }
  660.         goto 100;
  661.       end;
  662. {#<D}
  663.       if debug > 3 then begin
  664.         write(rfile, '...dropping token ');
  665.         tl := wrtok(tokary[1]);
  666.         writeln(rfile);
  667.       end;
  668. {#>}
  669.       tokenx := 2;
  670.       next_token;
  671. {#<D}
  672.       if debug > 3 then begin
  673.         write(rfile, 'New token ');
  674.         tl := wrtok(token);
  675.         writeln(rfile);
  676.       end
  677. {#>}
  678.     end;
  679.   99:  { found a solution }
  680.     copy_stack;
  681. {#<D}
  682.     if debug > 3 then begin
  683.       write(rfile, 'insertion of ');
  684.       tl := wrtok(tokary[0]);
  685.       writeln(rfile, ' succeeded');
  686.     end;
  687. {#>}
  688.     make_default(tokary[0], lsempary[0]);
  689.     tokenx := 0;  { forces a `real' rescan of the insertion }
  690.     if jstx<mstackx then
  691.       cstate := stack[jstx+1]
  692.     else
  693.       cstate := mcstate;  { cstate returned }
  694.   100:
  695.     error_recovery := cstate;
  696.     mstackx := jstx;
  697.     if debug > 3 then writeln(rfile, 'Ending error recovery');
  698.   end;
  699.  
  700.   {****************}
  701.   procedure PARSER;
  702.     { Carries out a complete parse, until
  703.       the halt state is seen -- same as empty stack}
  704.     var CSTATE, RX: int;
  705.         TSEMP: semrecp;
  706.  
  707.     {...............}
  708.     procedure PUSHREAD(CSTATE: int; SEMP: semrecp);
  709.       { do the push part of a readstate. }
  710.     begin
  711.       stackx := stackx+1;
  712.       if stackx>stacksize then
  713.         abort('stack overflow');
  714.       semstack[stackx]^ := semp^;
  715.       stack[stackx] := cstate;
  716.     end;
  717.  
  718.   begin
  719.     cstate := start_state;
  720.     stackx := -1;
  721.     new(tsemp);
  722.     tsemp^.semt := other;
  723.     pushread(stk_state_1, tsemp);
  724.     while cstate<>0 do begin
  725.       if cstate < readstate then begin
  726.         { a reduce state }
  727. {#<D    dump if debugging enabled. }
  728.         if debug > 0 then stk_dump('Reduce', stack, stackx, cstate);
  729. {#>     end conditional. }
  730.         if map[cstate] <> 0 then
  731.           { the semantics action }
  732.           apply(map[cstate], popno[cstate], tsemp);
  733.         if popno[cstate]=0 then begin
  734.           { empty production }
  735.           pushread(stk_state[statex[cstate]], tsemp);
  736.           cstate := stk_tostate[statex[cstate]];
  737.         end
  738.         else begin
  739.           { non-empty production:
  740.             semantics is preserved on a unit production A --> w,
  741.             where |w| = 1, unless something is in TSEMP.  Note that
  742.             if w is nonterminal, the production may be bypassed. }
  743.           stackx := stackx - popno[cstate] + 1;
  744.           if popno[cstate]=1 then begin
  745.             if tsemp^.semt<>other then
  746.               semstack[stackx]^ := tsemp^;
  747.           end
  748.           else
  749.             semstack[stackx]^ := tsemp^;
  750.           { compute the GOTO state }
  751.           rx := statex[cstate];
  752.           cstate := stack[stackx];
  753.           while (stk_state[rx]<>cstate) and (stk_state[rx]<>0) do
  754.             rx := rx+1;
  755.           cstate := stk_tostate[rx];
  756.         end;
  757.         tsemp^.semt := other;
  758.       end
  759.       else if cstate < lookstate then begin
  760.         { a read state }
  761.         next_token;  { need next token now }
  762. {#<D    dump if debugging enabled. }
  763.         if debug > 2 then stk_dump('Read', stack, stackx, cstate);
  764. {#>     end conditional. }
  765.         rx := statex[cstate];
  766.         while (toknum[rx]<>0) and (toknum[rx]<>token) do
  767.           rx := rx+1;
  768.         if toknum[rx]=0 then begin
  769.           error('syntax error');
  770.           cstate := error_recovery(stack, stackx, cstate);
  771.         end
  772.         else begin
  773.           pushread(cstate, lsemp);
  774.           cstate := tostate[rx];
  775.           tokenread;  { token has been scanned }
  776.         end
  777.       end
  778.       else begin
  779.         { lookahead state }
  780.         next_token;  { need another token now }
  781. {#<D    dump if debugging enabled. }
  782.         if debug > 2 then stk_dump('Look', stack, stackx, cstate);
  783. {#>     end conditional. }
  784.         rx := statex[cstate];
  785.         while (toknum[rx]<>0) and (toknum[rx]<>token) do
  786.           rx := rx+1;
  787.         cstate := tostate[rx];
  788.       end
  789.     end;
  790.     end_sem;
  791.   end;
  792.  
  793.   { PARSE INITIALIZATION }
  794.  
  795.   {*****************}
  796.   procedure INITTABLES;
  797.     var SX: int;
  798.  
  799. {#<F import the table file reading function if needed. }
  800.        {$I skelrtbl.pas}
  801. {#<D   debugging wanted, too?
  802.          {$I skeldtbl.pas}
  803. {#>    end debugging }
  804. {#:  else include the auxiliary functions needed by inline inits. }
  805.     {................}
  806.     procedure PUTSYM(STR: string80; TV: int);
  807.       var SYMP: symtabp;
  808.           TSYM: symbol;
  809.           I: int;
  810.     begin
  811.       fillchar(tsym, maxtoklen, ' ');
  812.       for i:=1 to length(str) do
  813.         tsym[i]:=str[i];
  814.       symp:=makesym(tsym, reserved, -1);
  815.       symp^.tokval:=tv;
  816.     end;
  817.  
  818. {#<D   also need to init debugging tables? }
  819.     {................}
  820.     procedure PUTTOK(PRINTVAL: string80;  TOKNUM, START: int);
  821.       { this procedure is used to initialize the token tables.
  822.         toknum is the number of the token to be initialized, and
  823.         start is where it should start in the tokchar array. }
  824.       var OFFSET:  int;
  825.     begin
  826.       tokx[toknum] := start;
  827.       for offset := 0 to length(printval)-1 do
  828.         tokchar[start+offset] := printval[offset+1];
  829.       tokchar[start+length(printval)] := chr(0)
  830.     end;
  831. {#>    end puttok insertion. }
  832. {#>  end table file conditional. }
  833.  
  834.     {................}
  835.     procedure INIT_PARSER_TABLES;
  836.       { initialize the parser tables }
  837.     begin
  838. {#<F  read from a table file? }
  839. {#T     insert table file name in next line. }
  840.         assign(tfile, '#');
  841.         reset(tfile);
  842.         read_header;
  843.         read_table_file;
  844. {#<D    take debugging info from the table file? }
  845.           read_debugging_tables;
  846. {#>     end if. }
  847.         close(tfile)
  848. {#:   not a table file; do the necessary inline inits }
  849. {#IS    inline symbol table inits. }
  850. {#<A    assignment style inits? }
  851. {#IP      do the parser tables inline. }
  852. {#>     end assignment inits. }
  853. {#<D    debugging? }
  854. {#IT      do the token tables inline. }
  855. {#>     end debugging }
  856. {#>   end of initialization style selection. }
  857.     end { init_parser_tables };
  858.  
  859.   begin { inittables }
  860.     pwr10_2[0] := 1E1;  {10^(2^0)}
  861.     pwr10_2[1] := 1E2;  {10^(2^1)}
  862.     pwr10_2[2] := 1E4;
  863.     pwr10_2[3] := 1E8;
  864.     pwr10_2[4] := 1E16;
  865.     pwr10_2[5] := 1E32;
  866.     errsym := 'ERR#AA         ';
  867.     new(lsempary[0]);
  868.     lsempary[0]^.semt := other;
  869.     new(lsempary[1]);
  870.     lsempary[1]^.semt := other;
  871.     lsemp := lsempary[1];
  872.     strtabx := 0;
  873.     putstr('ERROR');  { default error string }
  874.     tokenx := 2;  { no token queue }
  875.     for sx := 0 to hlimit do
  876.       symtab[sx] := nil;  { initialize symbol table }
  877.     for sx := 0 to stacksize do begin
  878.       new(semstack[sx]);
  879.       semstack[sx]^.semt := other;
  880.     end;
  881.     init_parser_tables;
  882.     init_sem;
  883.     line := '';  { fake a new line }
  884.     lx := 1;
  885.     errpos:=1;
  886.     nextch;  { fetch the first character, forcing a line read }
  887.   end;
  888.  
  889.   {===================== start calcskel changes =====================}
  890.   {*****************}
  891.   procedure OPENFILES;
  892.     { opens 'source' and 'listing' files (actually, the console in
  893.       both cases). }
  894.   begin
  895.     sfilename := '';  { this means to read from the console as well }
  896.     rfilename := '';  { as write to it (for other code's info). }
  897.     prompt_len:=2;    { characters in prompt }
  898.     assign(sfile, 'con:');
  899.     reset(sfile);
  900.     assign(rfile, 'con:');
  901.     rewrite(rfile)
  902.   end;
  903.   {===================== end of calcskel changes =====================}
  904.  
  905. begin
  906.   writeln('Interactive Calculator (vers. 18-Oct-84) -- "QUIT" to exit.');
  907.   writeln('COPYRIGHT (C) 1984, QCAD Systems, Inc.  All rights reserved');
  908.   writeln;
  909.   errors := 0;
  910.   debug := 0;
  911.   openfiles;
  912.   inittables;
  913.   parser;  { does it all }
  914.   close(sfile);
  915.   close(rfile)
  916. end.
  917.  
  918.