{ $Id$ Copyright (c) 1998 by Florian Klaempfl, Daniel Mantione Does the parsing of the procedures/functions 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 psub; interface uses cobjects, symconst,tokens,symtable; const pd_global = $1; { directive must be global } pd_body = $2; { directive needs a body } pd_implemen = $4; { directive can be used implementation section } pd_interface = $8; { directive can be used interface section } pd_object = $10; { directive can be used object declaration } pd_procvar = $20; { directive can be used procvar declaration } pd_notobject = $40;{ directive can not be used object declaration } procedure compile_proc_body(const proc_names:Tstringcontainer; make_global,parent_has_class:boolean); procedure parse_proc_head(options:tproctypeoption); procedure parse_proc_dec; function is_proc_directive(tok:ttoken):boolean; procedure parse_var_proc_directives(var sym : psym); procedure parse_object_proc_directives(var sym : pprocsym); procedure read_proc; implementation uses globtype,systems, strings,globals,verbose,files, scanner,aasm,tree,types, import,gendef, {$ifdef newcg} cgbase, {$else newcg} hcodegen, {$endif newcg} temp_gen,pass_1,cpubase,cpuasm {$ifndef NOPASS2} ,pass_2 {$endif} {$ifdef GDB} ,gdb {$endif GDB} {$ifdef i386} {$ifndef newcg} ,tgeni386 ,cgai386 {$endif newcg} {$ifndef NoOpt} ,aopt386 {$endif} {$endif} {$ifdef m68k} ,tgen68k,cga68k {$endif} { parser specific stuff } ,pbase,pdecl,pexpr,pstatmnt {$ifdef newcg} ,tgcpu,convtree,cgobj,tgeni386 { for the new code generator tgeni386 is only a dummy } {$endif newcg} ; var realname:string; { contains the real name of a procedure as it's typed } procedure formal_parameter_list; { handle_procvar needs the same changes } var sc : Pstringcontainer; s : string; storetokenpos : tfileposinfo; p : Pdef; hsym : psym; hvs, vs : Pvarsym; hs1,hs2 : string; varspez : Tvarspez; inserthigh : boolean; begin consume(_LKLAMMER); inc(testcurobject); repeat if try_to_consume(_VAR) then varspez:=vs_var else if try_to_consume(_CONST) then varspez:=vs_const else varspez:=vs_value; inserthigh:=false; readtypesym:=nil; if idtoken=_SELF then begin { we parse the defintion in the class definition } if assigned(procinfo^._class) and procinfo^._class^.is_class then begin {$ifndef UseNiceNames} hs2:=hs2+'$'+'self'; {$else UseNiceNames} hs2:=hs2+tostr(length('self'))+'self'; {$endif UseNiceNames} vs:=new(Pvarsym,init('@',procinfo^._class)); vs^.varspez:=vs_var; { insert the sym in the parasymtable } aktprocsym^.definition^.parast^.insert(vs); {$ifdef INCLUDEOK} include(aktprocsym^.definition^.procoptions,po_containsself); {$else} aktprocsym^.definition^.procoptions:=aktprocsym^.definition^.procoptions+[po_containsself]; {$endif} {$ifdef newcg} inc(procinfo^.selfpointer_offset,vs^.address); {$else newcg} inc(procinfo^.ESI_offset,vs^.address); {$endif newcg} consume(idtoken); consume(_COLON); p:=single_type(hs1,false); if assigned(readtypesym) then aktprocsym^.definition^.concattypesym(readtypesym,vs_value) else aktprocsym^.definition^.concatdef(p,vs_value); CheckTypes(p,procinfo^._class); end else consume(_ID); end else begin { read identifiers } sc:=idlist; { read type declaration, force reading for value and const paras } if (token=_COLON) or (varspez=vs_value) then begin consume(_COLON); { check for an open array } if token=_ARRAY then begin consume(_ARRAY); consume(_OF); { define range and type of range } p:=new(Parraydef,init(0,-1,s32bitdef)); { array of const ? } if (token=_CONST) and (m_objpas in aktmodeswitches) then begin consume(_CONST); srsym:=nil; getsymonlyin(systemunit,'TVARREC'); if not assigned(srsym) then InternalError(1234124); Parraydef(p)^.definition:=ptypesym(srsym)^.definition; Parraydef(p)^.IsArrayOfConst:=true; hs1:='array_of_const'; end else begin { define field type } Parraydef(p)^.definition:=single_type(hs1,false); hs1:='array_of_'+hs1; { we don't need the typesym anymore } readtypesym:=nil; end; inserthigh:=true; end { open string ? } else if (varspez=vs_var) and ( ( ((token=_STRING) or (idtoken=_SHORTSTRING)) and (cs_openstring in aktmoduleswitches) and not(cs_ansistrings in aktlocalswitches) ) or (idtoken=_OPENSTRING)) then begin consume(token); p:=openshortstringdef; hs1:='openstring'; inserthigh:=true; end { everything else } else p:=single_type(hs1,false); end else begin {$ifndef UseNiceNames} hs1:='$$$'; {$else UseNiceNames} hs1:='var'; {$endif UseNiceNames} p:=cformaldef; { } end; hs2:=aktprocsym^.definition^.mangledname; storetokenpos:=tokenpos; while not sc^.empty do begin {$ifndef UseNiceNames} hs2:=hs2+'$'+hs1; {$else UseNiceNames} hs2:=hs2+tostr(length(hs1))+hs1; {$endif UseNiceNames} s:=sc^.get_with_tokeninfo(tokenpos); if assigned(readtypesym) then begin aktprocsym^.definition^.concattypesym(readtypesym,varspez); vs:=new(Pvarsym,initsym(s,readtypesym)) end else begin aktprocsym^.definition^.concatdef(p,varspez); vs:=new(Pvarsym,init(s,p)); end; vs^.varspez:=varspez; { we have to add this to avoid var param to be in registers !!!} if (varspez in [vs_var,vs_const]) and push_addr_param(p) then {$ifdef INCLUDEOK} include(vs^.varoptions,vo_regable); {$else} vs^.varoptions:=vs^.varoptions+[vo_regable]; {$endif} { search for duplicate ids in object members/methods } { but only the current class, I don't know why ... } { at least TP and Delphi do it in that way (FK) } if assigned(procinfo^._class) and (lexlevel=normal_function_level) then begin hsym:=procinfo^._class^.symtable^.search(vs^.name); if assigned(hsym) then DuplicateSym(hsym); end; { do we need a local copy } if (varspez=vs_value) and push_addr_param(p) and not(is_open_array(p) or is_array_of_const(p)) then vs^.setname('val'+vs^.name); { insert the sym in the parasymtable } aktprocsym^.definition^.parast^.insert(vs); { also need to push a high value? } if inserthigh then begin hvs:=new(Pvarsym,init('high'+s,s32bitdef)); hvs^.varspez:=vs_const; aktprocsym^.definition^.parast^.insert(hvs); end; end; dispose(sc,done); tokenpos:=storetokenpos; end; aktprocsym^.definition^.setmangledname(hs2); until not try_to_consume(_SEMICOLON); dec(testcurobject); consume(_RKLAMMER); end; procedure parse_proc_head(options:tproctypeoption); var sp:stringid; pd:Pprocdef; paramoffset:longint; sym:Psym; hs:string; st : psymtable; overloaded_level:word; procstartfilepos : tfileposinfo; begin { Save the position where this procedure really starts and set col to 1 which looks nicer } procstartfilepos:=aktfilepos; procstartfilepos.column:=1; if (options=potype_operator) then begin sp:=overloaded_names[optoken]; realname:=sp; end else begin sp:=pattern; realname:=orgpattern; consume(_ID); end; { method ? } if not(parse_only) and try_to_consume(_POINT) then begin getsym(sp,true); sym:=srsym; { load proc name } sp:=pattern; realname:=orgpattern; { qualifier is class name ? } if (sym^.typ<>typesym) or (ptypesym(sym)^.definition^.deftype<>objectdef) then begin Message(parser_e_class_id_expected); aktprocsym:=nil; consume(_ID); end else begin { used to allow private syms to be seen } aktobjectdef:=pobjectdef(ptypesym(sym)^.definition); consume(_ID); procinfo^._class:=pobjectdef(ptypesym(sym)^.definition); aktprocsym:=pprocsym(procinfo^._class^.symtable^.search(sp)); {The procedure has been found. So it is a global one. Set the flags to mark this.} procinfo^.flags:=procinfo^.flags or pi_is_global; aktobjectdef:=nil; { we solve this below } if not(assigned(aktprocsym)) then Message(parser_e_methode_id_expected); end; end else begin { check for constructor/destructor which is not allowed here } if (not parse_only) and (options in [potype_constructor,potype_destructor]) then Message(parser_e_constructors_always_objects); aktprocsym:=pprocsym(symtablestack^.search(sp)); if not(parse_only) then begin {The procedure we prepare for is in the implementation part of the unit we compile. It is also possible that we are compiling a program, which is also some kind of implementaion part. We need to find out if the procedure is global. If it is global, it is in the global symtable.} if not assigned(aktprocsym) and (symtablestack^.symtabletype=staticsymtable) then begin {Search the procedure in the global symtable.} aktprocsym:=Pprocsym(search_a_symtable(sp,globalsymtable)); if assigned(aktprocsym) then begin {Check if it is a procedure.} if aktprocsym^.typ<>procsym then DuplicateSym(aktprocsym); {The procedure has been found. So it is a global one. Set the flags to mark this.} procinfo^.flags:=procinfo^.flags or pi_is_global; end; end; end; end; { Create the mangledname } {$ifndef UseNiceNames} if assigned(procinfo^._class) then begin if (pos('_$$_',procprefix)=0) then hs:=procprefix+'_$$_'+procinfo^._class^.objname^+'_$$_'+sp else hs:=procprefix+'_$'+sp; end else begin if lexlevel=normal_function_level then hs:=procprefix+'_'+sp else hs:=procprefix+'_$'+sp; end; {$else UseNiceNames} if assigned(procinfo^._class) then begin if (pos('_5Class_',procprefix)=0) then hs:=procprefix+'_5Class_'+procinfo^._class^.name^+'_'+tostr(length(sp))+sp else hs:=procprefix+'_'+tostr(length(sp))+sp; end else begin if lexlevel=normal_function_level then hs:=procprefix+'_'+tostr(length(sp))+sp else hs:=lowercase(procprefix)+'_'+tostr(length(sp))+sp; end; {$endif UseNiceNames} if assigned(aktprocsym) then begin { Check if overloading is enabled } if not(m_fpc in aktmodeswitches) then begin if aktprocsym^.typ<>procsym then begin DuplicateSym(aktprocsym); { try to recover by creating a new aktprocsym } aktprocsym:=new(pprocsym,init(sp)); end else begin if not(aktprocsym^.definition^.forwarddef) then Message(parser_e_procedure_overloading_is_off); end; end else begin { Check if the overloaded sym is realy a procsym } if aktprocsym^.typ<>procsym then begin Message1(parser_e_overloaded_no_procedure,aktprocsym^.name); { try to recover by creating a new aktprocsym } aktprocsym:=new(pprocsym,init(sp)); end; end; end else begin { create a new procsym and set the real filepos } aktprocsym:=new(pprocsym,init(sp)); { for operator we have only one definition for each overloaded operation } if (options=potype_operator) then begin { the only problem is that nextoverloaded might not be in a unit known for the unit itself } if assigned(overloaded_operators[optoken]) then aktprocsym^.definition:=overloaded_operators[optoken]^.definition; end; symtablestack^.insert(aktprocsym); end; st:=symtablestack; pd:=new(pprocdef,init); pd^.symtablelevel:=symtablestack^.symtablelevel; if assigned(procinfo^._class) then pd^._class := procinfo^._class; { set the options from the caller (podestructor or poconstructor) } pd^.proctypeoption:=options; { calculate the offset of the parameters } paramoffset:=8; { calculate frame pointer offset } if lexlevel>normal_function_level then begin procinfo^.framepointer_offset:=paramoffset; inc(paramoffset,target_os.size_of_pointer); { this is needed to get correct framepointer push for local forward functions !! } pd^.parast^.symtablelevel:=lexlevel; end; if assigned (procinfo^._Class) and not(procinfo^._Class^.is_class) and (pd^.proctypeoption in [potype_constructor,potype_destructor]) then inc(paramoffset,target_os.size_of_pointer); { self pointer offset } { self isn't pushed in nested procedure of methods } if assigned(procinfo^._class) and (lexlevel=normal_function_level) then begin {$ifdef newcg} procinfo^.selfpointer_offset:=paramoffset; {$else newcg} procinfo^.ESI_offset:=paramoffset; {$endif newcg} if assigned(aktprocsym^.definition) and not(po_containsself in aktprocsym^.definition^.procoptions) then inc(paramoffset,target_os.size_of_pointer); end; { destructor flag ? } if assigned (procinfo^._Class) and procinfo^._class^.is_class and (pd^.proctypeoption=potype_destructor) then inc(paramoffset,target_os.size_of_pointer); procinfo^.call_offset:=paramoffset; pd^.parast^.datasize:=0; pd^.nextoverloaded:=aktprocsym^.definition; aktprocsym^.definition:=pd; aktprocsym^.definition^.fileinfo:=procstartfilepos; aktprocsym^.definition^.setmangledname(hs); aktprocsym^.definition^.procsym:=aktprocsym; { update also the current filepos for aktprocsym } aktprocsym^.fileinfo:=procstartfilepos; if not parse_only then begin overloaded_level:=0; { we need another procprefix !!! } { count, but only those in the same unit !!} while assigned(pd) and (pd^.owner^.symtabletype in [globalsymtable,staticsymtable]) do begin { only count already implemented functions } if not(pd^.forwarddef) then inc(overloaded_level); pd:=pd^.nextoverloaded; end; if overloaded_level>0 then procprefix:=hs+'$'+tostr(overloaded_level)+'$' else procprefix:=hs+'$'; end; { this must also be inserted in the right symtable !! PM } { otherwise we get subbtle problems with definitions of args defs in staticsymtable for implementation of a global method } if token=_LKLAMMER then formal_parameter_list; { so we only restore the symtable now } symtablestack:=st; if (options=potype_operator) then overloaded_operators[optoken]:=aktprocsym; end; procedure parse_proc_dec; var hs : string; isclassmethod : boolean; begin inc(lexlevel); { read class method } if token=_CLASS then begin consume(_CLASS); isclassmethod:=true; end else isclassmethod:=false; case token of _FUNCTION : begin consume(_FUNCTION); parse_proc_head(potype_none); if token<>_COLON then begin if not(aktprocsym^.definition^.forwarddef) or (m_repeat_forward in aktmodeswitches) then begin consume(_COLON); consume_all_until(_SEMICOLON); end; end else begin consume(_COLON); inc(testcurobject); aktprocsym^.definition^.retdef:=single_type(hs,false); aktprocsym^.definition^.test_if_fpu_result; dec(testcurobject); end; end; _PROCEDURE : begin consume(_PROCEDURE); parse_proc_head(potype_none); aktprocsym^.definition^.retdef:=voiddef; end; _CONSTRUCTOR : begin consume(_CONSTRUCTOR); parse_proc_head(potype_constructor); if assigned(procinfo^._class) and procinfo^._class^.is_class then begin { CLASS constructors return the created instance } aktprocsym^.definition^.retdef:=procinfo^._class; end else begin { OBJECT constructors return a boolean } {$IfDef GDB} { GDB doesn't like unnamed types !} aktprocsym^.definition^.retdef:=globaldef('boolean'); {$else GDB} aktprocsym^.definition^.retdef:=new(porddef,init(bool8bit,0,1)); {$Endif GDB} end; end; _DESTRUCTOR : begin consume(_DESTRUCTOR); parse_proc_head(potype_destructor); aktprocsym^.definition^.retdef:=voiddef; end; _OPERATOR : begin if lexlevel>normal_function_level then Message(parser_e_no_local_operator); consume(_OPERATOR); if not(token in [_PLUS..last_overloaded]) then Message(parser_e_overload_operator_failed); optoken:=token; consume(Token); procinfo^.flags:=procinfo^.flags or pi_operator; parse_proc_head(potype_operator); if token<>_ID then begin opsym:=nil; if not(m_result in aktmodeswitches) then consume(_ID); end else begin opsym:=new(pvarsym,init(pattern,voiddef)); consume(_ID); end; if not try_to_consume(_COLON) then begin consume(_COLON); aktprocsym^.definition^.retdef:=generrordef; consume_all_until(_SEMICOLON); end else begin aktprocsym^.definition^.retdef:= single_type(hs,false); aktprocsym^.definition^.test_if_fpu_result; if (optoken in [_EQUAL,_GT,_LT,_GTE,_LTE]) and ((aktprocsym^.definition^.retdef^.deftype<> orddef) or (porddef(aktprocsym^.definition^. retdef)^.typ<>bool8bit)) then Message(parser_e_comparative_operator_return_boolean); if assigned(opsym) then opsym^.definition:=aktprocsym^.definition^.retdef; { We need to add the retrun type in the mangledname to allow overloading with just different results !! (PM) } aktprocsym^.definition^.setmangledname( aktprocsym^.definition^.mangledname+'$$'+hs); end; end; end; if isclassmethod and assigned(aktprocsym) then {$ifdef INCLUDEOK} include(aktprocsym^.definition^.procoptions,po_classmethod); {$else} aktprocsym^.definition^.procoptions:=aktprocsym^.definition^.procoptions+[po_classmethod]; {$endif} consume(_SEMICOLON); dec(lexlevel); end; {**************************************************************************** Procedure directive handlers ****************************************************************************} {$ifdef tp} {$F+} {$endif} procedure pd_far(const procnames:Tstringcontainer); begin Message(parser_w_proc_far_ignored); end; procedure pd_near(const procnames:Tstringcontainer); begin Message(parser_w_proc_near_ignored); end; procedure pd_export(const procnames:Tstringcontainer); begin if assigned(procinfo^._class) then Message(parser_e_methods_dont_be_export); if lexlevel<>normal_function_level then Message(parser_e_dont_nest_export); { only os/2 needs this } if target_info.target=target_i386_os2 then begin procnames.insert(realname); procinfo^.exported:=true; if cs_link_deffile in aktglobalswitches then deffile.AddExport(aktprocsym^.definition^.mangledname); end; end; procedure pd_inline(const procnames:Tstringcontainer); begin if not(cs_support_inline in aktmoduleswitches) then Message(parser_e_proc_inline_not_supported); end; procedure pd_forward(const procnames:Tstringcontainer); begin aktprocsym^.definition^.forwarddef:=true; end; procedure pd_stdcall(const procnames:Tstringcontainer); begin end; procedure pd_safecall(const procnames:Tstringcontainer); begin end; procedure pd_alias(const procnames:Tstringcontainer); begin consume(_COLON); procnames.insert(get_stringconst); end; procedure pd_asmname(const procnames:Tstringcontainer); begin aktprocsym^.definition^.setmangledname(target_os.Cprefix+pattern); if token=_CCHAR then consume(_CCHAR) else consume(_CSTRING); { we don't need anything else } aktprocsym^.definition^.forwarddef:=false; end; procedure pd_intern(const procnames:Tstringcontainer); begin consume(_COLON); aktprocsym^.definition^.extnumber:=get_intconst; end; procedure pd_system(const procnames:Tstringcontainer); begin aktprocsym^.definition^.setmangledname(realname); end; procedure pd_abstract(const procnames:Tstringcontainer); begin if (po_virtualmethod in aktprocsym^.definition^.procoptions) then {$ifdef INCLUDEOK} include(aktprocsym^.definition^.procoptions,po_abstractmethod) {$else} aktprocsym^.definition^.procoptions:=aktprocsym^.definition^.procoptions+[po_abstractmethod] {$endif} else Message(parser_e_only_virtual_methods_abstract); { the method is defined } aktprocsym^.definition^.forwarddef:=false; end; procedure pd_virtual(const procnames:Tstringcontainer); begin if (aktprocsym^.definition^.proctypeoption=potype_constructor) and not(aktprocsym^.definition^._class^.is_class) then Message(parser_e_constructor_cannot_be_not_virtual); end; procedure pd_static(const procnames:Tstringcontainer); begin if (cs_static_keyword in aktmoduleswitches) then begin {$ifdef INCLUDEOK} include(aktprocsym^.symoptions,sp_static); include(aktprocsym^.definition^.procoptions,po_staticmethod); {$else} aktprocsym^.symoptions:=aktprocsym^.symoptions+[sp_static]; aktprocsym^.definition^.procoptions:=aktprocsym^.definition^.procoptions+[po_staticmethod]; {$endif} end; end; procedure pd_override(const procnames:Tstringcontainer); begin if not(aktprocsym^.definition^._class^.is_class) then Message(parser_e_no_object_override); end; procedure pd_message(const procnames:Tstringcontainer); var pt : ptree; begin { check parameter type } if not(po_containsself in aktprocsym^.definition^.procoptions) and (assigned(aktprocsym^.definition^.para1^.next) or (aktprocsym^.definition^.para1^.paratyp<>vs_var)) then Message(parser_e_ill_msg_param); pt:=comp_expr(true); do_firstpass(pt); if pt^.treetype=stringconstn then begin {$ifdef INCLUDEOK} include(aktprocsym^.definition^.procoptions,po_msgstr); {$else} aktprocsym^.definition^.procoptions:=aktprocsym^.definition^.procoptions+[po_msgstr]; {$endif} aktprocsym^.definition^.messageinf.str:=strnew(pt^.value_str); end else if is_constintnode(pt) then begin {$ifdef INCLUDEOK} include(aktprocsym^.definition^.procoptions,po_msgint); {$else} aktprocsym^.definition^.procoptions:=aktprocsym^.definition^.procoptions+[po_msgint]; {$endif} aktprocsym^.definition^.messageinf.i:=pt^.value; end else Message(parser_e_ill_msg_expr); disposetree(pt); end; procedure pd_cdecl(const procnames:Tstringcontainer); begin if aktprocsym^.definition^.deftype<>procvardef then aktprocsym^.definition^.setmangledname(target_os.Cprefix+realname); end; procedure pd_register(const procnames:Tstringcontainer); begin Message(parser_w_proc_register_ignored); end; procedure pd_syscall(const procnames:Tstringcontainer); begin aktprocsym^.definition^.forwarddef:=false; aktprocsym^.definition^.extnumber:=get_intconst; end; procedure pd_external(const procnames:Tstringcontainer); { If import_dll=nil the procedure is assumed to be in another object file. In that object file it should have the name to which import_name is pointing to. Otherwise, the procedure is assumed to be in the DLL to which import_dll is pointing to. In that case either import_nr<>0 or import_name<>nil is true, so the procedure is either imported by number or by name. (DM) } var import_dll, import_name : string; import_nr : word; begin aktprocsym^.definition^.forwarddef:=false; { If the procedure should be imported from a DLL, a constant string follows. This isn't really correct, an contant string expression follows so we check if an semicolon follows, else a string constant have to follow (FK) } import_nr:=0; import_name:=''; if not(token=_SEMICOLON) and not(idtoken=_NAME) then begin import_dll:=get_stringconst; if (idtoken=_NAME) then begin consume(_NAME); import_name:=get_stringconst; end; if (idtoken=_INDEX) then begin {After the word index follows the index number in the DLL.} consume(_INDEX); import_nr:=get_intconst; end; if (import_nr=0) and (import_name='') then {if (aktprocsym^.definition^.options and pocdecl)<>0 then import_name:=aktprocsym^.definition^.mangledname else Message(parser_w_empty_import_name);} { this should work both for win32 and Linux !! PM } import_name:=realname; if not(current_module^.uses_imports) then begin current_module^.uses_imports:=true; importlib^.preparelib(current_module^.modulename^); end; if not(m_repeat_forward in aktmodeswitches) then begin { we can only have one overloaded here ! } if assigned(aktprocsym^.definition^.nextoverloaded) then importlib^.importprocedure(aktprocsym^.definition^.nextoverloaded^.mangledname, import_dll,import_nr,import_name) else importlib^.importprocedure(aktprocsym^.mangledname,import_dll,import_nr,import_name); end else importlib^.importprocedure(aktprocsym^.mangledname,import_dll,import_nr,import_name); end else begin if (idtoken=_NAME) then begin consume(_NAME); import_name:=get_stringconst; aktprocsym^.definition^.setmangledname(import_name); end else begin { external shouldn't override the cdecl/system name } if not (pocall_clearstack in aktprocsym^.definition^.proccalloptions) then aktprocsym^.definition^.setmangledname(aktprocsym^.name); end; end; end; {$ifdef TP} {$F-} {$endif} const namelength=15; type pd_handler=procedure(const procnames:Tstringcontainer); proc_dir_rec=record idtok : ttoken; pd_flags : longint; handler : pd_handler; pocall : tproccalloptions; pooption : tprocoptions; mutexclpocall : tproccalloptions; mutexclpotype : tproctypeoptions; mutexclpo : tprocoptions; end; const {Should contain the number of procedure directives we support.} num_proc_directives=29; proc_direcdata:array[1..num_proc_directives] of proc_dir_rec= ( ( idtok:_ABSTRACT; pd_flags : pd_interface+pd_object; handler : {$ifndef TP}@{$endif}pd_abstract; pocall : []; pooption : [po_abstractmethod]; mutexclpocall : [pocall_internproc,pocall_inline]; mutexclpotype : [potype_constructor,potype_destructor]; mutexclpo : [po_exports,po_interrupt,po_external] ),( idtok:_ALIAS; pd_flags : pd_implemen+pd_body; handler : {$ifndef TP}@{$endif}pd_alias; pocall : []; pooption : []; mutexclpocall : [pocall_inline]; mutexclpotype : []; mutexclpo : [po_external] ),( idtok:_ASMNAME; pd_flags : pd_interface+pd_implemen; handler : {$ifndef TP}@{$endif}pd_asmname; pocall : [pocall_cdecl,pocall_clearstack]; pooption : [po_external]; mutexclpocall : [pocall_internproc]; mutexclpotype : []; mutexclpo : [po_external] ),( idtok:_ASSEMBLER; pd_flags : pd_implemen+pd_body; handler : nil; pocall : []; pooption : [po_assembler]; mutexclpocall : []; mutexclpotype : []; mutexclpo : [po_external] ),( idtok:_CDECL; pd_flags : pd_interface+pd_implemen+pd_body+pd_procvar; handler : {$ifndef TP}@{$endif}pd_cdecl; pocall : [pocall_cdecl,pocall_clearstack]; pooption : [po_savestdregs]; mutexclpocall : [pocall_internproc,pocall_leftright,pocall_inline]; mutexclpotype : []; mutexclpo : [po_assembler,po_external] ),( idtok:_DYNAMIC; pd_flags : pd_interface+pd_object; handler : {$ifndef TP}@{$endif}pd_virtual; pocall : []; pooption : [po_virtualmethod]; mutexclpocall : [pocall_internproc,pocall_inline]; mutexclpotype : []; mutexclpo : [po_exports,po_interrupt,po_external] ),( idtok:_EXPORT; pd_flags : pd_body+pd_global+pd_interface+pd_implemen{??}; handler : {$ifndef TP}@{$endif}pd_export; pocall : []; pooption : [po_exports]; mutexclpocall : [pocall_internproc,pocall_inline]; mutexclpotype : []; mutexclpo : [po_external,po_interrupt] ),( idtok:_EXTERNAL; pd_flags : pd_implemen+pd_interface; handler : {$ifndef TP}@{$endif}pd_external; pocall : []; pooption : [po_external]; mutexclpocall : [pocall_internproc,pocall_inline,pocall_palmossyscall]; mutexclpotype : []; mutexclpo : [po_exports,po_interrupt,po_assembler] ),( idtok:_FAR; pd_flags : pd_implemen+pd_body+pd_interface+pd_procvar; handler : {$ifndef TP}@{$endif}pd_far; pocall : []; pooption : []; mutexclpocall : [pocall_internproc,pocall_inline]; mutexclpotype : []; mutexclpo : [] ),( idtok:_FORWARD; pd_flags : pd_implemen; handler : {$ifndef TP}@{$endif}pd_forward; pocall : []; pooption : []; mutexclpocall : [pocall_internproc,pocall_inline]; mutexclpotype : []; mutexclpo : [po_external] ),( idtok:_INLINE; pd_flags : pd_implemen+pd_body; handler : {$ifndef TP}@{$endif}pd_inline; pocall : [pocall_inline]; pooption : []; mutexclpocall : [pocall_internproc]; mutexclpotype : [potype_constructor,potype_destructor]; mutexclpo : [po_exports,po_external,po_interrupt] ),( idtok:_INTERNCONST; pd_flags : pd_implemen+pd_body; handler : {$ifndef TP}@{$endif}pd_intern; pocall : [pocall_internconst]; pooption : []; mutexclpocall : []; mutexclpotype : [potype_operator]; mutexclpo : [] ),( idtok:_INTERNPROC; pd_flags : pd_implemen; handler : {$ifndef TP}@{$endif}pd_intern; pocall : [pocall_internproc]; pooption : []; mutexclpocall : [pocall_inline,pocall_clearstack,pocall_leftright,pocall_cdecl]; mutexclpotype : [potype_constructor,potype_destructor,potype_operator]; mutexclpo : [po_exports,po_external,po_interrupt,po_assembler,po_iocheck] ),( idtok:_INTERRUPT; pd_flags : pd_implemen+pd_body; handler : nil; pocall : []; pooption : [po_interrupt]; mutexclpocall : [pocall_internproc,pocall_cdecl,pocall_clearstack,pocall_leftright,pocall_inline]; mutexclpotype : [potype_constructor,potype_destructor,potype_operator]; mutexclpo : [po_external] ),( idtok:_IOCHECK; pd_flags : pd_implemen+pd_body; handler : nil; pocall : []; pooption : [po_iocheck]; mutexclpocall : [pocall_internproc]; mutexclpotype : []; mutexclpo : [po_external] ),( idtok:_MESSAGE; pd_flags : pd_interface+pd_object; handler : {$ifndef TP}@{$endif}pd_message; pocall : []; pooption : []; { can be po_msgstr or po_msgint } mutexclpocall : [pocall_inline,pocall_internproc]; mutexclpotype : [potype_constructor,potype_destructor,potype_operator]; mutexclpo : [po_interrupt,po_external] ),( idtok:_NEAR; pd_flags : pd_implemen+pd_body+pd_procvar; handler : {$ifndef TP}@{$endif}pd_near; pocall : []; pooption : []; mutexclpocall : [pocall_internproc]; mutexclpotype : []; mutexclpo : [] ),( idtok:_OVERRIDE; pd_flags : pd_interface+pd_object; handler : {$ifndef TP}@{$endif}pd_override; pocall : []; pooption : [po_overridingmethod,po_virtualmethod]; mutexclpocall : [pocall_inline,pocall_internproc]; mutexclpotype : []; mutexclpo : [po_exports,po_external,po_interrupt] ),( idtok:_PASCAL; pd_flags : pd_implemen+pd_body+pd_procvar; handler : nil; pocall : [pocall_leftright]; pooption : []; mutexclpocall : [pocall_internproc]; mutexclpotype : []; mutexclpo : [po_external] ),( idtok:_POPSTACK; pd_flags : pd_interface+pd_implemen+pd_body+pd_procvar; handler : nil; pocall : [pocall_clearstack]; pooption : []; mutexclpocall : [pocall_inline,pocall_internproc]; mutexclpotype : []; mutexclpo : [po_assembler,po_external] ),( idtok:_PUBLIC; pd_flags : pd_implemen+pd_body+pd_global+pd_notobject; handler : nil; pocall : []; pooption : []; mutexclpocall : [pocall_internproc,pocall_inline]; mutexclpotype : []; mutexclpo : [po_external] ),( idtok:_REGISTER; pd_flags : pd_interface+pd_implemen+pd_body+pd_procvar; handler : {$ifndef TP}@{$endif}pd_register; pocall : [pocall_register]; pooption : []; mutexclpocall : [pocall_leftright,pocall_cdecl,pocall_internproc]; mutexclpotype : []; mutexclpo : [po_external] ),( idtok:_SAFECALL; pd_flags : pd_interface+pd_implemen+pd_body+pd_procvar; handler : {$ifndef TP}@{$endif}pd_safecall; pocall : [pocall_safecall]; pooption : [po_savestdregs]; mutexclpocall : [pocall_leftright,pocall_cdecl,pocall_internproc,pocall_inline]; mutexclpotype : []; mutexclpo : [po_external] ),( idtok:_SAVEREGISTERS; pd_flags : pd_interface+pd_implemen+pd_body+pd_procvar; handler : nil; pocall : []; pooption : [po_saveregisters]; mutexclpocall : [pocall_internproc]; mutexclpotype : []; mutexclpo : [po_external] ),( idtok:_STATIC; pd_flags : pd_interface+pd_object; handler : {$ifndef TP}@{$endif}pd_static; pocall : []; pooption : [po_staticmethod]; mutexclpocall : [pocall_inline,pocall_internproc]; mutexclpotype : [potype_constructor,potype_destructor]; mutexclpo : [po_external,po_interrupt,po_exports] ),( idtok:_STDCALL; pd_flags : pd_interface+pd_implemen+pd_body+pd_procvar; handler : {$ifndef TP}@{$endif}pd_stdcall; pocall : [pocall_stdcall]; pooption : [po_savestdregs]; mutexclpocall : [pocall_leftright,pocall_cdecl,pocall_inline,pocall_internproc]; mutexclpotype : []; mutexclpo : [po_external] ),( idtok:_SYSCALL; pd_flags : pd_interface; handler : {$ifndef TP}@{$endif}pd_syscall; pocall : [pocall_palmossyscall]; pooption : []; mutexclpocall : [pocall_cdecl,pocall_inline,pocall_internproc]; mutexclpotype : []; mutexclpo : [po_external,po_assembler,po_interrupt,po_exports] ),( idtok:_SYSTEM; pd_flags : pd_implemen; handler : {$ifndef TP}@{$endif}pd_system; pocall : [pocall_clearstack]; pooption : []; mutexclpocall : [pocall_leftright,pocall_inline,pocall_internproc]; mutexclpotype : []; mutexclpo : [po_external,po_assembler,po_interrupt] ),( idtok:_VIRTUAL; pd_flags : pd_interface+pd_object; handler : {$ifndef TP}@{$endif}pd_virtual; pocall : []; pooption : [po_virtualmethod]; mutexclpocall : [pocall_inline,pocall_internproc]; mutexclpotype : []; mutexclpo : [po_external,po_interrupt,po_exports] ) ); function is_proc_directive(tok:ttoken):boolean; var i : longint; begin is_proc_directive:=false; for i:=1 to num_proc_directives do if proc_direcdata[i].idtok=idtoken then begin is_proc_directive:=true; exit; end; end; function parse_proc_direc(const proc_names:Tstringcontainer;var pdflags:word):boolean; { Parse the procedure directive, returns true if a correct directive is found } var p : longint; found : boolean; name : string; begin parse_proc_direc:=false; name:=pattern; found:=false; for p:=1 to num_proc_directives do if proc_direcdata[p].idtok=idtoken then begin found:=true; break; end; { Check if the procedure directive is known } if not found then begin { parsing a procvar type the name can be any next variable !! } if (pdflags and (pd_procvar or pd_object))=0 then Message1(parser_w_unknown_proc_directive_ignored,name); exit; end; { static needs a special treatment } if (idtoken=_STATIC) and not (cs_static_keyword in aktmoduleswitches) then exit; { Conflicts between directives ? } if (aktprocsym^.definition^.proctypeoption in proc_direcdata[p].mutexclpotype) or ((aktprocsym^.definition^.proccalloptions*proc_direcdata[p].mutexclpocall)<>[]) or ((aktprocsym^.definition^.procoptions*proc_direcdata[p].mutexclpo)<>[]) then begin Message1(parser_e_proc_dir_conflict,name); exit; end; { Check if the directive is only for objects } if ((proc_direcdata[p].pd_flags and pd_object)<>0) and not assigned(aktprocsym^.definition^._class) then begin exit; end; { check if method and directive not for object public } if ((proc_direcdata[p].pd_flags and pd_notobject)<>0) and assigned(aktprocsym^.definition^._class) then begin exit; end; { consume directive, and turn flag on } consume(token); parse_proc_direc:=true; { Check the pd_flags if the directive should be allowed } if ((pdflags and pd_interface)<>0) and ((proc_direcdata[p].pd_flags and pd_interface)=0) then begin Message1(parser_e_proc_dir_not_allowed_in_interface,name); exit; end; if ((pdflags and pd_implemen)<>0) and ((proc_direcdata[p].pd_flags and pd_implemen)=0) then begin Message1(parser_e_proc_dir_not_allowed_in_implementation,name); exit; end; if ((pdflags and pd_procvar)<>0) and ((proc_direcdata[p].pd_flags and pd_procvar)=0) then begin Message1(parser_e_proc_dir_not_allowed_in_procvar,name); exit; end; { Return the new pd_flags } if (proc_direcdata[p].pd_flags and pd_body)=0 then pdflags:=pdflags and (not pd_body); if (proc_direcdata[p].pd_flags and pd_global)<>0 then pdflags:=pdflags or pd_global; { Add the correct flag } aktprocsym^.definition^.proccalloptions:=aktprocsym^.definition^.proccalloptions+proc_direcdata[p].pocall; aktprocsym^.definition^.procoptions:=aktprocsym^.definition^.procoptions+proc_direcdata[p].pooption; { Adjust positions of args for cdecl or stdcall } if (aktprocsym^.definition^.deftype=procdef) and (([pocall_cdecl,pocall_stdcall]*aktprocsym^.definition^.proccalloptions)<>[]) then aktprocsym^.definition^.parast^.set_alignment(target_os.size_of_longint); { Call the handler } if pointer({$ifndef FPC}@{$endif}proc_direcdata[p].handler)<>nil then proc_direcdata[p].handler(proc_names); end; {***************************************************************************} function check_identical(var p : pprocdef) : boolean; { Search for idendical definitions, if there is a forward, then kill this. Returns the result of the forward check. Removed from unter_dec to keep the source readable } var hd,pd : Pprocdef; storeparast : psymtable; ad,fd : psym; s : string; begin check_identical:=false; p:=nil; pd:=aktprocsym^.definition; if assigned(pd) then begin { Is there an overload/forward ? } if assigned(pd^.nextoverloaded) then begin { walk the procdef list } while (assigned(pd)) and (assigned(pd^.nextoverloaded)) do begin if not(m_repeat_forward in aktmodeswitches) or (equal_paras(aktprocsym^.definition^.para1,pd^.nextoverloaded^.para1,false) and { for operators equal_paras is not enough !! } ((aktprocsym^.definition^.proctypeoption<>potype_operator) or (optoken<>_ASSIGNMENT) or is_equal(pd^.nextoverloaded^.retdef,aktprocsym^.definition^.retdef))) then begin if pd^.nextoverloaded^.forwarddef then { remove the forward definition but don't delete it, } { the symtable is the owner !! } begin hd:=pd^.nextoverloaded; { Check if the procedure type and return type are correct } if (hd^.proctypeoption<>aktprocsym^.definition^.proctypeoption) or (not(is_equal(hd^.retdef,aktprocsym^.definition^.retdef)) and (m_repeat_forward in aktmodeswitches)) then begin Message1(parser_e_header_dont_match_forward,aktprocsym^.demangledName); exit; end; { Check calling convention, no check for internconst,internproc which are only defined in interface or implementation } if (hd^.proccalloptions-[pocall_internconst,pocall_internproc]<> aktprocsym^.definition^.proccalloptions-[pocall_internconst,pocall_internproc]) then begin { only trigger an error, becuase it doesn't hurt } Message(parser_e_call_convention_dont_match_forward); end; { manglednames are equal? } hd^.count:=false; if (m_repeat_forward in aktmodeswitches) or aktprocsym^.definition^.haspara then begin if (hd^.mangledname<>aktprocsym^.definition^.mangledname) then begin { When overloading is not possible then we issue an error } { This is not true, tp7/delphi don't give an error when a renamed type is used in the other declaration (PFV) if not(m_repeat_forward in aktmodeswitches) then begin Message1(parser_e_header_dont_match_forward,aktprocsym^.demangledName); exit; end; } if not(po_external in aktprocsym^.definition^.procoptions) then Message2(parser_n_interface_name_diff_implementation_name,hd^.mangledname, aktprocsym^.definition^.mangledname); { reset the mangledname of the interface part to be sure } { this is wrong because the mangled name might have been used already !! } if hd^.is_used then renameasmsymbol(hd^.mangledname,aktprocsym^.definition^.mangledname); hd^.setmangledname(aktprocsym^.definition^.mangledname); { so we need to keep the name of interface !! No!!!! The procedure directives can change the mangledname. I fixed this by first calling check_identical and then doing the proc directives, but this is not a good solution.(DM)} { this is also wrong (PM) aktprocsym^.definition^.setmangledname(hd^.mangledname);} end else begin { If mangled names are equal, therefore } { they have the same number of parameters } { Therefore we can check the name of these } { parameters... } if hd^.forwarddef and aktprocsym^.definition^.forwarddef then begin Message1(parser_e_function_already_declared_public_forward,aktprocsym^.demangledName); Check_identical:=true; { Remove other forward from the list to reduce errors } pd^.nextoverloaded:=pd^.nextoverloaded^.nextoverloaded; exit; end; ad:=psym(hd^.parast^.symindex^.first); fd:=psym(aktprocsym^.definition^.parast^.symindex^.first); if assigned(ad) and assigned(fd) then begin while assigned(ad) and assigned(fd) do begin s:=ad^.name; if s<>fd^.name then begin Message3(parser_e_header_different_var_names, aktprocsym^.name,s,fd^.name); break; end; { it is impossible to have a nil pointer } { for only one parameter - since they } { have the same number of parameters. } { Left = next parameter. } ad:=psym(ad^.left); fd:=psym(fd^.left); end; end; end; end; { also the call_offset } hd^.parast^.address_fixup:=aktprocsym^.definition^.parast^.address_fixup; hd^.count:=true; { remove pd^.nextoverloaded from the list } { and add aktprocsym^.definition } pd^.nextoverloaded:=pd^.nextoverloaded^.nextoverloaded; hd^.nextoverloaded:=aktprocsym^.definition^.nextoverloaded; { Alert! All fields of aktprocsym^.definition that are modified by the procdir handlers must be copied here!.} hd^.forwarddef:=false; hd^.proccalloptions:=hd^.proccalloptions + aktprocsym^.definition^.proccalloptions; hd^.procoptions:=hd^.procoptions + aktprocsym^.definition^.procoptions; if aktprocsym^.definition^.extnumber=-1 then aktprocsym^.definition^.extnumber:=hd^.extnumber else if hd^.extnumber=-1 then hd^.extnumber:=aktprocsym^.definition^.extnumber; { switch parast for warning in implementation PM } if (m_repeat_forward in aktmodeswitches) or aktprocsym^.definition^.haspara then begin storeparast:=hd^.parast; hd^.parast:=aktprocsym^.definition^.parast; aktprocsym^.definition^.parast:=storeparast; end; if pd=aktprocsym^.definition then p:=nil else p:=pd; aktprocsym^.definition:=hd; check_identical:=true; end else { abstract methods aren't forward defined, but this } { needs another error message } if not(po_abstractmethod in pd^.nextoverloaded^.procoptions) then Message(parser_e_overloaded_have_same_parameters) else Message(parser_e_abstract_no_definition); break; end; pd:=pd^.nextoverloaded; end; end else begin { there is no overloaded, so its always identical with itself } check_identical:=true; end; end; { insert opsym only in the right symtable } if ((procinfo^.flags and pi_operator)<>0) and assigned(opsym) and not parse_only then begin if ret_in_param(aktprocsym^.definition^.retdef) then begin pprocdef(aktprocsym^.definition)^.parast^.insert(opsym); { this increases the data size } { correct this to get the right ret $value } dec(pprocdef(aktprocsym^.definition)^.parast^.datasize,opsym^.getpushsize); { this allows to read the funcretoffset } opsym^.address:=-4; opsym^.varspez:=vs_var; end else pprocdef(aktprocsym^.definition)^.localst^.insert(opsym); end; end; procedure compile_proc_body(const proc_names:Tstringcontainer; make_global,parent_has_class:boolean); { Compile the body of a procedure } var oldexitlabel,oldexit2label : pasmlabel; oldfaillabel,oldquickexitlabel:Pasmlabel; _class,hp:Pobjectdef; { switches can change inside the procedure } entryswitches, exitswitches : tlocalswitches; { code for the subroutine as tree } {$ifdef newcg} code:pnode; {$else newcg} code:ptree; {$endif newcg} { size of the local strackframe } stackframe:longint; { true when no stackframe is required } nostackframe:boolean; { number of bytes which have to be cleared by RET } parasize:longint; { filepositions } entrypos, savepos, exitpos : tfileposinfo; begin { calculate the lexical level } inc(lexlevel); if lexlevel>32 then Message(parser_e_too_much_lexlevel); { static is also important for local procedures !! } if (po_staticmethod in aktprocsym^.definition^.procoptions) then allow_only_static:=true else if (lexlevel=normal_function_level) then allow_only_static:=false; { save old labels } oldexitlabel:=aktexitlabel; oldexit2label:=aktexit2label; oldquickexitlabel:=quickexitlabel; oldfaillabel:=faillabel; { get new labels } getlabel(aktexitlabel); getlabel(aktexit2label); { exit for fail in constructors } if (aktprocsym^.definition^.proctypeoption=potype_constructor) then begin getlabel(faillabel); getlabel(quickexitlabel); end; { reset break and continue labels } in_except_block:=false; aktbreaklabel:=nil; aktcontinuelabel:=nil; { insert symtables for the class, by only if it is no nested function } if assigned(procinfo^._class) and not(parent_has_class) then begin { insert them in the reverse order ! } hp:=nil; repeat _class:=procinfo^._class; while _class^.childof<>hp do _class:=_class^.childof; hp:=_class; _class^.symtable^.next:=symtablestack; symtablestack:=_class^.symtable; until hp=procinfo^._class; end; { insert parasymtable in symtablestack} { only if lexlevel > 1 !!! global symtable should be right after staticsymtazble for checking of same names used in interface and implementation !! } if lexlevel>=normal_function_level then begin aktprocsym^.definition^.parast^.next:=symtablestack; symtablestack:=aktprocsym^.definition^.parast; symtablestack^.symtablelevel:=lexlevel; end; { insert localsymtable in symtablestack} aktprocsym^.definition^.localst^.next:=symtablestack; symtablestack:=aktprocsym^.definition^.localst; symtablestack^.symtablelevel:=lexlevel; { constant symbols are inserted in this symboltable } constsymtable:=symtablestack; { reset the temporary memory } cleartempgen; {$ifdef newcg} tg.usedinproc:=[]; {$else newcg} { no registers are used } usedinproc:=0; {$endif newcg} { save entry info } entrypos:=aktfilepos; entryswitches:=aktlocalswitches; {$ifdef newcg} { parse the code ... } if (po_assembler in aktprocsym^.definition^.procoptions) then code:=convtree2node(assembler_block) else code:=convtree2node(block(current_module^.islibrary)); {$else newcg} { parse the code ... } if (po_assembler in aktprocsym^.definition^.procoptions) then code:=assembler_block else code:=block(current_module^.islibrary); {$endif newcg} { get a better entry point } if assigned(code) then entrypos:=code^.fileinfo; { save exit info } exitswitches:=aktlocalswitches; exitpos:=last_endtoken_filepos; { save current filepos } savepos:=aktfilepos; {When we are called to compile the body of a unit, aktprocsym should point to the unit initialization. If the unit has no initialization, aktprocsym=nil. But in that case code=nil. hus we should check for code=nil, when we use aktprocsym.} { set the framepointer to esp for assembler functions } { but only if the are no local variables } { already done in assembler_block } {$ifdef newcg} tg.setfirsttemp(procinfo^.firsttemp); {$else newcg} setfirsttemp(procinfo^.firsttemp); {$endif newcg} { ... and generate assembler } { but set the right switches for entry !! } aktlocalswitches:=entryswitches; {$ifndef NOPASS2} {$ifdef newcg} tg.setfirsttemp(procinfo^.firsttemp); {$else newcg} if assigned(code) then generatecode(code); {$endif newcg} { set switches to status at end of procedure } aktlocalswitches:=exitswitches; if assigned(code) then begin aktprocsym^.definition^.code:=code; { the procedure is now defined } aktprocsym^.definition^.forwarddef:=false; {$ifdef newcg} aktprocsym^.definition^.usedregisters:=tg.usedinproc; {$else newcg} aktprocsym^.definition^.usedregisters:=usedinproc; {$endif newcg} end; {$ifdef newcg} stackframe:=tg.gettempsize; {$else newcg} stackframe:=gettempsize; {$endif newcg} { first generate entry code with the correct position and switches } aktfilepos:=entrypos; aktlocalswitches:=entryswitches; {$ifdef newcg} if assigned(code) then cg^.g_entrycode(procinfo^.aktentrycode,proc_names,make_global,stackframe,parasize,nostackframe,false); {$else newcg} if assigned(code) then genentrycode(procinfo^.aktentrycode,proc_names,make_global,stackframe,parasize,nostackframe,false); {$endif newcg} { now generate exit code with the correct position and switches } aktfilepos:=exitpos; aktlocalswitches:=exitswitches; if assigned(code) then begin {$ifdef newcg} cg^.g_exitcode(procinfo^.aktexitcode,parasize,nostackframe,false); {$else newcg} genexitcode(procinfo^.aktexitcode,parasize,nostackframe,false); {$endif newcg} procinfo^.aktproccode^.insertlist(procinfo^.aktentrycode); procinfo^.aktproccode^.concatlist(procinfo^.aktexitcode); {$ifdef i386} {$ifndef NoOpt} if (cs_optimize in aktglobalswitches) and { do not optimize pure assembler procedures } ((procinfo^.flags and pi_is_assembler)=0) then Optimize(procinfo^.aktproccode); {$endif NoOpt} {$endif} { save local data (casetable) also in the same file } if assigned(procinfo^.aktlocaldata) and (not procinfo^.aktlocaldata^.empty) then begin procinfo^.aktproccode^.concat(new(pai_section,init(sec_data))); procinfo^.aktproccode^.concatlist(procinfo^.aktlocaldata); end; { now we can insert a cut } if (cs_create_smart in aktmoduleswitches) then codesegment^.concat(new(pai_cut,init)); { add the procedure to the codesegment } codesegment^.concatlist(procinfo^.aktproccode); end; {$else} if assigned(code) then firstpass(code); {$endif NOPASS2} { ... remove symbol tables, for the browser leave the static table } { if (cs_browser in aktmoduleswitches) and (symtablestack^.symtabletype=staticsymtable) then symtablestack^.next:=symtablestack^.next^.next else } if lexlevel>=normal_function_level then symtablestack:=symtablestack^.next^.next else symtablestack:=symtablestack^.next; { ... check for unused symbols } { but only if there is no asm block } if assigned(code) then begin if (Errorcount=0) then begin aktprocsym^.definition^.localst^.check_forwards; aktprocsym^.definition^.localst^.checklabels; end; if (procinfo^.flags and pi_uses_asm)=0 then begin { not for unit init, becuase the var can be used in finalize, it will be done in proc_unit } if not(aktprocsym^.definition^.proctypeoption in [potype_unitinit,potype_unitfinalize]) then aktprocsym^.definition^.localst^.allsymbolsused; aktprocsym^.definition^.parast^.allsymbolsused; end; end; { the local symtables can be deleted, but the parast } { doesn't, (checking definitons when calling a } { function } { not for a inline procedure !! (PM) } { at lexlevel = 1 localst is the staticsymtable itself } { so no dispose here !! } if assigned(code) and not(cs_browser in aktmoduleswitches) and not(pocall_inline in aktprocsym^.definition^.proccalloptions) then begin if lexlevel>=normal_function_level then dispose(aktprocsym^.definition^.localst,done); aktprocsym^.definition^.localst:=nil; end; { only now we can remove the temps } resettempgen; { remove code tree, if not inline procedure } if assigned(code) and not(pocall_inline in aktprocsym^.definition^.proccalloptions) then {$ifdef newcg} dispose(code,done); {$else newcg} disposetree(code); {$endif newcg} { remove class member symbol tables } while symtablestack^.symtabletype=objectsymtable do symtablestack:=symtablestack^.next; { restore filepos, the switches are already set } aktfilepos:=savepos; { free labels } freelabel(aktexitlabel); freelabel(aktexit2label); if (aktprocsym^.definition^.proctypeoption=potype_constructor) then begin freelabel(faillabel); freelabel(quickexitlabel); end; { restore labels } aktexitlabel:=oldexitlabel; aktexit2label:=oldexit2label; quickexitlabel:=oldquickexitlabel; faillabel:=oldfaillabel; { reset to normal non static function } if (lexlevel=normal_function_level) then allow_only_static:=false; { previous lexlevel } dec(lexlevel); end; procedure parse_proc_directives(Anames:Pstringcontainer;var pdflags:word); { Parse the procedure directives. It does not matter if procedure directives are written using ;procdir; or ['procdir'] syntax. } var res : boolean; begin while token in [_ID,_LECKKLAMMER] do begin if try_to_consume(_LECKKLAMMER) then begin repeat parse_proc_direc(Anames^,pdflags); until not try_to_consume(_COMMA); consume(_RECKKLAMMER); { we always expect at least '[];' } res:=true; end else res:=parse_proc_direc(Anames^,pdflags); { A procedure directive normally followed by a semicolon, but in a const section we should stop when _EQUAL is found } if res then begin if (block_type=bt_const) and (token=_EQUAL) then break; consume(_SEMICOLON); end else break; end; end; procedure parse_var_proc_directives(var sym : psym); var anames : pstringcontainer; pdflags : word; oldsym : pprocsym; pd : pabstractprocdef; begin oldsym:=aktprocsym; anames:=new(pstringcontainer,init); pdflags:=pd_procvar; { we create a temporary aktprocsym to read the directives } aktprocsym:=new(pprocsym,init(sym^.name)); case sym^.typ of varsym : pd:=pabstractprocdef(pvarsym(sym)^.definition); typedconstsym : pd:=pabstractprocdef(ptypedconstsym(sym)^.definition); typesym : pd:=pabstractprocdef(ptypesym(sym)^.definition); else internalerror(994932432); end; if pd^.deftype<>procvardef then internalerror(994932433); pabstractprocdef(aktprocsym^.definition):=pd; { names should never be used anyway } inc(lexlevel); parse_proc_directives(anames,pdflags); dec(lexlevel); aktprocsym^.definition:=nil; dispose(aktprocsym,done); dispose(anames,done); aktprocsym:=oldsym; end; procedure parse_object_proc_directives(var sym : pprocsym); var anames : pstringcontainer; pdflags : word; begin pdflags:=pd_object; anames:=new(pstringcontainer,init); inc(lexlevel); parse_proc_directives(anames,pdflags); dec(lexlevel); dispose(anames,done); if (po_containsself in aktprocsym^.definition^.procoptions) and (([po_msgstr,po_msgint]*aktprocsym^.definition^.procoptions)=[]) then Message(parser_e_self_in_non_message_handler); end; procedure checkvaluepara(p:pnamedindexobject);{$ifndef FPC}far;{$endif} var vs : pvarsym; s : string; begin with pvarsym(p)^ do begin if copy(name,1,3)='val' then begin s:=Copy(name,4,255); if not(po_assembler in aktprocsym^.definition^.procoptions) then begin vs:=new(Pvarsym,init(s,definition)); vs^.fileinfo:=fileinfo; vs^.varspez:=varspez; aktprocsym^.definition^.localst^.insert(vs); vs^.islocalcopy:=true; vs^.varstate:=vs_used; localvarsym:=vs; end else begin aktprocsym^.definition^.parast^.rename(name,s); end; end; end; end; procedure read_proc; { Parses the procedure directives, then parses the procedure body, then generates the code for it } var oldprefix : string; oldprocsym : Pprocsym; oldprocinfo : pprocinfo; oldconstsymtable : Psymtable; oldfilepos : tfileposinfo; names : Pstringcontainer; pdflags : word; prevdef,stdef : pprocdef; begin { save old state } oldprocsym:=aktprocsym; oldprefix:=procprefix; oldconstsymtable:=constsymtable; oldprocinfo:=procinfo; { create a new procedure } new(names,init); codegen_newprocedure; with procinfo^ do begin parent:=oldprocinfo; { clear flags } flags:=0; { standard frame pointer } framepointer:=frame_pointer; funcret_is_valid:=false; { is this a nested function of a method ? } if assigned(oldprocinfo) then _class:=oldprocinfo^._class; end; parse_proc_dec; { set the default function options } if parse_only then begin aktprocsym^.definition^.forwarddef:=true; { set also the interface flag, for better error message when the implementation doesn't much this header } aktprocsym^.definition^.interfacedef:=true; pdflags:=pd_interface; end else begin pdflags:=pd_body; if current_module^.in_implementation then pdflags:=pdflags or pd_implemen; if (not current_module^.is_unit) or (cs_create_smart in aktmoduleswitches) then pdflags:=pdflags or pd_global; procinfo^.exported:=false; aktprocsym^.definition^.forwarddef:=false; end; { parse the directives that may follow } inc(lexlevel); parse_proc_directives(names,pdflags); dec(lexlevel); { set aktfilepos to the beginning of the function declaration } oldfilepos:=aktfilepos; aktfilepos:=aktprocsym^.definition^.fileinfo; { search for forward declarations } if not check_identical(prevdef) then begin { A method must be forward defined (in the object declaration) } if assigned(procinfo^._class) and (not assigned(oldprocinfo^._class)) then Message(parser_e_header_dont_match_any_member); { Give a better error if there is a forward def in the interface and only a single implementation } if (not aktprocsym^.definition^.forwarddef) and assigned(aktprocsym^.definition^.nextoverloaded) and aktprocsym^.definition^.nextoverloaded^.forwarddef and aktprocsym^.definition^.nextoverloaded^.interfacedef and not(assigned(aktprocsym^.definition^.nextoverloaded^.nextoverloaded)) then Message1(parser_e_header_dont_match_forward,aktprocsym^.demangledName) else begin { check the global flag } if (procinfo^.flags and pi_is_global)<>0 then Message(parser_e_overloaded_must_be_all_global); end end; { set return type here, becuase the aktprocsym^.definition can be changed by check_identical (PFV) } procinfo^.retdef:=aktprocsym^.definition^.retdef; { pointer to the return value ? } if ret_in_param(procinfo^.retdef) then begin procinfo^.retoffset:=procinfo^.call_offset; inc(procinfo^.call_offset,target_os.size_of_pointer); end; { allows to access the parameters of main functions in nested functions } aktprocsym^.definition^.parast^.address_fixup:=procinfo^.call_offset; { when it is a value para and it needs a local copy then rename the parameter and insert a copy in the localst. This is not done for assembler procedures } if (not parse_only) and (not aktprocsym^.definition^.forwarddef) then aktprocsym^.definition^.parast^.foreach({$ifndef TP}@{$endif}checkvaluepara); { restore file pos } aktfilepos:=oldfilepos; { compile procedure when a body is needed } if (pdflags and pd_body)<>0 then begin Message1(parser_p_procedure_start,aktprocsym^.demangledname); names^.insert(aktprocsym^.definition^.mangledname); { set _FAIL as keyword if constructor } if (aktprocsym^.definition^.proctypeoption=potype_constructor) then tokeninfo^[_FAIL].keyword:=m_all; if assigned(aktprocsym^.definition^._class) then tokeninfo^[_SELF].keyword:=m_all; compile_proc_body(names^,((pdflags and pd_global)<>0),assigned(oldprocinfo^._class)); { reset _FAIL as normal } if (aktprocsym^.definition^.proctypeoption=potype_constructor) then tokeninfo^[_FAIL].keyword:=m_none; if assigned(aktprocsym^.definition^._class) and (lexlevel=main_program_level) then tokeninfo^[_SELF].keyword:=m_none; consume(_SEMICOLON); end; { close } dispose(names,done); codegen_doneprocedure; { Restore old state } constsymtable:=oldconstsymtable; { from now on all refernece to mangledname means that the function is already used } aktprocsym^.definition^.count:=true; { restore the interface order to maintain CRC values PM } if assigned(prevdef) and assigned(aktprocsym^.definition^.nextoverloaded) then begin stdef:=aktprocsym^.definition; aktprocsym^.definition:=stdef^.nextoverloaded; stdef^.nextoverloaded:=prevdef^.nextoverloaded; prevdef^.nextoverloaded:=stdef; end; aktprocsym:=oldprocsym; procprefix:=oldprefix; procinfo:=oldprocinfo; opsym:=nil; end; end. { $Log$ Revision 1.28 1999-10-13 10:37:36 peter * moved mangledname creation of normal proc so it also handles a wrong method proc Revision 1.27 1999/10/12 21:20:46 florian * new codegenerator compiles again Revision 1.26 1999/10/03 19:38:39 peter * fixed forward decl check for tp7/delphi Revision 1.25 1999/10/01 10:05:44 peter + procedure directive support in const declarations, fixes bug 232 Revision 1.24 1999/10/01 08:02:47 peter * forward type declaration rewritten Revision 1.23 1999/09/27 23:44:56 peter * procinfo is now a pointer * support for result setting in sub procedure Revision 1.22 1999/09/20 16:39:00 peter * cs_create_smart instead of cs_smartlink * -CX is create smartlink * -CD is create dynamic, but does nothing atm. Revision 1.21 1999/09/15 20:35:42 florian * small fix to operator overloading when in MMX mode + the compiler uses now fldz and fld1 if possible + some fixes to floating point registers + some math. functions (arctan, ln, sin, cos, sqrt, sqr, pi) are now inlined * .... ??? Revision 1.20 1999/09/10 18:48:09 florian * some bug fixes (e.g. must_be_valid and procinfo^.funcret_is_valid) * most things for stored properties fixed Revision 1.19 1999/09/07 14:59:40 pierre * bugfix for 237 and 244 Revision 1.18 1999/09/02 18:47:45 daniel * Could not compile with TP, some arrays moved to heap * NOAG386BIN default for TP * AG386* files were not compatible with TP, fixed. Revision 1.17 1999/08/30 10:17:57 peter * fixed crash in psub * ansistringcompare fixed * support for #$0b8 Revision 1.16 1999/08/27 10:41:46 pierre * pi_is_global was missing for global methods + code to restore overloaded list order (necessary to get same CRC values after interface and after implementation) Revision 1.15 1999/08/19 13:02:11 pierre + label faillabel added for _FAIL support Revision 1.14 1999/08/10 16:24:44 pierre * linking to C code with cdecl;external; was broken Revision 1.13 1999/08/10 12:37:44 pierre + procsym field of tprocdef set Revision 1.12 1999/08/05 16:53:06 peter * V_Fatal=1, all other V_ are also increased * Check for local procedure when assigning procvar * fixed comment parsing because directives * oldtp mode directives better supported * added some messages to errore.msg Revision 1.11 1999/08/04 13:03:01 jonas * all tokens now start with an underscore * PowerPC compiles!! Revision 1.10 1999/08/04 00:23:20 florian * renamed i386asm and i386base to cpuasm and cpubase Revision 1.9 1999/08/03 22:03:05 peter * moved bitmask constants to sets * some other type/const renamings Revision 1.8 1999/08/03 17:09:42 florian * the alpha compiler can be compiled now Revision 1.7 1999/08/02 21:29:01 florian * the main branch psub.pas is now used for newcg compiler Revision 1.6 1999/07/27 23:42:16 peter * indirect type referencing is now allowed Revision 1.5 1999/07/26 09:42:15 florian * bugs 494-496 fixed Revision 1.4 1999/07/11 20:10:24 peter * merged Revision 1.3 1999/07/02 13:02:24 peter * merged Revision 1.2 1999/06/17 13:19:56 pierre * merged from 0_99_12 branch Revision 1.1.2.4 1999/07/11 20:07:39 peter * message crash fixed * no error if self is used with non-string message Revision 1.1.2.3 1999/07/11 20:04:05 pierre * fix for problem with external without parameters in Delphi mode Revision 1.1.2.2 1999/07/02 12:59:52 peter * fixed parsing of message directive Revision 1.1.2.1 1999/06/17 12:44:47 pierre * solve problems related to assignment overloading * support Delphi syntax for operator * avoid problems if local procedure in operator Revision 1.1 1999/06/11 13:21:37 peter * reinserted Revision 1.153 1999/06/02 22:44:14 pierre * previous wrong log corrected Revision 1.152 1999/06/02 22:25:46 pierre * changed $ifdef FPC @ into $ifndef TP Revision 1.151 1999/06/01 22:47:06 pierre * problem with static keyword solved Revision 1.150 1999/06/01 14:45:53 peter * @procvar is now always needed for FPC Revision 1.149 1999/05/31 16:42:31 peter * interfacedef flag for procdef if it's defined in the interface, to make a difference with 'forward;' directive forwarddef. Fixes 253 Revision 1.148 1999/05/27 19:44:52 peter * removed oldasm * plabel -> pasmlabel * -a switches to source writing automaticly * assembler readers OOPed * asmsymbol automaticly external * jumptables and other label fixes for asm readers Revision 1.147 1999/05/24 08:55:27 florian * non working safecall directiv implemented, I don't know if we need it Revision 1.146 1999/05/23 18:42:11 florian * better error recovering in typed constants * some problems with arrays of const fixed, some problems due my previous - the location type of array constructor is now LOC_MEM - the pushing of high fixed - parameter copying fixed - zero temp. allocation removed * small problem in the assembler writers fixed: ref to nil wasn't written correctly Revision 1.145 1999/05/21 13:55:09 peter * NEWLAB for label as symbol Revision 1.144 1999/05/18 14:15:55 peter * containsself fixes * checktypes() Revision 1.143 1999/05/17 21:57:13 florian * new temporary ansistring handling Revision 1.142 1999/05/17 15:06:38 pierre * fixes for object type check Revision 1.141 1999/05/13 21:59:39 peter * removed oldppu code * warning if objpas is loaded from uses * first things for new deref writing Revision 1.140 1999/05/12 22:36:12 florian * override isn't allowed in objects! Revision 1.139 1999/05/10 09:01:41 peter * small message fixes Revision 1.138 1999/05/09 12:46:24 peter + hint where a duplicate sym is already defined Revision 1.137 1999/05/08 19:48:45 peter * better error message if declaration doesn't match forward Revision 1.136 1999/05/08 15:26:15 peter * print also manglednames when changed Revision 1.135 1999/05/06 10:12:10 peter * fixed operator result offset which destroyed parast^.datasize Revision 1.134 1999/05/01 13:24:36 peter * merged nasm compiler * old asm moved to oldasm/ Revision 1.133 1999/04/28 11:12:03 peter * fixed crash with self pointer Revision 1.132 1999/04/28 06:02:09 florian * changes of Bruessel: + message handler can now take an explicit self * typinfo fixed: sometimes the type names weren't written * the type checking for pointer comparisations and subtraction and are now more strict (was also buggy) * small bug fix to link.pas to support compiling on another drive * probable bug in popt386 fixed: call/jmp => push/jmp transformation didn't count correctly the jmp references + threadvar support * warning if ln/sqrt gets an invalid constant argument Revision 1.131 1999/04/26 13:31:44 peter * release storenumber,double_checksum Revision 1.130 1999/04/21 09:43:49 peter * storenumber works * fixed some typos in double_checksum + incompatible types type1 and type2 message (with storenumber) Revision 1.129 1999/04/20 14:39:07 daniel *** empty log message *** Revision 1.125 1999/04/14 09:14:55 peter * first things to store the symbol/def number in the ppu Revision 1.124 1999/04/07 15:31:13 pierre * all formaldefs are now a sinlge definition cformaldef (this was necessary for double_checksum) + small part of double_checksum code Revision 1.123 1999/04/06 11:21:58 peter * more use of ttoken Revision 1.122 1999/03/31 13:55:16 peter * assembler inlining working for ag386bin Revision 1.121 1999/03/26 00:05:39 peter * released valintern + deffile is now removed when compiling is finished * ^( compiles now correct + static directive * shrd fixed Revision 1.120 1999/03/24 23:17:18 peter * fixed bugs 212,222,225,227,229,231,233 Revision 1.119 1999/03/05 09:46:18 pierre * public problem for methods Revision 1.118 1999/03/05 01:14:24 pierre * bug0198 : call conventions for methods not yet implemented is the control of same calling convention for virtual and child's virtual * msgstr and msgint only created if message was found who implemented this by the way ? it leaks lots of plabels !!!! (check with heaptrc !) Revision 1.117 1999/03/04 13:55:47 pierre * some m68k fixes (still not compilable !) * new(tobj) does not give warning if tobj has no VMT ! Revision 1.116 1999/03/01 15:40:52 peter * external name didn't concatexternal() Revision 1.115 1999/03/01 13:31:58 pierre * external used before implemented problem fixed Revision 1.114 1999/02/24 00:59:15 peter * small updates for ag386bin Revision 1.113 1999/02/23 18:29:21 pierre * win32 compilation error fix + some work for local browser (not cl=omplete yet) Revision 1.112 1999/02/22 13:07:03 pierre + -b and -bl options work ! + cs_local_browser ($L+) is disabled if cs_browser ($Y+) is not enabled when quitting global section * local vars and procedures are not yet stored into PPU Revision 1.111 1999/02/22 02:15:33 peter * updates for ag386bin Revision 1.110 1999/02/16 12:23:19 pierre * nested forward procedure bug solved Revision 1.109 1999/02/15 10:07:06 pierre * memory leaks due to last commit solved Revision 1.108 1999/02/11 09:46:27 pierre * fix for normal method calls inside static methods : WARNING there were both parser and codegen errors !! added static_call boolean to calln tree Revision 1.107 1999/02/10 11:27:39 pierre * overloaded function locals problem bug0213 Revision 1.106 1999/02/08 11:29:05 pierre * fix for bug0214 several problems where combined search_class_member did not set srsymtable => in do_member_read the call node got a wrong symtable in cg386cal the vmt was pushed twice without chacking if it exists now %esi is set to zero and pushed if not vmt (not very efficient but should work !) Revision 1.105 1999/02/05 12:51:20 florian + openstring id is now supported Revision 1.104 1999/02/03 09:26:44 pierre + better reference for args of procs Revision 1.103 1999/02/02 11:04:37 florian * class destructors fixed, class instances weren't disposed correctly Revision 1.102 1999/01/21 22:10:46 peter * fixed array of const * generic platform independent high() support Revision 1.101 1999/01/20 14:18:38 pierre * bugs related to mangledname solved - linux external without name -external procs already used (added count and is_used boolean fiels in tprocvar) Revision 1.100 1999/01/20 10:20:19 peter * don't make localvar copies for assembler procedures Revision 1.99 1999/01/19 15:59:40 pierre * fix for function a; Revision 1.98 1999/01/19 12:16:07 peter * NOPASS2 now calls firstpass Revision 1.97 1999/01/14 11:35:30 daniel * Fixed manglednames Revision 1.96 1998/12/30 13:41:10 peter * released valuepara Revision 1.95 1998/12/30 10:36:39 michael + Delphi also allows external in interface section Revision 1.94 1998/12/29 18:48:26 jonas + optimize pascal code surrounding assembler blocks Revision 1.93 1998/12/28 15:44:49 peter + NOPASS2 define Revision 1.92 1998/12/11 00:03:39 peter + globtype,tokens,version unit splitted from globals Revision 1.91 1998/11/27 14:50:42 peter + open strings, $P switch support Revision 1.90 1998/11/18 17:45:27 peter * fixes for VALUEPARA Revision 1.89 1998/11/18 15:44:15 peter * VALUEPARA for tp7 compatible value parameters Revision 1.88 1998/11/16 15:40:30 pierre * mangling name and -So bugs solved Revision 1.87 1998/11/16 11:29:02 pierre * stackcheck removed for i386_win32 * exportlist does not crash at least !! (was need for tests dir !)z Revision 1.86 1998/11/16 10:13:54 peter * label defines are checked at the end of the proc Revision 1.85 1998/11/13 15:40:26 pierre + added -Se in Makefile cvstest target + lexlevel cleanup normal_function_level main_program_level and unit_init_level defined * tins_cache grown to A_EMMS (gave range check error in asm readers) (test added in code !) * -Un option was wrong * _FAIL and _SELF only keyword inside constructors and methods respectively Revision 1.84 1998/11/10 10:09:13 peter * va_list -> array of const Revision 1.83 1998/11/09 11:44:34 peter + va_list for printf support Revision 1.82 1998/10/29 11:35:53 florian * some dll support for win32 * fixed assembler writing for PalmOS Revision 1.81 1998/10/28 18:26:16 pierre * removed some erros after other errors (introduced by useexcept) * stabs works again correctly (for how long !) Revision 1.80 1998/10/27 13:45:37 pierre * classes get a vmt allways * better error info (tried to remove several error strings introduced by the tpexcept handling) Revision 1.79 1998/10/23 00:09:43 peter * fixed message for forward declaration Revision 1.78 1998/10/20 13:10:37 peter * fixed crash when aktprocsym<>procsym Revision 1.77 1998/10/20 08:06:55 pierre * several memory corruptions due to double freemem solved => never use p^.loc.location:=p^.left^.loc.location; + finally I added now by default that ra386dir translates global and unit symbols + added a first field in tsymtable and a nextsym field in tsym (this allows to obtain ordered type info for records and objects in gdb !) Revision 1.76 1998/10/19 08:55:02 pierre * wrong stabs info corrected once again !! + variable vmt offset with vmt field only if required implemented now !!! Revision 1.75 1998/10/16 08:51:48 peter + target_os.stackalignment + stack can be aligned at 2 or 4 byte boundaries Revision 1.74 1998/10/14 20:39:21 florian * syscall for PalmOs fixed Revision 1.73 1998/10/12 12:20:56 pierre + added tai_const_symbol_offset for r : pointer = @var.field; * better message for different arg names on implementation of function Revision 1.72 1998/10/08 23:29:03 peter * -vu shows unit info, -vt shows tried/used files Revision 1.71 1998/10/08 17:17:28 pierre * current_module old scanner tagged as invalid if unit is recompiled + added ppheap for better info on tracegetmem of heaptrc (adds line column and file index) * several memory leaks removed ith help of heaptrc !! Revision 1.70 1998/10/08 13:48:49 peter * fixed memory leaks for do nothing source * fixed unit interdependency Revision 1.69 1998/10/05 21:33:27 peter * fixed 161,165,166,167,168 Revision 1.68 1998/09/29 11:31:30 florian * better error recovering when the object type of procedure tobject.method isn't found Revision 1.67 1998/09/26 17:45:39 peter + idtoken and only one token table Revision 1.66 1998/09/24 23:49:16 peter + aktmodeswitches Revision 1.65 1998/09/24 11:08:14 florian * small problem in _proc_header with array of const fixed: getsymonlyin doesn't set srsym to nil Revision 1.64 1998/09/23 15:39:12 pierre * browser bugfixes was adding a reference when looking for the symbol if -bSYM_NAME was used Revision 1.63 1998/09/22 17:13:50 pierre + browsing updated and developed records and objects fields are also stored Revision 1.62 1998/09/22 15:37:21 peter + array of const start Revision 1.61 1998/09/21 08:45:20 pierre + added vmt_offset in tobjectdef.write for fututre use (first steps to have objects without vmt if no virtual !!) + added fpu_used field for tabstractprocdef : sets this level to 2 if the functions return with value in FPU (is then set to correct value at parsing of implementation) THIS MIGHT refuse some code with FPU expression too complex that were accepted before and even in some cases that don't overflow in fact ( like if f : float; is a forward that finally in implementation only uses one fpu register !!) Nevertheless I think that it will improve security on FPU operations !! * most other changes only for UseBrowser code (added symtable references for record and objects) local switch for refs to args and local of each function (static symtable still missing) UseBrowser still not stable and probably broken by the definition hash array !! Revision 1.60 1998/09/17 09:42:42 peter + pass_2 for cg386 * Message() -> CGMessage() for pass_1/pass_2 Revision 1.59 1998/09/15 14:05:25 jonas * fixed optimizer incompatibilities with freelabel code in psub Revision 1.58 1998/09/14 21:27:41 peter - freelabel calls, becuase they are instable with -O2 Revision 1.57 1998/09/14 10:38:27 peter * pd_alias now uses get_stringconst Revision 1.56 1998/09/14 10:29:38 daniel * Fixed memory leaks. Revision 1.55 1998/09/09 11:50:56 pierre * forward def are not put in record or objects + added check for forwards also in record and objects * dummy parasymtable for unit initialization removed from symtable stack Revision 1.54 1998/09/04 08:42:05 peter * updated some error messages Revision 1.53 1998/09/01 17:39:51 peter + internal constant functions Revision 1.52 1998/09/01 09:07:12 peter * m68k fixes, splitted cg68k like cgi386 Revision 1.51 1998/09/01 07:54:21 pierre * UseBrowser a little updated (might still be buggy !!) * bug in psub.pas in function specifier removed * stdcall allowed in interface and in implementation (FPC will not yet complain if it is missing in either part because stdcall is only a dummy !!) Revision 1.50 1998/08/31 12:26:31 peter * m68k and palmos updates from surebugfixes Revision 1.49 1998/08/25 12:42:43 pierre * CDECL changed to CVAR for variables specifications are read in structures also + started adding GPC compatibility mode ( option -Sp) * names changed to lowercase Revision 1.48 1998/08/21 08:43:30 pierre * pocdecl and poclearstack are now different external must but written as last specification Revision 1.47 1998/08/20 09:26:44 pierre + funcret setting in underproc testing compile with _dTEST_FUNCRET Revision 1.46 1998/08/19 18:04:55 peter * fixed current_module^.in_implementation flag Revision 1.45 1998/08/13 10:58:38 peter * fixed function reading for -So which was not correct after my previous fix for bug 147 Revision 1.44 1998/08/10 14:50:18 peter + localswitches, moduleswitches, globalswitches splitting Revision 1.43 1998/08/10 09:58:33 peter * Fixed function b; in -So mode Revision 1.42 1998/07/30 16:07:11 florian * try ... expect end; works now Revision 1.41 1998/07/23 19:31:19 jonas * split the optimizer Revision 1.40 1998/07/21 11:16:24 florian * bug0147 fixed Revision 1.39 1998/07/14 21:46:54 peter * updated messages file Revision 1.38 1998/07/14 14:46:57 peter * released NEWINPUT Revision 1.37 1998/07/10 13:12:53 peter * carls patch Revision 1.36 1998/07/10 13:06:53 michael + Carls patch. Checked make cycle. Revision 1.35 1998/07/10 00:00:01 peter * fixed ttypesym bug finally * fileinfo in the symtable and better using for unused vars Revision 1.34 1998/07/07 11:20:05 peter + NEWINPUT for a better inputfile and scanner object Revision 1.33 1998/06/15 15:38:08 pierre * small bug in systems.pas corrected + operators in different units better hanlded Revision 1.32 1998/06/13 00:10:13 peter * working browser and newppu * some small fixes against crashes which occured in bp7 (but not in fpc?!) Revision 1.31 1998/06/10 17:04:05 michael + Fix for reading untyped const parameters Revision 1.30 1998/06/09 16:01:50 pierre + added procedure directive parsing for procvars (accepted are popstack cdecl and pascal) + added C vars with the following syntax var C calias 'true_c_name';(can be followed by external) reason is that you must add the Cprefix which is target dependent Revision 1.29 1998/06/08 22:59:51 peter * smartlinking works for win32 * some defines to exclude some compiler parts Revision 1.28 1998/06/08 13:13:45 pierre + temporary variables now in temp_gen.pas unit because it is processor independent * mppc68k.bat modified to undefine i386 and support_mmx (which are defaults for i386) Revision 1.27 1998/06/05 17:47:30 peter * some better uses clauses Revision 1.26 1998/06/05 14:37:36 pierre * fixes for inline for operators * inline procedure more correctly restricted Revision 1.25 1998/06/04 23:51:54 peter * m68k compiles + .def file creation moved to gendef.pas so it could also be used for win32 Revision 1.24 1998/06/04 09:55:44 pierre * demangled name of procsym reworked to become independant of the mangling scheme Revision 1.23 1998/05/28 17:26:51 peter * fixed -R switch, it didn't work after my previous akt/init patch * fixed bugs 110,130,136 Revision 1.22 1998/05/28 14:40:27 peter * fixes for newppu, remake3 works now with it Revision 1.21 1998/05/23 01:21:25 peter + aktasmmode, aktoptprocessor, aktoutputformat + smartlink per module $SMARTLINK-/+ (like MMX) and moved to aktswitches + $LIBNAME to set the library name where the unit will be put in * splitted cgi386 a bit (codeseg to large for bp7) * nasm, tasm works again. nasm moved to ag386nsm.pas Revision 1.20 1998/05/21 19:33:34 peter + better procedure directive handling and only one table Revision 1.19 1998/05/20 09:42:36 pierre + UseTokenInfo now default * unit in interface uses and implementation uses gives error now * only one error for unknown symbol (uses lastsymknown boolean) the problem came from the label code ! + first inlined procedures and function work (warning there might be allowed cases were the result is still wrong !!) * UseBrower updated gives a global list of all position of all used symbols with switch -gb Revision 1.18 1998/05/11 13:07:56 peter + $ifdef NEWPPU for the new ppuformat + $define GDB not longer required * removed all warnings and stripped some log comments * no findfirst/findnext anymore to remove smartlink *.o files Revision 1.17 1998/05/06 18:36:54 peter * tai_section extended with code,data,bss sections and enumerated type * ident 'compiled by FPC' moved to pmodules * small fix for smartlink Revision 1.16 1998/05/06 08:38:47 pierre * better position info with UseTokenInfo UseTokenInfo greatly simplified + added check for changed tree after first time firstpass (if we could remove all the cases were it happen we could skip all firstpass if firstpasscount > 1) Only with ExtDebug Revision 1.15 1998/05/04 17:54:28 peter + smartlinking works (only case jumptable left todo) * redesign of systems.pas to support assemblers and linkers + Unitname is now also in the PPU-file, increased version to 14 Revision 1.14 1998/05/01 09:01:24 florian + correct semantics of private and protected * small fix in variable scope: a id can be used in a parameter list of a method, even it is used in an anchestor class as field id Revision 1.13 1998/04/30 15:59:42 pierre * GDB works again better : correct type info in one pass + UseTokenInfo for better source position * fixed one remaining bug in scanner for line counts * several little fixes Revision 1.12 1998/04/29 10:34:00 pierre + added some code for ansistring (not complete nor working yet) * corrected operator overloading * corrected nasm output + started inline procedures + added starstarn : use ** for exponentiation (^ gave problems) + started UseTokenInfo cond to get accurate positions Revision 1.11 1998/04/27 23:10:28 peter + new scanner * $makelib -> if smartlink * small filename fixes pmodule.setfilename * moved import from files.pas -> import.pas Revision 1.10 1998/04/21 10:16:48 peter * patches from strasbourg * objects is not used anymore in the fpc compiled version Revision 1.9 1998/04/13 22:20:36 florian + stricter checking for duplicate id, solves also bug0097 Revision 1.8 1998/04/13 21:15:42 florian * error handling of pass_1 and cgi386 fixed * the following bugs fixed: 0117, 0118, 0119 and 0129, 0122 was already fixed, verified Revision 1.7 1998/04/13 08:42:52 florian * call by reference and call by value open arrays fixed Revision 1.6 1998/04/10 15:39:48 florian * more fixes to get classes.pas compiled Revision 1.5 1998/04/10 14:41:43 peter * removed some Hints * small speed optimization for AsmLn Revision 1.4 1998/04/08 16:58:05 pierre * several bugfixes ADD ADC and AND are also sign extended nasm output OK (program still crashes at end and creates wrong assembler files !!) procsym types sym in tdef removed !! }