home *** CD-ROM | disk | FTP | other *** search
- program PQPascal;
-
- {
- PCQ Pascal Compiler
- Copyright (c) 1989 Patrick Quaid.
-
- This is the main file of the compiler. When this file is
- compiled, it allocates BSS for all the global variables.
- }
-
- const
- {$I "pasconst.i"}
-
- type
- {$I "pastype.i"}
-
- var
- {$I "pasvar.i"}
-
- { The following routines are all exported by the other
- compiler files. }
-
- function strlen(s : string): integer;
- forward;
- function AllocString(l : integer): string;
- forward;
- procedure error(s : string);
- forward;
- function findid(s : string): integer;
- forward;
- function addproc(p : string; i : boolean): integer;
- forward;
- procedure nextsymbol;
- forward;
- function match(s : integer): boolean;
- forward;
- function declvar(r, f : integer) : integer;
- forward;
- procedure decltype(f : integer);
- forward;
- procedure declconst(f : integer);
- forward;
- procedure ns;
- forward;
- procedure reformargs;
- forward;
- function readtype(n : integer): integer;
- forward;
- function endoffile(): boolean;
- forward;
- procedure vardeclarations(f : integer);
- forward;
- function reformvars(i : integer): integer;
- forward;
- procedure outname(s : string);
- forward;
- procedure initreserved;
- forward;
- procedure initglobals;
- forward;
- procedure dumpids;
- forward;
- procedure dumplits;
- forward;
- procedure dumptypes;
- forward;
- procedure trailer;
- forward;
- procedure compound;
- forward;
- procedure header;
- forward;
- procedure initstandard;
- forward;
- procedure readchar;
- forward;
- function an(c : char): boolean;
- forward;
- procedure needrightparent;
- forward;
- function simpletype(t : integer): boolean;
- forward;
-
-
- procedure openfiles;
-
- {
- This routine does all the command line business, which is
- at this point not much. It only accepts spaces and tabs as
- delimeters, for example, and doesn't take care of quotes or escape
- sequences. Furthermore, it doesn't handle any command line
- switches. In the future I'll use a routine more like that in
- ChopCL.p
- }
-
- var
- index : integer;
- str : string;
- begin
- index := 1;
- while ((commandline[index]= ' ') or (commandline[index] = chr(9)))
- and (index <= 128) do
- index := index + 1;
- if index >= 128 then begin
- writeln('Bad file names.');
- exit(20);
- end;
- mainname := string(adr(commandline[index]));
- while (commandline[index]<> ' ') and (commandline[index] <> chr(9))
- and (index <= 128) do
- index := index + 1;
- if index >= 128 then begin
- writeln('Bad file names.');
- exit(20);
- end;
- commandline[index] := chr(0);
- if not reopen(mainname, input) then begin
- writeln('Could not open ', mainname);
- exit(20);
- end;
- index := index + 1;
-
- while ((commandline[index]= ' ') or (commandline[index] = chr(9)))
- and (index <= 128) do
- index := index + 1;
- if index >= 128 then begin
- writeln('Bad file names.');
- exit(20);
- end;
- str := string(adr(commandline[index]));
- while (ord(commandline[index]) > ord(' ')) and
- (ord(commandline[index]) < 127) and
- (index <= 128) do
- index := index + 1;
- if index >= 128 then begin
- writeln('Bad file names.');
- exit(20);
- end;
- commandline[index] := chr(0);
-
- if not open(str, output) then begin
- writeln('Could not open the output file.');
- exit(20);
- end;
- end;
-
- procedure doblock(isfunction : boolean);
-
- {
- This is the main routine for handling program, procedure
- and function blocks. It handles the various declaration blocks and
- the procedure and function parameters. This is one of the many
- routines which should, and will, be broken into more manageable
- parts.
- }
-
- var
- blockloc : integer;
- blockspell : integer;
- firstident : integer;
- functype : integer;
- index : integer;
- varspace : integer;
- savefn : integer;
- forded : boolean;
- begin
- fnstart := lineno;
- firstident := identptr;
- forded := false;
- if blocklevel > 0 then begin
- if currsym <> ident1 then begin
- error("Missing function or procedure name!");
- return;
- end;
- currfn:= findid(symtext);
- if currfn <> 0 then begin
- if idents[currfn].upper <> 0 then
- error("Duplicate ID")
- else
- forded := true;
- end else
- currfn := addproc(symtext, isfunction);
- nextsymbol;
-
- if match(leftparent1) then begin
- prevarg := currfn;
- argstk := 0;
- while (currsym = ident1) or (currsym = var1) do begin
- if match(var1) then
- index := declvar(refarg, firstident)
- else
- index := declvar(valarg, firstident);
- if currsym <> rightparent1 then
- ns;
- end;
- idents[currfn].size := argstk;
- reformargs;
- needrightparent;
- end else if isfunction then
- error("Functions must have parentheses");
-
- if isfunction then begin
- if not match(colon1) then
- error("expecting :");
- functype := readtype(0);
- if functype > 0 then begin
- if not simpletype(functype) then begin
- error("expecting a simple type");
- functype := badtype;
- end;
- end else
- functype := badtype;
- idents[currfn].vtype := functype;
- end;
- ns;
- blockloc := identptr;
- blockspell := spellptr;
- varspace := 0;
- end;
-
- if match(forward1) then begin
- idents[currfn].upper := 0;
- ns;
- blockloc := idents[currfn].indtype;
- while blockloc <> 0 do begin
- idents[blockloc].name := string(adr(spelling));
- blockloc := idents[blockloc].indtype;
- end;
- end else begin
- idents[currfn].upper := -1;
- while currsym <> begin1 do begin
- if endoffile() then begin
- if mainmode or (blocklevel > 0) then
- error("There was no code section!");
- return;
- end else if match(var1) then begin
- index := identptr - 1;
- vardeclarations(firstident);
- if blocklevel > 0 then
- varspace := reformvars(index);
- end else if match(type1) then
- decltype(firstident)
- else if match(const1) then
- declconst(firstident)
- else if match(proc1) then begin
- blocklevel := blocklevel + 1;
- savefn := currfn;
- doblock(false);
- currfn := savefn;
- blocklevel := blocklevel - 1;
- end else if match(func1) then begin
- blocklevel := blocklevel + 1;
- savefn := currfn;
- doblock(true);
- currfn := savefn;
- blocklevel := blocklevel - 1;
- end else begin
- error("expecting block identifier");
- nextsymbol;
- end;
- end;
- if (not mainmode) and (blocklevel = 0) then begin
- error("Expected a procedure or function header");
- return;
- end;
- if (blocklevel = 0) and mainmode then begin
- writeln(output, "\n\tXDEF\t_MAIN");
- writeln(output, '_MAIN');
- end;
-
- if blocklevel > 0 then begin
- writeln(output, "\n\tXDEF\t_", idents[currfn].name);
- writeln(output, '_', idents[currfn].name, "\tlink\ta5,#", varspace);
- end;
- nextsymbol;
-
- compound;
-
- if blocklevel > 0 then begin
- ns;
- identptr := blockloc;
- spellptr := blockspell;
- writeln(output, "\tunlk\ta5");
-
- blockloc := idents[currfn].indtype;
- while blockloc <> 0 do begin
- idents[blockloc].name := string(adr(spelling));
- blockloc := idents[blockloc].indtype;
- end;
- end;
- writeln(output, "\trts");
- end;
- end;
-
- procedure parse;
-
- {
- This is the outermost parsing routine. It uses doblock()
- mainly, and will eventually be able to handle program parameters.
- }
-
- begin
- if match(program1) then begin
- mainmode:= true;
- if currsym <> ident1 then
- error("Missing program name.")
- else
- writeln('Compiling ', symtext);
- while not match(semicolon1) do
- nextsymbol;
- end else if match(extern1) then begin
- mainmode := false;
- writeln('Compiling external routines.');
- ns;
- end else begin
- error("First symbol must be PROGRAM or EXTERNAL.");
- mainmode:= false;
- end;
- header;
- blocklevel := 0;
- doblock(false);
- if mainmode then
- if not match(period1) then
- error("Program must end with a period.");
- if (not endoffile()) and (mainmode) then
- error("There should be nothing after the main procedure.");
- end;
-
- begin
-
- {
- This is the big one, the main routine, which by itself does
- very little. Read parse() and doblock() to get a much better idea
- of how things work.
- }
- writeln('PCQ Compiler 1.0 (February 1, 1989)');
- writeln('Copyright ', chr(169),
- ' 1989 Patrick Quaid. All rights reserved.');
-
- initglobals; { initialize everything }
- initreserved;
- openfiles;
- initstandard;
-
- readchar; { jump-start lex analysis }
- nextsymbol;
-
- parse; { do everything }
-
- if errorcount = 0 then
- writeln('There were no errors.')
- else if errorcount = 1 then
- writeln('There was one error')
- else
- writeln('There were ', errorcount, ' errors.');
-
- dumpids; { write ids and lits to assem file }
- dumplits;
- trailer; { write 'END' }
- if errorcount <> 0 then
- exit(10); { make sure there's an error is necessary }
- end.
-