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