diff options
Diffstat (limited to 'compiler/ptconst.pas')
-rw-r--r-- | compiler/ptconst.pas | 1030 |
1 files changed, 1030 insertions, 0 deletions
diff --git a/compiler/ptconst.pas b/compiler/ptconst.pas new file mode 100644 index 0000000000..5bd0a085cb --- /dev/null +++ b/compiler/ptconst.pas @@ -0,0 +1,1030 @@ +{ + 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; + + { this procedure reads typed constants } + { sym is only needed for ansi strings } + { the assembler label is in the middle (PM) } + procedure readtypedconst(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(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, + varalign : longint; + offset, + strlength : aint; + ll : tasmlabel; + 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; + cural : 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; + + if writable then + begin + cural:=al_typedconsts; + cursectype:=sec_data; + end + else + begin + cural:=al_rotypedconsts; + cursectype:=sec_rodata; + end; + + { 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 } + l:=sym.getsize; + maybe_new_object_file(asmlist[cural]); + new_section(asmlist[cural],cursectype,lower(sym.mangledname),const_align(l)); + + if (sym.owner.symtabletype=globalsymtable) or + maybe_smartlink_symbol or + (assigned(current_procinfo) and + (po_inline in current_procinfo.procdef.procoptions)) or + DLLSource then + asmlist[cural].concat(Tai_symbol.Createname_global(sym.mangledname,AT_DATA,l)) + else + asmlist[cural].concat(Tai_symbol.Createname(sym.mangledname,AT_DATA,l)); + aktfilepos:=storefilepos; + end; + + case t.def.deftype of + orddef: + begin + p:=comp_expr(true); + case torddef(t.def).typ of + bool8bit : + begin + if is_constboolnode(p) then + asmlist[cural].concat(Tai_const.Create_8bit(byte(tordconstnode(p).value))) + else + Message(parser_e_illegal_expression); + end; + bool16bit : + begin + if is_constboolnode(p) then + asmlist[cural].concat(Tai_const.Create_16bit(word(tordconstnode(p).value))) + else + Message(parser_e_illegal_expression); + end; + bool32bit : + begin + if is_constboolnode(p) then + asmlist[cural].concat(Tai_const.Create_32bit(longint(tordconstnode(p).value))) + else + Message(parser_e_illegal_expression); + end; + uchar : + begin + if is_constcharnode(p) then + asmlist[cural].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 + asmlist[cural].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 + asmlist[cural].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 + asmlist[cural].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 + asmlist[cural].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; + asmlist[cural].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 : + asmlist[cural].concat(Tai_real_32bit.Create(ts32real(value))); + s64real : +{$ifdef ARM} + if aktfputype in [fpu_fpa,fpu_fpa10,fpu_fpa11] then + asmlist[cural].concat(Tai_real_64bit.Create_hiloswapped(ts64real(value))) + else +{$endif ARM} + asmlist[cural].concat(Tai_real_64bit.Create(ts64real(value))); + s80real : + asmlist[cural].concat(Tai_real_80bit.Create(value)); + + { the round is necessary for native compilers where comp isn't a float } + s64comp : + asmlist[cural].concat(Tai_comp_64bit.Create(round(value))); + s64currency: + asmlist[cural].concat(Tai_comp_64bit.Create(round(value*10000))); + s128real: + asmlist[cural].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); + asmlist[cural].concat(Tai_const.Create_sym(objectlibrary.newasmsymbol( + Tobjectdef(pointertype.def).vmt_mangledname,AB_EXTERNAL,AT_DATA))); + end; + niln: + asmlist[cural].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 + asmlist[cural].concat(Tai_const.Create_64bit(TConstPtrUInt(tpointerconstnode(p).value))) + else + if sizeof(TConstPtrUInt)=4 then + asmlist[cural].concat(Tai_const.Create_32bit(TConstPtrUInt(tpointerconstnode(p).value))) + else + internalerror(200404122); + end + { nil pointer ? } + else if p.nodetype=niln then + asmlist[cural].concat(Tai_const.Create_sym(nil)) + { maybe pchar ? } + else + if is_char(tpointerdef(t.def).pointertype.def) and + (p.nodetype<>addrn) then + begin + objectlibrary.getdatalabel(ll); + asmlist[cural].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); + asmlist[al_const].concat(Tai_align.Create(varalign)); + asmlist[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); + asmlist[al_const].concat(Tai_string.Create_pchar(ca,len+1)); + end + else + if is_constcharnode(p) then + asmlist[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 + objectlibrary.getdatalabel(ll); + asmlist[cural].concat(Tai_const.Create_sym(ll)); + asmlist[al_typedconsts].concat(tai_align.create(const_align(sizeof(aint)))); + asmlist[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).st_type=st_widestring) then + begin + pw:=pcompilerwidestring(tstringconstnode(p).value_str); + for i:=0 to tstringconstnode(p).len-1 do + asmlist[al_typedconsts].concat(Tai_const.Create_16bit(pw^.data[i])); + { ending #0 } + asmlist[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 + len:=tarraydef(tvecnode(hp).left.resulttype.def).elesize; + base:=tarraydef(tvecnode(hp).left.resulttype.def).lowrange; + 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 + asmlist[cural].concat(Tai_const.Createname(tprocsym(srsym).first_procdef.mangledname,AT_FUNCTION,offset)); + end; + globalvarsym : + asmlist[cural].concat(Tai_const.Createname(tglobalvarsym(srsym).mangledname,AT_DATA,offset)); + typedconstsym : + asmlist[cural].concat(Tai_const.Createname(ttypedconstsym(srsym).mangledname,AT_DATA,offset)); + labelsym : + asmlist[cural].concat(Tai_const.Createname(tlabelsym(srsym).mangledname,AT_LABEL,offset)); + constsym : + if tconstsym(srsym).consttyp=constresourcestring then + asmlist[cural].concat(Tai_const.Createname(make_mangledname('RESOURCESTRINGLIST',tconstsym(srsym).owner,''),AT_DATA,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 + asmlist[cural].concat(Tai_const.createname( + tobjectdef(tinlinenode(p).left.resulttype.def).vmt_mangledname,AT_DATA,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 + asmlist[cural].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 + asmlist[cural].concat(tai_const.create_8bit(Psetbytes(tsetconstnode(p).value_set)^[j+3])); + asmlist[cural].concat(tai_const.create_8bit(Psetbytes(tsetconstnode(p).value_set)^[j+2])); + asmlist[cural].concat(tai_const.create_8bit(Psetbytes(tsetconstnode(p).value_set)^[j+1])); + asmlist[cural].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 : asmlist[cural].concat(Tai_const.Create_8bit(Byte(tordconstnode(p).value))); + 2 : asmlist[cural].concat(Tai_const.Create_16bit(Word(tordconstnode(p).value))); + 4 : asmlist[cural].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; + asmlist[cural].concat(Tai_const.Create_8bit(strlength)); + { this can also handle longer strings } + getmem(ca,strlength+1); + move(strval^,ca^,strlength); + ca[strlength]:=#0; + asmlist[cural].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 } + asmlist[cural].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 + asmlist[cural].concat(Tai_const.Create_sym(nil)) + else + begin + objectlibrary.getdatalabel(ll); + asmlist[cural].concat(Tai_const.Create_sym(ll)); + asmlist[al_const].concat(tai_align.create(const_align(sizeof(aint)))); + asmlist[al_const].concat(Tai_const.Create_aint(-1)); + asmlist[al_const].concat(Tai_const.Create_aint(strlength)); + asmlist[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; + asmlist[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 + asmlist[cural].concat(Tai_const.Create_sym(nil)) + else + begin + objectlibrary.getdatalabel(ll); + asmlist[cural].concat(Tai_const.Create_sym(ll)); + asmlist[al_const].concat(tai_align.create(const_align(sizeof(aint)))); + asmlist[al_const].concat(Tai_const.Create_aint(-1)); + asmlist[al_const].concat(Tai_const.Create_aint(strlength*cwidechartype.def.size)); + asmlist[al_const].concat(Tai_label.Create(ll)); + for i:=0 to strlength-1 do + asmlist[al_const].concat(Tai_const.Create_16bit(pcompilerwidestring(strval)^.data[i])); + { ending #0 } + asmlist[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); + asmlist[cural].concat(Tai_const.Create_sym(nil)); + end + else + if try_to_consume(_LKLAMMER) then + begin + for l:=tarraydef(t.def).lowrange to tarraydef(t.def).highrange-1 do + begin + readtypedconst(tarraydef(t.def).elementtype,nil,writable); + consume(_COMMA); + end; + readtypedconst(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 + asmlist[cural].concat(Tai_const.Create_8bit(byte(ca^))); + inc(ca); + end + else + {Fill the remaining positions with #0.} + asmlist[cural].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 + asmlist[cural].concat(Tai_const.Create_sym(nil)); + if (po_methodpointer in tprocvardef(t.def).procoptions) then + asmlist[cural].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 + asmlist[cural].concat(Tai_const.createname( + tprocsym(tloadnode(p).symtableentry).first_procdef.mangledname,AT_FUNCTION,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 + asmlist[cural].concat(Tai_const.Create_32bit(longint(tmpguid.D1))); + asmlist[cural].concat(Tai_const.Create_16bit(tmpguid.D2)); + asmlist[cural].concat(Tai_const.Create_16bit(tmpguid.D3)); + for i:=Low(tmpguid.D4) to High(tmpguid.D4) do + asmlist[cural].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 + asmlist[cural].concat(Tai_const.Create_8bit(0)); + + { new position } + aktpos:=tfieldvarsym(srsym).fieldoffset+tfieldvarsym(srsym).vartype.def.size; + + { read the data } + readtypedconst(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 + asmlist[cural].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(parser_e_type_const_not_possible); + consume_all_until(_RKLAMMER); + end + else + begin + asmlist[cural].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 + asmlist[cural].concat(tai_const.create_8bit(0)); + asmlist[cural].concat(tai_const.createname(vmt_mangledname,AT_DATA,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 + asmlist[cural].concat(Tai_const.Create_8bit(0)); + + { new position } + aktpos:=fieldoffset+vartype.def.size; + + { read the data } + readtypedconst(vartype,nil,writable); + + if token=_SEMICOLON then + consume(_SEMICOLON) + else 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 + asmlist[cural].concat(tai_const.create_8bit(0)); + asmlist[cural].concat(tai_const.createname(tobjectdef(t.def).vmt_mangledname,AT_DATA,0)); + { this is more general } + aktpos:=tobjectdef(t.def).vmt_offset + sizeof(aint); + end; + for i:=1 to t.def.size-aktpos do + asmlist[cural].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; + myexit: + block_type:=old_block_type; + end; +{$ifdef fpc} + {$maxfpuregisters default} +{$endif fpc} + +end. |