ORCA-Pascal/call.pas

2850 lines
69 KiB
ObjectPascal

{$optimize 15}
{------------------------------------------------------------}
{ }
{ ORCA/Pascal Call Procedure }
{ }
{ The call procedure handles parsing, semantic analysis }
{ and code generation for all procedure and function calls. }
{ This includes both user-defined and predeclared }
{ routines. }
{ }
{ By Mike Westerfield }
{ }
{ Copyright March 1988 }
{ By the Byte Works, Inc. }
{ }
{------------------------------------------------------------}
unit Call;
interface
{$segment 'Pascal2'}
{$LibPrefix '0/obj/'}
uses pcommon, scanner, cgi, symbols;
{-- Externally available variables --------------------------------------------}
type
{subroutine calls}
{----------------}
callKinds = (cStandard, cMethod, cInherited);
{temporary variable allocation}
{-----------------------------}
tempPtr = ^tempRecord;
tempRecord = record
last,next: tempPtr; {doubly linked list}
labelNum: integer; {label number}
size: integer; {size of the variable}
end;
var
psize: integer; {size of the parameter space for the current stack frame}
lc: addrrange; {current stack frame size}
{temporary variable allocation}
{-----------------------------}
tempList: tempPtr; {list of temp work variables}
{-- Externally available subroutines ------------------------------------------}
procedure Call (fsys: setofsys; fcp,fprocp: ctp);
{ generate a call to a procedure or function }
{ }
{ parameters: }
{ fsys - }
{ fcp - }
{ fprocp - }
procedure CallNonStandard (fsys: setofsys; fcp,fprocp: ctp; odisp: longint;
callKind: callKinds);
{ Handle a call to a user defined procedure/function }
{ }
{ parameters: }
{ fsys - }
{ fcp - }
{ fprocp - }
{ odisp - disp in object for method calls; else 0 }
{ callKind - type of this call }
procedure CheckBool;
{load a value, insuring that it is boolean}
procedure CheckBnds(fsp: stp);
{generate range checking code (if needed)}
procedure FreeTemp (labelNum, size: integer);
{ place a temporary label in the available label list }
{ }
{ parameters: }
{ labelNum - number of the label to free }
{ size - size of the variable }
{ }
{ variables: }
{ tempList - list of free labels }
function GetTemp (size: integer): integer;
{ find a temporary work variable }
{ }
{ parameters: }
{ size - size of the variable }
{ }
{ variables: }
{ tempList - list of free labels }
{ }
{ Returns the label number. }
procedure Load;
{load a value onto the evaluation stack}
procedure LoadAddress;
{load the address of a variable onto the top of the stack}
procedure LoadStringAddress;
{load the address and length of a string}
procedure LoadString(kind: stringKind);
{load the address of a string constant}
function ParmSize(lsp: stp; vkind: idkind): integer;
{find the length of a parameter}
procedure ResetTemp;
{ forget all of the temporary work variables }
procedure Store(var fattr: attr);
{store the value on top of stack}
{-- Private declarations ------------------------------------------------------}
implementation
const
realfw = 16; {field width for reals & doubles}
longfw = 16; {field width for long integers}
intfw = 8; {field width for integers}
boolfw = 8; {field width for booleans}
var
lkey: keyrange; {proc/func key for std proc compilation}
{-- Imported subroutines ------------------------------------------------------}
procedure DoConstant(fsys: setofsys; var fsp: stp; var fvalu: valu); extern;
{compile a constant term}
procedure Expression(fsys: setofsys; fprocp: ctp); extern;
{compile an expression}
procedure Selector (fsys: setofsys; fcp,fprocp: ctp; var isMethod: boolean);
extern;
{ handle indexing arrays, field selection, dereferencing of }
{ pointers, windowing files }
{ }
{ parameters: }
{ fsys - }
{ fcp - }
{ fprocp - }
{ isMethod - (returned) Did the selection resolve to a }
{ method call? If so, take no further action. }
{-- Private subroutines -------------------------------------------------------}
procedure Variable(fsys: setofsys; fprocp: ctp);
{compile a variable for the parm list of a standard proc/func}
var
isMethod: boolean; {dummy variable for Selector call}
lcp: ctp;
begin {Variable}
if sy = ident then begin
SearchId([varsm,field],lcp);
InSymbol;
end
else begin
Error(2);
lcp := uvarptr;
end;
Selector(fsys, lcp, fprocp, isMethod);
glcp := lcp;
end; {Variable}
procedure GetPutClose(fsys: setofsys; fprocp: ctp);
{Compile one of the named standard procs}
begin {GetPutClose}
{compile the file variable}
Variable(fsys + [rparent],fprocp);
{load the file variable}
Load;
Gen0t(pc_stk, cgULong);
{do type checking on file variable}
if gattr.typtr <> nil then
if gattr.typtr^.form <> files then
Error(44);
{generate the standard proc call}
Gen1(pc_csp,lkey{get,put,opn,cls})
end; {GetPutClose}
procedure resetrewriteopen(fsys: setofsys; fprocp: ctp);
var
key: integer; {open kind key; 1->read; 2->write; 3->both}
size: longint; {for remembering file size}
lsp: stp; {file type}
fkind: (stin,stout,errout,fileout); {kind of file}
begin {resetrewriteopen}
{process the file variable}
Variable(fsys+[comma,rparent],fprocp);
fkind := fileout;
if gattr.typtr = nil then
Error(44)
else if gattr.typtr^.form = files then begin
size := gattr.typtr^.filtype^.size;
if glcp = outptr then begin
fkind := stout;
if nooutput then Error(92);
end
else if glcp = inptr then begin
fkind := stin;
if noinput then Error(91);
end
else if glcp = erroroutputptr then
fkind := errout;
end
else Error(44);
{determine the type of the open}
if lkey = 3 then
key := 3
else
key := lkey-4;
case key of
1: if fkind in [stout,errout] then Error(44);
2: if fkind = stin then Error(44);
3: if fkind <> fileout then Error(44);
end;
if gattr.typtr <> nil then
if fkind = fileout then begin
{load the file variable}
LoadAddress;
Gen0t(pc_stk, cgULong);
{push the open type onto the stack}
lsp := glcp^.idtype;
if lsp^.form = pointerStruct then lsp := lsp^.eltype;
Gen1t(pc_ldc, key+4*ord(lsp=textptr), cgWord);
Gen0t(pc_stk, cgWord);
Gen0t(pc_bno, cgWord);
{load the length of the file}
Gen1t(pc_ldc, ord(size), cgWord);
Gen0t(pc_stk, cgWord);
Gen0t(pc_bno, cgWord);
end {if}
else begin
Gen1t(pc_ldc, ord(fkind), cgWord);
Gen0t(pc_stk, cgWord);
Gen0t(pc_bno, cgWord);
end; {else}
{if there is another parameter, use it for the file name}
if sy = comma then begin
if iso then Error(112);
InSymbol;
Expression(fsys+[rparent],fprocp);
if gattr.typtr <> nil then
if IsString(gattr.typtr) then begin
LoadStringAddress;
Gen0t(pc_bno, cgULong);
end {if}
else Error(44)
else Error(44);
end
else begin
GenLdcLong(0);
Gen0t(pc_stk, cgULong);
Gen0t(pc_bno, cgULong);
Gen1t(pc_ldc, 0, cgWord);
Gen0t(pc_stk, cgWord);
Gen0t(pc_bno, cgWord);
end; {else}
{open the file}
if fkind = fileout then
Gen1(pc_csp,3{opn})
else
Gen1(pc_csp,115{rdr});
end; {resetrewriteopen}
procedure seek(fsys: setofsys; fprocp: ctp);
{Compile the seek statement}
begin {seek}
Variable(fsys+[comma,rparent],fprocp);
if gattr.typtr = nil then
Error(44)
else if gattr.typtr^.form <> files then
Error(44);
Load;
Gen0t(pc_stk, cgULong);
Match(comma,20);
Expression(fsys+[rparent],fprocp);
Load;
if gattr.typtr <> nil then begin
if (gattr.typtr=intptr) or (gattr.typtr=byteptr) then begin
Gen2(pc_cnv,ord(cgWord),ord(cgLong));
gattr.typtr := longptr;
end;
if gattr.typtr <> longptr then Error(44);
end
else Error(44);
Gen0t(pc_stk, cgULong);
Gen0t(pc_bno, cgULong);
Gen1(pc_csp,44{sek});
end; {seek}
procedure page(fsys: setofsys; fprocp: ctp);
{compile a page procedure call}
var
lsp: stp;
begin {page}
if sy = lparent then begin
InSymbol;
Variable(fsys+[rparent],fprocp);
lsp := gattr.typtr;
if lsp <> nil then
if lsp = textptr then
if sy <> rparent then begin
Error(4);
Skip(fsys+[rparent]);
end
else InSymbol
else Error(44)
else Error(44);
if glcp = outptr then begin
Gen0(pc_nop);
Gen1(pc_csp,32{pag});
end {if}
else if glcp = erroroutputptr then begin
Gen0(pc_nop);
Gen1(pc_csp,33{pag});
end {else if}
else begin
Load;
Gen0t(pc_stk, cgULong);
Gen1(pc_csp,15{pag});
end;
end
else begin
if nooutput then Error(92);
Gen0(pc_nop);
Gen1(pc_csp,32{pag});
end;
end; {page}
procedure HaltSeed(fsys: setofsys; fprocp: ctp);
{compile a call to halt or seed}
begin {HaltSeed}
Expression(fsys+[rparent],fprocp);
Load;
if gattr.typtr <> nil then begin
if (gattr.typtr <> intptr) and (gattr.typtr <> byteptr) then Error(44);
end
else Error(44);
Gen0t(pc_stk, cgWord);
Gen1(pc_csp,46+lkey);
end; {HaltSeed}
procedure Delete(fsys: setofsys; fprocp: ctp);
{compile a call to the delete string procedure}
begin {Delete}
{load the string to delete characters from}
Expression(fsys+[comma,rparent],fprocp);
if gattr.typtr <> nil then
if IsString(gattr.typtr) then begin
if gattr.kind <> varbl then Error(44);
LoadStringAddress;
end
else Error(44)
else Error(44);
{load the index}
Match(comma,20);
Expression(fsys+[comma,rparent],fprocp);
Load;
Gen0t(pc_stk, cgWord);
Gen0t(pc_bno, cgWord);
if gattr.typtr <> nil then begin
if (gattr.typtr <> intptr) and (gattr.typtr <> byteptr) then
Error(44);
end
else Error(44);
{load the number of chars to delete}
Match(comma,20);
Expression(fsys+[rparent],fprocp);
Load;
Gen0t(pc_stk, cgWord);
Gen0t(pc_bno, cgWord);
if gattr.typtr <> nil then begin
if (gattr.typtr <> intptr) and (gattr.typtr <> byteptr) then Error(44);
end
else Error(44);
{call the delete procedure}
Gen1(pc_csp,68{dlt});
end; {Delete}
procedure Insert(fsys: setofsys; fprocp: ctp);
{compile a call to insert one string an another}
begin {Insert}
{load the string to insert characters into}
Expression(fsys+[comma,rparent],fprocp);
if gattr.typtr <> nil then
if IsString(gattr.typtr) then
LoadStringAddress
else if gattr.typtr = charptr then begin
Load;
Gen0t(pc_stk, cgWord);
GenLdcLong(-1);
Gen0t(pc_stk, cgULong);
Gen0t(pc_bno, cgWord);
end
else Error(44)
else Error(44);
{load the string to insert}
Match(comma,20);
Expression(fsys+[comma,rparent],fprocp);
if gattr.typtr <> nil then
if IsString(gattr.typtr) then begin
if gattr.kind <> varbl then
Error(44);
LoadStringAddress;
Gen0t(pc_bno, cgWord);
end
else Error(44)
else Error(44);
{load the index}
Match(comma,20);
Expression(fsys+[comma,rparent],fprocp);
Load;
Gen0t(pc_stk, cgWord);
Gen0t(pc_bno, cgWord);
if gattr.typtr <> nil then begin
if (gattr.typtr <> intptr) and (gattr.typtr <> byteptr) then Error(44);
end
else Error(44);
{call the insert procedure}
Gen1(pc_csp,69{ins});
end; {Insert}
procedure CommandLineShellID(fsys: setofsys; fprocp: ctp);
{compile a call to CommandLine or ShellID}
begin {CommandLineShellID}
{load the string to place characters in}
Expression(fsys+[rparent],fprocp);
if gattr.typtr <> nil then
if IsString(gattr.typtr) then begin
if gattr.kind <> varbl then Error(44);
LoadStringAddress;
end
else Error(44)
else Error(44);
{call the procedure}
Gen1(pc_csp,46+lkey);
end; {CommandLineShellID}
procedure StartGraphDesk(fsys: setofsys; fprocp: ctp);
{compile a call to StartGraph or StartDesk}
begin {StartGraphDesk}
Expression(fsys+[rparent],fprocp);
Load;
Gen0t(pc_stk, cgWord);
if gattr.typtr <> nil then begin
if (gattr.typtr <> intptr) and (gattr.typtr <> byteptr) then
Error(44);
end
else Error(44);
Gen1(pc_csp,46+lkey);
end; {StartGraphDesk}
procedure EndGraphDesk;
{compile a call to EndGraph or EndDesk}
begin {EndGraphDesk}
Gen0(pc_nop);
Gen1(pc_csp,46+lkey);
end; {EndGraphDesk}
procedure DoRead (fsys: setofsys; fprocp: ctp);
{ compile a read procedure call }
{ }
{ Parameters: }
{ fsys - }
{ fprocp - }
var
lattr,tattr: attr;
lsp : stp;
needBno: boolean; {do we need a pc_bno?}
test: boolean;
standardIn: boolean; {is the read from standard input?}
llb: unsigned; {for allocating temporary space}
inLocalPtr: boolean; {is file ptr in local area?}
begin {DoRead}
inLocalPtr := false;
standardIn := true;
lattr.typtr := textptr;
if sy = lparent then begin
InSymbol;
Variable(fsys + [comma, rparent], fprocp);
if glcp <> nil then
with glcp^ do
if klass = varsm then begin
if vcontvar then
Error(97);
if vlev <> level then
vrestrict := true;
end; {if}
lsp := gattr.typtr;
test := false;
if lsp <> nil then
if lsp^.form = files then
{handle reads from files}
with gattr, lsp^ do begin
if (lkey = 13{readln}) and (typtr <> textptr) then
Error(44);
if access = indrct then begin
Load;
llb := GetTemp(ptrsize);
Gen3t(pc_str, llb, 0, 0, cgULong);
inLocalPtr := true;
dplab := llb;
gattr.isPacked := false;
kind := varbl;
access := drct;
vlevel := level;
FreeTemp(llb, ptrsize);
end; {if}
lattr := gattr;
standardIn := glcp = inptr;
if sy = rparent then begin
if lkey = 7{read} then
Error(44);
test := true;
end {if}
else if sy <> comma then begin
Error(44);
Skip(fsys + [comma, rparent]);
end; {else if}
if sy = comma then begin
InSymbol;
Variable(fsys + [comma, rparent], fprocp);
end {if}
else
test := true;
end {with}
else if noinput then
Error(91);
if lattr.typtr = textptr then begin
{read from a text file}
if not test then
repeat
if glcp <> nil then
with glcp^ do
if klass = varsm then begin
if vcontvar then
Error(97);
if vlev <> level then
vrestrict := true;
end; {if}
needBno := false;
if IsString(gattr.typtr) then begin
if gattr.kind <> expr then begin
LoadAddress;
Gen0t(pc_stk, cgULong);
Gen1t(pc_ldc, StrLen(gattr.typtr), cgWord);
Gen0t(pc_stk, cgWord);
Gen0t(pc_bno, cgWord);
needBno := true;
end; {if}
end {if}
else begin
if gattr.typtr <> nil then
if (gattr.access<>drct) or
(gattr.typtr^.form in [arrays,records,objects,files]) then
LoadAddress;
end; {else}
tattr := gattr;
if not standardIn then begin
gattr := lattr;
if inLocalPtr then
Gen3t(pc_lod, gattr.dplab, 0, 0, cgULong)
else
Load;
Gen0t(pc_stk, cgULong);
if needBno then
Gen0t(pc_bno, cgULong);
end; {if}
if tattr.typtr <> nil then
if (tattr.typtr^.form <= subrange) or IsString(tattr.typtr) then
begin
if standardIn then
Gen0(pc_nop);
if CompTypes(intptr, tattr.typtr) then begin
if standardIn then
Gen1(pc_csp, 59{rii})
else
Gen1(pc_csp, 5{rdi});
CheckBnds(tattr.typtr);
Store(tattr);
end {if}
else if CompTypes(longptr, tattr.typtr) then begin
if standardIn then
Gen1(pc_csp, 98{ril})
else
Gen1(pc_csp, 99{rdl});
CheckBnds(tattr.typtr);
Store(tattr);
end {else if}
else if CompTypes(charptr, tattr.typtr) then begin
if standardIn then
Gen1(pc_csp, 58{ric})
else
Gen1(pc_csp, 7{rdc});
CheckBnds(tattr.typtr);
Store(tattr);
end {else if}
else if CompTypes(realptr, tattr.typtr) then begin
if standardIn then
Gen1(pc_csp, 61{rir})
else
Gen1(pc_csp, 6{rdr});
CheckBnds(tattr.typtr);
Store(tattr);
end {else if}
else if CompTypes(stringptr, tattr.typtr) then begin
if standardIn then
Gen1(pc_csp, 84{ris})
else
Gen1(pc_csp, 50{rds});
end {esle if}
else
Error(44);
end {if}
else
Error(44);
test := sy <> comma;
if not test then begin
InSymbol;
Variable(fsys + [comma, rparent], fprocp);
end; {if}
until test;
end {if}
else if not test then begin
{do non-text reads}
repeat
if glcp <> nil then
with glcp^ do
if klass = varsm then begin
if vcontvar then
Error(97);
if vlev <> level then
vrestrict := true;
end; {if}
if gattr.typtr <> nil then
if (gattr.access<>drct) or
(gattr.typtr^.form in [arrays,records,files]) then
LoadAddress;
tattr := gattr;
if not CompTypes(gattr.typtr, lattr.typtr^.filtype) then
if not CompObjects(gattr.typtr, lattr.typtr^.filtype) then
Error(44);
gattr := lattr;
if inLocalPtr then
Gen3t(pc_lod, gattr.dplab, 0, 0, cgULong)
else
Load;
with gattr do begin
typtr := lattr.typtr^.filtype;
kind := varbl;
isPacked := false;
access := indrct;
idplmt := 0;
end; {with}
if gattr.typtr^.form in [scalar,subrange,pointerStruct,power,objects]
then
Load
else
LoadAddress;
case tattr.typtr^.form of
scalar,subrange: begin
CheckBnds(tattr.typtr);
Store(tattr);
end;
pointerStruct,power,objects:
Store(tattr);
arrays,records:
Gen2(pc_mov, long(tattr.typtr^.size).msw,
long(tattr.typtr^.size).lsw);
files: Error(71);
end; {case}
{get the next file variable}
gattr := lattr;
if inLocalPtr then
Gen3t(pc_lod, gattr.dplab, 0, 0, cgULong)
else
Load;
Gen0t(pc_stk, cgULong);
Gen1(pc_csp, 1{get});
test := sy <> comma;
if not test then begin
InSymbol;
Variable(fsys+[comma,rparent], fprocp);
end; {if}
until test;
end; {else if not test}
Match(rparent, 4);
end {if}
else if lkey = 7{read} then
Error(44);
if lkey = 13{readln} then begin
if standardIn then begin
Gen0(pc_nop);
Gen1(pc_csp, 60{rin});
end {if}
else begin
gattr := lattr;
if inLocalPtr then
Gen3t(pc_lod, gattr.dplab, 0, 0, cgULong)
else
Load;
Gen0t(pc_stk, cgULong);
Gen1(pc_csp, 13{rln})
end; {else}
end; {if}
end; {DoRead}
procedure DoWrite(fsys: setofsys; fprocp: ctp);
{compile a call to write, writeln}
var
lsp: stp;
default,defaultr : boolean;
llkey: keyrange;
lcp: ctp;
len: addrrange;
lattr,tattr: attr;
test: boolean;
standardOut,errorOut: boolean; {is the write to the console?}
llb: unsigned; {for allocating temporary space}
inLocalPtr: boolean; {is file ptr in local area?}
procedure LoadFile;
{load the file variable}
begin {LoadFile}
gattr := lattr;
if inLocalPtr then
Gen3t(pc_lod, gattr.dplab, 0, 0, cgULong)
else
Load;
end; {LoadFile}
begin {DoWrite}
inLocalPtr := false;
llkey := lkey;
standardOut := true;
errorOut := false;
lattr.typtr := textptr;
if sy = lparent then begin
InSymbol;
Expression(fsys + [comma,colon,rparent],fprocp);
lsp := gattr.typtr;
test := false;
if lsp <> nil then
if lsp^.form = files then
with gattr, lsp^ do begin
if access = indrct then begin
Load;
llb := GetTemp(ptrsize);
Gen3t(pc_str, llb, 0, 0, cgULong);
gattr.isPacked := false;
kind := varbl;
access := drct;
vlevel := level;
dplab := llb;
inLocalPtr := true;
FreeTemp(llb, ptrsize);
end;
lattr := gattr;
standardOut := glcp = outptr;
errorOut := glcp = erroroutputptr;
if (lkey = 14{writeln}) and (typtr <> textptr) then Error(44);
if sy = rparent then begin
if llkey = 8{write} then Error(44);
test := true;
end
else if sy <> comma then begin
Error(44);
Skip(fsys+[comma,rparent]);
end;
if sy = comma then begin
InSymbol;
if lattr.typtr = textptr then
Expression(fsys+[comma,colon,rparent],fprocp);
end
else test := true
end
else if nooutput then Error(92);
if lattr.typtr = textptr then begin
{text file reads}
if not test then
repeat
lsp := gattr.typtr;
if lsp^.form = subrange then
lsp := lsp^.rangetype;
if lsp <> nil then
if lsp^.form <= subrange then begin
Load;
if (lsp = intptr) or (lsp = byteptr) or (lsp = charptr)
or (lsp = boolptr) then
Gen0t(pc_stk, cgWord)
else if lsp = longptr then
Gen0t(pc_stk, cgLong)
else if IsReal(lsp) then
Gen0t(pc_stk, cgExtended)
else if lsp <> nil then
Gen0t(pc_stk, cgULong);
end {if}
else begin
if IsString(gattr.typtr) then
LoadStringAddress
else begin
LoadAddress;
Gen0t(pc_stk, cgULong);
end; {else}
end;
if sy = colon then begin
InSymbol;
Expression(fsys + [comma,colon,rparent],fprocp);
Load;
Gen0t(pc_stk, cgWord);
Gen0t(pc_bno, cgWord);
if gattr.typtr <> nil then
if (gattr.typtr <> intptr) and (gattr.typtr <> byteptr) then
Error(44);
if debug then
Gen2t(pc_chk, 0, maxint, cgUWord);
default := false;
end
else default := true;
if sy = colon then begin
InSymbol;
Expression(fsys + [comma,rparent],fprocp);
Load;
Gen0t(pc_stk, cgWord);
Gen0t(pc_bno, cgWord);
if gattr.typtr <> nil then
if (gattr.typtr <> intptr) and (gattr.typtr <> byteptr) then
Error(44);
if not IsReal(lsp) then
Error(50);
defaultr := false;
end
else defaultr := true;
if (lsp = intptr) or (lsp = byteptr) then begin
if default then begin
Gen1t(pc_ldc, intfw, cgWord);
Gen0t(pc_stk, cgWord);
Gen0t(pc_bno, cgWord);
end; {if}
if standardOut then
Gen1(pc_csp,16{woi})
else if errorOut then
Gen1(pc_csp,42{wei})
else begin
LoadFile;
Gen0t(pc_stk, cgULong);
Gen0t(pc_bno, cgULong);
Gen1(pc_csp,9{wri});
end;
end
else if lsp = longptr then begin
if default then begin
Gen1t(pc_ldc, longfw, cgWord);
Gen0t(pc_stk, cgWord);
Gen0t(pc_bno, cgWord);
end; {if}
if standardOut then
Gen1(pc_csp,100{wol})
else if errorOut then
Gen1(pc_csp,101{wel})
else begin
LoadFile;
Gen0t(pc_stk, cgULong);
Gen0t(pc_bno, cgULong);
Gen1(pc_csp,102{wrl});
end;
end
else if IsReal(lsp) then begin
if default then begin
Gen1t(pc_ldc, realfw, cgWord);
Gen0t(pc_stk, cgWord);
Gen0t(pc_bno, cgWord);
end; {if}
if defaultr then begin
Gen1t(pc_ldc, 0, cgWord);
Gen0t(pc_stk, cgWord);
Gen0t(pc_bno, cgWord);
end; {if}
if standardOut then
Gen1(pc_csp,62{wor})
else if errorOut then
Gen1(pc_csp,53{wer})
else begin
LoadFile;
Gen0t(pc_stk, cgULong);
Gen0t(pc_bno, cgULong);
Gen1(pc_csp,10{wrr});
end; {else}
end {else if}
else if lsp = charptr then begin
if standardOut then
if default then
Gen1(pc_csp,40{wol})
else
Gen1(pc_csp,37{woc})
else if errorOut then
if default then
Gen1(pc_csp,41{wel})
else
Gen1(pc_csp,39{wec})
else begin
if default then begin
Gen1t(pc_ldc, 1, cgWord);
Gen0t(pc_stk, cgWord);
Gen0t(pc_bno, cgWord);
end; {if}
LoadFile;
Gen0t(pc_stk, cgULong);
Gen0t(pc_bno, cgULong);
Gen1(pc_csp,8{wrc});
end;
end
else if lsp = boolptr then begin
if default then begin
Gen1t(pc_ldc, boolfw, cgWord);
Gen0t(pc_stk, cgWord);
Gen0t(pc_bno, cgWord);
end; {if}
if standardOut then
Gen1(pc_csp,29{wob})
else if errorOut then
Gen1(pc_csp,31{web})
else begin
LoadFile;
Gen0t(pc_stk, cgULong);
Gen0t(pc_bno, cgULong);
Gen1(pc_csp,46{wrb});
end;
end
else if lsp <> nil then begin
if IsString(lsp) then begin
if default then begin
Gen1t(pc_ldc, $8000, cgWord);
Gen0t(pc_stk, cgWord);
Gen0t(pc_bno, cgWord);
end; {if}
if standardOut then
Gen1(pc_csp,21{wos})
else if errorOut then
Gen1(pc_csp,25{wes})
else begin
LoadFile;
Gen0t(pc_stk, cgULong);
Gen0t(pc_bno, cgULong);
Gen1(pc_csp,45{wrs});
end;
end
else Error(44);
end;
test := sy <> comma;
if not test then begin
InSymbol;
Expression(fsys + [comma,colon,rparent],fprocp)
end
until test;
end
else if not test then begin
{handle non-text files}
repeat
{assign the Expression to the file variable}
LoadFile;
tattr := gattr;
with tattr do begin
typtr := gattr.typtr^.filtype;
isPacked := false;
kind := varbl;
access := indrct;
idplmt := 0;
end;
if debug then
GenL2t(pc_chk, 1, maxaddr, cgULong);
Expression(fsys+[comma,colon,rparent],fprocp);
lsp := gattr.typtr;
if (lsp^.form <= subrange) or (lsp^.form = objects) then
Load
else
LoadAddress;
if not CompTypes(lsp,lattr.typtr^.filtype) then
if not CompObjects(lsp,lattr.typtr^.filtype) then
Error(44);
case tattr.typtr^.form of
scalar,subrange: begin
CheckBnds(tattr.typtr);
Store(tattr);
end;
pointerStruct,power,objects:
Store(tattr);
arrays,records:
Gen2(pc_mov, long(tattr.typtr^.size).msw, long(tattr.typtr^.size).lsw);
files: Error(71);
end; {case}
{write the file variable to the file}
LoadFile;
Gen0t(pc_stk, cgULong);
Gen1(pc_csp,2{put});
test := sy<>comma;
if not test then InSymbol;
until test;
end; {else if not test}
Match(rparent,4);
end
else if lkey = 8{write} then Error(44);
if lkey = 14{writeln} then begin
if standardOut then begin
Gen0(pc_nop);
Gen1(pc_csp,26{wol});
end {if}
else if errorOut then begin
Gen0(pc_nop);
Gen1(pc_csp,27{wel});
end {else if}
else begin
LoadFile;
Gen0t(pc_stk, cgULong);
Gen1(pc_csp,14{wln});
end;
end;
end; {DoWrite}
procedure DoPack(fsys: setofsys; fprocp: ctp);
{compile a call to pack}
var
lsp,lsp1: stp;
elSize: longint; {element size}
lmin,lmax: longint; {subrange of unpacked array}
begin {DoPack}
{get the unpacked array}
Variable(fsys + [comma,rparent],fprocp);
LoadAddress;
Gen0t(pc_stk, cgULong);
if gattr.typtr <> nil then
with gattr.typtr^ do
if (form = arrays) and (ispacked = pkunpacked) then begin
Gen1t(pc_ldc, long(aeltype^.size).lsw, cgUWord);
Gen0t(pc_stk, cgUWord);
Gen0t(pc_bno, cgUWord);
GenLdcLong(size div aeltype^.size);
Gen0t(pc_stk, cgULong);
Gen0t(pc_bno, cgULong);
lsp := inxtype;
lsp1 := aeltype;
GetBounds(lsp,lmin,lmax);
end
else Error(44);
Match(comma,20);
{get the staring index}
Expression(fsys + [comma,rparent],fprocp);
Load;
if CompTypes(longptr, lsp) then
if (gattr.typtr = intptr) or (gattr.typtr = bytePtr) then begin
Gen2(pc_cnv,ord(cgWord),ord(cgLong));
gattr.typtr := longptr;
end; {end}
if gattr.typtr <> nil then
if gattr.typtr^.form <> scalar then
Error(44)
else if not CompTypes(lsp,gattr.typtr) then
Error(44);
if not CompTypes(longptr, gattr.typtr) then begin
Gen2(pc_cnv, ord(GetType(gattr.typtr, false)), ord(cgLong));
gattr.typtr := longptr;
end; {end}
Match(comma,20);
if lmin <> 0 then begin
GenLdcLong(lmin);
Gen0(pc_sbl);
end; {if}
Gen0t(pc_stk, cgULong);
Gen0t(pc_bno, cgULong);
{get the packed array}
Variable(fsys + [rparent],fprocp);
LoadAddress;
Gen0t(pc_stk, cgULong);
Gen0t(pc_bno, cgULong);
if gattr.typtr <> nil then
with gattr.typtr^ do
if (form = arrays) and (ispacked = pkpacked) then begin
if not CompTypes(aeltype,lsp1) then Error(44);
elSize := aelType^.size;
if (aelType = charptr) or (aelType = boolptr) then
elSize := packedCharSize;
Gen1t(pc_ldc, long(elSize).lsw, cgUWord);
Gen0t(pc_stk, cgUWord);
Gen0t(pc_bno, cgUWord);
GenLdcLong(size div elSize);
Gen0t(pc_stk, cgULong);
Gen0t(pc_bno, cgULong);
end {if}
else Error(44);
{move the elements}
Gen1(pc_csp, 51{pak});
end; {DoPack}
procedure DoUnpack(fsys: setofsys; fprocp: ctp);
{compile a call to unpack}
var
lsp,lsp1: stp;
elSize: longint; {element size}
lmin,lmax: longint; {subrange of unpacked array}
begin {DoUnpack}
Variable(fsys + [comma,rparent],fprocp);
LoadAddress;
Gen0t(pc_stk, cgULong);
if gattr.typtr <> nil then
with gattr.typtr^ do
if (form = arrays) and (ispacked = pkpacked) then begin
elSize := aelType^.size;
if (aelType = charptr) or (aelType = boolptr) then
elSize := packedCharSize;
lsp1 := aeltype;
Gen1t(pc_ldc, long(elSize).lsw, cgWord);
Gen0t(pc_stk, cgUWord);
Gen0t(pc_bno, cgUWord);
GenLdcLong(size div elSize);
Gen0t(pc_stk, cgULong);
Gen0t(pc_bno, cgULong);
end
else Error(44);
Match(comma,20);
Variable(fsys + [comma,rparent],fprocp);
LoadAddress;
Gen0t(pc_stk, cgULong);
Gen0t(pc_bno, cgULong);
if gattr.typtr <> nil then
with gattr.typtr^ do
if (form = arrays) and (ispacked = pkunpacked) then begin
if not CompTypes(aeltype,lsp1) then Error(44);
Gen1t(pc_ldc, long(aeltype^.size).lsw, cgWord);
Gen0t(pc_stk, cgUWord);
Gen0t(pc_bno, cgUWord);
GenLdcLong(size div aeltype^.size);
Gen0t(pc_stk, cgULong);
Gen0t(pc_bno, cgULong);
lsp := inxtype;
GetBounds(lsp,lmin,lmax);
end
else Error(44);
Match(comma,20);
Expression(fsys + [rparent],fprocp);
Load;
if CompTypes(longptr, lsp) then
if (gattr.typtr = intptr) or (gattr.typtr = bytePtr) then begin
Gen2(pc_cnv, ord(cgWord), ord(cgLong));
gattr.typtr := longptr;
end; {end}
if gattr.typtr <> nil then
if gattr.typtr^.form <> scalar then
Error(44)
else if not CompTypes(lsp,gattr.typtr) then
Error(44);
if not CompTypes(longptr, gattr.typtr) then begin
Gen2(pc_cnv, ord(GetType(gattr.typtr, false)), ord(cgLong));
gattr.typtr := longptr;
end; {end}
if lmin <> 0 then begin
GenLdcLong(lmin);
Gen0(pc_sbl);
end; {if}
Gen0t(pc_stk, cgULong);
Gen0t(pc_bno, cgULong);
Gen1(pc_csp, 52{upk});
end; {DoUnpack}
procedure DoNew (fsys: setofsys; fprocp: ctp);
{ compile a call to new }
{ }
{ parameters: }
{ fsys - }
{ fprocp - }
label 1;
var
lattr: attr; {pointer/object variable's gattr}
lsize: addrrange; {amount of memory to allocate}
lsp,lsp1: stp;
lval: valu;
ofld: ctp; {object field list}
varts: integer;
function InitMethods (lcp: ctp): unsigned;
{ Set the address for all methods in a new object }
{ }
{ parameters: }
{ lsp - head of object field tree }
{ }
{ returns: Number of methods }
var
count: unsigned;
begin {InitMethods}
count := 0;
if lcp^.llink <> nil then
count := InitMethods(lcp^.llink);
if lcp^.rlink <> nil then
count := count + InitMethods(lcp^.rlink);
if lcp^.klass in [proc,func] then begin
count := count + 1;
Gen0Name(pc_lad, lcp^.pfoname);
Gen0t(pc_stk, cgULong);
GenLdcLong(lcp^.pfaddr);
Gen0t(pc_stk, cgULong);
Gen0t(pc_bno, cgULong);
Gen0t(pc_bno, cgULong);
end; {if}
InitMethods := count;
end; {InitMethods}
begin {DoNew}
{get the pointer to allocate}
Variable(fsys + [comma,rparent],fprocp);
lattr := gattr;
LoadAddress;
Gen0t(pc_stk, cgULong);
{examine the variable to see how much memory to allocate}
lsp := nil;
varts := 0;
lsize := 0;
ofld := nil;
if gattr.typtr <> nil then
with gattr.typtr^ do
if form = pointerStruct then begin
if eltype <> nil then begin
lsize := eltype^.size;
if eltype^.form = records then
lsp := eltype^.recvar;
end; {if}
end {if}
else if (form = objects) and objdef then begin
lsize := objsize;
ofld := objfld;
end {else if}
else
Error(44);
{handle the variant parts}
while sy = comma do begin
InSymbol;
DoConstant(fsys + [comma,rparent],lsp1,lval);
varts := varts+1;
if lsp = nil then
Error(82)
else if lsp^.form <> tagfld then
Error(86)
else if lsp^.tagfieldp <> nil then
if CompTypes(lsp^.tagfieldp^.idtype,lsp1) then begin
lsp1 := lsp^.fstvar;
while lsp1 <> nil do
with lsp1^ do
if varval = lval.ival then begin
lsize := size;
lsp := subvar;
goto 1;
end {if}
else
lsp1 := nxtvar;
end {if}
else
Error(44);
1: end {while} ;
{for objects, set up size, generation, and method addresses}
if ofld <> nil then begin
if lattr.typtr <> nil then begin
Gen1t(pc_ldc, lattr.typtr^.objlevel, cgUWord);
Gen0t(pc_stk, cgUWord);
Gen0t(pc_bno, cgUWord);
end; {if}
GenLdcLong(lsize);
Gen0t(pc_stk, cgULong);
Gen0t(pc_bno, cgULong);
Gen1t(pc_ldc, InitMethods(ofld), cgUWord);
Gen0t(pc_stk, cgUWord);
Gen0t(pc_bno, cgUWord);
{generate the call to allocate memory}
Gen1(pc_csp,118{newobj});
end {if}
else if lsize < maxint then begin
Gen1t(pc_ldc, long(lsize).lsw, cgWord);
Gen0t(pc_stk, cgWord);
Gen0t(pc_bno, cgWord);
Gen1(pc_csp,11{new});
end {if}
else begin
if lsize > $010000 then
if smallMemoryModel then
Error(122);
GenLdcLong(lsize);
Gen0t(pc_stk, cgULong);
Gen0t(pc_bno, cgULong);
Gen1(pc_csp,116{new4});
end; {else}
{if this points to a file, zero the area}
gattr := lattr;
if gattr.typtr <> nil then
if gattr.typtr^.form <> objects then
if gattr.typtr^.hasSFile then begin
Gen1t(pc_ldc, ord(gattr.typtr^.size), cgWord);
Gen0t(pc_stk, cgWord);
Load;
Gen0t(pc_stk, cgULong);
Gen0t(pc_bno, cgULong);
Gen1(pc_csp,35{clr});
end; {if}
end; {DoNew}
procedure DoSizeof;
{compile a call to sizeof}
var
lcp: ctp;
begin {DoSizeof}
Match(lparent,9);
SearchId([types,varsm], lcp);
if lcp^.idtype^.size < maxint then begin
Gen1t(pc_ldc, ord(lcp^.idtype^.size), cgWord);
gattr.typtr := intptr;
end {if}
else begin
GenLdcLong(lcp^.idtype^.size);
gattr.typtr := longptr;
end; {else}
InSymbol;
end; {DoSizeof}
procedure DoDispose (fsys: setofsys; fprocp: ctp);
{ Compile a call to dispose }
{ }
{ parameters: }
{ fsys - }
{ fprocp - }
label 1;
var
lsp,lsp1: stp;
lval: valu;
begin {DoDispose}
{get the pointer to dispose}
Expression(fsys+[rparent,comma],fprocp);
if gattr.typtr <> nil then
if gattr.typtr^.form = pointerStruct then begin
{dispose of a pointer}
Load;
Gen0t(pc_stk, cgULong);
Gen1(pc_csp,17{dsp});
lsp := nil;
with gattr.typtr^ do
if eltype <> nil then
if eltype^.form = records then
lsp := eltype^.recvar;
while sy = comma do begin
InSymbol;
DoConstant(fsys+[comma,rparent],lsp1,lval);
if lsp = nil then Error(82)
else if lsp^.form <> tagfld then
Error(86)
else if lsp^.tagfieldp <> nil then
if CompTypes(lsp^.tagfieldp^.idtype,lsp1) then begin
lsp1 := lsp^.fstvar;
while lsp1 <> nil do
with lsp1^ do
if varval = lval.ival then begin
lsp := subvar;
goto 1;
end {if}
else
lsp1 := nxtvar;
lsp := nil;
end {if}
else
Error(44);
1: end; {while}
end {if}
else if gattr.typtr^.form = objects then begin
{dispose of an object}
Load;
if debug then
GenL2t(pc_chk, 1, maxaddr, cgULong);
Gen0t(pc_stk, cgULong);
Gen1(pc_csp,17{dsp});
end {else if}
else
Error(44);
end; {DoDispose}
procedure Abs;
{compile an absolute value function call}
begin {Abs}
if gattr.typtr <> nil then
if (gattr.typtr = intptr) or (gattr.typtr = byteptr) then
Gen0(pc_abi)
else if IsReal(gattr.typtr) then
Gen0(pc_abr)
else if gattr.typtr = longptr then
Gen0(pc_abl)
else begin
Error(51);
gattr.typtr := intptr;
end;
end; {Abs}
procedure Sqr;
{compile a call to the square function}
begin {Sqr}
if gattr.typtr <> nil then
if (gattr.typtr = intptr) or (gattr.typtr = byteptr) then
Gen0(pc_sqi)
else if IsReal(gattr.typtr) then
Gen0(pc_sqr)
else if gattr.typtr = longptr then
Gen0(pc_sql)
else begin
Error(51);
gattr.typtr := intptr;
end;
end; {Sqr}
procedure TruncRound;
{compile trunc and round calls}
begin {TruncRound}
if gattr.typtr <> nil then
if not IsReal(gattr.typtr) then
Error(51);
if lkey = 3{trunc} then begin
Gen2(pc_cnv,ord(cgReal),ord(cgWord));
gattr.typtr := intptr;
end {if}
else if lkey = 42{trunc4} then begin
Gen2(pc_cnv,ord(cgReal),ord(cgLong));
gattr.typtr := longptr;
end {else if}
else if lkey = 43{round4} then begin
Gen0(pc_rn4);
gattr.typtr := longptr;
end {else if}
else begin
Gen0(pc_rnd);
gattr.typtr := intptr;
end; {else}
end; {TruncRound}
procedure DoOdd;
{compile a call to the odd function}
begin {DoOdd}
if (gattr.typtr = intptr) or (gattr.typtr = byteptr) then
Gen0(pc_odd)
else if gattr.typtr = longptr then
Gen0(pc_odl)
else
Error(51);
gattr.typtr := boolptr;
end; {DoOdd}
procedure DoOrd;
{compile the ord function}
begin {DoOrd}
if gattr.typtr <> nil then
if gattr.typtr^.form > pointerStruct then
Error(51)
else if (gattr.typtr^.form = pointerStruct) or (gattr.typtr = longptr) then
begin
if iso then Error(112);
Gen2(pc_cnv,ord(cgLong),ord(cgWord));
end
else if not (GetType(gattr.typtr, gattr.isPacked)
in [cgByte,cgUByte,cgWord,cgUWord]) then
Error(51);
gattr.typtr := intptr;
end; {DoOrd}
procedure DoOrd4;
{ compile the ord4 function }
begin {DoOrd4}
if gattr.typtr <> nil then
if gattr.typtr^.form > pointerStruct then
Error(51)
else if GetType(gattr.typtr, gattr.isPacked)
in [cgByte,cgUByte,cgWord,cgUWord] then
Gen2(pc_cnv,ord(cgWord),ord(cgLong))
else if not (GetType(gattr.typtr, gattr.isPacked) in [cgLong,cgULong]) then
Error(51);
gattr.typtr := longptr;
end; {DoOrd4}
procedure DoPointer;
{compile the Pointer function}
begin {DoPointer}
if gattr.typtr <> nil then
if gattr.typtr^.form > pointerStruct then
Error(51)
else if (gattr.typtr^.form <> pointerStruct) and (gattr.typtr <> longptr)
then
Gen2(pc_cnv,ord(cgWord),ord(cgLong));
{else the value is already 4 bytes}
gattr.typtr := nilptr;
end; {DoPointer}
procedure DoChr;
{compile a call to the chr function}
begin {DoChr}
if gattr.typtr <> nil then
if (gattr.typtr <> intptr) and (gattr.typtr <> byteptr) then Error(51);
{gen0(59( chr ));}
gattr.typtr := charptr;
end; {DoChr}
procedure PredSucc;
{compile a call to pred or succ}
begin {PredSucc}
if gattr.typtr <> nil then
if (gattr.typtr^.form <> scalar) or IsReal(gattr.typtr) then
Error(51);
if lkey = 8{pred} then
Gen1t(pc_dec, 1, GetType(gattr.typtr, gattr.isPacked))
else
Gen1t(pc_inc, 1, GetType(gattr.typtr, gattr.isPacked));
CheckBnds(gattr.typtr);
end; {PredSucc}
procedure DoEOF (fsys: setofsys; fprocp: ctp);
{ compile a call to eof or eoln }
{ }
{ Parameters: }
{ fsys - }
{ fprocp - }
begin {DoEOF}
if sy = lparent then begin
{handle a call for a given file}
InSymbol;
Variable(fsys + [rparent],fprocp);
Match(rparent,4);
if lkey = 11{eoln} then
if gattr.typtr <> textptr then
Error(44);
if gattr.typtr <> nil then
if gattr.typtr^.form <> files then
Error(51);
if glcp = inptr then
if lkey=10{eof} then
Gen1tName(pc_ldo, 0, cgUWord, @'~EOFINPUT')
else
Gen1tName(pc_ldo, 0, cgUWord, @'~EOLNINPUT')
else begin
Load;
Gen0t(pc_stk, cgULong);
Gen1t(pc_csp, 38+lkey{eof,eol}, cgUByte);
end; {else}
end {if}
else begin
{handle a call for standard in}
if noinput then
Error(91);
Gen0(pc_nop);
Gen1t(pc_csp, 175+lkey{eof,eol}, cgUByte);
end; {else}
gattr.typtr := boolptr;
end; {DoEOF}
procedure trans;
{compile transendental functions}
var
tkey: keyrange; {so we can change the number}
begin {trans}
tkey := lkey;
if gattr.typtr <> nil then
if (gattr.typtr = intptr) or (gattr.typtr = byteptr) then begin
gen2(pc_cnv,ord(cgWord),ord(cgReal));
gattr.typtr := realptr;
end
else if gattr.typtr = longptr then begin
Gen2(pc_cnv,ord(cgLong),ord(cgReal));
gattr.typtr := realptr;
end;
if not IsReal(gattr.typtr) then
Error(59);
case tkey of
12: Gen0(pc_sin);
13: Gen0(pc_cos);
14: Gen0(pc_exp);
15: Gen0(pc_sqt);
16: Gen0(pc_log);
17: Gen0(pc_atn);
36: Gen0(pc_tan);
37: Gen0(pc_acs);
38: Gen0(pc_asn);
otherwise:
Error(113);
end; {case}
end; {trans}
procedure DoArctan2(fsys: setofsys; fprocp: ctp);
{compile a call to Arctan2}
begin {DoArctan2}
Match(lparent,9);
Expression(fsys+[comma,rparent],fprocp);
Load;
if gattr.typtr <> nil then
if (gattr.typtr = intptr) or (gattr.typtr = byteptr) then begin
gen2(pc_cnv,ord(cgWord),ord(cgReal));
gattr.typtr := realptr;
end
else if gattr.typtr = longptr then begin
Gen2(pc_cnv,ord(cgLong),ord(cgReal));
gattr.typtr := realptr;
end;
if not IsReal(gattr.typtr) then
Error(59);
Match(comma,20);
Expression(fsys+[rparent],fprocp);
Load;
if gattr.typtr <> nil then
if (gattr.typtr = intptr) or (gattr.typtr = byteptr) then begin
gen2(pc_cnv,ord(cgWord),ord(cgReal));
gattr.typtr := realptr;
end
else if gattr.typtr = longptr then begin
Gen2(pc_cnv,ord(cgLong),ord(cgReal));
gattr.typtr := realptr;
end;
if not IsReal(gattr.typtr) then
Error(59);
Gen0(pc_at2);
end; {DoArctan2}
procedure DoUserID;
{compile a call to UserID}
begin {DoUserID}
Gen1tName(pc_ldo, 0, cgUWord, @'~USER_ID');
gattr.typtr := intptr;
end; {DoUserID}
procedure ToolError;
{compile a call to tollerror}
begin {ToolError}
Gen1tName(pc_ldo, 0, cgUWord, @'~TOOLERROR');
gattr.typtr := intptr;
end; {ToolError}
procedure Cnvfs(fsys: setofsys; fprocp: ctp);
{compile a call to Cnvrs or Cnvds}
begin {Cnvfs}
{load the value to convert}
Match(lparent,9);
Expression(fsys+[comma,rparent],fprocp);
Load;
if gattr.typtr <> nil then
if (gattr.typtr = intptr) or (gattr.typtr = byteptr) then begin
Gen2(pc_cnv,ord(cgWord),ord(cgReal));
gattr.typtr := realptr;
end
else if (gattr.typtr = longptr) then begin
Gen2(pc_cnv,ord(cgLong),ord(cgReal));
gattr.typtr := realptr;
end;
if not IsReal(gattr.typtr) then
Error(59);
Gen0t(pc_stk, cgExtended);
{load the two required field widths}
Match(comma,20);
Expression(fsys+[comma,rparent],fprocp);
Load;
Gen0t(pc_stk, cgWord);
Gen0t(pc_bno, cgWord);
if gattr.typtr <> nil then begin
if (gattr.typtr <> intptr) and (gattr.typtr <> byteptr) then Error(44);
end
else Error(44);
Match(comma,20);
Expression(fsys+[rparent],fprocp);
Load;
Gen0t(pc_stk, cgWord);
Gen0t(pc_bno, cgWord);
if gattr.typtr <> nil then begin
if (gattr.typtr <> intptr) and (gattr.typtr <> byteptr) then Error(44);
end
else Error(44);
Gen1t(pc_csp,77{cfs},cgString);
gattr.typtr := stringptr;
gattr.kind := expr;
stringHeap := true;
end; {Cnvfs}
procedure Cnvis;
{compile a call to Cnvis}
begin {Cnvis}
if (gattr.typtr = intptr) or (gattr.typtr = byteptr) then
Gen2(pc_cnv,ord(cgWord),ord(cgLong))
else if gattr.typtr <> longptr then Error(44);
Gen0t(pc_stk, cgULong);
Gen1t(pc_csp,78{cis},cgString);
gattr.typtr := stringptr;
gattr.kind := expr;
stringHeap := true;
end; {Cnvis}
procedure CnvSF(fsys: setofsys; fprocp: ctp);
{compile a call to CnvSR or CnvSD}
begin {Cnvsf}
Match(lparent,9);
Expression(fsys+[rparent],fprocp);
if gattr.typtr <> nil then
if IsString(gattr.typtr) then
LoadStringAddress
else Error(44)
else Error(44);
gattr.typtr := realptr;
Gen1t(pc_csp,79{csf},cgReal);
end; {Cnvsf}
procedure CnvSI(fsys: setofsys; fprocp: ctp);
{compile a call to CnvSI}
begin {Cnvsi}
Match(lparent,9);
Expression(fsys+[rparent],fprocp);
if gattr.typtr <> nil then
if IsString(gattr.typtr) then
LoadStringAddress
else Error(44)
else Error(44);
gattr.typtr := intptr;
Gen1t(pc_csp,80{csi},cgWord);
end; {Cnvsi}
procedure CnvSL(fsys: setofsys; fprocp: ctp);
{compile a call to CnvSL}
begin {Cnvsl}
Match(lparent,9);
Expression(fsys+[rparent],fprocp);
if gattr.typtr <> nil then
if IsString(gattr.typtr) then
LoadStringAddress
else Error(44)
else Error(44);
gattr.typtr := longptr;
Gen1t(pc_csp,81{csl},cgLong);
end; {Cnvsl}
procedure Randomf;
{generate a random real or double}
begin {Randomf}
Gen0(pc_nop);
gattr.typtr := realptr;
Gen1t(pc_csp,82{rnf},cgReal);
end; {Randomf}
procedure RandomInteger;
{generate a random integer}
begin {RandomInteger}
Gen0(pc_nop);
gattr.typtr := intptr;
Gen1t(pc_csp,83{rni},cgWord);
end; {RandomInteger}
procedure RandomLongInt;
{generate a random longint}
begin {RandomLongInt}
Gen0(pc_nop);
gattr.typtr := longptr;
Gen1t(pc_csp,83{rni},cgLong);
end; {RandomLongint}
procedure Concat(fsys: setofsys; fprocp: ctp);
{concatonate a series of strings}
var
numStrings: integer; {# of strings to concatonate}
stop: boolean; {loop termination var}
begin {Concat}
stringHeap := true;
numStrings := 0;
{mark stack so parameters are tagged}
{load the strings}
Match(lparent,9);
repeat
Expression(fsys+[comma,rparent],fprocp);
if gattr.typtr <> nil then
if IsString(gattr.typtr) then
LoadStringAddress
else if gattr.typtr = charptr then begin
Load;
Gen0t(pc_stk, cgUWord);
GenLdcLong(-1);
Gen0t(pc_stk, cgULong);
Gen0t(pc_bno, cgULong);
end
else Error(44)
else Error(44);
stop := sy <> comma;
if not stop then InSymbol;
numStrings := numStrings+1;
if numStrings <> 1 then
Gen0t(pc_bno, cgULong);
until stop or eofl;
Match(rparent,4);
Gen1t(pc_ldc, numStrings, cgWord);
Gen0t(pc_stk, cgWord);
Gen0t(pc_bno, cgWord);
{call the concat function}
Gen1t(pc_csp,85{cat},cgString);
gattr.typtr := stringptr;
gattr.kind := expr;
end; {Concat}
procedure Copy(fsys: setofsys; fprocp: ctp);
{compile a call to copy characters from a string}
begin {Copy}
stringHeap := true;
{load the string to copy characters from}
Match(lparent,9);
Expression(fsys+[comma,rparent],fprocp);
if gattr.typtr <> nil then
if IsString(gattr.typtr) then
LoadStringAddress
else Error(44)
else Error(44);
{load the index}
Match(comma,20);
Expression(fsys+[comma,rparent],fprocp);
Load;
Gen0t(pc_stk, cgWord);
Gen0t(pc_bno, cgWord);
if gattr.typtr <> nil then begin
if (gattr.typtr <> intptr) and (gattr.typtr <> byteptr) then Error(44);
end
else Error(44);
{load the number of chars to copy}
Match(comma,20);
Expression(fsys+[rparent],fprocp);
Load;
Gen0t(pc_stk, cgWord);
Gen0t(pc_bno, cgWord);
if gattr.typtr <> nil then begin
if (gattr.typtr <> intptr) and (gattr.typtr <> byteptr) then Error(44);
end
else Error(44);
{call the copy function}
Gen1t(pc_csp,86{cpy},cgString);
gattr.typtr := stringptr;
gattr.kind := expr;
end; {Copy}
procedure DoLength(fsys: setofsys; fprocp: ctp);
{compile a call to Length}
begin {DoLength}
{load the string}
Match(lparent,9);
Expression(fsys+[comma,rparent],fprocp);
if gattr.typtr <> nil then
if IsString(gattr.typtr) then
LoadStringAddress
else if gattr.typtr = charptr then begin
Load;
Gen0t(pc_stk, cgUWord);
GenLdcLong(-1);
Gen0t(pc_stk, cgULong);
Gen0t(pc_bno, cgULong);
end
else Error(44)
else Error(44);
gattr.typtr := intptr;
Gen1t(pc_csp,87{lgt},cgWord);
end; {DoLength}
procedure Pos(fsys: setofsys; fprocp: ctp);
{compile a call to find the position of one string in another}
begin {Pos}
{load the strings}
Match(lparent,9);
Expression(fsys+[comma,rparent],fprocp);
if gattr.typtr <> nil then
if IsString(gattr.typtr) then
LoadStringAddress
else if gattr.typtr = charptr then begin
Load;
Gen0t(pc_stk, cgUWord);
GenLdcLong(-1);
Gen0t(pc_stk, cgULong);
Gen0t(pc_bno, cgULong);
end
else Error(44)
else Error(44);
Match(comma,20);
Expression(fsys+[rparent],fprocp);
if gattr.typtr <> nil then
if IsString(gattr.typtr) then
LoadStringAddress
else if gattr.typtr = charptr then begin
Load;
Gen0t(pc_stk, cgUWord);
GenLdcLong(-1);
Gen0t(pc_stk, cgULong);
Gen0t(pc_bno, cgULong);
end
else Error(44)
else Error(44);
Gen0t(pc_bno, cgWord);
{call the pos function}
Gen1t(pc_csp,88{pos},cgWord);
gattr.typtr := intptr;
end; {Pos}
procedure DoMember (fsys: setofsys; fprocp: ctp);
{ Compile a call to the member function }
{ }
{ paremeters: }
{ fsys - follow symbols }
{ fprocp - identifier for program or program-level }
{ subroutine contining this statement }
var
lcp: ctp; {work identifier}
begin {DoMember}
Match(lparent, 9);
Expression(fsys+[comma], fprocp);
Load;
Match(comma,20);
if sy = ident then begin
SearchId([types], lcp);
InSymbol;
if lcp <> nil then
if lcp^.idtype <> nil then
if gattr.typtr <> nil then begin
Gen0t(pc_stk, cgULong);
if CompObjects(lcp^.idtype, gattr.typtr) then
Gen1t(pc_ldc, lcp^.idtype^.objlevel, cgUWord)
else
Gen1t(pc_ldc, 0, cgUWord);
Gen0t(pc_stk, cgUWord);
Gen0t(pc_bno, cgUWord);
Gen1t(pc_csp, 117{mbr}, cgUWord);
end; {if}
end {if}
else
Error(2);
gattr.typtr := boolptr;
end; {DoMember}
{-- Externally available subroutines ------------------------------------------}
procedure Call {fsys: setofsys; fcp,fprocp: ctp};
{ generate a call to a procedure or function }
{ }
{ parameters: }
{ fsys - follow symbols }
{ fcp - }
{ fprocp - }
var
tkey: keyrange; {for saving lkey on recursive fn calls}
begin {Call}
tkey := lkey;
if fcp^.pfdeckind = standard then begin
lkey := fcp^.key;
if fcp^.klass = proc then begin
{compile standard procedure calls}
if iso then
if lkey in [3,4,12,16,18..29] then
Error(112);
if not(lkey in [7,8,13..15,28,29]) then
Match(lparent,9);
case lkey of
1,2,4: getputclose(fsys,fprocp);
3,5,6: resetrewriteopen(fsys,fprocp);
7,13: DoRead(fsys,fprocp);
8,14: DoWrite(fsys,fprocp);
9: DoPack(fsys,fprocp);
10: DoUnpack(fsys,fprocp);
11: DoNew(fsys,fprocp);
17: DoDispose(fsys,fprocp);
15: page(fsys,fprocp);
19: seek(fsys,fprocp);
20,21: HaltSeed(fsys,fprocp);
22: Delete(fsys,fprocp);
23: Insert(fsys,fprocp);
24,25: CommandLineShellID(fsys,fprocp);
26,27: StartGraphDesk(fsys,fprocp);
28,29: EndGraphDesk;
end; {case}
if not(lkey in [7,8,13..15,28,29]) then
Match(rparent,4);
end
else begin
{compile standard function calls}
if iso then
if lkey in [18..44] then
Error(112);
if not(lkey in [10,11,19,21..34,39..41,44]) then begin
Match(lparent, 9);
Expression(fsys+[rparent], fprocp);
Load;
end; {if}
case lkey of
1: abs;
2: sqr;
3,4,42,43: truncround;
5: DoOdd;
6: DoOrd;
7: DoChr;
8,9: predsucc;
10,11: DoEOF(fsys,fprocp);
12,13,14,15,16,17,36,37,38: trans;
18: DoOrd4;
19,32: Cnvfs(fsys,fprocp);
20: Cnvis;
21,33: Cnvsf(fsys,fprocp);
22: Cnvsi(fsys,fprocp);
23: Cnvsl(fsys,fprocp);
24,31: Randomf;
25: RandomInteger;
26: RandomLongInt;
27: Concat(fsys,fprocp);
28: Copy(fsys,fprocp);
29: DoLength(fsys,fprocp);
30: Pos(fsys,fprocp);
34: DoUserID;
35: DoPointer;
39: DoArctan2(fsys,fprocp);
40: ToolError;
41: DoSizeof;
44: DoMember(fsys, fprocp);
end;
if not (lkey in [10,11,24..27,31,34,40]) then
Match(rparent,4);
end;
end {else}
else
CallNonStandard(fsys, fcp, fprocp, 0, cStandard);
lkey := tkey;
end; {Call}
procedure CallNonStandard {fsys: setofsys; fcp,fprocp: ctp; odisp: longint;
callKind: callKinds};
{ Handle a call to a user defined procedure/function }
{ }
{ parameters: }
{ fsys - }
{ fcp - }
{ fprocp - }
{ odisp - disp in object for method calls; else 0 }
{ callKind - type of this call }
label 1,2,3;
var
nxt,lcp: ctp;
lattr: attr; {for forming fake parm types}
lsp: stp;
i: integer;
typeNum: baseTypeEnum;
pcount: unsigned; {number of parameters processed}
procedure CheckParm (lcp1,lcp2: ctp);
{ insure that the parm list matches the definition }
{ }
{ parameters: }
{ lcp1, lcp2 - parameter lists to check }
label 1;
begin {CheckParm}
if lcp1 = nil then begin
if lcp2 <> nil then Error(52);
end
else begin
while lcp1 <> nil do begin
if lcp2 = nil then begin Error(52); goto 1; end;
if (lcp1^.idtype <> lcp2^.idtype) or (lcp1^.klass<>lcp2^.klass)
then begin Error(59); goto 1; end
else begin
if lcp1^.klass = varsm then begin
if (lcp1^.vkind <> lcp2^.vkind) or
(lcp1^.vitem <> lcp2^.vitem) then
begin Error(59); goto 1; end
end
else {lcp1^.klass = proc or func} begin
CheckParm(lcp1^.pfnext,lcp2^.pfnext);
if lcp1^.klass = func then
if lcp1^.idtype <> lcp2^.idtype then Error(53);
end;
end;
lcp1 := lcp1^.next;
lcp2 := lcp2^.next;
end;
if lcp2 <> nil then begin Error(52); goto 1; end;
end;
1: end; {CheckParm}
begin {CallNonStandard}
{get the head of the parameter list; preload indirect call addresses}
with fcp^ do
if pfkind = formal then begin
nxt := pfnext;
if callKind = cStandard then begin
Gen3t(pc_lod, pflabel, 0, level-pflev, cgULong);
Gen3t(pc_lod, pflabel, 4, level-pflev, cgUWord);
Gen0t(pc_bno, cgUWord);
end; {if}
end {if}
else begin
nxt := pfparms;
if callKind <> cStandard then
nxt := nxt^.next; {skip SELF}
end; {else}
{for methods, the 'SELF' parameter has already been pushed}
if callKind in [cMethod,cInherited] then
pcount := 1
else
pcount := 0;
{compile the call's parameter list}
if sy = lparent then begin
repeat
InSymbol;
{check for too many parms}
if nxt = nil then begin
Error(52);
goto 1;
end;
{handle procs and funcs in parm list}
if nxt^.klass in [proc,func] then begin
if sy <> ident then begin
Error(2);
Skip(fsys + [comma,rparent]);
end
else begin
if nxt^.klass = proc then
SearchId([proc],lcp)
else begin
SearchId([func],lcp);
if lcp^.idtype <> nxt^.idtype then
Error(53);
end; {else}
if lcp <> nil then with lcp^ do begin
if pfkind = formal then begin
CheckParm(pfnext,nxt^.pfnext);
Gen3t(pc_lod, pflabel, 4, level-pflev, cgUWord);
Gen0t(pc_stk, cgUWord);
if pcount <> 0 then
Gen0t(pc_bno, cgUWord);
pcount := pcount+1;
Gen3t(pc_lod, pflabel, 0, level-pflev, cgULong);
end {if}
else begin
CheckParm(pfparms, nxt^.pfnext);
Gen1(pc_lsl, level-pflev);
Gen0t(pc_stk, cgUWord);
if pcount <> 0 then
Gen0t(pc_bno, cgUWord);
pcount := pcount+1;
if pflev = 1 then
Gen0Name(pc_lad,lcp^.name)
else
Gen1(pc_lla, pfname);
end;
Gen0t(pc_stk, cgULong);
end;
InSymbol;
if not (sy in fsys + [comma,rparent]) then begin
Error(6);
Skip(fsys + [comma,rparent]);
end;
end;
goto 2;
end;
{handle expressions in parm list}
if sy = stringConst then
if nxt <> nil then
if nxt^.vkind = actual then
if IsString(nxt^.idtype) then begin
if StrLen(nxt^.idtype) < 0 then
LoadString(lengthString)
else
LoadString(nullString);
InSymbol;
goto 3;
end; {if}
1: Expression(fsys + [comma,rparent],fprocp);
3: if gattr.typtr <> nil then
if nxt <> nil then begin
lsp := nxt^.idtype;
if lsp <> nil then begin
if (nxt^.vkind = actual) then begin
if lsp^.form <= power then begin
if gattr.typtr^.form <= power then
Load
else
LoadAddress;
CheckBnds(lsp);
if IsReal(lsp) then begin
if (gattr.typtr = intptr) or (gattr.typtr = byteptr) then
begin
Gen2(pc_cnv,ord(cgWord),ord(cgExtended));
gattr.typtr := realptr;
end
else if gattr.typtr = longptr then begin
Gen2(pc_cnv,ord(cgLong),ord(cgExtended));
gattr.typtr := realptr;
end;
end
else if lsp = longptr then begin
if (gattr.typtr = intptr) or (gattr.typtr = byteptr) then
begin
Gen2(pc_cnv, ord(cgWord), ord(cgLong));
gattr.typtr := longptr;
end;
end {else if}
else if nxt^.vuniv then
if ParmSize(lsp, actual) = 4 then
if ParmSize(gattr.typtr, actual) = 2 then begin
Gen2(pc_cnv, ord(cgWord), ord(cgLong));
gattr.typtr := longptr;
end; {if}
case GetType(gattr.typtr, gattr.isPacked) of
cgByte,cgUByte,cgWord,cgUWord:
Gen0t(pc_stk, cgWord);
cgLong,cgULong,cgString:
Gen0t(pc_stk, cgLong);
cgReal,cgDouble,cgComp,cgExtended:
Gen0t(pc_stk, cgExtended);
cgSet:
Gen1(pc_siz, ord(lsp^.size));
otherwise: ;
end; {case}
end
else if gattr.typtr^.form = objects then begin
Load;
if debug then
GenL2t(pc_chk, 1, maxaddr, cgULong);
Gen0t(pc_stk, cgULong);
end {else if}
else if gattr.typtr^.form = records then begin
{value records <= 4 bytes passed by value; otherwise }
{ pass an address }
if gattr.typtr^.size <= 4 then
if gattr.typtr^.size <= 2 then begin
lattr := gattr;
gattr.typtr := intptr;
Load;
Gen0t(pc_stk, cgWord);
gattr := lattr;
end {if}
else begin
lattr := gattr;
gattr.typtr := longptr;
Load;
Gen0t(pc_stk, cgLong);
gattr := lattr;
end {else}
else begin
LoadAddress;
Gen0t(pc_stk, cgULong);
end;
end {else if}
else if IsString(lsp) then begin
if gattr.kind = expr then begin
LoadAddress;
Gen0t(pc_stk, cgULong);
if StrLen(lsp) < 0 then
Gen1t(pc_csp, 119{fxp}, cgULong)
else
Gen1t(pc_csp, 120{fxc}, cgULong);
end {if}
else
LoadAddress;
Gen0t(pc_stk, cgULong);
end {else if}
else begin
LoadAddress;
Gen0t(pc_stk, cgULong);
end; {else}
if not CompTypes(lsp,gattr.typtr) then
if (ParmSize(lsp,actual) <> ParmSize(gattr.typtr,actual)) then
Error(67);
end
else begin
if lsp <> gattr.typtr then
if not nxt^.vuniv then
Error(67);
if gattr.kind = varbl then begin
LoadAddress;
Gen0t(pc_stk, cgULong);
end {if}
else
Error(78);
if glcp <> nil then with glcp^ do begin
if klass = varsm then begin
if vcontvar then Error(97);
if vlev <> level then vrestrict := true;
end
else if klass = field then
if fldvar then Error(95);
end;
if gispacked then Error(95);
end;
end
end;
2: {next parm in definition}
if nxt <> nil then
nxt := nxt^.next;
if pcount <> 0 then
Gen0t(pc_bno, cgWord);
pcount := pcount+1;
until sy <> comma;
Match(rparent,4);
end; {if}
if pcount = 0 then
Gen0(pc_nop);
{check for not enough parameters}
if nxt <> nil then
Error(52);
{generate the call}
with fcp^ do begin
if klass <> func then
typeNum := cgVoid
else begin
if idtype = realptr then
typeNum := cgReal
else if idtype = doubleptr then
typeNum := cgDouble
else if idtype = compptr then
typeNum := cgComp
else if idtype = extendedptr then
typeNum := cgExtended
else if idtype = longptr then
typeNum := cgLong
else if idtype^.form = pointerStruct then
typeNum := cgULong
else
typeNum := cgWord;
end; {else}
if callKind = cMethod then
GenL1t(pc_cum, odisp, typeNum)
else if pfkind = formal then
Gen0t(pc_cui, typeNum)
else {if pfkind = actual then}
case pfdirective of
drnone,drforw,drextern: {standard calls}
if pflev = 1 then
Gen1tName(pc_cup, level-pflev, typeNum, fcp^.pfoname)
else
Gen2t(pc_cup, pfname, level-pflev, typeNum);
drprodos: {in line prodos call}
Gen1(pc_pds, pfcallnum);
drtool1,drtool2,drvector: begin {in line tool call with passed parms}
if pfdirective = drtool1 then
Gen2t(pc_tl1, pftoolnum, pfcallnum, typeNum)
else if pfdirective = drtool2 then
Gen2t(pc_tl2, pftoolnum, pfcallnum, typeNum)
else
Gen1L1t(pc_vct, pfcallnum, pfaddr, typeNum);
if klass = func then
if idtype = boolptr then begin
Gen1t(pc_ldc, 0, cgWord);
Gen0t(pc_neq, cgWord);
end; {if}
end;
end; {case}
end;
{for functions, set the return type}
gattr.typtr := fcp^.idtype
end; {CallNonStandard}
procedure CheckBool;
{load a value, insuring that it is boolean}
begin {CheckBool}
load;
if gattr.typtr <> nil then
if gattr.typtr <> boolptr then Error(60);
end; {CheckBool}
procedure CheckBnds{fsp: stp};
{generate range checking code (if needed)}
var
lmin,lmax: integer;
begin {CheckBnds}
if debug then
if fsp <> nil then
if fsp = charptr then
Gen2t(pc_chk, ordminchar, ordmaxchar, cgUWord)
else if fsp^.form = subrange then
if fsp^.rangetype = longptr then
GenL2t(pc_chk, fsp^.min, fsp^.max, cgULong)
else
Gen2t(pc_chk, long(fsp^.min).lsw, long(fsp^.max).lsw, cgUWord);
end; {CheckBnds}
procedure FreeTemp{labelNum, size: integer};
{ place a temporary label in the available label list }
{ }
{ parameters: }
{ labelNum - number of the label to free }
{ size - size of the variable }
{ }
{ variables: }
{ tempList - list of free labels }
var
tl: tempPtr; {work pointer}
begin {FreeTemp}
new(tl);
tl^.next := tempList;
tl^.last := nil;
tl^.labelNum := labelNum;
tl^.size := size;
if tempList <> nil then
tempList^.last := tl;
tempList := tl;
end; {FreeTemp}
function GetTemp{size: integer): integer};
{ find a temporary work variable }
{ }
{ parameters: }
{ size - size of the variable }
{ }
{ variables: }
{ tempList - list of free labels }
{ }
{ Returns the label number. }
label 1;
var
ln: integer; {label number}
tl: tempPtr; {work pointer}
begin {GetTemp}
{try to find a temp from the existing list}
tl := tempList;
while tl <> nil do begin
if tl^.size = size then begin
{found an old one - use it}
if tl^.last = nil then
tempList := tl^.next
else
tl^.last^.next := tl^.next;
if tl^.next <> nil then
tl^.next^.last := tl^.last;
GetTemp := tl^.labelNum;
goto 1;
end; {if}
tl := tl^.next;
end; {while}
{none found - get a new one}
ln := GetLocalLabel;
GetTemp := ln;
Gen2(dc_loc, ln, size);
1:
end; {GetTemp}
procedure Load;
{load a value onto the evaluation stack}
var
lmt: addrrange; {temp disp}
ltype: stp; {base type}
begin {Load}
with gattr do
if typtr <> nil then begin
ltype := typtr;
if ltype^.form = subrange then
ltype := ltype^.rangetype;
case kind of
cst: if (ltype^.form = scalar) and (not IsReal(ltype)) then
if ltype = boolptr then
Gen1t(pc_ldc, cval.ival, cgUWord)
else if ltype=charptr then
Gen1t(pc_ldc, cval.ival, cgUWord)
else if ltype = longptr then
GenLdcLong(cval.valp^.lval)
else if cval.ival >= 0 then
Gen1t(pc_ldc, cval.ival, cgUWord)
else
Gen1t(pc_ldc, cval.ival, cgWord)
else if ltype = nilptr then
GenLdcLong(0)
else if IsReal(ltype) then
GenLdcReal(cval.valp^.rval)
else
GenLdcSet(cval.valp^);
varbl: begin
if access = drct then
if dpdisp > maxint then begin
lmt := dpdisp;
if vlevel <= 1 then
Gen1Name(pc_lao, 0, aname)
else
Gen3(pc_lda, gattr.dplab, 0, 0);
access := indrct;
idplmt := lmt;
end; {if}
case access of
drct: if ltype^.form = power then begin
if vlevel<=1 then
Gen2tName(pc_ldo, long(dpdisp).lsw, ord(typtr^.size),
cgSet, aname)
else
Gen4t(pc_lod, gattr.dplab, long(dpdisp).lsw,
level-vlevel, ord(typtr^.size), cgSet);
end {if}
else begin
if vlevel<=1 then
Gen1tName(pc_ldo, long(dpdisp).lsw,
GetType(typtr, isPacked), aname)
else
Gen3t(pc_lod, gattr.dplab, long(dpdisp).lsw,
level-vlevel, GetType(typtr, isPacked));
end; {else}
indrct: begin
if idplmt >= maxint then begin
GenLdcLong(idplmt);
Gen0(pc_adl);
idplmt := 0;
end; {if}
if ltype^.form = power then
Gen2t(pc_ind, ord(idplmt), ord(typtr^.size), cgSet)
else
Gen1t(pc_ind, ord(idplmt), GetType(typtr, isPacked));
end;
inxd: Error(113)
end; {case}
end;
otherwise:
end;
typtr := ltype;
kind := expr;
end;
end; {Load}
procedure LoadAddress;
{load the address of a variable onto the top of the stack}
var
lmt: addrrange; {temp disp}
begin {LoadAddress}
with gattr do
if typtr <> nil then begin
if typtr^.form = subrange then
typtr := typtr^.rangetype;
case kind of
cst: if IsString(typtr) then
GenPS(pc_lca, @cval.valp^.sval)
else
Error(113);
varbl: begin
if access = drct then
if dpdisp > maxint then begin
lmt := dpdisp;
if vlevel <= 1 then
Gen1Name(pc_lao, 0, aname)
else
Gen3(pc_lda, gattr.dplab, 0, 0);
access := indrct;
idplmt := lmt;
end; {if}
case access of
drct: if vlevel <= 1 then
Gen1Name(pc_lao, long(dpdisp).lsw, aname)
else
Gen3(pc_lda, dplab, level-vlevel, long(dpdisp).lsw);
indrct: begin
if idplmt >= maxint then begin
GenLdcLong(idplmt);
Gen0(pc_adl);
end {if}
else
Gen1t(pc_inc,ord(idplmt),cgULong);
end;
inxd: Error(113)
end; {case}
end;
expr: if typtr <> stringPtr then Error(113);
end;
kind := varbl;
access := indrct;
idplmt := 0;
end
end; {LoadAddress}
procedure LoadStringAddress;
{load the address and length of a string}
var
lattr: attr;
begin {LoadStringAddress}
lattr := gattr;
LoadAddress;
Gen0t(pc_stk, cgULong);
if lattr.kind <> expr then begin
Gen1t(pc_ldc, StrLen(gattr.typtr), cgUWord);
Gen0t(pc_stk, cgUWord);
Gen0t(pc_bno, cgUWord);
end; {if}
end; {LoadStringAddress}
procedure LoadString {kind: stringKind};
{ load the address of a string constant }
{ }
{ parameters: }
{ kind - string kind }
var
i: unsigned; {loop variable}
len: unsigned; {length of the string}
tch: char; {temp for building string from char}
begin {LoadString}
if lgth = 1 then begin {if the length is 1, make a string }
tch := chr(val.ival); { from a character }
val.valp := pointer(Malloc(sizeof(constantRec)));
with val.valp^ do begin
cclass := strg;
sval[0] := chr(1);
sval[1] := tch;
end; {with}
end; {if}
with val.valp^ do begin
if lgth = 0 then begin {for a nul string, use two zeros}
sval[0] := chr(2);
sval[1] := chr(0);
sval[2] := chr(0);
end {if}
else if kind = lengthString then begin {add the length byte}
len := length(sval);
for i := len downto 1 do
sval[i+1] := sval[i];
sval[1] := sval[0];
sval[0] := chr(len+2);
end {else}
else {bump the length for the null terminator}
sval[0] := succ(sval[0]);
sval[ord(sval[0])] := chr(0); {place a trailing nul on the string}
gattr.cval := val; {set up for the load}
gattr.typtr := stringptr;
gattr.kind := cst;
gattr.isPacked := false;
end; {with}
end; {LoadString}
function ParmSize {lsp: stp; vkind: idkind): integer};
{ find the length of a parameter }
{ }
{ parameters: }
{ lsp - }
{ vkind - }
{ }
{ Returns: stack size of parameter, in bytes }
begin {ParmSize}
ParmSize := ptrsize;
if lsp <> nil then
with lsp^ do
if vkind = actual then
if form <= power then begin
ParmSize := ord(size);
if IsReal(lsp) then
ParmSize := extSize
else if lsp = byteptr then
ParmSize := intSize;
end {if}
else if form = records then
if size <= 2 then
ParmSize := 2;
end; {ParmSize}
procedure ResetTemp;
{ forget all of the temporary work variables }
var
tl: tempPtr; {work pointer}
begin {ResetTemp}
while tempList <> nil do begin
tl := tempList;
tempList := tl^.next;
dispose(tl);
end; {while}
end; {ResetTemp}
procedure Store{var fattr: attr};
{store the value on top of stack}
var
lmt: addrrange; {temp disp}
begin {Store}
with fattr do
if typtr <> nil then begin
case access of
drct: if typtr^.form = power then begin
if vlevel <= 1 then
Gen2tName(pc_sro, long(dpdisp).lsw, ord(typtr^.size), cgSet,
aname)
else
Gen4t(pc_str, dplab, long(dpdisp).lsw, level-vlevel,
ord(typtr^.size), cgSet);
end
else begin
if vlevel <= 1 then
Gen1tName(pc_sro, long(dpdisp).lsw, GetType(typtr, isPacked),
aname)
else
Gen3t(pc_str, dplab, long(dpdisp).lsw, level-vlevel,
GetType(typtr, isPacked));
end;
indrct: begin
if typtr^.form = power then
Gen1t(pc_sto, ord(typtr^.size), cgSet)
else
Gen0t(pc_sto, GetType(typtr, isPacked));
end;
inxd: Error(113)
end; {case}
end; {if}
end; {Store}
end.