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

  1. program PQPascal;
  2.  
  3. {
  4.     PCQ Pascal Compiler
  5.     Copyright (c) 1989 Patrick Quaid.
  6.  
  7.     This is the main file of the compiler.  When this file is
  8. compiled, it allocates BSS for all the global variables.
  9. }
  10.  
  11. const
  12. {$I "pasconst.i"}
  13.  
  14. type
  15. {$I "pastype.i"}
  16.  
  17. var
  18. {$I "pasvar.i"}
  19.  
  20.     { The following routines are all exported by the other
  21.       compiler files. }
  22.  
  23.     function strlen(s : string): integer;
  24.         forward;
  25.     function AllocString(l : integer): string;
  26.         forward;
  27.     procedure error(s : string);
  28.         forward;
  29.     function findid(s : string): integer;
  30.         forward;
  31.     function addproc(p : string; i : boolean): integer;
  32.         forward;
  33.     procedure nextsymbol;
  34.         forward;
  35.     function match(s : integer): boolean;
  36.         forward;
  37.     function declvar(r, f : integer) : integer;
  38.         forward;
  39.     procedure decltype(f : integer);
  40.         forward;
  41.     procedure declconst(f : integer);
  42.         forward;
  43.     procedure ns;
  44.         forward;
  45.     procedure reformargs;
  46.         forward;
  47.     function readtype(n : integer): integer;
  48.         forward;
  49.     function endoffile(): boolean;
  50.         forward;
  51.     procedure vardeclarations(f : integer);
  52.         forward;
  53.     function reformvars(i : integer): integer;
  54.         forward;
  55.     procedure outname(s : string);
  56.         forward;
  57.     procedure initreserved;
  58.         forward;
  59.     procedure initglobals;
  60.         forward;
  61.     procedure dumpids;
  62.         forward;
  63.     procedure dumplits;
  64.         forward;
  65.     procedure dumptypes;
  66.         forward;
  67.     procedure trailer;
  68.         forward;
  69.     procedure compound;
  70.         forward;
  71.     procedure header;
  72.         forward;
  73.     procedure initstandard;
  74.         forward;
  75.     procedure readchar;
  76.         forward;
  77.     function an(c : char): boolean;
  78.         forward;
  79.     procedure needrightparent;
  80.         forward;
  81.     function simpletype(t : integer): boolean;
  82.         forward;
  83.  
  84.  
  85. procedure openfiles;
  86.  
  87. {
  88.     This routine does all the command line business, which is
  89. at this point not much.  It only accepts spaces and tabs as
  90. delimeters, for example, and doesn't take care of quotes or escape
  91. sequences.  Furthermore, it doesn't handle any command line
  92. switches.  In the future I'll use a routine more like that in
  93. ChopCL.p
  94. }
  95.  
  96. var
  97.     index    : integer;
  98.     str        : string;
  99. begin
  100.     index := 1;
  101.     while ((commandline[index]= ' ') or (commandline[index] = chr(9)))
  102.     and (index <= 128) do
  103.     index := index + 1;
  104.     if index >= 128 then begin
  105.     writeln('Bad file names.');
  106.     exit(20);
  107.     end;
  108.     mainname := string(adr(commandline[index]));
  109.     while (commandline[index]<> ' ') and (commandline[index] <> chr(9))
  110.     and (index <= 128) do
  111.     index := index + 1;
  112.     if index >= 128 then begin
  113.     writeln('Bad file names.');
  114.     exit(20);
  115.     end;
  116.     commandline[index] := chr(0);
  117.     if not reopen(mainname, input) then begin
  118.     writeln('Could not open ', mainname);
  119.     exit(20);
  120.     end;
  121.     index := index + 1;
  122.  
  123.     while ((commandline[index]= ' ') or (commandline[index] = chr(9)))
  124.     and (index <= 128) do
  125.     index := index + 1;
  126.     if index >= 128 then begin
  127.     writeln('Bad file names.');
  128.     exit(20);
  129.     end;
  130.     str := string(adr(commandline[index]));
  131.     while (ord(commandline[index]) > ord(' ')) and
  132.       (ord(commandline[index]) < 127) and
  133.       (index <= 128) do
  134.     index := index + 1;
  135.     if index >= 128 then begin
  136.     writeln('Bad file names.');
  137.     exit(20);
  138.     end;
  139.     commandline[index] := chr(0);
  140.  
  141.     if not open(str, output) then begin
  142.     writeln('Could not open the output file.');
  143.     exit(20);
  144.     end;
  145. end;
  146.  
  147. procedure doblock(isfunction : boolean);
  148.  
  149. {
  150.     This is the main routine for handling program, procedure
  151. and function blocks.  It handles the various declaration blocks and
  152. the procedure and function parameters.  This is one of the many
  153. routines which should, and will, be broken into more manageable
  154. parts.
  155. }
  156.  
  157. var
  158.     blockloc    : integer;
  159.     blockspell    : integer;
  160.     firstident    : integer;
  161.     functype    : integer;
  162.     index    : integer;
  163.     varspace    : integer;
  164.     savefn    : integer;
  165.     forded    : boolean;
  166. begin
  167.     fnstart := lineno;
  168.     firstident := identptr;
  169.     forded := false;
  170.     if blocklevel > 0 then begin
  171.     if currsym <> ident1 then begin
  172.         error("Missing function or procedure name!");
  173.         return;
  174.     end;
  175.     currfn:= findid(symtext);
  176.     if currfn <> 0 then begin
  177.         if idents[currfn].upper <> 0 then
  178.         error("Duplicate ID")
  179.         else
  180.         forded := true;
  181.     end else
  182.         currfn := addproc(symtext, isfunction);
  183.     nextsymbol;
  184.  
  185.     if match(leftparent1) then begin
  186.         prevarg := currfn;
  187.         argstk := 0;
  188.         while (currsym = ident1) or (currsym = var1) do begin
  189.         if match(var1) then
  190.             index := declvar(refarg, firstident)
  191.         else
  192.             index := declvar(valarg, firstident);
  193.         if currsym <> rightparent1 then
  194.             ns;
  195.         end;
  196.         idents[currfn].size := argstk;
  197.         reformargs;
  198.         needrightparent;
  199.     end else if isfunction then
  200.         error("Functions must have parentheses");
  201.  
  202.     if isfunction then begin
  203.         if not match(colon1) then
  204.         error("expecting :");
  205.         functype := readtype(0);
  206.         if functype > 0 then begin
  207.         if not simpletype(functype) then begin
  208.             error("expecting a simple type");
  209.             functype := badtype;
  210.         end;
  211.         end else
  212.         functype := badtype;
  213.         idents[currfn].vtype := functype;
  214.     end;
  215.     ns;
  216.     blockloc := identptr;
  217.     blockspell := spellptr;
  218.     varspace := 0;
  219.     end;
  220.  
  221.     if match(forward1) then begin
  222.     idents[currfn].upper := 0;
  223.     ns;
  224.     blockloc := idents[currfn].indtype;
  225.     while blockloc <> 0 do begin
  226.         idents[blockloc].name := string(adr(spelling));
  227.         blockloc := idents[blockloc].indtype;
  228.     end;
  229.     end else begin
  230.     idents[currfn].upper := -1;
  231.     while currsym <> begin1 do begin
  232.         if endoffile() then begin
  233.         if mainmode or (blocklevel > 0) then
  234.             error("There was no code section!");
  235.         return;
  236.         end else if match(var1) then begin
  237.         index := identptr - 1;
  238.         vardeclarations(firstident);
  239.         if blocklevel > 0 then
  240.             varspace := reformvars(index);
  241.         end else if match(type1) then
  242.         decltype(firstident)
  243.         else if match(const1) then
  244.         declconst(firstident)
  245.         else if match(proc1) then begin
  246.         blocklevel := blocklevel + 1;
  247.         savefn := currfn;
  248.         doblock(false);
  249.         currfn := savefn;
  250.         blocklevel := blocklevel - 1;
  251.         end else if match(func1) then begin
  252.         blocklevel := blocklevel + 1;
  253.         savefn := currfn;
  254.         doblock(true);
  255.         currfn := savefn;
  256.         blocklevel := blocklevel - 1;
  257.         end else begin
  258.         error("expecting block identifier");
  259.         nextsymbol;
  260.         end;
  261.     end;
  262.     if (not mainmode) and (blocklevel = 0) then begin
  263.         error("Expected a procedure or function header");
  264.         return;
  265.     end;
  266.     if (blocklevel = 0) and mainmode then begin
  267.         writeln(output, "\n\tXDEF\t_MAIN");
  268.         writeln(output, '_MAIN');
  269.     end;
  270.  
  271.     if blocklevel > 0 then begin
  272.         writeln(output, "\n\tXDEF\t_", idents[currfn].name);
  273.         writeln(output, '_', idents[currfn].name, "\tlink\ta5,#", varspace);
  274.     end;
  275.     nextsymbol;
  276.  
  277.     compound;
  278.  
  279.     if blocklevel > 0 then begin
  280.         ns;
  281.         identptr := blockloc;
  282.         spellptr := blockspell;
  283.         writeln(output, "\tunlk\ta5");
  284.  
  285.         blockloc := idents[currfn].indtype;
  286.         while blockloc <> 0 do begin
  287.         idents[blockloc].name := string(adr(spelling));
  288.         blockloc := idents[blockloc].indtype;
  289.         end;
  290.     end;
  291.     writeln(output, "\trts");
  292.     end;
  293. end;
  294.  
  295. procedure parse;
  296.  
  297. {
  298.     This is the outermost parsing routine.  It uses doblock()
  299. mainly, and will eventually be able to handle program parameters.
  300. }
  301.  
  302. begin
  303.     if match(program1) then begin
  304.     mainmode:= true;
  305.     if currsym <> ident1 then
  306.         error("Missing program name.")
  307.     else
  308.         writeln('Compiling ', symtext);
  309.     while not match(semicolon1) do
  310.         nextsymbol;
  311.     end else if match(extern1) then begin
  312.     mainmode := false;
  313.     writeln('Compiling external routines.');
  314.     ns;
  315.     end else begin
  316.     error("First symbol must be PROGRAM or EXTERNAL.");
  317.     mainmode:= false;
  318.     end;
  319.     header;
  320.     blocklevel := 0;
  321.     doblock(false);
  322.     if mainmode then
  323.     if not match(period1) then
  324.         error("Program must end with a period.");
  325.     if (not endoffile()) and (mainmode) then
  326.     error("There should be nothing after the main procedure.");
  327. end;
  328.  
  329. begin
  330.  
  331. {
  332.     This is the big one, the main routine, which by itself does
  333. very little.  Read parse() and doblock() to get a much better idea
  334. of how things work.
  335. }
  336.     writeln('PCQ Compiler 1.0  (February 1, 1989)');
  337.     writeln('Copyright ', chr(169),
  338.         ' 1989 Patrick Quaid.  All rights reserved.');
  339.  
  340.     initglobals;    { initialize everything }
  341.     initreserved;
  342.     openfiles;
  343.     initstandard;
  344.  
  345.     readchar;        { jump-start lex analysis }
  346.     nextsymbol;
  347.  
  348.     parse;        { do everything }
  349.  
  350.     if errorcount = 0 then
  351.     writeln('There were no errors.')
  352.     else if errorcount = 1 then
  353.     writeln('There was one error')
  354.     else
  355.     writeln('There were ', errorcount, ' errors.');
  356.  
  357.     dumpids;        { write ids and lits to assem file }
  358.     dumplits;
  359.     trailer;        { write 'END' }
  360.     if errorcount <> 0 then
  361.     exit(10);    { make sure there's an error is necessary }
  362. end.
  363.