mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-26 18:43:42 +02:00
5605 lines
206 KiB
ObjectPascal
5605 lines
206 KiB
ObjectPascal
{
|
||
$Id$
|
||
Copyright (c) 1996-98 by Florian Klaempfl
|
||
|
||
This unit implements the first pass of the code generator
|
||
|
||
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.
|
||
|
||
****************************************************************************
|
||
}
|
||
|
||
{$ifdef tp}
|
||
{$F+}
|
||
{$endif tp}
|
||
unit pass_1;
|
||
|
||
interface
|
||
|
||
uses tree;
|
||
|
||
function do_firstpass(var p : ptree) : boolean;
|
||
|
||
implementation
|
||
|
||
uses
|
||
cobjects,verbose,comphook,systems,globals,
|
||
aasm,symtable,types,strings,hcodegen,files
|
||
{$ifdef i386}
|
||
,i386
|
||
,tgeni386
|
||
{$endif}
|
||
{$ifdef m68k}
|
||
,m68k
|
||
,tgen68k
|
||
{$endif}
|
||
{$ifdef UseBrowser}
|
||
,browser
|
||
{$endif UseBrowser}
|
||
;
|
||
|
||
{ firstcallparan without varspez
|
||
we don't count the ref }
|
||
const
|
||
count_ref : boolean = true;
|
||
|
||
procedure message(const t : tmsgconst);
|
||
|
||
var
|
||
olderrorcount : longint;
|
||
|
||
begin
|
||
if not(codegenerror) then
|
||
begin
|
||
olderrorcount:=status.errorcount;
|
||
verbose.Message(t);
|
||
codegenerror:=olderrorcount<>status.errorcount;
|
||
end;
|
||
end;
|
||
|
||
procedure message1(const t : tmsgconst;const s : string);
|
||
|
||
var
|
||
olderrorcount : longint;
|
||
|
||
begin
|
||
if not(codegenerror) then
|
||
begin
|
||
olderrorcount:=status.errorcount;
|
||
verbose.Message1(t,s);
|
||
codegenerror:=olderrorcount<>status.errorcount;
|
||
end;
|
||
end;
|
||
|
||
procedure message2(const t : tmsgconst;const s1,s2 : string);
|
||
|
||
var
|
||
olderrorcount : longint;
|
||
|
||
begin
|
||
if not(codegenerror) then
|
||
begin
|
||
olderrorcount:=status.errorcount;
|
||
verbose.Message2(t,s1,s2);
|
||
codegenerror:=olderrorcount<>status.errorcount;
|
||
end;
|
||
end;
|
||
|
||
procedure message3(const t : tmsgconst;const s1,s2,s3 : string);
|
||
|
||
var
|
||
olderrorcount : longint;
|
||
|
||
begin
|
||
if not(codegenerror) then
|
||
begin
|
||
olderrorcount:=status.errorcount;
|
||
verbose.Message3(t,s1,s2,s3);
|
||
codegenerror:=olderrorcount<>status.errorcount;
|
||
end;
|
||
end;
|
||
|
||
procedure firstpass(var p : ptree);forward;
|
||
|
||
{ marks an lvalue as "unregable" }
|
||
procedure make_not_regable(p : ptree);
|
||
|
||
begin
|
||
case p^.treetype of
|
||
typeconvn :
|
||
make_not_regable(p^.left);
|
||
loadn :
|
||
if p^.symtableentry^.typ=varsym then
|
||
pvarsym(p^.symtableentry)^.var_options :=
|
||
pvarsym(p^.symtableentry)^.var_options and not vo_regable;
|
||
end;
|
||
end;
|
||
|
||
|
||
procedure left_right_max(p : ptree);
|
||
begin
|
||
if assigned(p^.left) then
|
||
begin
|
||
if assigned(p^.right) then
|
||
begin
|
||
p^.registers32:=max(p^.left^.registers32,p^.right^.registers32);
|
||
p^.registersfpu:=max(p^.left^.registersfpu,p^.right^.registersfpu);
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=max(p^.left^.registersmmx,p^.right^.registersmmx);
|
||
{$endif SUPPORT_MMX}
|
||
end
|
||
else
|
||
begin
|
||
p^.registers32:=p^.left^.registers32;
|
||
p^.registersfpu:=p^.left^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=p^.left^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
{ calculates the needed registers for a binary operator }
|
||
procedure calcregisters(p : ptree;r32,fpu,mmx : word);
|
||
|
||
begin
|
||
left_right_max(p);
|
||
|
||
{ Only when the difference between the left and right registers < the
|
||
wanted registers allocate the amount of registers }
|
||
|
||
if assigned(p^.left) then
|
||
begin
|
||
if assigned(p^.right) then
|
||
begin
|
||
if (abs(p^.left^.registers32-p^.right^.registers32)<r32) then
|
||
inc(p^.registers32,r32);
|
||
if (abs(p^.left^.registersfpu-p^.right^.registersfpu)<fpu) then
|
||
inc(p^.registersfpu,fpu);
|
||
{$ifdef SUPPORT_MMX}
|
||
if (abs(p^.left^.registersmmx-p^.right^.registersmmx)<mmx) then
|
||
inc(p^.registersmmx,mmx);
|
||
{$endif SUPPORT_MMX}
|
||
end
|
||
else
|
||
begin
|
||
if (p^.left^.registers32<r32) then
|
||
inc(p^.registers32,r32);
|
||
if (p^.left^.registersfpu<fpu) then
|
||
inc(p^.registersfpu,fpu);
|
||
{$ifdef SUPPORT_MMX}
|
||
if (p^.left^.registersmmx<mmx) then
|
||
inc(p^.registersmmx,mmx);
|
||
{$endif SUPPORT_MMX}
|
||
end;
|
||
end;
|
||
|
||
{ error message, if more than 8 floating point }
|
||
{ registers are needed }
|
||
if p^.registersfpu>8 then
|
||
Message(cg_e_too_complex_expr);
|
||
end;
|
||
|
||
|
||
function both_rm(p : ptree) : boolean;
|
||
begin
|
||
both_rm:=(p^.left^.location.loc in [LOC_MEM,LOC_REFERENCE]) and
|
||
(p^.right^.location.loc in [LOC_MEM,LOC_REFERENCE]);
|
||
end;
|
||
|
||
|
||
function is_assignment_overloaded(from_def,to_def : pdef) : boolean;forward;
|
||
|
||
|
||
function isconvertable(def_from,def_to : pdef;
|
||
var doconv : tconverttype;fromtreetype : ttreetyp;
|
||
explicit : boolean) : boolean;
|
||
const
|
||
{ Tbasetype: uauto,uvoid,uchar,
|
||
u8bit,u16bit,u32bit,
|
||
s8bit,s16bit,s32,
|
||
bool8bit,bool16bit,boot32bit }
|
||
basedefconverts : array[tbasetype,tbasetype] of tconverttype =
|
||
{uauto}
|
||
((tc_not_possible,tc_not_possible,tc_not_possible,
|
||
tc_not_possible,tc_not_possible,tc_not_possible,
|
||
tc_not_possible,tc_not_possible,tc_not_possible,
|
||
tc_not_possible,tc_not_possible,tc_not_possible),
|
||
{uvoid}
|
||
(tc_not_possible,tc_not_possible,tc_not_possible,
|
||
tc_not_possible,tc_not_possible,tc_not_possible,
|
||
tc_not_possible,tc_not_possible,tc_not_possible,
|
||
tc_not_possible,tc_not_possible,tc_not_possible),
|
||
{uchar}
|
||
(tc_not_possible,tc_not_possible,tc_only_rangechecks32bit,
|
||
tc_not_possible,tc_not_possible,tc_not_possible,
|
||
tc_not_possible,tc_not_possible,tc_not_possible,
|
||
tc_not_possible,tc_not_possible,tc_not_possible),
|
||
{u8bit}
|
||
(tc_not_possible,tc_not_possible,tc_not_possible,
|
||
tc_only_rangechecks32bit,tc_u8bit_2_u16bit,tc_u8bit_2_u32bit,
|
||
tc_only_rangechecks32bit,tc_u8bit_2_s16bit,tc_u8bit_2_s32bit,
|
||
tc_int_2_bool,tc_int_2_bool,tc_int_2_bool),
|
||
{u16bit}
|
||
(tc_not_possible,tc_not_possible,tc_not_possible,
|
||
tc_u16bit_2_u8bit,tc_only_rangechecks32bit,tc_u16bit_2_u32bit,
|
||
tc_u16bit_2_s8bit,tc_only_rangechecks32bit,tc_u16bit_2_s32bit,
|
||
tc_int_2_bool,tc_int_2_bool,tc_int_2_bool),
|
||
{u32bit}
|
||
(tc_not_possible,tc_not_possible,tc_not_possible,
|
||
tc_u32bit_2_u8bit,tc_u32bit_2_u16bit,tc_only_rangechecks32bit,
|
||
tc_u32bit_2_s8bit,tc_u32bit_2_s16bit,tc_only_rangechecks32bit,
|
||
tc_int_2_bool,tc_int_2_bool,tc_int_2_bool),
|
||
{s8bit}
|
||
(tc_not_possible,tc_not_possible,tc_not_possible,
|
||
tc_only_rangechecks32bit,tc_s8bit_2_u16bit,tc_s8bit_2_u32bit,
|
||
tc_only_rangechecks32bit,tc_s8bit_2_s16bit,tc_s8bit_2_s32bit,
|
||
tc_int_2_bool,tc_int_2_bool,tc_int_2_bool),
|
||
{s16bit}
|
||
(tc_not_possible,tc_not_possible,tc_not_possible,
|
||
tc_s16bit_2_u8bit,tc_only_rangechecks32bit,tc_s16bit_2_u32bit,
|
||
tc_s16bit_2_s8bit,tc_only_rangechecks32bit,tc_s16bit_2_s32bit,
|
||
tc_int_2_bool,tc_int_2_bool,tc_int_2_bool),
|
||
{s32bit}
|
||
(tc_not_possible,tc_not_possible,tc_not_possible,
|
||
tc_s32bit_2_u8bit,tc_s32bit_2_u16bit,tc_only_rangechecks32bit,
|
||
tc_s32bit_2_s8bit,tc_s32bit_2_s16bit,tc_only_rangechecks32bit,
|
||
tc_int_2_bool,tc_int_2_bool,tc_int_2_bool),
|
||
{bool8bit}
|
||
(tc_not_possible,tc_not_possible,tc_not_possible,
|
||
tc_bool_2_int,tc_bool_2_int,tc_bool_2_int,
|
||
tc_bool_2_int,tc_bool_2_int,tc_bool_2_int,
|
||
tc_only_rangechecks32bit,tc_bool_2_int,tc_bool_2_int),
|
||
{bool16bit}
|
||
(tc_not_possible,tc_not_possible,tc_not_possible,
|
||
tc_bool_2_int,tc_bool_2_int,tc_bool_2_int,
|
||
tc_bool_2_int,tc_bool_2_int,tc_bool_2_int,
|
||
tc_bool_2_int,tc_only_rangechecks32bit,tc_bool_2_int),
|
||
{bool32bit}
|
||
(tc_not_possible,tc_not_possible,tc_not_possible,
|
||
tc_bool_2_int,tc_bool_2_int,tc_bool_2_int,
|
||
tc_bool_2_int,tc_bool_2_int,tc_bool_2_int,
|
||
tc_bool_2_int,tc_bool_2_int,tc_only_rangechecks32bit));
|
||
|
||
var
|
||
b : boolean;
|
||
hd1,hd2 : pdef;
|
||
begin
|
||
b:=false;
|
||
if (not assigned(def_from)) or (not assigned(def_to)) then
|
||
begin
|
||
isconvertable:=false;
|
||
exit;
|
||
end;
|
||
|
||
{ handle ord to ord first }
|
||
if (def_from^.deftype=orddef) and (def_to^.deftype=orddef) then
|
||
begin
|
||
doconv:=basedefconverts[porddef(def_from)^.typ,porddef(def_to)^.typ];
|
||
if doconv<>tc_not_possible then
|
||
b:=true;
|
||
end
|
||
else
|
||
|
||
if (def_from^.deftype=orddef) and (def_to^.deftype=floatdef) then
|
||
begin
|
||
if pfloatdef(def_to)^.typ=f32bit then
|
||
doconv:=tc_int_2_fix
|
||
else
|
||
doconv:=tc_int_2_real;
|
||
b:=true;
|
||
end
|
||
else
|
||
|
||
{ 2 float types ? }
|
||
if (def_from^.deftype=floatdef) and (def_to^.deftype=floatdef) then
|
||
begin
|
||
if pfloatdef(def_from)^.typ=pfloatdef(def_to)^.typ then
|
||
doconv:=tc_equal
|
||
else
|
||
begin
|
||
if pfloatdef(def_from)^.typ=f32bit then
|
||
doconv:=tc_fix_2_real
|
||
else if pfloatdef(def_to)^.typ=f32bit then
|
||
doconv:=tc_real_2_fix
|
||
else
|
||
doconv:=tc_real_2_real;
|
||
{ comp isn't a floating type }
|
||
{$ifdef i386}
|
||
if (pfloatdef(def_to)^.typ=s64bit) and
|
||
(pfloatdef(def_from)^.typ<>s64bit) and
|
||
not (explicit) then
|
||
Message(parser_w_convert_real_2_comp);
|
||
{$endif}
|
||
end;
|
||
b:=true;
|
||
end
|
||
else
|
||
|
||
{ enum to enum }
|
||
if (def_from^.deftype=enumdef) and (def_to^.deftype=enumdef) then
|
||
begin
|
||
if assigned(penumdef(def_from)^.basedef) then
|
||
hd1:=penumdef(def_from)^.basedef
|
||
else
|
||
hd1:=def_from;
|
||
if assigned(penumdef(def_to)^.basedef) then
|
||
hd2:=penumdef(def_to)^.basedef
|
||
else
|
||
hd2:=def_to;
|
||
b:=(hd1=hd2);
|
||
end
|
||
else
|
||
|
||
{ assignment overwritten ?? }
|
||
if is_assignment_overloaded(def_from,def_to) then
|
||
b:=true
|
||
else
|
||
|
||
if (def_from^.deftype=pointerdef) and (def_to^.deftype=arraydef) and
|
||
(parraydef(def_to)^.lowrange=0) and
|
||
is_equal(ppointerdef(def_from)^.definition,parraydef(def_to)^.definition) then
|
||
begin
|
||
doconv:=tc_pointer_to_array;
|
||
b:=true;
|
||
end
|
||
else
|
||
|
||
if (def_from^.deftype=arraydef) and (def_to^.deftype=pointerdef) and
|
||
(parraydef(def_from)^.lowrange=0) and
|
||
is_equal(parraydef(def_from)^.definition,ppointerdef(def_to)^.definition) then
|
||
begin
|
||
doconv:=tc_array_to_pointer;
|
||
b:=true;
|
||
end
|
||
else
|
||
|
||
{ typed files are all equal to the abstract file type
|
||
name TYPEDFILE in system.pp in is_equal in types.pas
|
||
the problem is that it sholud be also compatible to FILE
|
||
but this would leed to a problem for ASSIGN RESET and REWRITE
|
||
when trying to find the good overloaded function !!
|
||
so all file function are doubled in system.pp
|
||
this is not very beautiful !!}
|
||
if (def_from^.deftype=filedef) and (def_to^.deftype=filedef) and
|
||
(
|
||
(
|
||
(pfiledef(def_from)^.filetype = ft_typed) and
|
||
(pfiledef(def_to)^.filetype = ft_typed) and
|
||
(
|
||
(pfiledef(def_from)^.typed_as = pdef(voiddef)) or
|
||
(pfiledef(def_to)^.typed_as = pdef(voiddef))
|
||
)
|
||
) or
|
||
(
|
||
(
|
||
(pfiledef(def_from)^.filetype = ft_untyped) and
|
||
(pfiledef(def_to)^.filetype = ft_typed)
|
||
) or
|
||
(
|
||
(pfiledef(def_from)^.filetype = ft_typed) and
|
||
(pfiledef(def_to)^.filetype = ft_untyped)
|
||
)
|
||
)
|
||
) then
|
||
begin
|
||
doconv:=tc_equal;
|
||
b:=true;
|
||
end
|
||
else
|
||
|
||
{ object pascal objects }
|
||
if (def_from^.deftype=objectdef) and (def_to^.deftype=objectdef) {and
|
||
pobjectdef(def_from)^.isclass and pobjectdef(def_to)^.isclass }then
|
||
begin
|
||
doconv:=tc_equal;
|
||
b:=pobjectdef(def_from)^.isrelated(
|
||
pobjectdef(def_to));
|
||
end
|
||
else
|
||
{ class types and class reference type
|
||
can be assigned to void pointers }
|
||
if (((def_from^.deftype=objectdef) and
|
||
pobjectdef(def_from)^.isclass) or
|
||
(def_from^.deftype=classrefdef)
|
||
) and
|
||
(def_to^.deftype=pointerdef) and
|
||
(ppointerdef(def_to)^.definition^.deftype=orddef) and
|
||
(porddef(ppointerdef(def_to)^.definition)^.typ=uvoid) then
|
||
|
||
begin
|
||
doconv:=tc_equal;
|
||
b:=true;
|
||
end
|
||
else
|
||
|
||
{ class reference types }
|
||
if (def_from^.deftype=classrefdef) and (def_from^.deftype=classrefdef) then
|
||
begin
|
||
doconv:=tc_equal;
|
||
b:=pobjectdef(pclassrefdef(def_from)^.definition)^.isrelated(
|
||
pobjectdef(pclassrefdef(def_to)^.definition));
|
||
end
|
||
else
|
||
|
||
if (def_from^.deftype=pointerdef) and (def_to^.deftype=pointerdef) then
|
||
begin
|
||
{ child class pointer can be assigned to anchestor pointers }
|
||
if (
|
||
(ppointerdef(def_from)^.definition^.deftype=objectdef) and
|
||
(ppointerdef(def_to)^.definition^.deftype=objectdef) and
|
||
pobjectdef(ppointerdef(def_from)^.definition)^.isrelated(
|
||
pobjectdef(ppointerdef(def_to)^.definition))
|
||
) or
|
||
{ all pointers can be assigned to void-pointer }
|
||
is_equal(ppointerdef(def_to)^.definition,voiddef) or
|
||
{ in my opnion, is this not clean pascal }
|
||
{ well, but it's handy to use, it isn't ? (FK) }
|
||
is_equal(ppointerdef(def_from)^.definition,voiddef) then
|
||
begin
|
||
doconv:=tc_equal;
|
||
b:=true;
|
||
end
|
||
end
|
||
else
|
||
|
||
if (def_from^.deftype=stringdef) and (def_to^.deftype=stringdef) then
|
||
begin
|
||
doconv:=tc_string_to_string;
|
||
b:=true;
|
||
end
|
||
else
|
||
|
||
{ char to string}
|
||
if is_equal(def_from,cchardef) and (def_to^.deftype=stringdef) then
|
||
begin
|
||
doconv:=tc_char_to_string;
|
||
b:=true;
|
||
end
|
||
else
|
||
|
||
{ string constant to zero terminated string constant }
|
||
if (fromtreetype=stringconstn) and
|
||
((def_to^.deftype=pointerdef) and is_equal(Ppointerdef(def_to)^.definition,cchardef)) then
|
||
begin
|
||
doconv:=tc_cstring_charpointer;
|
||
b:=true;
|
||
end
|
||
else
|
||
|
||
{ array of char to string, the length check is done by the firstpass of this node }
|
||
if (def_from^.deftype=stringdef) and
|
||
((def_to^.deftype=arraydef) and is_equal(parraydef(def_to)^.definition,cchardef)) then
|
||
begin
|
||
doconv:=tc_string_chararray;
|
||
b:=true;
|
||
end
|
||
else
|
||
|
||
{ string to array of char, the length check is done by the firstpass of this node }
|
||
if ((def_from^.deftype=arraydef) and is_equal(parraydef(def_from)^.definition,cchardef)) and
|
||
(def_to^.deftype=stringdef) then
|
||
begin
|
||
doconv:=tc_chararray_2_string;
|
||
b:=true;
|
||
end
|
||
else
|
||
|
||
if (fromtreetype=ordconstn) and is_equal(def_from,cchardef) then
|
||
begin
|
||
if (def_to^.deftype=pointerdef) and
|
||
is_equal(ppointerdef(def_to)^.definition,cchardef) then
|
||
begin
|
||
doconv:=tc_cchar_charpointer;
|
||
b:=true;
|
||
end;
|
||
end
|
||
else
|
||
|
||
if (def_to^.deftype=procvardef) and (def_from^.deftype=procdef) then
|
||
begin
|
||
def_from^.deftype:=procvardef;
|
||
doconv:=tc_proc2procvar;
|
||
b:=is_equal(def_from,def_to);
|
||
def_from^.deftype:=procdef;
|
||
end
|
||
else
|
||
|
||
{ nil is compatible with class instances }
|
||
if (fromtreetype=niln) and (def_to^.deftype=objectdef)
|
||
and (pobjectdef(def_to)^.isclass) then
|
||
begin
|
||
doconv:=tc_equal;
|
||
b:=true;
|
||
end
|
||
else
|
||
|
||
{ nil is compatible with class references }
|
||
if (fromtreetype=niln) and (def_to^.deftype=classrefdef) then
|
||
begin
|
||
doconv:=tc_equal;
|
||
b:=true;
|
||
end
|
||
else
|
||
|
||
{ nil is compatible with procvars }
|
||
if (fromtreetype=niln) and (def_to^.deftype=procvardef) then
|
||
begin
|
||
doconv:=tc_equal;
|
||
b:=true;
|
||
end
|
||
else
|
||
|
||
{ nil is compatible with ansi- and wide strings }
|
||
if (fromtreetype=niln) and (def_to^.deftype=stringdef)
|
||
and (pstringdef(def_to)^.string_typ in [st_ansistring,st_widestring]) then
|
||
begin
|
||
doconv:=tc_equal;
|
||
b:=true;
|
||
end
|
||
else
|
||
{ ansi- and wide strings can be assigned to void pointers }
|
||
if (def_from^.deftype=stringdef) and
|
||
(pstringdef(def_from)^.string_typ in [st_ansistring,st_widestring]) and
|
||
(def_to^.deftype=pointerdef) and
|
||
(ppointerdef(def_to)^.definition^.deftype=orddef) and
|
||
(porddef(ppointerdef(def_to)^.definition)^.typ=uvoid) then
|
||
begin
|
||
doconv:=tc_equal;
|
||
b:=true;
|
||
end
|
||
else
|
||
{ ansistrings can be assigned to pchar }
|
||
if is_ansistring(def_from) and
|
||
(def_to^.deftype=pointerdef) and
|
||
(ppointerdef(def_to)^.definition^.deftype=orddef) and
|
||
(porddef(ppointerdef(def_to)^.definition)^.typ=uchar) then
|
||
begin
|
||
doconv:=tc_ansistring_2_pchar;
|
||
b:=true;
|
||
end
|
||
else
|
||
{ pchar can be assigned to ansistrings }
|
||
if ((def_from^.deftype=pointerdef) and
|
||
(ppointerdef(def_from)^.definition^.deftype=orddef) and
|
||
(porddef(ppointerdef(def_from)^.definition)^.typ=uchar)) and
|
||
is_ansistring(def_to) then
|
||
begin
|
||
doconv:=tc_pchar_2_ansistring;
|
||
b:=true;
|
||
end
|
||
else
|
||
|
||
{ procedure variable can be assigned to an void pointer }
|
||
{ Not anymore. Use the @ operator now.}
|
||
if not (cs_tp_compatible in aktmoduleswitches) then
|
||
begin
|
||
if (def_from^.deftype=procvardef) and
|
||
(def_to^.deftype=pointerdef) and
|
||
(ppointerdef(def_to)^.definition^.deftype=orddef) and
|
||
(porddef(ppointerdef(def_to)^.definition)^.typ=uvoid) then
|
||
begin
|
||
doconv:=tc_equal;
|
||
b:=true;
|
||
end;
|
||
end;
|
||
|
||
isconvertable:=b;
|
||
end;
|
||
|
||
|
||
procedure firsterror(var p : ptree);
|
||
|
||
begin
|
||
p^.error:=true;
|
||
codegenerror:=true;
|
||
p^.resulttype:=generrordef;
|
||
end;
|
||
|
||
procedure firstload(var p : ptree);
|
||
|
||
begin
|
||
p^.location.loc:=LOC_REFERENCE;
|
||
p^.registers32:=0;
|
||
p^.registersfpu:=0;
|
||
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=0;
|
||
{$endif SUPPORT_MMX}
|
||
clear_reference(p^.location.reference);
|
||
if p^.symtableentry^.typ=funcretsym then
|
||
begin
|
||
putnode(p);
|
||
p:=genzeronode(funcretn);
|
||
p^.funcretprocinfo:=pprocinfo(pfuncretsym(p^.symtableentry)^.funcretprocinfo);
|
||
p^.retdef:=pfuncretsym(p^.symtableentry)^.funcretdef;
|
||
firstpass(p);
|
||
exit;
|
||
end;
|
||
if p^.symtableentry^.typ=absolutesym then
|
||
begin
|
||
p^.resulttype:=pabsolutesym(p^.symtableentry)^.definition;
|
||
if pabsolutesym(p^.symtableentry)^.abstyp=tovar then
|
||
p^.symtableentry:=pabsolutesym(p^.symtableentry)^.ref;
|
||
p^.symtable:=p^.symtableentry^.owner;
|
||
p^.is_absolute:=true;
|
||
end;
|
||
case p^.symtableentry^.typ of
|
||
absolutesym :;
|
||
varsym :
|
||
begin
|
||
if not(p^.is_absolute) and (p^.resulttype=nil) then
|
||
p^.resulttype:=pvarsym(p^.symtableentry)^.definition;
|
||
if ((p^.symtable^.symtabletype=parasymtable) or
|
||
(p^.symtable^.symtabletype=localsymtable)) and
|
||
(lexlevel>p^.symtable^.symtablelevel) then
|
||
begin
|
||
{ sollte sich die Variable in einem anderen Stackframe }
|
||
{ befinden, so brauchen wir ein Register zum Dereferenceieren }
|
||
if (p^.symtable^.symtablelevel)>0 then
|
||
begin
|
||
p^.registers32:=1;
|
||
{ au<61>erdem kann sie nicht mehr in ein Register
|
||
geladen werden }
|
||
pvarsym(p^.symtableentry)^.var_options :=
|
||
pvarsym(p^.symtableentry)^.var_options and not vo_regable;
|
||
end;
|
||
end;
|
||
if (pvarsym(p^.symtableentry)^.varspez=vs_const) then
|
||
p^.location.loc:=LOC_MEM;
|
||
{ we need a register for call by reference parameters }
|
||
if (pvarsym(p^.symtableentry)^.varspez=vs_var) or
|
||
((pvarsym(p^.symtableentry)^.varspez=vs_const) and
|
||
dont_copy_const_param(pvarsym(p^.symtableentry)^.definition)
|
||
) or
|
||
{ call by value open arrays are also indirect addressed }
|
||
is_open_array(pvarsym(p^.symtableentry)^.definition) then
|
||
p^.registers32:=1;
|
||
if p^.symtable^.symtabletype=withsymtable then
|
||
p^.registers32:=1;
|
||
|
||
{ a class variable is a pointer !!!
|
||
yes, but we have to resolve the reference in an
|
||
appropriate tree node (FK)
|
||
|
||
if (pvarsym(p^.symtableentry)^.definition^.deftype=objectdef) and
|
||
((pobjectdef(pvarsym(p^.symtableentry)^.definition)^.options and oois_class)<>0) then
|
||
p^.registers32:=1;
|
||
}
|
||
|
||
{ count variable references }
|
||
|
||
if must_be_valid and p^.is_first then
|
||
begin
|
||
if pvarsym(p^.symtableentry)^.is_valid=2 then
|
||
if (assigned(pvarsym(p^.symtableentry)^.owner) and assigned(aktprocsym)
|
||
and (pvarsym(p^.symtableentry)^.owner = aktprocsym^.definition^.localst)) then
|
||
Message1(sym_n_uninitialized_local_variable,pvarsym(p^.symtableentry)^.name);
|
||
end;
|
||
if count_ref then
|
||
begin
|
||
if (p^.is_first) then
|
||
begin
|
||
if (pvarsym(p^.symtableentry)^.is_valid=2) then
|
||
pvarsym(p^.symtableentry)^.is_valid:=1;
|
||
p^.is_first:=false;
|
||
end;
|
||
end;
|
||
{ this will create problem with local var set by
|
||
under_procedures
|
||
if (assigned(pvarsym(p^.symtableentry)^.owner) and assigned(aktprocsym)
|
||
and ((pvarsym(p^.symtableentry)^.owner = aktprocsym^.definition^.localst)
|
||
or (pvarsym(p^.symtableentry)^.owner = aktprocsym^.definition^.localst))) then }
|
||
if t_times<1 then
|
||
inc(pvarsym(p^.symtableentry)^.refs)
|
||
else
|
||
inc(pvarsym(p^.symtableentry)^.refs,t_times);
|
||
end;
|
||
typedconstsym :
|
||
if not p^.is_absolute then
|
||
p^.resulttype:=ptypedconstsym(p^.symtableentry)^.definition;
|
||
procsym :
|
||
begin
|
||
if assigned(pprocsym(p^.symtableentry)^.definition^.nextoverloaded) then
|
||
Message(parser_e_no_overloaded_procvars);
|
||
p^.resulttype:=pprocsym(p^.symtableentry)^.definition;
|
||
end;
|
||
else internalerror(3);
|
||
end;
|
||
end;
|
||
|
||
|
||
procedure firstadd(var p : ptree);
|
||
|
||
procedure make_bool_equal_size(var p:ptree);
|
||
begin
|
||
if porddef(p^.left^.resulttype)^.typ>porddef(p^.right^.resulttype)^.typ then
|
||
begin
|
||
p^.right:=gentypeconvnode(p^.right,porddef(p^.left^.resulttype));
|
||
p^.right^.convtyp:=tc_bool_2_int;
|
||
p^.right^.explizit:=true;
|
||
firstpass(p^.right);
|
||
end
|
||
else
|
||
if porddef(p^.left^.resulttype)^.typ<porddef(p^.right^.resulttype)^.typ then
|
||
begin
|
||
p^.left:=gentypeconvnode(p^.left,porddef(p^.right^.resulttype));
|
||
p^.left^.convtyp:=tc_bool_2_int;
|
||
p^.left^.explizit:=true;
|
||
firstpass(p^.left);
|
||
end;
|
||
end;
|
||
|
||
var
|
||
t : ptree;
|
||
lt,rt : ttreetyp;
|
||
rv,lv : longint;
|
||
rvd,lvd : bestreal;
|
||
rd,ld : pdef;
|
||
tempdef : pdef;
|
||
concatstrings : boolean;
|
||
|
||
{ to evalute const sets }
|
||
resultset : pconstset;
|
||
i : longint;
|
||
b : boolean;
|
||
convdone : boolean;
|
||
{$ifndef UseAnsiString}
|
||
s1,s2:^string;
|
||
{$else UseAnsiString}
|
||
s1,s2 : pchar;
|
||
l1,l2 : longint;
|
||
{$endif UseAnsiString}
|
||
|
||
{ this totally forgets to set the pi_do_call flag !! }
|
||
label
|
||
no_overload;
|
||
|
||
begin
|
||
{ first do the two subtrees }
|
||
firstpass(p^.left);
|
||
firstpass(p^.right);
|
||
lt:=p^.left^.treetype;
|
||
rt:=p^.right^.treetype;
|
||
rd:=p^.right^.resulttype;
|
||
ld:=p^.left^.resulttype;
|
||
convdone:=false;
|
||
|
||
if codegenerror then
|
||
exit;
|
||
|
||
{ overloaded operator ? }
|
||
if (p^.treetype=starstarn) or
|
||
(ld^.deftype=recorddef) or
|
||
{ <> and = are defined for classes }
|
||
((ld^.deftype=objectdef) and
|
||
(not(pobjectdef(ld)^.isclass) or
|
||
not(p^.treetype in [equaln,unequaln])
|
||
)
|
||
) or
|
||
(rd^.deftype=recorddef) or
|
||
{ <> and = are defined for classes }
|
||
((rd^.deftype=objectdef) and
|
||
(not(pobjectdef(rd)^.isclass) or
|
||
not(p^.treetype in [equaln,unequaln])
|
||
)
|
||
) then
|
||
begin
|
||
{!!!!!!!!! handle paras }
|
||
case p^.treetype of
|
||
{ the nil as symtable signs firstcalln that this is
|
||
an overloaded operator }
|
||
addn:
|
||
t:=gencallnode(overloaded_operators[plus],nil);
|
||
subn:
|
||
t:=gencallnode(overloaded_operators[minus],nil);
|
||
muln:
|
||
t:=gencallnode(overloaded_operators[star],nil);
|
||
starstarn:
|
||
t:=gencallnode(overloaded_operators[starstar],nil);
|
||
slashn:
|
||
t:=gencallnode(overloaded_operators[slash],nil);
|
||
ltn:
|
||
t:=gencallnode(overloaded_operators[globals.lt],nil);
|
||
gtn:
|
||
t:=gencallnode(overloaded_operators[gt],nil);
|
||
lten:
|
||
t:=gencallnode(overloaded_operators[lte],nil);
|
||
gten:
|
||
t:=gencallnode(overloaded_operators[gte],nil);
|
||
equaln,unequaln :
|
||
t:=gencallnode(overloaded_operators[equal],nil);
|
||
else goto no_overload;
|
||
end;
|
||
{ we have to convert p^.left and p^.right into
|
||
callparanodes }
|
||
t^.left:=gencallparanode(p^.left,nil);
|
||
t^.left:=gencallparanode(p^.right,t^.left);
|
||
if t^.symtableprocentry=nil then
|
||
Message(parser_e_operator_not_overloaded);
|
||
if p^.treetype=unequaln then
|
||
t:=gensinglenode(notn,t);
|
||
firstpass(t);
|
||
putnode(p);
|
||
p:=t;
|
||
exit;
|
||
end;
|
||
no_overload:
|
||
{ compact consts }
|
||
|
||
{ convert int consts to real consts, if the }
|
||
{ other operand is a real const }
|
||
if (rt=realconstn) and is_constintnode(p^.left) then
|
||
begin
|
||
t:=genrealconstnode(p^.left^.value);
|
||
disposetree(p^.left);
|
||
p^.left:=t;
|
||
lt:=realconstn;
|
||
end;
|
||
if (lt=realconstn) and is_constintnode(p^.right) then
|
||
begin
|
||
t:=genrealconstnode(p^.right^.value);
|
||
disposetree(p^.right);
|
||
p^.right:=t;
|
||
rt:=realconstn;
|
||
end;
|
||
|
||
{ both are int constants ? }
|
||
if is_constintnode(p^.left) and is_constintnode(p^.right) then
|
||
begin
|
||
lv:=p^.left^.value;
|
||
rv:=p^.right^.value;
|
||
case p^.treetype of
|
||
addn : t:=genordinalconstnode(lv+rv,s32bitdef);
|
||
subn : t:=genordinalconstnode(lv-rv,s32bitdef);
|
||
muln : t:=genordinalconstnode(lv*rv,s32bitdef);
|
||
xorn : t:=genordinalconstnode(lv xor rv,s32bitdef);
|
||
orn : t:=genordinalconstnode(lv or rv,s32bitdef);
|
||
andn : t:=genordinalconstnode(lv and rv,s32bitdef);
|
||
ltn : t:=genordinalconstnode(ord(lv<rv),booldef);
|
||
lten : t:=genordinalconstnode(ord(lv<=rv),booldef);
|
||
gtn : t:=genordinalconstnode(ord(lv>rv),booldef);
|
||
gten : t:=genordinalconstnode(ord(lv>=rv),booldef);
|
||
equaln : t:=genordinalconstnode(ord(lv=rv),booldef);
|
||
unequaln : t:=genordinalconstnode(ord(lv<>rv),booldef);
|
||
slashn : begin
|
||
{ int/int becomes a real }
|
||
t:=genrealconstnode(int(lv)/int(rv));
|
||
firstpass(t);
|
||
end;
|
||
else
|
||
Message(sym_e_type_mismatch);
|
||
end;
|
||
disposetree(p);
|
||
firstpass(t);
|
||
p:=t;
|
||
exit;
|
||
end;
|
||
|
||
{ both real constants ? }
|
||
if (lt=realconstn) and (rt=realconstn) then
|
||
begin
|
||
lvd:=p^.left^.valued;
|
||
rvd:=p^.right^.valued;
|
||
case p^.treetype of
|
||
addn : t:=genrealconstnode(lvd+rvd);
|
||
subn : t:=genrealconstnode(lvd-rvd);
|
||
muln : t:=genrealconstnode(lvd*rvd);
|
||
caretn : t:=genrealconstnode(exp(ln(lvd)*rvd));
|
||
slashn : t:=genrealconstnode(lvd/rvd);
|
||
ltn : t:=genordinalconstnode(ord(lvd<rvd),booldef);
|
||
lten : t:=genordinalconstnode(ord(lvd<=rvd),booldef);
|
||
gtn : t:=genordinalconstnode(ord(lvd>rvd),booldef);
|
||
gten : t:=genordinalconstnode(ord(lvd>=rvd),booldef);
|
||
equaln : t:=genordinalconstnode(ord(lvd=rvd),booldef);
|
||
unequaln : t:=genordinalconstnode(ord(lvd<>rvd),booldef);
|
||
else
|
||
Message(sym_e_type_mismatch);
|
||
end;
|
||
disposetree(p);
|
||
p:=t;
|
||
firstpass(p);
|
||
exit;
|
||
end;
|
||
|
||
{ concating strings ? }
|
||
concatstrings:=false;
|
||
{$ifdef UseAnsiString}
|
||
s1:=nil;
|
||
s2:=nil;
|
||
{$else UseAnsiString}
|
||
new(s1);
|
||
new(s2);
|
||
{$endif UseAnsiString}
|
||
if (lt=ordconstn) and (rt=ordconstn) and
|
||
(ld^.deftype=orddef) and (porddef(ld)^.typ=uchar) and
|
||
(rd^.deftype=orddef) and (porddef(rd)^.typ=uchar) then
|
||
begin
|
||
{$ifdef UseAnsiString}
|
||
s1:=strpnew(char(byte(p^.left^.value)));
|
||
s2:=strpnew(char(byte(p^.right^.value)));
|
||
l1:=1;l2:=1;
|
||
{$else UseAnsiString}
|
||
s1^:=char(byte(p^.left^.value));
|
||
s2^:=char(byte(p^.right^.value));
|
||
concatstrings:=true;
|
||
{$endif UseAnsiString}
|
||
end
|
||
else
|
||
if (lt=stringconstn) and (rt=ordconstn) and
|
||
(rd^.deftype=orddef) and (porddef(rd)^.typ=uchar) then
|
||
begin
|
||
{$ifdef UseAnsiString}
|
||
{ here there is allways the damn #0 problem !! }
|
||
s1:=getpcharcopy(p^.left);
|
||
l1:=p^.left^.length;
|
||
s2:=strpnew(char(byte(p^.right^.value)));
|
||
l2:=1;
|
||
{$else UseAnsiString}
|
||
s1^:=p^.left^.values^;
|
||
s2^:=char(byte(p^.right^.value));
|
||
concatstrings:=true;
|
||
{$endif UseAnsiString}
|
||
end
|
||
else if (lt=ordconstn) and (rt=stringconstn) and
|
||
(ld^.deftype=orddef) and
|
||
(porddef(ld)^.typ=uchar) then
|
||
begin
|
||
{$ifdef UseAnsiString}
|
||
{ here there is allways the damn #0 problem !! }
|
||
s1:=strpnew(char(byte(p^.left^.value)));
|
||
l1:=1;
|
||
s2:=getpcharcopy(p^.right);
|
||
l2:=p^.right^.length;
|
||
{$else UseAnsiString}
|
||
s1^:=char(byte(p^.left^.value));
|
||
s2^:=p^.right^.values^;
|
||
concatstrings:=true;
|
||
{$endif UseAnsiString}
|
||
end
|
||
else if (lt=stringconstn) and (rt=stringconstn) then
|
||
begin
|
||
{$ifdef UseAnsiString}
|
||
s1:=getpcharcopy(p^.left);
|
||
l1:=p^.left^.length;
|
||
s2:=getpcharcopy(p^.right);
|
||
l2:=p^.right^.length;
|
||
concatstrings:=true;
|
||
{$else UseAnsiString}
|
||
s1^:=p^.left^.values^;
|
||
s2^:=p^.right^.values^;
|
||
concatstrings:=true;
|
||
{$endif UseAnsiString}
|
||
end;
|
||
|
||
{ I will need to translate all this to ansistrings !!! }
|
||
if concatstrings then
|
||
begin
|
||
case p^.treetype of
|
||
{$ifndef UseAnsiString}
|
||
addn : t:=genstringconstnode(s1^+s2^);
|
||
ltn : t:=genordinalconstnode(byte(s1^<s2^),booldef);
|
||
lten : t:=genordinalconstnode(byte(s1^<=s2^),booldef);
|
||
gtn : t:=genordinalconstnode(byte(s1^>s2^),booldef);
|
||
gten : t:=genordinalconstnode(byte(s1^>=s2^),booldef);
|
||
equaln : t:=genordinalconstnode(byte(s1^=s2^),booldef);
|
||
unequaln : t:=genordinalconstnode(byte(s1^<>s2^),booldef);
|
||
{$else UseAnsiString}
|
||
addn : t:=genpcharconstnode(
|
||
concatansistrings(s1,s2,l1,l2),l1+l2);
|
||
ltn : t:=genordinalconstnode(
|
||
byte(compareansistrings(s1,s2,l1,l2)<0),booldef);
|
||
lten : t:=genordinalconstnode(
|
||
byte(compareansistrings(s1,s2,l1,l2)<=0),booldef);
|
||
gtn : t:=genordinalconstnode(
|
||
byte(compareansistrings(s1,s2,l1,l2)>0),booldef);
|
||
gten : t:=genordinalconstnode(
|
||
byte(compareansistrings(s1,s2,l1,l2)>=0),booldef);
|
||
equaln : t:=genordinalconstnode(
|
||
byte(compareansistrings(s1,s2,l1,l2)=0),booldef);
|
||
unequaln : t:=genordinalconstnode(
|
||
byte(compareansistrings(s1,s2,l1,l2)<>0),booldef);
|
||
{$endif UseAnsiString}
|
||
end;
|
||
{$ifdef UseAnsiString}
|
||
ansistringdispose(s1,l1);
|
||
ansistringdispose(s2,l2);
|
||
{$else UseAnsiString}
|
||
dispose(s1);
|
||
dispose(s2);
|
||
{$endif UseAnsiString}
|
||
disposetree(p);
|
||
firstpass(t);
|
||
p:=t;
|
||
exit;
|
||
end;
|
||
{$ifdef UseAnsiString}
|
||
ansistringdispose(s1,l1);
|
||
ansistringdispose(s2,l2);
|
||
{$else UseAnsiString}
|
||
dispose(s1);
|
||
dispose(s2);
|
||
{$endif UseAnsiString}
|
||
|
||
{ if both are orddefs then check sub types }
|
||
if (ld^.deftype=orddef) and (rd^.deftype=orddef) then
|
||
begin
|
||
{ 2 booleans ? }
|
||
if (porddef(ld)^.typ in [bool8bit,bool16bit,bool32bit]) and
|
||
(porddef(rd)^.typ in [bool8bit,bool16bit,bool32bit]) then
|
||
begin
|
||
case p^.treetype of
|
||
andn,orn : begin
|
||
calcregisters(p,0,0,0);
|
||
p^.location.loc:=LOC_JUMP;
|
||
end;
|
||
unequaln,
|
||
equaln,xorn : begin
|
||
make_bool_equal_size(p);
|
||
calcregisters(p,1,0,0);
|
||
end
|
||
else
|
||
Message(sym_e_type_mismatch);
|
||
end;
|
||
convdone:=true;
|
||
end
|
||
else
|
||
{ Both are chars? only convert to strings for addn }
|
||
if (porddef(rd)^.typ=uchar) and (porddef(ld)^.typ=uchar) then
|
||
begin
|
||
if p^.treetype=addn then
|
||
begin
|
||
p^.left:=gentypeconvnode(p^.left,cstringdef);
|
||
firstpass(p^.left);
|
||
p^.right:=gentypeconvnode(p^.right,cstringdef);
|
||
firstpass(p^.right);
|
||
{ here we call STRCOPY }
|
||
procinfo.flags:=procinfo.flags or pi_do_call;
|
||
calcregisters(p,0,0,0);
|
||
p^.location.loc:=LOC_MEM;
|
||
end
|
||
else
|
||
calcregisters(p,1,0,0);
|
||
convdone:=true;
|
||
end;
|
||
end
|
||
else
|
||
|
||
{ is one of the sides a string ? }
|
||
if (ld^.deftype=stringdef) or (rd^.deftype=stringdef) then
|
||
begin
|
||
{ convert other side to a string, if not both site are strings,
|
||
the typeconv will put give an error if it's not possible }
|
||
if not((rd^.deftype=stringdef) and (ld^.deftype=stringdef)) then
|
||
begin
|
||
if ld^.deftype=stringdef then
|
||
p^.right:=gentypeconvnode(p^.right,cstringdef)
|
||
else
|
||
p^.left:=gentypeconvnode(p^.left,cstringdef);
|
||
firstpass(p^.left);
|
||
firstpass(p^.right);
|
||
end;
|
||
{ here we call STRCONCAT or STRCMP or STRCOPY }
|
||
procinfo.flags:=procinfo.flags or pi_do_call;
|
||
calcregisters(p,0,0,0);
|
||
p^.location.loc:=LOC_MEM;
|
||
convdone:=true;
|
||
end
|
||
else
|
||
|
||
{ left side a setdef ? }
|
||
if (ld^.deftype=setdef) then
|
||
begin
|
||
{ right site must also be a setdef, unless addn is used }
|
||
if not(p^.treetype in [subn,symdifn,addn,muln,equaln,unequaln]) or
|
||
((rd^.deftype<>setdef) and (p^.treetype<>addn)) then
|
||
Message(sym_e_type_mismatch);
|
||
|
||
if ((rd^.deftype=setdef) and not(is_equal(rd,ld))) and
|
||
not((rt=setelementn) and is_equal(psetdef(ld)^.setof,rd)) then
|
||
Message(sym_e_set_element_are_not_comp);
|
||
|
||
{ ranges require normsets }
|
||
if (psetdef(ld)^.settype=smallset) and
|
||
(rt=setelementn) and
|
||
assigned(p^.right^.right) then
|
||
begin
|
||
{ generate a temporary normset def }
|
||
tempdef:=new(psetdef,init(psetdef(ld)^.setof,255));
|
||
p^.left:=gentypeconvnode(p^.left,tempdef);
|
||
firstpass(p^.left);
|
||
dispose(tempdef,done);
|
||
ld:=p^.left^.resulttype;
|
||
end;
|
||
|
||
{ if the destination is not a smallset then insert a typeconv
|
||
which loads a smallset into a normal set }
|
||
if (psetdef(ld)^.settype<>smallset) and
|
||
(psetdef(rd)^.settype=smallset) then
|
||
begin
|
||
p^.right:=gentypeconvnode(p^.right,psetdef(p^.left^.resulttype));
|
||
firstpass(p^.right);
|
||
end;
|
||
|
||
{ do constant evalution }
|
||
if (p^.right^.treetype=setconstrn) and
|
||
(p^.left^.treetype=setconstrn) then
|
||
begin
|
||
new(resultset);
|
||
case p^.treetype of
|
||
addn : begin
|
||
for i:=0 to 31 do
|
||
resultset^[i]:=
|
||
p^.right^.constset^[i] or p^.left^.constset^[i];
|
||
t:=gensetconstruktnode(resultset,psetdef(ld));
|
||
end;
|
||
muln : begin
|
||
for i:=0 to 31 do
|
||
resultset^[i]:=
|
||
p^.right^.constset^[i] and p^.left^.constset^[i];
|
||
t:=gensetconstruktnode(resultset,psetdef(ld));
|
||
end;
|
||
subn : begin
|
||
for i:=0 to 31 do
|
||
resultset^[i]:=
|
||
p^.left^.constset^[i] and not(p^.right^.constset^[i]);
|
||
t:=gensetconstruktnode(resultset,psetdef(ld));
|
||
end;
|
||
symdifn : begin
|
||
for i:=0 to 31 do
|
||
resultset^[i]:=
|
||
p^.left^.constset^[i] xor p^.right^.constset^[i];
|
||
t:=gensetconstruktnode(resultset,psetdef(ld));
|
||
end;
|
||
unequaln : begin
|
||
b:=true;
|
||
for i:=0 to 31 do
|
||
if p^.right^.constset^[i]=p^.left^.constset^[i] then
|
||
begin
|
||
b:=false;
|
||
break;
|
||
end;
|
||
t:=genordinalconstnode(ord(b),booldef);
|
||
end;
|
||
equaln : begin
|
||
b:=true;
|
||
for i:=0 to 31 do
|
||
if p^.right^.constset^[i]<>p^.left^.constset^[i] then
|
||
begin
|
||
b:=false;
|
||
break;
|
||
end;
|
||
t:=genordinalconstnode(ord(b),booldef);
|
||
end;
|
||
end;
|
||
dispose(resultset);
|
||
disposetree(p);
|
||
p:=t;
|
||
firstpass(p);
|
||
exit;
|
||
end
|
||
else
|
||
if psetdef(ld)^.settype=smallset then
|
||
begin
|
||
calcregisters(p,1,0,0);
|
||
p^.location.loc:=LOC_REGISTER;
|
||
end
|
||
else
|
||
begin
|
||
calcregisters(p,0,0,0);
|
||
{ here we call SET... }
|
||
procinfo.flags:=procinfo.flags or pi_do_call;
|
||
p^.location.loc:=LOC_MEM;
|
||
end;
|
||
convdone:=true;
|
||
end
|
||
else
|
||
|
||
{ is one a real float ? }
|
||
if (rd^.deftype=floatdef) or (ld^.deftype=floatdef) then
|
||
begin
|
||
{ if one is a fixed, then convert to f32bit }
|
||
if ((rd^.deftype=floatdef) and (pfloatdef(rd)^.typ=f32bit)) or
|
||
((ld^.deftype=floatdef) and (pfloatdef(ld)^.typ=f32bit)) then
|
||
begin
|
||
if not(porddef(rd)^.typ in [u8bit,s8bit,u16bit,s16bit,s32bit,u32bit]) or (p^.treetype<>muln) then
|
||
p^.right:=gentypeconvnode(p^.right,s32fixeddef);
|
||
if not(porddef(rd)^.typ in [u8bit,s8bit,u16bit,s16bit,s32bit,u32bit]) or (p^.treetype<>muln) then
|
||
p^.left:=gentypeconvnode(p^.left,s32fixeddef);
|
||
firstpass(p^.left);
|
||
firstpass(p^.right);
|
||
calcregisters(p,1,0,0);
|
||
p^.location.loc:=LOC_REGISTER;
|
||
end
|
||
else
|
||
{ convert both to c64float }
|
||
begin
|
||
p^.right:=gentypeconvnode(p^.right,c64floatdef);
|
||
p^.left:=gentypeconvnode(p^.left,c64floatdef);
|
||
firstpass(p^.left);
|
||
firstpass(p^.right);
|
||
calcregisters(p,1,1,0);
|
||
p^.location.loc:=LOC_FPU;
|
||
end;
|
||
convdone:=true;
|
||
end
|
||
else
|
||
|
||
{ pointer comperation and subtraction }
|
||
if (rd^.deftype=pointerdef) and (ld^.deftype=pointerdef) then
|
||
begin
|
||
p^.location.loc:=LOC_REGISTER;
|
||
p^.right:=gentypeconvnode(p^.right,ld);
|
||
firstpass(p^.right);
|
||
calcregisters(p,1,0,0);
|
||
case p^.treetype of
|
||
equaln,unequaln : ;
|
||
ltn,lten,gtn,gten:
|
||
begin
|
||
if not(cs_extsyntax in aktmoduleswitches) then
|
||
Message(sym_e_type_mismatch);
|
||
end;
|
||
subn:
|
||
begin
|
||
if not(cs_extsyntax in aktmoduleswitches) then
|
||
Message(sym_e_type_mismatch);
|
||
p^.resulttype:=s32bitdef;
|
||
exit;
|
||
end;
|
||
else Message(sym_e_type_mismatch);
|
||
end;
|
||
convdone:=true;
|
||
end
|
||
else
|
||
|
||
if (rd^.deftype=objectdef) and (ld^.deftype=objectdef) and
|
||
pobjectdef(rd)^.isclass and pobjectdef(ld)^.isclass then
|
||
begin
|
||
p^.location.loc:=LOC_REGISTER;
|
||
if pobjectdef(rd)^.isrelated(pobjectdef(ld)) then
|
||
p^.right:=gentypeconvnode(p^.right,ld)
|
||
else
|
||
p^.left:=gentypeconvnode(p^.left,rd);
|
||
firstpass(p^.right);
|
||
firstpass(p^.left);
|
||
calcregisters(p,1,0,0);
|
||
case p^.treetype of
|
||
equaln,unequaln : ;
|
||
else Message(sym_e_type_mismatch);
|
||
end;
|
||
convdone:=true;
|
||
end
|
||
else
|
||
|
||
if (rd^.deftype=classrefdef) and (ld^.deftype=classrefdef) then
|
||
begin
|
||
p^.location.loc:=LOC_REGISTER;
|
||
if pobjectdef(pclassrefdef(rd)^.definition)^.isrelated(pobjectdef(
|
||
pclassrefdef(ld)^.definition)) then
|
||
p^.right:=gentypeconvnode(p^.right,ld)
|
||
else
|
||
p^.left:=gentypeconvnode(p^.left,rd);
|
||
firstpass(p^.right);
|
||
firstpass(p^.left);
|
||
calcregisters(p,1,0,0);
|
||
case p^.treetype of
|
||
equaln,unequaln : ;
|
||
else Message(sym_e_type_mismatch);
|
||
end;
|
||
convdone:=true;
|
||
end
|
||
else
|
||
|
||
{ allows comperasion with nil pointer }
|
||
if (rd^.deftype=objectdef) and
|
||
pobjectdef(rd)^.isclass then
|
||
begin
|
||
p^.location.loc:=LOC_REGISTER;
|
||
p^.left:=gentypeconvnode(p^.left,rd);
|
||
firstpass(p^.left);
|
||
calcregisters(p,1,0,0);
|
||
case p^.treetype of
|
||
equaln,unequaln : ;
|
||
else Message(sym_e_type_mismatch);
|
||
end;
|
||
convdone:=true;
|
||
end
|
||
else
|
||
|
||
if (ld^.deftype=objectdef) and
|
||
pobjectdef(ld)^.isclass then
|
||
begin
|
||
p^.location.loc:=LOC_REGISTER;
|
||
p^.right:=gentypeconvnode(p^.right,ld);
|
||
firstpass(p^.right);
|
||
calcregisters(p,1,0,0);
|
||
case p^.treetype of
|
||
equaln,unequaln : ;
|
||
else Message(sym_e_type_mismatch);
|
||
end;
|
||
convdone:=true;
|
||
end
|
||
else
|
||
|
||
if (rd^.deftype=classrefdef) then
|
||
begin
|
||
p^.left:=gentypeconvnode(p^.left,rd);
|
||
firstpass(p^.left);
|
||
calcregisters(p,1,0,0);
|
||
case p^.treetype of
|
||
equaln,unequaln : ;
|
||
else Message(sym_e_type_mismatch);
|
||
end;
|
||
convdone:=true;
|
||
end
|
||
else
|
||
|
||
if (ld^.deftype=classrefdef) then
|
||
begin
|
||
p^.right:=gentypeconvnode(p^.right,ld);
|
||
firstpass(p^.right);
|
||
calcregisters(p,1,0,0);
|
||
case p^.treetype of
|
||
equaln,unequaln : ;
|
||
else
|
||
Message(sym_e_type_mismatch);
|
||
end;
|
||
convdone:=true;
|
||
end
|
||
else
|
||
|
||
if (rd^.deftype=pointerdef) then
|
||
begin
|
||
p^.location.loc:=LOC_REGISTER;
|
||
p^.left:=gentypeconvnode(p^.left,s32bitdef);
|
||
firstpass(p^.left);
|
||
calcregisters(p,1,0,0);
|
||
if p^.treetype=addn then
|
||
begin
|
||
if not(cs_extsyntax in aktmoduleswitches) then
|
||
Message(sym_e_type_mismatch);
|
||
end
|
||
else
|
||
Message(sym_e_type_mismatch);
|
||
convdone:=true;
|
||
end
|
||
else
|
||
|
||
if (ld^.deftype=pointerdef) then
|
||
begin
|
||
p^.location.loc:=LOC_REGISTER;
|
||
p^.right:=gentypeconvnode(p^.right,s32bitdef);
|
||
firstpass(p^.right);
|
||
calcregisters(p,1,0,0);
|
||
case p^.treetype of
|
||
addn,subn : if not(cs_extsyntax in aktmoduleswitches) then
|
||
Message(sym_e_type_mismatch);
|
||
else
|
||
Message(sym_e_type_mismatch);
|
||
end;
|
||
convdone:=true;
|
||
end
|
||
else
|
||
|
||
if (rd^.deftype=procvardef) and (ld^.deftype=procvardef) and is_equal(rd,ld) then
|
||
begin
|
||
calcregisters(p,1,0,0);
|
||
p^.location.loc:=LOC_REGISTER;
|
||
case p^.treetype of
|
||
equaln,unequaln : ;
|
||
else
|
||
Message(sym_e_type_mismatch);
|
||
end;
|
||
convdone:=true;
|
||
end
|
||
else
|
||
|
||
{$ifdef SUPPORT_MMX}
|
||
if (cs_mmx in aktlocalswitches) and is_mmx_able_array(ld) and
|
||
is_mmx_able_array(rd) and is_equal(ld,rd) then
|
||
begin
|
||
firstpass(p^.right);
|
||
firstpass(p^.left);
|
||
case p^.treetype of
|
||
addn,subn,xorn,orn,andn:
|
||
;
|
||
{ mul is a little bit restricted }
|
||
muln:
|
||
if not(mmx_type(p^.left^.resulttype) in
|
||
[mmxu16bit,mmxs16bit,mmxfixed16]) then
|
||
Message(sym_e_type_mismatch);
|
||
else
|
||
Message(sym_e_type_mismatch);
|
||
end;
|
||
p^.location.loc:=LOC_MMXREGISTER;
|
||
calcregisters(p,0,0,1);
|
||
convdone:=true;
|
||
end
|
||
else
|
||
{$endif SUPPORT_MMX}
|
||
|
||
if (ld^.deftype=enumdef) and (rd^.deftype=enumdef) and (is_equal(ld,rd)) then
|
||
begin
|
||
calcregisters(p,1,0,0);
|
||
case p^.treetype of
|
||
equaln,unequaln,
|
||
ltn,lten,gtn,gten : ;
|
||
else Message(sym_e_type_mismatch);
|
||
end;
|
||
convdone:=true;
|
||
end;
|
||
|
||
{ the general solution is to convert to 32 bit int }
|
||
if not convdone then
|
||
begin
|
||
{ but an int/int gives real/real! }
|
||
if p^.treetype=slashn then
|
||
begin
|
||
Message(parser_w_use_int_div_int_op);
|
||
p^.right:=gentypeconvnode(p^.right,c64floatdef);
|
||
p^.left:=gentypeconvnode(p^.left,c64floatdef);
|
||
firstpass(p^.left);
|
||
firstpass(p^.right);
|
||
{ maybe we need an integer register to save }
|
||
{ a reference }
|
||
if ((p^.left^.location.loc<>LOC_FPU) or
|
||
(p^.right^.location.loc<>LOC_FPU)) and
|
||
(p^.left^.registers32=p^.right^.registers32) then
|
||
calcregisters(p,1,1,0)
|
||
else
|
||
calcregisters(p,0,1,0);
|
||
p^.location.loc:=LOC_FPU;
|
||
end
|
||
else
|
||
begin
|
||
p^.right:=gentypeconvnode(p^.right,s32bitdef);
|
||
p^.left:=gentypeconvnode(p^.left,s32bitdef);
|
||
firstpass(p^.left);
|
||
firstpass(p^.right);
|
||
calcregisters(p,1,0,0);
|
||
p^.location.loc:=LOC_REGISTER;
|
||
end;
|
||
end;
|
||
|
||
if codegenerror then
|
||
exit;
|
||
|
||
{ determines result type for comparions }
|
||
{ here the is a problem with multiple passes }
|
||
{ example length(s)+1 gets internal 'longint' type first }
|
||
{ if it is a arg it is converted to 'LONGINT' }
|
||
{ but a second first pass will reset this to 'longint' }
|
||
case p^.treetype of
|
||
ltn,lten,gtn,gten,equaln,unequaln:
|
||
begin
|
||
if not assigned(p^.resulttype) then
|
||
p^.resulttype:=booldef;
|
||
p^.location.loc:=LOC_FLAGS;
|
||
end;
|
||
xorn:
|
||
begin
|
||
if not assigned(p^.resulttype) then
|
||
p^.resulttype:=p^.left^.resulttype;
|
||
p^.location.loc:=LOC_REGISTER;
|
||
end;
|
||
addn:
|
||
begin
|
||
{ the result of a string addition is a string of length 255 }
|
||
if (p^.left^.resulttype^.deftype=stringdef) or
|
||
(p^.right^.resulttype^.deftype=stringdef) then
|
||
begin
|
||
{$ifndef UseAnsiString}
|
||
if not assigned(p^.resulttype) then
|
||
p^.resulttype:=cstringdef
|
||
{$else UseAnsiString}
|
||
if is_ansistring(p^.left^.resulttype) or
|
||
is_ansistring(p^.right^.resulttype) then
|
||
p^.resulttype:=cansistringdef
|
||
else
|
||
p^.resulttype:=cstringdef;
|
||
{$endif UseAnsiString}
|
||
end
|
||
else
|
||
if not assigned(p^.resulttype) then
|
||
p^.resulttype:=p^.left^.resulttype;
|
||
end;
|
||
else if not assigned(p^.resulttype) then
|
||
p^.resulttype:=p^.left^.resulttype;
|
||
end;
|
||
end;
|
||
|
||
procedure firstmoddiv(var p : ptree);
|
||
|
||
var
|
||
t : ptree;
|
||
{power : longint; }
|
||
|
||
begin
|
||
firstpass(p^.left);
|
||
firstpass(p^.right);
|
||
|
||
if codegenerror then
|
||
exit;
|
||
|
||
if is_constintnode(p^.left) and is_constintnode(p^.right) then
|
||
begin
|
||
case p^.treetype of
|
||
modn : t:=genordinalconstnode(p^.left^.value mod p^.right^.value,s32bitdef);
|
||
divn : t:=genordinalconstnode(p^.left^.value div p^.right^.value,s32bitdef);
|
||
end;
|
||
disposetree(p);
|
||
firstpass(t);
|
||
p:=t;
|
||
exit;
|
||
end;
|
||
{ !!!!!! u32bit }
|
||
p^.right:=gentypeconvnode(p^.right,s32bitdef);
|
||
p^.left:=gentypeconvnode(p^.left,s32bitdef);
|
||
firstpass(p^.left);
|
||
firstpass(p^.right);
|
||
|
||
if codegenerror then
|
||
exit;
|
||
|
||
left_right_max(p);
|
||
if p^.left^.registers32<=p^.right^.registers32 then
|
||
inc(p^.registers32);
|
||
|
||
p^.resulttype:=s32bitdef;
|
||
p^.location.loc:=LOC_REGISTER;
|
||
end;
|
||
|
||
procedure firstshlshr(var p : ptree);
|
||
|
||
var
|
||
t : ptree;
|
||
|
||
begin
|
||
firstpass(p^.left);
|
||
firstpass(p^.right);
|
||
|
||
if codegenerror then
|
||
exit;
|
||
|
||
if is_constintnode(p^.left) and is_constintnode(p^.right) then
|
||
begin
|
||
case p^.treetype of
|
||
shrn : t:=genordinalconstnode(p^.left^.value shr p^.right^.value,s32bitdef);
|
||
shln : t:=genordinalconstnode(p^.left^.value shl p^.right^.value,s32bitdef);
|
||
end;
|
||
disposetree(p);
|
||
firstpass(t);
|
||
p:=t;
|
||
exit;
|
||
end;
|
||
p^.right:=gentypeconvnode(p^.right,s32bitdef);
|
||
p^.left:=gentypeconvnode(p^.left,s32bitdef);
|
||
firstpass(p^.left);
|
||
firstpass(p^.right);
|
||
|
||
if codegenerror then
|
||
exit;
|
||
|
||
calcregisters(p,2,0,0);
|
||
{
|
||
p^.registers32:=p^.left^.registers32;
|
||
|
||
if p^.registers32<p^.right^.registers32 then
|
||
p^.registers32:=p^.right^.registers32;
|
||
if p^.registers32<1 then p^.registers32:=1;
|
||
}
|
||
p^.resulttype:=s32bitdef;
|
||
p^.location.loc:=LOC_REGISTER;
|
||
end;
|
||
|
||
procedure firstrealconst(var p : ptree);
|
||
|
||
begin
|
||
p^.location.loc:=LOC_MEM;
|
||
end;
|
||
|
||
procedure firstfixconst(var p : ptree);
|
||
|
||
begin
|
||
p^.location.loc:=LOC_MEM;
|
||
end;
|
||
|
||
procedure firstordconst(var p : ptree);
|
||
|
||
begin
|
||
p^.location.loc:=LOC_MEM;
|
||
end;
|
||
|
||
procedure firstniln(var p : ptree);
|
||
|
||
begin
|
||
p^.resulttype:=voidpointerdef;
|
||
p^.location.loc:=LOC_MEM;
|
||
end;
|
||
|
||
procedure firststringconst(var p : ptree);
|
||
|
||
begin
|
||
{why this !!! lost of dummy type definitions
|
||
one per const string !!!
|
||
p^.resulttype:=new(pstringdef,init(length(p^.values^)));}
|
||
if cs_ansistrings in aktlocalswitches then
|
||
p^.resulttype:=cansistringdef
|
||
else
|
||
p^.resulttype:=cstringdef;
|
||
p^.location.loc:=LOC_MEM;
|
||
end;
|
||
|
||
procedure firstumminus(var p : ptree);
|
||
|
||
var
|
||
t : ptree;
|
||
minusdef : pprocdef;
|
||
|
||
begin
|
||
firstpass(p^.left);
|
||
p^.registers32:=p^.left^.registers32;
|
||
p^.registersfpu:=p^.left^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=p^.left^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
p^.resulttype:=p^.left^.resulttype;
|
||
if codegenerror then
|
||
exit;
|
||
if is_constintnode(p^.left) then
|
||
begin
|
||
t:=genordinalconstnode(-p^.left^.value,s32bitdef);
|
||
disposetree(p);
|
||
firstpass(t);
|
||
p:=t;
|
||
exit;
|
||
end;
|
||
{ nasm can not cope with negativ reals !! }
|
||
if is_constrealnode(p^.left)
|
||
{$ifdef i386}
|
||
and not(aktoutputformat in [as_nasmcoff,as_nasmelf,as_nasmobj])
|
||
{$endif}
|
||
then
|
||
begin
|
||
t:=genrealconstnode(-p^.left^.valued);
|
||
disposetree(p);
|
||
firstpass(t);
|
||
p:=t;
|
||
exit;
|
||
end;
|
||
if (p^.left^.resulttype^.deftype=floatdef) then
|
||
begin
|
||
if pfloatdef(p^.left^.resulttype)^.typ=f32bit then
|
||
begin
|
||
if (p^.left^.location.loc<>LOC_REGISTER) and
|
||
(p^.registers32<1) then
|
||
p^.registers32:=1;
|
||
p^.location.loc:=LOC_REGISTER;
|
||
end
|
||
else
|
||
p^.location.loc:=LOC_FPU;
|
||
end
|
||
{$ifdef SUPPORT_MMX}
|
||
else if (cs_mmx in aktlocalswitches) and
|
||
is_mmx_able_array(p^.left^.resulttype) then
|
||
begin
|
||
if (p^.left^.location.loc<>LOC_MMXREGISTER) and
|
||
(p^.registersmmx<1) then
|
||
p^.registersmmx:=1;
|
||
{ if saturation is on, p^.left^.resulttype isn't
|
||
"mmx able" (FK)
|
||
if (cs_mmx_saturation in aktlocalswitches^) and
|
||
(porddef(parraydef(p^.resulttype)^.definition)^.typ in
|
||
[s32bit,u32bit]) then
|
||
Message(sym_e_type_mismatch);
|
||
}
|
||
end
|
||
{$endif SUPPORT_MMX}
|
||
else if (p^.left^.resulttype^.deftype=orddef) then
|
||
begin
|
||
p^.left:=gentypeconvnode(p^.left,s32bitdef);
|
||
firstpass(p^.left);
|
||
p^.registersfpu:=p^.left^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=p^.left^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
p^.registers32:=p^.left^.registers32;
|
||
if codegenerror then
|
||
exit;
|
||
if (p^.left^.location.loc<>LOC_REGISTER) and
|
||
(p^.registers32<1) then
|
||
p^.registers32:=1;
|
||
p^.location.loc:=LOC_REGISTER;
|
||
p^.resulttype:=p^.left^.resulttype;
|
||
end
|
||
else
|
||
begin
|
||
if assigned(overloaded_operators[minus]) then
|
||
minusdef:=overloaded_operators[minus]^.definition
|
||
else
|
||
minusdef:=nil;
|
||
while assigned(minusdef) do
|
||
begin
|
||
if (minusdef^.para1^.data=p^.left^.resulttype) and
|
||
(minusdef^.para1^.next=nil) then
|
||
begin
|
||
t:=gencallnode(overloaded_operators[minus],nil);
|
||
t^.left:=gencallparanode(p^.left,nil);
|
||
putnode(p);
|
||
p:=t;
|
||
firstpass(p);
|
||
exit;
|
||
end;
|
||
minusdef:=minusdef^.nextoverloaded;
|
||
end;
|
||
Message(sym_e_type_mismatch);
|
||
end;
|
||
end;
|
||
|
||
procedure firstaddr(var p : ptree);
|
||
|
||
var
|
||
hp : ptree;
|
||
hp2 : pdefcoll;
|
||
store_valid : boolean;
|
||
hp3 : pabstractprocdef;
|
||
|
||
begin
|
||
make_not_regable(p^.left);
|
||
if not(assigned(p^.resulttype)) then
|
||
begin
|
||
if p^.left^.treetype=calln then
|
||
begin
|
||
hp:=genloadnode(pvarsym(p^.left^.symtableprocentry),p^.left^.symtableproc);
|
||
{ result is a procedure variable }
|
||
{ No, to be TP compatible, you must return a pointer to
|
||
the procedure that is stored in the procvar.}
|
||
if not(cs_tp_compatible in aktmoduleswitches) then
|
||
begin
|
||
p^.resulttype:=new(pprocvardef,init);
|
||
|
||
{ it could also be a procvar, not only pprocsym ! }
|
||
if p^.left^.symtableprocentry^.typ=varsym then
|
||
hp3:=pabstractprocdef(pvarsym(p^.left^.symtableprocentry)^.definition)
|
||
else
|
||
hp3:=pabstractprocdef(pprocsym(p^.left^.symtableprocentry)^.definition);
|
||
|
||
pprocvardef(p^.resulttype)^.options:=hp3^.options;
|
||
pprocvardef(p^.resulttype)^.retdef:=hp3^.retdef;
|
||
|
||
hp2:=hp3^.para1;
|
||
while assigned(hp2) do
|
||
begin
|
||
pprocvardef(p^.resulttype)^.concatdef(hp2^.data,hp2^.paratyp);
|
||
hp2:=hp2^.next;
|
||
end;
|
||
end
|
||
else
|
||
p^.resulttype:=voidpointerdef;
|
||
|
||
disposetree(p^.left);
|
||
p^.left:=hp;
|
||
end
|
||
else
|
||
begin
|
||
if not(cs_typed_addresses in aktlocalswitches) then
|
||
p^.resulttype:=voidpointerdef
|
||
else p^.resulttype:=new(ppointerdef,init(p^.left^.resulttype));
|
||
end;
|
||
end;
|
||
store_valid:=must_be_valid;
|
||
must_be_valid:=false;
|
||
firstpass(p^.left);
|
||
must_be_valid:=store_valid;
|
||
if codegenerror then
|
||
exit;
|
||
|
||
{ we should allow loc_mem for @string }
|
||
if (p^.left^.location.loc<>LOC_REFERENCE) and
|
||
(p^.left^.location.loc<>LOC_MEM) then
|
||
Message(cg_e_illegal_expression);
|
||
|
||
p^.registers32:=p^.left^.registers32;
|
||
p^.registersfpu:=p^.left^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=p^.left^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
if p^.registers32<1 then
|
||
p^.registers32:=1;
|
||
p^.location.loc:=LOC_REGISTER;
|
||
end;
|
||
|
||
procedure firstdoubleaddr(var p : ptree);
|
||
|
||
begin
|
||
make_not_regable(p^.left);
|
||
firstpass(p^.left);
|
||
if p^.resulttype=nil then
|
||
p^.resulttype:=voidpointerdef;
|
||
if (p^.left^.resulttype^.deftype)<>procvardef then
|
||
Message(cg_e_illegal_expression);
|
||
|
||
if codegenerror then
|
||
exit;
|
||
|
||
if (p^.left^.location.loc<>LOC_REFERENCE) then
|
||
Message(cg_e_illegal_expression);
|
||
|
||
p^.registers32:=p^.left^.registers32;
|
||
p^.registersfpu:=p^.left^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=p^.left^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
if p^.registers32<1 then
|
||
p^.registers32:=1;
|
||
p^.location.loc:=LOC_REGISTER;
|
||
end;
|
||
|
||
procedure firstnot(var p : ptree);
|
||
|
||
var
|
||
t : ptree;
|
||
|
||
begin
|
||
firstpass(p^.left);
|
||
|
||
if codegenerror then
|
||
exit;
|
||
|
||
if (p^.left^.treetype=ordconstn) then
|
||
begin
|
||
t:=genordinalconstnode(not(p^.left^.value),p^.left^.resulttype);
|
||
disposetree(p);
|
||
firstpass(t);
|
||
p:=t;
|
||
exit;
|
||
end;
|
||
p^.resulttype:=p^.left^.resulttype;
|
||
p^.location.loc:=p^.left^.location.loc;
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=p^.left^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
if is_equal(p^.resulttype,booldef) then
|
||
begin
|
||
p^.registers32:=p^.left^.registers32;
|
||
if ((p^.location.loc=LOC_REFERENCE) or
|
||
(p^.location.loc=LOC_CREGISTER)) and
|
||
(p^.registers32<1) then
|
||
p^.registers32:=1;
|
||
end
|
||
else
|
||
{$ifdef SUPPORT_MMX}
|
||
if (cs_mmx in aktlocalswitches) and
|
||
is_mmx_able_array(p^.left^.resulttype) then
|
||
begin
|
||
if (p^.left^.location.loc<>LOC_MMXREGISTER) and
|
||
(p^.registersmmx<1) then
|
||
p^.registersmmx:=1;
|
||
end
|
||
else
|
||
{$endif SUPPORT_MMX}
|
||
begin
|
||
p^.left:=gentypeconvnode(p^.left,s32bitdef);
|
||
firstpass(p^.left);
|
||
|
||
if codegenerror then
|
||
exit;
|
||
|
||
p^.resulttype:=p^.left^.resulttype;
|
||
p^.registers32:=p^.left^.registers32;
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=p^.left^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
|
||
if (p^.left^.location.loc<>LOC_REGISTER) and
|
||
(p^.registers32<1) then
|
||
p^.registers32:=1;
|
||
p^.location.loc:=LOC_REGISTER;
|
||
end;
|
||
p^.registersfpu:=p^.left^.registersfpu;
|
||
end;
|
||
|
||
procedure firstnothing(var p : ptree);
|
||
|
||
begin
|
||
p^.resulttype:=voiddef;
|
||
end;
|
||
|
||
procedure firstassignment(var p : ptree);
|
||
|
||
var
|
||
store_valid : boolean;
|
||
hp : ptree;
|
||
|
||
begin
|
||
store_valid:=must_be_valid;
|
||
must_be_valid:=false;
|
||
|
||
firstpass(p^.left);
|
||
if codegenerror then
|
||
exit;
|
||
|
||
{ assignements to open arrays aren't allowed }
|
||
if is_open_array(p^.left^.resulttype) then
|
||
Message(sym_e_type_mismatch);
|
||
{ test if we can avoid copying string to temp
|
||
as in s:=s+...; (PM) }
|
||
{$ifdef dummyi386}
|
||
if ((p^.right^.treetype=addn) or (p^.right^.treetype=subn)) and
|
||
equal_trees(p^.left,p^.right^.left) and
|
||
(ret_in_acc(p^.left^.resulttype)) and
|
||
(not cs_rangechecking in aktmoduleswitches^) then
|
||
begin
|
||
disposetree(p^.right^.left);
|
||
hp:=p^.right;
|
||
p^.right:=p^.right^.right;
|
||
if hp^.treetype=addn then
|
||
p^.assigntyp:=at_plus
|
||
else
|
||
p^.assigntyp:=at_minus;
|
||
putnode(hp);
|
||
end;
|
||
if p^.assigntyp<>at_normal then
|
||
begin
|
||
{ for fpu type there is no faster way }
|
||
if is_fpu(p^.left^.resulttype) then
|
||
case p^.assigntyp of
|
||
at_plus : p^.right:=gennode(addn,getcopy(p^.left),p^.right);
|
||
at_minus : p^.right:=gennode(subn,getcopy(p^.left),p^.right);
|
||
at_star : p^.right:=gennode(muln,getcopy(p^.left),p^.right);
|
||
at_slash : p^.right:=gennode(slashn,getcopy(p^.left),p^.right);
|
||
end;
|
||
end;
|
||
{$endif i386}
|
||
must_be_valid:=true;
|
||
firstpass(p^.right);
|
||
must_be_valid:=store_valid;
|
||
if codegenerror then
|
||
exit;
|
||
|
||
{ some string functions don't need conversion, so treat them separatly }
|
||
|
||
if is_shortstring(p^.left^.resulttype) and (assigned(p^.right^.resulttype)) then
|
||
begin
|
||
if not ((p^.right^.resulttype^.deftype=stringdef) or
|
||
((p^.right^.resulttype^.deftype=orddef) and (porddef(p^.right^.resulttype)^.typ=uchar))) then
|
||
begin
|
||
p^.right:=gentypeconvnode(p^.right,p^.left^.resulttype);
|
||
firstpass(p^.right);
|
||
if codegenerror then
|
||
exit;
|
||
end;
|
||
{ we call STRCOPY }
|
||
procinfo.flags:=procinfo.flags or pi_do_call;
|
||
hp:=p^.right;
|
||
{ test for s:=s+anything ... }
|
||
{ the problem is for
|
||
s:=s+s+s;
|
||
this is broken here !! }
|
||
{ while hp^.treetype=addn do hp:=hp^.left;
|
||
if equal_trees(p^.left,hp) then
|
||
begin
|
||
p^.concat_string:=true;
|
||
hp:=p^.right;
|
||
while hp^.treetype=addn do
|
||
begin
|
||
hp^.use_strconcat:=true;
|
||
hp:=hp^.left;
|
||
end;
|
||
end; }
|
||
end
|
||
else
|
||
begin
|
||
if (p^.right^.treetype=realconstn) then
|
||
begin
|
||
if p^.left^.resulttype^.deftype=floatdef then
|
||
begin
|
||
case pfloatdef(p^.left^.resulttype)^.typ of
|
||
s32real : p^.right^.realtyp:=ait_real_32bit;
|
||
s64real : p^.right^.realtyp:=ait_real_64bit;
|
||
s80real : p^.right^.realtyp:=ait_real_extended;
|
||
{ what about f32bit and s64bit }
|
||
else
|
||
begin
|
||
p^.right:=gentypeconvnode(p^.right,p^.left^.resulttype);
|
||
|
||
{ nochmal firstpass wegen der Typkonvertierung aufrufen }
|
||
firstpass(p^.right);
|
||
|
||
if codegenerror then
|
||
exit;
|
||
end;
|
||
end;
|
||
end;
|
||
end
|
||
else
|
||
begin
|
||
p^.right:=gentypeconvnode(p^.right,p^.left^.resulttype);
|
||
firstpass(p^.right);
|
||
if codegenerror then
|
||
exit;
|
||
end;
|
||
end;
|
||
|
||
p^.resulttype:=voiddef;
|
||
{
|
||
p^.registers32:=max(p^.left^.registers32,p^.right^.registers32);
|
||
p^.registersfpu:=max(p^.left^.registersfpu,p^.right^.registersfpu);
|
||
}
|
||
p^.registers32:=p^.left^.registers32+p^.right^.registers32;
|
||
p^.registersfpu:=max(p^.left^.registersfpu,p^.right^.registersfpu);
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=max(p^.left^.registersmmx,p^.right^.registersmmx);
|
||
{$endif SUPPORT_MMX}
|
||
end;
|
||
|
||
procedure firstlr(var p : ptree);
|
||
|
||
begin
|
||
firstpass(p^.left);
|
||
firstpass(p^.right);
|
||
end;
|
||
|
||
procedure firstderef(var p : ptree);
|
||
|
||
begin
|
||
firstpass(p^.left);
|
||
if codegenerror then
|
||
begin
|
||
p^.resulttype:=generrordef;
|
||
exit;
|
||
end;
|
||
|
||
p^.registers32:=max(p^.left^.registers32,1);
|
||
p^.registersfpu:=p^.left^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=p^.left^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
|
||
if p^.left^.resulttype^.deftype<>pointerdef then
|
||
Message(cg_e_invalid_qualifier);
|
||
|
||
p^.resulttype:=ppointerdef(p^.left^.resulttype)^.definition;
|
||
p^.location.loc:=LOC_REFERENCE;
|
||
end;
|
||
|
||
procedure firstrange(var p : ptree);
|
||
|
||
var
|
||
ct : tconverttype;
|
||
|
||
begin
|
||
firstpass(p^.left);
|
||
firstpass(p^.right);
|
||
if codegenerror then
|
||
exit;
|
||
{ both types must be compatible }
|
||
if not(is_equal(p^.left^.resulttype,p^.right^.resulttype)) and
|
||
not(isconvertable(p^.left^.resulttype,p^.right^.resulttype,ct,ordconstn,false)) then
|
||
Message(sym_e_type_mismatch);
|
||
{ Check if only when its a constant set }
|
||
if (p^.left^.treetype=ordconstn) and (p^.right^.treetype=ordconstn) then
|
||
begin
|
||
{ upper limit must be greater or equal than lower limit }
|
||
{ not if u32bit }
|
||
if (p^.left^.value>p^.right^.value) and
|
||
(( p^.left^.value<0) or (p^.right^.value>=0)) then
|
||
Message(cg_e_upper_lower_than_lower);
|
||
end;
|
||
left_right_max(p);
|
||
p^.resulttype:=p^.left^.resulttype;
|
||
set_location(p^.location,p^.left^.location);
|
||
end;
|
||
|
||
|
||
procedure firstvecn(var p : ptree);
|
||
|
||
var
|
||
harr : pdef;
|
||
ct : tconverttype;
|
||
|
||
|
||
begin
|
||
firstpass(p^.left);
|
||
firstpass(p^.right);
|
||
if codegenerror then
|
||
exit;
|
||
|
||
{ range check only for arrays }
|
||
if (p^.left^.resulttype^.deftype=arraydef) then
|
||
begin
|
||
if not(isconvertable(p^.right^.resulttype,
|
||
parraydef(p^.left^.resulttype)^.rangedef,
|
||
ct,ordconstn,false)) and
|
||
not(is_equal(p^.right^.resulttype,
|
||
parraydef(p^.left^.resulttype)^.rangedef)) then
|
||
Message(sym_e_type_mismatch);
|
||
end;
|
||
{ Never convert a boolean or a char !}
|
||
{ maybe type conversion }
|
||
if (p^.right^.resulttype^.deftype<>enumdef) and
|
||
not ((p^.right^.resulttype^.deftype=orddef) and
|
||
(Porddef(p^.right^.resulttype)^.typ in [bool8bit,bool16bit,bool32bit,uchar])) then
|
||
begin
|
||
p^.right:=gentypeconvnode(p^.right,s32bitdef);
|
||
{ once more firstpass }
|
||
{?? It's better to only firstpass when the tree has
|
||
changed, isn't it ?}
|
||
firstpass(p^.right);
|
||
end;
|
||
if codegenerror then
|
||
exit;
|
||
|
||
{ determine return type }
|
||
if not assigned(p^.resulttype) then
|
||
if p^.left^.resulttype^.deftype=arraydef then
|
||
p^.resulttype:=parraydef(p^.left^.resulttype)^.definition
|
||
else if (p^.left^.resulttype^.deftype=pointerdef) then
|
||
begin
|
||
{ convert pointer to array }
|
||
harr:=new(parraydef,init(0,$7fffffff,s32bitdef));
|
||
parraydef(harr)^.definition:=ppointerdef(p^.left^.resulttype)^.definition;
|
||
p^.left:=gentypeconvnode(p^.left,harr);
|
||
firstpass(p^.left);
|
||
|
||
if codegenerror then
|
||
exit;
|
||
p^.resulttype:=parraydef(harr)^.definition
|
||
end
|
||
else if p^.left^.resulttype^.deftype=stringdef then
|
||
begin
|
||
{ indexed access to strings }
|
||
case pstringdef(p^.left^.resulttype)^.string_typ of
|
||
{
|
||
st_widestring : p^.resulttype:=cwchardef;
|
||
}
|
||
st_ansistring : p^.resulttype:=cchardef;
|
||
st_longstring : p^.resulttype:=cchardef;
|
||
st_shortstring : p^.resulttype:=cchardef;
|
||
end;
|
||
end
|
||
else
|
||
Message(sym_e_type_mismatch);
|
||
{ the register calculation is easy if a const index is used }
|
||
if p^.right^.treetype=ordconstn then
|
||
begin
|
||
p^.registers32:=p^.left^.registers32;
|
||
|
||
{ for ansi/wide strings, we need at least one register }
|
||
if is_ansistring(p^.left^.resulttype) or
|
||
is_widestring(p^.left^.resulttype) then
|
||
p^.registers32:=max(p^.registers32,1);
|
||
end
|
||
else
|
||
begin
|
||
{ this rules are suboptimal, but they should give }
|
||
{ good results }
|
||
p^.registers32:=max(p^.left^.registers32,p^.right^.registers32);
|
||
|
||
{ for ansi/wide strings, we need at least one register }
|
||
if is_ansistring(p^.left^.resulttype) or
|
||
is_widestring(p^.left^.resulttype) then
|
||
p^.registers32:=max(p^.registers32,1);
|
||
|
||
{ need we an extra register when doing the restore ? }
|
||
if (p^.left^.registers32<=p^.right^.registers32) and
|
||
{ only if the node needs less than 3 registers }
|
||
{ two for the right node and one for the }
|
||
{ left address }
|
||
(p^.registers32<3) then
|
||
inc(p^.registers32);
|
||
|
||
{ need we an extra register for the index ? }
|
||
if (p^.right^.location.loc<>LOC_REGISTER)
|
||
{ only if the right node doesn't need a register }
|
||
and (p^.right^.registers32<1) then
|
||
inc(p^.registers32);
|
||
|
||
{ not correct, but what works better ?
|
||
if p^.left^.registers32>0 then
|
||
p^.registers32:=max(p^.registers32,2)
|
||
else
|
||
min. one register
|
||
p^.registers32:=max(p^.registers32,1);
|
||
}
|
||
end;
|
||
p^.registersfpu:=max(p^.left^.registersfpu,p^.right^.registersfpu);
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=max(p^.left^.registersmmx,p^.right^.registersmmx);
|
||
{$endif SUPPORT_MMX}
|
||
p^.location.loc:=p^.left^.location.loc;
|
||
end;
|
||
|
||
type
|
||
tfirstconvproc = procedure(var p : ptree);
|
||
|
||
procedure first_bigger_smaller(var p : ptree);
|
||
|
||
begin
|
||
if (p^.left^.location.loc<>LOC_REGISTER) and (p^.registers32=0) then
|
||
p^.registers32:=1;
|
||
p^.location.loc:=LOC_REGISTER;
|
||
end;
|
||
|
||
procedure first_cstring_charpointer(var p : ptree);
|
||
|
||
begin
|
||
p^.registers32:=1;
|
||
p^.location.loc:=LOC_REGISTER;
|
||
end;
|
||
|
||
procedure first_string_chararray(var p : ptree);
|
||
|
||
begin
|
||
p^.registers32:=1;
|
||
p^.location.loc:=LOC_REGISTER;
|
||
end;
|
||
|
||
procedure first_string_string(var p : ptree);
|
||
|
||
begin
|
||
if pstringdef(p^.resulttype)^.string_typ<>
|
||
pstringdef(p^.left^.resulttype)^.string_typ then
|
||
begin
|
||
if p^.left^.treetype=stringconstn then
|
||
p^.left^.stringtype:=pstringdef(p^.resulttype)^.string_typ
|
||
else
|
||
procinfo.flags:=procinfo.flags or pi_do_call;
|
||
end;
|
||
{ for simplicity lets first keep all ansistrings
|
||
as LOC_MEM, could also become LOC_REGISTER }
|
||
p^.location.loc:=LOC_MEM;
|
||
end;
|
||
|
||
procedure first_char_to_string(var p : ptree);
|
||
|
||
var
|
||
hp : ptree;
|
||
|
||
begin
|
||
if p^.left^.treetype=ordconstn then
|
||
begin
|
||
hp:=genstringconstnode(chr(p^.left^.value));
|
||
firstpass(hp);
|
||
disposetree(p);
|
||
p:=hp;
|
||
end
|
||
else
|
||
p^.location.loc:=LOC_MEM;
|
||
end;
|
||
|
||
procedure first_nothing(var p : ptree);
|
||
|
||
begin
|
||
p^.location.loc:=LOC_MEM;
|
||
end;
|
||
|
||
procedure first_array_to_pointer(var p : ptree);
|
||
|
||
begin
|
||
if p^.registers32<1 then
|
||
p^.registers32:=1;
|
||
p^.location.loc:=LOC_REGISTER;
|
||
end;
|
||
|
||
procedure first_int_real(var p : ptree);
|
||
|
||
var t : ptree;
|
||
|
||
begin
|
||
if p^.left^.treetype=ordconstn then
|
||
begin
|
||
{ convert constants direct }
|
||
{ not because of type conversion }
|
||
t:=genrealconstnode(p^.left^.value);
|
||
{ do a first pass here
|
||
because firstpass of typeconv does
|
||
not redo it for left field !! }
|
||
firstpass(t);
|
||
{ the type can be something else than s64real !!}
|
||
t:=gentypeconvnode(t,p^.resulttype);
|
||
firstpass(t);
|
||
disposetree(p);
|
||
p:=t;
|
||
exit;
|
||
end
|
||
else
|
||
begin
|
||
if p^.registersfpu<1 then
|
||
p^.registersfpu:=1;
|
||
p^.location.loc:=LOC_FPU;
|
||
end;
|
||
end;
|
||
|
||
procedure first_int_fix(var p : ptree);
|
||
|
||
begin
|
||
if p^.left^.treetype=ordconstn then
|
||
begin
|
||
{ convert constants direct }
|
||
p^.treetype:=fixconstn;
|
||
p^.valuef:=p^.left^.value shl 16;
|
||
p^.disposetyp:=dt_nothing;
|
||
disposetree(p^.left);
|
||
p^.location.loc:=LOC_MEM;
|
||
end
|
||
else
|
||
begin
|
||
if p^.registers32<1 then
|
||
p^.registers32:=1;
|
||
p^.location.loc:=LOC_REGISTER;
|
||
end;
|
||
end;
|
||
|
||
procedure first_real_fix(var p : ptree);
|
||
|
||
begin
|
||
if p^.left^.treetype=realconstn then
|
||
begin
|
||
{ convert constants direct }
|
||
p^.treetype:=fixconstn;
|
||
p^.valuef:=round(p^.left^.valued*65536);
|
||
p^.disposetyp:=dt_nothing;
|
||
disposetree(p^.left);
|
||
p^.location.loc:=LOC_MEM;
|
||
end
|
||
else
|
||
begin
|
||
{ at least one fpu and int register needed }
|
||
if p^.registers32<1 then
|
||
p^.registers32:=1;
|
||
if p^.registersfpu<1 then
|
||
p^.registersfpu:=1;
|
||
p^.location.loc:=LOC_REGISTER;
|
||
end;
|
||
end;
|
||
|
||
procedure first_fix_real(var p : ptree);
|
||
|
||
begin
|
||
if p^.left^.treetype=fixconstn then
|
||
begin
|
||
{ convert constants direct }
|
||
p^.treetype:=realconstn;
|
||
p^.valued:=round(p^.left^.valuef/65536.0);
|
||
p^.disposetyp:=dt_nothing;
|
||
disposetree(p^.left);
|
||
p^.location.loc:=LOC_MEM;
|
||
end
|
||
else
|
||
begin
|
||
if p^.registersfpu<1 then
|
||
p^.registersfpu:=1;
|
||
p^.location.loc:=LOC_FPU;
|
||
end;
|
||
end;
|
||
|
||
procedure first_real_real(var p : ptree);
|
||
|
||
begin
|
||
if p^.registersfpu<1 then
|
||
p^.registersfpu:=1;
|
||
p^.location.loc:=LOC_FPU;
|
||
end;
|
||
|
||
procedure first_pointer_to_array(var p : ptree);
|
||
|
||
begin
|
||
if p^.registers32<1 then
|
||
p^.registers32:=1;
|
||
p^.location.loc:=LOC_REFERENCE;
|
||
end;
|
||
|
||
procedure first_chararray_string(var p : ptree);
|
||
|
||
begin
|
||
{ the only important information is the location of the }
|
||
{ result }
|
||
{ other stuff is done by firsttypeconv }
|
||
p^.location.loc:=LOC_MEM;
|
||
end;
|
||
|
||
procedure first_cchar_charpointer(var p : ptree);
|
||
|
||
begin
|
||
p^.left:=gentypeconvnode(p^.left,cstringdef);
|
||
{ convert constant char to constant string }
|
||
firstpass(p^.left);
|
||
{ evalute tree }
|
||
firstpass(p);
|
||
end;
|
||
|
||
procedure first_locmem(var p : ptree);
|
||
|
||
begin
|
||
p^.location.loc:=LOC_MEM;
|
||
end;
|
||
|
||
procedure first_bool_int(var p : ptree);
|
||
begin
|
||
p^.location.loc:=LOC_REGISTER;
|
||
{ Florian I think this is overestimated
|
||
but I still do not really understand how to get this right (PM) }
|
||
{ Hmmm, I think we need only one reg to return the result of }
|
||
{ this node => so }
|
||
if p^.registers32<1 then
|
||
p^.registers32:=1;
|
||
{ should work (FK)
|
||
p^.registers32:=p^.left^.registers32+1;}
|
||
end;
|
||
|
||
procedure first_int_bool(var p : ptree);
|
||
|
||
begin
|
||
p^.location.loc:=LOC_REGISTER;
|
||
{ Florian I think this is overestimated
|
||
but I still do not really understand how to get this right (PM) }
|
||
{ Hmmm, I think we need only one reg to return the result of }
|
||
{ this node => so }
|
||
p^.left:=gentypeconvnode(p^.left,s32bitdef);
|
||
firstpass(p^.left);
|
||
if p^.registers32<1 then
|
||
p^.registers32:=1;
|
||
{ p^.resulttype:=booldef; }
|
||
{ should work (FK)
|
||
p^.registers32:=p^.left^.registers32+1;}
|
||
end;
|
||
|
||
procedure first_proc_to_procvar(var p : ptree);
|
||
|
||
begin
|
||
{ hmmm, I'am not sure if that is necessary (FK) }
|
||
firstpass(p^.left);
|
||
if codegenerror then
|
||
exit;
|
||
|
||
if (p^.left^.location.loc<>LOC_REFERENCE) then
|
||
Message(cg_e_illegal_expression);
|
||
|
||
p^.registers32:=p^.left^.registers32;
|
||
if p^.registers32<1 then
|
||
p^.registers32:=1;
|
||
p^.location.loc:=LOC_REGISTER;
|
||
end;
|
||
|
||
procedure first_load_smallset(var p : ptree);
|
||
|
||
begin
|
||
end;
|
||
|
||
procedure first_pchar_to_ansistring(var p : ptree);
|
||
|
||
begin
|
||
p^.location.loc:=LOC_REGISTER;
|
||
if p^.registers32<1 then
|
||
p^.registers32:=1;
|
||
end;
|
||
|
||
procedure first_ansistring_to_pchar(var p : ptree);
|
||
|
||
begin
|
||
p^.location.loc:=LOC_REGISTER;
|
||
if p^.registers32<1 then
|
||
p^.registers32:=1;
|
||
end;
|
||
|
||
function is_procsym_load(p:Ptree):boolean;
|
||
|
||
begin
|
||
is_procsym_load:=((p^.treetype=loadn) and (p^.symtableentry^.typ=procsym)) or
|
||
((p^.treetype=addrn) and (p^.left^.treetype=loadn)
|
||
and (p^.left^.symtableentry^.typ=procsym)) ;
|
||
end;
|
||
|
||
{ change a proc call to a procload for assignment to a procvar }
|
||
{ this can only happen for proc/function without arguments }
|
||
function is_procsym_call(p:Ptree):boolean;
|
||
|
||
begin
|
||
is_procsym_call:=(p^.treetype=calln) and (p^.left=nil) and
|
||
(((p^.symtableprocentry^.typ=procsym) and (p^.right=nil)) or
|
||
((p^.right<>nil) and (p^.right^.symtableprocentry^.typ=varsym)));
|
||
end;
|
||
{***}
|
||
|
||
function is_assignment_overloaded(from_def,to_def : pdef) : boolean;
|
||
var
|
||
passproc : pprocdef;
|
||
convtyp : tconverttype;
|
||
begin
|
||
is_assignment_overloaded:=false;
|
||
if assigned(overloaded_operators[assignment]) then
|
||
passproc:=overloaded_operators[assignment]^.definition
|
||
else
|
||
exit;
|
||
while passproc<>nil do
|
||
begin
|
||
if is_equal(passproc^.retdef,to_def) and
|
||
isconvertable(from_def,passproc^.para1^.data,convtyp,
|
||
ordconstn { nur Dummy},false ) then
|
||
begin
|
||
is_assignment_overloaded:=true;
|
||
break;
|
||
end;
|
||
passproc:=passproc^.nextoverloaded;
|
||
end;
|
||
end;
|
||
|
||
{ Attention: do *** no *** recursive call of firstpass }
|
||
{ because the child tree is always passed }
|
||
|
||
procedure firsttypeconv(var p : ptree);
|
||
|
||
var
|
||
hp : ptree;
|
||
aprocdef : pprocdef;
|
||
proctype : tdeftype;
|
||
|
||
const
|
||
firstconvert : array[tconverttype] of
|
||
tfirstconvproc = (first_nothing,first_nothing,
|
||
first_bigger_smaller,first_nothing,first_bigger_smaller,
|
||
first_bigger_smaller,first_bigger_smaller,
|
||
first_bigger_smaller,first_bigger_smaller,
|
||
first_bigger_smaller,first_string_string,
|
||
first_cstring_charpointer,first_string_chararray,
|
||
first_array_to_pointer,first_pointer_to_array,
|
||
first_char_to_string,first_bigger_smaller,
|
||
first_bigger_smaller,first_bigger_smaller,
|
||
first_bigger_smaller,first_bigger_smaller,
|
||
first_bigger_smaller,first_bigger_smaller,
|
||
first_bigger_smaller,first_bigger_smaller,
|
||
first_bigger_smaller,first_bigger_smaller,
|
||
first_bigger_smaller,first_bigger_smaller,
|
||
first_bigger_smaller,first_bigger_smaller,
|
||
first_bigger_smaller,first_bigger_smaller,
|
||
first_bigger_smaller,first_bigger_smaller,
|
||
first_bool_int,first_int_bool,
|
||
first_int_real,first_real_fix,
|
||
first_fix_real,first_int_fix,first_real_real,
|
||
first_locmem,first_proc_to_procvar,
|
||
first_cchar_charpointer,
|
||
first_load_smallset,
|
||
first_ansistring_to_pchar,
|
||
first_pchar_to_ansistring);
|
||
|
||
begin
|
||
aprocdef:=nil;
|
||
{ if explicite type conversation, then run firstpass }
|
||
if p^.explizit then
|
||
firstpass(p^.left);
|
||
|
||
if codegenerror then
|
||
begin
|
||
p^.resulttype:=generrordef;
|
||
exit;
|
||
end;
|
||
|
||
if not assigned(p^.left^.resulttype) then
|
||
begin
|
||
codegenerror:=true;
|
||
internalerror(52349);
|
||
exit;
|
||
end;
|
||
|
||
{ load the values from the left part }
|
||
p^.registers32:=p^.left^.registers32;
|
||
p^.registersfpu:=p^.left^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=p^.left^.registersmmx;
|
||
{$endif}
|
||
set_location(p^.location,p^.left^.location);
|
||
|
||
{ remove obsolete type conversions }
|
||
if is_equal(p^.left^.resulttype,p^.resulttype) then
|
||
begin
|
||
{ becuase is_equal only checks the basetype for sets we need to
|
||
check here if we are loading a smallset into a normalset }
|
||
if (p^.resulttype^.deftype=setdef) and
|
||
(p^.left^.resulttype^.deftype=setdef) and
|
||
(psetdef(p^.resulttype)^.settype<>smallset) and
|
||
(psetdef(p^.left^.resulttype)^.settype=smallset) then
|
||
begin
|
||
{ try to define the set as a normalset if it's a constant set }
|
||
if p^.left^.treetype=setconstrn then
|
||
begin
|
||
p^.resulttype:=p^.left^.resulttype;
|
||
psetdef(p^.resulttype)^.settype:=normset
|
||
end
|
||
else
|
||
p^.convtyp:=tc_load_smallset;
|
||
exit;
|
||
end
|
||
else
|
||
begin
|
||
hp:=p;
|
||
p:=p^.left;
|
||
p^.resulttype:=hp^.resulttype;
|
||
putnode(hp);
|
||
exit;
|
||
end;
|
||
end;
|
||
|
||
if is_assignment_overloaded(p^.left^.resulttype,p^.resulttype) then
|
||
begin
|
||
procinfo.flags:=procinfo.flags or pi_do_call;
|
||
hp:=gencallnode(overloaded_operators[assignment],nil);
|
||
hp^.left:=gencallparanode(p^.left,nil);
|
||
putnode(p);
|
||
p:=hp;
|
||
firstpass(p);
|
||
exit;
|
||
end;
|
||
if (not(isconvertable(p^.left^.resulttype,p^.resulttype,
|
||
p^.convtyp,p^.left^.treetype,p^.explizit))) then
|
||
begin
|
||
{Procedures have a resulttype of voiddef and functions of their
|
||
own resulttype. They will therefore always be incompatible with
|
||
a procvar. Because isconvertable cannot check for procedures we
|
||
use an extra check for them.}
|
||
if (cs_tp_compatible in aktmoduleswitches) and
|
||
((is_procsym_load(p^.left) or is_procsym_call(p^.left)) and
|
||
(p^.resulttype^.deftype=procvardef)) then
|
||
begin
|
||
{ just a test: p^.explizit:=false; }
|
||
if is_procsym_call(p^.left) then
|
||
begin
|
||
if p^.left^.right=nil then
|
||
begin
|
||
p^.left^.treetype:=loadn;
|
||
{ are at same offset so this could be spared, but
|
||
it more secure to do it anyway }
|
||
p^.left^.symtableentry:=p^.left^.symtableprocentry;
|
||
p^.left^.resulttype:=pprocsym(p^.left^.symtableentry)^.definition;
|
||
aprocdef:=pprocdef(p^.left^.resulttype);
|
||
end
|
||
else
|
||
begin
|
||
p^.left^.right^.treetype:=loadn;
|
||
p^.left^.right^.symtableentry:=p^.left^.right^.symtableentry;
|
||
P^.left^.right^.resulttype:=pvarsym(p^.left^.symtableentry)^.definition;
|
||
hp:=p^.left^.right;
|
||
putnode(p^.left);
|
||
p^.left:=hp;
|
||
{ should we do that ? }
|
||
firstpass(p^.left);
|
||
if not is_equal(p^.left^.resulttype,p^.resulttype) then
|
||
begin
|
||
Message(sym_e_type_mismatch);
|
||
exit;
|
||
end
|
||
else
|
||
begin
|
||
hp:=p;
|
||
p:=p^.left;
|
||
p^.resulttype:=hp^.resulttype;
|
||
putnode(hp);
|
||
exit;
|
||
end;
|
||
end;
|
||
end
|
||
else
|
||
begin
|
||
if p^.left^.treetype=addrn then
|
||
begin
|
||
hp:=p^.left;
|
||
p^.left:=p^.left^.left;
|
||
putnode(p^.left);
|
||
end
|
||
else
|
||
aprocdef:=pprocsym(p^.left^.symtableentry)^.definition;
|
||
end;
|
||
|
||
p^.convtyp:=tc_proc2procvar;
|
||
{ Now check if the procedure we are going to assign to
|
||
the procvar, is compatible with the procvar's type.
|
||
Did the original procvar support do such a check?
|
||
I can't find any.}
|
||
{ answer : is_equal works for procvardefs !! }
|
||
{ but both must be procvardefs, so we cheet little }
|
||
if assigned(aprocdef) then
|
||
begin
|
||
proctype:=aprocdef^.deftype;
|
||
aprocdef^.deftype:=procvardef;
|
||
|
||
if not is_equal(aprocdef,p^.resulttype) then
|
||
begin
|
||
aprocdef^.deftype:=proctype;
|
||
Message(sym_e_type_mismatch);
|
||
end;
|
||
aprocdef^.deftype:=proctype;
|
||
firstconvert[p^.convtyp](p);
|
||
end
|
||
else
|
||
Message(sym_e_type_mismatch);
|
||
exit;
|
||
end
|
||
else
|
||
begin
|
||
if p^.explizit then
|
||
begin
|
||
{ boolean to byte are special because the
|
||
location can be different }
|
||
if (p^.resulttype^.deftype=orddef) and
|
||
(porddef(p^.resulttype)^.typ=u8bit) and
|
||
(p^.left^.resulttype^.deftype=orddef) and
|
||
(porddef(p^.left^.resulttype)^.typ=bool8bit) then
|
||
begin
|
||
p^.convtyp:=tc_bool_2_int;
|
||
firstconvert[p^.convtyp](p);
|
||
exit;
|
||
end;
|
||
{ normal tc_equal-Konvertierung durchf<68>hren }
|
||
p^.convtyp:=tc_equal;
|
||
{ wenn Aufz<66>hltyp nach Ordinal konvertiert werden soll }
|
||
{ dann Aufz<66>hltyp=s32bit }
|
||
if (p^.left^.resulttype^.deftype=enumdef) and
|
||
is_ordinal(p^.resulttype) then
|
||
begin
|
||
if p^.left^.treetype=ordconstn then
|
||
begin
|
||
hp:=genordinalconstnode(p^.left^.value,p^.resulttype);
|
||
disposetree(p);
|
||
firstpass(hp);
|
||
p:=hp;
|
||
exit;
|
||
end
|
||
else
|
||
begin
|
||
if not isconvertable(s32bitdef,p^.resulttype,p^.convtyp,
|
||
ordconstn { nur Dummy},false ) then
|
||
Message(cg_e_illegal_type_conversion);
|
||
end;
|
||
|
||
end
|
||
{ ordinal to enumeration }
|
||
else
|
||
if (p^.resulttype^.deftype=enumdef) and
|
||
is_ordinal(p^.left^.resulttype) then
|
||
begin
|
||
if p^.left^.treetype=ordconstn then
|
||
begin
|
||
hp:=genordinalconstnode(p^.left^.value,p^.resulttype);
|
||
disposetree(p);
|
||
firstpass(hp);
|
||
p:=hp;
|
||
exit;
|
||
end
|
||
else
|
||
begin
|
||
if not isconvertable(p^.left^.resulttype,s32bitdef,p^.convtyp,
|
||
ordconstn { nur Dummy},false ) then
|
||
Message(cg_e_illegal_type_conversion);
|
||
end;
|
||
end
|
||
{Are we typecasting an ordconst to a char?}
|
||
else
|
||
if is_equal(p^.resulttype,cchardef) and
|
||
is_ordinal(p^.left^.resulttype) then
|
||
begin
|
||
if p^.left^.treetype=ordconstn then
|
||
begin
|
||
hp:=genordinalconstnode(p^.left^.value,p^.resulttype);
|
||
firstpass(hp);
|
||
disposetree(p);
|
||
p:=hp;
|
||
exit;
|
||
end
|
||
else
|
||
begin
|
||
{ this is wrong because it converts to a 4 byte long var !!
|
||
if not isconvertable(p^.left^.resulttype,s32bitdef,p^.convtyp,ordconstn nur Dummy ) then }
|
||
if not isconvertable(p^.left^.resulttype,u8bitdef,
|
||
p^.convtyp,ordconstn { nur Dummy},false ) then
|
||
Message(cg_e_illegal_type_conversion);
|
||
end;
|
||
end
|
||
{ only if the same size or formal def }
|
||
{ why do we allow typecasting of voiddef ?? (PM) }
|
||
else
|
||
if not(
|
||
(p^.left^.resulttype^.deftype=formaldef) or
|
||
(p^.left^.resulttype^.size=p^.resulttype^.size) or
|
||
(is_equal(p^.left^.resulttype,voiddef) and
|
||
(p^.left^.treetype=derefn))
|
||
) then
|
||
Message(cg_e_illegal_type_conversion);
|
||
{ the conversion into a strutured type is only }
|
||
{ possible, if the source is no register }
|
||
if ((p^.resulttype^.deftype in [recorddef,stringdef,arraydef]) or
|
||
((p^.resulttype^.deftype=objectdef) and not(pobjectdef(p^.resulttype)^.isclass))
|
||
) and (p^.left^.location.loc in [LOC_REGISTER,LOC_CREGISTER]) and
|
||
{it also works if the assignment is overloaded }
|
||
not is_assignment_overloaded(p^.left^.resulttype,p^.resulttype) then
|
||
Message(cg_e_illegal_type_conversion);
|
||
end
|
||
else
|
||
Message(sym_e_type_mismatch);
|
||
end
|
||
end
|
||
else
|
||
begin
|
||
{ just a test: p^.explizit:=false; }
|
||
{ ordinale contants are direct converted }
|
||
if (p^.left^.treetype=ordconstn) and is_ordinal(p^.resulttype) then
|
||
begin
|
||
{ perform range checking }
|
||
if not(p^.explizit and (cs_tp_compatible in aktmoduleswitches)) then
|
||
testrange(p^.resulttype,p^.left^.value);
|
||
hp:=genordinalconstnode(p^.left^.value,p^.resulttype);
|
||
disposetree(p);
|
||
firstpass(hp);
|
||
p:=hp;
|
||
exit;
|
||
end;
|
||
if p^.convtyp<>tc_equal then
|
||
firstconvert[p^.convtyp](p);
|
||
end;
|
||
end;
|
||
|
||
{ *************** subroutine handling **************** }
|
||
|
||
{ protected field handling
|
||
protected field can not appear in
|
||
var parameters of function !!
|
||
this can only be done after we have determined the
|
||
overloaded function
|
||
this is the reason why it is not in the parser
|
||
PM }
|
||
|
||
procedure test_protected_sym(sym : psym);
|
||
|
||
begin
|
||
if ((sym^.properties and sp_protected)<>0) and
|
||
((sym^.owner^.symtabletype=unitsymtable) or
|
||
((sym^.owner^.symtabletype=objectsymtable) and
|
||
(pobjectdef(sym^.owner^.defowner)^.owner^.symtabletype=unitsymtable))) then
|
||
Message(parser_e_cant_access_protected_member);
|
||
end;
|
||
|
||
procedure test_protected(p : ptree);
|
||
|
||
begin
|
||
if p^.treetype=loadn then
|
||
begin
|
||
test_protected_sym(p^.symtableentry);
|
||
end
|
||
else if p^.treetype=typeconvn then
|
||
begin
|
||
test_protected(p^.left);
|
||
end
|
||
else if p^.treetype=derefn then
|
||
begin
|
||
test_protected(p^.left);
|
||
end
|
||
else if p^.treetype=subscriptn then
|
||
begin
|
||
{ test_protected(p^.left);
|
||
Is a field of a protected var
|
||
also protected ??? PM }
|
||
test_protected_sym(p^.vs);
|
||
end;
|
||
end;
|
||
|
||
procedure firstcallparan(var p : ptree;defcoll : pdefcoll);
|
||
|
||
var store_valid : boolean;
|
||
convtyp : tconverttype;
|
||
begin
|
||
inc(parsing_para_level);
|
||
if assigned(p^.right) then
|
||
begin
|
||
if defcoll=nil then
|
||
firstcallparan(p^.right,nil)
|
||
else
|
||
firstcallparan(p^.right,defcoll^.next);
|
||
p^.registers32:=p^.right^.registers32;
|
||
p^.registersfpu:=p^.right^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=p^.right^.registersmmx;
|
||
{$endif}
|
||
end;
|
||
if defcoll=nil then
|
||
begin
|
||
{ this breaks typeconversions in write !!! (PM) }
|
||
{if not(assigned(p^.resulttype)) then }
|
||
if not(assigned(p^.resulttype)) or
|
||
(p^.left^.treetype=typeconvn) then
|
||
firstpass(p^.left);
|
||
{else
|
||
exit; this broke the
|
||
value of registers32 !! }
|
||
|
||
if codegenerror then
|
||
begin
|
||
dec(parsing_para_level);
|
||
exit;
|
||
end;
|
||
|
||
p^.resulttype:=p^.left^.resulttype;
|
||
end
|
||
{ if we know the routine which is called, then the type }
|
||
{ conversions are inserted }
|
||
else
|
||
begin
|
||
if count_ref then
|
||
begin
|
||
store_valid:=must_be_valid;
|
||
if (defcoll^.paratyp=vs_var) then
|
||
test_protected(p^.left);
|
||
if (defcoll^.paratyp<>vs_var) then
|
||
must_be_valid:=true
|
||
else
|
||
must_be_valid:=false;
|
||
{ here we must add something for the implicit type }
|
||
{ conversion from array of char to pchar }
|
||
if isconvertable(p^.left^.resulttype,defcoll^.data,convtyp,
|
||
p^.left^.treetype,false) then
|
||
if convtyp=tc_array_to_pointer then
|
||
must_be_valid:=false;
|
||
firstpass(p^.left);
|
||
must_be_valid:=store_valid;
|
||
end;
|
||
if not(is_shortstring(p^.left^.resulttype) and
|
||
is_shortstring(defcoll^.data)) and
|
||
(defcoll^.data^.deftype<>formaldef) then
|
||
begin
|
||
if (defcoll^.paratyp=vs_var) and
|
||
{ allows conversion from word to integer and
|
||
byte to shortint }
|
||
(not(
|
||
(p^.left^.resulttype^.deftype=orddef) and
|
||
(defcoll^.data^.deftype=orddef) and
|
||
(p^.left^.resulttype^.size=defcoll^.data^.size)
|
||
) and
|
||
{ an implicit pointer conversion is allowed }
|
||
not(
|
||
(p^.left^.resulttype^.deftype=pointerdef) and
|
||
(defcoll^.data^.deftype=pointerdef)
|
||
) and
|
||
{ child classes can be also passed }
|
||
not(
|
||
(p^.left^.resulttype^.deftype=objectdef) and
|
||
(defcoll^.data^.deftype=objectdef) and
|
||
pobjectdef(p^.left^.resulttype)^.isrelated(pobjectdef(defcoll^.data))
|
||
) and
|
||
|
||
{ an implicit file conversion is also allowed }
|
||
{ from a typed file to an untyped one }
|
||
not(
|
||
(p^.left^.resulttype^.deftype=filedef) and
|
||
(defcoll^.data^.deftype=filedef) and
|
||
(pfiledef(defcoll^.data)^.filetype = ft_untyped) and
|
||
(pfiledef(p^.left^.resulttype)^.filetype = ft_typed)
|
||
) and
|
||
not(is_equal(p^.left^.resulttype,defcoll^.data))) then
|
||
Message(parser_e_call_by_ref_without_typeconv);
|
||
{ don't generate an type conversion for open arrays }
|
||
{ else we loss the ranges }
|
||
if not(is_open_array(defcoll^.data)) then
|
||
begin
|
||
p^.left:=gentypeconvnode(p^.left,defcoll^.data);
|
||
firstpass(p^.left);
|
||
end;
|
||
if codegenerror then
|
||
begin
|
||
dec(parsing_para_level);
|
||
exit;
|
||
end;
|
||
end;
|
||
{ check var strings }
|
||
if (cs_strict_var_strings in aktlocalswitches) and
|
||
is_shortstring(p^.left^.resulttype) and
|
||
is_shortstring(defcoll^.data) and
|
||
(defcoll^.paratyp=vs_var) and
|
||
not(is_equal(p^.left^.resulttype,defcoll^.data)) then
|
||
Message(parser_e_strict_var_string_violation);
|
||
{ Variablen, die call by reference <20>bergeben werden, }
|
||
{ k<>nnen nicht in ein Register kopiert werden }
|
||
{ is this usefull here ? }
|
||
{ this was missing in formal parameter list }
|
||
if defcoll^.paratyp=vs_var then
|
||
make_not_regable(p^.left);
|
||
|
||
p^.resulttype:=defcoll^.data;
|
||
end;
|
||
if p^.left^.registers32>p^.registers32 then
|
||
p^.registers32:=p^.left^.registers32;
|
||
if p^.left^.registersfpu>p^.registersfpu then
|
||
p^.registersfpu:=p^.left^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
if p^.left^.registersmmx>p^.registersmmx then
|
||
p^.registersmmx:=p^.left^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
dec(parsing_para_level);
|
||
end;
|
||
|
||
procedure firstcalln(var p : ptree);
|
||
|
||
type
|
||
pprocdefcoll = ^tprocdefcoll;
|
||
|
||
tprocdefcoll = record
|
||
data : pprocdef;
|
||
nextpara : pdefcoll;
|
||
firstpara : pdefcoll;
|
||
next : pprocdefcoll;
|
||
end;
|
||
|
||
var
|
||
hp,procs,hp2 : pprocdefcoll;
|
||
pd : pprocdef;
|
||
actprocsym : pprocsym;
|
||
def_from,def_to,conv_to : pdef;
|
||
pt,inlinecode : ptree;
|
||
exactmatch,inlined : boolean;
|
||
paralength,l : longint;
|
||
pdc : pdefcoll;
|
||
{$ifdef UseBrowser}
|
||
curtokenpos : tfileposinfo;
|
||
{$endif UseBrowser}
|
||
|
||
{ only Dummy }
|
||
hcvt : tconverttype;
|
||
regi : tregister;
|
||
store_valid, old_count_ref : boolean;
|
||
|
||
{ types.is_equal can't handle a formaldef ! }
|
||
function is_equal(def1,def2 : pdef) : boolean;
|
||
|
||
begin
|
||
{ all types can be passed to a formaldef }
|
||
is_equal:=(def1^.deftype=formaldef) or
|
||
(assigned(def2) and types.is_equal(def1,def2))
|
||
{ to support ansi/long/wide strings in a proper way }
|
||
{ string and string[10] are assumed as equal }
|
||
{ when searching the correct overloaded procedure }
|
||
or
|
||
(assigned(def1) and assigned(def2) and
|
||
(def1^.deftype=stringdef) and (def2^.deftype=stringdef) and
|
||
(pstringdef(def1)^.string_typ=pstringdef(def2)^.string_typ)
|
||
)
|
||
;
|
||
end;
|
||
|
||
function is_in_limit(def_from,def_to : pdef) : boolean;
|
||
|
||
begin
|
||
is_in_limit:=(def_from^.deftype = orddef) and
|
||
(def_to^.deftype = orddef) and
|
||
(porddef(def_from)^.low>porddef(def_to)^.low) and
|
||
(porddef(def_from)^.high<porddef(def_to)^.high);
|
||
end;
|
||
|
||
|
||
begin
|
||
{ release registers! }
|
||
{ if procdefinition<>nil then we called firstpass already }
|
||
{ it seems to be bad because of the registers }
|
||
{ at least we can avoid the overloaded search !! }
|
||
procs:=nil;
|
||
{ made this global for disposing !! }
|
||
store_valid:=must_be_valid;
|
||
must_be_valid:=false;
|
||
|
||
inlined:=false;
|
||
if assigned(p^.procdefinition) and
|
||
((p^.procdefinition^.options and poinline)<>0) then
|
||
begin
|
||
inlinecode:=p^.right;
|
||
if assigned(inlinecode) then
|
||
begin
|
||
inlined:=true;
|
||
p^.procdefinition^.options:=p^.procdefinition^.options and (not poinline);
|
||
end;
|
||
p^.right:=nil;
|
||
end;
|
||
{ procedure variable ? }
|
||
if assigned(p^.right) then
|
||
begin
|
||
{ procedure does a call }
|
||
procinfo.flags:=procinfo.flags or pi_do_call;
|
||
|
||
{ calc the correture value for the register }
|
||
{$ifdef i386}
|
||
for regi:=R_EAX to R_EDI do
|
||
inc(reg_pushes[regi],t_times*2);
|
||
{$endif}
|
||
{$ifdef m68k}
|
||
for regi:=R_D0 to R_A6 do
|
||
inc(reg_pushes[regi],t_times*2);
|
||
{$endif}
|
||
{ calculate the type of the parameters }
|
||
if assigned(p^.left) then
|
||
begin
|
||
old_count_ref:=count_ref;
|
||
count_ref:=false;
|
||
firstcallparan(p^.left,nil);
|
||
count_ref:=old_count_ref;
|
||
if codegenerror then
|
||
exit;
|
||
end;
|
||
firstpass(p^.right);
|
||
|
||
{ check the parameters }
|
||
pdc:=pprocvardef(p^.right^.resulttype)^.para1;
|
||
pt:=p^.left;
|
||
while assigned(pdc) and assigned(pt) do
|
||
begin
|
||
pt:=pt^.right;
|
||
pdc:=pdc^.next;
|
||
end;
|
||
if assigned(pt) or assigned(pdc) then
|
||
Message(parser_e_illegal_parameter_list);
|
||
|
||
{ insert type conversions }
|
||
if assigned(p^.left) then
|
||
begin
|
||
old_count_ref:=count_ref;
|
||
count_ref:=true;
|
||
firstcallparan(p^.left,pprocvardef(p^.right^.resulttype)^.para1);
|
||
count_ref:=old_count_ref;
|
||
if codegenerror then
|
||
exit;
|
||
end;
|
||
p^.resulttype:=pprocvardef(p^.right^.resulttype)^.retdef;
|
||
{ this was missing, leads to a bug below if
|
||
the procvar is a function }
|
||
p^.procdefinition:=pprocdef(p^.right^.resulttype);
|
||
end
|
||
else
|
||
{ not a procedure variable }
|
||
begin
|
||
{ determine the type of the parameters }
|
||
if assigned(p^.left) then
|
||
begin
|
||
old_count_ref:=count_ref;
|
||
count_ref:=false;
|
||
store_valid:=must_be_valid;
|
||
must_be_valid:=false;
|
||
firstcallparan(p^.left,nil);
|
||
count_ref:=old_count_ref;
|
||
must_be_valid:=store_valid;
|
||
if codegenerror then
|
||
exit;
|
||
end;
|
||
|
||
{ do we know the procedure to call ? }
|
||
if not(assigned(p^.procdefinition)) then
|
||
begin
|
||
actprocsym:=pprocsym(p^.symtableprocentry);
|
||
{ determine length of parameter list }
|
||
pt:=p^.left;
|
||
paralength:=0;
|
||
while assigned(pt) do
|
||
begin
|
||
inc(paralength);
|
||
pt:=pt^.right;
|
||
end;
|
||
|
||
{ alle in Frage kommenden Prozeduren in eine }
|
||
{ verkettete Liste einf<6E>gen }
|
||
pd:=actprocsym^.definition;
|
||
while assigned(pd) do
|
||
begin
|
||
{ we should also check that the overloaded function
|
||
has been declared in a unit that is in the uses !! }
|
||
{ pd^.owner should be in the symtablestack !! }
|
||
{ Laenge der deklarierten Parameterliste feststellen: }
|
||
{ not necessary why nextprocsym field }
|
||
{st:=symtablestack;
|
||
if (pd^.owner^.symtabletype<>objectsymtable) then
|
||
while assigned(st) do
|
||
begin
|
||
if (st=pd^.owner) then break;
|
||
st:=st^.next;
|
||
end;
|
||
if assigned(st) then }
|
||
begin
|
||
pdc:=pd^.para1;
|
||
l:=0;
|
||
while assigned(pdc) do
|
||
begin
|
||
inc(l);
|
||
pdc:=pdc^.next;
|
||
end;
|
||
{ nur wenn die Parameterl<72>nge pa<70>t, dann Einf<6E>gen }
|
||
if l=paralength then
|
||
begin
|
||
new(hp);
|
||
hp^.data:=pd;
|
||
hp^.next:=procs;
|
||
hp^.nextpara:=pd^.para1;
|
||
hp^.firstpara:=pd^.para1;
|
||
procs:=hp;
|
||
end;
|
||
end;
|
||
pd:=pd^.nextoverloaded;
|
||
{$ifdef CHAINPROCSYMS}
|
||
if (pd=nil) and not (p^.unit_specific) then
|
||
begin
|
||
actprocsym:=actprocsym^.nextprocsym;
|
||
if assigned(actprocsym) then
|
||
pd:=actprocsym^.definition;
|
||
end;
|
||
{$endif CHAINPROCSYMS}
|
||
end;
|
||
|
||
{ nun alle Parameter nacheinander vergleichen }
|
||
pt:=p^.left;
|
||
while assigned(pt) do
|
||
begin
|
||
{ matches a parameter of one procedure exact ? }
|
||
exactmatch:=false;
|
||
hp:=procs;
|
||
while assigned(hp) do
|
||
begin
|
||
if is_equal(hp^.nextpara^.data,pt^.resulttype) then
|
||
begin
|
||
if hp^.nextpara^.data=pt^.resulttype then
|
||
begin
|
||
pt^.exact_match_found:=true;
|
||
hp^.nextpara^.argconvtyp:=act_exact;
|
||
end
|
||
else
|
||
hp^.nextpara^.argconvtyp:=act_equal;
|
||
exactmatch:=true;
|
||
end
|
||
else
|
||
hp^.nextpara^.argconvtyp:=act_convertable;
|
||
hp:=hp^.next;
|
||
end;
|
||
|
||
{ .... if yes, del all the other procedures }
|
||
if exactmatch then
|
||
begin
|
||
{ the first .... }
|
||
while (assigned(procs)) and not(is_equal(procs^.nextpara^.data,pt^.resulttype)) do
|
||
begin
|
||
hp:=procs^.next;
|
||
dispose(procs);
|
||
procs:=hp;
|
||
end;
|
||
{ and the others }
|
||
hp:=procs;
|
||
while (assigned(hp)) and assigned(hp^.next) do
|
||
begin
|
||
if not(is_equal(hp^.next^.nextpara^.data,pt^.resulttype)) then
|
||
begin
|
||
hp2:=hp^.next^.next;
|
||
dispose(hp^.next);
|
||
hp^.next:=hp2;
|
||
end
|
||
else
|
||
hp:=hp^.next;
|
||
end;
|
||
end
|
||
{ sollte nirgendwo ein Parameter exakt passen, }
|
||
{ so alle Prozeduren entfernen, bei denen }
|
||
{ der Parameter auch nach einer impliziten }
|
||
{ Typkonvertierung nicht passt }
|
||
else
|
||
begin
|
||
{ erst am Anfang }
|
||
while (assigned(procs)) and
|
||
not(isconvertable(pt^.resulttype,procs^.nextpara^.data,
|
||
hcvt,pt^.left^.treetype,false)) do
|
||
begin
|
||
hp:=procs^.next;
|
||
dispose(procs);
|
||
procs:=hp;
|
||
end;
|
||
{ und jetzt aus der Mitte }
|
||
hp:=procs;
|
||
while (assigned(hp)) and assigned(hp^.next) do
|
||
begin
|
||
if not(isconvertable(pt^.resulttype,hp^.next^.nextpara^.data,
|
||
hcvt,pt^.left^.treetype,false)) then
|
||
begin
|
||
hp2:=hp^.next^.next;
|
||
dispose(hp^.next);
|
||
hp^.next:=hp2;
|
||
end
|
||
else
|
||
hp:=hp^.next;
|
||
end;
|
||
end;
|
||
{ nun bei denn Prozeduren den nextpara-Zeiger auf den }
|
||
{ naechsten Parameter setzen }
|
||
hp:=procs;
|
||
while assigned(hp) do
|
||
begin
|
||
hp^.nextpara:=hp^.nextpara^.next;
|
||
hp:=hp^.next;
|
||
end;
|
||
pt:=pt^.right;
|
||
end;
|
||
|
||
if procs=nil then
|
||
if (parsing_para_level=0) or (p^.left<>nil) then
|
||
begin
|
||
Message(parser_e_illegal_parameter_list);
|
||
exit;
|
||
end
|
||
else
|
||
begin
|
||
{ try to convert to procvar }
|
||
p^.treetype:=loadn;
|
||
p^.resulttype:=pprocsym(p^.symtableprocentry)^.definition;
|
||
p^.symtableentry:=p^.symtableprocentry;
|
||
p^.is_first:=false;
|
||
p^.disposetyp:=dt_nothing;
|
||
firstpass(p);
|
||
exit;
|
||
end;
|
||
|
||
{ if there are several choices left then for orddef }
|
||
{ if a type is totally included in the other }
|
||
{ we don't fear an overflow , }
|
||
{ so we can do as if it is an exact match }
|
||
{ this will convert integer to longint }
|
||
{ rather than to words }
|
||
{ conversion of byte to integer or longint }
|
||
{would still not be solved }
|
||
if assigned(procs^.next) then
|
||
begin
|
||
hp:=procs;
|
||
while assigned(hp) do
|
||
begin
|
||
hp^.nextpara:=hp^.firstpara;
|
||
hp:=hp^.next;
|
||
end;
|
||
pt:=p^.left;
|
||
while assigned(pt) do
|
||
begin
|
||
{ matches a parameter of one procedure exact ? }
|
||
exactmatch:=false;
|
||
def_from:=pt^.resulttype;
|
||
hp:=procs;
|
||
while assigned(hp) do
|
||
begin
|
||
if not is_equal(hp^.nextpara^.data,pt^.resulttype) then
|
||
begin
|
||
def_to:=hp^.nextpara^.data;
|
||
if ((def_from^.deftype=orddef) and (def_to^.deftype=orddef)) and
|
||
(is_in_limit(def_from,def_to) or
|
||
((hp^.nextpara^.paratyp=vs_var) and
|
||
(def_from^.size=def_to^.size))) then
|
||
begin
|
||
exactmatch:=true;
|
||
conv_to:=def_to;
|
||
end;
|
||
end;
|
||
hp:=hp^.next;
|
||
end;
|
||
|
||
{ .... if yes, del all the other procedures }
|
||
if exactmatch then
|
||
begin
|
||
{ the first .... }
|
||
while (assigned(procs)) and not(is_in_limit(def_from,procs^.nextpara^.data)) do
|
||
begin
|
||
hp:=procs^.next;
|
||
dispose(procs);
|
||
procs:=hp;
|
||
end;
|
||
{ and the others }
|
||
hp:=procs;
|
||
while (assigned(hp)) and assigned(hp^.next) do
|
||
begin
|
||
if not(is_in_limit(def_from,hp^.next^.nextpara^.data)) then
|
||
begin
|
||
hp2:=hp^.next^.next;
|
||
dispose(hp^.next);
|
||
hp^.next:=hp2;
|
||
end
|
||
else
|
||
begin
|
||
def_to:=hp^.next^.nextpara^.data;
|
||
if (conv_to^.size>def_to^.size) or
|
||
((porddef(conv_to)^.low<porddef(def_to)^.low) and
|
||
(porddef(conv_to)^.high>porddef(def_to)^.high)) then
|
||
begin
|
||
hp2:=procs;
|
||
procs:=hp;
|
||
conv_to:=def_to;
|
||
dispose(hp2);
|
||
end
|
||
else
|
||
hp:=hp^.next;
|
||
end;
|
||
end;
|
||
end;
|
||
{ nun bei denn Prozeduren den nextpara-Zeiger auf den }
|
||
{ naechsten Parameter setzen }
|
||
hp:=procs;
|
||
while assigned(hp) do
|
||
begin
|
||
hp^.nextpara:=hp^.nextpara^.next;
|
||
hp:=hp^.next;
|
||
end;
|
||
pt:=pt^.right;
|
||
end;
|
||
end;
|
||
{ let's try to eliminate equal is exact is there }
|
||
{if assigned(procs^.next) then
|
||
begin
|
||
pt:=p^.left;
|
||
while assigned(pt) do
|
||
begin
|
||
if pt^.exact_match_found then
|
||
begin
|
||
hp:=procs;
|
||
while (assigned(procs)) and (procs^.nextpara^.data<>pt^.resulttype) do
|
||
begin
|
||
hp:=procs^.next;
|
||
dispose(procs);
|
||
procs:=hp;
|
||
end;
|
||
end;
|
||
pt:=pt^.right;
|
||
end;
|
||
end; }
|
||
|
||
{$ifndef CHAINPROCSYMS}
|
||
if assigned(procs^.next) then
|
||
Message(cg_e_cant_choose_overload_function);
|
||
{$else CHAINPROCSYMS}
|
||
if assigned(procs^.next) then
|
||
{ if the last retained is the only one }
|
||
{ from a unit it is OK PM }
|
||
{ the last is the one coming from the first symtable }
|
||
{ as the diff defcoll are inserted in front }
|
||
begin
|
||
hp2:=procs;
|
||
while assigned(hp2^.next) and assigned(hp2^.next^.next) do
|
||
hp2:=hp2^.next;
|
||
if (hp2^.data^.owner<>hp2^.next^.data^.owner) then
|
||
begin
|
||
hp:=procs^.next;
|
||
{hp2 is the correct one }
|
||
hp2:=hp2^.next;
|
||
while hp<>hp2 do
|
||
begin
|
||
dispose(procs);
|
||
procs:=hp;
|
||
hp:=procs^.next;
|
||
end;
|
||
procs:=hp2;
|
||
end
|
||
else
|
||
Message(cg_e_cant_choose_overload_function);
|
||
error(too_much_matches);
|
||
end;
|
||
{$endif CHAINPROCSYMS}
|
||
{$ifdef UseBrowser}
|
||
if make_ref then
|
||
begin
|
||
get_cur_file_pos(curtokenpos);
|
||
procs^.data^.lastref:=new(pref,init(procs^.data^.lastref,@curtokenpos));
|
||
end;
|
||
{$endif UseBrowser}
|
||
|
||
p^.procdefinition:=procs^.data;
|
||
p^.resulttype:=procs^.data^.retdef;
|
||
{ big error for with statements
|
||
p^.symtableproc:=p^.procdefinition^.owner; }
|
||
p^.location.loc:=LOC_MEM;
|
||
{$ifdef CHAINPROCSYMS}
|
||
{ object with method read;
|
||
call to read(x) will be a usual procedure call }
|
||
if assigned(p^.methodpointer) and
|
||
(p^.procdefinition^._class=nil) then
|
||
begin
|
||
{ not ok for extended }
|
||
case p^.methodpointer^.treetype of
|
||
typen,hnewn : fatalerror(no_para_match);
|
||
end;
|
||
disposetree(p^.methodpointer);
|
||
p^.methodpointer:=nil;
|
||
end;
|
||
{$endif CHAINPROCSYMS}
|
||
end;{ end of procedure to call determination }
|
||
|
||
{ handle predefined procedures }
|
||
if (p^.procdefinition^.options and pointernproc)<>0 then
|
||
begin
|
||
{ settextbuf needs two args }
|
||
if assigned(p^.left^.right) then
|
||
pt:=geninlinenode(pprocdef(p^.procdefinition)^.extnumber,p^.left)
|
||
else
|
||
begin
|
||
pt:=geninlinenode(pprocdef(p^.procdefinition)^.extnumber,p^.left^.left);
|
||
putnode(p^.left);
|
||
end;
|
||
putnode(p);
|
||
firstpass(pt);
|
||
{ was placed after the exit }
|
||
{ caused GPF }
|
||
{ error caused and corrected by (PM) }
|
||
p:=pt;
|
||
|
||
must_be_valid:=store_valid;
|
||
if codegenerror then
|
||
exit;
|
||
|
||
dispose(procs);
|
||
exit;
|
||
end
|
||
else
|
||
{ no intern procedure => we do a call }
|
||
{ calc the correture value for the register }
|
||
{ handle predefined procedures }
|
||
if (p^.procdefinition^.options and poinline)<>0 then
|
||
begin
|
||
if assigned(p^.methodpointer) then
|
||
Message(cg_e_unable_inline_object_methods);
|
||
if assigned(p^.right) and (p^.right^.treetype<>procinlinen) then
|
||
Message(cg_e_unable_inline_procvar);
|
||
{ p^.treetype:=procinlinen; }
|
||
if not assigned(p^.right) then
|
||
begin
|
||
if assigned(p^.procdefinition^.code) then
|
||
inlinecode:=genprocinlinenode(p,ptree(p^.procdefinition^.code))
|
||
else
|
||
Message(cg_e_no_code_for_inline_stored);
|
||
if assigned(inlinecode) then
|
||
begin
|
||
{ consider it has not inlined if called
|
||
again inside the args }
|
||
p^.procdefinition^.options:=p^.procdefinition^.options and (not poinline);
|
||
firstpass(inlinecode);
|
||
inlined:=true;
|
||
end;
|
||
end;
|
||
end
|
||
else
|
||
procinfo.flags:=procinfo.flags or pi_do_call;
|
||
|
||
{ work trough all parameters to insert the type conversions }
|
||
{ !!! done now after internproc !! (PM) }
|
||
if assigned(p^.left) then
|
||
begin
|
||
old_count_ref:=count_ref;
|
||
count_ref:=true;
|
||
firstcallparan(p^.left,p^.procdefinition^.para1);
|
||
count_ref:=old_count_ref;
|
||
end;
|
||
{$ifdef i386}
|
||
for regi:=R_EAX to R_EDI do
|
||
begin
|
||
if (p^.procdefinition^.usedregisters and ($80 shr word(regi)))<>0 then
|
||
inc(reg_pushes[regi],t_times*2);
|
||
end;
|
||
{$endif}
|
||
{$ifdef m68k}
|
||
for regi:=R_D0 to R_A6 do
|
||
begin
|
||
if (p^.procdefinition^.usedregisters and ($800 shr word(regi)))<>0 then
|
||
inc(reg_pushes[regi],t_times*2);
|
||
end;
|
||
{$endif}
|
||
end;
|
||
{ ensure that the result type is set }
|
||
p^.resulttype:=p^.procdefinition^.retdef;
|
||
{ get a register for the return value }
|
||
if (p^.resulttype<>pdef(voiddef)) then
|
||
begin
|
||
if (p^.procdefinition^.options and poconstructor)<>0 then
|
||
begin
|
||
{ extra handling of classes }
|
||
{ p^.methodpointer should be assigned! }
|
||
if assigned(p^.methodpointer) and assigned(p^.methodpointer^.resulttype) and
|
||
(p^.methodpointer^.resulttype^.deftype=classrefdef) then
|
||
begin
|
||
p^.location.loc:=LOC_REGISTER;
|
||
p^.registers32:=1;
|
||
{ the result type depends on the classref }
|
||
p^.resulttype:=pclassrefdef(p^.methodpointer^.resulttype)^.definition;
|
||
end
|
||
{ a object constructor returns the result with the flags }
|
||
else
|
||
p^.location.loc:=LOC_FLAGS;
|
||
end
|
||
else
|
||
begin
|
||
{$ifdef SUPPORT_MMX}
|
||
if (cs_mmx in aktlocalswitches) and
|
||
is_mmx_able_array(p^.resulttype) then
|
||
begin
|
||
p^.location.loc:=LOC_MMXREGISTER;
|
||
p^.registersmmx:=1;
|
||
end
|
||
else
|
||
{$endif SUPPORT_MMX}
|
||
if ret_in_acc(p^.resulttype) then
|
||
begin
|
||
p^.location.loc:=LOC_REGISTER;
|
||
p^.registers32:=1;
|
||
end
|
||
else if (p^.resulttype^.deftype=floatdef) then
|
||
begin
|
||
p^.location.loc:=LOC_FPU;
|
||
p^.registersfpu:=1;
|
||
end
|
||
end;
|
||
end;
|
||
|
||
{$ifdef StoreFPULevel}
|
||
{ a fpu can be used in any procedure !! }
|
||
p^.registersfpu:=p^.procdefinition^.fpu_used;
|
||
{$endif StoreFPULevel}
|
||
{ if this is a call to a method calc the registers }
|
||
if (p^.methodpointer<>nil) then
|
||
begin
|
||
case p^.methodpointer^.treetype of
|
||
{ but only, if this is not a supporting node }
|
||
typen,hnewn : ;
|
||
else
|
||
begin
|
||
{ R.Assign is not a constructor !!! }
|
||
{ but for R^.Assign, R must be valid !! }
|
||
if ((p^.procdefinition^.options and poconstructor) <> 0) or
|
||
((p^.methodpointer^.treetype=loadn) and
|
||
((pobjectdef(p^.methodpointer^.resulttype)^.options and oo_hasvirtual) = 0)) then
|
||
must_be_valid:=false
|
||
else
|
||
must_be_valid:=true;
|
||
firstpass(p^.methodpointer);
|
||
p^.registersfpu:=max(p^.methodpointer^.registersfpu,p^.registersfpu);
|
||
p^.registers32:=max(p^.methodpointer^.registers32,p^.registers32);
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=max(p^.methodpointer^.registersmmx,p^.registersmmx);
|
||
{$endif SUPPORT_MMX}
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
if inlined then
|
||
begin
|
||
p^.right:=inlinecode;
|
||
p^.procdefinition^.options:=p^.procdefinition^.options or poinline;
|
||
end;
|
||
{ determine the registers of the procedure variable }
|
||
{ is this OK for inlined procs also ?? (PM) }
|
||
if assigned(p^.right) then
|
||
begin
|
||
p^.registersfpu:=max(p^.right^.registersfpu,p^.registersfpu);
|
||
p^.registers32:=max(p^.right^.registers32,p^.registers32);
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=max(p^.right^.registersmmx,p^.registersmmx);
|
||
{$endif SUPPORT_MMX}
|
||
end;
|
||
{ determine the registers of the procedure }
|
||
if assigned(p^.left) then
|
||
begin
|
||
p^.registersfpu:=max(p^.left^.registersfpu,p^.registersfpu);
|
||
p^.registers32:=max(p^.left^.registers32,p^.registers32);
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=max(p^.left^.registersmmx,p^.registersmmx);
|
||
{$endif SUPPORT_MMX}
|
||
end;
|
||
if assigned(procs) then
|
||
dispose(procs);
|
||
must_be_valid:=store_valid;
|
||
end;
|
||
|
||
procedure firstfuncret(var p : ptree);
|
||
|
||
begin
|
||
p^.resulttype:=p^.retdef;
|
||
p^.location.loc:=LOC_REFERENCE;
|
||
if ret_in_param(p^.retdef) or
|
||
(@procinfo<>pprocinfo(p^.funcretprocinfo)) then
|
||
p^.registers32:=1;
|
||
{ no claim if setting higher return values }
|
||
if must_be_valid and
|
||
(@procinfo=pprocinfo(p^.funcretprocinfo)) and
|
||
not procinfo.funcret_is_valid then
|
||
Message(sym_w_function_result_not_set);
|
||
if count_ref then
|
||
pprocinfo(p^.funcretprocinfo)^.funcret_is_valid:=true;
|
||
end;
|
||
|
||
|
||
{ intern inline suborutines }
|
||
procedure firstinline(var p : ptree);
|
||
|
||
var
|
||
hp,hpp : ptree;
|
||
store_count_ref,isreal,store_valid,file_is_typed : boolean;
|
||
|
||
procedure do_lowhigh(adef : pdef);
|
||
|
||
var
|
||
v : longint;
|
||
enum : penumsym;
|
||
|
||
begin
|
||
case Adef^.deftype of
|
||
orddef:
|
||
begin
|
||
if p^.inlinenumber=in_low_x then
|
||
v:=porddef(Adef)^.low
|
||
else
|
||
v:=porddef(Adef)^.high;
|
||
hp:=genordinalconstnode(v,adef);
|
||
firstpass(hp);
|
||
disposetree(p);
|
||
p:=hp;
|
||
end;
|
||
enumdef:
|
||
begin
|
||
enum:=Penumdef(Adef)^.first;
|
||
if p^.inlinenumber=in_high_x then
|
||
while enum^.next<>nil do
|
||
enum:=enum^.next;
|
||
hp:=genenumnode(enum);
|
||
disposetree(p);
|
||
p:=hp;
|
||
end
|
||
end;
|
||
end;
|
||
|
||
begin
|
||
store_valid:=must_be_valid;
|
||
store_count_ref:=count_ref;
|
||
count_ref:=false;
|
||
if not (p^.inlinenumber in [in_read_x,in_readln_x,in_sizeof_x,
|
||
in_typeof_x,in_ord_x,in_str_x_string,
|
||
in_reset_typedfile,in_rewrite_typedfile]) then
|
||
must_be_valid:=true
|
||
else
|
||
must_be_valid:=false;
|
||
{ if we handle writeln; p^.left contains no valid address }
|
||
if assigned(p^.left) then
|
||
begin
|
||
if p^.left^.treetype=callparan then
|
||
firstcallparan(p^.left,nil)
|
||
else
|
||
firstpass(p^.left);
|
||
p^.registers32:=p^.left^.registers32;
|
||
p^.registersfpu:=p^.left^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=p^.left^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
set_location(p^.location,p^.left^.location);
|
||
end;
|
||
case p^.inlinenumber of
|
||
in_lo_word,in_hi_word:
|
||
begin
|
||
if p^.registers32<1 then
|
||
p^.registers32:=1;
|
||
p^.resulttype:=u8bitdef;
|
||
p^.location.loc:=LOC_REGISTER;
|
||
end;
|
||
in_lo_long,in_hi_long:
|
||
begin
|
||
if p^.registers32<1 then
|
||
p^.registers32:=1;
|
||
p^.resulttype:=u16bitdef;
|
||
p^.location.loc:=LOC_REGISTER;
|
||
end;
|
||
in_sizeof_x:
|
||
begin
|
||
if p^.registers32<1 then
|
||
p^.registers32:=1;
|
||
p^.resulttype:=s32bitdef;
|
||
p^.location.loc:=LOC_REGISTER;
|
||
end;
|
||
in_typeof_x:
|
||
begin
|
||
if p^.registers32<1 then
|
||
p^.registers32:=1;
|
||
p^.location.loc:=LOC_REGISTER;
|
||
p^.resulttype:=voidpointerdef;
|
||
end;
|
||
in_ord_x:
|
||
begin
|
||
if (p^.left^.treetype=ordconstn) then
|
||
begin
|
||
hp:=genordinalconstnode(p^.left^.value,s32bitdef);
|
||
disposetree(p);
|
||
p:=hp;
|
||
firstpass(p);
|
||
end
|
||
else
|
||
begin
|
||
if (p^.left^.resulttype^.deftype=orddef) then
|
||
if (porddef(p^.left^.resulttype)^.typ in [uchar,bool8bit]) then
|
||
begin
|
||
if porddef(p^.left^.resulttype)^.typ=bool8bit then
|
||
begin
|
||
hp:=gentypeconvnode(p^.left,u8bitdef);
|
||
putnode(p);
|
||
p:=hp;
|
||
p^.convtyp:=tc_bool_2_int;
|
||
p^.explizit:=true;
|
||
firstpass(p);
|
||
end
|
||
else
|
||
begin
|
||
hp:=gentypeconvnode(p^.left,u8bitdef);
|
||
putnode(p);
|
||
p:=hp;
|
||
p^.explizit:=true;
|
||
firstpass(p);
|
||
end;
|
||
end
|
||
{ can this happen ? }
|
||
else if (porddef(p^.left^.resulttype)^.typ=uvoid) then
|
||
Message(sym_e_type_mismatch)
|
||
else
|
||
{ all other orddef need no transformation }
|
||
begin
|
||
hp:=p^.left;
|
||
putnode(p);
|
||
p:=hp;
|
||
end
|
||
else if (p^.left^.resulttype^.deftype=enumdef) then
|
||
begin
|
||
hp:=gentypeconvnode(p^.left,s32bitdef);
|
||
putnode(p);
|
||
p:=hp;
|
||
p^.explizit:=true;
|
||
firstpass(p);
|
||
end
|
||
else
|
||
begin
|
||
{ can anything else be ord() ?}
|
||
Message(sym_e_type_mismatch);
|
||
end;
|
||
end;
|
||
end;
|
||
in_chr_byte:
|
||
begin
|
||
hp:=gentypeconvnode(p^.left,cchardef);
|
||
putnode(p);
|
||
p:=hp;
|
||
p^.explizit:=true;
|
||
firstpass(p);
|
||
end;
|
||
in_length_string:
|
||
begin
|
||
{$ifdef UseAnsiString}
|
||
if is_ansistring(p^.left^.resulttype) then
|
||
p^.resulttype:=s32bitdef
|
||
else
|
||
{$endif UseAnsiString}
|
||
p^.resulttype:=u8bitdef;
|
||
{ wer don't need string conversations here }
|
||
if (p^.left^.treetype=typeconvn) and
|
||
(p^.left^.left^.resulttype^.deftype=stringdef) then
|
||
begin
|
||
hp:=p^.left^.left;
|
||
putnode(p^.left);
|
||
p^.left:=hp;
|
||
end;
|
||
|
||
{ evalutes length of constant strings direct }
|
||
if (p^.left^.treetype=stringconstn) then
|
||
begin
|
||
{$ifdef UseAnsiString}
|
||
hp:=genordinalconstnode(p^.left^.length,s32bitdef);
|
||
{$else UseAnsiString}
|
||
hp:=genordinalconstnode(length(p^.left^.values^),s32bitdef);
|
||
{$endif UseAnsiString}
|
||
disposetree(p);
|
||
firstpass(hp);
|
||
p:=hp;
|
||
end;
|
||
|
||
end;
|
||
in_assigned_x:
|
||
begin
|
||
p^.resulttype:=booldef;
|
||
p^.location.loc:=LOC_FLAGS;
|
||
end;
|
||
in_pred_x,
|
||
in_succ_x:
|
||
begin
|
||
p^.resulttype:=p^.left^.resulttype;
|
||
p^.location.loc:=LOC_REGISTER;
|
||
if not is_ordinal(p^.resulttype) then
|
||
Message(sym_e_type_mismatch)
|
||
else
|
||
begin
|
||
if (p^.resulttype^.deftype=enumdef) and
|
||
(penumdef(p^.resulttype)^.has_jumps) then
|
||
begin
|
||
Message(parser_e_succ_and_pred_enums_with_assign_not_possible);
|
||
end
|
||
else if p^.left^.treetype=ordconstn then
|
||
begin
|
||
if p^.inlinenumber=in_pred_x then
|
||
hp:=genordinalconstnode(p^.left^.value+1,
|
||
p^.left^.resulttype)
|
||
else
|
||
hp:=genordinalconstnode(p^.left^.value-1,
|
||
p^.left^.resulttype);
|
||
disposetree(p);
|
||
firstpass(hp);
|
||
p:=hp;
|
||
end;
|
||
end;
|
||
end;
|
||
in_inc_x,
|
||
in_dec_x:
|
||
begin
|
||
p^.resulttype:=voiddef;
|
||
if assigned(p^.left) then
|
||
begin
|
||
firstcallparan(p^.left,nil);
|
||
if codegenerror then
|
||
exit;
|
||
{ first param must be var }
|
||
if not (p^.left^.left^.location.loc in [LOC_MEM,LOC_REFERENCE]) then
|
||
Message(cg_e_illegal_expression);
|
||
{ check type }
|
||
if (p^.left^.resulttype^.deftype in [enumdef,pointerdef]) or
|
||
((p^.left^.resulttype^.deftype=orddef) and
|
||
(porddef(p^.left^.resulttype)^.typ in [uchar,bool8bit,u8bit,s8bit,
|
||
bool16bit,u16bit,s16bit,bool32bit,u32bit,s32bit])) then
|
||
begin
|
||
{ two paras ? }
|
||
if assigned(p^.left^.right) then
|
||
begin
|
||
{ insert a type conversion }
|
||
{ the second param is always longint }
|
||
p^.left^.right^.left:=gentypeconvnode(p^.left^.right^.left,s32bitdef);
|
||
{ check the type conversion }
|
||
firstpass(p^.left^.right^.left);
|
||
if assigned(p^.left^.right^.right) then
|
||
Message(cg_e_illegal_expression);
|
||
end;
|
||
end
|
||
else
|
||
Message(sym_e_type_mismatch);
|
||
end
|
||
else
|
||
Message(sym_e_type_mismatch);
|
||
end;
|
||
in_read_x,
|
||
in_readln_x,
|
||
in_write_x,
|
||
in_writeln_x :
|
||
begin
|
||
{ needs a call }
|
||
procinfo.flags:=procinfo.flags or pi_do_call;
|
||
p^.resulttype:=voiddef;
|
||
{ we must know if it is a typed file or not }
|
||
{ but we must first do the firstpass for it }
|
||
file_is_typed:=false;
|
||
if assigned(p^.left) then
|
||
begin
|
||
firstcallparan(p^.left,nil);
|
||
{ now we can check }
|
||
hp:=p^.left;
|
||
while assigned(hp^.right) do
|
||
hp:=hp^.right;
|
||
{ if resulttype is not assigned, then automatically }
|
||
{ file is not typed. }
|
||
if assigned(hp) and assigned(hp^.resulttype) then
|
||
Begin
|
||
if (hp^.resulttype^.deftype=filedef) and
|
||
(pfiledef(hp^.resulttype)^.filetype=ft_typed) then
|
||
begin
|
||
file_is_typed:=true;
|
||
{ test the type here
|
||
so we can use a trick in cgi386 (PM) }
|
||
hpp:=p^.left;
|
||
while (hpp<>hp) do
|
||
begin
|
||
{ should we allow type conversion ? (PM)
|
||
if not isconvertable(hpp^.resulttype,
|
||
pfiledef(hp^.resulttype)^.typed_as,convtyp,hpp^.treetype) then
|
||
Message(sym_e_type_mismatch);
|
||
if not(is_equal(hpp^.resulttype,pfiledef(hp^.resulttype)^.typed_as)) then
|
||
begin
|
||
hpp^.left:=gentypeconvnode(hpp^.left,pfiledef(hp^.resulttype)^.typed_as);
|
||
end; }
|
||
if not is_equal(hpp^.resulttype,pfiledef(hp^.resulttype)^.typed_as) then
|
||
Message(sym_e_type_mismatch);
|
||
hpp:=hpp^.right;
|
||
end;
|
||
{ once again for typeconversions }
|
||
firstcallparan(p^.left,nil);
|
||
end;
|
||
end; { endif assigned(hp) }
|
||
{ insert type conversions for write(ln) }
|
||
if (not file_is_typed) and
|
||
((p^.inlinenumber=in_write_x) or (p^.inlinenumber=in_writeln_x)) then
|
||
begin
|
||
hp:=p^.left;
|
||
while assigned(hp) do
|
||
begin
|
||
if assigned(hp^.left^.resulttype) then
|
||
begin
|
||
if hp^.left^.resulttype^.deftype=floatdef then
|
||
begin
|
||
isreal:=true;
|
||
end
|
||
else if hp^.left^.resulttype^.deftype=orddef then
|
||
case porddef(hp^.left^.resulttype)^.typ of
|
||
u8bit,s8bit,
|
||
u16bit,s16bit : hp^.left:=gentypeconvnode(hp^.left,s32bitdef);
|
||
bool16bit,bool32bit : hp^.left:=gentypeconvnode(hp^.left,booldef);
|
||
end
|
||
{ but we convert only if the first index<>0, because in this case }
|
||
{ we have a ASCIIZ string }
|
||
else if (hp^.left^.resulttype^.deftype=arraydef) and
|
||
(parraydef(hp^.left^.resulttype)^.lowrange<>0) and
|
||
(parraydef(hp^.left^.resulttype)^.definition^.deftype=orddef) and
|
||
(porddef(parraydef(hp^.left^.resulttype)^.definition)^.typ=uchar) then
|
||
hp^.left:=gentypeconvnode(hp^.left,cstringdef);
|
||
end;
|
||
hp:=hp^.right;
|
||
end;
|
||
end;
|
||
{ pass all parameters again }
|
||
firstcallparan(p^.left,nil);
|
||
end;
|
||
end;
|
||
in_settextbuf_file_x :
|
||
begin
|
||
{ warning here p^.left is the callparannode
|
||
not the argument directly }
|
||
{ p^.left^.left is text var }
|
||
{ p^.left^.right^.left is the buffer var }
|
||
{ firstcallparan(p^.left,nil);
|
||
already done in firstcalln }
|
||
{ now we know the type of buffer }
|
||
getsymonlyin(systemunit,'SETTEXTBUF');
|
||
hp:=gencallnode(pprocsym(srsym),systemunit);
|
||
hp^.left:=gencallparanode(
|
||
genordinalconstnode(p^.left^.left^.resulttype^.size,s32bitdef),p^.left);
|
||
putnode(p);
|
||
p:=hp;
|
||
firstpass(p);
|
||
end;
|
||
{ the firstpass of the arg has been done in firstcalln ? }
|
||
in_reset_typedfile,in_rewrite_typedfile :
|
||
begin
|
||
procinfo.flags:=procinfo.flags or pi_do_call;
|
||
{ to be sure the right definition is loaded }
|
||
p^.left^.resulttype:=nil;
|
||
firstload(p^.left);
|
||
p^.resulttype:=voiddef;
|
||
end;
|
||
in_str_x_string :
|
||
begin
|
||
procinfo.flags:=procinfo.flags or pi_do_call;
|
||
p^.resulttype:=voiddef;
|
||
if assigned(p^.left) then
|
||
begin
|
||
hp:=p^.left^.right;
|
||
{ first pass just the string for first local use }
|
||
must_be_valid:=false;
|
||
count_ref:=true;
|
||
p^.left^.right:=nil;
|
||
firstcallparan(p^.left,nil);
|
||
must_be_valid:=true;
|
||
p^.left^.right:=hp;
|
||
firstcallparan(p^.left^.right,nil);
|
||
hp:=p^.left;
|
||
isreal:=false;
|
||
{ valid string ? }
|
||
if not assigned(hp) or
|
||
(hp^.left^.resulttype^.deftype<>stringdef) or
|
||
(hp^.right=nil) or
|
||
(hp^.left^.location.loc<>LOC_REFERENCE) then
|
||
Message(cg_e_illegal_expression);
|
||
{ !!!! check length of string }
|
||
|
||
while assigned(hp^.right) do hp:=hp^.right;
|
||
|
||
{ check and convert the first param }
|
||
if hp^.is_colon_para then
|
||
Message(cg_e_illegal_expression)
|
||
else if hp^.resulttype^.deftype=orddef then
|
||
case porddef(hp^.left^.resulttype)^.typ of
|
||
u8bit,s8bit,
|
||
u16bit,s16bit :
|
||
hp^.left:=gentypeconvnode(hp^.left,s32bitdef);
|
||
end
|
||
else if hp^.resulttype^.deftype=floatdef then
|
||
begin
|
||
isreal:=true;
|
||
end
|
||
else Message(cg_e_illegal_expression);
|
||
|
||
{ some format options ? }
|
||
hp:=p^.left^.right;
|
||
if assigned(hp) and hp^.is_colon_para then
|
||
begin
|
||
hp^.left:=gentypeconvnode(hp^.left,s32bitdef);
|
||
hp:=hp^.right;
|
||
end;
|
||
if assigned(hp) and hp^.is_colon_para then
|
||
begin
|
||
if isreal then
|
||
hp^.left:=gentypeconvnode(hp^.left,s32bitdef)
|
||
else
|
||
Message(parser_e_illegal_colon_qualifier);
|
||
hp:=hp^.right;
|
||
end;
|
||
|
||
{ for first local use }
|
||
must_be_valid:=false;
|
||
count_ref:=true;
|
||
if assigned(hp) then
|
||
firstcallparan(hp,nil);
|
||
end
|
||
else
|
||
Message(parser_e_illegal_parameter_list);
|
||
{ check params once more }
|
||
if codegenerror then
|
||
exit;
|
||
must_be_valid:=true;
|
||
firstcallparan(p^.left,nil);
|
||
end;
|
||
in_include_x_y,
|
||
in_exclude_x_y:
|
||
begin
|
||
p^.resulttype:=voiddef;
|
||
if assigned(p^.left) then
|
||
begin
|
||
firstcallparan(p^.left,nil);
|
||
p^.registers32:=p^.left^.registers32;
|
||
p^.registersfpu:=p^.left^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=p^.left^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
{ first param must be var }
|
||
if (p^.left^.left^.location.loc<>LOC_REFERENCE) and
|
||
(p^.left^.left^.location.loc<>LOC_CREGISTER) then
|
||
Message(cg_e_illegal_expression);
|
||
{ check type }
|
||
if (p^.left^.resulttype^.deftype=setdef) then
|
||
begin
|
||
{ two paras ? }
|
||
if assigned(p^.left^.right) then
|
||
begin
|
||
{ insert a type conversion }
|
||
{ to the type of the set elements }
|
||
p^.left^.right^.left:=gentypeconvnode(
|
||
p^.left^.right^.left,
|
||
psetdef(p^.left^.resulttype)^.setof);
|
||
{ check the type conversion }
|
||
firstpass(p^.left^.right^.left);
|
||
{ only three parameters are allowed }
|
||
if assigned(p^.left^.right^.right) then
|
||
Message(cg_e_illegal_expression);
|
||
end;
|
||
end
|
||
else
|
||
Message(sym_e_type_mismatch);
|
||
end
|
||
else
|
||
Message(sym_e_type_mismatch);
|
||
end;
|
||
in_low_x,in_high_x:
|
||
begin
|
||
if p^.left^.treetype in [typen,loadn] then
|
||
begin
|
||
case p^.left^.resulttype^.deftype of
|
||
orddef,enumdef:
|
||
begin
|
||
do_lowhigh(p^.left^.resulttype);
|
||
firstpass(p);
|
||
end;
|
||
setdef:
|
||
begin
|
||
do_lowhigh(Psetdef(p^.left^.resulttype)^.setof);
|
||
firstpass(p);
|
||
end;
|
||
arraydef:
|
||
begin
|
||
if is_open_array(p^.left^.resulttype) then
|
||
begin
|
||
if p^.inlinenumber=in_low_x then
|
||
begin
|
||
hp:=genordinalconstnode(Parraydef(p^.left^.resulttype)^.lowrange,s32bitdef);
|
||
disposetree(p);
|
||
p:=hp;
|
||
firstpass(p);
|
||
end
|
||
else
|
||
begin
|
||
p^.resulttype:=s32bitdef;
|
||
p^.registers32:=max(1,
|
||
p^.registers32);
|
||
p^.location.loc:=LOC_REGISTER;
|
||
end;
|
||
end
|
||
else
|
||
begin
|
||
if p^.inlinenumber=in_low_x then
|
||
hp:=genordinalconstnode(Parraydef(p^.left^.resulttype)^.lowrange,s32bitdef)
|
||
else
|
||
hp:=genordinalconstnode(Parraydef(p^.left^.resulttype)^.highrange,s32bitdef);
|
||
disposetree(p);
|
||
p:=hp;
|
||
firstpass(p);
|
||
end;
|
||
end;
|
||
stringdef:
|
||
begin
|
||
if p^.inlinenumber=in_low_x then
|
||
hp:=genordinalconstnode(0,u8bitdef)
|
||
else
|
||
hp:=genordinalconstnode(Pstringdef(p^.left^.resulttype)^.len,u8bitdef);
|
||
disposetree(p);
|
||
p:=hp;
|
||
firstpass(p);
|
||
end;
|
||
else
|
||
Message(sym_e_type_mismatch);
|
||
end;
|
||
end
|
||
else
|
||
Message(parser_e_varid_or_typeid_expected);
|
||
end
|
||
else internalerror(8);
|
||
end;
|
||
must_be_valid:=store_valid;
|
||
count_ref:=store_count_ref;
|
||
end;
|
||
|
||
procedure firstsubscriptn(var p : ptree);
|
||
|
||
begin
|
||
firstpass(p^.left);
|
||
if codegenerror then
|
||
begin
|
||
p^.resulttype:=generrordef;
|
||
exit;
|
||
end;
|
||
|
||
p^.resulttype:=p^.vs^.definition;
|
||
{ this must be done in the parser
|
||
if count_ref and not must_be_valid then
|
||
if (p^.vs^.properties and sp_protected)<>0 then
|
||
Message(parser_e_cant_write_protected_member);
|
||
}
|
||
p^.registers32:=p^.left^.registers32;
|
||
p^.registersfpu:=p^.left^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=p^.left^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
{ classes must be dereferenced implicit }
|
||
if (p^.left^.resulttype^.deftype=objectdef) and
|
||
pobjectdef(p^.left^.resulttype)^.isclass then
|
||
begin
|
||
if p^.registers32=0 then
|
||
p^.registers32:=1;
|
||
p^.location.loc:=LOC_REFERENCE;
|
||
end
|
||
else
|
||
begin
|
||
if (p^.left^.location.loc<>LOC_MEM) and
|
||
(p^.left^.location.loc<>LOC_REFERENCE) then
|
||
Message(cg_e_illegal_expression);
|
||
set_location(p^.location,p^.left^.location);
|
||
end;
|
||
end;
|
||
|
||
procedure firstselfn(var p : ptree);
|
||
|
||
begin
|
||
if (p^.resulttype^.deftype=classrefdef) or
|
||
((p^.resulttype^.deftype=objectdef)
|
||
and pobjectdef(p^.resulttype)^.isclass
|
||
) then
|
||
p^.location.loc:=LOC_REGISTER
|
||
else
|
||
p^.location.loc:=LOC_REFERENCE;
|
||
end;
|
||
|
||
procedure firsttypen(var p : ptree);
|
||
|
||
begin
|
||
{ DM: Why not allowed? For example: low(word) results in a type
|
||
id of word.
|
||
error(typeid_here_not_allowed);}
|
||
end;
|
||
|
||
procedure firsthnewn(var p : ptree);
|
||
|
||
begin
|
||
end;
|
||
|
||
procedure firsthdisposen(var p : ptree);
|
||
|
||
begin
|
||
firstpass(p^.left);
|
||
|
||
if codegenerror then
|
||
exit;
|
||
|
||
p^.registers32:=p^.left^.registers32;
|
||
p^.registersfpu:=p^.left^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=p^.left^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
if p^.registers32<1 then
|
||
p^.registers32:=1;
|
||
{
|
||
if p^.left^.location.loc<>LOC_REFERENCE then
|
||
Message(cg_e_illegal_expression);
|
||
}
|
||
p^.location.loc:=LOC_REFERENCE;
|
||
p^.resulttype:=ppointerdef(p^.left^.resulttype)^.definition;
|
||
end;
|
||
|
||
procedure firstnewn(var p : ptree);
|
||
|
||
begin
|
||
{ Standardeinleitung }
|
||
firstpass(p^.left);
|
||
|
||
if codegenerror then
|
||
exit;
|
||
p^.registers32:=p^.left^.registers32;
|
||
p^.registersfpu:=p^.left^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=p^.left^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
{ result type is already set }
|
||
procinfo.flags:=procinfo.flags or pi_do_call;
|
||
p^.location.loc:=LOC_REGISTER;
|
||
end;
|
||
|
||
procedure firstsimplenewdispose(var p : ptree);
|
||
|
||
begin
|
||
{ this cannot be in a register !! }
|
||
make_not_regable(p^.left);
|
||
|
||
firstpass(p^.left);
|
||
|
||
{ check the type }
|
||
if (p^.left^.resulttype=nil) or (p^.left^.resulttype^.deftype<>pointerdef) then
|
||
Message(parser_e_pointer_type_expected);
|
||
|
||
if (p^.left^.location.loc<>LOC_REFERENCE) {and
|
||
(p^.left^.location.loc<>LOC_CREGISTER)} then
|
||
Message(cg_e_illegal_expression);
|
||
|
||
p^.registers32:=p^.left^.registers32;
|
||
p^.registersfpu:=p^.left^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=p^.left^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
p^.resulttype:=voiddef;
|
||
procinfo.flags:=procinfo.flags or pi_do_call;
|
||
end;
|
||
|
||
|
||
procedure firstsetele(var p : ptree);
|
||
begin
|
||
firstpass(p^.left);
|
||
if codegenerror then
|
||
exit;
|
||
|
||
if assigned(p^.right) then
|
||
begin
|
||
firstpass(p^.right);
|
||
if codegenerror then
|
||
exit;
|
||
end;
|
||
|
||
calcregisters(p,0,0,0);
|
||
p^.resulttype:=p^.left^.resulttype;
|
||
set_location(p^.location,p^.left^.location);
|
||
end;
|
||
|
||
|
||
procedure firstsetcons(var p : ptree);
|
||
begin
|
||
p^.location.loc:=LOC_MEM;
|
||
end;
|
||
|
||
|
||
procedure firstin(var p : ptree);
|
||
|
||
begin
|
||
p^.location.loc:=LOC_FLAGS;
|
||
p^.resulttype:=booldef;
|
||
|
||
firstpass(p^.right);
|
||
if codegenerror then
|
||
exit;
|
||
|
||
if p^.right^.resulttype^.deftype<>setdef then
|
||
Message(sym_e_set_expected);
|
||
|
||
firstpass(p^.left);
|
||
if codegenerror then
|
||
exit;
|
||
|
||
p^.left:=gentypeconvnode(p^.left,psetdef(p^.right^.resulttype)^.setof);
|
||
|
||
firstpass(p^.left);
|
||
if codegenerror then
|
||
exit;
|
||
|
||
left_right_max(p);
|
||
{ this is not allways true due to optimization }
|
||
{ but if we don't set this we get problems with optimizing self code }
|
||
if psetdef(p^.right^.resulttype)^.settype<>smallset then
|
||
procinfo.flags:=procinfo.flags or pi_do_call;
|
||
end;
|
||
|
||
procedure firststatement(var p : ptree);
|
||
|
||
begin
|
||
{ left is the next statement in the list }
|
||
p^.resulttype:=voiddef;
|
||
|
||
{ no temps over several statements }
|
||
cleartempgen;
|
||
{ right is the statement itself calln assignn or a complex one }
|
||
firstpass(p^.right);
|
||
if (not (cs_extsyntax in aktmoduleswitches)) and
|
||
assigned(p^.right^.resulttype) and
|
||
(p^.right^.resulttype<>pdef(voiddef)) then
|
||
Message(cg_e_illegal_expression);
|
||
if codegenerror then
|
||
exit;
|
||
p^.registers32:=p^.right^.registers32;
|
||
p^.registersfpu:=p^.right^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=p^.right^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
{ left is the next in the list }
|
||
firstpass(p^.left);
|
||
if codegenerror then
|
||
exit;
|
||
if p^.right^.registers32>p^.registers32 then
|
||
p^.registers32:=p^.right^.registers32;
|
||
if p^.right^.registersfpu>p^.registersfpu then
|
||
p^.registersfpu:=p^.right^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
if p^.right^.registersmmx>p^.registersmmx then
|
||
p^.registersmmx:=p^.right^.registersmmx;
|
||
{$endif}
|
||
|
||
end;
|
||
|
||
procedure firstblock(var p : ptree);
|
||
|
||
var
|
||
hp : ptree;
|
||
count : longint;
|
||
|
||
begin
|
||
count:=0;
|
||
hp:=p^.left;
|
||
while assigned(hp) do
|
||
begin
|
||
if cs_regalloc in aktglobalswitches then
|
||
begin
|
||
{ Codeumstellungen }
|
||
|
||
{ Funktionsresultate an exit anh<6E>ngen }
|
||
{ this is wrong for string or other complex
|
||
result types !!! }
|
||
if ret_in_acc(procinfo.retdef) and
|
||
assigned(hp^.left) and
|
||
(hp^.left^.right^.treetype=exitn) and
|
||
(hp^.right^.treetype=assignn) and
|
||
(hp^.right^.left^.treetype=funcretn) then
|
||
begin
|
||
if assigned(hp^.left^.right^.left) then
|
||
Message(cg_n_inefficient_code)
|
||
else
|
||
begin
|
||
hp^.left^.right^.left:=getcopy(hp^.right^.right);
|
||
disposetree(hp^.right);
|
||
hp^.right:=nil;
|
||
end;
|
||
end
|
||
{ warning if unreachable code occurs and elimate this }
|
||
else if (hp^.right^.treetype in
|
||
[exitn,breakn,continuen,goton]) and
|
||
assigned(hp^.left) and
|
||
(hp^.left^.treetype<>labeln) then
|
||
begin
|
||
{ use correct line number }
|
||
aktfilepos:=hp^.left^.fileinfo;
|
||
disposetree(hp^.left);
|
||
hp^.left:=nil;
|
||
Message(cg_w_unreachable_code);
|
||
{ old lines }
|
||
aktfilepos:=hp^.right^.fileinfo;
|
||
end;
|
||
end;
|
||
if assigned(hp^.right) then
|
||
begin
|
||
cleartempgen;
|
||
firstpass(hp^.right);
|
||
if (not (cs_extsyntax in aktmoduleswitches)) and
|
||
assigned(hp^.right^.resulttype) and
|
||
(hp^.right^.resulttype<>pdef(voiddef)) then
|
||
Message(cg_e_illegal_expression);
|
||
if codegenerror then
|
||
exit;
|
||
|
||
hp^.registers32:=hp^.right^.registers32;
|
||
hp^.registersfpu:=hp^.right^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
hp^.registersmmx:=hp^.right^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
end
|
||
else
|
||
hp^.registers32:=0;
|
||
|
||
if hp^.registers32>p^.registers32 then
|
||
p^.registers32:=hp^.registers32;
|
||
if hp^.registersfpu>p^.registersfpu then
|
||
p^.registersfpu:=hp^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
if hp^.registersmmx>p^.registersmmx then
|
||
p^.registersmmx:=hp^.registersmmx;
|
||
{$endif}
|
||
inc(count);
|
||
hp:=hp^.left;
|
||
end;
|
||
{ p^.registers32:=round(p^.registers32/count); }
|
||
end;
|
||
|
||
procedure first_while_repeat(var p : ptree);
|
||
|
||
var
|
||
old_t_times : longint;
|
||
|
||
begin
|
||
old_t_times:=t_times;
|
||
|
||
{ Registergewichtung bestimmen }
|
||
if not(cs_littlesize in aktglobalswitches ) then
|
||
t_times:=t_times*8;
|
||
|
||
cleartempgen;
|
||
must_be_valid:=true;
|
||
firstpass(p^.left);
|
||
if codegenerror then
|
||
exit;
|
||
if not((p^.left^.resulttype^.deftype=orddef) and
|
||
(porddef(p^.left^.resulttype)^.typ=bool8bit)) then
|
||
begin
|
||
Message(sym_e_type_mismatch);
|
||
exit;
|
||
end;
|
||
|
||
p^.registers32:=p^.left^.registers32;
|
||
p^.registersfpu:=p^.left^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=p^.left^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
|
||
{ loop instruction }
|
||
if assigned(p^.right) then
|
||
begin
|
||
cleartempgen;
|
||
firstpass(p^.right);
|
||
if codegenerror then
|
||
exit;
|
||
|
||
if p^.registers32<p^.right^.registers32 then
|
||
p^.registers32:=p^.right^.registers32;
|
||
if p^.registersfpu<p^.right^.registersfpu then
|
||
p^.registersfpu:=p^.right^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
if p^.registersmmx<p^.right^.registersmmx then
|
||
p^.registersmmx:=p^.right^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
end;
|
||
|
||
t_times:=old_t_times;
|
||
end;
|
||
|
||
procedure firstif(var p : ptree);
|
||
|
||
var
|
||
old_t_times : longint;
|
||
hp : ptree;
|
||
|
||
begin
|
||
old_t_times:=t_times;
|
||
|
||
cleartempgen;
|
||
must_be_valid:=true;
|
||
firstpass(p^.left);
|
||
if codegenerror then
|
||
exit;
|
||
if not((p^.left^.resulttype^.deftype=orddef) and
|
||
(porddef(p^.left^.resulttype)^.typ in [bool8bit,bool16bit,bool32bit])) then
|
||
begin
|
||
Message(sym_e_type_mismatch);
|
||
exit;
|
||
end;
|
||
|
||
p^.registers32:=p^.left^.registers32;
|
||
p^.registersfpu:=p^.left^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=p^.left^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
|
||
{ determines registers weigths }
|
||
if not(cs_littlesize in aktglobalswitches) then
|
||
t_times:=t_times div 2;
|
||
if t_times=0 then
|
||
t_times:=1;
|
||
|
||
{ if path }
|
||
if assigned(p^.right) then
|
||
begin
|
||
cleartempgen;
|
||
firstpass(p^.right);
|
||
if codegenerror then
|
||
exit;
|
||
|
||
if p^.registers32<p^.right^.registers32 then
|
||
p^.registers32:=p^.right^.registers32;
|
||
if p^.registersfpu<p^.right^.registersfpu then
|
||
p^.registersfpu:=p^.right^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
if p^.registersmmx<p^.right^.registersmmx then
|
||
p^.registersmmx:=p^.right^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
end;
|
||
|
||
{ else path }
|
||
if assigned(p^.t1) then
|
||
begin
|
||
cleartempgen;
|
||
firstpass(p^.t1);
|
||
if codegenerror then
|
||
exit;
|
||
|
||
if p^.registers32<p^.t1^.registers32 then
|
||
p^.registers32:=p^.t1^.registers32;
|
||
if p^.registersfpu<p^.t1^.registersfpu then
|
||
p^.registersfpu:=p^.t1^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
if p^.registersmmx<p^.t1^.registersmmx then
|
||
p^.registersmmx:=p^.t1^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
end;
|
||
if p^.left^.treetype=ordconstn then
|
||
begin
|
||
{ optimize }
|
||
if p^.left^.value=1 then
|
||
begin
|
||
disposetree(p^.left);
|
||
hp:=p^.right;
|
||
disposetree(p^.t1);
|
||
{ we cannot set p to nil !!! }
|
||
if assigned(hp) then
|
||
begin
|
||
putnode(p);
|
||
p:=hp;
|
||
end
|
||
else
|
||
begin
|
||
p^.left:=nil;
|
||
p^.t1:=nil;
|
||
p^.treetype:=nothingn;
|
||
end;
|
||
end
|
||
else
|
||
begin
|
||
disposetree(p^.left);
|
||
hp:=p^.t1;
|
||
disposetree(p^.right);
|
||
{ we cannot set p to nil !!! }
|
||
if assigned(hp) then
|
||
begin
|
||
putnode(p);
|
||
p:=hp;
|
||
end
|
||
else
|
||
begin
|
||
p^.left:=nil;
|
||
p^.right:=nil;
|
||
p^.treetype:=nothingn;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
t_times:=old_t_times;
|
||
end;
|
||
|
||
procedure firstexitn(var p : ptree);
|
||
|
||
begin
|
||
if assigned(p^.left) then
|
||
begin
|
||
firstpass(p^.left);
|
||
p^.registers32:=p^.left^.registers32;
|
||
p^.registersfpu:=p^.left^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=p^.left^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
|
||
end;
|
||
end;
|
||
|
||
procedure firstfor(var p : ptree);
|
||
|
||
var
|
||
old_t_times : longint;
|
||
|
||
begin
|
||
{ Registergewichtung bestimmen
|
||
(nicht genau), }
|
||
old_t_times:=t_times;
|
||
if not(cs_littlesize in aktglobalswitches) then
|
||
t_times:=t_times*8;
|
||
|
||
cleartempgen;
|
||
if p^.t1<>nil then
|
||
firstpass(p^.t1);
|
||
|
||
p^.registers32:=p^.t1^.registers32;
|
||
p^.registersfpu:=p^.t1^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=p^.left^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
|
||
if p^.left^.treetype<>assignn then
|
||
Message(cg_e_illegal_expression);
|
||
|
||
{ Laufvariable retten }
|
||
p^.t2:=getcopy(p^.left^.left);
|
||
|
||
{ Check count var }
|
||
if (p^.t2^.treetype<>loadn) then
|
||
Message(cg_e_illegal_count_var);
|
||
|
||
if (not(is_ordinal(p^.t2^.resulttype))) then
|
||
Message(parser_e_ordinal_expected);
|
||
|
||
cleartempgen;
|
||
must_be_valid:=false;
|
||
firstpass(p^.left);
|
||
must_be_valid:=true;
|
||
if p^.left^.registers32>p^.registers32 then
|
||
p^.registers32:=p^.left^.registers32;
|
||
if p^.left^.registersfpu>p^.registersfpu then
|
||
p^.registersfpu:=p^.left^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
if p^.left^.registersmmx>p^.registersmmx then
|
||
p^.registersmmx:=p^.left^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
cleartempgen;
|
||
firstpass(p^.t2);
|
||
if p^.t2^.registers32>p^.registers32 then
|
||
p^.registers32:=p^.t2^.registers32;
|
||
if p^.t2^.registersfpu>p^.registersfpu then
|
||
p^.registersfpu:=p^.t2^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
if p^.t2^.registersmmx>p^.registersmmx then
|
||
p^.registersmmx:=p^.t2^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
|
||
cleartempgen;
|
||
firstpass(p^.right);
|
||
if p^.right^.treetype<>ordconstn then
|
||
begin
|
||
p^.right:=gentypeconvnode(p^.right,p^.t2^.resulttype);
|
||
cleartempgen;
|
||
firstpass(p^.right);
|
||
end;
|
||
|
||
if p^.right^.registers32>p^.registers32 then
|
||
p^.registers32:=p^.right^.registers32;
|
||
if p^.right^.registersfpu>p^.registersfpu then
|
||
p^.registersfpu:=p^.right^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
if p^.right^.registersmmx>p^.registersmmx then
|
||
p^.registersmmx:=p^.right^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
t_times:=old_t_times;
|
||
end;
|
||
|
||
procedure firstasm(var p : ptree);
|
||
|
||
begin
|
||
{ it's a f... to determine the used registers }
|
||
{ should be done by getnode
|
||
I think also, that all values should be set to their maximum (FK)
|
||
p^.registers32:=0;
|
||
p^.registersfpu:=0;
|
||
p^.registersmmx:=0;
|
||
}
|
||
procinfo.flags:=procinfo.flags or pi_uses_asm;
|
||
end;
|
||
|
||
procedure firstgoto(var p : ptree);
|
||
|
||
begin
|
||
{
|
||
p^.registers32:=0;
|
||
p^.registersfpu:=0;
|
||
}
|
||
p^.resulttype:=voiddef;
|
||
end;
|
||
|
||
procedure firstlabel(var p : ptree);
|
||
|
||
begin
|
||
cleartempgen;
|
||
firstpass(p^.left);
|
||
p^.registers32:=p^.left^.registers32;
|
||
p^.registersfpu:=p^.left^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=p^.left^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
p^.resulttype:=voiddef;
|
||
end;
|
||
|
||
procedure firstcase(var p : ptree);
|
||
|
||
var
|
||
old_t_times : longint;
|
||
hp : ptree;
|
||
|
||
begin
|
||
{ evalutes the case expression }
|
||
cleartempgen;
|
||
must_be_valid:=true;
|
||
firstpass(p^.left);
|
||
if codegenerror then
|
||
exit;
|
||
p^.registers32:=p^.left^.registers32;
|
||
p^.registersfpu:=p^.left^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=p^.left^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
|
||
{ walk through all instructions }
|
||
|
||
{ estimates the repeat of each instruction }
|
||
old_t_times:=t_times;
|
||
if not(cs_littlesize in aktglobalswitches) then
|
||
begin
|
||
t_times:=t_times div case_count_labels(p^.nodes);
|
||
if t_times<1 then
|
||
t_times:=1;
|
||
end;
|
||
{ first case }
|
||
hp:=p^.right;
|
||
while assigned(hp) do
|
||
begin
|
||
cleartempgen;
|
||
firstpass(hp^.right);
|
||
|
||
{ searchs max registers }
|
||
if hp^.right^.registers32>p^.registers32 then
|
||
p^.registers32:=hp^.right^.registers32;
|
||
if hp^.right^.registersfpu>p^.registersfpu then
|
||
p^.registersfpu:=hp^.right^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
if hp^.right^.registersmmx>p^.registersmmx then
|
||
p^.registersmmx:=hp^.right^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
|
||
hp:=hp^.left;
|
||
end;
|
||
|
||
{ may be handle else tree }
|
||
if assigned(p^.elseblock) then
|
||
begin
|
||
cleartempgen;
|
||
firstpass(p^.elseblock);
|
||
if codegenerror then
|
||
exit;
|
||
if p^.registers32<p^.elseblock^.registers32 then
|
||
p^.registers32:=p^.elseblock^.registers32;
|
||
if p^.registersfpu<p^.elseblock^.registersfpu then
|
||
p^.registersfpu:=p^.elseblock^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
if p^.registersmmx<p^.elseblock^.registersmmx then
|
||
p^.registersmmx:=p^.elseblock^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
end;
|
||
t_times:=old_t_times;
|
||
|
||
{ there is one register required for the case expression }
|
||
if p^.registers32<1 then p^.registers32:=1;
|
||
end;
|
||
|
||
procedure firsttryexcept(var p : ptree);
|
||
|
||
begin
|
||
cleartempgen;
|
||
firstpass(p^.left);
|
||
|
||
{ on statements }
|
||
if assigned(p^.right) then
|
||
begin
|
||
cleartempgen;
|
||
firstpass(p^.right);
|
||
p^.registers32:=max(p^.registers32,p^.right^.registers32);
|
||
p^.registersfpu:=max(p^.registersfpu,p^.right^.registersfpu);
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=max(p^.registersmmx,p^.right^.registersmmx);
|
||
{$endif SUPPORT_MMX}
|
||
end;
|
||
{ else block }
|
||
if assigned(p^.t1) then
|
||
begin
|
||
firstpass(p^.t1);
|
||
p^.registers32:=max(p^.registers32,p^.t1^.registers32);
|
||
p^.registersfpu:=max(p^.registersfpu,p^.t1^.registersfpu);
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=max(p^.registersmmx,p^.t1^.registersmmx);
|
||
{$endif SUPPORT_MMX}
|
||
end;
|
||
end;
|
||
|
||
procedure firsttryfinally(var p : ptree);
|
||
|
||
begin
|
||
p^.resulttype:=voiddef;
|
||
cleartempgen;
|
||
must_be_valid:=true;
|
||
firstpass(p^.left);
|
||
|
||
cleartempgen;
|
||
must_be_valid:=true;
|
||
firstpass(p^.right);
|
||
if codegenerror then
|
||
exit;
|
||
left_right_max(p);
|
||
end;
|
||
|
||
procedure firstis(var p : ptree);
|
||
|
||
begin
|
||
firstpass(p^.left);
|
||
firstpass(p^.right);
|
||
|
||
if (p^.right^.resulttype^.deftype<>classrefdef) then
|
||
Message(sym_e_type_mismatch);
|
||
if codegenerror then
|
||
exit;
|
||
|
||
left_right_max(p);
|
||
|
||
{ left must be a class }
|
||
if (p^.left^.resulttype^.deftype<>objectdef) or
|
||
not(pobjectdef(p^.left^.resulttype)^.isclass) then
|
||
Message(sym_e_type_mismatch);
|
||
|
||
{ the operands must be related }
|
||
if (not(pobjectdef(p^.left^.resulttype)^.isrelated(
|
||
pobjectdef(pclassrefdef(p^.right^.resulttype)^.definition)))) and
|
||
(not(pobjectdef(pclassrefdef(p^.right^.resulttype)^.definition)^.isrelated(
|
||
pobjectdef(p^.left^.resulttype)))) then
|
||
Message(sym_e_type_mismatch);
|
||
|
||
p^.location.loc:=LOC_FLAGS;
|
||
p^.resulttype:=booldef;
|
||
end;
|
||
|
||
procedure firstas(var p : ptree);
|
||
|
||
begin
|
||
firstpass(p^.right);
|
||
firstpass(p^.left);
|
||
if (p^.right^.resulttype^.deftype<>classrefdef) then
|
||
Message(sym_e_type_mismatch);
|
||
|
||
if codegenerror then
|
||
exit;
|
||
|
||
left_right_max(p);
|
||
|
||
{ left must be a class }
|
||
if (p^.left^.resulttype^.deftype<>objectdef) or
|
||
not(pobjectdef(p^.left^.resulttype)^.isclass) then
|
||
Message(sym_e_type_mismatch);
|
||
|
||
{ the operands must be related }
|
||
if (not(pobjectdef(p^.left^.resulttype)^.isrelated(
|
||
pobjectdef(pclassrefdef(p^.right^.resulttype)^.definition)))) and
|
||
(not(pobjectdef(pclassrefdef(p^.right^.resulttype)^.definition)^.isrelated(
|
||
pobjectdef(p^.left^.resulttype)))) then
|
||
Message(sym_e_type_mismatch);
|
||
|
||
p^.location:=p^.left^.location;
|
||
p^.resulttype:=pclassrefdef(p^.right^.resulttype)^.definition;
|
||
end;
|
||
|
||
procedure firstloadvmt(var p : ptree);
|
||
|
||
begin
|
||
{ resulttype must be set !
|
||
p^.registersfpu:=0;
|
||
}
|
||
p^.registers32:=1;
|
||
p^.location.loc:=LOC_REGISTER;
|
||
end;
|
||
|
||
procedure firstraise(var p : ptree);
|
||
|
||
begin
|
||
p^.resulttype:=voiddef;
|
||
{
|
||
p^.registersfpu:=0;
|
||
p^.registers32:=0;
|
||
}
|
||
if assigned(p^.left) then
|
||
begin
|
||
firstpass(p^.left);
|
||
|
||
{ this must be a _class_ }
|
||
if (p^.left^.resulttype^.deftype<>objectdef) or
|
||
((pobjectdef(p^.left^.resulttype)^.options and oois_class)=0) then
|
||
Message(sym_e_type_mismatch);
|
||
|
||
p^.registersfpu:=p^.left^.registersfpu;
|
||
p^.registers32:=p^.left^.registers32;
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=p^.left^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
if assigned(p^.right) then
|
||
begin
|
||
firstpass(p^.right);
|
||
p^.right:=gentypeconvnode(p^.right,s32bitdef);
|
||
firstpass(p^.right);
|
||
left_right_max(p);
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
procedure firstwith(var p : ptree);
|
||
|
||
begin
|
||
if assigned(p^.left) and assigned(p^.right) then
|
||
begin
|
||
firstpass(p^.left);
|
||
if codegenerror then
|
||
exit;
|
||
|
||
firstpass(p^.right);
|
||
|
||
if codegenerror then
|
||
exit;
|
||
|
||
left_right_max(p);
|
||
p^.resulttype:=voiddef;
|
||
end
|
||
else
|
||
begin
|
||
{ optimization }
|
||
disposetree(p);
|
||
p:=nil;
|
||
end;
|
||
end;
|
||
|
||
procedure firstonn(var p : ptree);
|
||
|
||
begin
|
||
{ that's really an example procedure for a firstpass :) }
|
||
cleartempgen;
|
||
p^.resulttype:=voiddef;
|
||
p^.registers32:=0;
|
||
p^.registersfpu:=0;
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=0;
|
||
{$endif SUPPORT_MMX}
|
||
if assigned(p^.left) then
|
||
begin
|
||
firstpass(p^.left);
|
||
p^.registers32:=p^.left^.registers32;
|
||
p^.registersfpu:=p^.left^.registersfpu;
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=p^.left^.registersmmx;
|
||
{$endif SUPPORT_MMX}
|
||
end;
|
||
|
||
cleartempgen;
|
||
if assigned(p^.right) then
|
||
begin
|
||
firstpass(p^.right);
|
||
p^.registers32:=max(p^.registers32,p^.right^.registers32);
|
||
p^.registersfpu:=max(p^.registersfpu,p^.right^.registersfpu);
|
||
{$ifdef SUPPORT_MMX}
|
||
p^.registersmmx:=max(p^.registersmmx,p^.right^.registersmmx);
|
||
{$endif SUPPORT_MMX}
|
||
end;
|
||
end;
|
||
|
||
procedure firstprocinline(var p : ptree);
|
||
|
||
begin
|
||
{left contains the code in tree form }
|
||
{ but it has already been firstpassed }
|
||
{ so firstpass(p^.left); does not seem required }
|
||
{ might be required later if we change the arg handling !! }
|
||
end;
|
||
|
||
type
|
||
firstpassproc = procedure(var p : ptree);
|
||
|
||
procedure firstpass(var p : ptree);
|
||
|
||
(* 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.}
|
||
umminusn, {Represents a sign change (i.e. -2).}
|
||
asmn, {Represents an assembler node }
|
||
vecn, {Represents array indexing.}
|
||
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.}
|
||
setelen, {A set element (i.e. [a,b]).}
|
||
setconstrn, {A set constant (i.e. [1,2]).}
|
||
blockn, {A block of statements.}
|
||
statementn, {One statement in list 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.}
|
||
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 }
|
||
{ added for optimizations where we cannot suppress }
|
||
nothingn,
|
||
loadvmtn); {???.} *)
|
||
const
|
||
procedures : array[ttreetyp] of firstpassproc =
|
||
(firstadd,firstadd,firstadd,firstmoddiv,firstadd,
|
||
firstmoddiv,firstassignment,firstload,firstrange,
|
||
firstadd,firstadd,firstadd,firstadd,
|
||
firstadd,firstadd,firstin,firstadd,
|
||
firstadd,firstshlshr,firstshlshr,firstadd,
|
||
firstadd,firstsubscriptn,firstderef,firstaddr,firstdoubleaddr,
|
||
firstordconst,firsttypeconv,firstcalln,firstnothing,
|
||
firstrealconst,firstfixconst,firstumminus,firstasm,firstvecn,
|
||
firststringconst,firstfuncret,firstselfn,
|
||
firstnot,firstinline,firstniln,firsterror,
|
||
firsttypen,firsthnewn,firsthdisposen,firstnewn,
|
||
firstsimplenewdispose,firstsetele,firstsetcons,firstblock,
|
||
firststatement,firstnothing,firstif,firstnothing,
|
||
firstnothing,first_while_repeat,first_while_repeat,firstfor,
|
||
firstexitn,firstwith,firstcase,firstlabel,
|
||
firstgoto,firstsimplenewdispose,firsttryexcept,
|
||
firstraise,firstnothing,firsttryfinally,
|
||
firstonn,firstis,firstas,firstadd,
|
||
firstnothing,firstadd,firstprocinline,firstnothing,firstloadvmt);
|
||
|
||
var
|
||
oldcodegenerror : boolean;
|
||
oldlocalswitches : tlocalswitches;
|
||
oldpos : tfileposinfo;
|
||
{$ifdef extdebug}
|
||
str1,str2 : string;
|
||
oldp : ptree;
|
||
not_first : boolean;
|
||
{$endif extdebug}
|
||
|
||
begin
|
||
{$ifdef extdebug}
|
||
if (p^.firstpasscount>0) and only_one_pass then
|
||
exit;
|
||
{$endif extdebug}
|
||
oldcodegenerror:=codegenerror;
|
||
oldpos:=aktfilepos;
|
||
oldlocalswitches:=aktlocalswitches;
|
||
{$ifdef extdebug}
|
||
if p^.firstpasscount>0 then
|
||
begin
|
||
move(p^,str1[1],sizeof(ttree));
|
||
str1[0]:=char(sizeof(ttree));
|
||
new(oldp);
|
||
oldp^:=p^;
|
||
not_first:=true;
|
||
end
|
||
else
|
||
not_first:=false;
|
||
{$endif extdebug}
|
||
|
||
aktfilepos:=p^.fileinfo;
|
||
aktlocalswitches:=p^.localswitches;
|
||
if not p^.error then
|
||
begin
|
||
codegenerror:=false;
|
||
procedures[p^.treetype](p);
|
||
p^.error:=codegenerror;
|
||
codegenerror:=codegenerror or oldcodegenerror;
|
||
end
|
||
else
|
||
codegenerror:=true;
|
||
{$ifdef extdebug}
|
||
if not_first then
|
||
begin
|
||
{ dirty trick to compare two ttree's (PM) }
|
||
move(p^,str2[1],sizeof(ttree));
|
||
str2[0]:=char(sizeof(ttree));
|
||
if str1<>str2 then
|
||
begin
|
||
comment(v_debug,'tree changed after first counting pass '
|
||
+tostr(longint(p^.treetype)));
|
||
compare_trees(oldp,p);
|
||
end;
|
||
dispose(oldp);
|
||
end;
|
||
if count_ref then
|
||
inc(p^.firstpasscount);
|
||
{$endif extdebug}
|
||
aktlocalswitches:=oldlocalswitches;
|
||
aktfilepos:=oldpos;
|
||
end;
|
||
|
||
function do_firstpass(var p : ptree) : boolean;
|
||
|
||
begin
|
||
codegenerror:=false;
|
||
firstpass(p);
|
||
do_firstpass:=codegenerror;
|
||
end;
|
||
|
||
{ to be called only for a whole function }
|
||
{ to insert code at entry and exit }
|
||
|
||
function function_firstpass(var p : ptree) : boolean;
|
||
|
||
begin
|
||
codegenerror:=false;
|
||
firstpass(p);
|
||
function_firstpass:=codegenerror;
|
||
end;
|
||
|
||
end.
|
||
{
|
||
$Log$
|
||
Revision 1.65 1998-08-28 12:51:40 florian
|
||
+ ansistring to pchar type cast fixed
|
||
|
||
Revision 1.64 1998/08/28 10:54:22 peter
|
||
* fixed smallset generation from elements, it has never worked before!
|
||
|
||
Revision 1.63 1998/08/24 10:05:39 florian
|
||
+ class types and class reference types are now compatible with void
|
||
pointers
|
||
+ class can be stored now registers, even if a type conversation is applied
|
||
|
||
Revision 1.62 1998/08/23 16:07:22 florian
|
||
* internalerror with mod/div fixed
|
||
|
||
Revision 1.61 1998/08/21 14:08:47 pierre
|
||
+ TEST_FUNCRET now default (old code removed)
|
||
works also for m68k (at least compiles)
|
||
|
||
Revision 1.60 1998/08/20 12:59:57 peter
|
||
- removed obsolete in_*
|
||
|
||
Revision 1.59 1998/08/20 09:26:39 pierre
|
||
+ funcret setting in underproc testing
|
||
compile with _dTEST_FUNCRET
|
||
|
||
Revision 1.58 1998/08/19 16:07:51 jonas
|
||
* changed optimizer switches + cleanup of DestroyRefs in daopt386.pas
|
||
|
||
Revision 1.57 1998/08/19 00:42:39 peter
|
||
+ subrange types for enums
|
||
+ checking for bounds type with ranges
|
||
|
||
Revision 1.56 1998/08/18 09:24:42 pierre
|
||
* small warning position bug fixed
|
||
* support_mmx switches splitting was missing
|
||
* rhide error and warning output corrected
|
||
|
||
Revision 1.55 1998/08/14 18:18:44 peter
|
||
+ dynamic set contruction
|
||
* smallsets are now working (always longint size)
|
||
|
||
Revision 1.54 1998/08/13 11:00:10 peter
|
||
* fixed procedure<>procedure construct
|
||
|
||
Revision 1.53 1998/08/12 19:39:28 peter
|
||
* fixed some crashes
|
||
|
||
Revision 1.52 1998/08/10 14:50:08 peter
|
||
+ localswitches, moduleswitches, globalswitches splitting
|
||
|
||
Revision 1.51 1998/08/10 10:18:29 peter
|
||
+ Compiler,Comphook unit which are the new interface units to the
|
||
compiler
|
||
|
||
Revision 1.50 1998/08/08 21:51:39 peter
|
||
* small crash prevent is firstassignment
|
||
|
||
Revision 1.49 1998/07/30 16:07:08 florian
|
||
* try ... expect <statement> end; works now
|
||
|
||
Revision 1.48 1998/07/30 13:30:35 florian
|
||
* final implemenation of exception support, maybe it needs
|
||
some fixes :)
|
||
|
||
Revision 1.47 1998/07/30 11:18:17 florian
|
||
+ first implementation of try ... except on .. do end;
|
||
* limitiation of 65535 bytes parameters for cdecl removed
|
||
|
||
Revision 1.46 1998/07/28 21:52:52 florian
|
||
+ implementation of raise and try..finally
|
||
+ some misc. exception stuff
|
||
|
||
Revision 1.45 1998/07/26 21:58:59 florian
|
||
+ better support for switch $H
|
||
+ index access to ansi strings added
|
||
+ assigment of data (records/arrays) containing ansi strings
|
||
|
||
Revision 1.44 1998/07/24 22:16:59 florian
|
||
* internal error 10 together with array access fixed. I hope
|
||
that's the final fix.
|
||
|
||
Revision 1.43 1998/07/20 18:40:14 florian
|
||
* handling of ansi string constants should now work
|
||
|
||
Revision 1.42 1998/07/20 10:23:01 florian
|
||
* better ansi string assignement
|
||
|
||
Revision 1.41 1998/07/18 22:54:27 florian
|
||
* some ansi/wide/longstring support fixed:
|
||
o parameter passing
|
||
o returning as result from functions
|
||
|
||
Revision 1.40 1998/07/18 17:11:09 florian
|
||
+ ansi string constants fixed
|
||
+ switch $H partial implemented
|
||
|
||
Revision 1.39 1998/07/14 21:46:47 peter
|
||
* updated messages file
|
||
|
||
Revision 1.38 1998/07/14 14:46:50 peter
|
||
* released NEWINPUT
|
||
|
||
Revision 1.37 1998/07/07 12:31:44 peter
|
||
* fixed string:= which allowed almost any type
|
||
|
||
Revision 1.36 1998/07/07 11:20:00 peter
|
||
+ NEWINPUT for a better inputfile and scanner object
|
||
|
||
Revision 1.35 1998/06/25 14:04:19 peter
|
||
+ internal inc/dec
|
||
|
||
Revision 1.34 1998/06/25 08:48:14 florian
|
||
* first version of rtti support
|
||
|
||
Revision 1.33 1998/06/16 08:56:24 peter
|
||
+ targetcpu
|
||
* cleaner pmodules for newppu
|
||
|
||
Revision 1.32 1998/06/14 18:23:57 peter
|
||
* fixed xor bug (from mailinglist)
|
||
|
||
Revision 1.31 1998/06/13 00:10:09 peter
|
||
* working browser and newppu
|
||
* some small fixes against crashes which occured in bp7 (but not in
|
||
fpc?!)
|
||
|
||
Revision 1.30 1998/06/12 10:32:28 pierre
|
||
* column problem hopefully solved
|
||
+ C vars declaration changed
|
||
|
||
Revision 1.29 1998/06/09 16:01:44 pierre
|
||
+ added procedure directive parsing for procvars
|
||
(accepted are popstack cdecl and pascal)
|
||
+ added C vars with the following syntax
|
||
var C calias 'true_c_name';(can be followed by external)
|
||
reason is that you must add the Cprefix
|
||
|
||
which is target dependent
|
||
|
||
Revision 1.28 1998/06/05 14:37:29 pierre
|
||
* fixes for inline for operators
|
||
* inline procedure more correctly restricted
|
||
|
||
Revision 1.27 1998/06/05 00:01:06 florian
|
||
* bugs with assigning related objects and passing objects by reference
|
||
to a procedure
|
||
|
||
Revision 1.26 1998/06/04 09:55:39 pierre
|
||
* demangled name of procsym reworked to become independant
|
||
of the mangling scheme
|
||
|
||
Revision 1.25 1998/06/03 22:48:57 peter
|
||
+ wordbool,longbool
|
||
* rename bis,von -> high,low
|
||
* moved some systemunit loading/creating to psystem.pas
|
||
|
||
Revision 1.24 1998/06/02 17:03:01 pierre
|
||
* with node corrected for objects
|
||
* small bugs for SUPPORT_MMX fixed
|
||
|
||
Revision 1.23 1998/06/01 16:50:20 peter
|
||
+ boolean -> ord conversion
|
||
* fixed ord -> boolean conversion
|
||
|
||
Revision 1.22 1998/05/28 17:26:49 peter
|
||
* fixed -R switch, it didn't work after my previous akt/init patch
|
||
* fixed bugs 110,130,136
|
||
|
||
Revision 1.21 1998/05/25 17:11:41 pierre
|
||
* firstpasscount bug fixed
|
||
now all is already set correctly the first time
|
||
under EXTDEBUG try -gp to skip all other firstpasses
|
||
it works !!
|
||
* small bug fixes
|
||
- for smallsets with -dTESTSMALLSET
|
||
- some warnings removed (by correcting code !)
|
||
|
||
Revision 1.20 1998/05/23 01:21:17 peter
|
||
+ aktasmmode, aktoptprocessor, aktoutputformat
|
||
+ smartlink per module $SMARTLINK-/+ (like MMX) and moved to aktswitches
|
||
+ $LIBNAME to set the library name where the unit will be put in
|
||
* splitted cgi386 a bit (codeseg to large for bp7)
|
||
* nasm, tasm works again. nasm moved to ag386nsm.pas
|
||
|
||
Revision 1.19 1998/05/20 09:42:34 pierre
|
||
+ UseTokenInfo now default
|
||
* unit in interface uses and implementation uses gives error now
|
||
* only one error for unknown symbol (uses lastsymknown boolean)
|
||
the problem came from the label code !
|
||
+ first inlined procedures and function work
|
||
(warning there might be allowed cases were the result is still wrong !!)
|
||
* UseBrower updated gives a global list of all position of all used symbols
|
||
with switch -gb
|
||
|
||
Revision 1.18 1998/05/11 13:07:55 peter
|
||
+ $ifdef NEWPPU for the new ppuformat
|
||
+ $define GDB not longer required
|
||
* removed all warnings and stripped some log comments
|
||
* no findfirst/findnext anymore to remove smartlink *.o files
|
||
|
||
Revision 1.17 1998/05/06 08:38:43 pierre
|
||
* better position info with UseTokenInfo
|
||
UseTokenInfo greatly simplified
|
||
+ added check for changed tree after first time firstpass
|
||
(if we could remove all the cases were it happen
|
||
we could skip all firstpass if firstpasscount > 1)
|
||
Only with ExtDebug
|
||
|
||
Revision 1.16 1998/05/01 16:38:45 florian
|
||
* handling of private and protected fixed
|
||
+ change_keywords_to_tp implemented to remove
|
||
keywords which aren't supported by tp
|
||
* break and continue are now symbols of the system unit
|
||
+ widestring, longstring and ansistring type released
|
||
|
||
Revision 1.15 1998/05/01 09:01:23 florian
|
||
+ correct semantics of private and protected
|
||
* small fix in variable scope:
|
||
a id can be used in a parameter list of a method, even it is used in
|
||
an anchestor class as field id
|
||
|
||
Revision 1.14 1998/04/30 15:59:41 pierre
|
||
* GDB works again better :
|
||
correct type info in one pass
|
||
+ UseTokenInfo for better source position
|
||
* fixed one remaining bug in scanner for line counts
|
||
* several little fixes
|
||
|
||
Revision 1.13 1998/04/29 10:33:56 pierre
|
||
+ added some code for ansistring (not complete nor working yet)
|
||
* corrected operator overloading
|
||
* corrected nasm output
|
||
+ started inline procedures
|
||
+ added starstarn : use ** for exponentiation (^ gave problems)
|
||
+ started UseTokenInfo cond to get accurate positions
|
||
|
||
Revision 1.12 1998/04/22 21:06:50 florian
|
||
* last fixes before the release:
|
||
- veryyyy slow firstcall fixed
|
||
|
||
Revision 1.11 1998/04/21 10:16:48 peter
|
||
* patches from strasbourg
|
||
* objects is not used anymore in the fpc compiled version
|
||
|
||
Revision 1.10 1998/04/14 23:27:03 florian
|
||
+ exclude/include with constant second parameter added
|
||
|
||
Revision 1.9 1998/04/13 21:15:42 florian
|
||
* error handling of pass_1 and cgi386 fixed
|
||
* the following bugs fixed: 0117, 0118, 0119 and 0129, 0122 was already
|
||
fixed, verified
|
||
|
||
Revision 1.8 1998/04/13 08:42:52 florian
|
||
* call by reference and call by value open arrays fixed
|
||
|
||
Revision 1.7 1998/04/12 22:39:44 florian
|
||
* problem with read access to properties solved
|
||
* correct handling of hidding methods via virtual (COM)
|
||
* correct result type of constructor calls (COM), the resulttype
|
||
depends now on the type of the class reference
|
||
|
||
Revision 1.6 1998/04/09 22:16:34 florian
|
||
* problem with previous REGALLOC solved
|
||
* improved property support
|
||
|
||
Revision 1.5 1998/04/08 16:58:04 pierre
|
||
* several bugfixes
|
||
ADD ADC and AND are also sign extended
|
||
nasm output OK (program still crashes at end
|
||
and creates wrong assembler files !!)
|
||
procsym types sym in tdef removed !!
|
||
|
||
Revision 1.4 1998/04/07 22:45:04 florian
|
||
* bug0092, bug0115 and bug0121 fixed
|
||
+ packed object/class/array
|
||
}
|