home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Fish 1
/
GoldFishApril1994_CD1.img
/
d1xx
/
d183
/
pcq
/
source
/
calls.p
next >
Wrap
Text File
|
1989-02-25
|
14KB
|
495 lines
external;
{
Calls.p (of PCQ Pascal)
Copyright (c) 1989 Patrick Quaid
Calls.p is the first attempt to organize the various
addressing and code generating routines in one section. If you
read the other sections you'll find that not much effort went into
this project. Nonetheless, a couple of common addressing things
can be found here.
If the compiler were designed so that all the addressing
things were here, it would be much easier to port to a different
computer.
}
const
{$I "pasconst.i"}
type
{$I "pastype.i"}
var
{$I "pasvar.i"}
function match(s : integer) : boolean;
forward;
procedure error(s : string);
forward;
function findfield(s : string; p : integer): integer;
forward;
procedure nextsymbol;
forward;
function expression() : integer;
forward;
function typecheck(t1, t2 : integer): boolean;
forward;
function typecmp(t1, t2 : integer) : boolean;
forward;
function findid(s : string) : integer;
forward;
function isvariable(i : integer) : boolean;
forward;
function getlabel() : integer;
forward;
procedure printlabel(l : integer);
forward;
procedure ns;
forward;
function suffix(s : integer): char;
forward;
procedure mismatch;
forward;
function basetype(t : integer): integer;
forward;
function simpletype(t : integer): boolean;
forward;
function numbertype(t : integer): Boolean;
forward;
procedure promotetype(var f : integer; o, r : integer);
forward;
procedure dorangecheck(vartype : integer);
{
This routine is called from selector() when range checking
is turned on. Notice that the code is all inline, rather than
calling some library function. I see this as a debugging option,
so I didn't try very hard to optimize it.
}
var
safelabel : integer;
badlabel : integer;
begin
if idents[vartype].offset = varray then begin
safelabel := getlabel();
badlabel := getlabel();
writeln(output, "\tcmp.l\t#", idents[vartype].lower, ',d0');
write(output, "\tblt.s\t");
printlabel(badlabel);
writeln(output, "\n\tcmp.l\t#", idents[vartype].upper, ',d0');
write(output, "\tbgt.s\t");
printlabel(badlabel);
write(output, "\n\tbra.s\t");
printlabel(safelabel);
writeln(output);
printlabel(badlabel);
writeln(output, "\tmove.l\t#52,d0");
writeln(output, "\tjsr\t_p%exit");
printlabel(safelabel);
writeln(output);
end;
end;
procedure getpointerval(varindex : integer);
{
This routine puts the value of a pointer variable (or a
reference parameter) into d0.
}
begin
if idents[varindex].object = global then
writeln(output, "\tmove.l\t_", idents[varindex].name, ',d0');
else if idents[varindex].object = refarg then begin
writeln(output, "\tmove.l\t", idents[varindex].offset, '(a5),a0');
writeln(output, "\tmove.l\t(a0),d0");
end else
writeln(output, "\tmove.l\t", idents[varindex].offset, '(a5),d0');
end;
procedure simpleaddress(varindex : integer);
{
simpleaddress() is passed a idrecord of some sort of
variable, and just loads its address into a0.
}
begin
if idents[varindex].object = global then
writeln(output, "\tmove.l\t#_", idents[varindex].name, ',a0');
else if (idents[varindex].object = local)
or (idents[varindex].object = valarg) then
writeln(output, "\tlea\t", idents[varindex].offset, '(a5),a0');
else if idents[varindex].object = refarg then
writeln(output, "\tmove.l\t", idents[varindex].offset, '(a5),a0');
end;
function selector(varindex : integer) : integer;
{
This is an overlarge function that handles all the
selectors- in other words ^, ., and []. It can handle a series of
them, of course. selector() returns 0 if no selection was
required, and the type if there was some selection. This routine
will be split up, and I'm planning to add addressing for strings
like that in C.
}
var
vartype : integer;
typeindex : integer;
indextype : integer;
stacked : boolean;
bufsize : integer;
begin
stacked := false;
vartype := idents[varindex].vtype;
while (currsym = period1) or (currsym = leftbrack1) or
(currsym = carat1) do begin
if match(period1) then begin
if idents[vartype].offset <> vrecord then
error("not a record type");
typeindex := findfield(symtext, vartype);
if typeindex = 0 then
error("unknown field");
nextsymbol;
if idents[typeindex].offset <> 0 then begin
if stacked then
write(output, "\tadd.l\t#")
else
write(output, "\tmove.l\t#");
writeln(output, idents[typeindex].offset, ',d0');
end else if not stacked then
writeln(output, "\tmoveq\t#0,d0");
stacked := true;
vartype := idents[typeindex].vtype;
end else if match(carat1) then begin
if idents[vartype].offset = vfile then begin
if stacked then
writeln(output, "\tmove.l\td0,a0")
else begin
simpleaddress(varindex);
stacked := true;
end;
bufsize := idents[vartype].vtype;
bufsize := idents[bufsize].size;
if (bufsize <= 4) and (bufsize <> 3) then begin
writeln(output, "\tlea\t4(a0),a0");
writeln(output, "\tmove.l\ta0,d0");
end else
writeln(output, "\tmove.l\t4(a0),d0");
vartype := idents[vartype].vtype;
end else if idents[vartype].offset = vpointer then begin
if stacked then begin
writeln(output, "\tmove.l\td0,a0");
writeln(output, "\tmove.l\t(a0),d0");
end else
getpointerval(varindex);
stacked := true;
vartype := idents[vartype].vtype;
end else
error("Need a file or pointer for ^");
end else if match(leftbrack1) then begin
if idents[vartype].offset <> varray then
error("not an array");
if stacked then
writeln(output, "\tmove.l\td0,-(sp)");
indextype := expression();
promotetype(indextype, inttype, 0);
if rangecheck then
dorangecheck(vartype);
if not typecheck(indextype, idents[vartype].indtype) then
mismatch;
if not match(rightbrack1) then
error("expecting ]");
if idents[vartype].lower <> 0 then
writeln(output, "\tsub.l\t#", idents[vartype].lower, ',d0');
vartype := idents[vartype].vtype;
if idents[vartype].size <> 1 then
writeln(output, "\tmuls\t#", idents[vartype].size, ',d0');
if stacked then begin
writeln(output, "\tmove.l\t(sp)+,d1");
writeln(output, "\tadd.l\td1,d0");
end else
stacked := true;
end;
end;
if stacked then
selector := vartype
else
selector := 0;
end;
function loadvar(varindex : integer) : integer;
{
This routine is used in assignments. If the variable
reference requires selection, loadvar() loads the address into d0
and returns the appropriate type. If not, it does not load the
address, and returns zero.
}
var
vartype : integer;
originaltype : integer;
begin
nextsymbol;
vartype := selector(varindex);
originaltype := idents[varindex].vtype;
if vartype = 0 then
loadvar := 0
else begin
if (idents[originaltype].offset <> vpointer) and
(idents[originaltype].offset <> vfile) then begin
simpleaddress(varindex);
writeln(output, "\tadd.l\ta0,d0");
end;
loadvar := vartype;
end;
end;
function loadaddress() : integer;
{
This is the routine used wherever I need the address of a
variable, for example reference parameters or the adr() function.
The address is loaded into a0.
}
var
argindex : integer;
argtype : integer;
bt : integer;
begin
if currsym = ident1 then begin
argindex := findid(symtext);
nextsymbol;
if argindex = 0 then begin
error("Unknown ID");
argindex := badtype;
end else begin
if isvariable(argindex) then begin
argtype := selector(argindex);
bt := basetype(idents[argindex].vtype);
if argtype = 0 then begin
simpleaddress(argindex);
argtype := idents[argindex].vtype
end else begin
if (idents[bt].offset = vpointer) or
(idents[bt].offset = vfile) then
writeln(output, "\tmove.l\td0,a0");
else begin
simpleaddress(argindex);
writeln(output, "\tadda.l\td0,a0");
end;
end;
loadaddress := argtype;
end else
if argindex <> badtype then
error("expecting a variable (reference parameter)");
end
end else
error("expecting a variable identifier");
loadaddress := badtype;
end;
procedure getparams(procindex : integer);
{
This routine handles the parameters of a call (not the
declaration, which is handled in doblock()). It sorts out the
various reference and value parameters and gets the stack properly
set up.
}
var
currentparam : integer;
stay : boolean;
argtype : integer;
argindex : integer;
totalsize : integer;
lab : integer;
begin
stay := true;
if match(leftparent1) then begin
currentparam := idents[procindex].indtype;
while (not match(rightparent1)) and stay do begin
if currentparam = 0 then begin
error("argument not expected");
nextsymbol;
stay := false;
end else begin
if idents[currentparam].object = valarg then begin
argtype := expression();
if not typecheck(argtype, idents[currentparam].vtype)
then begin
mismatch;
argtype := badtype;
end else begin
if numbertype(argtype) then
promotetype(argtype, idents[currentparam].vtype, 0);
argtype := idents[currentparam].vtype;
if simpletype(argtype) then begin
if idents[argtype].size <= 2 then
writeln(output, "\tmove.w\td0,-(sp)")
else if idents[argtype].size = 4 then
writeln(output, "\tmove.l\td0,-(sp)");
end else begin
writeln(output, "\tmove.l\td0,a0");
writeln(output, "\tmove.l\tsp,a1");
writeln(output, "\tsub.l\t#",
idents[argtype].size, ',a1');
writeln(output, "\tmove.l\t#",
idents[argtype].size - 1, ',d1');
lab := getlabel();
printlabel(lab);
writeln(output, "\tmove.b\t(a0)+,d0");
writeln(output, "\tmove.b\td0,(a1)+");
write(output, "\tdbra\td1,");
printlabel(lab);
writeln(output);
write(output, "\tsub.l\t#");
if odd(idents[argtype].size) then
write(output, idents[argtype].size + 1)
else
write(output, idents[argtype].size);
writeln(output, ',sp');
end;
end;
end else if idents[currentparam].object = refarg then begin
if currsym = ident1 then begin
argtype := loadaddress();
writeln(output, "\tmove.l\ta0,-(sp)");
if not typecmp(argtype, idents[currentparam].vtype)
then
mismatch;
end else
error("Expecting a variable name (reference param)");
end;
currentparam := idents[currentparam].indtype;
if currentparam <> 0 then
if not match(comma1) then
error("expected ,");
end;
end;
if currentparam <> 0 then
error("more parameters needed");
end else begin
if idents[procindex].indtype <> 0 then
error("expecting some parameters")
else if idents[procindex].object = func then
error("expecting parentheses for a function");
end
end;
procedure callproc(varindex : integer);
{
This routine makes an actual call to a procedure. In the
next version this routine will have to push an extra address, which
will point to the routine's parent's frame pointer. Never mind
about that except that it is required in order to properly
implement nested blocks.
}
begin
nextsymbol;
getparams(varindex);
ns;
writeln(output, "\tjsr\t_", idents[varindex].name);
if idents[varindex].size <> 0 then
writeln(output, "\tadd.l\t#", idents[varindex].size, ',sp');
end;
procedure callfunc(varindex : integer);
{
This calls a function. It's mostly the same as callproc,
but it's called from deep within expression() rather than
statement(). This will also have to push a back pointer.
}
begin
getparams(varindex);
writeln(output, "\tjsr\t_", idents[varindex].name);
if idents[varindex].size <> 0 then
writeln(output, "\tadd.l\t#", idents[varindex].size, ',sp');
end;
procedure savethrougha0(totalsize : integer);
{
This saves a complex data object pointed to by d0 to the
memory at a0.
}
var
lab : integer;
begin
writeln(output, "\tmove.l\td0,a1");
writeln(output, "\tmove.l\t#", totalsize - 1, ',d1');
lab := getlabel();
printlabel(lab);
writeln(output, "\tmove.b\t(a1)+,d0");
writeln(output, "\tmove.b\td0,(a0)+");
write(output, "\tdbra\td1,");
printlabel(lab);
writeln(output);
end;
procedure savestack(typeindex : integer);
{
This saves a variable into the memory pointed to by the
longword on the top of the stack. Odd as it may sound, this occurs
fairly often.
}
begin
writeln(output, "\tmove.l\t(sp)+,a0");
if simpletype(typeindex) then
writeln(output, "\tmove.", suffix(idents[typeindex].size), "\td0,(a0)");
else
savethrougha0(idents[typeindex].size);
end;
procedure saveval(varindex : integer);
{
This saves whatever's in d0 into the variable pointed to by
varindex.
}
var
totalsize : integer;
begin
totalsize := idents[varindex].vtype;
totalsize := idents[totalsize].size;
if idents[varindex].object = global then begin
if not simpletype(idents[varindex].vtype) then begin
writeln(output, "\tmove.l\t#_", idents[varindex].name, ',a0');
savethrougha0(totalsize);
end else
writeln(output, "\tmove.", suffix(totalsize), "\td0,_",
idents[varindex].name);
end else if (idents[varindex].object = local) or
(idents[varindex].object = valarg) then begin
if not simpletype(idents[varindex].vtype) then begin
writeln(output, "\tlea\t", idents[varindex].offset, '(a5),a0');
savethrougha0(totalsize);
end else
writeln(output, "\tmove.", suffix(totalsize), "\td0,",
idents[varindex].offset, '(a5)');
end else begin
writeln(output, "\tmove.l\t", idents[varindex].offset, '(a5),a0');
if not simpletype(idents[varindex].vtype) then
savethrougha0(totalsize)
else
writeln(output, "\tmove.", suffix(totalsize), "\td0,(a0)");
end;
end;