diff options
Diffstat (limited to 'closures/compiler/pdecvar.pas')
-rw-r--r-- | closures/compiler/pdecvar.pas | 1864 |
1 files changed, 1864 insertions, 0 deletions
diff --git a/closures/compiler/pdecvar.pas b/closures/compiler/pdecvar.pas new file mode 100644 index 0000000000..e4be488a71 --- /dev/null +++ b/closures/compiler/pdecvar.pas @@ -0,0 +1,1864 @@ +{ + Copyright (c) 1998-2002 by Florian Klaempfl + + Parses variable declarations. Used for var statement and record + definitions + + 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 pdecvar; + +{$i fpcdefs.inc} + +interface + + uses + symsym,symdef; + + type + tvar_dec_option=(vd_record,vd_object,vd_threadvar,vd_class); + tvar_dec_options=set of tvar_dec_option; + + function read_property_dec(is_classproperty:boolean;astruct:tabstractrecorddef):tpropertysym; + + procedure read_var_decls(options:Tvar_dec_options); + + procedure read_record_fields(options:Tvar_dec_options); + + procedure read_public_and_external(vs: tabstractvarsym); + + procedure try_consume_sectiondirective(var asection: ansistring); + +implementation + + uses + SysUtils, + { common } + cutils,cclasses, + { global } + globtype,globals,tokens,verbose,constexp, + systems, + { symtable } + symconst,symbase,symtype,symtable,defutil,defcmp, + fmodule,htypechk, + { pass 1 } + node,pass_1,aasmdata, + nmat,nadd,ncal,nset,ncnv,ninl,ncon,nld,nflw,nmem,nutils, + { codegen } + ncgutil, + { parser } + scanner, + pbase,pexpr,ptype,ptconst,pdecsub, + { link } + import + ; + + + function read_property_dec(is_classproperty:boolean;astruct:tabstractrecorddef):tpropertysym; + + { convert a node tree to symlist and return the last + symbol } + function parse_symlist(pl:tpropaccesslist;var def:tdef):boolean; + var + idx : longint; + sym : tsym; + srsymtable : TSymtable; + st : TSymtable; + p : tnode; + begin + result:=true; + def:=nil; + if token=_ID then + begin + if assigned(astruct) then + sym:=search_struct_member(astruct,pattern) + else + searchsym(pattern,sym,srsymtable); + if assigned(sym) then + begin + if assigned(astruct) and + not is_visible_for_object(sym,astruct) then + Message(parser_e_cant_access_private_member); + case sym.typ of + fieldvarsym : + begin + if (symtablestack.top.currentvisibility<>vis_private) then + addsymref(sym); + pl.addsym(sl_load,sym); + def:=tfieldvarsym(sym).vardef; + end; + procsym : + begin + if (symtablestack.top.currentvisibility<>vis_private) then + addsymref(sym); + pl.addsym(sl_call,sym); + end; + else + begin + Message1(parser_e_illegal_field_or_method,orgpattern); + def:=generrordef; + result:=false; + end; + end; + end + else + begin + Message1(parser_e_illegal_field_or_method,orgpattern); + def:=generrordef; + result:=false; + end; + consume(_ID); + repeat + case token of + _ID, + _SEMICOLON : + begin + break; + end; + _POINT : + begin + consume(_POINT); + if assigned(def) then + begin + st:=def.GetSymtable(gs_record); + if assigned(st) then + begin + sym:=tsym(st.Find(pattern)); + if not(assigned(sym)) and is_object(def) then + sym:=search_struct_member(tobjectdef(def),pattern); + if assigned(sym) then + begin + pl.addsym(sl_subscript,sym); + case sym.typ of + fieldvarsym : + def:=tfieldvarsym(sym).vardef; + else + begin + Message1(sym_e_illegal_field,orgpattern); + result:=false; + end; + end; + end + else + begin + Message1(sym_e_illegal_field,orgpattern); + result:=false; + end; + end + else + begin + Message(parser_e_invalid_qualifier); + result:=false; + end; + end + else + begin + Message(parser_e_invalid_qualifier); + result:=false; + end; + consume(_ID); + end; + _LECKKLAMMER : + begin + consume(_LECKKLAMMER); + repeat + if def.typ=arraydef then + begin + idx:=0; + p:=comp_expr(true,false); + if (not codegenerror) then + begin + if (p.nodetype=ordconstn) then + begin + { type/range checking } + inserttypeconv(p,tarraydef(def).rangedef); + if (Tordconstnode(p).value<int64(low(longint))) or + (Tordconstnode(p).value>int64(high(longint))) then + message(parser_e_array_range_out_of_bounds) + else + idx:=Tordconstnode(p).value.svalue + end + else + Message(type_e_ordinal_expr_expected) + end; + pl.addconst(sl_vec,idx,p.resultdef); + p.free; + def:=tarraydef(def).elementdef; + end + else + begin + Message(parser_e_invalid_qualifier); + result:=false; + end; + until not try_to_consume(_COMMA); + consume(_RECKKLAMMER); + end; + else + begin + Message(parser_e_ill_property_access_sym); + result:=false; + break; + end; + end; + until false; + end + else + begin + Message(parser_e_ill_property_access_sym); + result:=false; + end; + end; + + function allow_default_property(p : tpropertysym) : boolean; + + begin + allow_default_property:= + (is_ordinal(p.propdef) or +{$ifndef cpu64bitaddr} + is_64bitint(p.propdef) or +{$endif cpu64bitaddr} + is_class(p.propdef) or + is_single(p.propdef) or + (p.propdef.typ in [classrefdef,pointerdef]) or + is_smallset(p.propdef) + ) and not + ( + (p.propdef.typ=arraydef) and + (ppo_indexed in p.propoptions) + ) and not + (ppo_hasparameters in p.propoptions); + end; + + procedure create_accessor_procsym(p: tpropertysym; pd: tprocdef; const prefix: string; + accesstype: tpropaccesslisttypes); + var + sym: tprocsym; + begin + handle_calling_convention(pd); + sym:=tprocsym.create(prefix+lower(p.realname)); + symtablestack.top.insert(sym); + pd.procsym:=sym; + include(pd.procoptions,po_dispid); + include(pd.procoptions,po_global); + pd.visibility:=vis_private; + proc_add_definition(pd); + p.propaccesslist[accesstype].addsym(sl_call,sym); + p.propaccesslist[accesstype].procdef:=pd; + end; + + procedure parse_dispinterface(p : tpropertysym; readpd,writepd: tprocdef; + var paranr: word); + var + hasread, haswrite: boolean; + pt: tnode; + hdispid: longint; + hparavs: tparavarsym; + begin + p.propaccesslist[palt_read].clear; + p.propaccesslist[palt_write].clear; + + hasread:=true; + haswrite:=true; + + if try_to_consume(_READONLY) then + haswrite:=false + else if try_to_consume(_WRITEONLY) then + hasread:=false; + + if try_to_consume(_DISPID) then + begin + pt:=comp_expr(true,false); + if is_constintnode(pt) then + if (Tordconstnode(pt).value<int64(low(longint))) or (Tordconstnode(pt).value>int64(high(longint))) then + message(parser_e_range_check_error) + else + hdispid:=Tordconstnode(pt).value.svalue + else + Message(parser_e_dispid_must_be_ord_const); + pt.free; + end + else + hdispid:=tobjectdef(astruct).get_next_dispid; + + { COM property is simply a pair of methods, tagged with 'propertyget' + and 'propertyset' flags (or a single method if access is restricted). + Creating these implicit accessor methods also allows the rest of compiler + to handle dispinterface properties the same way as regular ones. } + if hasread then + begin + readpd.returndef:=p.propdef; + readpd.dispid:=hdispid; + readpd.proctypeoption:=potype_propgetter; + create_accessor_procsym(p,readpd,'get$',palt_read); + end; + if haswrite then + begin + { add an extra parameter, a placeholder of the value to set } + inc(paranr); + hparavs:=tparavarsym.create('$value',10*paranr,vs_value,p.propdef,[]); + writepd.parast.insert(hparavs); + + writepd.proctypeoption:=potype_propsetter; + writepd.dispid:=hdispid; + create_accessor_procsym(p,writepd,'put$',palt_write); + end; + end; + + procedure add_parameters(p: tpropertysym; readprocdef, writeprocdef: tprocdef); + var + i: integer; + orig, hparavs: tparavarsym; + begin + for i := 0 to p.parast.SymList.Count - 1 do + begin + orig:=tparavarsym(p.parast.SymList[i]); + hparavs:=tparavarsym.create(orig.RealName,orig.paranr,orig.varspez,orig.vardef,[]); + readprocdef.parast.insert(hparavs); + hparavs:=tparavarsym.create(orig.RealName,orig.paranr,orig.varspez,orig.vardef,[]); + writeprocdef.parast.insert(hparavs); + end; + end; + + procedure add_index_parameter(var paranr: word; p: tpropertysym; readprocdef, writeprocdef: tprocdef); + var + hparavs: tparavarsym; + begin + inc(paranr); + hparavs:=tparavarsym.create('$index',10*paranr,vs_value,p.indexdef,[]); + readprocdef.parast.insert(hparavs); + hparavs:=tparavarsym.create('$index',10*paranr,vs_value,p.indexdef,[]); + writeprocdef.parast.insert(hparavs); + end; + + var + sym : tsym; + srsymtable: tsymtable; + p : tpropertysym; + overridden : tsym; + varspez : tvarspez; + hdef : tdef; + arraytype : tdef; + def : tdef; + pt : tnode; + sc : TFPObjectList; + paranr : word; + i : longint; + ImplIntf : TImplementedInterface; + found : boolean; + hreadparavs, + hparavs : tparavarsym; + storedprocdef: tprocvardef; + readprocdef, + writeprocdef : tprocdef; + begin + { Generate temp procdefs to search for matching read/write + procedures. the readprocdef will store all definitions } + paranr:=0; + readprocdef:=tprocdef.create(normal_function_level); + writeprocdef:=tprocdef.create(normal_function_level); + + readprocdef.struct:=astruct; + writeprocdef.struct:=astruct; + + if assigned(astruct) and is_classproperty then + begin + readprocdef.procoptions:=[po_staticmethod,po_classmethod]; + writeprocdef.procoptions:=[po_staticmethod,po_classmethod]; + end; + + if token<>_ID then + begin + consume(_ID); + consume(_SEMICOLON); + exit; + end; + { Generate propertysym and insert in symtablestack } + p:=tpropertysym.create(orgpattern); + p.visibility:=symtablestack.top.currentvisibility; + p.default:=longint($80000000); + if is_classproperty then + include(p.symoptions, sp_static); + symtablestack.top.insert(p); + consume(_ID); + { property parameters ? } + if try_to_consume(_LECKKLAMMER) then + begin + if (p.visibility=vis_published) and + not (m_delphi in current_settings.modeswitches) then + Message(parser_e_cant_publish_that_property); + { create a list of the parameters } + p.parast:=tparasymtable.create(nil,0); + symtablestack.push(p.parast); + sc:=TFPObjectList.create(false); + repeat + if try_to_consume(_VAR) then + varspez:=vs_var + else if try_to_consume(_CONST) then + varspez:=vs_const + else if try_to_consume(_CONSTREF) then + varspez:=vs_constref + else if (m_out in current_settings.modeswitches) and try_to_consume(_OUT) then + varspez:=vs_out + else + varspez:=vs_value; + sc.clear; + repeat + inc(paranr); + hreadparavs:=tparavarsym.create(orgpattern,10*paranr,varspez,generrordef,[]); + p.parast.insert(hreadparavs); + sc.add(hreadparavs); + consume(_ID); + until not try_to_consume(_COMMA); + if try_to_consume(_COLON) then + begin + if try_to_consume(_ARRAY) then + begin + consume(_OF); + { define range and type of range } + hdef:=tarraydef.create(0,-1,s32inttype); + { define field type } + single_type(arraytype,[]); + tarraydef(hdef).elementdef:=arraytype; + end + else + single_type(hdef,[]); + end + else + hdef:=cformaltype; + for i:=0 to sc.count-1 do + tparavarsym(sc[i]).vardef:=hdef; + until not try_to_consume(_SEMICOLON); + sc.free; + symtablestack.pop(p.parast); + consume(_RECKKLAMMER); + + { the parser need to know if a property has parameters, the + index parameter doesn't count (PFV) } + if paranr>0 then + begin + add_parameters(p,readprocdef,writeprocdef); + include(p.propoptions,ppo_hasparameters); + end; + end; + { overridden property ? } + { force property interface + there is a property parameter + a global property } + if (token=_COLON) or (paranr>0) or (astruct=nil) then + begin + consume(_COLON); + single_type(p.propdef,[stoAllowSpecialization]); + + if is_dispinterface(astruct) and not is_automatable(p.propdef) then + Message1(type_e_not_automatable,p.propdef.typename); + + if (idtoken=_INDEX) then + begin + consume(_INDEX); + pt:=comp_expr(true,false); + { Only allow enum and integer indexes. Convert all integer + values to s32int to be compatible with delphi, because the + procedure matching requires equal parameters } + if is_constnode(pt) and + is_ordinal(pt.resultdef) +{$ifndef cpu64bitaddr} + and (not is_64bitint(pt.resultdef)) +{$endif cpu64bitaddr} + then + begin + if is_integer(pt.resultdef) then + inserttypeconv_internal(pt,s32inttype); + p.index:=tordconstnode(pt).value.svalue; + end + else + begin + Message(parser_e_invalid_property_index_value); + p.index:=0; + end; + p.indexdef:=pt.resultdef; + include(p.propoptions,ppo_indexed); + { concat a longint to the para templates } + add_index_parameter(paranr,p,readprocdef,writeprocdef); + pt.free; + end; + end + else + begin + { do an property override } + if (astruct.typ=objectdef) then + overridden:=search_struct_member(tobjectdef(astruct).childof,p.name) + else + overridden:=nil; + if assigned(overridden) and + (overridden.typ=propertysym) and + not(is_dispinterface(astruct)) then + begin + p.overriddenpropsym:=tpropertysym(overridden); + { inherit all type related entries } + p.indexdef:=tpropertysym(overridden).indexdef; + p.propdef:=tpropertysym(overridden).propdef; + p.index:=tpropertysym(overridden).index; + p.default:=tpropertysym(overridden).default; + p.propoptions:=tpropertysym(overridden).propoptions + [ppo_overrides]; + if ppo_hasparameters in p.propoptions then + begin + p.parast:=tpropertysym(overridden).parast.getcopy; + add_parameters(p,readprocdef,writeprocdef); + paranr:=p.parast.SymList.Count; + end; + if ppo_indexed in p.propoptions then + add_index_parameter(paranr,p,readprocdef,writeprocdef); + end + else + begin + p.propdef:=generrordef; + message(parser_e_no_property_found_to_override); + end; + end; + if ((p.visibility=vis_published) or is_dispinterface(astruct)) and + (not(p.propdef.is_publishable) or (sp_static in p.symoptions)) then + begin + Message(parser_e_cant_publish_that_property); + p.visibility:=vis_public; + end; + + if not(is_dispinterface(astruct)) then + begin + if try_to_consume(_READ) then + begin + p.propaccesslist[palt_read].clear; + if parse_symlist(p.propaccesslist[palt_read],def) then + begin + sym:=p.propaccesslist[palt_read].firstsym^.sym; + case sym.typ of + procsym : + begin + { read is function returning the type of the property } + readprocdef.returndef:=p.propdef; + { Insert hidden parameters } + handle_calling_convention(readprocdef); + { search procdefs matching readprocdef } + { we ignore hidden stuff here because the property access symbol might have + non default calling conventions which might change the hidden stuff; + see tw3216.pp (FK) } + p.propaccesslist[palt_read].procdef:=Tprocsym(sym).Find_procdef_bypara(readprocdef.paras,p.propdef,[cpo_allowdefaults,cpo_ignorehidden]); + if not assigned(p.propaccesslist[palt_read].procdef) or + { because of cpo_ignorehidden we need to compare if it is a static class method and we have a class property } + ((sp_static in p.symoptions) <> tprocdef(p.propaccesslist[palt_read].procdef).no_self_node) then + Message(parser_e_ill_property_access_sym); + end; + fieldvarsym : + begin + if not assigned(def) then + internalerror(200310071); + if compare_defs(def,p.propdef,nothingn)>=te_equal then + begin + { property parameters are allowed if this is + an indexed property, because the index is then + the parameter. + Note: In the help of Kylix it is written + that it isn't allowed, but the compiler accepts it (PFV) } + if (ppo_hasparameters in p.propoptions) or + ((sp_static in p.symoptions) <> (sp_static in sym.symoptions)) then + Message(parser_e_ill_property_access_sym); + end + else + IncompatibleTypes(def,p.propdef); + end; + else + Message(parser_e_ill_property_access_sym); + end; + end; + end; + if try_to_consume(_WRITE) then + begin + p.propaccesslist[palt_write].clear; + if parse_symlist(p.propaccesslist[palt_write],def) then + begin + sym:=p.propaccesslist[palt_write].firstsym^.sym; + case sym.typ of + procsym : + begin + { write is a procedure with an extra value parameter + of the of the property } + writeprocdef.returndef:=voidtype; + inc(paranr); + hparavs:=tparavarsym.create('$value',10*paranr,vs_value,p.propdef,[]); + writeprocdef.parast.insert(hparavs); + { Insert hidden parameters } + handle_calling_convention(writeprocdef); + { search procdefs matching writeprocdef } + if cs_varpropsetter in current_settings.localswitches then + p.propaccesslist[palt_write].procdef:=Tprocsym(sym).Find_procdef_bypara(writeprocdef.paras,writeprocdef.returndef,[cpo_allowdefaults,cpo_ignorevarspez]) + else + p.propaccesslist[palt_write].procdef:=Tprocsym(sym).Find_procdef_bypara(writeprocdef.paras,writeprocdef.returndef,[cpo_allowdefaults]); + if not assigned(p.propaccesslist[palt_write].procdef) then + Message(parser_e_ill_property_access_sym); + end; + fieldvarsym : + begin + if not assigned(def) then + internalerror(200310072); + if compare_defs(def,p.propdef,nothingn)>=te_equal then + begin + { property parameters are allowed if this is + an indexed property, because the index is then + the parameter. + Note: In the help of Kylix it is written + that it isn't allowed, but the compiler accepts it (PFV) } + if (ppo_hasparameters in p.propoptions) or + ((sp_static in p.symoptions) <> (sp_static in sym.symoptions)) then + Message(parser_e_ill_property_access_sym); + end + else + IncompatibleTypes(def,p.propdef); + end; + else + Message(parser_e_ill_property_access_sym); + end; + end; + end; + end + else + parse_dispinterface(p,readprocdef,writeprocdef,paranr); + + { stored is not allowed for dispinterfaces, records or class properties } + if assigned(astruct) and not(is_dispinterface(astruct) or is_record(astruct)) and not is_classproperty then + begin + { ppo_stored is default on for not overridden properties } + if not assigned(p.overriddenpropsym) then + include(p.propoptions,ppo_stored); + if try_to_consume(_STORED) then + begin + include(p.propoptions,ppo_stored); + p.propaccesslist[palt_stored].clear; + case token of + _ID: + begin + { in the case that idtoken=_DEFAULT } + { we have to do nothing except } + { setting ppo_stored, it's the same } + { as stored true } + if idtoken<>_DEFAULT then + begin + { parse_symlist cannot deal with constsyms, and + we also don't want to put constsyms in symlists + since they have to be evaluated immediately rather + than each time the property is accessed + + The proper fix would be to always create a parse tree + and then convert that one, if appropriate, to a symlist. + Currently, we e.g. don't support any constant expressions + yet either here, while Delphi does. + + } + { make sure we don't let constants mask class fields/ + methods + } + if (not assigned(astruct) or + (search_struct_member(astruct,pattern)=nil)) and + searchsym(pattern,sym,srsymtable) and + (sym.typ = constsym) then + begin + addsymref(sym); + if not is_boolean(tconstsym(sym).constdef) then + Message(parser_e_stored_property_must_be_boolean) + else if (tconstsym(sym).value.valueord=0) then + { same as for _FALSE } + exclude(p.propoptions,ppo_stored) + else + { same as for _TRUE } + p.default:=longint($80000000); + consume(_ID); + end + else if parse_symlist(p.propaccesslist[palt_stored],def) then + begin + sym:=p.propaccesslist[palt_stored].firstsym^.sym; + case sym.typ of + procsym : + begin + { Create a temporary procvardef to handle parameters } + storedprocdef:=tprocvardef.create(normal_function_level); + include(storedprocdef.procoptions,po_methodpointer); + { Return type must be boolean } + storedprocdef.returndef:=pasbool8type; + { Add index parameter if needed } + if ppo_indexed in p.propoptions then + begin + hparavs:=tparavarsym.create('$index',10,vs_value,p.indexdef,[]); + storedprocdef.parast.insert(hparavs); + end; + + { Insert hidden parameters } + handle_calling_convention(storedprocdef); + p.propaccesslist[palt_stored].procdef:=Tprocsym(sym).Find_procdef_bypara(storedprocdef.paras,storedprocdef.returndef,[cpo_allowdefaults,cpo_ignorehidden]); + if not assigned(p.propaccesslist[palt_stored].procdef) then + message(parser_e_ill_property_storage_sym); + { Not needed anymore } + storedprocdef.owner.deletedef(storedprocdef); + end; + fieldvarsym : + begin + if not assigned(def) then + internalerror(200310073); + if (ppo_hasparameters in p.propoptions) or + not(is_boolean(def)) then + Message(parser_e_stored_property_must_be_boolean); + end; + else + Message(parser_e_ill_property_access_sym); + end; + end; + end; + end; + _FALSE: + begin + consume(_FALSE); + exclude(p.propoptions,ppo_stored); + end; + _TRUE: + begin + p.default:=longint($80000000); + consume(_TRUE); + end; + end; + end; + end; + if not is_record(astruct) and try_to_consume(_DEFAULT) then + begin + if not allow_default_property(p) then + begin + Message(parser_e_property_cant_have_a_default_value); + { Error recovery } + pt:=comp_expr(true,false); + pt.free; + end + else + begin + { Get the result of the default, the firstpass is + needed to support values like -1 } + pt:=comp_expr(true,false); + if (p.propdef.typ=setdef) and + (pt.nodetype=arrayconstructorn) then + begin + arrayconstructor_to_set(pt); + do_typecheckpass(pt); + end; + inserttypeconv(pt,p.propdef); + if not(is_constnode(pt)) then + Message(parser_e_property_default_value_must_const); + { Set default value } + case pt.nodetype of + setconstn : + p.default:=plongint(tsetconstnode(pt).value_set)^; + ordconstn : + if (Tordconstnode(pt).value<int64(low(longint))) or + (Tordconstnode(pt).value>int64(high(cardinal))) then + message(parser_e_range_check_error) + else + p.default:=longint(tordconstnode(pt).value.svalue); + niln : + p.default:=0; + realconstn: + p.default:=longint(single(trealconstnode(pt).value_real)); + end; + pt.free; + end; + end + else if not is_record(astruct) and try_to_consume(_NODEFAULT) then + begin + p.default:=longint($80000000); + end; +(* + else {if allow_default_property(p) then + begin + p.default:=longint($80000000); + end; +*) + { Parse possible "implements" keyword } + if not is_record(astruct) and try_to_consume(_IMPLEMENTS) then + repeat + single_type(def,[]); + + if not(is_interface(def)) then + message(parser_e_class_implements_must_be_interface); + + if is_interface(p.propdef) then + begin + { an interface type may delegate itself or one of its ancestors } + if not p.propdef.is_related(def) then + begin + message2(parser_e_implements_must_have_correct_type,def.typename,p.propdef.typename); + exit; + end; + end + else if is_class(p.propdef) then + begin + ImplIntf:=tobjectdef(p.propdef).find_implemented_interface(tobjectdef(def)); + if assigned(ImplIntf) then + begin + if compare_defs(ImplIntf.IntfDef,def,nothingn)<te_equal then + begin + message2(parser_e_implements_must_have_correct_type,ImplIntf.IntfDef.typename,def.typename); + exit; + end; + end + else + begin + message2(parser_e_class_doesnt_implement_interface,p.propdef.typename,def.typename); + exit; + end; + end + else + begin + message(parser_e_implements_must_be_class_or_interface); + exit; + end; + + + if not assigned(p.propaccesslist[palt_read].firstsym) then + begin + message(parser_e_implements_must_read_specifier); + exit; + end; + if assigned(p.propaccesslist[palt_read].procdef) and + (tprocdef(p.propaccesslist[palt_read].procdef).proccalloption<>pocall_default) then + message(parser_e_implements_getter_not_default_cc); + if assigned(p.propaccesslist[palt_write].firstsym) then + begin + message(parser_e_implements_must_not_have_write_specifier); + exit; + end; + if assigned(p.propaccesslist[palt_stored].firstsym) then + begin + message(parser_e_implements_must_not_have_stored_specifier); + exit; + end; + found:=false; + for i:=0 to tobjectdef(astruct).ImplementedInterfaces.Count-1 do + begin + ImplIntf:=TImplementedInterface(tobjectdef(astruct).ImplementedInterfaces[i]); + + if compare_defs(def,ImplIntf.IntfDef,nothingn)>=te_equal then + begin + found:=true; + break; + end; + end; + if found then + begin + { An interface may not be delegated by more than one property, + it also may not have method mappings. } + if Assigned(ImplIntf.ImplementsGetter) then + message1(parser_e_duplicate_implements_clause,ImplIntf.IntfDef.typename); + if Assigned(ImplIntf.NameMappings) then + message2(parser_e_mapping_no_implements,ImplIntf.IntfDef.typename,astruct.objrealname^); + + ImplIntf.ImplementsGetter:=p; + ImplIntf.VtblImplIntf:=ImplIntf; + case p.propaccesslist[palt_read].firstsym^.sym.typ of + procsym : + begin + if (po_virtualmethod in tprocdef(p.propaccesslist[palt_read].procdef).procoptions) and + not is_objectpascal_helper(tprocdef(p.propaccesslist[palt_read].procdef).struct) then + ImplIntf.IType:=etVirtualMethodResult + else + ImplIntf.IType:=etStaticMethodResult; + end; + fieldvarsym : + begin + ImplIntf.IType:=etFieldValue; + { this must be done more sophisticated, here is also probably the wrong place } + ImplIntf.IOffset:=tfieldvarsym(p.propaccesslist[palt_read].firstsym^.sym).fieldoffset; + end + else + internalerror(200802161); + end; + if not is_interface(p.propdef) then + case ImplIntf.IType of + etVirtualMethodResult: ImplIntf.IType := etVirtualMethodClass; + etStaticMethodResult: ImplIntf.IType := etStaticMethodClass; + etFieldValue: ImplIntf.IType := etFieldValueClass; + else + internalerror(200912101); + end; + end + else + message1(parser_e_implements_uses_non_implemented_interface,def.typename); + until not try_to_consume(_COMMA); + + { remove unneeded procdefs } + if readprocdef.proctypeoption<>potype_propgetter then + readprocdef.owner.deletedef(readprocdef); + if writeprocdef.proctypeoption<>potype_propsetter then + writeprocdef.owner.deletedef(writeprocdef); + + result:=p; + end; + + + function maybe_parse_proc_directives(def:tdef):boolean; + var + newtype : ttypesym; + begin + result:=false; + { Process procvar directives before = and ; } + if (def.typ=procvardef) and + (def.typesym=nil) and + check_proc_directive(true) then + begin + newtype:=ttypesym.create('unnamed',def); + parse_var_proc_directives(tsym(newtype)); + newtype.typedef:=nil; + def.typesym:=nil; + newtype.free; + result:=true; + end; + end; + + + const + variantrecordlevel : longint = 0; + + + procedure read_public_and_external_sc(sc:TFPObjectList); + var + vs: tabstractvarsym; + begin + { only allowed for one var } + vs:=tabstractvarsym(sc[0]); + if sc.count>1 then + Message(parser_e_absolute_only_one_var); + read_public_and_external(vs); + end; + + + procedure read_public_and_external(vs: tabstractvarsym); + var + is_dll, + is_cdecl, + is_external_var, + is_weak_external, + is_public_var : boolean; + dll_name,section_name, + C_name,mangledname : string; + begin + { only allowed for one var } + { only allow external and public on global symbols } + if vs.typ<>staticvarsym then + begin + Message(parser_e_no_local_var_external); + exit; + end; + { defaults } + is_dll:=false; + is_cdecl:=false; + is_external_var:=false; + is_public_var:=false; + section_name := ''; + C_name:=vs.realname; + + { macpas specific handling due to some switches} + if (m_mac in current_settings.modeswitches) then + begin + if (cs_external_var in current_settings.localswitches) then + begin {The effect of this is the same as if cvar; external; has been given as directives.} + is_cdecl:=true; + is_external_var:=true; + end + else if (cs_externally_visible in current_settings.localswitches) then + begin {The effect of this is the same as if cvar has been given as directives and it's made public.} + is_cdecl:=true; + is_public_var:=true; + end; + end; + + { cdecl } + if try_to_consume(_CVAR) then + begin + consume(_SEMICOLON); + is_cdecl:=true; + end; + + { external } + is_weak_external:=try_to_consume(_WEAKEXTERNAL); + if is_weak_external or + try_to_consume(_EXTERNAL) then + begin + is_external_var:=true; + if (idtoken<>_NAME) and (token<>_SEMICOLON) then + begin + is_dll:=true; + dll_name:=get_stringconst; + if ExtractFileExt(dll_name)='' then + dll_name:=ChangeFileExt(dll_name,target_info.sharedlibext); + end; + if not(is_cdecl) and try_to_consume(_NAME) then + C_name:=get_stringconst; + consume(_SEMICOLON); + end; + + { export or public } + if idtoken in [_EXPORT,_PUBLIC] then + begin + consume(_ID); + if is_external_var then + Message(parser_e_not_external_and_export) + else + is_public_var:=true; + if try_to_consume(_NAME) then + C_name:=get_stringconst; + if (target_info.system in systems_allow_section_no_semicolon) and + (vs.typ=staticvarsym) and + try_to_consume (_SECTION) then + section_name:=get_stringconst; + consume(_SEMICOLON); + end; + + { Windows uses an indirect reference using import tables } + if is_dll and + (target_info.system in systems_all_windows) then + include(vs.varoptions,vo_is_dll_var); + + { This can only happen if vs.typ=staticvarsym } + if section_name<>'' then + begin + tstaticvarsym(vs).section:=section_name; + include(vs.varoptions,vo_has_section); + end; + + + { Add C _ prefix } + if is_cdecl or + ( + is_dll and + (target_info.system in systems_darwin) + ) then + C_Name := target_info.Cprefix+C_Name; + + if is_public_var then + begin + include(vs.varoptions,vo_is_public); + vs.varregable := vr_none; + { mark as referenced } + inc(vs.refs); + end; + + mangledname:=C_name; + { now we can insert it in the import lib if its a dll, or + add it to the externals } + if is_external_var then + begin + if vo_is_typed_const in vs.varoptions then + Message(parser_e_initialized_not_for_external); + include(vs.varoptions,vo_is_external); + if (is_weak_external) then + begin + if not(target_info.system in systems_weak_linking) then + message(parser_e_weak_external_not_supported); + include(vs.varoptions,vo_is_weak_external); + end; + vs.varregable := vr_none; + if is_dll then + begin + if target_info.system in (systems_all_windows + systems_nativent + + [system_i386_emx, system_i386_os2]) then + mangledname:=make_dllmangledname(dll_name,C_name,0,pocall_none); + + current_module.AddExternalImport(dll_name,C_Name,mangledname,0,true,false); + end + else + if tf_has_dllscanner in target_info.flags then + current_module.dllscannerinputlist.Add(vs.mangledname,vs); + end; + + { Set the assembler name } + tstaticvarsym(vs).set_mangledname(mangledname); + end; + + + procedure try_consume_sectiondirective(var asection: ansistring); + begin + if idtoken=_SECTION then + begin + consume(_ID); + asection:=get_stringconst; + consume(_SEMICOLON); + end; + end; + + + procedure read_var_decls(options:Tvar_dec_options); + + procedure read_default_value(sc : TFPObjectList); + var + vs : tabstractnormalvarsym; + tcsym : tstaticvarsym; + begin + vs:=tabstractnormalvarsym(sc[0]); + if sc.count>1 then + Message(parser_e_initialized_only_one_var); + if vo_is_thread_var in vs.varoptions then + Message(parser_e_initialized_not_for_threadvar); + consume(_EQ); + case vs.typ of + localvarsym : + begin + tcsym:=tstaticvarsym.create('$default'+vs.realname,vs_const,vs.vardef,[]); + include(tcsym.symoptions,sp_internal); + vs.defaultconstsym:=tcsym; + symtablestack.top.insert(tcsym); + read_typed_const(current_asmdata.asmlists[al_typedconsts],tcsym,false); + end; + staticvarsym : + begin + read_typed_const(current_asmdata.asmlists[al_typedconsts],tstaticvarsym(vs),false); + end; + else + internalerror(200611051); + end; + vs.varstate:=vs_initialised; + end; + +{$ifdef gpc_mode} + procedure read_gpc_name(sc : TFPObjectList); + var + vs : tabstractnormalvarsym; + C_Name : string; + begin + consume(_ID); + C_Name:=get_stringconst; + vs:=tabstractnormalvarsym(sc[0]); + if sc.count>1 then + Message(parser_e_absolute_only_one_var); + if vs.typ=staticvarsym then + begin + tstaticvarsym(vs).set_mangledname(C_Name); + include(vs.varoptions,vo_is_external); + end + else + Message(parser_e_no_local_var_external); + end; +{$endif} + + procedure read_absolute(sc : TFPObjectList); + var + vs : tabstractvarsym; + abssym : tabsolutevarsym; + pt,hp : tnode; + st : tsymtable; + {$ifdef i386} + tmpaddr : int64; + {$endif} + begin + abssym:=nil; + { only allowed for one var } + vs:=tabstractvarsym(sc[0]); + if sc.count>1 then + Message(parser_e_absolute_only_one_var); + if vo_is_typed_const in vs.varoptions then + Message(parser_e_initialized_not_for_external); + { parse the rest } + pt:=expr(true); + { check allowed absolute types } + if (pt.nodetype=stringconstn) or + (is_constcharnode(pt)) then + begin + abssym:=tabsolutevarsym.create(vs.realname,vs.vardef); + abssym.fileinfo:=vs.fileinfo; + if pt.nodetype=stringconstn then + abssym.asmname:=stringdup(strpas(tstringconstnode(pt).value_str)) + else + abssym.asmname:=stringdup(chr(tordconstnode(pt).value.svalue)); + consume(token); + abssym.abstyp:=toasm; + end + { address } + else if is_constintnode(pt) then + begin + abssym:=tabsolutevarsym.create(vs.realname,vs.vardef); + abssym.fileinfo:=vs.fileinfo; + abssym.abstyp:=toaddr; +{$ifndef cpu64bitaddr} + { on 64 bit systems, abssym.addroffset is a qword and hence this + test is useless (value is a 64 bit entity) and will always fail + for positive values (since int64(high(abssym.addroffset))=-1 + } + if (Tordconstnode(pt).value<int64(low(abssym.addroffset))) or + (Tordconstnode(pt).value>int64(high(abssym.addroffset))) then + message(parser_e_range_check_error) + else +{$endif} + abssym.addroffset:=Tordconstnode(pt).value.svalue; +{$ifdef i386} + abssym.absseg:=false; + if (target_info.system in [system_i386_go32v2,system_i386_watcom]) and + try_to_consume(_COLON) then + begin + pt.free; + pt:=expr(true); + if is_constintnode(pt) then + begin + tmpaddr:=abssym.addroffset shl 4+tordconstnode(pt).value.svalue; + if (tmpaddr<int64(low(abssym.addroffset))) or + (tmpaddr>int64(high(abssym.addroffset))) then + message(parser_e_range_check_error) + else + abssym.addroffset:=tmpaddr; + abssym.absseg:=true; + end + else + Message(type_e_ordinal_expr_expected); + end; +{$endif i386} + end + { variable } + else + begin + { we have to be able to take the address of the absolute + expression + } + valid_for_addr(pt,true); + { remove subscriptn before checking for loadn } + hp:=pt; + while (hp.nodetype in [subscriptn,typeconvn,vecn]) do + begin + { check for implicit dereferencing and reject it } + if (hp.nodetype in [subscriptn,vecn]) then + begin + if (tunarynode(hp).left.resultdef.typ in [pointerdef,classrefdef]) then + break; + { catch, e.g., 'var b: char absolute pchar_var[5];" + (pchar_var[5] is a pchar_2_string typeconv -> + the vecn only sees an array of char) + I don't know if all of these type conversions are + possible, but they're definitely all bad. + } + if (tunarynode(hp).left.nodetype=typeconvn) and + (ttypeconvnode(tunarynode(hp).left).convtype in + [tc_pchar_2_string,tc_pointer_2_array, + tc_intf_2_string,tc_intf_2_guid, + tc_dynarray_2_variant,tc_interface_2_variant, + tc_array_2_dynarray]) then + break; + + if (tunarynode(hp).left.resultdef.typ=stringdef) and + not(tstringdef(tunarynode(hp).left.resultdef).stringtype in [st_shortstring,st_longstring]) then + break; + if (tunarynode(hp).left.resultdef.typ=objectdef) and + (tobjectdef(tunarynode(hp).left.resultdef).objecttype<>odt_object) then + break; + if is_dynamic_array(tunarynode(hp).left.resultdef) then + break; + end; + hp:=tunarynode(hp).left; + end; + if (hp.nodetype=loadn) then + begin + { we should check the result type of loadn } + if not (tloadnode(hp).symtableentry.typ in [fieldvarsym,staticvarsym,localvarsym,paravarsym]) then + Message(parser_e_absolute_only_to_var_or_const); + abssym:=tabsolutevarsym.create(vs.realname,vs.vardef); + abssym.fileinfo:=vs.fileinfo; + abssym.abstyp:=tovar; + abssym.ref:=node_to_propaccesslist(pt); + + { if the sizes are different, can't be a regvar since you } + { can't be "absolute upper 8 bits of a register" (except } + { if its a record field of the same size of a record } + { regvar, but in that case pt.resultdef.size will have } + { the same size since it refers to the field and not to } + { the whole record -- which is why we use pt and not hp) } + + { we can't take the size of an open array } + if is_open_array(pt.resultdef) or + (vs.vardef.size <> pt.resultdef.size) then + make_not_regable(pt,[ra_addr_regable]); + end + else + Message(parser_e_absolute_only_to_var_or_const); + end; + pt.free; + { replace old varsym with the new absolutevarsym } + if assigned(abssym) then + begin + st:=vs.owner; + vs.owner.Delete(vs); + st.insert(abssym); + sc[0]:=abssym; + end; + end; + + var + sc : TFPObjectList; + vs : tabstractvarsym; + hdef : tdef; + i : longint; + semicoloneaten, + allowdefaultvalue, + hasdefaultvalue : boolean; + hintsymoptions : tsymoptions; + deprecatedmsg : pshortstring; + old_block_type : tblock_type; + sectionname : ansistring; + begin + old_block_type:=block_type; + block_type:=bt_var; + { Force an expected ID error message } + if not (token in [_ID,_CASE,_END]) then + consume(_ID); + { read vars } + sc:=TFPObjectList.create(false); + while (token=_ID) do + begin + semicoloneaten:=false; + hasdefaultvalue:=false; + allowdefaultvalue:=true; + sc.clear; + repeat + if (token = _ID) then + begin + case symtablestack.top.symtabletype of + localsymtable : + vs:=tlocalvarsym.create(orgpattern,vs_value,generrordef,[]); + staticsymtable, + globalsymtable : + begin + vs:=tstaticvarsym.create(orgpattern,vs_value,generrordef,[]); + if vd_threadvar in options then + include(vs.varoptions,vo_is_thread_var); + end; + else + internalerror(200411064); + end; + sc.add(vs); + symtablestack.top.insert(vs); + end; + consume(_ID); + until not try_to_consume(_COMMA); + + { read variable type def } + block_type:=bt_var_type; + consume(_COLON); + +{$ifdef gpc_mode} + if (m_gpc in current_settings.modeswitches) and + (token=_ID) and + (orgpattern='__asmname__') then + read_gpc_name(sc); +{$endif} + + read_anon_type(hdef,false); + for i:=0 to sc.count-1 do + begin + vs:=tabstractvarsym(sc[i]); + vs.vardef:=hdef; + end; + block_type:=bt_var; + + { Process procvar directives } + if maybe_parse_proc_directives(hdef) then + semicoloneaten:=true; + + { check for absolute } + if try_to_consume(_ABSOLUTE) then + begin + read_absolute(sc); + allowdefaultvalue:=false; + end; + + { Check for EXTERNAL etc directives before a semicolon } + if (idtoken in [_EXPORT,_EXTERNAL,_WEAKEXTERNAL,_PUBLIC,_CVAR]) then + begin + read_public_and_external_sc(sc); + allowdefaultvalue:=false; + semicoloneaten:=true; + end; + + { try to parse the hint directives } + hintsymoptions:=[]; + deprecatedmsg:=nil; + try_consume_hintdirective(hintsymoptions,deprecatedmsg); + for i:=0 to sc.count-1 do + begin + vs:=tabstractvarsym(sc[i]); + vs.symoptions := vs.symoptions + hintsymoptions; + if deprecatedmsg<>nil then + vs.deprecatedmsg:=stringdup(deprecatedmsg^); + end; + stringdispose(deprecatedmsg); + + { Handling of Delphi typed const = initialized vars } + if allowdefaultvalue and + (token=_EQ) and + not(m_tp7 in current_settings.modeswitches) and + (symtablestack.top.symtabletype<>parasymtable) then + begin + { Add calling convention for procvar } + if (hdef.typ=procvardef) and + (hdef.typesym=nil) then + handle_calling_convention(tprocvardef(hdef)); + read_default_value(sc); + hasdefaultvalue:=true; + end + else + begin + if not(semicoloneaten) then + consume(_SEMICOLON); + end; + + { Support calling convention for procvars after semicolon } + if not(hasdefaultvalue) and + (hdef.typ=procvardef) and + (hdef.typesym=nil) then + begin + { Parse procvar directives after ; } + maybe_parse_proc_directives(hdef); + { Add calling convention for procvar } + handle_calling_convention(tprocvardef(hdef)); + { Handling of Delphi typed const = initialized vars } + if (token=_EQ) and + not(m_tp7 in current_settings.modeswitches) and + (symtablestack.top.symtabletype<>parasymtable) then + begin + read_default_value(sc); + hasdefaultvalue:=true; + end; + end; + + { Check for EXTERNAL etc directives or, in macpas, if cs_external_var is set} + if ( + ( + (idtoken in [_EXPORT,_EXTERNAL,_WEAKEXTERNAL,_PUBLIC,_CVAR]) and + (m_cvar_support in current_settings.modeswitches) + ) or + ( + (m_mac in current_settings.modeswitches) and + ( + (cs_external_var in current_settings.localswitches) or + (cs_externally_visible in current_settings.localswitches) + ) + ) + ) then + read_public_and_external_sc(sc); + + { try to parse a section directive } + if (target_info.system in systems_allow_section) and + (symtablestack.top.symtabletype in [staticsymtable,globalsymtable]) and + (idtoken=_SECTION) then + begin + try_consume_sectiondirective(sectionname); + if sectionname<>'' then + begin + for i:=0 to sc.count-1 do + begin + vs:=tabstractvarsym(sc[i]); + if (vs.varoptions *[vo_is_external,vo_is_weak_external])<>[] then + Message(parser_e_externals_no_section); + if vs.typ<>staticvarsym then + Message(parser_e_section_no_locals); + tstaticvarsym(vs).section:=sectionname; + include(vs.varoptions, vo_has_section); + end; + end; + end; + + { allocate normal variable (non-external and non-typed-const) staticvarsyms } + for i:=0 to sc.count-1 do + begin + vs:=tabstractvarsym(sc[i]); + if (vs.typ=staticvarsym) and + not(vo_is_typed_const in vs.varoptions) and + not(vo_is_external in vs.varoptions) then + insertbssdata(tstaticvarsym(vs)); + end; + end; + block_type:=old_block_type; + { free the list } + sc.free; + end; + + + procedure read_record_fields(options:Tvar_dec_options); + var + sc : TFPObjectList; + i : longint; + hs,sorg,static_name : string; + hdef,casetype : tdef; + { maxsize contains the max. size of a variant } + { startvarrec contains the start of the variant part of a record } + maxsize, startvarrecsize : longint; + usedalign, + maxalignment,startvarrecalign, + maxpadalign, startpadalign: shortint; + pt : tnode; + fieldvs : tfieldvarsym; + hstaticvs : tstaticvarsym; + vs : tabstractvarsym; + srsym : tsym; + srsymtable : TSymtable; + visibility : tvisibility; + recst : tabstractrecordsymtable; + recstlist : tfpobjectlist; + unionsymtable : trecordsymtable; + offset : longint; + uniondef : trecorddef; + hintsymoptions : tsymoptions; + deprecatedmsg : pshortstring; + semicoloneaten, + removeclassoption: boolean; +{$if defined(powerpc) or defined(powerpc64)} + tempdef: tdef; + is_first_type: boolean; +{$endif powerpc or powerpc64} + sl: tpropaccesslist; + old_block_type: tblock_type; + begin + old_block_type:=block_type; + block_type:=bt_var; + recst:=tabstractrecordsymtable(symtablestack.top); +{$if defined(powerpc) or defined(powerpc64)} + is_first_type:=true; +{$endif powerpc or powerpc64} + { Force an expected ID error message } + if not (token in [_ID,_CASE,_END]) then + consume(_ID); + { read vars } + sc:=TFPObjectList.create(false); + recstlist:=TFPObjectList.create(false); + removeclassoption:=false; + while (token=_ID) and + not(((vd_object in options) or + ((vd_record in options) and (m_advanced_records in current_settings.modeswitches))) and + (idtoken in [_PUBLIC,_PRIVATE,_PUBLISHED,_PROTECTED,_STRICT])) do + begin + visibility:=symtablestack.top.currentvisibility; + semicoloneaten:=false; + sc.clear; + repeat + sorg:=orgpattern; + if token=_ID then + begin + vs:=tfieldvarsym.create(sorg,vs_value,generrordef,[]); + sc.add(vs); + recst.insert(vs); + end; + consume(_ID); + until not try_to_consume(_COMMA); + if m_delphi in current_settings.modeswitches then + block_type:=bt_var_type + else + block_type:=old_block_type; + consume(_COLON); + + { Don't search for types where they can't be: + types can be only in objects, classes and records. + This just speedup the search a bit. } + recstlist.count:=0; + if not is_class_or_object(tdef(recst.defowner)) and + not is_record(tdef(recst.defowner)) then + begin + recstlist.add(recst); + symtablestack.pop(recst); + end; + read_anon_type(hdef,false); + block_type:=bt_var; + { allow only static fields reference to struct where they are declared } + if not (vd_class in options) and + (is_object(hdef) or is_record(hdef)) and + is_owned_by(tabstractrecorddef(recst.defowner),tabstractrecorddef(hdef)) then + begin + Message1(type_e_type_is_not_completly_defined, tabstractrecorddef(hdef).RttiName); + { for error recovery or compiler will crash later } + hdef:=generrordef; + end; + { restore stack } + for i:=recstlist.count-1 downto 0 do + begin + recst:=tabstractrecordsymtable(recstlist[i]); + symtablestack.push(recst); + end; + + { Process procvar directives } + if maybe_parse_proc_directives(hdef) then + semicoloneaten:=true; + +{$if defined(powerpc) or defined(powerpc64)} + { from gcc/gcc/config/rs6000/rs6000.h: + /* APPLE LOCAL begin Macintosh alignment 2002-1-22 ff */ + /* Return the alignment of a struct based on the Macintosh PowerPC + alignment rules. In general the alignment of a struct is + determined by the greatest alignment of its elements. However, the + PowerPC rules cause the alignment of a struct to peg at word + alignment except when the first field has greater than word + (32-bit) alignment, in which case the alignment is determined by + the alignment of the first field. */ + } + if (target_info.system in [system_powerpc_darwin, system_powerpc_macos, system_powerpc64_darwin]) and + is_first_type and + (symtablestack.top.symtabletype=recordsymtable) and + (trecordsymtable(symtablestack.top).usefieldalignment=C_alignment) then + begin + tempdef:=hdef; + while tempdef.typ=arraydef do + tempdef:=tarraydef(tempdef).elementdef; + if tempdef.typ<>recorddef then + maxpadalign:=tempdef.alignment + else + maxpadalign:=trecorddef(tempdef).padalignment; + + if (maxpadalign>4) and + (maxpadalign>trecordsymtable(symtablestack.top).padalignment) then + trecordsymtable(symtablestack.top).padalignment:=maxpadalign; + is_first_type:=false; + end; +{$endif powerpc or powerpc64} + + { types that use init/final are not allowed in variant parts, but + classes are allowed } + if (variantrecordlevel>0) then + if is_managed_type(hdef) then + Message(parser_e_cant_use_inittable_here) + else + if hdef.typ=undefineddef then + Message(parser_e_cant_use_type_parameters_here); + + { try to parse the hint directives } + hintsymoptions:=[]; + deprecatedmsg:=nil; + try_consume_hintdirective(hintsymoptions,deprecatedmsg); + + { update variable type and hints } + for i:=0 to sc.count-1 do + begin + fieldvs:=tfieldvarsym(sc[i]); + fieldvs.vardef:=hdef; + { insert any additional hint directives } + fieldvs.symoptions := fieldvs.symoptions + hintsymoptions; + if deprecatedmsg<>nil then + fieldvs.deprecatedmsg:=stringdup(deprecatedmsg^); + end; + stringdispose(deprecatedmsg); + + { Records and objects can't have default values } + { for a record there doesn't need to be a ; before the END or ) } + if not(token in [_END,_RKLAMMER]) and + not(semicoloneaten) then + consume(_SEMICOLON); + + { Parse procvar directives after ; } + maybe_parse_proc_directives(hdef); + + { Add calling convention for procvar } + if (hdef.typ=procvardef) and + (hdef.typesym=nil) then + handle_calling_convention(tprocvardef(hdef)); + + { check if it is a class field } + if (vd_object in options) then + begin + { if it is not a class var section and token=STATIC then it is a class field too } + if not (vd_class in options) and try_to_consume(_STATIC) then + begin + consume(_SEMICOLON); + include(options,vd_class); + removeclassoption:=true; + end; + end; + if vd_class in options then + begin + { add static flag and staticvarsyms } + for i:=0 to sc.count-1 do + begin + fieldvs:=tfieldvarsym(sc[i]); + include(fieldvs.symoptions,sp_static); + { generate the symbol which reserves the space } + static_name:=lower(generate_nested_name(recst,'_'))+'_'+fieldvs.name; + hstaticvs:=tstaticvarsym.create('$_static_'+static_name,vs_value,hdef,[]); + include(hstaticvs.symoptions,sp_internal); + recst.get_unit_symtable.insert(hstaticvs); + insertbssdata(hstaticvs); + { generate the symbol for the access } + sl:=tpropaccesslist.create; + sl.addsym(sl_load,hstaticvs); + recst.insert(tabsolutevarsym.create_ref('$'+static_name,hdef,sl)); + end; + if removeclassoption then + begin + exclude(options,vd_class); + removeclassoption:=false; + end; + end; + if (visibility=vis_published) and + not(is_class(hdef)) then + begin + MessagePos(tfieldvarsym(sc[0]).fileinfo,parser_e_cant_publish_that); + visibility:=vis_public; + end; + + if (visibility=vis_published) and + not(oo_can_have_published in tobjectdef(hdef).objectoptions) and + not(m_delphi in current_settings.modeswitches) then + begin + MessagePos(tfieldvarsym(sc[0]).fileinfo,parser_e_only_publishable_classes_can_be_published); + visibility:=vis_public; + end; + + { Generate field in the recordsymtable } + for i:=0 to sc.count-1 do + begin + fieldvs:=tfieldvarsym(sc[i]); + { static data fields are already inserted in the globalsymtable } + if not(sp_static in fieldvs.symoptions) then + recst.addfield(fieldvs,visibility); + end; + end; + recstlist.free; + + if m_delphi in current_settings.modeswitches then + block_type:=bt_var_type + else + block_type:=old_block_type; + { Check for Case } + if (vd_record in options) and + try_to_consume(_CASE) then + begin + maxsize:=0; + maxalignment:=0; + maxpadalign:=0; + { including a field declaration? } + fieldvs:=nil; + sorg:=orgpattern; + hs:=pattern; + searchsym(hs,srsym,srsymtable); + if not(assigned(srsym) and (srsym.typ in [typesym,unitsym])) then + begin + consume(_ID); + consume(_COLON); + fieldvs:=tfieldvarsym.create(sorg,vs_value,generrordef,[]); + symtablestack.top.insert(fieldvs); + end; + read_anon_type(casetype,true); + block_type:=bt_var; + if assigned(fieldvs) then + begin + fieldvs.vardef:=casetype; + recst.addfield(fieldvs,recst.currentvisibility); + end; + if not(is_ordinal(casetype)) +{$ifndef cpu64bitaddr} + or is_64bitint(casetype) +{$endif cpu64bitaddr} + then + Message(type_e_ordinal_expr_expected); + consume(_OF); + + UnionSymtable:=trecordsymtable.create('',current_settings.packrecords); + UnionDef:=trecorddef.create('',unionsymtable); + uniondef.isunion:=true; + startvarrecsize:=UnionSymtable.datasize; + { align the bitpacking to the next byte } + UnionSymtable.datasize:=startvarrecsize; + startvarrecalign:=UnionSymtable.fieldalignment; + startpadalign:=Unionsymtable.padalignment; + symtablestack.push(UnionSymtable); + repeat + repeat + pt:=comp_expr(true,false); + if not(pt.nodetype=ordconstn) then + Message(parser_e_illegal_expression); + if try_to_consume(_POINTPOINT) then + pt:=crangenode.create(pt,comp_expr(true,false)); + pt.free; + if token=_COMMA then + consume(_COMMA) + else + break; + until false; + if m_delphi in current_settings.modeswitches then + block_type:=bt_var_type + else + block_type:=old_block_type; + consume(_COLON); + { read the vars } + consume(_LKLAMMER); + inc(variantrecordlevel); + if token<>_RKLAMMER then + read_record_fields([vd_record]); + dec(variantrecordlevel); + consume(_RKLAMMER); + { calculates maximal variant size } + maxsize:=max(maxsize,unionsymtable.datasize); + maxalignment:=max(maxalignment,unionsymtable.fieldalignment); + maxpadalign:=max(maxpadalign,unionsymtable.padalignment); + { the items of the next variant are overlayed } + unionsymtable.datasize:=startvarrecsize; + unionsymtable.fieldalignment:=startvarrecalign; + unionsymtable.padalignment:=startpadalign; + if (token<>_END) and (token<>_RKLAMMER) then + consume(_SEMICOLON) + else + break; + until (token=_END) or (token=_RKLAMMER); + symtablestack.pop(UnionSymtable); + { at last set the record size to that of the biggest variant } + unionsymtable.datasize:=maxsize; + unionsymtable.fieldalignment:=maxalignment; + unionsymtable.addalignmentpadding; +{$if defined(powerpc) or defined(powerpc64)} + { parent inherits the alignment padding if the variant is the first "field" of the parent record/variant } + if (target_info.system in [system_powerpc_darwin, system_powerpc_macos, system_powerpc64_darwin]) and + is_first_type and + (recst.usefieldalignment=C_alignment) and + (maxpadalign>recst.padalignment) then + recst.padalignment:=maxpadalign; +{$endif powerpc or powerpc64} + { Align the offset where the union symtable is added } + case recst.usefieldalignment of + { allow the unionsymtable to be aligned however it wants } + { (within the global min/max limits) } + 0, { default } + C_alignment: + usedalign:=used_align(unionsymtable.recordalignment,current_settings.alignment.recordalignmin,current_settings.alignment.maxCrecordalign); + { 1 byte alignment if we are bitpacked } + bit_alignment: + usedalign:=1; + mac68k_alignment: + usedalign:=2; + { otherwise alignment at the packrecords alignment of the } + { current record } + else + usedalign:=used_align(recst.fieldalignment,current_settings.alignment.recordalignmin,current_settings.alignment.recordalignmax); + end; + offset:=align(recst.datasize,usedalign); + recst.datasize:=offset+unionsymtable.datasize; + + if unionsymtable.recordalignment>recst.fieldalignment then + recst.fieldalignment:=unionsymtable.recordalignment; + + trecordsymtable(recst).insertunionst(Unionsymtable,offset); + uniondef.owner.deletedef(uniondef); + end; + { free the list } + sc.free; +{$ifdef powerpc} + is_first_type := false; +{$endif powerpc} + block_type:=old_block_type; + end; + +end. |