home *** CD-ROM | disk | FTP | other *** search
- external;
-
- {
- Declarations.p (of PCQ Pascal)
- Copyright (c) 1989 Patrick Quaid
-
- Generally speaking, this module handles the various
- declarations. The major exception to this is doblock(), in main.p,
- which might be considered a declaration.
- }
-
- const
- {$I "pasconst.i"}
-
- type
- {$I "pastype.i"}
-
- var
- {$I "pasvar.i"}
-
- procedure enterspell(s : string);
- forward;
- function enterstandard(a, b, c, d, e, f, g : integer) : integer;
- forward;
- function match(i : integer): boolean;
- forward;
- procedure error(s : string);
- forward;
- function conexpr(var i : integer): integer;
- forward;
- function addtype(i, j, k, l, m, n : integer): integer;
- forward;
- function declvar(r, f : integer) : integer;
- forward;
- procedure ns;
- forward;
- function typecmp(f, s : integer): boolean;
- forward;
- function findid(s: string): integer;
- forward;
- function checkid(s : string; f : integer): integer;
- forward;
- procedure nextsymbol;
- forward;
- procedure needrightparent;
- forward;
-
- procedure reformargs;
-
- {
- This is the first in a series of routines that assigns the
- proper addresses to procedure or function arguments.
- }
-
- var
- index : integer;
- typeindex : integer;
- begin
- index := idents[currfn].indtype;
- while index <> 0 do begin
- if idents[index].object = valarg then begin
- typeindex := idents[index].vtype;
- argstk := argstk - idents[typeindex].size;
- if odd(argstk) then
- argstk := argstk - 1;
- idents[index].offset := argstk + 8;
- if idents[typeindex].size = 1 then
- idents[index].offset := idents[index].offset + 1;
- end else if idents[index].object = refarg then begin
- argstk := argstk - 4;
- idents[index].offset := argstk + 8;
- end;
- index := idents[index].indtype;
- end;
- end;
-
- function reformvars(firstindex : integer) : integer;
-
- {
- reformvars does a similar job for a block's local
- variables.
- }
-
- var
- index : integer;
- typesize : integer;
- off : integer;
- begin
- off := 0;
- index := firstindex;
- while index < identptr do begin
- if idents[index].object = local then begin
- typesize := idents[index].vtype;
- typesize := idents[typesize].size;
- if odd(abs(off)) and (typesize <> 1) then
- off := off - 1;
- off := off - typesize;
- idents[index].offset := off;
- end;
- index := index + 1;
- end;
- if odd(abs(off)) then
- off := off - 1;
- reformvars := off;
- end;
-
- function reformfields(startindex : integer): integer;
-
- {
- This routine is much like the previous two. It cleans up
- the addresses of the fields of a record.
- }
-
- var
- index : integer;
- totalsize : integer;
- typeindex : integer;
- begin
- index := idents[startindex].indtype;
- totalsize := 0;
- while index <> 0 do begin
- typeindex := idents[index].vtype;
- typeindex := idents[typeindex].size;
- if odd(totalsize) and (typeindex > 1) then
- totalsize := totalsize + 1;
- idents[index].offset := totalsize;
- totalsize := totalsize + typeindex;
- index := idents[index].indtype;
- end;
- if odd(totalsize) then
- totalsize := totalsize + 1;
- reformfields := totalsize;
- end;
-
- function addproc(procname : string; isfunction : boolean): integer;
-
- {
- This just adds a procedure to the identifier array.
- Hmmm... sounds like this belongs in utilities.p
- }
-
- begin
- idents[identptr].name := string(integer(adr(spelling)) + spellptr - 1);
- enterspell(procname);
- if isfunction then
- idents[identptr].object := func
- else
- idents[identptr].object := proc;
- idents[identptr].offset := 0;
- idents[identptr].vtype := 0;
- idents[identptr].upper := 0;
- idents[identptr].lower := 0;
- idents[identptr].size := 0;
- idents[identptr].indtype := 0;
- identptr := identptr + 1;
- addproc := identptr - 1;
- end;
-
- procedure getrange(var typerec : idrecord);
-
- {
- This is rather a mistake, actually. The routine that
- declares arrays ought to just look for a range type inside the
- brackets, but instead it uses this routine to look for an explicit
- range. When I add range types to the language, this will fix
- itself.
- }
-
- var
- lowindex : integer;
- highindex : integer;
- begin
- typerec.lower := conexpr(lowindex);
- if not match(dotdot1) then
- error("expecting '..' here");
- typerec.upper := conexpr(highindex);
- if not typecmp(lowindex, highindex) then begin
- error("incompatible range types");
- typerec.upper := typerec.lower;
- end;
- if typerec.lower > typerec.upper then begin
- error("lower bound greater than upper bound");
- typerec.object := typerec.lower;
- typerec.lower := typerec.upper;
- typerec.upper := typerec.object;
- end;
- typerec.indtype := lowindex;
- end;
-
- function readrecord(predname : string): integer;
-
- {
- This just reads a record. Note that I had to do a bit of
- gymnastics in order to handle a field that's a pointer to its
- parent record.
- }
-
- var
- typeindex : integer;
- startindex : integer;
- begin
- startindex := addtype(vrecord, 0, 0, 0, 0, 0);
- if predname <> string(0) then
- idents[startindex].name := predname
- else
- idents[startindex].name := string(adr(spelling));
- prevarg := startindex;
- while currsym = ident1 do begin
- typeindex := declvar(field, startindex);
- ns;
- end;
- if not match(end1) then
- error("Missing END of record");
- idents[startindex].size := reformfields(startindex);
- idents[startindex].name := string(adr(spelling));
- readrecord := startindex;
- end;
-
- function readenumeration(): integer;
-
- {
- This just reads enumerations and assigns them numbers
- starting with zero.
- }
-
- var
- position : integer;
- enumtype : integer;
- previous : integer;
- current : integer;
- begin
- position := 0;
- enumtype := addtype(vordinal, 0, 0, 0, 2, 0);
- previous := enumtype;
- while currsym = ident1 do begin
- if findid(symtext) <> 0 then
- error("Duplicate ID");
- current := enterstandard(constant, position, enumtype, 0, 0, 0, 0);
- enterspell(symtext);
- idents[previous].indtype := current;
- previous := current;
- position := position + 1;
- nextsymbol;
- if currsym <> rightparent1 then
- if not match(comma1) then
- error("missing comma");
- end;
- needrightparent;
- readenumeration := enumtype;
- end;
-
- function readtype(predname : string): integer;
-
- {
- This is a bit of a monster function, but needs yet more
- stuff (like ranges). The pointer part should have support for a
- pointer to an as-yet-unknown-id. This routine returns the index of
- the type produced by the type declaration. Note that I use the
- same routine almost wherever I need a type, which is why you can
- use a full type description most places.
- }
-
- var
- typeindex : integer;
- typerec : idrecord;
- tempint : integer;
- begin
- if currsym = ident1 then begin
- typeindex := findid(symtext);
- if (typeindex = 0) or
- (idents[typeindex].object <> obtype) then begin
- error("looking for a type description here.");
- typeindex := badtype;
- end;
- nextsymbol;
- end else if match(carat1) then begin
- typeindex := readtype(string(0));
- typeindex := addtype(vpointer, typeindex, 0, 0, 4, 0);
- end else if match(leftparent1) then
- typeindex := readenumeration()
- else if match(array1) then begin
- if not match(leftbrack1) then
- error("expecting leftbracket");
- getrange(typerec);
- if not match(rightbrack1) then
- error("expecting a right bracket");
- if not match(of1) then
- error("expecting OF");
- typeindex := readtype(string(0));
- typerec.size := (typerec.upper - typerec.lower + 1) *
- idents[typeindex].size;
- typeindex := addtype(varray, typeindex, typerec.upper,
- typerec.lower, typerec.size, typerec.indtype);
- end else if match(record1) then begin
- typeindex := readrecord(predname);
- end else if match(file1) then begin
- if not match(of1) then
- error("expecting OF");
- typeindex := readtype(string(0));
- typeindex := addtype(vfile, typeindex,
- idents[typeindex].size, 0, 18, 0);
- end else begin
- error("unknown type of thing");
- typeindex := badtype;
- end;
- readtype := typeindex;
- end;
-
- procedure decltype(firstpos : integer);
-
- {
- This handles a type declaration block.
- }
-
- var
- typeindex : integer;
- spellindex : string;
- begin
- while currsym = ident1 do begin
- if checkid(symtext, firstpos) <> 0 then
- error("duplicate id");
- spellindex := string(integer(adr(spelling)) + spellptr - 1);
- enterspell(symtext);
- nextsymbol;
- if not match(equal1) then
- error("expecting '=' here");
- typeindex := readtype(spellindex);
- ns;
- if typeindex <> 0 then begin
- if idents[typeindex].name = string(adr(spelling)) then
- idents[typeindex].name := spellindex
- else begin
- typeindex := addtype(vsynonym, typeindex, 0, 0,
- idents[typeindex].size, 0);
- idents[typeindex].name := spellindex;
- end;
- end;
- end;
- end;
-
- function addvar(varname : string; varob, vartype, varoff : integer) : integer;
-
- {
- I suppose this too belong in utilities.p
- }
-
- begin
- idents[identptr].name := string(integer(adr(spelling)) + spellptr - 1);
- enterspell(varname);
- idents[identptr].object := varob;
- idents[identptr].offset := varoff;
- idents[identptr].vtype := vartype;
- idents[identptr].upper := 0;
- idents[identptr].lower := 0;
- idents[identptr].size := 0;
- idents[identptr].indtype := 0;
- identptr := identptr + 1;
- addvar := identptr - 1;
- end;
-
- procedure declvar(storage, firstpos : integer);
-
- {
- This is used to declare a parameter, local variable, global
- variable, field, whatever. It's also the reason I need the
- reform things above.
- }
-
- var
- typeindex : integer;
- varindex : integer;
- typesize : integer;
- begin
- if currsym = ident1 then begin
- if (storage = global) or (storage = local) then begin
- if checkid(symtext, firstpos) <> 0 then
- error("Duplicate id");
- varindex := addvar(symtext, storage, 0, 0)
- end else if (storage = valarg) or (storage = refarg) or
- (storage = field) then begin
- if checkid(symtext, firstpos) <> 0 then
- error("duplicate ID");
- varindex := addvar(symtext, storage, 0, 0);
- idents[prevarg].indtype := varindex;
- prevarg := varindex;
- end;
- nextsymbol;
- if match(comma1) then
- typeindex := declvar(storage, firstpos)
- else begin
- if not match(colon1) then
- error("expecting :");
- typeindex := readtype(string(0));
- end;
- if typeindex <> 0 then begin
- idents[varindex].vtype := typeindex;
- if storage = valarg then begin
- typesize := idents[typeindex].size;
- if odd(typesize) then
- typesize := typesize + 1;
- argstk := argstk + typesize;
- end else if storage = refarg then
- argstk := argstk + 4;
- end;
- end else begin
- error("expecting an identifier");
- if match(colon1) then
- typeindex := readtype(string(0));
- end;
- declvar := typeindex;
- end;
-
- procedure vardeclarations(firstpos : integer);
-
- {
- This handles a variable declaration block.
- }
-
- var
- typeindex : integer;
- begin
- while currsym = ident1 do begin
- if blocklevel = 0 then begin
- typeindex := declvar(global, firstpos);
- ns;
- end else begin
- typeindex := declvar(local, firstpos);
- ns;
- end
- end;
- end;
-
- function addcon(conname : string) : integer;
-
- {
- How did all these get in here?
- }
-
- begin
- idents[identptr].name := string(integer(adr(spelling)) + spellptr - 1);
- enterspell(conname);
- idents[identptr].object := constant;
- idents[identptr].offset := 0;
- idents[identptr].vtype := 0;
- idents[identptr].upper := 0;
- idents[identptr].lower := 0;
- idents[identptr].size := 0;
- idents[identptr].indtype := 0;
- identptr := identptr + 1;
- addcon := identptr - 1;
- end;
-
- procedure declconst(firstpos : integer);
-
- {
- This handles a const declaration block. The grunt work is
- does by conexpr() in expression.p, which is the routine to look at
- if you want to improve constant declarations.
- }
-
- var
- conindex : integer;
- typeindex : integer;
- begin
- while currsym = ident1 do begin
- if checkid(symtext, firstpos) <> 0 then
- error("Duplicate ID");
- conindex := addcon(symtext);
- nextsymbol;
- if not match(equal1) then
- error("expecting =");
- idents[conindex].offset := conexpr(typeindex);
- idents[conindex].vtype := typeindex;
- ns;
- end;
- end;
-