home *** CD-ROM | disk | FTP | other *** search
Text File | 1987-07-28 | 58.0 KB | 2,502 lines |
- (***************************************************************************)
- (***************************************************************************)
- (** **)
- (** Copyright (C) 1987 by Per Bergsten, Gothenburg, Sweden **)
- (** **)
- (** No part of this program, or parts derived from this program, **)
- (** may be sold, hired or otherwise exploited without the author's **)
- (** written consent. **)
- (** **)
- (** The program may be freely redistributed provided that: **)
- (** **)
- (** 1) the original program text, including this notice, **)
- (** is reproduced unaltered, **)
- (** 2) no charge (other than a nominal media cost) is **)
- (** demanded for the copy. **)
- (** **)
- (** The program may be included in a package only on the condition **)
- (** that the package as a whole is distributed at media cost. **)
- (** **)
- (***************************************************************************)
- (***************************************************************************)
- (** **)
- (** The program ptc is a Pascal-to-C translator. **)
- (** It accepts a correct Pascal program and creates a C program **)
- (** with the same behaviour. It is not a complete compiler in the **)
- (** sense that it does NOT do complete typechecking or error- **)
- (** reporting. Only a minimal typecheck is done so that the meaning **)
- (** of each construct can be determined. Therefore, an incorrect **)
- (** Pascal program can easily cause the translator to malfunction. **)
- (** **)
- (***************************************************************************)
- (***************************************************************************)
- (** **)
- (** Things which are known to be dependent on the underlying cha- **)
- (** racterset are marked with a comment containing the word CHAR. **)
- (** Things that are known to be dependent on the host operating **)
- (** system are marked with a comment containing the word OS. **)
- (** Things known to be dependent on the cpu and/or the target C- **)
- (** implementation are marked with the word CPU. **)
- (** Things dependent on the target C-library are marked with LIB. **)
- (** **)
- (** The code generated by the translator assumes that there is a **)
- (** C-implementation with at least a reasonable <stdio> library **)
- (** since all input/output is implemented in terms of C functions **)
- (** like fprintf(), getc(), fopen(), rewind() etc. **)
- (** If the source-program uses Pascal functions like sin(), sqrt() **)
- (** etc, there must also exist such functions in the C-library. **)
- (** **)
- (***************************************************************************)
- (***************************************************************************)
-
- program ptc(input, output);
-
- label 9999; (* end of program *)
-
- const version = '@(#)ptc.p 1.5 Date 87/05/01';
-
- keytablen = 38; (* nr of keywords *)
- keywordlen = 10; (* length of a keyword *)
- othersym = 'otherwise '; (* keyword for others *)
- externsym = 'external '; (* keyword for external *)
- dummysym = ' '; (* dummy keyword *)
-
- (* a Pascal set is implemented as an array of "wordtype" where *)
- (* each element contains bits numbered from 0 to "setbits" *)
- wordtype = 'unsigned short'; (* CPU *)
- setbits = 15; (* CPU *)
-
- (* a Pascal file is implemented as a struct which (among other *)
- (* things) contain a flag-field, currently 3 bits are used *)
- filebits = 'unsigned short'; (* flags for files *)
- filefill = 12; (* 16 less used 3 bits *)
-
- maxsetrange = 15; (* nr of words in a set *)
- scalbase = 0; (* ordinal value of first scalar member *)
-
- maxprio = 7;
-
- maxmachdefs = 8; (* max nr of machine integer types *)
- machdeflen = 16; (* max length of machine int type name *)
-
- (* limit of identifier table, identifiers and strings are saved *)
- (* in an array 0 .. maxblkcnt of ^ array 0 .. maxstrblk of char *)
- maxstrblk = 1023;
- maxblkcnt = 63;
- maxstrstor = 65535; (* maxstrstor should be ==
- (maxblkcnt+1) * (maxstrblk+1) - 1 *)
-
- maxtoknlen = 127; (* max size of token (i.e. identifier,
- string or number); must be > keywordlen
- and should be <= 256, see hashtokn() *)
-
- hashmax = 64; (* size of hashtable - 1 *)
-
- null = 0; (* "impossible" character value, CHAR;
- a char with this value is used as delimiter
- of strings in "strstor" and in toknbuffers;
- it is also used as end-of-input marker by
- the input procedures in lexical analysis *)
-
- minchar = null;
- maxchar = 127; (* greatest possible character, CHAR; limits
- the number of elements in type "char" *)
-
- (* tmpfilename is used in the generated code to obtain names of
- temporary files for reset/rewrite, the last character is supplied
- by the reset/rewrite routine *)
- tmpfilename = '"/tmp/ptc%d%c", getpid(), '; (* OS *)
-
- (* some frequently used characters *)
- space = ' ';
- tab1 = ' ';
- tab2 = ' ';
- tab3 = ' ';
- tab4 = ' ';
- bslash = '\';
- nlchr = '''\n''';
- ffchr = '''\f''';
- nulchr = '''\0''';
- spchr = ''' ''';
- quote = '''';
- cite = '"';
- xpnent = 'e'; (* exponent char in output. CPU *)
- percent = '%';
- uscore = '_';
- badchr = '?'; (* CHAR *)
- okchr = quote; (* CHAR *)
-
- tabwidth = 8; (* width of a tab-stop. OS *)
-
- echo = false; (* echo input as read *)
- diffcomm = false; (* comment delimiters different *)
- lazyfor = false; (* compile for-stmts a la C *)
- unionnew = true; (* malloc unions for variants *)
-
- inttyp = 'int'; (* for predefined functions *)
- chartyp = 'char';
- setwtyp = 'setword';
- setptyp = 'setptr';
- floattyp = 'float';
- doubletyp = 'double';
- dblcast = '(double)'; (* for predefined functions *)
-
- realtyp = doubletyp; (* user real-vars and functions *)
-
- voidtyp = 'void'; (* for procedures *)
- voidcast = '(void)';
-
- intlen = 10; (* length of written integer *)
- fixlen = 20; (* length of written real *)
-
- type
- hashtyp = 0 .. hashmax; (* index to hash-tables *)
-
- strindx = 0 .. maxstrstor; (* index to "strstor" *)
-
- (* string-table "strstor" is implemented as an array that is grown
- dynamically by adding blocks when needed *)
- strbidx = 0 .. maxstrblk;
- strblk = array [ strbidx ] of char;
- strptr = ^ strblk;
- strbcnt = 0 .. maxblkcnt;
-
- (* table for stored identifiers *)
- (* an identifier in any scope is represented by an idnode which is
- hooked to a slot in "idtab" as determined by a hash-function.
- whenever the input procedures find an identifier its idnode is
- immediately located, or created, if none was found; the identifier
- is then always handled though a pointer to the idnode. the actual
- text of the identifier is stored in "strstor". *)
- idptr = ^ idnode;
- idnode = record
- inext : idptr; (* chain of idnode's *)
- inref : 0 .. 127; (* # of refs to this id *)
- ihash : hashtyp; (* its hash value *)
- istr : strindx; (* index to "strstor" *)
- end;
-
- (* toknbuf is used to handle identifiers and strings in those situations
- where the actual text is of intrest *)
- toknidx = 1 .. maxtoknlen;
- toknbuf = array [ toknidx ] of char;
-
- (* a type to hold Pascal keywords *)
- keyword = packed array [ 1 .. keywordlen ] of char;
-
- (* predefined identifier enumeration *)
- predefs = (
- dabs, darctan, dargc, dargv,
- dboolean, dchar, dchr, dclose,
- dcos, ddispose, deof, deoln,
- dexit, dexp, dfalse, dflush,
- dget, dhalt, dinput, dinteger,
- dln, dmaxint, dmessage, dnew,
- dodd, dord, doutput, dpage,
- dpack, dpred, dput, dread,
- dreadln, dreal, dreset, drewrite,
- dround, dsin, dsqr, dsqrt,
- dsucc, dtext, dtrue, dtrunc,
- dtan, dwrite, dwriteln, dunpack,
- dzinit, dztring
- );
-
- (* lexical symbol enumeration *)
- symtyp = (
- (* keywords and eof are sorted alphabetically ...... *)
- sand, sarray, sbegin, scase,
- sconst, sdiv, sdo, sdownto,
- selse, send, sextern, sfile,
- sfor, sforward, sfunc, sgoto,
- sif, sinn, slabel, smod,
- snil, snot, sof, sor,
- sother, spacked, sproc, spgm,
- srecord, srepeat, sset, sthen,
- sto, stype, suntil, svar,
- swhile, swith, seof,
- (* ...... sorted *)
- sinteger,
- sreal, sstring, schar, sid,
- splus, sminus, smul, squot,
- sarrow, slpar, srpar, slbrack,
- srbrack, seq, sne, slt,
- sle, sgt, sge, scomma,
- scolon, ssemic, sassign, sdotdot,
- sdot
- );
- symset = set of symtyp;
-
- (* lexical symbol definition *)
- (* the lexical symbol holds a descriptor and the value of a symbol
- read by the input procedures; note that real values are represented
- as strings saved in "strstor" like ordinary strings to avoid using
- float-variables and float-arithmetic in the translator *)
- lexsym =
- record
- case st : symtyp of
- sid: (vid : idptr);
- schar: (vchr : char);
- sinteger: (vint : integer);
- sreal: (vflt : strindx);
- sstring: (vstr : strindx);
- end;
-
- (* enumeration of symnode variants *)
- ltypes = (
- lpredef, lidentifier, lfield, lforward,
- lpointer, lstring, llabel, lforwlab,
- linteger, lreal, lcharacter
- );
-
- declptr = ^ declnode;
- treeptr = ^ treenode;
- symptr = ^ symnode;
- (* identifier/literal symbol definition *)
- (* in a given scope an identifier or a label is uniquely represented
- by a "symnode"; in order to have a uniform treatment of all objects
- occurring in the same syntactical positions (and hence in the parse-
- tree) the literal constants are represented in a similar manner *)
- symnode =
- record
- lsymdecl : treeptr; (* symbol decl. point *)
- lnext : symptr; (* symtab chain pointer *)
- ldecl : declptr; (* backptr to symtab *)
- case lt : ltypes of
- lpredef, (* a predefined id *)
- lfield, (* a record field *)
- lpointer, (* a pointer id *)
- lidentifier, (* an identifier *)
- lforward:
- (
- lid : idptr; (* ptr to its idnode *)
- lused : boolean (* true if symbol used *)
- );
- lstring: (* a string literal *)
- (
- lstr : strindx (* index to "strstor" *)
- );
- lreal: (* a real literal *)
- (
- lfloat : strindx (* index to "strstor" *)
- );
- lforwlab, (* a declared label *)
- llabel: (* label decl & defined *)
- (
- lno : integer; (* label number *)
- lgo : boolean (* non-local usage *)
- );
- linteger: (* an integer literal *)
- (
- linum : integer (* its value *)
- );
- lcharacter: (* a character literal *)
- (
- lchar : char (* its value *)
- )
- end;
-
- (* symbol table definition *)
- (* the symbol table consists of symnodes chained along the lnext
- field; the nodes are connected in reverse order of occurence (last
- declared, first in chain) in the slot in the declnode determined
- by the hashfunction; when a new scope is entered a new declnode is
- manufactured and the previous one is hooked to the dprev field, thus
- nested scopes are represented by a list of declnodes *)
- declnode = record
- dprev : declptr;
- ddecl : array [ hashtyp ] of symptr
- end;
-
- (* enumeration of nodes in parse tree *)
- (* NOTE: the subrange [ assignment .. nil ] have priorities *)
- treetyp = (
- npredef, npgm, nfunc, nproc,
- nlabel, nconst, ntype, nvar,
- nvalpar, nvarpar, nparproc, nparfunc,
- nsubrange, nvariant, nfield, nrecord,
- narray, nconfarr, nfileof, nsetof,
- nbegin, nptr, nscalar, nif,
- nwhile, nrepeat, nfor, ncase,
- nchoise, ngoto, nwith, nwithvar,
- nempty, nlabstmt, nassign, nformat,
- nin, neq, nne, nlt,
- nle, ngt, nge, nor,
- nplus, nminus, nand, nmul,
- ndiv, nmod, nquot, nnot,
- numinus, nuplus, nset, nrange,
- nindex, nselect, nderef, ncall,
- nid, nchar, ninteger, nreal,
- nstring, nnil, npush, npop,
- nbreak
- );
-
- (* enumeration of predefined types *)
- pretyps = (
- tnone, tboolean, tchar, tinteger,
- treal, tstring, tnil, tset,
- ttext, tpoly, terror
- );
-
- (* enumeration of some special attributes *)
- attributes = (
- anone, aregister, aextern, areference
- );
-
- (* parse tree definition *)
- (* the sourceprogram is represented by a treestructure built from
- treenodes where each node corresponds to one syntactic form from
- the pascal program *)
- treenode =
- record
- tnext, (* ptr to next node in a list *)
- ttype, (* pointer to nodes type *)
- tup : treeptr; (* ptr to parent node *)
- case tt : treetyp of
- npredef: (* predefined object decl *)
- (
- tdef: (* predefined object descr. *)
- predefs;
- tobtyp: (* object type *)
- pretyps
- );
- npgm, (* program declaration *)
- nproc, (* procedure declaration *)
- nfunc: (* function declaration *)
- (
- tsubid, (* subr. identifier (nid) *)
- tsubpar, (* parameter list *)
- tfuntyp, (* function type (nid) *)
- tsublab, (* label decl list (nlabel) *)
- tsubconst, (* const decl list (nconst) *)
- tsubtype, (* type decl list (ntype) *)
- tsubvar, (* var decl list (nvar) *)
- tsubsub, (* subr. decl (nproc/nfunc) *)
- tsubstmt: (* stmt. list (NOT nbegin) *)
- treeptr;
- tstat: (* static declaration level *)
- integer;
- tscope: (* symbol table for local id's *)
- declptr
- );
- nvalpar, (* value parameter declaration *)
- nvarpar, (* var parameter declaration *)
- nconst, (* constant declaration *)
- ntype, (* type declaration *)
- nfield, (* record field declaration *)
- nvar: (* var declaration declaration *)
- (
- tidl, (* list of declared id's (nid) *)
- tbind: (* var/type-type, const-value *)
- treeptr;
- tattr: (* special attributes for vars *)
- attributes
- );
- nparproc, (* parameter procedure *)
- nparfunc: (* parameter function *)
- (
- tparid, (* parm proc/func id (nid) *)
- tparparm, (* parm proc/func parm decl *)
- tpartyp: (* parm func type (nid) *)
- treeptr
- );
- nptr: (* pointer constructor *)
- (
- tptrid: (* referenced type (nid) *)
- treeptr;
- tptrflag: (* have seen node before *)
- boolean
- );
- nscalar: (* scalar type constructor *)
- (
- tscalid: (* list of scalar ids (nid) *)
- treeptr
- );
- nfileof, (* file type constructor *)
- nsetof: (* set type constructor *)
- (
- tof: (* set/file component type *)
- treeptr
- );
- nsubrange: (* subrange type constructor *)
- (
- tlo, thi: (* subrange limits *)
- treeptr
- );
- nvariant: (* record variant constructor *)
- (
- tselct, (* selector list (constants) *)
- tvrnt: (* variant field decl (nrecord) *)
- treeptr
- );
-
- (* the tuid field is used to attach a name to variants since
- C requires all union members to have names *)
- nrecord: (* record/variant constructor *)
- (
- tflist, (* fixed field list (nfield) *)
- tvlist: (* variant list (nvariant) *)
- treeptr;
- tuid: (* variant name *)
- idptr;
- trscope: (* symbol table for local id's *)
- declptr
- );
- nconfarr: (* conformant array constructor *)
- (
- tcindx, (* index declaration *)
- tindtyp, (* conf. arr. index type (nid) *)
- tcelem: (* array element type decl *)
- treeptr;
- tcuid: (* variant name *)
- idptr
- );
- narray: (* array type constructor *)
- (
- taindx, (* index declaration *)
- taelem: (* array element type decl *)
- treeptr
- );
- nbegin: (* begin statement *)
- (
- tbegin: (* statement list *)
- treeptr
- );
- nlabstmt: (* labeled statement *)
- (
- tlabno, (* label number (nlabel) *)
- tstmt: (* statement *)
- treeptr
- );
- ngoto: (* goto statement *)
- (
- tlabel: (* label to go to (nlabel) *)
- treeptr
- );
-
- nassign: (* assignment statement *)
- (
- tlhs, (* variable *)
- trhs: (* value *)
- treeptr
- );
-
- (* npush/npop is used in proc/func which have local variables
- used in local proc/funcs; those variables are converted to
- global ptrs initialized to reference the local variable *)
- npush, (* init code for proc/func *)
- npop: (* exit code for proc/func *)
- (
- tglob, (* global identifier (nid) *)
- tloc, (* local identifier (nid) *)
- ttmp: (* temp store for global (nid) *)
- treeptr
- );
-
- nbreak:
- (
- tbrkid, (* for-variable *)
- tbrkxp: (* value for break *)
- treeptr
- );
-
- ncall: (* procedure/function call *)
- (
- tcall, (* called identifier *)
- taparm: (* actual paramters *)
- treeptr
- );
- nif: (* if statement *)
- (
- tifxp, (* conditional expression *)
- tthen, (* stmt execd if true condition *)
- telse: (* stmt execd if true condition *)
- treeptr
- );
- nwhile: (* while statemnet *)
- (
- twhixp, (* conditional expression *)
- twhistmt: (* stmt execd if true condition *)
- treeptr
- );
- nrepeat: (* repeat statement *)
- (
- treptstmt, (* statement list *)
- treptxp: (* conditional expression *)
- treeptr
- );
- nfor: (* for statement *)
- (
- tforid, (* loop control variable (nid) *)
- tfrom, (* initial value *)
- tto, (* final value *)
- tforstmt: (* stmt execd in loop *)
- treeptr;
- tincr: (* to/downto flag true <==> to *)
- boolean
- );
- ncase: (* case statement *)
- (
- tcasxp, (* selecting expression *)
- tcaslst, (* list of choises *)
- tcasother: (* default action *)
- treeptr
- );
- nchoise: (* a choise in a case-stmt *)
- (
- tchocon, (* list of constants *)
- tchostmt: (* execd statement *)
- treeptr
- );
- nwith: (* with statment *)
- (
- twithvar, (* list of variables (nwithvar) *)
- twithstmt: (* statement execd in new scope *)
- treeptr
- );
-
- (* the local symbol table holds identifiers, picked from
- the record fields, temporarily declared during parsing
- of remainder of with-statement; these identifiers are
- later converted into fields referenced through a ptr *)
- nwithvar: (* variable in with statement *)
- (
- texpw: (* record variable *)
- treeptr;
- tenv: (* symbol table for local scope *)
- declptr
- );
-
- nindex: (* array indexing expression *)
- (
- tvariable, (* indexed variable *)
- toffset: (* index expression *)
- treeptr
- );
- nselect: (* record field selection expr *)
- (
- trecord, (* record variable *)
- tfield: (* selected field (nid) *)
- treeptr
- );
-
- (* binary operators or constructors *)
- nrange, (* .. (set range) *)
- nformat, (* : (write format) *)
- nin, (* in *)
- neq, (* = *)
- nne, (* <> *)
- nlt, (* < *)
- nle, (* <= *)
- ngt, (* > *)
- nge, (* >= *)
- nor, (* or *)
- nplus, (* + *)
- nminus, (* - *)
- nand, (* and *)
- nmul, (* * *)
- ndiv, (* div *)
- nmod, (* mod *)
- nquot: (* / *)
- (
- texpl, (* left operand expr *)
- texpr: (* right operand expr *)
- treeptr
- );
-
- (* unary operators or constructors; note that uplus is
- used to represent any parenthesized expression *)
- nderef, (* ^ (ptr dereference) *)
- nnot, (* not *)
- nset, (* [ ] (set constr) *)
- nuplus, (* + *)
- numinus: (* - *)
- (
- texps: (* operand expression *)
- treeptr
- );
-
- nid, (* identifier in decl or stmt *)
- nreal, (* literal real (decl or stmt) *)
- ninteger, (* literal int ( - " - ) *)
- nchar, (* literal char ( - " - ) *)
- nstring, (* literal string ( - " - ) *)
- nlabel: (* label (decl, defpt or use) *)
- (
- tsym:
- symptr
- );
-
- nnil, (* nil (pointer constant) *)
- nempty: (* empty statement *)
- ( );
- end;
-
- (* "reserved" words and standard identifiers from C, C LIB and
- OS environment excluding those reserved in Pascal *)
- cnames = (
- cabort, cbreak, ccontinue, cdefine,
- cdefault, cdouble, cedata, cenum,
- cetext, cextern, cfgetc, cfclose,
- cfflush, cfloat, cfloor, cfprintf,
- cfputc, cfread, cfscanf, cfwrite,
- cgetc, cgetpid, cint, cinclude,
- clong, clog, cmain, cmalloc,
- cprintf, cpower, cputc, cread,
- creturn, cregister, crewind, cscanf,
- csetbits, csetword, csetptr, cshort,
- csigned, csizeof, csprintf, cstdin,
- cstdout, cstderr, cstrncmp, cstrncpy,
- cstruct, cstatic, cswitch, ctypedef,
- cundef, cungetc, cunion, cunlink,
- cunsigned, cwrite
- );
-
- (* these are the detected errors. some are user-errors,
- some are internal problems and some are host system errors *)
- errors = (
- ebadsymbol, elongstring, elongtokn, erange,
- emanytokn, enotdeclid, emultdeclid, enotdecllab,
- emultdecllab, emuldeflab, ebadstring, enulchr,
- ebadchar, eeofcmnt, eeofstr, evarpar,
- enew, esetbase, esetsize, eoverflow,
- etree, etag, euprconf, easgnconf,
- ecmpconf, econfconf, evrntfile, evarfile,
- emanymachs, ebadmach
- );
-
- machdefstr = packed array [ 1 .. machdeflen ] of char;
-
- var
- usemax, (* program needs max-function *)
- usejmps, (* source program uses non-local gotos *)
- usecase, (* source program has case-statement *)
- usesets, (* source program uses set-operations *)
- useunion,
- usediff,
- usemksub,
- useintr,
- usesge,
- usesle,
- useseq,
- usesne,
- usememb,
- useins,
- usescpy,
- usecomp, (* source program uses string-compare *)
- usefopn, (* source program uses reset/rewrite *)
- usescan,
- usegetl,
- usenilp, (* source program uses nil-pointer *)
- usebool : boolean; (* source program writes boolean-values *)
-
- top : treeptr; (* top of parsetree, result from parse *)
-
- setlst : treeptr; (* list of set-initializations *)
- setcnt : integer; (* counter for setlst length *)
-
- currsym : lexsym; (* current lexical symbol *)
-
- keytab : array [ 0 .. keytablen ] of (* table of keywords *)
- record
- wrd : keyword; (* keyword text *)
- sym : symtyp (* corresponding symbol *)
- end;
-
- strstor : array [ strbcnt ] of strptr; (* store for strings *)
- strfree : strindx; (* first free position *)
- strleft : strbidx; (* room in last blk *)
-
- idtab : array [ hashtyp ] of idptr; (* hashed table of id's *)
-
- symtab : declptr; (* table of symbols *)
-
- statlvl, (* static decl. level *)
- maxlevel : integer; (* - " - maximum value *)
-
- deftab : array [ predefs ] of treeptr; (* predefined idents. *)
- defnams : array [ predefs ] of symptr; (* - " - *)
- typnods : array [ pretyps ] of treeptr; (* predef. types. *)
-
- pprio,
- cprio : array [ nassign .. nnil ] of 0 .. maxprio;
-
- ctable : array [ cnames ] of idptr; (* table of C-keywords *)
-
- nmachdefs : 0 .. maxmachdefs;
- machdefs : array [ 1 .. maxmachdefs ] of (* table of C-types *)
- record
- lolim, hilim : integer;
- typstr : strindx
- end;
-
- lineno, (* input line number *)
- colno, (* input column number *)
- lastcol, (* last OK input column *)
- lastline : integer; (* last OK input line *)
-
- lasttok : toknbuf; (* last input token *)
-
- varno : integer; (* counter for unique id's *)
-
- hexdig : packed array [ 0 .. 15 ] of char;
-
- (* Prtmsg produces an error message. It asssumes that procedure *)
- (* "message" (predefined) will "writeln" to user tty. OS *)
- procedure prtmsg(m : errors);
-
- const user = 'Error: ';
- restr = 'Implementation restriction: ';
- inter = '* Internal error * ';
- xtoklen = 64; (* should be <= maxtoklen *)
-
- var i : toknidx;
- xtok : packed array [ 1 .. xtoklen ] of char;
-
- begin
- case m of
- ebadsymbol:
- message(user, 'Unexpected symbol');
- ebadchar:
- message(user, 'Bad character');
- elongstring:
- message(restr, 'Too long string');
- ebadstring:
- message(user, 'Newline in string or character');
- eeofstr:
- message(user, 'End of file in string or character');
- eeofcmnt:
- message(user, 'End of file in comment');
- elongtokn:
- message(restr, 'Too long identfier');
- emanytokn:
- message(restr, 'Too many strings, identifiers or real numbers');
- enotdeclid:
- message(user, 'Identifier not declared');
- emultdeclid:
- message(user, 'Identifier declared twice');
- enotdecllab:
- message(user, 'Label not declared');
- emultdecllab:
- message(user, 'Label declared twice');
- emuldeflab:
- message(user, 'Label defined twice');
- evarpar:
- message(user, 'Actual parameter not a variable');
- enulchr:
- message(restr, 'Cannot handle nul-character in strings');
- enew:
- message(restr, 'New returned a nil-pointer');
- eoverflow:
- message(restr, 'Token buffer overflowed');
- esetbase:
- message(restr, 'Cannot handle sets with base >> 0');
- esetsize:
- message(restr, 'Cannot handle sets with very large range');
- etree:
- message(inter, 'Bad tree structure');
- etag:
- message(inter, 'Cannot find tag');
- evrntfile:
- message(restr, 'Cannot initialize files in record variants');
- evarfile:
- message(restr, 'Cannot handle files in structured variables');
- euprconf:
- message(inter, 'No upper bound on conformant arrays');
- easgnconf:
- message(inter, 'Cannot assign conformant arrays');
- ecmpconf:
- message(inter, 'Cannot compare conformant arrays');
- econfconf:
- message(restr, 'Cannot handle nested conformat arrays');
- erange:
- message(inter, 'Cannot find C-type for integer-subrange');
- emanymachs:
- message(restr, 'Too many machine integer types');
- ebadmach:
- message(inter, 'Bad name for machine integer type');
- end;(* case *)
- if lastline <> 0 then
- begin
- (* error detected during parsing,
- report line/column and print the offending symbol *)
- message('Line ', lastline:1, ', col ', lastcol:1, ':');
- if m in [enulchr, ebadchar, ebadstring, ebadsymbol,
- emuldeflab, emultdecllab, enotdecllab, emultdeclid,
- enotdeclid, elongtokn, elongstring] then
- begin
- i := 1;
- while (i < xtoklen) and (lasttok[i] <> chr(null)) do
- begin
- xtok[i] := lasttok[i];
- i := i + 1
- end;
- while i < xtoklen do
- begin
- xtok[i] := ' ';
- i := i + 1
- end;
- xtok[xtoklen] := ' ';
- message('Current symbol: ', xtok)
- end
- end
- end;
-
- procedure fatal(m : errors); forward;
- procedure error(m : errors); forward;
-
- (* Map letters to upper-case. *)
- (* This function assumes a machine collating sequence where the *)
- (* letters of either case form a contigous sequence, CHAR. *)
- function uppercase(c : char) : char;
-
- begin
- if (c >= 'a') and (c <= 'z') then
- uppercase := chr(ord(c) + ord('A') - ord('a'))
- else
- uppercase := c
- end;
-
-
- (* Map letters to lower-case. *)
- (* This function assumes a machine collating sequence where the *)
- (* letters of either case form a contigous sequence, CHAR. *)
- function lowercase(c : char) : char;
-
- begin
- if (c >= 'A') and (c <= 'Z') then
- lowercase := chr(ord(c) - ord('A') + ord('a'))
- else
- lowercase := c
- end;
-
- (* Retrieve a string from strstor. *)
- procedure gettokn(i : strindx; var t : toknbuf);
-
- var c : char;
- k : toknidx;
- j : strbidx;
- p : strptr;
-
- begin
- k := 1;
- (* compute block and offset in block *)
- p := strstor[i div (maxstrblk + 1)];
- j := i mod (maxstrblk + 1);
- (* retrieve text up to null *)
- repeat
- c := p^[j];
- t[k] := c;
- j := j + 1;
- k := k + 1;
- if k = maxtoknlen then
- begin
- c := chr(null);
- t[maxtoknlen] := chr(null);
- prtmsg(eoverflow)
- end
- until c = chr(null)
- end;
-
- (* Deposit a string into strstor at a given start-position. *)
- procedure puttokn(i : strindx; var t : toknbuf);
-
- var c : char;
- k : toknidx;
- j : strbidx;
- p : strptr;
-
- begin
- k := 1;
- p := strstor[i div (maxstrblk + 1)];
- j := i mod (maxstrblk + 1);
- repeat
- c := t[k];
- p^[j] := c;
- k := k + 1;
- j := j + 1
- until c = chr(null)
- end;
-
- (* Write a token on standard output. *)
- procedure writetok(var w : toknbuf);
-
- var j : toknidx;
-
- begin
- j := 1;
- while w[j] <> chr(null) do
- begin
- write(w[j]);
- j := j + 1
- end
- end;
-
- (* Print a float number on standard output. *)
- procedure printtok(i : strindx);
-
- var w : toknbuf;
-
- begin
- gettokn(i, w);
- writetok(w)
- end;
-
- (* Print an identifier on standard output. *)
- procedure printid(ip : idptr);
-
- begin
- printtok(ip^.istr)
- end;
-
- (* Print a character on standard output with proper C-quoting. *)
- procedure printchr(c : char);
-
- begin
- if (c = quote) or (c = bslash) then
- write(quote, bslash, c, quote)
- else
- write(quote, c, quote)
- end;
-
- (* Print a string on standard output with proper C-quoting. *)
- procedure printstr(i : strindx);
-
- var k : toknidx;
- c : char;
- w : toknbuf;
-
- begin
- gettokn(i, w);
- write(cite);
- k := 1;
- while w[k] <> chr(null) do
- begin
- c := w[k];
- k := k + 1;
- if (c = cite) or (c = bslash) then
- write(bslash);
- write(c)
- end;
- write(cite)
- end;
-
- (* Return a pointer to the declarationpoint of an identifier. *)
- function idup(ip : treeptr) : treeptr;
-
- begin
- idup := ip^.tsym^.lsymdecl^.tup
- end;
-
- (* Compute a hashvalue for an identifier or a string. *)
- function hashtokn(var id : toknbuf) : hashtyp;
-
- var h : integer;
- i : toknidx;
-
- begin
- i := 1;
- h := 0;
- while id[i] <> chr(null) do
- begin
- (* if ord() of a character ranges from 0 to 127 then we can loop
- 256 times without causing h to exceed 32767, this is safe as
- both strings and identifiers are limited in length *)
- h := h + ord(id[i]); (* CHAR, CPU *)
- i := i + 1
- end;
- hashtokn := h mod hashmax
- end;
-
- (* Global string table update. *)
- (* This function accepts a string and stores it in strstor. *)
- (* It returns the id-number for the new string. *)
- function savestr(var t : toknbuf) : strindx;
-
- var k : toknidx;
- i : strindx;
- j : strbcnt;
-
- begin
- (* find length of new string including null-char *)
- k := 1;
- while t[k] <> chr(null) do
- k := k + 1;
- if k > strleft then
- begin
- (* out of space in strstore *)
- if strstor[maxblkcnt] <> nil then (* last slot used *)
- error(emanytokn);
- (* allocate a new block *)
- j := (strfree + maxstrblk) div (maxstrblk + 1);
- new(strstor[j]);
- if strstor[j] = nil then
- error(enew);
- strfree := j * (maxstrblk + 1);
- strleft := maxstrblk
- end;
- (* copy new str, update location of last used cell,
- return starting location for new str *)
- i := strfree;
- strfree := strfree + k;
- strleft := strleft - k;
- puttokn(i, t);
- savestr := i
- end;
-
- (* Global id table lookup. *)
- (* This procedure accepts an identifier and determines if it has *)
- (* been seen before. If that is the case a pointer to its idnode *)
- (* is returned, otherwise the identifier is saved and a pointer to *)
- (* a new node is returned. *)
- function saveid(var id : toknbuf) : idptr;
-
- label 999;
-
- var k : toknidx;
- ip : idptr;
- h : hashtyp;
- t : toknbuf;
-
- begin
- h := hashtokn(id);
- ip := idtab[h]; (* scan hashlist for id *)
- while ip <> nil do
- begin
- gettokn(ip^.istr, t); (* look at saved token *)
- k := 1;
- while id[k] = t[k] do
- if id[k] = chr(null) then
- goto 999 (* found it! *)
- else
- k := k + 1; (* look at next char *)
- ip := ip^.inext
- end;
-
- (* identifier wasn't previously seen, manufacture a new idnode,
- save index to strstor and hashvalue, insert idnode in idtab *)
- new(ip);
- if ip = nil then
- error(enew);
- ip^.inref := 0;
- ip^.istr := savestr(id);
- ip^.ihash := h;
- ip^.inext := idtab[h];
- idtab[h] := ip;
-
- 999:
- (* return the idnode *)
- saveid := ip
- end;
-
- (* This function creates a new variable by concatenating one name *)
- (* with another injecting a given separator. *)
- function mkconc(sep : char; p, q : idptr) : idptr;
-
- var w, x : toknbuf;
- i, j : toknidx;
-
- begin
- (* fetch second part and determine its length *)
- gettokn(q^.istr, x);
- j := 1;
- while x[j] <> chr(null) do
- j := j + 1;
- (* fetch first part and locate its end *)
- w[1] := chr(null);
- if p <> nil then
- gettokn(p^.istr, w);
- i := 1;
- while w[i] <> chr(null) do
- i := i + 1;
- (* check total length *)
- if i + j + 2 >= maxtoknlen then
- error(eoverflow);
-
- (* add separators *)
- if sep = '>' then
- begin
- (* special case 1: > gives arrow: a->b *)
- w[i] := '-';
- i := i + 1
- end;
- if sep <> space then
- begin
- (* special case 2: space gives nothing: ab *)
- w[i] := sep;
- i := i + 1
- end;
- (* add second part *)
- j := 1;
- repeat
- w[i] := x[j];
- i := i + 1;
- j := j + 1
- until w[i-1] = chr(null);
- (* save new identifier *)
- mkconc := saveid(w)
- end;
-
- (* Create a new id with name-prefix from w. *)
- function mkuniqname(var t : toknbuf) : idptr;
-
- var i : toknidx;
-
- procedure dig(n : integer);
- begin
- if n > 0 then
- begin
- dig(n div 10);
- if i = maxtoknlen then
- error(eoverflow);
- t[i] := chr(n mod 10 + ord('0')); (* CHAR *)
- i := i + 1
- end
- end;
-
- begin
- i := 1;
- while t[i] <> chr(null) do
- i := i + 1;
- varno := varno + 1;
- dig(varno);
- t[i] := chr(null);
- mkuniqname := saveid(t)
- end;
-
- (* Make a new unique variable with given char as prefix. *)
- function mkvariable(c : char) : idptr;
-
- var t : toknbuf;
-
- begin
- t[1] := c;
- t[2] := chr(null);
- mkvariable := mkuniqname(t)
- end;
-
- (* Make a new unique variable with given char as prefix and *)
- (* with a given id as tail. Commonly used for renaming id's. *)
- function mkrename(c : char; ip : idptr) : idptr;
-
- begin
- mkrename := mkconc(uscore, mkvariable(c), ip)
- end;
-
- (* Make a name for a variant. Variants are mapped onto C unions, *)
- (* which we always give the name "U", thus the name of the variant *)
- (* becomes "U.Vnnn" where "nnn" is a unique number. *)
- function mkvrnt : idptr;
-
- var t : toknbuf;
-
- begin
- t[1] := 'U';
- t[2] := '.';
- t[3] := 'V';
- t[4] := chr(null);
- mkvrnt := mkuniqname(t)
- end;
-
- procedure checksymbol(ss : symset);
- begin
- if not (currsym.st in ss) then
- error(ebadsymbol);
- end;
-
- (* Lexical analysis routine. *)
- (* This procedure reads and classifies the next lexical token in *)
- (* the input stream. The token is saved in the global variable *)
- (* "currsym". The found symbol should be one of the symbols given *)
- (* in the parameter "ss" otherwise the error routine is called. *)
- procedure nextsymbol(ss : symset);
-
- var lastchr : 0 .. maxtoknlen;
-
- (* This function reads the next character from the input *)
- (* and updates "lineno" and "colno" accordingly. *)
- function nextchar : char;
-
- var c : char;
-
- begin
- if eof then
- c := chr(null)
- else begin
- colno := colno + 1;
- if eoln then
- begin
- lineno := lineno + 1;
- colno := 0
- end;
- read(c);
- if echo then
- if colno = 0 then
- writeln
- else
- write(c);
- if c = tab1 then
- colno := ((colno div tabwidth) + 1) * tabwidth
- end;
- if lastchr > 0 then
- begin
- lasttok[lastchr] := c;
- lastchr := lastchr + 1
- end;
- nextchar := c
- end;
-
- (* This function looks at the next input character. *)
- function peekchar : char;
-
- begin
- if eof then
- peekchar := chr(null)
- else
- peekchar := input^
- end;
-
- (* Read and classify the next token. *)
- procedure nexttoken(realok : boolean);
-
- var c : char;
- n : integer;
-
- ready : boolean;
-
- wl : toknidx;
- wb : toknbuf;
-
- (* Determine if c is valid in an identifier. *)
- (* This function assumes a machine collating *)
- (* sequence where letters and digits form conti- *)
- (* gous sequences, CHAR. *)
- function idchar(c : char) : boolean;
-
- begin
- idchar :=
- (c >= 'a') and (c <= 'z') or
- (c >= '0') and (c <= '9') or
- (c >= 'A') and (c <= 'Z') or
- (c = uscore)
- end;
-
- (* Determine if c is valid in a number. CHAR. *)
- function numchar(c : char) : boolean;
-
- begin
- numchar := (c >= '0') and (c <= '9')
- end;
-
- (* Convert a digit to its numeric value. CHAR *)
- function numval(c : char) : integer;
-
- begin
- numval := ord(c) - ord('0')
- end;
-
- (* Determine if the current token is a keyword. *)
- function keywordcheck(var w : toknbuf; l : toknidx) : symtyp;
-
- var n : 1 .. keywordlen;
- i, j, k : 0 .. keytablen;
- wrd : keyword;
- kwc : symtyp;
-
- begin
- (* quick check on token length,
- pascal keywords range from 2 to 9 chars in length *)
- if (l > 1) and (l < keywordlen) then
- begin
- (* could be a keyword, initialize wrd *)
- wrd := keytab[keytablen].wrd;
- (* copy w to wrd *)
- for n := 1 to l do
- wrd[n] := w[n];
-
- (* binary search for tokn,
- relies on symtyp being sorted *)
- i := 0;
- j := keytablen;
- while j > i do
- begin
- k := (i + j) div 2;
- if keytab[k].wrd >= wrd then
- j := k
- else
- i := k + 1
- end;
- if keytab[j].wrd = wrd then
- kwc := keytab[j].sym
- else
- kwc := sid
- end
- else
- kwc := sid;
- keywordcheck := kwc
- end;
-
- begin (* nexttoken *)
- (* don't save blanks/comments *)
- lastchr := 0;
- (* read non-blank character *)
- repeat
- c := nextchar;
- (* skip comments, the two comment delimiters of pascal
- are treated as different if "diffcomm" is true *)
- if c = '{' then
- begin
- repeat
- c := nextchar;
- if diffcomm then
- ready := c = '}'
- else
- ready := ((c = '*') and
- (peekchar = ')'))
- or (c = '}')
- until ready or eof;
- if eof and not ready then
- error(eeofcmnt);
- if (c = '*') and not eof then
- c := nextchar;
- c := space
- end
- else if (c = '(') and (peekchar = '*') then
- begin
- c := nextchar;
- repeat
- c := nextchar;
- if diffcomm then
- ready := (c = '*') and
- (peekchar = ')')
- else
- ready := ((c = '*') and
- (peekchar = ')'))
- or (c = '}')
- until ready or eof;
- if eof and not ready then
- error(eeofcmnt);
- if (c = '*') and not eof then
- c := nextchar;
- c := space
- end
- until (c <> space) and (c <> tab1);
-
- (* save characters from this token and save line- and column-
- numbers for errormessages *)
- lasttok[1] := c;
- lastchr := 2;
- lastcol := colno;
- lastline := lineno;
-
- (* map all CHAR control characters onto "badchr" *)
- if c < okchr then
- c := badchr;
-
- (* decode symbol *)
- with currsym do
- if eof then
- begin
- lasttok[1] := '*';
- lasttok[2] := 'E';
- lasttok[3] := 'O';
- lasttok[4] := 'F';
- lasttok[5] := '*';
- lastchr := 6;
- st := seof
- end
- else
- case c of
-
-
- (* CHAR, chars not in Pascal *)
- '|', '`', '~', '}',
- bslash, uscore, badchr:
- error(ebadchar);
-
- (* identifiers or keywords *)
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
- 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
- 'u', 'v', 'w', 'x', 'y', 'z',
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
- 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
- 'U', 'V', 'W', 'X', 'Y', 'Z':
- begin
- (* read token into buffer *)
- wb[1] := lowercase(c);
- wl := 2;
- while (wl < maxtoknlen) and idchar(peekchar) do
- begin
- wb[wl] := lowercase(nextchar);
- wl := wl + 1
- end;
- if wl >= maxtoknlen then
- begin
- lasttok[lastchr] := chr(null);
- error(elongtokn)
- end;
- (* terminate token and match *)
- wb[wl] := chr(null);
- (* check if keyword/identifier *)
- st := keywordcheck(wb, wl-1);
- if st = sid then
- vid := saveid(wb)
- end;
-
- (* integer or real numbers *)
- '0', '1', '2', '3', '4', '5', '6', '7' ,'8', '9':
- begin
- (* assume integer number, save it in buffer *)
- wb[1] := c;
- wl := 2;
- n := numval(c);
- while numchar(peekchar) do
- begin
- c := nextchar;
- n := n * 10 + numval(c);
- wb[wl] := c;
- wl := wl + 1
- end;
- st := sinteger;
- vint := n;
- if realok then
- begin
- (* accept real numbers *)
- if peekchar = '.' then
- begin
- (* this is a real number *)
- st := sreal;
- wb[wl] := nextchar;
- wl := wl + 1;
- while numchar(peekchar) do
- begin
- wb[wl] := nextchar;
- wl := wl + 1
- end
- end;
- c := peekchar;
- if (c = 'e') or (c = 'E') then
- begin
- (* this is a real number *)
- st := sreal;
- c := nextchar;
- wb[wl] := xpnent;
- wl := wl + 1;
- c := peekchar;
- if (c = '-') or (c = '+') then
- begin
- wb[wl] := nextchar;
- wl := wl + 1
- end;
- while numchar(peekchar) do
- begin
- wb[wl] := nextchar;
- wl := wl + 1
- end
- end;
- if st = sreal then
- begin
- wb[wl] := chr(null);
- vflt := savestr(wb)
- end
- end
- end;
-
- '(':
- if peekchar = '.' then
- begin
- (* some compilers on non-ascii systems
- use (. for [ and .) for ] *)
- c := nextchar;
- st := slbrack
- end
- else
- st := slpar;
- ')':
- st := srpar;
- '[':
- st := slbrack;
- ']':
- st := srbrack;
- '.':
- if peekchar = '.' then
- begin
- c := nextchar;
- st := sdotdot
- end
- else if peekchar = ')' then
- begin
- c := nextchar;
- st := srbrack
- end
- else
- st := sdot;
- ';':
- st := ssemic;
- ':':
- if peekchar = '=' then
- begin
- c := nextchar;
- st := sassign
- end
- else
- st := scolon;
- ',':
- st := scomma;
- '@',
- '^':
- st := sarrow;
- '=':
- st := seq;
- '<':
- if peekchar = '=' then
- begin
- c := nextchar;
- st := sle
- end
- else if peekchar = '>' then
- begin
- c := nextchar;
- st := sne
- end
- else
- st := slt;
- '>':
- if peekchar = '=' then
- begin
- c := nextchar;
- st := sge
- end
- else
- st := sgt;
- '+':
- st := splus;
- '-':
- st := sminus;
- '*':
- st := smul;
- '/':
- st := squot;
- quote:
- begin
- (* assume the symbol is a literal string *)
- wl := 0;
- ready := false;
- repeat
- if eoln then
- begin
- lasttok[lastchr] := chr(null);
- error(ebadstring)
- end;
- c := nextchar;
- if c = quote then
- if peekchar = quote then
- c := nextchar
- else
- ready := true;
- if c = chr(null) then
- begin
- if eof then
- error(eeofstr);
- lasttok[lastchr] := chr(null);
- error(enulchr)
- end;
- if not ready then
- begin
- wl := wl + 1;
- if wl >= maxtoknlen then
- begin
- lasttok[lastchr] :=
- chr(null);
- error(elongstring)
- end;
- wb[wl] := c
- end
- until ready;
- if wl = 1 then
- begin
- (* only 1 character => not a string *)
- st := schar;
- vchr := wb[1]
- end
- else begin
- (* > 1 character => its a string *)
- wl := wl + 1;
- if wl >= maxtoknlen then
- begin
- lasttok[lastchr] := chr(null);
- error(elongstring)
- end;
- wb[wl] := chr(null);
- st := sstring;
- vstr := savestr(wb)
- end
- end
-
- end;(* case *)
- if lastchr = 0 then
- lastchr := 1;
- lasttok[lastchr] := chr(null)
- end; (* nexttoken *)
-
- begin (* nextsymbol *)
- nexttoken(sreal in ss);
- checksymbol(ss)
- end; (* nextsymbol *)
-
- (* Return a pointer to the node describing the type of tp. This *)
- (* function also stores the result in the node for future ref. *)
- function typeof(tp : treeptr) : treeptr;
-
- var tf, tq : treeptr;
-
- begin
- tq := tp;
- tf := tq^.ttype;
- (* keep working until a type is found *)
- while tf = nil do
- begin
- case tq^.tt of
- nchar:
- tf := typnods[tchar];
-
- ninteger:
- tf := typnods[tinteger];
-
- nreal:
- tf := typnods[treal];
-
- nstring:
- tf := typnods[tstring];
-
- nnil:
- tf := typnods[tnil];
-
- nid:
- begin
- tq := idup(tq);
- if tq = nil then
- fatal(etree)
- end;
-
- ntype,
- nvar,
- nconst,
- nfield,
- nvalpar,
- nvarpar:
- tq := tq^.tbind;
-
- npredef,
- nptr,
- nscalar,
- nrecord,
- nconfarr,
- narray,
- nfileof,
- nsetof:
- tf := tq; (* these nodetypes represent types *)
-
- nsubrange:
- if tq^.tup^.tt = nconfarr then
- tf := tq^.tup^.tindtyp
- else
- tf := tq;
-
- ncall:
- begin
- tf := typeof(tq^.tcall);
- if tf = typnods[tpoly] then
- tf := typeof(tq^.taparm)
- end;
-
- nfunc:
- tq := tq^.tfuntyp;
-
- nparfunc:
- tq := tq^.tpartyp;
-
- nproc,
- nparproc:
- tf := typnods[tnone];
-
- nvariant,
- nlabel,
- npgm,
- nempty,
- nbegin,
- nlabstmt,
- nassign,
- npush,
- npop,
- nif,
- nwhile,
- nrepeat,
- nfor,
- ncase,
- nchoise,
- ngoto,
- nwith,
- nwithvar:
- fatal(etree);
-
- nformat,
- nrange:
- tq := tq^.texpl;
-
- nplus,
- nminus,
- nmul:
- begin
- tf := typeof(tq^.texpl);
- if tf = typnods[tinteger] then
- tf := typeof(tq^.texpr)
- else if tf^.tt = nsetof then
- tf := typnods[tset]
- end;
-
- numinus,
- nuplus:
- tq := tq^.texps;
-
- nmod,
- ndiv:
- tf := typnods[tinteger];
-
- nquot:
- tf := typnods[treal];
-
- neq,
- nne,
- nlt,
- nle,
- ngt,
- nge,
- nin,
- nor,
- nand,
- nnot:
- tf := typnods[tboolean];
-
- nset:
- tf := typnods[tset];
-
- nselect:
- tq := tq^.tfield;
-
- nderef:
- begin
- tq := typeof(tq^.texps);
- case tq^.tt of
- nptr:
- tq := tq^.tptrid;
- nfileof:
- tq := tq^.tof;
- npredef:
- tf := typnods[tchar] (* textfile *)
- end (* case *)
- end;
-
- nindex:
- begin
- tq := typeof(tq^.tvariable);
- if tq^.tt = nconfarr then
- tq := tq^.tcelem
- else if tq = typnods[tstring] then
- tf := typnods[tchar]
- else
- tq := tq^.taelem
- end;
-
- end (* case *)
- end;
- if tp^.ttype = nil then
- tp^.ttype := tf; (* remember type for future reference *)
- typeof := tf
- end; (* typeof *)
-
- (* Connect all nodes to their fathers. *)
- procedure linkup(up, tp : treeptr);
-
- begin
- while tp <> nil do
- begin
- if tp^.tup = nil then
- begin
- tp^.tup := up;
- case tp^.tt of
- npgm,
- nfunc,
- nproc:
- begin
- linkup(tp, tp^.tsubid);
- linkup(tp, tp^.tsubpar);
- linkup(tp, tp^.tfuntyp);
- linkup(tp, tp^.tsublab);
- linkup(tp, tp^.tsubconst);
- linkup(tp, tp^.tsubtype);
- linkup(tp, tp^.tsubvar);
- linkup(tp, tp^.tsubsub);
- linkup(tp, tp^.tsubstmt)
- end;
-
-
- nvalpar,
- nvarpar,
- nconst,
- ntype,
- nfield,
- nvar:
- begin
- linkup(tp, tp^.tidl);
- linkup(tp, tp^.tbind)
- end;
-
- nparproc,
- nparfunc:
- begin
- linkup(tp, tp^.tparid);
- linkup(tp, tp^.tparparm);
- linkup(tp, tp^.tpartyp)
- end;
-
- nptr:
- linkup(tp, tp^.tptrid);
- nscalar:
- linkup(tp, tp^.tscalid);
-
- nsubrange:
- begin
- linkup(tp, tp^.tlo);
- linkup(tp, tp^.thi)
- end;
- nvariant:
- begin
- linkup(tp, tp^.tselct);
- linkup(tp, tp^.tvrnt)
- end;
- nrecord:
- begin
- linkup(tp, tp^.tflist);
- linkup(tp, tp^.tvlist)
- end;
- nconfarr:
- begin
- linkup(tp, tp^.tcindx);
- linkup(tp, tp^.tcelem);
- linkup(tp, tp^.tindtyp)
- end;
- narray:
- begin
- linkup(tp, tp^.taindx);
- linkup(tp, tp^.taelem)
- end;
- nfileof,
- nsetof:
- linkup(tp, tp^.tof);
- nbegin:
- linkup(tp, tp^.tbegin);
- nlabstmt:
- begin
- linkup(tp, tp^.tlabno);
- linkup(tp, tp^.tstmt)
- end;
- nassign:
- begin
- linkup(tp, tp^.tlhs);
- linkup(tp, tp^.trhs)
- end;
- npush,
- npop:
- begin
- linkup(tp, tp^.tglob);
- linkup(tp, tp^.tloc);
- linkup(tp, tp^.ttmp)
- end;
- ncall:
- begin
- linkup(tp, tp^.tcall);
- linkup(tp, tp^.taparm )
- end;
- nif:
- begin
- linkup(tp, tp^.tifxp);
- linkup(tp, tp^.tthen);
- linkup(tp, tp^.telse)
- end;
- nwhile:
- begin
- linkup(tp, tp^.twhixp);
- linkup(tp, tp^.twhistmt)
- end;
- nrepeat:
- begin
- linkup(tp, tp^.treptstmt);
- linkup(tp, tp^.treptxp)
- end;
- nfor:
- begin
- linkup(tp, tp^.tforid);
- linkup(tp, tp^.tfrom);
- linkup(tp, tp^.tto);
- linkup(tp, tp^.tforstmt)
- end;
- ncase:
- begin
- linkup(tp, tp^.tcasxp);
- linkup(tp, tp^.tcaslst);
- linkup(tp, tp^.tcasother)
- end;
- nchoise:
- begin
- linkup(tp, tp^.tchocon);
- linkup(tp, tp^.tchostmt)
- end;
- nwith:
- begin
- linkup(tp, tp^.twithvar);
- linkup(tp, tp^.twithstmt)
- end;
- nwithvar:
- linkup(tp, tp^.texpw);
- nindex:
- begin
- linkup(tp, tp^.tvariable);
- linkup(tp, tp^.toffset)
- end;
- nselect:
- begin
- linkup(tp, tp^.trecord);
- linkup(tp, tp^.tfield)
- end;
-
- ngoto:
- linkup(tp, tp^.tlabel);
-
- nrange, nformat,
- nin, neq,
- nne, nlt, nle,
- ngt, nge, nor,
- nplus, nminus,
- nand, nmul,
- ndiv, nmod,
- nquot:
- begin
- linkup(tp, tp^.texpl);
- linkup(tp, tp^.texpr)
- end;
-
- nderef,
- nnot, nset,
- numinus,
- nuplus:
- linkup(tp, tp^.texps);
-
- nid,
- nnil, ninteger,
- nreal, nchar,
- nstring, npredef,
- nlabel, nempty:
- (* no op *)
- end (* case *)
- end;
- tp := tp^.tnext
- end
- end; (* linkup *)
-
- (* Allocate a new symbol node. *)
- function mksym(vt : ltypes) : symptr;
-
- var mp : symptr;
-
- begin
- new(mp);
- if mp = nil then
- error(enew);
- mp^.lt := vt;
- mp^.lnext := nil;
- mp^.lsymdecl := nil;
- mp^.ldecl := nil;
- mksym := mp
- end;
-
- (* Enter a symbol at current declarationlevel. *)
- procedure declsym(sp : symptr);
-
- var h : hashtyp;
-
- begin
- if sp^.lt in [lpredef, lidentifier, lfield, lforward, lpointer] then
- h := sp^.lid^.ihash
- else
- h := hashmax;
- sp^.lnext := symtab^.ddecl[h];
- symtab^.ddecl[h] := sp;
- sp^.ldecl := symtab
- end;
-
- (* Create a node of selected type. *)
- function mknode(nt : treetyp) : treeptr;
-
- var tp : treeptr;
-
- begin
- tp := nil;
- case nt of
- npredef: new(tp, npredef);
- npgm: new(tp, npgm);
- nfunc: new(tp, nfunc);
- nproc: new(tp, nproc);
- nlabel: new(tp, nlabel);
- nconst: new(tp, nconst);
- ntype: new(tp, ntype);
- nvar: new(tp, nvar);
- nvalpar: new(tp, nvalpar);
- nvarpar: new(tp, nvarpar);
- nparproc: new(tp, nparproc);
- nparfunc: new(tp, nparfunc);
- nsubrange: new(tp, nsubrange);
- nvariant: new(tp, nvariant);
- nfield: new(tp, nfield);
- nrecord: new(tp, nrecord);
- nconfarr: new(tp, nconfarr);
- narray: new(tp, narray);
- nfileof: new(tp, nfileof);
- nsetof: new(tp, nsetof);
- nbegin: new(tp, nbegin);
- nptr: new(tp, nptr);
- nscalar: new(tp, nscalar);
- nif: new(tp, nif);
- nwhile: new(tp, nwhile);
- nrepeat: new(tp, nrepeat);
- nfor: new(tp, nfor);
- ncase: new(tp, ncase);
- nchoise: new(tp, nchoise);
- ngoto: new(tp, ngoto);
- nwith: new(tp, nwith);
- nwithvar: new(tp, nwithvar);
- nempty: new(tp, nempty);
- nlabstmt: new(tp, nlabstmt);
- nassign: new(tp, nassign);
- nformat: new(tp, nformat);
- nin: new(tp, nin);
- neq: new(tp, neq);
- nne: new(tp, nne);
- nlt: new(tp, nlt);
- nle: new(tp, nle);
- ngt: new(tp, ngt);
- nge: new(tp, nge);
- nor: new(tp, nor);
- nplus: new(tp, nplus);
- nminus: new(tp, nminus);
- nand: new(tp, nand);
- nmul: new(tp, nmul);
- ndiv: new(tp, ndiv);
- nmod: new(tp, nmod);
- nquot: new(tp, nquot);
- nnot: new(tp, nnot);
- numinus: new(tp, numinus);
- nuplus: new(tp, nuplus);
- nset: new(tp, nset);
- nrange: new(tp, nrange);
- nindex: new(tp, nindex);
- nselect: new(tp, nselect);
- nderef: new(tp, nderef);
- ncall: new(tp, ncall);
- nid: new(tp, nid);
- nchar: new(tp, nchar);
- ninteger: new(tp, ninteger);
- nreal: new(tp, nreal);
- nstring: new(tp, nstring);
- nnil: new(tp, nnil);
- npush: new(tp, npush);
- npop: new(tp, npop);
- nbreak: new(tp, nbreak)
- end;(* case *)
- if tp = nil then
- error(enew);
- tp^.tt := nt;
- tp^.tnext := nil;
- tp^.tup := nil;
- tp^.ttype := nil;
- mknode := tp
- end;
-
- (* Create a node with a literal value. *)
- function mklit : treeptr;
-
- var sp : symptr;
- tp : treeptr;
-
- begin
- case currsym.st of
- sinteger:
- begin
- sp := mksym(linteger);
- sp^.linum := currsym.vint;
- tp := mknode(ninteger);
- end;
- sreal:
- begin
- sp := mksym(lreal);
- sp^.lfloat := currsym.vflt;
- tp := mknode(nreal);
- end;
- schar:
- begin
- sp := mksym(lcharacter);
- sp^.lchar := currsym.vchr;
- tp := mknode(nchar);
- end;
- sstring:
- begin
- sp := mksym(lstring);
- sp^.lstr := currsym.vstr;
- tp := mknode(nstring);
- end
- end;(* case *)
- tp^.tsym := sp;
- sp^.lsymdecl := tp;
- mklit := tp
- end;
-
- (* Look up an identifier among declared symbols. *)
- function lookupid(ip : idptr; fieldok : boolean) : symptr;
-
- label 999;
-
- var sp : symptr;
- dp : declptr;
- vs : set of ltypes;
-
- begin
- lookupid := nil;
- if fieldok then
- vs := [lidentifier, lforward, lpointer, lfield]
- else
- vs := [lidentifier, lforward, lpointer];
- sp := nil;
-
- (* pick up symboltable from innermost scope *)
- dp := symtab;
- while dp <> nil do
- begin
- (* scan linked symbols with same hasvalue *)
- sp := dp^.ddecl[ip^.ihash];
- while sp <> nil do
- begin
- (* break out when proper id found *)
- if (sp^.lt in vs) and (sp^.lid = ip) then
- goto 999;
- sp := sp^.lnext
- end;
- (* proceed to enclosing scope *)
- dp := dp^.dprev
- end;
- 999:
- lookupid := sp
- end;
-
- (* Look up a label. *)
- function lookuplabel(i : integer) : symptr;
-
- label 999;
-
- var sp : symptr;
- dp : declptr;
-
- begin
- sp := nil;
- dp := symtab;
- while dp <> nil do
- begin
- sp := dp^.ddecl[hashmax];
- while sp <> nil do
- begin
- if (sp^.lt in [lforwlab, llabel]) and (sp^.lno = i) then
- goto 999;
- sp := sp^.lnext
- end;
- dp := dp^.dprev
- end;
- 999:
- lookuplabel := sp
- end;
-
- (* Create a new declaration level (a new scope) link declnode to *)
- (* previous node. dp is non-nil when a procedure/function body *)
- (* is encountered for which we have seen a forward declaration. *)
- procedure enterscope(dp : declptr);
-
- var h : hashtyp;
-
- begin
- if dp = nil then
- begin
- new(dp);
- for h := 0 to hashmax do
- dp^.ddecl[h] := nil
- end;
- dp^.dprev := symtab;
- symtab := dp
- end;
-
- (* Return current scope (as a pointer to symbol-table). *)
- function currscope : declptr;
-
- begin
- currscope := symtab
- end;
-
- (* Drop innermost declaration scope. *)
- procedure leavescope;
-
- begin
- symtab := symtab^.dprev
- end;
-
- (* Create a new identifier symbol. *)
- function mkid(ip : idptr) : symptr;
-
- var sp : symptr;
-
- begin
- sp := mksym(lidentifier);
- sp^.lid := ip;
- sp^.lused := false;
- declsym(sp);
- ip^.inref := ip^.inref + 1;
- mkid := sp
- end;
-
- (* Check that the current identifier is new then save it in the *)
- (* current scope. Create and return a new node representing this *)
- (* instance of the identifier. *)
- function newid(ip : idptr) : treeptr;
-
- var sp : symptr;
- tp : treeptr;
-
- begin
- sp := lookupid(ip, false);
- if sp <> nil then
- if sp^.ldecl <> symtab then
- sp := nil;
- if sp = nil then
- begin
- (* new identifier *)
- tp := mknode(nid);
- sp := mkid(ip);
- sp^.lsymdecl := tp;
- tp^.tsym := sp
- end
- else if sp^.lt = lpointer then
- begin
- (* previously declared as a pointer type *)
- tp := mknode(nid);
- tp^.tsym := sp;
- sp^.lt := lidentifier;
- sp^.lsymdecl := tp
- end
- else if sp^.lt = lforward then
- begin
- (* previously forward declared *)
- sp^.lt := lidentifier;
- tp := sp^.lsymdecl
- end
- else
- error(emultdeclid);
- newid := tp
- end;
-
- (* Check that the current identifier is already declared, *)
- (* we fail unless l in [lforward, lpointer]. *)
- (* Create and return a new node referencing it. *)
- function oldid(ip : idptr; l : ltypes) : treeptr;
-
- var sp : symptr;
- tp : treeptr;
-
- begin
- sp := lookupid(ip, true);
- if sp = nil then
- begin
- if l in [lforward, lpointer] then
- begin
- tp := newid(ip);
- tp^.tsym^.lt := l
- end
- else
- error(enotdeclid)
- end
- else begin
- sp^.lused := true;
- tp := mknode(nid);
- tp^.tsym := sp;
- if (sp^.lt = lpointer) and (l = lidentifier) then
- begin
- sp^.lt := lidentifier;
- sp^.lsymdecl := tp
- end
- end;
- oldid := tp
- end;
-
- (* Look up a field in a record declaration. *)
- (* Return nil if field isn't declared in "tp" or its variants. *)
- function oldfield(tp : treeptr; ip : idptr) : treeptr;
-
- label 999;
-
- var tq, ti,
- fp : treeptr;
-
- begin
- fp := nil;
- tq := tp^.tflist;
- while tq <> nil do
- begin
- ti := tq^.tidl;
- while ti <> nil do
- begin
- if ti^.tsym^.lid = ip then
- begin
- fp := mknode(nid);
- fp^.tsym := ti^.tsym;
- goto 999
- end;
- ti := ti^.tnext
- end;
- tq := tq^.tnext
- end;
- tq := tp^.tvlist;
- while tq <> nil do
- begin
- fp := oldfield(tq^.tvrnt, ip);
- if fp <> nil then
- tq := nil
- else
- tq := tq^.tnext
- end;
- 999:
- oldfield := fp
- end;
-
- (* This is the main parsing routine. It parses a correct pascal- *)
- (* program and builds a parsetree which is left in the global *)
- (* variable top. *)
- (* Parsing is done through recursive descent using a set of *)
- (* mutually recursive functions. *)
- procedure parse;
-
- function plabel : treeptr; forward;
- function pidlist(l : ltypes) : treeptr; forward;
- function pconst : treeptr; forward;
- function pconstant(realok : boolean) : treeptr; forward;
- function precord(cs : symtyp; dp : declptr) : treeptr; forward;
- function ptypedef : treeptr; forward;
- function ptype : treeptr; forward;
- function pvar : treeptr; forward;
- function psubs : treeptr; forward;
- function psubpar : treeptr; forward;
- function plabstmt : treeptr; forward;
- function pstmt : treeptr; forward;
- function psimple : treeptr; forward;
- function pvariable(varptr : treeptr) : treeptr; forward;
- function pexpr(tnp : treeptr) : treeptr; forward;
- function pcase : treeptr; forward;
- function pif : treeptr; forward;
- function pwhile : treeptr; forward;
- function prepeat : treeptr; forward;
- function pfor : treeptr; forward;
- function pwith : treeptr; forward;
- function pgoto : treeptr; forward;
- function pbegin(retain : boolean) : treeptr; forward;
-
- (* Open scope of a record variable. *)
- procedure scopeup(tp : treeptr);
-
- (* Scan a record-declaration and add all fields to *)
- (* current scope. *)
- procedure addfields(rp : treeptr);
-
- var fp, ip, vp : treeptr;
- sp : symptr;
-
- begin
- fp := rp^.tflist;
- while fp <> nil do
- begin
- ip := fp^.tidl;
- while ip <> nil do
- begin
- sp := mksym(lfield);
- sp^.lid := ip^.tsym^.lid;
- sp^.lused := false;
- sp^.lsymdecl := ip;
- declsym(sp);
- ip := ip^.tnext
- end;
- fp := fp^.tnext
- end;
- vp := rp^.tvlist;
- while vp <> nil do
- begin
- addfields(vp^.tvrnt);
- vp := vp^.tnext
- end
- end;
- begin
- addfields(typeof(tp))
- end;
-
- (* Check that the current label is new then save it in the *)
- (* current scope. Create and return a new node referencing *)
- (* the label. *)
- function newlbl : treeptr;
-
- var sp : symptr;
- tp : treeptr;
-
- begin
- tp := mknode(nlabel);
- sp := lookuplabel(currsym.vint);
- if sp <> nil then
- if sp^.ldecl <> symtab then
- sp := nil;
- if sp = nil then
- begin
- sp := mksym(lforwlab);
- sp^.lno := currsym.vint;
- sp^.lgo := false;
- sp^.lsymdecl := tp;
- declsym(sp)
- end
- else
- error(emultdecllab);
- tp^.tsym := sp;
- newlbl := tp
- end;
-
- (* Check that the current label is already declared. *)
- (* Create and return a new node referencing it. *)
- function oldlbl(defpt : boolean) : treeptr;
-
- var sp : symptr;
- tp : treeptr;
-
- begin
- sp := lookuplabel(currsym.vint);
- if sp = nil then
- begin
- prtmsg(enotdecllab);
- tp := newlbl;
- sp := tp^.tsym
- end
- else begin
- tp := mknode(nlabel);
- tp^.tsym := sp
- end;
- if defpt then
- begin
-
-