mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-26 15:13:58 +02:00
2179 lines
66 KiB
ObjectPascal
2179 lines
66 KiB
ObjectPascal
{
|
|
$Id$
|
|
Copyright (c) 1998-2000 by Florian Klaempfl
|
|
|
|
This units exports some routines to manage the parse tree
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
****************************************************************************
|
|
}
|
|
unit tree;
|
|
|
|
{$i defines.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
globtype,cobjects,cpuinfo
|
|
{$IFDEF NEWST}
|
|
,objects,symtable,symbols,defs
|
|
{$ELSE}
|
|
,symconst,symtable
|
|
{$ENDIF NEWST}
|
|
,aasm,cpubase;
|
|
|
|
type
|
|
pconstset = ^tconstset;
|
|
tconstset = array[0..31] of byte;
|
|
|
|
ttreetyp = (
|
|
addn, {Represents the + operator.}
|
|
muln, {Represents the * operator.}
|
|
subn, {Represents the - operator.}
|
|
divn, {Represents the div operator.}
|
|
symdifn, {Represents the >< operator.}
|
|
modn, {Represents the mod operator.}
|
|
assignn, {Represents an assignment.}
|
|
loadn, {Represents the use of a variabele.}
|
|
rangen, {Represents a range (i.e. 0..9).}
|
|
ltn, {Represents the < operator.}
|
|
lten, {Represents the <= operator.}
|
|
gtn, {Represents the > operator.}
|
|
gten, {Represents the >= operator.}
|
|
equaln, {Represents the = operator.}
|
|
unequaln, {Represents the <> operator.}
|
|
inn, {Represents the in operator.}
|
|
orn, {Represents the or operator.}
|
|
xorn, {Represents the xor operator.}
|
|
shrn, {Represents the shr operator.}
|
|
shln, {Represents the shl operator.}
|
|
slashn, {Represents the / operator.}
|
|
andn, {Represents the and operator.}
|
|
subscriptn, {??? Field in a record/object?}
|
|
derefn, {Dereferences a pointer.}
|
|
addrn, {Represents the @ operator.}
|
|
doubleaddrn, {Represents the @@ operator.}
|
|
ordconstn, {Represents an ordinal value.}
|
|
typeconvn, {Represents type-conversion/typecast.}
|
|
calln, {Represents a call node.}
|
|
callparan, {Represents a parameter.}
|
|
realconstn, {Represents a real value.}
|
|
fixconstn, {Represents a fixed value.}
|
|
unaryminusn, {Represents a sign change (i.e. -2).}
|
|
asmn, {Represents an assembler node }
|
|
vecn, {Represents array indexing.}
|
|
pointerconstn,
|
|
stringconstn, {Represents a string constant.}
|
|
funcretn, {Represents the function result var.}
|
|
selfn, {Represents the self parameter.}
|
|
notn, {Represents the not operator.}
|
|
inlinen, {Internal procedures (i.e. writeln).}
|
|
niln, {Represents the nil pointer.}
|
|
errorn, {This part of the tree could not be
|
|
parsed because of a compiler error.}
|
|
typen, {A type name. Used for i.e. typeof(obj).}
|
|
hnewn, {The new operation, constructor call.}
|
|
hdisposen, {The dispose operation with destructor call.}
|
|
newn, {The new operation, constructor call.}
|
|
simpledisposen, {The dispose operation.}
|
|
setelementn, {A set element(s) (i.e. [a,b] and also [a..b]).}
|
|
setconstn, {A set constant (i.e. [1,2]).}
|
|
blockn, {A block of statements.}
|
|
statementn, {One statement in a block of nodes.}
|
|
loopn, { used in genloopnode, must be converted }
|
|
ifn, {An if statement.}
|
|
breakn, {A break statement.}
|
|
continuen, {A continue statement.}
|
|
repeatn, {A repeat until block.}
|
|
whilen, {A while do statement.}
|
|
forn, {A for loop.}
|
|
exitn, {An exit statement.}
|
|
withn, {A with statement.}
|
|
casen, {A case statement.}
|
|
labeln, {A label.}
|
|
goton, {A goto statement.}
|
|
simplenewn, {The new operation.}
|
|
tryexceptn, {A try except block.}
|
|
raisen, {A raise statement.}
|
|
switchesn, {??? Currently unused...}
|
|
tryfinallyn, {A try finally statement.}
|
|
onn, { for an on statement in exception code }
|
|
isn, {Represents the is operator.}
|
|
asn, {Represents the as typecast.}
|
|
caretn, {Represents the ^ operator.}
|
|
failn, {Represents the fail statement.}
|
|
starstarn, {Represents the ** operator exponentiation }
|
|
procinlinen, {Procedures that can be inlined }
|
|
arrayconstructn, {Construction node for [...] parsing}
|
|
arrayconstructrangen, {Range element to allow sets in array construction tree}
|
|
{ added for optimizations where we cannot suppress }
|
|
nothingn,
|
|
loadvmtn
|
|
);
|
|
|
|
tconverttype = (
|
|
tc_equal,
|
|
tc_not_possible,
|
|
tc_string_2_string,
|
|
tc_char_2_string,
|
|
tc_pchar_2_string,
|
|
tc_cchar_2_pchar,
|
|
tc_cstring_2_pchar,
|
|
tc_ansistring_2_pchar,
|
|
tc_string_2_chararray,
|
|
tc_chararray_2_string,
|
|
tc_array_2_pointer,
|
|
tc_pointer_2_array,
|
|
tc_int_2_int,
|
|
tc_int_2_bool,
|
|
tc_bool_2_bool,
|
|
tc_bool_2_int,
|
|
tc_real_2_real,
|
|
tc_int_2_real,
|
|
tc_int_2_fix,
|
|
tc_real_2_fix,
|
|
tc_fix_2_real,
|
|
tc_proc_2_procvar,
|
|
tc_arrayconstructor_2_set,
|
|
tc_load_smallset,
|
|
tc_cord_2_pointer
|
|
);
|
|
|
|
{ allows to determine which elementes are to be replaced }
|
|
tdisposetyp = (dt_nothing,dt_leftright,dt_left,dt_leftrighthigh,
|
|
dt_mbleft,dt_typeconv,dt_inlinen,dt_leftrightmethod,
|
|
dt_mbleft_and_method,dt_loop,dt_case,dt_with,dt_onn,
|
|
dt_leftrightframe);
|
|
|
|
{ different assignment types }
|
|
|
|
tassigntyp = (at_normal,at_plus,at_minus,at_star,at_slash);
|
|
|
|
pcaserecord = ^tcaserecord;
|
|
tcaserecord = record
|
|
|
|
{ range }
|
|
_low,_high : TConstExprInt;
|
|
|
|
{ only used by gentreejmp }
|
|
_at : pasmlabel;
|
|
|
|
{ label of instruction }
|
|
statement : pasmlabel;
|
|
|
|
{ is this the first of an case entry, needed to release statement
|
|
label (PFV) }
|
|
firstlabel : boolean;
|
|
|
|
{ left and right tree node }
|
|
less,greater : pcaserecord;
|
|
end;
|
|
|
|
ptree = ^ttree;
|
|
ttree = record
|
|
error : boolean;
|
|
disposetyp : tdisposetyp;
|
|
{ is true, if the right and left operand are swaped }
|
|
swaped : boolean;
|
|
{ do we need to parse childs to set var state }
|
|
varstateset : boolean;
|
|
{ the location of the result of this node }
|
|
location : tlocation;
|
|
|
|
{ the number of registers needed to evalute the node }
|
|
registers32,registersfpu : longint; { must be longint !!!! }
|
|
{$ifdef SUPPORT_MMX}
|
|
registersmmx : longint;
|
|
{$endif SUPPORT_MMX}
|
|
left,right : ptree;
|
|
resulttype : pdef;
|
|
fileinfo : tfileposinfo;
|
|
localswitches : tlocalswitches;
|
|
isproperty : boolean;
|
|
{$ifdef extdebug}
|
|
firstpasscount : longint;
|
|
{$endif extdebug}
|
|
{$ifdef TEMPREGDEBUG}
|
|
usableregs : longint;
|
|
{$endif TEMPREGDEBUG}
|
|
{$ifdef EXTTEMPREGDEBUG}
|
|
reallyusedregs : longint;
|
|
{$endif EXTTEMPREGDEBUG}
|
|
{$ifdef TEMPS_NOT_PUSH}
|
|
temp_offset : longint;
|
|
{$endif TEMPS_NOT_PUSH}
|
|
case treetype : ttreetyp of
|
|
addn : (use_strconcat : boolean;string_typ : tstringtype);
|
|
callparan : (is_colon_para : boolean;exact_match_found,
|
|
convlevel1found,convlevel2found:boolean;hightree:ptree);
|
|
assignn : (assigntyp : tassigntyp;concat_string : boolean);
|
|
loadn : (symtableentry : psym;symtable : psymtable;
|
|
is_absolute,is_first : boolean);
|
|
calln : (symtableprocentry : pprocsym;
|
|
symtableproc : psymtable;procdefinition : pabstractprocdef;
|
|
methodpointer : ptree;
|
|
no_check,unit_specific,
|
|
return_value_used,static_call : boolean);
|
|
addrn : (procvarload:boolean);
|
|
ordconstn : (value : TConstExprInt);
|
|
realconstn : (value_real : bestreal;lab_real : pasmlabel);
|
|
fixconstn : (value_fix: longint);
|
|
funcretn : (funcretprocinfo : pointer;
|
|
{$IFDEF NEWST}
|
|
retsym:Psym;
|
|
{$ELSE}
|
|
rettype : ttype;
|
|
{$ENDIF}
|
|
is_first_funcret : boolean);
|
|
subscriptn : (vs : pvarsym);
|
|
raisen : (frametree : ptree);
|
|
vecn : (memindex,memseg:boolean;callunique : boolean);
|
|
stringconstn : (value_str : pchar;length : longint; lab_str : pasmlabel;stringtype : tstringtype);
|
|
typeconvn : (convtyp : tconverttype;explizit : boolean);
|
|
typen : (typenodetype : pdef;typenodesym:ptypesym);
|
|
inlinen : (inlinenumber : byte;inlineconst:boolean);
|
|
procinlinen : (inlinetree:ptree;inlineprocsym:pprocsym;retoffset,para_offset,para_size : longint);
|
|
setconstn : (value_set : pconstset;lab_set:pasmlabel);
|
|
loopn : (t1,t2 : ptree;backward : boolean);
|
|
asmn : (p_asm : paasmoutput;object_preserved : boolean);
|
|
casen : (nodes : pcaserecord;elseblock : ptree);
|
|
labeln,goton : (labelnr : pasmlabel;exceptionblock : ptree;labsym : plabelsym);
|
|
{$IFDEF NEWST}
|
|
withn : (withsymtables:Pcollection;
|
|
withreference:preference;
|
|
islocal:boolean);
|
|
{$ELSE}
|
|
withn : (withsymtable : pwithsymtable;
|
|
tablecount : longint;
|
|
withreference:preference;
|
|
islocal:boolean);
|
|
{$ENDIF NEWST}
|
|
onn : (exceptsymtable : psymtable;excepttype : pobjectdef);
|
|
arrayconstructn : (cargs,cargswap,forcevaria,novariaallowed: boolean;constructdef:pdef);
|
|
end;
|
|
|
|
function gennode(t : ttreetyp;l,r : ptree) : ptree;
|
|
function genlabelnode(t : ttreetyp;nr : pasmlabel) : ptree;
|
|
function genloadnode(v : pvarsym;st : psymtable) : ptree;
|
|
function genloadcallnode(v: pprocsym;st: psymtable): ptree;
|
|
function genloadmethodcallnode(v: pprocsym;st: psymtable; mp:ptree): ptree;
|
|
function gensinglenode(t : ttreetyp;l : ptree) : ptree;
|
|
function gensubscriptnode(varsym : pvarsym;l : ptree) : ptree;
|
|
function genordinalconstnode(v : TConstExprInt;def : pdef) : ptree;
|
|
{ same as genordinalconstnode, but the resulttype }
|
|
{ is determines automatically }
|
|
function genintconstnode(v : TConstExprInt) : ptree;
|
|
function genpointerconstnode(v : tpointerord;def : pdef) : ptree;
|
|
function genfixconstnode(v : longint;def : pdef) : ptree;
|
|
function gentypeconvnode(node : ptree;t : pdef) : ptree;
|
|
function gentypenode(t : pdef;sym:ptypesym) : ptree;
|
|
function gencallparanode(expr,next : ptree) : ptree;
|
|
function genrealconstnode(v : bestreal;def : pdef) : ptree;
|
|
function gencallnode(v : pprocsym;st : psymtable) : ptree;
|
|
function genmethodcallnode(v : pprocsym;st : psymtable;mp : ptree) : ptree;
|
|
|
|
{ allow pchar or string for defining a pchar node }
|
|
function genstringconstnode(const s : string;st:tstringtype) : ptree;
|
|
{ length is required for ansistrings }
|
|
function genpcharconstnode(s : pchar;length : longint) : ptree;
|
|
{ helper routine for conststring node }
|
|
function getpcharcopy(p : ptree) : pchar;
|
|
|
|
function genzeronode(t : ttreetyp) : ptree;
|
|
function geninlinenode(number : byte;is_const:boolean;l : ptree) : ptree;
|
|
function genprocinlinenode(callp,code : ptree) : ptree;
|
|
function gentypedconstloadnode(sym : ptypedconstsym;st : psymtable) : ptree;
|
|
function genenumnode(v : penumsym) : ptree;
|
|
function genselfnode(_class : pdef) : ptree;
|
|
function gensetconstnode(s : pconstset;settype : psetdef) : ptree;
|
|
function genloopnode(t : ttreetyp;l,r,n1: ptree;back : boolean) : ptree;
|
|
function genasmnode(p_asm : paasmoutput) : ptree;
|
|
function gencasenode(l,r : ptree;nodes : pcaserecord) : ptree;
|
|
{$IFDEF NEWST}
|
|
function genwithnode(symtables:Pcollection;l,r : ptree) : ptree;
|
|
{$ELSE}
|
|
function genwithnode(symtable:pwithsymtable;l,r : ptree;count : longint) : ptree;
|
|
{$ENDIF NEWST}
|
|
function genconstsymtree(p:pconstsym):ptree;
|
|
|
|
function getcopy(p : ptree) : ptree;
|
|
|
|
function equal_trees(t1,t2 : ptree) : boolean;
|
|
{$ifdef newoptimizations2}
|
|
{ checks if t1 is loaded more than once in t2 and its sub-trees }
|
|
function multiple_uses(t1,t2: ptree): boolean;
|
|
{$endif newoptimizations2}
|
|
|
|
procedure swaptree(p:Ptree);
|
|
procedure disposetree(p : ptree);
|
|
procedure putnode(p : ptree);
|
|
function getnode : ptree;
|
|
procedure clear_location(var loc : tlocation);
|
|
procedure set_location(var destloc,sourceloc : tlocation);
|
|
procedure swap_location(var destloc,sourceloc : tlocation);
|
|
procedure set_file_line(from,_to : ptree);
|
|
procedure set_tree_filepos(p : ptree;const filepos : tfileposinfo);
|
|
{$ifdef extdebug}
|
|
procedure compare_trees(oldp,p : ptree);
|
|
const
|
|
maxfirstpasscount : longint = 0;
|
|
{$endif extdebug}
|
|
|
|
{ sets the callunique flag, if the node is a vecn, }
|
|
{ takes care of type casts etc. }
|
|
procedure set_unique(p : ptree);
|
|
|
|
{ sets funcret_is_valid to true, if p contains a funcref node }
|
|
procedure set_funcret_is_valid(p : ptree);
|
|
|
|
{
|
|
type
|
|
tvarstaterequire = (vsr_can_be_undefined,vsr_must_be_valid,
|
|
vsr_is_used_after,vsr_must_be_valid_and_is_used_after); }
|
|
|
|
{ sets varsym varstate field correctly }
|
|
procedure unset_varstate(p : ptree);
|
|
procedure set_varstate(p : ptree;must_be_valid : boolean);
|
|
|
|
{ returns the ordinal value of the node, if it hasn't a ord. }
|
|
{ value an error is generated }
|
|
function get_ordinal_value(p : ptree) : longint;
|
|
|
|
function is_constnode(p : ptree) : boolean;
|
|
{ true, if p is a pointer to a const int value }
|
|
function is_constintnode(p : ptree) : boolean;
|
|
function is_constboolnode(p : ptree) : boolean;
|
|
function is_constrealnode(p : ptree) : boolean;
|
|
function is_constcharnode(p : ptree) : boolean;
|
|
function is_constresourcestringnode(p : ptree) : boolean;
|
|
|
|
function str_length(p : ptree) : longint;
|
|
function is_emptyset(p : ptree):boolean;
|
|
|
|
{ counts the labels }
|
|
function case_count_labels(root : pcaserecord) : longint;
|
|
{ searches the highest label }
|
|
function case_get_max(root : pcaserecord) : longint;
|
|
{ searches the lowest label }
|
|
function case_get_min(root : pcaserecord) : longint;
|
|
|
|
type
|
|
pptree = ^ptree;
|
|
|
|
{$ifdef TEMPREGDEBUG}
|
|
const
|
|
curptree : pptree = nil;
|
|
{$endif TEMPREGDEBUG}
|
|
|
|
{$I innr.inc}
|
|
|
|
{$ifdef newcg}
|
|
{$I nodeh.inc}
|
|
{$endif newcg}
|
|
implementation
|
|
|
|
uses
|
|
systems,
|
|
cutils,globals,verbose,fmodule,types,
|
|
{$ifdef newcg}
|
|
cgbase
|
|
{$else newcg}
|
|
hcodegen
|
|
{$endif newcg}
|
|
{$IFDEF NEWST}
|
|
,symtablt
|
|
{$ENDIF}
|
|
;
|
|
|
|
function getnode : ptree;
|
|
|
|
var
|
|
hp : ptree;
|
|
|
|
begin
|
|
new(hp);
|
|
{ makes error tracking easier }
|
|
fillchar(hp^,sizeof(ttree),0);
|
|
{ reset }
|
|
hp^.location.loc:=LOC_INVALID;
|
|
{ save local info }
|
|
hp^.fileinfo:=aktfilepos;
|
|
hp^.localswitches:=aktlocalswitches;
|
|
getnode:=hp;
|
|
end;
|
|
|
|
|
|
procedure putnode(p : ptree);
|
|
begin
|
|
{ clean up the contents of a node }
|
|
case p^.treetype of
|
|
asmn : if assigned(p^.p_asm) then
|
|
dispose(p^.p_asm,done);
|
|
stringconstn : begin
|
|
ansistringdispose(p^.value_str,p^.length);
|
|
end;
|
|
setconstn : begin
|
|
if assigned(p^.value_set) then
|
|
dispose(p^.value_set);
|
|
end;
|
|
end;
|
|
{$ifdef extdebug}
|
|
if p^.firstpasscount>maxfirstpasscount then
|
|
maxfirstpasscount:=p^.firstpasscount;
|
|
{$endif extdebug}
|
|
dispose(p);
|
|
end;
|
|
|
|
function getcopy(p : ptree) : ptree;
|
|
|
|
var
|
|
hp : ptree;
|
|
|
|
begin
|
|
if not assigned(p) then
|
|
begin
|
|
getcopy:=nil;
|
|
exit;
|
|
end;
|
|
hp:=getnode;
|
|
hp^:=p^;
|
|
case p^.disposetyp of
|
|
dt_leftright :
|
|
begin
|
|
if assigned(p^.left) then
|
|
hp^.left:=getcopy(p^.left);
|
|
if assigned(p^.right) then
|
|
hp^.right:=getcopy(p^.right);
|
|
end;
|
|
dt_leftrighthigh :
|
|
begin
|
|
if assigned(p^.left) then
|
|
hp^.left:=getcopy(p^.left);
|
|
if assigned(p^.right) then
|
|
hp^.right:=getcopy(p^.right);
|
|
if assigned(p^.hightree) then
|
|
hp^.hightree:=getcopy(p^.hightree);
|
|
end;
|
|
dt_leftrightframe :
|
|
begin
|
|
if assigned(p^.left) then
|
|
hp^.left:=getcopy(p^.left);
|
|
if assigned(p^.right) then
|
|
hp^.right:=getcopy(p^.right);
|
|
if assigned(p^.frametree) then
|
|
hp^.frametree:=getcopy(p^.frametree);
|
|
end;
|
|
dt_leftrightmethod :
|
|
begin
|
|
if assigned(p^.left) then
|
|
hp^.left:=getcopy(p^.left);
|
|
if assigned(p^.right) then
|
|
hp^.right:=getcopy(p^.right);
|
|
if assigned(p^.methodpointer) then
|
|
hp^.methodpointer:=getcopy(p^.methodpointer);
|
|
end;
|
|
dt_nothing : ;
|
|
dt_left :
|
|
if assigned(p^.left) then
|
|
hp^.left:=getcopy(p^.left);
|
|
dt_mbleft :
|
|
if assigned(p^.left) then
|
|
hp^.left:=getcopy(p^.left);
|
|
dt_mbleft_and_method :
|
|
begin
|
|
if assigned(p^.left) then
|
|
hp^.left:=getcopy(p^.left);
|
|
hp^.methodpointer:=getcopy(p^.methodpointer);
|
|
end;
|
|
dt_loop :
|
|
begin
|
|
if assigned(p^.left) then
|
|
hp^.left:=getcopy(p^.left);
|
|
if assigned(p^.right) then
|
|
hp^.right:=getcopy(p^.right);
|
|
if assigned(p^.t1) then
|
|
hp^.t1:=getcopy(p^.t1);
|
|
if assigned(p^.t2) then
|
|
hp^.t2:=getcopy(p^.t2);
|
|
end;
|
|
dt_typeconv : hp^.left:=getcopy(p^.left);
|
|
dt_inlinen :
|
|
if assigned(p^.left) then
|
|
hp^.left:=getcopy(p^.left);
|
|
else internalerror(11);
|
|
end;
|
|
{ now check treetype }
|
|
case p^.treetype of
|
|
stringconstn : begin
|
|
hp^.value_str:=getpcharcopy(p);
|
|
hp^.length:=p^.length;
|
|
end;
|
|
setconstn : begin
|
|
new(hp^.value_set);
|
|
hp^.value_set:=p^.value_set;
|
|
end;
|
|
end;
|
|
getcopy:=hp;
|
|
end;
|
|
|
|
procedure deletecaselabels(p : pcaserecord);
|
|
|
|
begin
|
|
if assigned(p^.greater) then
|
|
deletecaselabels(p^.greater);
|
|
if assigned(p^.less) then
|
|
deletecaselabels(p^.less);
|
|
dispose(p);
|
|
end;
|
|
|
|
procedure swaptree(p:Ptree);
|
|
|
|
var swapp:Ptree;
|
|
|
|
begin
|
|
swapp:=p^.right;
|
|
p^.right:=p^.left;
|
|
p^.left:=swapp;
|
|
p^.swaped:=not(p^.swaped);
|
|
end;
|
|
|
|
|
|
procedure disposetree(p : ptree);
|
|
|
|
var
|
|
symt : psymtable;
|
|
i : longint;
|
|
|
|
begin
|
|
if not(assigned(p)) then
|
|
exit;
|
|
if not(p^.treetype in [addn..loadvmtn]) then
|
|
internalerror(26219);
|
|
case p^.disposetyp of
|
|
dt_leftright :
|
|
begin
|
|
if assigned(p^.left) then
|
|
disposetree(p^.left);
|
|
if assigned(p^.right) then
|
|
disposetree(p^.right);
|
|
end;
|
|
dt_leftrighthigh :
|
|
begin
|
|
if assigned(p^.left) then
|
|
disposetree(p^.left);
|
|
if assigned(p^.right) then
|
|
disposetree(p^.right);
|
|
if assigned(p^.hightree) then
|
|
disposetree(p^.hightree);
|
|
end;
|
|
dt_leftrightframe :
|
|
begin
|
|
if assigned(p^.left) then
|
|
disposetree(p^.left);
|
|
if assigned(p^.right) then
|
|
disposetree(p^.right);
|
|
if assigned(p^.frametree) then
|
|
disposetree(p^.frametree);
|
|
end;
|
|
dt_leftrightmethod :
|
|
begin
|
|
if assigned(p^.left) then
|
|
disposetree(p^.left);
|
|
if assigned(p^.right) then
|
|
disposetree(p^.right);
|
|
if assigned(p^.methodpointer) then
|
|
disposetree(p^.methodpointer);
|
|
end;
|
|
dt_case :
|
|
begin
|
|
if assigned(p^.left) then
|
|
disposetree(p^.left);
|
|
if assigned(p^.right) then
|
|
disposetree(p^.right);
|
|
if assigned(p^.nodes) then
|
|
deletecaselabels(p^.nodes);
|
|
if assigned(p^.elseblock) then
|
|
disposetree(p^.elseblock);
|
|
end;
|
|
dt_nothing : ;
|
|
dt_left :
|
|
if assigned(p^.left) then
|
|
disposetree(p^.left);
|
|
dt_mbleft :
|
|
if assigned(p^.left) then
|
|
disposetree(p^.left);
|
|
dt_mbleft_and_method :
|
|
begin
|
|
if assigned(p^.left) then disposetree(p^.left);
|
|
disposetree(p^.methodpointer);
|
|
end;
|
|
dt_typeconv : disposetree(p^.left);
|
|
dt_inlinen :
|
|
if assigned(p^.left) then
|
|
disposetree(p^.left);
|
|
dt_loop :
|
|
begin
|
|
if assigned(p^.left) then
|
|
disposetree(p^.left);
|
|
if assigned(p^.right) then
|
|
disposetree(p^.right);
|
|
if assigned(p^.t1) then
|
|
disposetree(p^.t1);
|
|
if assigned(p^.t2) then
|
|
disposetree(p^.t2);
|
|
end;
|
|
dt_onn:
|
|
begin
|
|
if assigned(p^.left) then
|
|
disposetree(p^.left);
|
|
if assigned(p^.right) then
|
|
disposetree(p^.right);
|
|
if assigned(p^.exceptsymtable) then
|
|
dispose(p^.exceptsymtable,done);
|
|
end;
|
|
dt_with :
|
|
begin
|
|
if assigned(p^.left) then
|
|
disposetree(p^.left);
|
|
if assigned(p^.right) then
|
|
disposetree(p^.right);
|
|
{$IFDEF NEWST}
|
|
dispose(p^.withsymtables,done);
|
|
{$ELSE}
|
|
symt:=p^.withsymtable;
|
|
for i:=1 to p^.tablecount do
|
|
begin
|
|
if assigned(symt) then
|
|
begin
|
|
p^.withsymtable:=pwithsymtable(symt^.next);
|
|
dispose(symt,done);
|
|
end;
|
|
symt:=p^.withsymtable;
|
|
end;
|
|
{$ENDIF NEWST}
|
|
end;
|
|
else internalerror(12);
|
|
end;
|
|
putnode(p);
|
|
end;
|
|
|
|
procedure set_file_line(from,_to : ptree);
|
|
|
|
begin
|
|
if assigned(from) then
|
|
_to^.fileinfo:=from^.fileinfo;
|
|
end;
|
|
|
|
procedure set_tree_filepos(p : ptree;const filepos : tfileposinfo);
|
|
begin
|
|
p^.fileinfo:=filepos;
|
|
end;
|
|
|
|
{$IFDEF NEWST}
|
|
function genwithnode(symtables:Pcollection;l,r : ptree) : ptree;
|
|
|
|
var
|
|
p : ptree;
|
|
|
|
begin
|
|
p:=getnode;
|
|
p^.disposetyp:=dt_with;
|
|
p^.treetype:=withn;
|
|
p^.left:=l;
|
|
p^.right:=r;
|
|
p^.registers32:=0;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
p^.resulttype:=nil;
|
|
p^.withsymtables:=symtables;
|
|
p^.withreference:=nil;
|
|
p^.islocal:=false;
|
|
set_file_line(l,p);
|
|
genwithnode:=p;
|
|
end;
|
|
{$ELSE}
|
|
function genwithnode(symtable : pwithsymtable;l,r : ptree;count : longint) : ptree;
|
|
|
|
var
|
|
p : ptree;
|
|
|
|
begin
|
|
p:=getnode;
|
|
p^.disposetyp:=dt_with;
|
|
p^.treetype:=withn;
|
|
p^.left:=l;
|
|
p^.right:=r;
|
|
p^.registers32:=0;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
p^.resulttype:=nil;
|
|
p^.withsymtable:=symtable;
|
|
p^.tablecount:=count;
|
|
p^.withreference:=nil;
|
|
p^.islocal:=false;
|
|
set_file_line(l,p);
|
|
genwithnode:=p;
|
|
end;
|
|
{$ENDIF NEWST}
|
|
|
|
function genfixconstnode(v : longint;def : pdef) : ptree;
|
|
|
|
var
|
|
p : ptree;
|
|
|
|
begin
|
|
p:=getnode;
|
|
p^.disposetyp:=dt_nothing;
|
|
p^.treetype:=fixconstn;
|
|
p^.registers32:=0;
|
|
{ p^.registers16:=0;
|
|
p^.registers8:=0; }
|
|
p^.registersfpu:=0;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
p^.resulttype:=def;
|
|
p^.value:=v;
|
|
genfixconstnode:=p;
|
|
end;
|
|
|
|
function gencallparanode(expr,next : ptree) : ptree;
|
|
|
|
var
|
|
p : ptree;
|
|
|
|
begin
|
|
p:=getnode;
|
|
p^.disposetyp:=dt_leftrighthigh;
|
|
p^.treetype:=callparan;
|
|
p^.left:=expr;
|
|
p^.right:=next;
|
|
p^.registers32:=0;
|
|
{ p^.registers16:=0;
|
|
p^.registers8:=0; }
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
p^.registersfpu:=0;
|
|
p^.resulttype:=nil;
|
|
p^.exact_match_found:=false;
|
|
p^.convlevel1found:=false;
|
|
p^.convlevel2found:=false;
|
|
p^.is_colon_para:=false;
|
|
p^.hightree:=nil;
|
|
set_file_line(expr,p);
|
|
gencallparanode:=p;
|
|
end;
|
|
|
|
function gennode(t : ttreetyp;l,r : ptree) : ptree;
|
|
|
|
var
|
|
p : ptree;
|
|
|
|
begin
|
|
p:=getnode;
|
|
p^.disposetyp:=dt_leftright;
|
|
p^.treetype:=t;
|
|
p^.left:=l;
|
|
p^.right:=r;
|
|
p^.registers32:=0;
|
|
{ p^.registers16:=0;
|
|
p^.registers8:=0; }
|
|
p^.registersfpu:=0;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
p^.resulttype:=nil;
|
|
gennode:=p;
|
|
end;
|
|
|
|
function gencasenode(l,r : ptree;nodes : pcaserecord) : ptree;
|
|
|
|
var
|
|
p : ptree;
|
|
|
|
begin
|
|
p:=getnode;
|
|
p^.disposetyp:=dt_case;
|
|
p^.treetype:=casen;
|
|
p^.left:=l;
|
|
p^.right:=r;
|
|
p^.nodes:=nodes;
|
|
p^.registers32:=0;
|
|
p^.registersfpu:=0;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
p^.resulttype:=nil;
|
|
set_file_line(l,p);
|
|
gencasenode:=p;
|
|
end;
|
|
|
|
function genloopnode(t : ttreetyp;l,r,n1 : ptree;back : boolean) : ptree;
|
|
|
|
var
|
|
p : ptree;
|
|
|
|
begin
|
|
p:=getnode;
|
|
p^.disposetyp:=dt_loop;
|
|
p^.treetype:=t;
|
|
p^.left:=l;
|
|
p^.right:=r;
|
|
p^.t1:=n1;
|
|
p^.t2:=nil;
|
|
p^.registers32:=0;
|
|
p^.backward:=back;
|
|
{ p^.registers16:=0;
|
|
p^.registers8:=0; }
|
|
p^.registersfpu:=0;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
p^.resulttype:=nil;
|
|
set_file_line(l,p);
|
|
genloopnode:=p;
|
|
end;
|
|
|
|
function genordinalconstnode(v : tconstexprint;def : pdef) : ptree;
|
|
|
|
var
|
|
p : ptree;
|
|
|
|
begin
|
|
p:=getnode;
|
|
p^.disposetyp:=dt_nothing;
|
|
p^.treetype:=ordconstn;
|
|
p^.registers32:=0;
|
|
{ p^.registers16:=0;
|
|
p^.registers8:=0; }
|
|
p^.registersfpu:=0;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
p^.resulttype:=def;
|
|
p^.value:=v;
|
|
{$IFDEF NEWST}
|
|
if typeof(p^.resulttype^)=typeof(Torddef) then
|
|
testrange(p^.resulttype,p^.value);
|
|
{$ELSE NEWST}
|
|
if p^.resulttype^.deftype=orddef then
|
|
testrange(p^.resulttype,p^.value);
|
|
{$ENDIF}
|
|
genordinalconstnode:=p;
|
|
end;
|
|
|
|
function genintconstnode(v : TConstExprInt) : ptree;
|
|
|
|
var
|
|
i : TConstExprInt;
|
|
|
|
begin
|
|
{ we need to bootstrap this code, so it's a little bit messy }
|
|
i:=2147483647;
|
|
if (v<=i) and (v>=-i-1) then
|
|
genintconstnode:=genordinalconstnode(v,s32bitdef)
|
|
else
|
|
genintconstnode:=genordinalconstnode(v,cs64bitdef);
|
|
end;
|
|
|
|
function genpointerconstnode(v : tpointerord;def : pdef) : ptree;
|
|
|
|
var
|
|
p : ptree;
|
|
|
|
begin
|
|
p:=getnode;
|
|
p^.disposetyp:=dt_nothing;
|
|
p^.treetype:=pointerconstn;
|
|
p^.registers32:=0;
|
|
{ p^.registers16:=0;
|
|
p^.registers8:=0; }
|
|
p^.registersfpu:=0;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
p^.resulttype:=def;
|
|
p^.value:=v;
|
|
genpointerconstnode:=p;
|
|
end;
|
|
|
|
function genenumnode(v : penumsym) : ptree;
|
|
|
|
var
|
|
p : ptree;
|
|
|
|
begin
|
|
p:=getnode;
|
|
p^.disposetyp:=dt_nothing;
|
|
p^.treetype:=ordconstn;
|
|
p^.registers32:=0;
|
|
{ p^.registers16:=0;
|
|
p^.registers8:=0; }
|
|
p^.registersfpu:=0;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
p^.resulttype:=v^.definition;
|
|
p^.value:=v^.value;
|
|
testrange(p^.resulttype,p^.value);
|
|
genenumnode:=p;
|
|
end;
|
|
|
|
|
|
function genrealconstnode(v : bestreal;def : pdef) : ptree;
|
|
|
|
var
|
|
p : ptree;
|
|
|
|
begin
|
|
p:=getnode;
|
|
p^.disposetyp:=dt_nothing;
|
|
p^.treetype:=realconstn;
|
|
p^.registers32:=0;
|
|
{ p^.registers16:=0;
|
|
p^.registers8:=0; }
|
|
p^.registersfpu:=0;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
p^.resulttype:=def;
|
|
p^.value_real:=v;
|
|
p^.lab_real:=nil;
|
|
genrealconstnode:=p;
|
|
end;
|
|
|
|
|
|
function genstringconstnode(const s : string;st:tstringtype) : ptree;
|
|
|
|
var
|
|
p : ptree;
|
|
l : longint;
|
|
begin
|
|
p:=getnode;
|
|
p^.disposetyp:=dt_nothing;
|
|
p^.treetype:=stringconstn;
|
|
p^.registers32:=0;
|
|
{ p^.registers16:=0;
|
|
p^.registers8:=0; }
|
|
p^.registersfpu:=0;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
l:=length(s);
|
|
p^.length:=l;
|
|
{ stringdup write even past a #0 }
|
|
getmem(p^.value_str,l+1);
|
|
move(s[1],p^.value_str^,l);
|
|
p^.value_str[l]:=#0;
|
|
p^.lab_str:=nil;
|
|
if st=st_default then
|
|
begin
|
|
if cs_ansistrings in aktlocalswitches then
|
|
p^.stringtype:=st_ansistring
|
|
else
|
|
p^.stringtype:=st_shortstring;
|
|
end
|
|
else
|
|
p^.stringtype:=st;
|
|
case p^.stringtype of
|
|
st_shortstring :
|
|
p^.resulttype:=cshortstringdef;
|
|
st_ansistring :
|
|
p^.resulttype:=cansistringdef;
|
|
else
|
|
internalerror(44990099);
|
|
end;
|
|
genstringconstnode:=p;
|
|
end;
|
|
|
|
function getpcharcopy(p : ptree) : pchar;
|
|
var
|
|
pc : pchar;
|
|
begin
|
|
pc:=nil;
|
|
getmem(pc,p^.length+1);
|
|
if pc=nil then
|
|
Message(general_f_no_memory_left);
|
|
move(p^.value_str^,pc^,p^.length+1);
|
|
getpcharcopy:=pc;
|
|
end;
|
|
|
|
|
|
function genpcharconstnode(s : pchar;length : longint) : ptree;
|
|
var
|
|
p : ptree;
|
|
begin
|
|
p:=getnode;
|
|
p^.disposetyp:=dt_nothing;
|
|
p^.treetype:=stringconstn;
|
|
p^.registers32:=0;
|
|
{ p^.registers16:=0;
|
|
p^.registers8:=0; }
|
|
p^.registersfpu:=0;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
p^.length:=length;
|
|
if (cs_ansistrings in aktlocalswitches) or
|
|
(length>255) then
|
|
begin
|
|
p^.stringtype:=st_ansistring;
|
|
p^.resulttype:=cansistringdef;
|
|
end
|
|
else
|
|
begin
|
|
p^.stringtype:=st_shortstring;
|
|
p^.resulttype:=cshortstringdef;
|
|
end;
|
|
p^.value_str:=s;
|
|
p^.lab_str:=nil;
|
|
genpcharconstnode:=p;
|
|
end;
|
|
|
|
|
|
function gensinglenode(t : ttreetyp;l : ptree) : ptree;
|
|
|
|
var
|
|
p : ptree;
|
|
|
|
begin
|
|
p:=getnode;
|
|
p^.disposetyp:=dt_left;
|
|
p^.treetype:=t;
|
|
p^.left:=l;
|
|
p^.registers32:=0;
|
|
{ p^.registers16:=0;
|
|
p^.registers8:=0; }
|
|
p^.registersfpu:=0;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
p^.resulttype:=nil;
|
|
gensinglenode:=p;
|
|
end;
|
|
|
|
function genasmnode(p_asm : paasmoutput) : ptree;
|
|
|
|
var
|
|
p : ptree;
|
|
|
|
begin
|
|
p:=getnode;
|
|
p^.disposetyp:=dt_nothing;
|
|
p^.treetype:=asmn;
|
|
p^.registers32:=4;
|
|
p^.p_asm:=p_asm;
|
|
p^.object_preserved:=false;
|
|
{ p^.registers16:=0;
|
|
p^.registers8:=0; }
|
|
p^.registersfpu:=8;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=8;
|
|
{$endif SUPPORT_MMX}
|
|
p^.resulttype:=nil;
|
|
genasmnode:=p;
|
|
end;
|
|
|
|
function genloadnode(v : pvarsym;st : psymtable) : ptree;
|
|
|
|
var
|
|
p : ptree;
|
|
|
|
begin
|
|
p:=getnode;
|
|
p^.registers32:=0;
|
|
{ p^.registers16:=0;
|
|
p^.registers8:=0; }
|
|
p^.registersfpu:=0;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
p^.treetype:=loadn;
|
|
{$IFDEF NEWST}
|
|
p^.resulttype:=v^.definition;
|
|
{$ELSE}
|
|
p^.resulttype:=v^.vartype.def;
|
|
{$ENDIF NEWST}
|
|
p^.symtableentry:=v;
|
|
p^.symtable:=st;
|
|
p^.is_first := False;
|
|
{ method pointer load nodes can use the left subtree }
|
|
p^.disposetyp:=dt_left;
|
|
p^.left:=nil;
|
|
genloadnode:=p;
|
|
end;
|
|
|
|
function genloadcallnode(v: pprocsym;st: psymtable): ptree;
|
|
var
|
|
p : ptree;
|
|
|
|
begin
|
|
p:=getnode;
|
|
p^.registers32:=0;
|
|
{ p^.registers16:=0;
|
|
p^.registers8:=0; }
|
|
p^.registersfpu:=0;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
p^.treetype:=loadn;
|
|
p^.left:=nil;
|
|
{$IFDEF NEWST}
|
|
p^.resulttype:=nil; {We don't know which overloaded procedure is
|
|
wanted...}
|
|
{$ELSE}
|
|
p^.resulttype:=v^.definition;
|
|
{$ENDIF}
|
|
p^.symtableentry:=v;
|
|
p^.symtable:=st;
|
|
p^.is_first := False;
|
|
p^.disposetyp:=dt_nothing;
|
|
genloadcallnode:=p;
|
|
end;
|
|
|
|
function genloadmethodcallnode(v: pprocsym;st: psymtable; mp:ptree): ptree;
|
|
var
|
|
p : ptree;
|
|
|
|
begin
|
|
p:=getnode;
|
|
p^.registers32:=0;
|
|
{ p^.registers16:=0;
|
|
p^.registers8:=0; }
|
|
p^.registersfpu:=0;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
p^.treetype:=loadn;
|
|
p^.left:=nil;
|
|
{$IFDEF NEWST}
|
|
p^.resulttype:=nil; {We don't know which overloaded procedure is
|
|
wanted...}
|
|
{$ELSE}
|
|
p^.resulttype:=v^.definition;
|
|
{$ENDIF}
|
|
p^.symtableentry:=v;
|
|
p^.symtable:=st;
|
|
p^.is_first := False;
|
|
p^.disposetyp:=dt_left;
|
|
p^.left:=mp;
|
|
genloadmethodcallnode:=p;
|
|
end;
|
|
|
|
|
|
function gentypedconstloadnode(sym : ptypedconstsym;st : psymtable) : ptree;
|
|
|
|
var
|
|
p : ptree;
|
|
|
|
begin
|
|
p:=getnode;
|
|
p^.registers32:=0;
|
|
{ p^.registers16:=0;
|
|
p^.registers8:=0; }
|
|
p^.registersfpu:=0;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
p^.treetype:=loadn;
|
|
p^.left:=nil;
|
|
{$IFDEF NEWST}
|
|
p^.resulttype:=sym^.definition;
|
|
{$ELSE}
|
|
p^.resulttype:=sym^.typedconsttype.def;
|
|
{$ENDIF NEWST}
|
|
p^.symtableentry:=sym;
|
|
p^.symtable:=st;
|
|
p^.disposetyp:=dt_nothing;
|
|
gentypedconstloadnode:=p;
|
|
end;
|
|
|
|
function gentypeconvnode(node : ptree;t : pdef) : ptree;
|
|
|
|
var
|
|
p : ptree;
|
|
|
|
begin
|
|
p:=getnode;
|
|
p^.disposetyp:=dt_typeconv;
|
|
p^.treetype:=typeconvn;
|
|
p^.left:=node;
|
|
p^.registers32:=0;
|
|
{ p^.registers16:=0;
|
|
p^.registers8:=0; }
|
|
p^.convtyp:=tc_equal;
|
|
p^.registersfpu:=0;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
p^.resulttype:=t;
|
|
p^.explizit:=false;
|
|
set_file_line(node,p);
|
|
gentypeconvnode:=p;
|
|
end;
|
|
|
|
function gentypenode(t : pdef;sym:ptypesym) : ptree;
|
|
var
|
|
p : ptree;
|
|
begin
|
|
p:=getnode;
|
|
p^.disposetyp:=dt_nothing;
|
|
p^.treetype:=typen;
|
|
p^.registers32:=0;
|
|
{ p^.registers16:=0;
|
|
p^.registers8:=0; }
|
|
p^.registersfpu:=0;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
p^.resulttype:=generrordef;
|
|
p^.typenodetype:=t;
|
|
p^.typenodesym:=sym;
|
|
gentypenode:=p;
|
|
end;
|
|
|
|
function gencallnode(v : pprocsym;st : psymtable) : ptree;
|
|
|
|
var
|
|
p : ptree;
|
|
|
|
begin
|
|
p:=getnode;
|
|
p^.registers32:=0;
|
|
{ p^.registers16:=0;
|
|
p^.registers8:=0; }
|
|
p^.registersfpu:=0;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
p^.treetype:=calln;
|
|
p^.symtableprocentry:=v;
|
|
p^.symtableproc:=st;
|
|
p^.unit_specific:=false;
|
|
p^.no_check:=false;
|
|
p^.return_value_used:=true;
|
|
p^.disposetyp := dt_leftrightmethod;
|
|
p^.methodpointer:=nil;
|
|
p^.left:=nil;
|
|
p^.right:=nil;
|
|
p^.procdefinition:=nil;
|
|
gencallnode:=p;
|
|
end;
|
|
|
|
function genmethodcallnode(v : pprocsym;st : psymtable;mp : ptree) : ptree;
|
|
|
|
var
|
|
p : ptree;
|
|
|
|
begin
|
|
p:=getnode;
|
|
p^.registers32:=0;
|
|
{ p^.registers16:=0;
|
|
p^.registers8:=0; }
|
|
p^.registersfpu:=0;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
p^.treetype:=calln;
|
|
p^.return_value_used:=true;
|
|
p^.symtableprocentry:=v;
|
|
p^.symtableproc:=st;
|
|
p^.disposetyp:=dt_leftrightmethod;
|
|
p^.left:=nil;
|
|
p^.right:=nil;
|
|
p^.methodpointer:=mp;
|
|
p^.procdefinition:=nil;
|
|
genmethodcallnode:=p;
|
|
end;
|
|
|
|
function gensubscriptnode(varsym : pvarsym;l : ptree) : ptree;
|
|
|
|
var
|
|
p : ptree;
|
|
|
|
begin
|
|
p:=getnode;
|
|
p^.disposetyp:=dt_left;
|
|
p^.treetype:=subscriptn;
|
|
p^.left:=l;
|
|
p^.registers32:=0;
|
|
p^.vs:=varsym;
|
|
{ p^.registers16:=0;
|
|
p^.registers8:=0; }
|
|
p^.registersfpu:=0;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
p^.resulttype:=nil;
|
|
gensubscriptnode:=p;
|
|
end;
|
|
|
|
function genzeronode(t : ttreetyp) : ptree;
|
|
|
|
var
|
|
p : ptree;
|
|
|
|
begin
|
|
p:=getnode;
|
|
p^.disposetyp:=dt_nothing;
|
|
p^.treetype:=t;
|
|
p^.registers32:=0;
|
|
{ p^.registers16:=0;
|
|
p^.registers8:=0; }
|
|
p^.registersfpu:=0;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
p^.resulttype:=nil;
|
|
genzeronode:=p;
|
|
end;
|
|
|
|
function genlabelnode(t : ttreetyp;nr : pasmlabel) : ptree;
|
|
|
|
var
|
|
p : ptree;
|
|
|
|
begin
|
|
p:=getnode;
|
|
p^.disposetyp:=dt_nothing;
|
|
p^.treetype:=t;
|
|
p^.registers32:=0;
|
|
{ p^.registers16:=0;
|
|
p^.registers8:=0; }
|
|
p^.registersfpu:=0;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
p^.resulttype:=nil;
|
|
{ for security }
|
|
{ nr^.is_used:=true;}
|
|
p^.labelnr:=nr;
|
|
p^.exceptionblock:=nil;
|
|
genlabelnode:=p;
|
|
end;
|
|
|
|
function genselfnode(_class : pdef) : ptree;
|
|
|
|
var
|
|
p : ptree;
|
|
|
|
begin
|
|
p:=getnode;
|
|
p^.disposetyp:=dt_nothing;
|
|
p^.treetype:=selfn;
|
|
p^.registers32:=0;
|
|
{ p^.registers16:=0;
|
|
p^.registers8:=0; }
|
|
p^.registersfpu:=0;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
p^.resulttype:=_class;
|
|
genselfnode:=p;
|
|
end;
|
|
|
|
function geninlinenode(number : byte;is_const:boolean;l : ptree) : ptree;
|
|
|
|
var
|
|
p : ptree;
|
|
|
|
begin
|
|
p:=getnode;
|
|
p^.disposetyp:=dt_inlinen;
|
|
p^.treetype:=inlinen;
|
|
p^.left:=l;
|
|
p^.inlinenumber:=number;
|
|
p^.inlineconst:=is_const;
|
|
p^.registers32:=0;
|
|
{ p^.registers16:=0;
|
|
p^.registers8:=0; }
|
|
p^.registersfpu:=0;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
p^.resulttype:=nil;
|
|
geninlinenode:=p;
|
|
end;
|
|
|
|
|
|
{ uses the callnode to create the new procinline node }
|
|
function genprocinlinenode(callp,code : ptree) : ptree;
|
|
|
|
var
|
|
p : ptree;
|
|
|
|
begin
|
|
p:=getnode;
|
|
p^.disposetyp:=dt_nothing;
|
|
p^.treetype:=procinlinen;
|
|
p^.inlineprocsym:=callp^.symtableprocentry;
|
|
p^.retoffset:=-4; { less dangerous as zero (PM) }
|
|
p^.para_offset:=0;
|
|
{$IFDEF NEWST}
|
|
{Fixme!!}
|
|
internalerror($00022801);
|
|
{$ELSE}
|
|
p^.para_size:=p^.inlineprocsym^.definition^.para_size(target_os.stackalignment);
|
|
if ret_in_param(p^.inlineprocsym^.definition^.rettype.def) then
|
|
p^.para_size:=p^.para_size+target_os.size_of_pointer;
|
|
{$ENDIF NEWST}
|
|
{ copy args }
|
|
p^.inlinetree:=code;
|
|
p^.registers32:=code^.registers32;
|
|
p^.registersfpu:=code^.registersfpu;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
{$IFDEF NEWST}
|
|
{Fixme!!}
|
|
{$ELSE}
|
|
p^.resulttype:=p^.inlineprocsym^.definition^.rettype.def;
|
|
{$ENDIF NEWST}
|
|
genprocinlinenode:=p;
|
|
end;
|
|
|
|
function gensetconstnode(s : pconstset;settype : psetdef) : ptree;
|
|
|
|
var
|
|
p : ptree;
|
|
|
|
begin
|
|
p:=getnode;
|
|
p^.disposetyp:=dt_nothing;
|
|
p^.treetype:=setconstn;
|
|
p^.registers32:=0;
|
|
p^.registersfpu:=0;
|
|
{$ifdef SUPPORT_MMX}
|
|
p^.registersmmx:=0;
|
|
{$endif SUPPORT_MMX}
|
|
p^.resulttype:=settype;
|
|
p^.left:=nil;
|
|
new(p^.value_set);
|
|
p^.value_set^:=s^;
|
|
gensetconstnode:=p;
|
|
end;
|
|
|
|
|
|
function genconstsymtree(p:pconstsym):ptree;
|
|
var
|
|
p1 : ptree;
|
|
len : longint;
|
|
pc : pchar;
|
|
begin
|
|
p1:=nil;
|
|
case p^.consttyp of
|
|
constint :
|
|
p1:=genordinalconstnode(p^.value,s32bitdef);
|
|
conststring :
|
|
begin
|
|
len:=p^.len;
|
|
if not(cs_ansistrings in aktlocalswitches) and (len>255) then
|
|
len:=255;
|
|
getmem(pc,len+1);
|
|
move(pchar(tpointerord(p^.value))^,pc^,len);
|
|
pc[len]:=#0;
|
|
p1:=genpcharconstnode(pc,len);
|
|
end;
|
|
constchar :
|
|
p1:=genordinalconstnode(p^.value,cchardef);
|
|
constreal :
|
|
p1:=genrealconstnode(pbestreal(tpointerord(p^.value))^,bestrealdef^);
|
|
constbool :
|
|
p1:=genordinalconstnode(p^.value,booldef);
|
|
constset :
|
|
p1:=gensetconstnode(pconstset(tpointerord(p^.value)),psetdef(p^.consttype.def));
|
|
constord :
|
|
p1:=genordinalconstnode(p^.value,p^.consttype.def);
|
|
constpointer :
|
|
p1:=genpointerconstnode(p^.value,p^.consttype.def);
|
|
constnil :
|
|
p1:=genzeronode(niln);
|
|
constresourcestring:
|
|
begin
|
|
p1:=genloadnode(pvarsym(p),pvarsym(p)^.owner);
|
|
p1^.resulttype:=cansistringdef;
|
|
end;
|
|
end;
|
|
genconstsymtree:=p1;
|
|
end;
|
|
|
|
|
|
{$ifdef extdebug}
|
|
procedure compare_trees(oldp,p : ptree);
|
|
|
|
var
|
|
error_found : boolean;
|
|
|
|
begin
|
|
if oldp^.resulttype<>p^.resulttype then
|
|
begin
|
|
error_found:=true;
|
|
if is_equal(oldp^.resulttype,p^.resulttype) then
|
|
comment(v_debug,'resulttype fields are different but equal')
|
|
else
|
|
comment(v_warning,'resulttype fields are really different');
|
|
end;
|
|
if oldp^.treetype<>p^.treetype then
|
|
begin
|
|
comment(v_warning,'treetype field different');
|
|
error_found:=true;
|
|
end
|
|
else
|
|
comment(v_debug,' treetype '+tostr(longint(oldp^.treetype)));
|
|
if oldp^.error<>p^.error then
|
|
begin
|
|
comment(v_warning,'error field different');
|
|
error_found:=true;
|
|
end;
|
|
if oldp^.disposetyp<>p^.disposetyp then
|
|
begin
|
|
comment(v_warning,'disposetyp field different');
|
|
error_found:=true;
|
|
end;
|
|
{ is true, if the right and left operand are swaped }
|
|
if oldp^.swaped<>p^.swaped then
|
|
begin
|
|
comment(v_warning,'swaped field different');
|
|
error_found:=true;
|
|
end;
|
|
|
|
{ the location of the result of this node }
|
|
if oldp^.location.loc<>p^.location.loc then
|
|
begin
|
|
comment(v_warning,'location.loc field different');
|
|
error_found:=true;
|
|
end;
|
|
|
|
{ the number of registers needed to evalute the node }
|
|
if oldp^.registers32<>p^.registers32 then
|
|
begin
|
|
comment(v_warning,'registers32 field different');
|
|
comment(v_warning,' old '+tostr(oldp^.registers32)+'<> new '+tostr(p^.registers32));
|
|
error_found:=true;
|
|
end;
|
|
if oldp^.registersfpu<>p^.registersfpu then
|
|
begin
|
|
comment(v_warning,'registersfpu field different');
|
|
error_found:=true;
|
|
end;
|
|
{$ifdef SUPPORT_MMX}
|
|
if oldp^.registersmmx<>p^.registersmmx then
|
|
begin
|
|
comment(v_warning,'registersmmx field different');
|
|
error_found:=true;
|
|
end;
|
|
{$endif SUPPORT_MMX}
|
|
if oldp^.left<>p^.left then
|
|
begin
|
|
comment(v_warning,'left field different');
|
|
error_found:=true;
|
|
end;
|
|
if oldp^.right<>p^.right then
|
|
begin
|
|
comment(v_warning,'right field different');
|
|
error_found:=true;
|
|
end;
|
|
if oldp^.fileinfo.line<>p^.fileinfo.line then
|
|
begin
|
|
comment(v_warning,'fileinfo.line field different');
|
|
error_found:=true;
|
|
end;
|
|
if oldp^.fileinfo.column<>p^.fileinfo.column then
|
|
begin
|
|
comment(v_warning,'fileinfo.column field different');
|
|
error_found:=true;
|
|
end;
|
|
if oldp^.fileinfo.fileindex<>p^.fileinfo.fileindex then
|
|
begin
|
|
comment(v_warning,'fileinfo.fileindex field different');
|
|
error_found:=true;
|
|
end;
|
|
if oldp^.localswitches<>p^.localswitches then
|
|
begin
|
|
comment(v_warning,'localswitches field different');
|
|
error_found:=true;
|
|
end;
|
|
{$ifdef extdebug}
|
|
if oldp^.firstpasscount<>p^.firstpasscount then
|
|
begin
|
|
comment(v_warning,'firstpasscount field different');
|
|
error_found:=true;
|
|
end;
|
|
{$endif extdebug}
|
|
if oldp^.treetype=p^.treetype then
|
|
case oldp^.treetype of
|
|
addn :
|
|
begin
|
|
if oldp^.use_strconcat<>p^.use_strconcat then
|
|
begin
|
|
comment(v_warning,'use_strconcat field different');
|
|
error_found:=true;
|
|
end;
|
|
if oldp^.string_typ<>p^.string_typ then
|
|
begin
|
|
comment(v_warning,'stringtyp field different');
|
|
error_found:=true;
|
|
end;
|
|
end;
|
|
callparan :
|
|
{(is_colon_para : boolean;exact_match_found : boolean);}
|
|
begin
|
|
if oldp^.is_colon_para<>p^.is_colon_para then
|
|
begin
|
|
comment(v_warning,'use_strconcat field different');
|
|
error_found:=true;
|
|
end;
|
|
if oldp^.exact_match_found<>p^.exact_match_found then
|
|
begin
|
|
comment(v_warning,'exact_match_found field different');
|
|
error_found:=true;
|
|
end;
|
|
end;
|
|
assignn :
|
|
{(assigntyp : tassigntyp;concat_string : boolean);}
|
|
begin
|
|
if oldp^.assigntyp<>p^.assigntyp then
|
|
begin
|
|
comment(v_warning,'assigntyp field different');
|
|
error_found:=true;
|
|
end;
|
|
if oldp^.concat_string<>p^.concat_string then
|
|
begin
|
|
comment(v_warning,'concat_string field different');
|
|
error_found:=true;
|
|
end;
|
|
end;
|
|
loadn :
|
|
{(symtableentry : psym;symtable : psymtable;
|
|
is_absolute,is_first : boolean);}
|
|
begin
|
|
if oldp^.symtableentry<>p^.symtableentry then
|
|
begin
|
|
comment(v_warning,'symtableentry field different');
|
|
error_found:=true;
|
|
end;
|
|
if oldp^.symtable<>p^.symtable then
|
|
begin
|
|
comment(v_warning,'symtable field different');
|
|
error_found:=true;
|
|
end;
|
|
if oldp^.is_absolute<>p^.is_absolute then
|
|
begin
|
|
comment(v_warning,'is_absolute field different');
|
|
error_found:=true;
|
|
end;
|
|
if oldp^.is_first<>p^.is_first then
|
|
begin
|
|
comment(v_warning,'is_first field different');
|
|
error_found:=true;
|
|
end;
|
|
end;
|
|
calln :
|
|
{(symtableprocentry : pprocsym;
|
|
symtableproc : psymtable;procdefinition : pprocdef;
|
|
methodpointer : ptree;
|
|
no_check,unit_specific : boolean);}
|
|
begin
|
|
if oldp^.symtableprocentry<>p^.symtableprocentry then
|
|
begin
|
|
comment(v_warning,'symtableprocentry field different');
|
|
error_found:=true;
|
|
end;
|
|
if oldp^.symtableproc<>p^.symtableproc then
|
|
begin
|
|
comment(v_warning,'symtableproc field different');
|
|
error_found:=true;
|
|
end;
|
|
if oldp^.procdefinition<>p^.procdefinition then
|
|
begin
|
|
comment(v_warning,'procdefinition field different');
|
|
error_found:=true;
|
|
end;
|
|
if oldp^.methodpointer<>p^.methodpointer then
|
|
begin
|
|
comment(v_warning,'methodpointer field different');
|
|
error_found:=true;
|
|
end;
|
|
if oldp^.no_check<>p^.no_check then
|
|
begin
|
|
comment(v_warning,'no_check field different');
|
|
error_found:=true;
|
|
end;
|
|
if oldp^.unit_specific<>p^.unit_specific then
|
|
begin
|
|
error_found:=true;
|
|
comment(v_warning,'unit_specific field different');
|
|
end;
|
|
end;
|
|
ordconstn :
|
|
begin
|
|
if oldp^.value<>p^.value then
|
|
begin
|
|
comment(v_warning,'value field different');
|
|
error_found:=true;
|
|
end;
|
|
end;
|
|
realconstn :
|
|
begin
|
|
if oldp^.value_real<>p^.value_real then
|
|
begin
|
|
comment(v_warning,'valued field different');
|
|
error_found:=true;
|
|
end;
|
|
if oldp^.lab_real<>p^.lab_real then
|
|
begin
|
|
comment(v_warning,'labnumber field different');
|
|
error_found:=true;
|
|
end;
|
|
{ if oldp^.realtyp<>p^.realtyp then
|
|
begin
|
|
comment(v_warning,'realtyp field different');
|
|
error_found:=true;
|
|
end; }
|
|
end;
|
|
end;
|
|
if not error_found then
|
|
comment(v_warning,'did not find difference in trees');
|
|
|
|
end;
|
|
{$endif extdebug}
|
|
|
|
function equal_trees(t1,t2 : ptree) : boolean;
|
|
|
|
begin
|
|
if t1^.treetype=t2^.treetype then
|
|
begin
|
|
case t1^.treetype of
|
|
addn,
|
|
muln,
|
|
equaln,
|
|
orn,
|
|
xorn,
|
|
andn,
|
|
unequaln:
|
|
begin
|
|
equal_trees:=(equal_trees(t1^.left,t2^.left) and
|
|
equal_trees(t1^.right,t2^.right)) or
|
|
(equal_trees(t1^.right,t2^.left) and
|
|
equal_trees(t1^.left,t2^.right));
|
|
end;
|
|
subn,
|
|
divn,
|
|
modn,
|
|
assignn,
|
|
ltn,
|
|
lten,
|
|
gtn,
|
|
gten,
|
|
inn,
|
|
shrn,
|
|
shln,
|
|
slashn,
|
|
rangen:
|
|
begin
|
|
equal_trees:=(equal_trees(t1^.left,t2^.left) and
|
|
equal_trees(t1^.right,t2^.right));
|
|
end;
|
|
unaryminusn,
|
|
notn,
|
|
derefn,
|
|
addrn:
|
|
begin
|
|
equal_trees:=(equal_trees(t1^.left,t2^.left));
|
|
end;
|
|
loadn:
|
|
begin
|
|
equal_trees:=(t1^.symtableentry=t2^.symtableentry)
|
|
{ not necessary
|
|
and (t1^.symtable=t2^.symtable)};
|
|
end;
|
|
{
|
|
|
|
subscriptn,
|
|
ordconstn,typeconvn,calln,callparan,
|
|
realconstn,asmn,vecn,
|
|
stringconstn,funcretn,selfn,
|
|
inlinen,niln,errorn,
|
|
typen,hnewn,hdisposen,newn,
|
|
disposen,setelen,setconstrn
|
|
}
|
|
else equal_trees:=false;
|
|
end;
|
|
end
|
|
else
|
|
equal_trees:=false;
|
|
end;
|
|
|
|
{$ifdef newoptimizations2}
|
|
function multiple_uses(t1,t2: ptree): boolean;
|
|
var nr: longint;
|
|
|
|
procedure check_tree(t: ptree);
|
|
begin
|
|
inc(nr,ord(equal_trees(t1,t)));
|
|
if (nr < 2) and assigned(t^.left) then
|
|
check_tree(t^.left);
|
|
if (nr < 2) and assigned(t^.right) then
|
|
check_tree(t^.right);
|
|
end;
|
|
|
|
begin
|
|
nr := 0;
|
|
check_tree(t2);
|
|
multiple_uses := nr > 1;
|
|
end;
|
|
{$endif newoptimizations2}
|
|
|
|
procedure set_unique(p : ptree);
|
|
|
|
begin
|
|
if assigned(p) then
|
|
begin
|
|
case p^.treetype of
|
|
vecn:
|
|
p^.callunique:=true;
|
|
typeconvn,subscriptn,derefn:
|
|
set_unique(p^.left);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure set_funcret_is_valid(p : ptree);
|
|
|
|
begin
|
|
if assigned(p) then
|
|
begin
|
|
case p^.treetype of
|
|
funcretn:
|
|
begin
|
|
if p^.is_first_funcret then
|
|
pprocinfo(p^.funcretprocinfo)^.funcret_state:=vs_assigned;
|
|
end;
|
|
vecn,typeconvn,subscriptn{,derefn}:
|
|
set_funcret_is_valid(p^.left);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure unset_varstate(p : ptree);
|
|
begin
|
|
while assigned(p) do
|
|
begin
|
|
p^.varstateset:=false;
|
|
case p^.treetype of
|
|
typeconvn,
|
|
subscriptn,
|
|
vecn :
|
|
p:=p^.left;
|
|
else
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure set_varstate(p : ptree;must_be_valid : boolean);
|
|
|
|
begin
|
|
if not assigned(p) then
|
|
exit
|
|
else
|
|
begin
|
|
if p^.varstateset then
|
|
exit;
|
|
case p^.treetype of
|
|
typeconvn :
|
|
if p^.convtyp in
|
|
[
|
|
tc_cchar_2_pchar,
|
|
tc_cstring_2_pchar,
|
|
tc_array_2_pointer
|
|
] then
|
|
set_varstate(p^.left,false)
|
|
else if p^.convtyp in
|
|
[
|
|
tc_pchar_2_string,
|
|
tc_pointer_2_array
|
|
] then
|
|
set_varstate(p^.left,true)
|
|
else
|
|
set_varstate(p^.left,must_be_valid);
|
|
subscriptn :
|
|
set_varstate(p^.left,must_be_valid);
|
|
vecn:
|
|
begin
|
|
if (p^.left^.resulttype^.deftype in [stringdef,arraydef]) then
|
|
set_varstate(p^.left,must_be_valid)
|
|
else
|
|
set_varstate(p^.left,true);
|
|
set_varstate(p^.right,true);
|
|
end;
|
|
{ do not parse calln }
|
|
calln : ;
|
|
callparan:
|
|
begin
|
|
set_varstate(p^.left,must_be_valid);
|
|
set_varstate(p^.right,must_be_valid);
|
|
end;
|
|
loadn :
|
|
if (p^.symtableentry^.typ=varsym) then
|
|
begin
|
|
if must_be_valid and p^.is_first then
|
|
begin
|
|
if (pvarsym(p^.symtableentry)^.varstate=vs_declared_and_first_found) or
|
|
(pvarsym(p^.symtableentry)^.varstate=vs_set_but_first_not_passed) then
|
|
if (assigned(pvarsym(p^.symtableentry)^.owner) and
|
|
assigned(aktprocsym) and
|
|
(pvarsym(p^.symtableentry)^.owner = aktprocsym^.definition^.localst)) then
|
|
begin
|
|
if p^.symtable^.symtabletype=localsymtable then
|
|
CGMessage1(sym_n_uninitialized_local_variable,pvarsym(p^.symtableentry)^.name)
|
|
else
|
|
CGMessage1(sym_n_uninitialized_variable,pvarsym(p^.symtableentry)^.name);
|
|
end;
|
|
end;
|
|
if (p^.is_first) then
|
|
begin
|
|
if pvarsym(p^.symtableentry)^.varstate=vs_declared_and_first_found then
|
|
{ this can only happen at left of an assignment, no ? PM }
|
|
if (parsing_para_level=0) and not must_be_valid then
|
|
pvarsym(p^.symtableentry)^.varstate:=vs_assigned
|
|
else
|
|
pvarsym(p^.symtableentry)^.varstate:=vs_used;
|
|
if pvarsym(p^.symtableentry)^.varstate=vs_set_but_first_not_passed then
|
|
pvarsym(p^.symtableentry)^.varstate:=vs_used;
|
|
p^.is_first:=false;
|
|
end
|
|
else
|
|
begin
|
|
if (pvarsym(p^.symtableentry)^.varstate=vs_assigned) and
|
|
(must_be_valid or (parsing_para_level>0) or
|
|
(p^.resulttype^.deftype=procvardef)) then
|
|
pvarsym(p^.symtableentry)^.varstate:=vs_used;
|
|
if (pvarsym(p^.symtableentry)^.varstate=vs_declared_and_first_found) and
|
|
(must_be_valid or (parsing_para_level>0) or
|
|
(p^.resulttype^.deftype=procvardef)) then
|
|
pvarsym(p^.symtableentry)^.varstate:=vs_set_but_first_not_passed;
|
|
end;
|
|
end;
|
|
funcretn:
|
|
begin
|
|
{ no claim if setting higher return value_str }
|
|
if must_be_valid and
|
|
(procinfo=pprocinfo(p^.funcretprocinfo)) and
|
|
((procinfo^.funcret_state=vs_declared) or
|
|
((p^.is_first_funcret) and
|
|
(procinfo^.funcret_state=vs_declared_and_first_found))) then
|
|
begin
|
|
CGMessage(sym_w_function_result_not_set);
|
|
{ avoid multiple warnings }
|
|
procinfo^.funcret_state:=vs_assigned;
|
|
end;
|
|
if p^.is_first_funcret and not must_be_valid then
|
|
pprocinfo(p^.funcretprocinfo)^.funcret_state:=vs_assigned;
|
|
end;
|
|
else
|
|
begin
|
|
{internalerror(565656);}
|
|
end;
|
|
end;{case }
|
|
p^.varstateset:=true;
|
|
end;
|
|
end;
|
|
|
|
procedure clear_location(var loc : tlocation);
|
|
|
|
begin
|
|
loc.loc:=LOC_INVALID;
|
|
end;
|
|
|
|
{This is needed if you want to be able to delete the string with the nodes !!}
|
|
procedure set_location(var destloc,sourceloc : tlocation);
|
|
|
|
begin
|
|
destloc:= sourceloc;
|
|
end;
|
|
|
|
procedure swap_location(var destloc,sourceloc : tlocation);
|
|
|
|
var
|
|
swapl : tlocation;
|
|
|
|
begin
|
|
swapl := destloc;
|
|
destloc := sourceloc;
|
|
sourceloc := swapl;
|
|
end;
|
|
|
|
|
|
function get_ordinal_value(p : ptree) : longint;
|
|
begin
|
|
if p^.treetype=ordconstn then
|
|
get_ordinal_value:=p^.value
|
|
else
|
|
begin
|
|
Message(type_e_ordinal_expr_expected);
|
|
get_ordinal_value:=0;
|
|
end;
|
|
end;
|
|
|
|
|
|
function is_constnode(p : ptree) : boolean;
|
|
begin
|
|
is_constnode:=(p^.treetype in [ordconstn,realconstn,stringconstn,fixconstn,setconstn]);
|
|
end;
|
|
|
|
|
|
function is_constintnode(p : ptree) : boolean;
|
|
begin
|
|
is_constintnode:=(p^.treetype=ordconstn) and is_integer(p^.resulttype);
|
|
end;
|
|
|
|
|
|
function is_constcharnode(p : ptree) : boolean;
|
|
|
|
begin
|
|
is_constcharnode:=(p^.treetype=ordconstn) and is_char(p^.resulttype);
|
|
end;
|
|
|
|
function is_constrealnode(p : ptree) : boolean;
|
|
|
|
begin
|
|
is_constrealnode:=(p^.treetype=realconstn);
|
|
end;
|
|
|
|
function is_constboolnode(p : ptree) : boolean;
|
|
|
|
begin
|
|
is_constboolnode:=(p^.treetype=ordconstn) and is_boolean(p^.resulttype);
|
|
end;
|
|
|
|
|
|
function is_constresourcestringnode(p : ptree) : boolean;
|
|
begin
|
|
is_constresourcestringnode:=(p^.treetype=loadn) and
|
|
(p^.symtableentry^.typ=constsym) and
|
|
(pconstsym(p^.symtableentry)^.consttyp=constresourcestring);
|
|
end;
|
|
|
|
|
|
function str_length(p : ptree) : longint;
|
|
|
|
begin
|
|
str_length:=p^.length;
|
|
end;
|
|
|
|
|
|
function is_emptyset(p : ptree):boolean;
|
|
{
|
|
return true if set s is empty
|
|
}
|
|
var
|
|
i : longint;
|
|
begin
|
|
i:=0;
|
|
if p^.treetype=setconstn then
|
|
begin
|
|
while (i<32) and (p^.value_set^[i]=0) do
|
|
inc(i);
|
|
end;
|
|
is_emptyset:=(i=32);
|
|
end;
|
|
|
|
|
|
{*****************************************************************************
|
|
Case Helpers
|
|
*****************************************************************************}
|
|
|
|
function case_count_labels(root : pcaserecord) : longint;
|
|
var
|
|
_l : longint;
|
|
|
|
procedure count(p : pcaserecord);
|
|
begin
|
|
inc(_l);
|
|
if assigned(p^.less) then
|
|
count(p^.less);
|
|
if assigned(p^.greater) then
|
|
count(p^.greater);
|
|
end;
|
|
|
|
begin
|
|
_l:=0;
|
|
count(root);
|
|
case_count_labels:=_l;
|
|
end;
|
|
|
|
|
|
function case_get_max(root : pcaserecord) : longint;
|
|
var
|
|
hp : pcaserecord;
|
|
begin
|
|
hp:=root;
|
|
while assigned(hp^.greater) do
|
|
hp:=hp^.greater;
|
|
case_get_max:=hp^._high;
|
|
end;
|
|
|
|
|
|
function case_get_min(root : pcaserecord) : longint;
|
|
var
|
|
hp : pcaserecord;
|
|
begin
|
|
hp:=root;
|
|
while assigned(hp^.less) do
|
|
hp:=hp^.less;
|
|
case_get_min:=hp^._low;
|
|
end;
|
|
|
|
{$ifdef newcg}
|
|
{$I node.inc}
|
|
{$endif newcg}
|
|
end.
|
|
{
|
|
$Log$
|
|
Revision 1.10 2000-09-27 18:14:31 florian
|
|
* fixed a lot of syntax errors in the n*.pas stuff
|
|
|
|
Revision 1.9 2000/09/24 15:06:32 peter
|
|
* use defines.inc
|
|
|
|
Revision 1.8 2000/08/27 16:11:55 peter
|
|
* moved some util functions from globals,cobjects to cutils
|
|
* splitted files into finput,fmodule
|
|
|
|
Revision 1.7 2000/08/17 12:03:48 florian
|
|
* fixed several problems with the int64 constants
|
|
|
|
Revision 1.6 2000/08/16 13:06:07 florian
|
|
+ support of 64 bit integer constants
|
|
|
|
Revision 1.5 2000/08/12 06:46:51 florian
|
|
+ case statement for int64/qword implemented
|
|
|
|
Revision 1.4 2000/08/06 19:39:28 peter
|
|
* default parameters working !
|
|
|
|
Revision 1.3 2000/08/04 22:00:52 peter
|
|
* merges from fixes
|
|
|
|
Revision 1.2 2000/07/13 11:32:52 michael
|
|
+ removed logs
|
|
} |