fpc/compiler/ptconst.pas
Jonas Maebe eccbc78e04 + support for bitpacked arrays:
+ use {$bitpacking on/+} to change the meaning of "packed"
      into "bitpacked" for arrays. This is the default for MacPas.
      You can also define individual arrays as "bitpacked", but
      this is not encouraged since this keyword is not known by
      other compilers and therefore makes your code unportable.
    + pack(unpackedarray,index,packedarray) to pack
      length(packedarray) elements starting at
      unpackedarray[index] into packedarray.
    + unpack(packedarray,unpackedarray,index) to unpack
      packedarray into unpackedarray, with the first
      element being stored at unpackedarray[index]
  * todo:
    * "open packed arrays" and rtti for packed arrays are not
      yet supported
    * gdb does not properly support bitpacked arrays

git-svn-id: trunk@4449 -
2006-08-19 12:54:12 +00:00

1064 lines
47 KiB
ObjectPascal

{
Copyright (c) 1998-2002 by Florian Klaempfl
Reads typed constants
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************
}
unit ptconst;
{$i fpcdefs.inc}
interface
uses symtype,symsym,aasmdata;
{ this procedure reads typed constants }
{ sym is only needed for ansi strings }
{ the assembler label is in the middle (PM) }
procedure readtypedconst(list:tasmlist;const t:ttype;sym : ttypedconstsym;writable : boolean);
implementation
uses
strings,
globtype,systems,tokens,verbose,
cutils,globals,widestr,scanner,
symconst,symbase,symdef,symtable,
aasmbase,aasmtai,aasmcpu,defutil,defcmp,
{ pass 1 }
node,htypechk,procinfo,
nmat,nadd,ncal,nmem,nset,ncnv,ninl,ncon,nld,nflw,
{ parser specific stuff }
pbase,pexpr,
{ codegen }
cpuinfo,cgbase,dbgbase
;
{$ifdef fpc}
{$maxfpuregisters 0}
{$endif fpc}
{ this procedure reads typed constants }
procedure readtypedconst(list:tasmlist;const t:ttype;sym : ttypedconstsym;writable : boolean);
label
myexit;
type
setbytes = array[0..31] of byte;
Psetbytes = ^setbytes;
var
len,base : longint;
p,hp : tnode;
i,j,l : longint;
varalign : shortint;
offset,
strlength : aint;
ll : tasmlabel;
c_name,
s,sorg : string;
c : char;
ca : pchar;
tmpguid : tguid;
aktpos : longint;
obj : tobjectdef;
recsym,
srsym : tsym;
symt : tsymtable;
value : bestreal;
intvalue : tconstexprint;
strval : pchar;
pw : pcompilerwidestring;
error : boolean;
old_block_type : tblock_type;
storefilepos : tfileposinfo;
cursectype : TAsmSectiontype;
datalist : tasmlist;
procedure check_range(def:torddef);
begin
if ((tordconstnode(p).value>def.high) or
(tordconstnode(p).value<def.low)) then
begin
if (cs_check_range in aktlocalswitches) then
Message(parser_e_range_check_error)
else
Message(parser_w_range_check_error);
end;
end;
begin
old_block_type:=block_type;
block_type:=bt_const;
datalist:=tasmlist.create;
case t.def.deftype of
orddef:
begin
p:=comp_expr(true);
case torddef(t.def).typ of
bool8bit :
begin
if is_constboolnode(p) then
datalist.concat(Tai_const.Create_8bit(byte(tordconstnode(p).value)))
else
Message(parser_e_illegal_expression);
end;
bool16bit :
begin
if is_constboolnode(p) then
datalist.concat(Tai_const.Create_16bit(word(tordconstnode(p).value)))
else
Message(parser_e_illegal_expression);
end;
bool32bit :
begin
if is_constboolnode(p) then
datalist.concat(Tai_const.Create_32bit(longint(tordconstnode(p).value)))
else
Message(parser_e_illegal_expression);
end;
uchar :
begin
if is_constcharnode(p) then
datalist.concat(Tai_const.Create_8bit(byte(tordconstnode(p).value)))
else
Message(parser_e_illegal_expression);
end;
uwidechar :
begin
if is_constcharnode(p) then
inserttypeconv(p,cwidechartype);
if is_constwidecharnode(p) then
datalist.concat(Tai_const.Create_16bit(word(tordconstnode(p).value)))
else
Message(parser_e_illegal_expression);
end;
s8bit,
u8bit :
begin
if is_constintnode(p) then
begin
datalist.concat(Tai_const.Create_8bit(byte(tordconstnode(p).value)));
check_range(torddef(t.def));
end
else
Message(parser_e_illegal_expression);
end;
u16bit,
s16bit :
begin
if is_constintnode(p) then
begin
datalist.concat(Tai_const.Create_16bit(word(tordconstnode(p).value)));
check_range(torddef(t.def));
end
else
Message(parser_e_illegal_expression);
end;
s32bit,
u32bit :
begin
if is_constintnode(p) then
begin
datalist.concat(Tai_const.Create_32bit(longint(tordconstnode(p).value)));
if torddef(t.def).typ<>u32bit then
check_range(torddef(t.def));
end
else
Message(parser_e_illegal_expression);
end;
s64bit,
u64bit,
scurrency:
begin
if is_constintnode(p) then
intvalue := tordconstnode(p).value
else if is_constrealnode(p) and
(torddef(t.def).typ=scurrency)
{ allow bootstrapping }
then
begin
intvalue:=round(trealconstnode(p).value_real*10000);
end
else
begin
intvalue:=0;
Message(parser_e_illegal_expression);
end;
datalist.concat(Tai_const.Create_64bit(intvalue));
end;
else
internalerror(3799);
end;
p.free;
end;
floatdef:
begin
p:=comp_expr(true);
if is_constrealnode(p) then
value:=trealconstnode(p).value_real
else if is_constintnode(p) then
value:=tordconstnode(p).value
else
Message(parser_e_illegal_expression);
case tfloatdef(t.def).typ of
s32real :
datalist.concat(Tai_real_32bit.Create(ts32real(value)));
s64real :
{$ifdef ARM}
if aktfputype in [fpu_fpa,fpu_fpa10,fpu_fpa11] then
datalist.concat(Tai_real_64bit.Create_hiloswapped(ts64real(value)))
else
{$endif ARM}
datalist.concat(Tai_real_64bit.Create(ts64real(value)));
s80real :
datalist.concat(Tai_real_80bit.Create(value));
{ the round is necessary for native compilers where comp isn't a float }
s64comp :
datalist.concat(Tai_comp_64bit.Create(round(value)));
s64currency:
datalist.concat(Tai_comp_64bit.Create(round(value*10000)));
s128real:
datalist.concat(Tai_real_128bit.Create(value));
else
internalerror(18);
end;
p.free;
end;
classrefdef:
begin
p:=comp_expr(true);
case p.nodetype of
loadvmtaddrn:
with Tclassrefdef(p.resulttype.def) do
begin
if not Tobjectdef(pointertype.def).is_related(Tobjectdef(pointertype.def)) then
message(parser_e_illegal_expression);
datalist.concat(Tai_const.Create_sym(current_asmdata.RefAsmSymbol(
Tobjectdef(pointertype.def).vmt_mangledname)));
end;
niln:
datalist.concat(Tai_const.Create_sym(nil));
else Message(parser_e_illegal_expression);
end;
p.free;
end;
pointerdef:
begin
p:=comp_expr(true);
if (p.nodetype=typeconvn) then
with Ttypeconvnode(p) do
if (left.nodetype in [addrn,niln]) and equal_defs(t.def,p.resulttype.def) then
begin
hp:=left;
left:=nil;
p.free;
p:=hp;
end;
{ allows horrible ofs(typeof(TButton)^) code !! }
if (p.nodetype=addrn) then
with Taddrnode(p) do
if left.nodetype=derefn then
begin
hp:=tderefnode(left).left;
tderefnode(left).left:=nil;
p.free;
p:=hp;
end;
{ const pointer ? }
if (p.nodetype = pointerconstn) then
begin
if sizeof(TConstPtrUInt)=8 then
datalist.concat(Tai_const.Create_64bit(TConstPtrUInt(tpointerconstnode(p).value)))
else
if sizeof(TConstPtrUInt)=4 then
datalist.concat(Tai_const.Create_32bit(TConstPtrUInt(tpointerconstnode(p).value)))
else
internalerror(200404122);
end
{ nil pointer ? }
else if p.nodetype=niln then
datalist.concat(Tai_const.Create_sym(nil))
{ maybe pchar ? }
else
if is_char(tpointerdef(t.def).pointertype.def) and
(p.nodetype<>addrn) then
begin
current_asmdata.getdatalabel(ll);
datalist.concat(Tai_const.Create_sym(ll));
if p.nodetype=stringconstn then
varalign:=size_2_align(tstringconstnode(p).len)
else
varalign:=0;
varalign:=const_align(varalign);
current_asmdata.asmlists[al_const].concat(Tai_align.Create(varalign));
current_asmdata.asmlists[al_const].concat(Tai_label.Create(ll));
if p.nodetype=stringconstn then
begin
len:=tstringconstnode(p).len;
{ For tp7 the maximum lentgh can be 255 }
if (m_tp7 in aktmodeswitches) and
(len>255) then
len:=255;
getmem(ca,len+2);
move(tstringconstnode(p).value_str^,ca^,len+1);
current_asmdata.asmlists[al_const].concat(Tai_string.Create_pchar(ca,len+1));
end
else
if is_constcharnode(p) then
current_asmdata.asmlists[al_const].concat(Tai_string.Create(char(byte(tordconstnode(p).value))+#0))
else
message(parser_e_illegal_expression);
end
{ maybe pwidechar ? }
else
if is_widechar(tpointerdef(t.def).pointertype.def) and
(p.nodetype<>addrn) then
begin
current_asmdata.getdatalabel(ll);
datalist.concat(Tai_const.Create_sym(ll));
current_asmdata.asmlists[al_typedconsts].concat(tai_align.create(const_align(sizeof(aint))));
current_asmdata.asmlists[al_typedconsts].concat(Tai_label.Create(ll));
if (p.nodetype in [stringconstn,ordconstn]) then
begin
{ convert to widestring stringconstn }
inserttypeconv(p,cwidestringtype);
if (p.nodetype=stringconstn) and
(tstringconstnode(p).cst_type=cst_widestring) then
begin
pw:=pcompilerwidestring(tstringconstnode(p).value_str);
for i:=0 to tstringconstnode(p).len-1 do
current_asmdata.asmlists[al_typedconsts].concat(Tai_const.Create_16bit(pw^.data[i]));
{ ending #0 }
current_asmdata.asmlists[al_typedconsts].concat(Tai_const.Create_16bit(0))
end;
end
else
Message(parser_e_illegal_expression);
end
else
if (p.nodetype=addrn) or
is_procvar_load(p) then
begin
{ insert typeconv }
inserttypeconv(p,t);
hp:=p;
while assigned(hp) and (hp.nodetype in [addrn,typeconvn,subscriptn,vecn]) do
hp:=tunarynode(hp).left;
if (hp.nodetype=loadn) then
begin
hp:=p;
offset:=0;
while assigned(hp) and (hp.nodetype<>loadn) do
begin
case hp.nodetype of
vecn :
begin
case tvecnode(hp).left.resulttype.def.deftype of
stringdef :
begin
{ this seems OK for shortstring and ansistrings PM }
{ it is wrong for widestrings !! }
len:=1;
base:=0;
end;
arraydef :
begin
if not is_packed_array(tvecnode(hp).left.resulttype.def) then
begin
len:=tarraydef(tvecnode(hp).left.resulttype.def).elesize;
base:=tarraydef(tvecnode(hp).left.resulttype.def).lowrange;
end
else
begin
Message(parser_e_packed_dynamic_open_array);
len:=1;
base:=0;
end;
end
else
Message(parser_e_illegal_expression);
end;
if is_constintnode(tvecnode(hp).right) then
inc(offset,len*(get_ordinal_value(tvecnode(hp).right)-base))
else
Message(parser_e_illegal_expression);
end;
subscriptn :
inc(offset,tsubscriptnode(hp).vs.fieldoffset);
typeconvn :
begin
if not(ttypeconvnode(hp).convtype in [tc_equal,tc_proc_2_procvar]) then
Message(parser_e_illegal_expression);
end;
addrn :
;
else
Message(parser_e_illegal_expression);
end;
hp:=tunarynode(hp).left;
end;
srsym:=tloadnode(hp).symtableentry;
case srsym.typ of
procsym :
begin
if Tprocsym(srsym).procdef_count>1 then
Message(parser_e_no_overloaded_procvars);
if po_abstractmethod in tprocsym(srsym).first_procdef.procoptions then
Message(type_e_cant_take_address_of_abstract_method)
else
datalist.concat(Tai_const.Createname(tprocsym(srsym).first_procdef.mangledname,offset));
end;
globalvarsym :
datalist.concat(Tai_const.Createname(tglobalvarsym(srsym).mangledname,offset));
typedconstsym :
datalist.concat(Tai_const.Createname(ttypedconstsym(srsym).mangledname,offset));
labelsym :
datalist.concat(Tai_const.Createname(tlabelsym(srsym).mangledname,offset));
constsym :
if tconstsym(srsym).consttyp=constresourcestring then
datalist.concat(Tai_const.Createname(make_mangledname('RESOURCESTRINGLIST',tconstsym(srsym).owner,''),tconstsym(srsym).resstrindex*(4+sizeof(aint)*3)+4+sizeof(aint)))
else
Message(type_e_variable_id_expected);
else
Message(type_e_variable_id_expected);
end;
end
else
Message(parser_e_illegal_expression);
end
else
{ allow typeof(Object type)}
if (p.nodetype=inlinen) and
(tinlinenode(p).inlinenumber=in_typeof_x) then
begin
if (tinlinenode(p).left.nodetype=typen) then
begin
datalist.concat(Tai_const.createname(
tobjectdef(tinlinenode(p).left.resulttype.def).vmt_mangledname,0));
end
else
Message(parser_e_illegal_expression);
end
else
Message(parser_e_illegal_expression);
p.free;
end;
setdef:
begin
p:=comp_expr(true);
if p.nodetype=setconstn then
begin
{ be sure to convert to the correct result, else
it can generate smallset data instead of normalset (PFV) }
inserttypeconv(p,t);
{ we only allow const sets }
if assigned(tsetconstnode(p).left) then
Message(parser_e_illegal_expression)
else
begin
{ this writing is endian independant }
{ untrue - because they are considered }
{ arrays of 32-bit values CEC }
if source_info.endian = target_info.endian then
begin
for l:=0 to p.resulttype.def.size-1 do
datalist.concat(tai_const.create_8bit(Psetbytes(tsetconstnode(p).value_set)^[l]));
end
else
begin
{ store as longint values in swaped format }
j:=0;
for l:=0 to ((p.resulttype.def.size-1) div 4) do
begin
datalist.concat(tai_const.create_8bit(Psetbytes(tsetconstnode(p).value_set)^[j+3]));
datalist.concat(tai_const.create_8bit(Psetbytes(tsetconstnode(p).value_set)^[j+2]));
datalist.concat(tai_const.create_8bit(Psetbytes(tsetconstnode(p).value_set)^[j+1]));
datalist.concat(tai_const.create_8bit(Psetbytes(tsetconstnode(p).value_set)^[j]));
Inc(j,4);
end;
end;
end;
end
else
Message(parser_e_illegal_expression);
p.free;
end;
enumdef:
begin
p:=comp_expr(true);
if p.nodetype=ordconstn then
begin
if equal_defs(p.resulttype.def,t.def) or
is_subequal(p.resulttype.def,t.def) then
begin
case longint(p.resulttype.def.size) of
1 : datalist.concat(Tai_const.Create_8bit(Byte(tordconstnode(p).value)));
2 : datalist.concat(Tai_const.Create_16bit(Word(tordconstnode(p).value)));
4 : datalist.concat(Tai_const.Create_32bit(Longint(tordconstnode(p).value)));
end;
end
else
IncompatibleTypes(p.resulttype.def,t.def);
end
else
Message(parser_e_illegal_expression);
p.free;
end;
stringdef:
begin
p:=comp_expr(true);
{ load strval and strlength of the constant tree }
if (p.nodetype=stringconstn) or is_widestring(t.def) then
begin
{ convert to the expected string type so that
for widestrings strval is a pcompilerwidestring }
inserttypeconv(p,t);
strlength:=tstringconstnode(p).len;
strval:=tstringconstnode(p).value_str;
end
else if is_constcharnode(p) then
begin
{ strval:=pchar(@tordconstnode(p).value);
THIS FAIL on BIG_ENDIAN MACHINES PM }
c:=chr(tordconstnode(p).value and $ff);
strval:=@c;
strlength:=1
end
else if is_constresourcestringnode(p) then
begin
strval:=pchar(tconstsym(tloadnode(p).symtableentry).value.valueptr);
strlength:=tconstsym(tloadnode(p).symtableentry).value.len;
end
else
begin
Message(parser_e_illegal_expression);
strlength:=-1;
end;
if strlength>=0 then
begin
case tstringdef(t.def).string_typ of
st_shortstring:
begin
if strlength>=t.def.size then
begin
message2(parser_w_string_too_long,strpas(strval),tostr(t.def.size-1));
strlength:=t.def.size-1;
end;
datalist.concat(Tai_const.Create_8bit(strlength));
{ this can also handle longer strings }
getmem(ca,strlength+1);
move(strval^,ca^,strlength);
ca[strlength]:=#0;
datalist.concat(Tai_string.Create_pchar(ca,strlength));
{ fillup with spaces if size is shorter }
if t.def.size>strlength then
begin
getmem(ca,t.def.size-strlength);
{ def.size contains also the leading length, so we }
{ we have to subtract one }
fillchar(ca[0],t.def.size-strlength-1,' ');
ca[t.def.size-strlength-1]:=#0;
{ this can also handle longer strings }
datalist.concat(Tai_string.Create_pchar(ca,t.def.size-strlength-1));
end;
end;
st_ansistring:
begin
{ an empty ansi string is nil! }
if (strlength=0) then
datalist.concat(Tai_const.Create_sym(nil))
else
begin
current_asmdata.getdatalabel(ll);
datalist.concat(Tai_const.Create_sym(ll));
current_asmdata.asmlists[al_const].concat(tai_align.create(const_align(sizeof(aint))));
current_asmdata.asmlists[al_const].concat(Tai_const.Create_aint(-1));
current_asmdata.asmlists[al_const].concat(Tai_const.Create_aint(strlength));
current_asmdata.asmlists[al_const].concat(Tai_label.Create(ll));
getmem(ca,strlength+1);
move(strval^,ca^,strlength);
{ The terminating #0 to be stored in the .data section (JM) }
ca[strlength]:=#0;
current_asmdata.asmlists[al_const].concat(Tai_string.Create_pchar(ca,strlength+1));
end;
end;
st_widestring:
begin
{ an empty ansi string is nil! }
if (strlength=0) then
datalist.concat(Tai_const.Create_sym(nil))
else
begin
current_asmdata.getdatalabel(ll);
datalist.concat(Tai_const.Create_sym(ll));
current_asmdata.asmlists[al_const].concat(tai_align.create(const_align(sizeof(aint))));
if tf_winlikewidestring in target_info.flags then
current_asmdata.asmlists[al_const].concat(Tai_const.Create_32bit(strlength*cwidechartype.def.size))
else
begin
current_asmdata.asmlists[al_const].concat(Tai_const.Create_aint(-1));
current_asmdata.asmlists[al_const].concat(Tai_const.Create_aint(strlength*cwidechartype.def.size));
end;
current_asmdata.asmlists[al_const].concat(Tai_label.Create(ll));
for i:=0 to strlength-1 do
current_asmdata.asmlists[al_const].concat(Tai_const.Create_16bit(pcompilerwidestring(strval)^.data[i]));
{ ending #0 }
current_asmdata.asmlists[al_const].concat(Tai_const.Create_16bit(0))
end;
end;
st_longstring:
begin
internalerror(200107081);
end;
end;
end;
p.free;
end;
arraydef:
begin
{ dynamic array nil }
if is_dynamic_array(t.def) then
begin
{ Only allow nil initialization }
consume(_NIL);
datalist.concat(Tai_const.Create_sym(nil));
end
{ no packed array constants supported }
else if is_packed_array(t.def) then
begin
Message(type_e_no_const_packed_array);
consume_all_until(_RKLAMMER);
end
else
if try_to_consume(_LKLAMMER) then
begin
for l:=tarraydef(t.def).lowrange to tarraydef(t.def).highrange-1 do
begin
readtypedconst(datalist,tarraydef(t.def).elementtype,nil,writable);
consume(_COMMA);
end;
readtypedconst(datalist,tarraydef(t.def).elementtype,nil,writable);
consume(_RKLAMMER);
end
else
{ if array of char then we allow also a string }
if is_char(tarraydef(t.def).elementtype.def) then
begin
p:=comp_expr(true);
if p.nodetype=stringconstn then
begin
len:=tstringconstnode(p).len;
{ For tp7 the maximum lentgh can be 255 }
if (m_tp7 in aktmodeswitches) and
(len>255) then
len:=255;
ca:=tstringconstnode(p).value_str;
end
else
if is_constcharnode(p) then
begin
c:=chr(tordconstnode(p).value and $ff);
ca:=@c;
len:=1;
end
else
begin
Message(parser_e_illegal_expression);
len:=0;
end;
if len>(tarraydef(t.def).highrange-tarraydef(t.def).lowrange+1) then
Message(parser_e_string_larger_array);
for i:=tarraydef(t.def).lowrange to tarraydef(t.def).highrange do
begin
if i+1-tarraydef(t.def).lowrange<=len then
begin
datalist.concat(Tai_const.Create_8bit(byte(ca^)));
inc(ca);
end
else
{Fill the remaining positions with #0.}
datalist.concat(Tai_const.Create_8bit(0));
end;
p.free;
end
else
begin
{ we want the ( }
consume(_LKLAMMER);
end;
end;
procvardef:
begin
{ Procvars and pointers are no longer compatible. }
{ under tp: =nil or =var under fpc: =nil or =@var }
if token=_NIL then
begin
datalist.concat(Tai_const.Create_sym(nil));
if (po_methodpointer in tprocvardef(t.def).procoptions) then
datalist.concat(Tai_const.Create_sym(nil));
consume(_NIL);
goto myexit;
end;
{ you can't assign a value other than NIL to a typed constant }
{ which is a "procedure of object", because this also requires }
{ address of an object/class instance, which is not known at }
{ compile time (JM) }
if (po_methodpointer in tprocvardef(t.def).procoptions) then
Message(parser_e_no_procvarobj_const);
{ parse the rest too, so we can continue with error checking }
getprocvardef:=tprocvardef(t.def);
p:=comp_expr(true);
getprocvardef:=nil;
if codegenerror then
begin
p.free;
goto myexit;
end;
{ let type conversion check everything needed }
inserttypeconv(p,t);
if codegenerror then
begin
p.free;
goto myexit;
end;
{ remove typeconvs, that will normally insert a lea
instruction which is not necessary for us }
while p.nodetype=typeconvn do
begin
hp:=ttypeconvnode(p).left;
ttypeconvnode(p).left:=nil;
p.free;
p:=hp;
end;
{ remove addrn which we also don't need here }
if p.nodetype=addrn then
begin
hp:=taddrnode(p).left;
taddrnode(p).left:=nil;
p.free;
p:=hp;
end;
{ we now need to have a loadn with a procsym }
if (p.nodetype=loadn) and
(tloadnode(p).symtableentry.typ=procsym) then
begin
datalist.concat(Tai_const.createname(
tprocsym(tloadnode(p).symtableentry).first_procdef.mangledname,0));
end
else
Message(parser_e_illegal_expression);
p.free;
end;
{ reads a typed constant record }
recorddef:
begin
{ KAZ }
if (trecorddef(t.def)=rec_tguid) and
((token=_CSTRING) or (token=_CCHAR) or (token=_ID)) then
begin
p:=comp_expr(true);
inserttypeconv(p,cshortstringtype);
if p.nodetype=stringconstn then
begin
s:=strpas(tstringconstnode(p).value_str);
p.free;
if string2guid(s,tmpguid) then
begin
datalist.concat(Tai_const.Create_32bit(longint(tmpguid.D1)));
datalist.concat(Tai_const.Create_16bit(tmpguid.D2));
datalist.concat(Tai_const.Create_16bit(tmpguid.D3));
for i:=Low(tmpguid.D4) to High(tmpguid.D4) do
datalist.concat(Tai_const.Create_8bit(tmpguid.D4[i]));
end
else
Message(parser_e_improper_guid_syntax);
end
else
begin
p.free;
Message(parser_e_illegal_expression);
goto myexit;
end;
end
else
begin
consume(_LKLAMMER);
sorg:='';
aktpos:=0;
srsym := tsym(trecorddef(t.def).symtable.symindex.first);
recsym := nil;
while token<>_RKLAMMER do
begin
s:=pattern;
sorg:=orgpattern;
consume(_ID);
consume(_COLON);
error := false;
recsym := tsym(trecorddef(t.def).symtable.search(s));
if not assigned(recsym) then
begin
Message1(sym_e_illegal_field,sorg);
error := true;
end;
if (not error) and
(not assigned(srsym) or
(s <> srsym.name)) then
{ possible variant record (JM) }
begin
{ All parts of a variant start at the same offset }
{ Also allow jumping from one variant part to another, }
{ as long as the offsets match }
if (assigned(srsym) and
(tfieldvarsym(recsym).fieldoffset = tfieldvarsym(srsym).fieldoffset)) or
{ srsym is not assigned after parsing w2 in the }
{ typed const in the next example: }
{ type tr = record case byte of }
{ 1: (l1,l2: dword); }
{ 2: (w1,w2: word); }
{ end; }
{ const r: tr = (w1:1;w2:1;l2:5); }
(tfieldvarsym(recsym).fieldoffset = aktpos) then
srsym := recsym
{ going backwards isn't allowed in any mode }
else if (tfieldvarsym(recsym).fieldoffset<aktpos) then
begin
Message(parser_e_invalid_record_const);
error := true;
end
{ Delphi allows you to skip fields }
else if (m_delphi in aktmodeswitches) then
begin
Message1(parser_w_skipped_fields_before,sorg);
srsym := recsym;
end
{ FPC and TP don't }
else
begin
Message1(parser_e_skipped_fields_before,sorg);
error := true;
end;
end;
if error then
consume_all_until(_SEMICOLON)
else
begin
{ if needed fill (alignment) }
if tfieldvarsym(srsym).fieldoffset>aktpos then
for i:=1 to tfieldvarsym(srsym).fieldoffset-aktpos do
datalist.concat(Tai_const.Create_8bit(0));
{ new position }
aktpos:=tfieldvarsym(srsym).fieldoffset+tfieldvarsym(srsym).vartype.def.size;
{ read the data }
readtypedconst(datalist,tfieldvarsym(srsym).vartype,nil,writable);
{ keep previous field for checking whether whole }
{ record was initialized (JM) }
recsym := srsym;
{ goto next field }
srsym := tsym(srsym.indexnext);
if token=_SEMICOLON then
consume(_SEMICOLON)
else break;
end;
end;
{ are there any fields left? }
if assigned(srsym) and
{ don't complain if there only come other variant parts }
{ after the last initialized field }
((recsym=nil) or
(tfieldvarsym(srsym).fieldoffset > tfieldvarsym(recsym).fieldoffset)) then
Message1(parser_w_skipped_fields_after,sorg);
for i:=1 to t.def.size-aktpos do
datalist.concat(Tai_const.Create_8bit(0));
consume(_RKLAMMER);
end;
end;
{ reads a typed object }
objectdef:
begin
if is_class_or_interface(t.def) then
begin
p:=comp_expr(true);
if p.nodetype<>niln then
begin
Message(type_e_no_const_packed_array);
consume_all_until(_SEMICOLON);
end
else
begin
datalist.concat(Tai_const.Create_sym(nil));
end;
p.free;
end
{ for objects we allow it only if it doesn't contain a vmt }
else if (oo_has_vmt in tobjectdef(t.def).objectoptions) and
(m_fpc in aktmodeswitches) then
Message(parser_e_type_const_not_possible)
else
begin
consume(_LKLAMMER);
aktpos:=0;
while token<>_RKLAMMER do
begin
s:=pattern;
sorg:=orgpattern;
consume(_ID);
consume(_COLON);
srsym:=nil;
obj:=tobjectdef(t.def);
symt:=obj.symtable;
while (srsym=nil) and assigned(symt) do
begin
srsym:=tsym(symt.search(s));
if assigned(obj) then
obj:=obj.childof;
if assigned(obj) then
symt:=obj.symtable
else
symt:=nil;
end;
if srsym=nil then
begin
Message1(sym_e_id_not_found,sorg);
consume_all_until(_SEMICOLON);
end
else
with tfieldvarsym(srsym) do
begin
{ check position }
if fieldoffset<aktpos then
message(parser_e_invalid_record_const);
{ check in VMT needs to be added for TP mode }
with Tobjectdef(t.def) do
if not(m_fpc in aktmodeswitches) and
(oo_has_vmt in objectoptions) and
(vmt_offset<fieldoffset) then
begin
for i:=1 to vmt_offset-aktpos do
datalist.concat(tai_const.create_8bit(0));
datalist.concat(tai_const.createname(vmt_mangledname,0));
{ this is more general }
aktpos:=vmt_offset + sizeof(aint);
end;
{ if needed fill }
if fieldoffset>aktpos then
for i:=1 to fieldoffset-aktpos do
datalist.concat(Tai_const.Create_8bit(0));
{ new position }
aktpos:=fieldoffset+vartype.def.size;
{ read the data }
readtypedconst(datalist,vartype,nil,writable);
if not try_to_consume(_SEMICOLON) then
break;
end;
end;
if not(m_fpc in aktmodeswitches) and
(oo_has_vmt in tobjectdef(t.def).objectoptions) and
(tobjectdef(t.def).vmt_offset>=aktpos) then
begin
for i:=1 to tobjectdef(t.def).vmt_offset-aktpos do
datalist.concat(tai_const.create_8bit(0));
datalist.concat(tai_const.createname(tobjectdef(t.def).vmt_mangledname,0));
{ this is more general }
aktpos:=tobjectdef(t.def).vmt_offset + sizeof(aint);
end;
for i:=1 to t.def.size-aktpos do
datalist.concat(Tai_const.Create_8bit(0));
consume(_RKLAMMER);
end;
end;
errordef:
begin
{ try to consume something useful }
if token=_LKLAMMER then
consume_all_until(_RKLAMMER)
else
consume_all_until(_SEMICOLON);
end;
else Message(parser_e_type_const_not_possible);
end;
{ Parse hints and public directive }
if assigned(sym) then
begin
try_consume_hintdirective(sym.symoptions);
{ Support public name directive }
if try_to_consume(_PUBLIC) then
begin
if try_to_consume(_NAME) then
C_name:=get_stringconst
else
C_name:=sorg;
sym.set_mangledname(C_Name);
end;
end;
myexit:
block_type:=old_block_type;
{ Add symbol name if this is specified. For array
elements sym=nil and we should skip this }
if assigned(sym) then
begin
storefilepos:=aktfilepos;
aktfilepos:=sym.fileinfo;
{ insert cut for smartlinking or alignment }
if writable then
cursectype:=sec_data
else
cursectype:=sec_rodata;
maybe_new_object_file(list);
new_section(list,cursectype,lower(sym.mangledname),const_align(t.def.alignment));
if (sym.owner.symtabletype=globalsymtable) or
maybe_smartlink_symbol or
(assigned(current_procinfo) and
(po_inline in current_procinfo.procdef.procoptions)) or
DLLSource then
list.concat(Tai_symbol.Createname_global(sym.mangledname,AT_DATA,0))
else
list.concat(Tai_symbol.Createname(sym.mangledname,AT_DATA,0));
list.concatlist(datalist);
list.concat(tai_symbol_end.Createname(sym.mangledname));
aktfilepos:=storefilepos;
end
else
list.concatlist(datalist);
datalist.free;
end;
{$ifdef fpc}
{$maxfpuregisters default}
{$endif fpc}
end.