home *** CD-ROM | disk | FTP | other *** search
- { Copyright (C) 1984 by QCAD Systems, Inc., All Rights Reserved. }
-
- {#P -- program line goes here }
- program #(input, output);
-
- { Calcskel:
-
- This is the skeleton file for a four-function calculator run
- by an LALR(1) table-driven parser. It is based on LR1SKEL, but
- doesn't have all the file opening options, and doesn't use
- a report file. }
-
- const
- STACKSIZE = 60; { maximum size of LR(1) parser stack }
- EOS = 0; { marks end of line in LINE }
- EOFCH = 26; { reader end-of-file character }
- EOLCH = 12; { end of line character }
- LINELEN = 80; { maximum length of a line }
- STRTABLEN = 500; { maximum number of chars in string table }
- STRING_QUOTE = ''''; { character delimiting quoted strings }
- MAXERRORS = 20; { maximum errors before aborting }
- HASHSIZE = 67; { hash table size -- prime number! }
- HLIMIT = 66; { limit in hash table (hashsize minus one) }
- MAXTOKLEN = 15; { length of a token or symbol }
-
- {#C -- constants defined by the parser generator go here }
- IDENT_TOKLEN = #C; { maximum user identifier length }
- MAXRPLEN = #D; { length of longest production right part }
- TERM_TOKS = #E; { number of terminal tokens }
- NTERM_TOKS = #F; { number of nonterminal tokens }
- ALL_TOKS = #G; { term_toks + nterm_toks }
- IDENT_TOKX = #H; { token number of <identifier> }
- INT_TOKX = #I; { token number of <integer> }
- REAL_TOKX = #J; { token number of <real> }
- STR_TOKX = #K; { token number of <string> }
- STOP_TOKX = #L; { token number of stopsign (end-of-file) }
- GOAL_TOKX = #M; { token number of goal }
- EOL_TOKX = #N; { token number of end-of-line }
- READSTATE = #O; { first READ state }
- LOOKSTATE = #P; { first LOOK state }
- MAXSTATE = #Q; { largest state number }
- REDUCELEN = #R; { number of productions }
- RLTOKENS = #S;
- SSTOKENS = #T;
- PRODTOKS = #U;
- TOKCHARS = #V;
- START_STATE = #W; { initial state }
- STK_STATE_1 = #X; { state initially pushed on stack }
- {#> -- end of constants }
- {#F -- form for FLAG constants }
- #N = #V;
-
- type
- INT = -32767..32767;
- STRING8 = string[8];
- STRING80 = string[80];
- TOKRANGE = 1..term_toks;
- {================== added operator for calcskel ==================}
- OPERATOR = int; { same type as the flags }
-
- SYMBOL = packed array [1..maxtoklen] of char;
- {================ added real_variable for calcskel ===============}
- SYMTYPE = (RESERVED, SYMERR, USER, REAL_VARIABLE);
- SYMTABP = ^symtabtype;
- SYMTABTYPE = record
- { structure for <identifier>s and keywords }
- NEXT: symtabp;
- LEVEL: int;
- SYM: symbol;
- case SYMT: symtype of
- reserved: (TOKVAL: tokrange);
- {=========== added for calcskel ==============}
- real_variable: (RVAL: real);
- end;
- SYMTABNAMES = array [symtype] of string[8];
- const SYMTYPENAME: symtabnames =
- ('reserved', 'symerr ', 'user ', 'real var');
-
- type
- SEMTYPE = (OTHER, IDENT, FIXED, FLOAT, STRNG);
- SEMRECP = ^semrec;
- SEMREC = record { semantic stack structure }
- case SEMT: semtype of
- ident: (SYMP: symtabp);
- fixed: (NUMVAL: integer); { fixed point }
- float: (RVAL: real); { floating point }
- strng: (STX: int); { position in strtab }
- { Add more options as needed }
- end;
- SEMTABNAMES = array [semtype] of string[5];
- const SEMTYPENAME: semtabnames =
- ('other', 'ident', 'fixed', 'float', 'strng');
-
- type
- STATE_STACK = array [0..stacksize] of int;
- { Types for parser tables. NB: These type names are used by
- the typed constant generation. }
- STATE_ARRAY = array [1..maxstate] of int;
- REDUCE_ARRAY = array [1..reducelen] of int;
- POP_ARRAY = array [1..reducelen] of byte;
- TOKEN_ARRAY = array [0..rltokens] of byte;
- TOSTATE_ARRAY = array [0..rltokens] of int;
- SS_ARRAY = array [0..sstokens] of int;
- PROD_ARRAY = array [1..prodtoks] of byte;
- TOKX_ARRAY = array [1..all_toks] of int;
- TOKCHAR_ARRAY = array [1..tokchars] of char;
- INSYM_ARRAY = array [1..lookstate] of int;
-
- {#<C -- put typed constants here, if they've been requested }
- const
- { Static parser data structures (parser tables). }
- {#IP}
- {#>}
-
- var
- { Dynamic parser data structures }
- STACK: state_stack; { the LR(1) state stack }
- SEMSTACK: array [0..stacksize] of semrecp; { semantics stack }
- STACKX: int; { index of top of stack }
-
- {#<~C -- the following are redundant if typed constants are used }
- { Static parser data structures (parser tables). }
- STATEX: state_array; { stack top index }
- MAP: reduce_array; { mapping from state to apply numbers }
- POPNO: pop_array; { reduce pop size }
- TOKNUM: token_array; { token list }
- TOSTATE: tostate_array; { read, look states }
- STK_STATE: ss_array;
- STK_TOSTATE: ss_array;
- {#<D -- these are for parser stack dumps. }
- PRODX: reduce_array; { prod index into ... }
- PRODS: prod_array; { token number, index into ... }
- INSYM: insym_array;
- {#> -- end if for debugging. }
- {#> -- end if for typed constants. }
-
- {#<D -- debugging (these cannot be typed constants.) }
- { These guys are for printing tokens in parser stack dumps. }
- TOKX: tokx_array; { token index, index into ... }
- TOKCHAR: tokchar_array; { token characters }
- {#> -- end if for debugging. }
-
- { Lexical and token data }
- LINE: string[linelen]; { source line }
- LX: int; { index of next character in LINE }
- ERRPOS:int; { current token position in LINE }
- PROMPT_LEN:int; { number of prompt characters }
- CH: char; { next character from input file }
- TOKEN: int; { Next token in input list }
- LSEMP: semrecp; { current semantics assoc. with token }
- TOKENX: int; { index into TOKARY, LSEMPARY }
- TOKARY: array [0..1] of int; { token queue }
- LSEMPARY: array [0..1] of semrecp;
- ERRSYM: symbol; { special symbol reserved for errors }
- { The next table can be omitted if real numbers are not used. }
- PWR10_2: array [0..8] of real; { Binary powers of ten. }
-
- { Symbol table data }
- SYMTAB: array [0..hlimit] of symtabp;
- STRTAB: packed array [0..strtablen] of char;
- STRTABX: int;
-
- SFILE, RFILE: text; { source, report files }
- SFILENAME, RFILENAME: string80; { source, report file name }
- TFILE: file of int; { sometimes used for table inits }
-
- ERRORS: int;
- DEBUG: int; { >0 turns on some tracing }
-
- { GENERAL UTILITIES }
-
- {*********************}
- function RESP(MSG: string80): char;
- { print a message and return a single character response. }
- var CH: char;
- begin
- write(msg);
- read(kbd, ch);
- writeln(ch);
- resp := ch
- end;
-
- {*********************}
- function YESRESP (MSG: string80): boolean;
- { query with a Y or N reply }
- var CH: char;
- begin
- ch := resp(msg);
- yesresp := (ch='y') or (ch='Y');
- end;
-
- {******************}
- procedure MORE(MSG: string80);
- { print the string, and let the user type
- any character to proceed. }
- var FOO: char;
- begin
- foo := resp(msg)
- end;
-
- {******************}
- procedure REPORT_ERR(MSG: string80);
- begin
- if errpos+prompt_len>1 then
- write(rfile, ' ':errpos+prompt_len-1);
- writeln(rfile, '^'); { mark error point }
- writeln(rfile, 'ERROR: ', msg);
- errors := errors+1;
- end;
-
- {*******************}
- procedure ABORT(MSG: string80);
- begin
- report_err(msg);
- while true do more('FATAL -- PLEASE ABORT:')
- end;
-
- {******************}
- procedure ERROR(MSG: string80);
- begin
- report_err(msg);
- if errors>maxerrors then abort('Error limit exceeded');
- more('Type any character to continue:')
- end;
-
- {*****************}
- function UPSHIFT(CH: char): char;
- begin
- if (ch>='a') and (ch<='z') then
- upshift := chr(ord(ch) - ord('a') + ord('A'))
- else
- upshift := ch
- end;
-
- {$I skelsyms.pas}
-
- {#<D -- debugging utilities. }
- {=========== changed for calcskel ==============}
- {$I calcdbug.pas}
-
- {#> -- end debugging stuff. }
- { LEXICAL ANALYZER }
-
- {*******************}
- procedure GETLINE;
- { read the next source line, when nextch exhausts
- the current one. }
-
- {.............}
- procedure GENEOF;
- begin
- line := chr(eofch);
- lx := 1
- end;
-
- {............}
- procedure GRABLINE;
- var TX: int;
- begin
- readln(sfile, line);
- {======================== not needed in calcskel ===============}
- { writeln(rfile, line); }
- lx := 1
- end;
-
- begin { getline }
- if sfilename='' then begin
- { prompt if from the console file }
- write('> ');
- grabline;
- if line = 'EOF' then geneof
- end
- else if eof(sfile) then
- geneof
- else
- grabline;
- {#<E -- the line ending gets treated differently here. }
- { The appended blank allows a reduction containing <EOL> to take
- place before reading another line. This behavior is essential
- for interactive systems, and makes no difference in batch. }
- line := line+chr(eolch)+' '
- {#: -- case where <EOL> is not significant. }
- { The appended eol character ensures that tokens are broken over
- line endings; they would otherwise be invisible to the scanner.
- eolch allows the string scanner to distinguish ends of lines. }
- line := line+chr(eolch)
- {#> -- end of eol business. }
- end;
-
- {*******************}
- procedure NEXTCH;
- { gets next character from line }
- begin
- if lx > length(line) then
- getline;
- ch := line[lx];
- { don't move past an eof mark }
- if ch <> chr(eofch) then lx := lx+1
- end;
-
- {#<~E -- Pick a blank skipper, depending on appearance of <eol> }
- {********************}
- procedure SKIPBLANKS; { when <eol> has NOT appeared }
- { This considers left brace as an open comment and right brace
- as a close-comment; comments may run over multiple lines. }
- begin
- repeat
- while ch = ' ' do nextch;
- if ch='{' then begin { open a comment }
- while (ch <> '}') and (ch <> chr(eofch)) do nextch;
- if ch=chr(eofch) then
- error('unclosed comment')
- else
- nextch
- end
- until ch <> ' '
- end;
-
- {#: -- the second choice}
- {********************}
- procedure SKIPBLANKS; { when <eol> HAS appeared }
- { This version of skipblanks treats everything from OC to the
- end of a line as a comment. }
- const OC= ';';
- begin
- while ch=' ' do nextch;
- if ch=oc then while ch<>chr(eolch) do nextch
- end;
-
- {#> -- end of the selection}
- {********************}
- procedure PUTSTRCH(CH: char);
- begin
- if strtabx>strtablen then
- abort('String table overflow ... please abort');
- strtab[strtabx] := ch;
- strtabx := strtabx+1;
- end;
-
- {******************}
- procedure PUTSTR(STR: string80);
- var SX: int;
- begin
- for sx := 1 to length(str) do putstrch(str[sx]);
- putstrch(chr(eos));
- end;
-
- {****************}
- procedure GET_SYMBOL;
- var SX: int;
- SYM: symbol;
- STP: symtabp;
- begin
- fillchar(sym, maxtoklen, ' ');
- sx := 1;
- { keep snarfing alphanumeric characters. up to the first
- maxtoklen of them will be put in the symbol spelling. }
- while ((ch>='a') and (ch<='z')) or
- ((ch>='A') and (ch<='Z')) or
- ((ch>='0') and (ch<='9')) or
- (ch='_') do begin
- if sx <= maxtoklen then
- sym[sx] := upshift(ch);
- sx := sx+1;
- nextch;
- end;
- stp := makesym(sym, user, 0); { the default level is 0 }
- with lsemp^ do begin
- if stp^.symt=reserved then begin
- { a reserved keyword }
- semt := other;
- token := stp^.tokval;
- end
- else begin
- semt := ident;
- symp := stp;
- token := ident_tokx;
- end
- end
- end;
-
- {$I skelnum.pas} { Number scanning }
-
- {*****************}
- procedure GET_STRING;
- { Scans a string, putting it into the string table, and setting
- up the semantic record for it correctly. Removing the "and
- (ch <> chr(eolch))" clause in the WHILE loop below will allow
- strings to run over the end of a line by storing embedded
- eolch's. However, this could have unpleasant consequences for
- languages with <eol> in the grammar. See the comments at the
- end of getline. }
- var END_OF_STRING: boolean;
- begin
- nextch; { get past the first quote mark }
- lsemp^.semt := strng;
- lsemp^.stx := strtabx;
- repeat
- while (ch <> chr(eofch)) and (ch <> chr(eolch))
- and (ch <> string_quote) do begin
- putstrch(ch);
- nextch
- end;
- end_of_string := true;
- { peek ahead a bit to see if there's a doubled quote }
- if ch = string_quote then begin
- nextch;
- if ch = string_quote then begin
- end_of_string := false;
- putstrch(ch);
- nextch
- end
- end
- else if (ch = chr(eofch)) or (ch = chr(eolch)) then begin
- error('unterminated string')
- end
- until end_of_string;
- putstrch(chr(eos));
- token := str_tokx;
- end;
-
- {********************}
- procedure GET_TOKEN;
- { Pascal-style lexical analyzer -- sets TOKEN to token number }
- begin
- lsemp^.semt := other; { default case }
- skipblanks;
- errpos:=lx-1;
- case ch of
- 'a'..'z', 'A'..'Z': get_symbol;
- '0'..'9': get_number;
- string_quote: get_string;
- {#<D -- if debugging, invoke idebug on a bang (or other char). }
- '!': begin
- idebug;
- nextch;
- get_token
- end;
- {#>}
- {#G special symbol cases go here }
- ELSE begin
- if ch=chr(eofch) then
- token := stop_tokx
- else if ch=chr(eolch) then begin
- nextch;
- {#<E end-of-line token dealt with here }
- token := eol_tokx { accept an end-of-line token }
- {#:}
- get_token { go find another (significant) character }
- {#>}
- end
- else begin
- error('illegal character');
- nextch;
- get_token { try again }
- end
- end { case alternatives }
- end { case }
- end { get_token };
-
- {*******************}
- procedure NEXT_TOKEN;
- begin
- if tokenx>1 then begin
- tokenx := 1;
- get_token; { goes into token, lsemp }
- tokary[1] := token;
- lsempary[1] := lsemp;
- end
- else begin
- { is in tokary }
- token := tokary[tokenx];
- lsemp := lsempary[tokenx];
- end
- end;
-
- {*****************}
- procedure TOKENREAD;
- begin
- tokenx := tokenx+1;
- end;
-
- { LR(1) PARSER procedures }
-
- {======================= calculator semantics ======================}
- {$I calcutil.pas} { utility routines }
- {$I calcsem.pas} { the apply procedure }
-
- {****************}
- function ERROR_RECOVERY(var MSTACK: state_stack;
- var MSTACKX: int; MCSTATE: int): int;
- label 99, 100;
- var STACK: state_stack; { local copy of stack }
- STACKX, { local stack pointer }
- CSTATE, { local state }
- JSTX, { temporary stack limit }
- RX, TL: int; { index into TOKNUM table }
-
- {...............}
- procedure COPY_STACK;
- var STX: int;
- begin
- if (jstx<0) or (jstx>mstackx) then abort('ERROR RECOVERY BUG');
- for stx := 0 to jstx do
- stack[stx] := mstack[stx];
- stackx := jstx;
- if jstx=mstackx then
- cstate := mcstate
- else
- cstate := mstack[jstx+1];
- end;
-
- {...............}
- procedure PUSHREAD(CSTATE: int);
- { adjusts the state stack }
- begin
- stackx := stackx+1;
- if stackx>stacksize then
- abort('stack overflow');
- stack[stackx] := cstate;
- end;
-
- {...............}
- function TRIAL_PARSE: boolean;
- { parses from current read state through the inserted and the
- error token; if successful, returns TRUE. }
- label 99;
- var RX: int;
- begin
- trial_parse := true; { until proven otherwise }
- while cstate<>0 do begin
- if cstate < readstate then begin
- { a reduce state }
- {#<D dump if debugging enabled. }
- if debug > 3 then stk_dump('E*Reduce', stack,
- stackx, cstate);
- {#> end conditional. }
- if popno[cstate]=0 then begin
- { empty production }
- pushread(stk_state[statex[cstate]]);
- cstate := stk_tostate[statex[cstate]];
- end
- else begin
- { non-empty production }
- stackx := stackx - popno[cstate] + 1;
- rx := statex[cstate]; { compute the GOTO state }
- cstate := stack[stackx];
- while (stk_state[rx]<>cstate) and
- (stk_state[rx]<>0) do rx := rx+1;
- cstate := stk_tostate[rx];
- end
- end
- else if cstate < lookstate then begin
- { a read state }
- next_token; { need a token now }
- {#<D dump if debugging enabled. }
- if debug > 3 then stk_dump('E*Read', stack, stackx, cstate);
- {#> end conditional. }
- rx := statex[cstate];
- while (toknum[rx]<>0) and
- (toknum[rx]<>token) do rx := rx+1;
- if toknum[rx]=0 then begin
- { failure }
- trial_parse := false;
- goto 99;
- end
- else begin
- { did read something }
- pushread(cstate);
- cstate := tostate[rx];
- tokenread; { scan the token }
- if tokenx>1 then goto 99 { successful }
- end
- end
- else begin
- { lookahead state }
- next_token; { need a token now }
- {#<D dump if debugging enabled. }
- if debug > 3 then stk_dump('E*Look', stack, stackx, cstate);
- {#> end conditional. }
- rx := statex[cstate];
- while (toknum[rx]<>0) and
- (toknum[rx]<>token) do rx := rx+1;
- cstate := tostate[rx];
- end
- end;
- 99:
- end;
-
- {.................}
- procedure INCR_ERRSYM;
- { Note that this procedure assumes ASCII. }
- begin
- if errsym[6]='Z' then begin
- errsym[5] := succ(errsym[5]);
- errsym[6] := 'A';
- end
- else
- errsym[6] := succ(errsym[6]);
- end;
-
- {.................}
- procedure MAKE_DEFAULT(TOKX: int; SEMP: semrecp);
- { creates a default token data structure }
- var SYM: symbol;
- begin
- with semp^ do begin
- case tokx of
- int_tokx:
- begin
- semt := fixed;
- numval := 1;
- end;
- real_tokx:
- begin
- semt := float;
- rval := 1.0;
- end;
- ident_tokx:
- begin
- semt := ident;
- symp := makesym(errsym, symerr, 0);
- incr_errsym;
- end;
- str_tokx:
- begin
- semt := strng;
- stx := 0; { default string at origin }
- end;
- ELSE
- semt := other;
- end { case tokx }
- end
- end;
-
- begin { ERROR_RECOVERY }
- if debug > 3 then writeln(rfile, 'Going into ERROR RECOVERY');
- while true do begin
- jstx := mstackx;
- while jstx>=0 do begin
- copy_stack;
- rx := statex[cstate];
- while toknum[rx]<>0 do begin
- { scan through legal next tokens }
- if debug > 3 then writeln(rfile, '...starting trial parse');
- tokary[0] := toknum[rx]; { the insertion }
- tokenx := 0;
- if trial_parse then goto 99; { it clicked! }
- rx := rx+1;
- if toknum[rx]<>0 then
- copy_stack;
- end;
- jstx := jstx-1; { reduce stack }
- end;
- if token=stop_tokx then begin
- { empty stack, no more tokens }
- cstate := 0; { halt state }
- tokenx := 2;
- jstx := 0; { bottom of stack }
- goto 100;
- end;
- {#<D}
- if debug > 3 then begin
- write(rfile, '...dropping token ');
- tl := wrtok(tokary[1]);
- writeln(rfile);
- end;
- {#>}
- tokenx := 2;
- next_token;
- {#<D}
- if debug > 3 then begin
- write(rfile, 'New token ');
- tl := wrtok(token);
- writeln(rfile);
- end
- {#>}
- end;
- 99: { found a solution }
- copy_stack;
- {#<D}
- if debug > 3 then begin
- write(rfile, 'insertion of ');
- tl := wrtok(tokary[0]);
- writeln(rfile, ' succeeded');
- end;
- {#>}
- make_default(tokary[0], lsempary[0]);
- tokenx := 0; { forces a `real' rescan of the insertion }
- if jstx<mstackx then
- cstate := stack[jstx+1]
- else
- cstate := mcstate; { cstate returned }
- 100:
- error_recovery := cstate;
- mstackx := jstx;
- if debug > 3 then writeln(rfile, 'Ending error recovery');
- end;
-
- {****************}
- procedure PARSER;
- { Carries out a complete parse, until
- the halt state is seen -- same as empty stack}
- var CSTATE, RX: int;
- TSEMP: semrecp;
-
- {...............}
- procedure PUSHREAD(CSTATE: int; SEMP: semrecp);
- { do the push part of a readstate. }
- begin
- stackx := stackx+1;
- if stackx>stacksize then
- abort('stack overflow');
- semstack[stackx]^ := semp^;
- stack[stackx] := cstate;
- end;
-
- begin
- cstate := start_state;
- stackx := -1;
- new(tsemp);
- tsemp^.semt := other;
- pushread(stk_state_1, tsemp);
- while cstate<>0 do begin
- if cstate < readstate then begin
- { a reduce state }
- {#<D dump if debugging enabled. }
- if debug > 0 then stk_dump('Reduce', stack, stackx, cstate);
- {#> end conditional. }
- if map[cstate] <> 0 then
- { the semantics action }
- apply(map[cstate], popno[cstate], tsemp);
- if popno[cstate]=0 then begin
- { empty production }
- pushread(stk_state[statex[cstate]], tsemp);
- cstate := stk_tostate[statex[cstate]];
- end
- else begin
- { non-empty production:
- semantics is preserved on a unit production A --> w,
- where |w| = 1, unless something is in TSEMP. Note that
- if w is nonterminal, the production may be bypassed. }
- stackx := stackx - popno[cstate] + 1;
- if popno[cstate]=1 then begin
- if tsemp^.semt<>other then
- semstack[stackx]^ := tsemp^;
- end
- else
- semstack[stackx]^ := tsemp^;
- { compute the GOTO state }
- rx := statex[cstate];
- cstate := stack[stackx];
- while (stk_state[rx]<>cstate) and (stk_state[rx]<>0) do
- rx := rx+1;
- cstate := stk_tostate[rx];
- end;
- tsemp^.semt := other;
- end
- else if cstate < lookstate then begin
- { a read state }
- next_token; { need next token now }
- {#<D dump if debugging enabled. }
- if debug > 2 then stk_dump('Read', stack, stackx, cstate);
- {#> end conditional. }
- rx := statex[cstate];
- while (toknum[rx]<>0) and (toknum[rx]<>token) do
- rx := rx+1;
- if toknum[rx]=0 then begin
- error('syntax error');
- cstate := error_recovery(stack, stackx, cstate);
- end
- else begin
- pushread(cstate, lsemp);
- cstate := tostate[rx];
- tokenread; { token has been scanned }
- end
- end
- else begin
- { lookahead state }
- next_token; { need another token now }
- {#<D dump if debugging enabled. }
- if debug > 2 then stk_dump('Look', stack, stackx, cstate);
- {#> end conditional. }
- rx := statex[cstate];
- while (toknum[rx]<>0) and (toknum[rx]<>token) do
- rx := rx+1;
- cstate := tostate[rx];
- end
- end;
- end_sem;
- end;
-
- { PARSE INITIALIZATION }
-
- {*****************}
- procedure INITTABLES;
- var SX: int;
-
- {#<F import the table file reading function if needed. }
- {$I skelrtbl.pas}
- {#<D debugging wanted, too?
- {$I skeldtbl.pas}
- {#> end debugging }
- {#: else include the auxiliary functions needed by inline inits. }
- {................}
- procedure PUTSYM(STR: string80; TV: int);
- var SYMP: symtabp;
- TSYM: symbol;
- I: int;
- begin
- fillchar(tsym, maxtoklen, ' ');
- for i:=1 to length(str) do
- tsym[i]:=str[i];
- symp:=makesym(tsym, reserved, -1);
- symp^.tokval:=tv;
- end;
-
- {#<D also need to init debugging tables? }
- {................}
- procedure PUTTOK(PRINTVAL: string80; TOKNUM, START: int);
- { this procedure is used to initialize the token tables.
- toknum is the number of the token to be initialized, and
- start is where it should start in the tokchar array. }
- var OFFSET: int;
- begin
- tokx[toknum] := start;
- for offset := 0 to length(printval)-1 do
- tokchar[start+offset] := printval[offset+1];
- tokchar[start+length(printval)] := chr(0)
- end;
- {#> end puttok insertion. }
- {#> end table file conditional. }
-
- {................}
- procedure INIT_PARSER_TABLES;
- { initialize the parser tables }
- begin
- {#<F read from a table file? }
- {#T insert table file name in next line. }
- assign(tfile, '#');
- reset(tfile);
- read_header;
- read_table_file;
- {#<D take debugging info from the table file? }
- read_debugging_tables;
- {#> end if. }
- close(tfile)
- {#: not a table file; do the necessary inline inits }
- {#IS inline symbol table inits. }
- {#<A assignment style inits? }
- {#IP do the parser tables inline. }
- {#> end assignment inits. }
- {#<D debugging? }
- {#IT do the token tables inline. }
- {#> end debugging }
- {#> end of initialization style selection. }
- end { init_parser_tables };
-
- begin { inittables }
- pwr10_2[0] := 1E1; {10^(2^0)}
- pwr10_2[1] := 1E2; {10^(2^1)}
- pwr10_2[2] := 1E4;
- pwr10_2[3] := 1E8;
- pwr10_2[4] := 1E16;
- pwr10_2[5] := 1E32;
- errsym := 'ERR#AA ';
- new(lsempary[0]);
- lsempary[0]^.semt := other;
- new(lsempary[1]);
- lsempary[1]^.semt := other;
- lsemp := lsempary[1];
- strtabx := 0;
- putstr('ERROR'); { default error string }
- tokenx := 2; { no token queue }
- for sx := 0 to hlimit do
- symtab[sx] := nil; { initialize symbol table }
- for sx := 0 to stacksize do begin
- new(semstack[sx]);
- semstack[sx]^.semt := other;
- end;
- init_parser_tables;
- init_sem;
- line := ''; { fake a new line }
- lx := 1;
- errpos:=1;
- nextch; { fetch the first character, forcing a line read }
- end;
-
- {===================== start calcskel changes =====================}
- {*****************}
- procedure OPENFILES;
- { opens 'source' and 'listing' files (actually, the console in
- both cases). }
- begin
- sfilename := ''; { this means to read from the console as well }
- rfilename := ''; { as write to it (for other code's info). }
- prompt_len:=2; { characters in prompt }
- assign(sfile, 'con:');
- reset(sfile);
- assign(rfile, 'con:');
- rewrite(rfile)
- end;
- {===================== end of calcskel changes =====================}
-
- begin
- writeln('Interactive Calculator (vers. 18-Oct-84) -- "QUIT" to exit.');
- writeln('COPYRIGHT (C) 1984, QCAD Systems, Inc. All rights reserved');
- writeln;
- errors := 0;
- debug := 0;
- openfiles;
- inittables;
- parser; { does it all }
- close(sfile);
- close(rfile)
- end.
-