home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d1xx / d183 / pcq.lha / PCQ / Source / Declarations.p < prev    next >
Text File  |  1989-02-26  |  12KB  |  477 lines

  1. external;
  2.  
  3. {
  4.     Declarations.p (of PCQ Pascal)
  5.     Copyright (c) 1989 Patrick Quaid
  6.  
  7.     Generally speaking, this module handles the various
  8. declarations.  The major exception to this is doblock(), in main.p,
  9. which might be considered a declaration.
  10. }
  11.  
  12. const
  13. {$I "pasconst.i"}
  14.  
  15. type
  16. {$I "pastype.i"}
  17.  
  18. var
  19. {$I "pasvar.i"}
  20.  
  21.     procedure enterspell(s : string);
  22.         forward;
  23.     function enterstandard(a, b, c, d, e, f, g : integer) : integer;
  24.         forward;
  25.     function match(i : integer): boolean;
  26.         forward;
  27.     procedure error(s : string);
  28.         forward;
  29.     function conexpr(var i : integer): integer;
  30.         forward;
  31.     function addtype(i, j, k, l, m, n : integer): integer;
  32.         forward;
  33.     function declvar(r, f : integer) : integer;
  34.         forward;
  35.     procedure ns;
  36.         forward;
  37.     function typecmp(f, s : integer): boolean;
  38.         forward;
  39.     function findid(s: string): integer;
  40.         forward;
  41.     function checkid(s : string; f : integer): integer;
  42.         forward;
  43.     procedure nextsymbol;
  44.         forward;
  45.     procedure needrightparent;
  46.         forward;
  47.  
  48. procedure reformargs;
  49.  
  50. {
  51.     This is the first in a series of routines that assigns the
  52. proper addresses to procedure or function arguments.
  53. }
  54.  
  55. var
  56.     index    : integer;
  57.     typeindex    : integer;
  58. begin
  59.     index := idents[currfn].indtype;
  60.     while index <> 0 do begin
  61.     if idents[index].object = valarg then begin
  62.         typeindex := idents[index].vtype;
  63.         argstk := argstk - idents[typeindex].size;
  64.         if odd(argstk) then
  65.         argstk := argstk - 1;
  66.         idents[index].offset := argstk + 8;
  67.         if idents[typeindex].size = 1 then
  68.         idents[index].offset := idents[index].offset + 1;
  69.     end else if idents[index].object = refarg then begin
  70.         argstk := argstk - 4;
  71.         idents[index].offset := argstk + 8;
  72.     end;
  73.     index := idents[index].indtype;
  74.     end;
  75. end;
  76.  
  77. function reformvars(firstindex : integer) : integer;
  78.  
  79. {
  80.     reformvars does a similar job for a block's local
  81. variables.
  82. }
  83.  
  84. var
  85.     index    : integer;
  86.     typesize    : integer;
  87.     off        : integer;
  88. begin
  89.     off := 0;
  90.     index := firstindex;
  91.     while index < identptr do begin
  92.     if idents[index].object = local then begin
  93.         typesize := idents[index].vtype;
  94.         typesize := idents[typesize].size;
  95.         if odd(abs(off)) and (typesize <> 1) then
  96.         off := off - 1;
  97.         off := off - typesize;
  98.         idents[index].offset := off;
  99.     end;
  100.     index := index + 1;
  101.     end;
  102.     if odd(abs(off)) then
  103.     off := off - 1;
  104.     reformvars := off;
  105. end;
  106.  
  107. function reformfields(startindex : integer): integer;
  108.  
  109. {
  110.     This routine is much like the previous two.  It cleans up
  111. the addresses of the fields of a record.
  112. }
  113.  
  114. var
  115.     index    : integer;
  116.     totalsize    : integer;
  117.     typeindex    : integer;
  118. begin
  119.     index := idents[startindex].indtype;
  120.     totalsize := 0;
  121.     while index <> 0 do begin
  122.     typeindex := idents[index].vtype;
  123.     typeindex := idents[typeindex].size;
  124.     if odd(totalsize) and (typeindex > 1) then
  125.         totalsize := totalsize + 1;
  126.     idents[index].offset := totalsize;
  127.     totalsize := totalsize + typeindex;
  128.     index := idents[index].indtype;
  129.     end;
  130.     if odd(totalsize) then
  131.     totalsize := totalsize + 1;
  132.     reformfields := totalsize;
  133. end;
  134.  
  135. function addproc(procname : string; isfunction : boolean): integer;
  136.  
  137. {
  138.     This just adds a procedure to the identifier array.
  139. Hmmm... sounds like this belongs in utilities.p
  140. }
  141.  
  142. begin
  143.     idents[identptr].name := string(integer(adr(spelling)) + spellptr - 1);
  144.     enterspell(procname);
  145.     if isfunction then
  146.     idents[identptr].object := func
  147.     else
  148.     idents[identptr].object := proc;
  149.     idents[identptr].offset := 0;
  150.     idents[identptr].vtype := 0;
  151.     idents[identptr].upper := 0;
  152.     idents[identptr].lower := 0;
  153.     idents[identptr].size := 0;
  154.     idents[identptr].indtype := 0;
  155.     identptr := identptr + 1;
  156.     addproc := identptr - 1;
  157. end;
  158.  
  159. procedure getrange(var typerec : idrecord);
  160.  
  161. {
  162.     This is rather a mistake, actually.  The routine that
  163. declares arrays ought to just look for a range type inside the
  164. brackets, but instead it uses this routine to look for an explicit
  165. range.  When I add range types to the language, this will fix
  166. itself.
  167. }
  168.  
  169. var
  170.     lowindex    : integer;
  171.     highindex    : integer;
  172. begin
  173.     typerec.lower := conexpr(lowindex);
  174.     if not match(dotdot1) then
  175.     error("expecting '..' here");
  176.     typerec.upper := conexpr(highindex);
  177.     if not typecmp(lowindex, highindex) then begin
  178.     error("incompatible range types");
  179.     typerec.upper := typerec.lower;
  180.     end;
  181.     if typerec.lower > typerec.upper then begin
  182.     error("lower bound greater than upper bound");
  183.     typerec.object := typerec.lower;
  184.     typerec.lower := typerec.upper;
  185.     typerec.upper := typerec.object;
  186.     end;
  187.     typerec.indtype := lowindex;
  188. end;
  189.  
  190. function readrecord(predname : string): integer;
  191.  
  192. {
  193.     This just reads a record.  Note that I had to do a bit of
  194. gymnastics in order to handle a field that's a pointer to its
  195. parent record.
  196. }
  197.  
  198. var
  199.     typeindex    : integer;
  200.     startindex    : integer;
  201. begin
  202.     startindex := addtype(vrecord, 0, 0, 0, 0, 0);
  203.     if predname <> string(0) then
  204.     idents[startindex].name := predname
  205.     else
  206.     idents[startindex].name := string(adr(spelling));
  207.     prevarg := startindex;
  208.     while currsym = ident1 do begin
  209.     typeindex := declvar(field, startindex);
  210.     ns;
  211.     end;
  212.     if not match(end1) then
  213.     error("Missing END of record");
  214.     idents[startindex].size := reformfields(startindex);
  215.     idents[startindex].name := string(adr(spelling));
  216.     readrecord := startindex;
  217. end;
  218.  
  219. function readenumeration(): integer;
  220.  
  221. {
  222.     This just reads enumerations and assigns them numbers
  223. starting with zero.
  224. }
  225.  
  226. var
  227.     position : integer;
  228.     enumtype : integer;
  229.     previous : integer;
  230.     current  : integer;
  231. begin
  232.     position := 0;
  233.     enumtype := addtype(vordinal, 0, 0, 0, 2, 0);
  234.     previous := enumtype;
  235.     while currsym = ident1 do begin
  236.     if findid(symtext) <> 0 then
  237.         error("Duplicate ID");
  238.     current := enterstandard(constant, position, enumtype, 0, 0, 0, 0);
  239.     enterspell(symtext);
  240.     idents[previous].indtype := current;
  241.     previous := current;
  242.     position := position + 1;
  243.     nextsymbol;
  244.     if currsym <> rightparent1 then
  245.         if not match(comma1) then
  246.         error("missing comma");
  247.     end;
  248.     needrightparent;
  249.     readenumeration := enumtype;
  250. end;
  251.  
  252. function readtype(predname : string): integer;
  253.  
  254. {
  255.     This is a bit of a monster function, but needs yet more
  256. stuff (like ranges).  The pointer part should have support for a
  257. pointer to an as-yet-unknown-id.  This routine returns the index of
  258. the type produced by the type declaration.  Note that I use the
  259. same routine almost wherever I need a type, which is why you can
  260. use a full type description most places.
  261. }
  262.  
  263. var
  264.     typeindex    : integer;
  265.     typerec    : idrecord;
  266.     tempint    : integer;
  267. begin
  268.     if currsym = ident1 then begin
  269.     typeindex := findid(symtext);
  270.     if (typeindex = 0) or
  271.        (idents[typeindex].object <> obtype) then begin
  272.         error("looking for a type description here.");
  273.         typeindex := badtype;
  274.     end;
  275.     nextsymbol;
  276.     end else if match(carat1) then begin
  277.     typeindex := readtype(string(0));
  278.     typeindex := addtype(vpointer, typeindex, 0, 0, 4, 0);
  279.     end else if match(leftparent1) then
  280.     typeindex := readenumeration()
  281.     else if match(array1) then begin
  282.     if not match(leftbrack1) then
  283.         error("expecting leftbracket");
  284.     getrange(typerec);
  285.     if not match(rightbrack1) then
  286.         error("expecting a right bracket");
  287.     if not match(of1) then
  288.         error("expecting OF");
  289.     typeindex := readtype(string(0));
  290.     typerec.size := (typerec.upper - typerec.lower + 1) *
  291.                idents[typeindex].size;
  292.     typeindex := addtype(varray, typeindex, typerec.upper,
  293.             typerec.lower, typerec.size, typerec.indtype);
  294.     end else if match(record1) then begin
  295.     typeindex := readrecord(predname);
  296.     end else if match(file1) then begin
  297.     if not match(of1) then
  298.         error("expecting OF");
  299.     typeindex := readtype(string(0));
  300.     typeindex := addtype(vfile, typeindex,
  301.                  idents[typeindex].size, 0, 18, 0);
  302.     end else begin
  303.     error("unknown type of thing");
  304.     typeindex := badtype;
  305.     end;
  306.     readtype := typeindex;
  307. end;
  308.  
  309. procedure decltype(firstpos : integer);
  310.  
  311. {
  312.     This handles a type declaration block.
  313. }
  314.  
  315. var
  316.     typeindex : integer;
  317.     spellindex : string;
  318. begin
  319.     while currsym = ident1 do begin
  320.     if checkid(symtext, firstpos) <> 0 then
  321.         error("duplicate id");
  322.     spellindex := string(integer(adr(spelling)) + spellptr - 1);
  323.     enterspell(symtext);
  324.     nextsymbol;
  325.     if not match(equal1) then
  326.         error("expecting '=' here");
  327.     typeindex := readtype(spellindex);
  328.     ns;
  329.     if typeindex <> 0 then begin
  330.         if idents[typeindex].name = string(adr(spelling)) then
  331.         idents[typeindex].name := spellindex
  332.         else begin
  333.         typeindex := addtype(vsynonym, typeindex, 0, 0,
  334.                      idents[typeindex].size, 0);
  335.         idents[typeindex].name := spellindex;
  336.         end;
  337.     end;
  338.     end;
  339. end;
  340.  
  341. function addvar(varname : string; varob, vartype, varoff : integer) : integer;
  342.  
  343. {
  344.     I suppose this too belong in utilities.p
  345. }
  346.  
  347. begin
  348.     idents[identptr].name := string(integer(adr(spelling)) + spellptr - 1);
  349.     enterspell(varname);
  350.     idents[identptr].object  := varob;
  351.     idents[identptr].offset  := varoff;
  352.     idents[identptr].vtype   := vartype;
  353.     idents[identptr].upper   := 0;
  354.     idents[identptr].lower   := 0;
  355.     idents[identptr].size    := 0;
  356.     idents[identptr].indtype := 0;
  357.     identptr := identptr + 1;
  358.     addvar := identptr - 1;
  359. end;
  360.  
  361. procedure declvar(storage, firstpos : integer);
  362.  
  363. {
  364.     This is used to declare a parameter, local variable, global
  365. variable, field, whatever.  It's also the reason I need the
  366. reform things above.
  367. }
  368.  
  369. var
  370.     typeindex    : integer;
  371.     varindex    : integer;
  372.     typesize    : integer;
  373. begin
  374.     if currsym = ident1 then begin
  375.     if (storage = global) or (storage = local) then begin
  376.         if checkid(symtext, firstpos) <> 0 then
  377.         error("Duplicate id");
  378.         varindex := addvar(symtext, storage, 0, 0)
  379.     end else if (storage = valarg) or (storage = refarg) or
  380.             (storage = field) then begin
  381.         if checkid(symtext, firstpos) <> 0 then
  382.         error("duplicate ID");
  383.         varindex := addvar(symtext, storage, 0, 0);
  384.         idents[prevarg].indtype := varindex;
  385.         prevarg := varindex;
  386.     end;
  387.     nextsymbol;
  388.     if match(comma1) then
  389.         typeindex := declvar(storage, firstpos)
  390.     else begin
  391.         if not match(colon1) then
  392.         error("expecting :");
  393.         typeindex := readtype(string(0));
  394.     end;
  395.     if typeindex <> 0 then begin
  396.         idents[varindex].vtype := typeindex;
  397.         if storage = valarg then begin
  398.         typesize := idents[typeindex].size;
  399.         if odd(typesize) then
  400.             typesize := typesize + 1;
  401.         argstk := argstk + typesize;
  402.         end else if storage = refarg then
  403.         argstk := argstk + 4;        
  404.     end;
  405.     end else begin
  406.     error("expecting an identifier");
  407.     if match(colon1) then
  408.         typeindex := readtype(string(0));
  409.     end;
  410.     declvar := typeindex;
  411. end;
  412.  
  413. procedure vardeclarations(firstpos : integer);
  414.  
  415. {
  416.     This handles a variable declaration block.
  417. }
  418.  
  419. var
  420.     typeindex    : integer;
  421. begin
  422.     while currsym = ident1 do begin
  423.     if blocklevel = 0 then begin
  424.         typeindex := declvar(global, firstpos);
  425.         ns;
  426.     end else begin
  427.         typeindex := declvar(local, firstpos);
  428.         ns;
  429.     end
  430.     end;
  431. end;
  432.  
  433. function addcon(conname : string) : integer;
  434.  
  435. {
  436.     How did all these get in here?
  437. }
  438.  
  439. begin
  440.     idents[identptr].name := string(integer(adr(spelling)) + spellptr - 1);
  441.     enterspell(conname);
  442.     idents[identptr].object  := constant;
  443.     idents[identptr].offset  := 0;
  444.     idents[identptr].vtype   := 0;
  445.     idents[identptr].upper   := 0;
  446.     idents[identptr].lower   := 0;
  447.     idents[identptr].size    := 0;
  448.     idents[identptr].indtype := 0;
  449.     identptr := identptr + 1;
  450.     addcon := identptr - 1;
  451. end;
  452.  
  453. procedure declconst(firstpos : integer);
  454.  
  455. {
  456.     This handles a const declaration block.  The grunt work is
  457. does by conexpr() in expression.p, which is the routine to look at
  458. if you want to improve constant declarations.
  459. }
  460.  
  461. var
  462.     conindex    : integer;
  463.     typeindex    : integer;
  464. begin
  465.     while currsym = ident1 do begin
  466.     if checkid(symtext, firstpos) <> 0 then
  467.         error("Duplicate ID");
  468.     conindex := addcon(symtext);
  469.     nextsymbol;
  470.     if not match(equal1) then
  471.         error("expecting =");
  472.     idents[conindex].offset := conexpr(typeindex);
  473.     idents[conindex].vtype  := typeindex;
  474.     ns;
  475.     end;
  476. end;
  477.