fpc/compiler/pexpr.pas
peter 503d5a1cfa * const parameter is now checked
* better and generic check if a node can be used for assigning
  * export fixes
  * procvar equal works now (it never had worked at least from 0.99.8)
  * defcoll changed to linkedlist with pparaitem so it can easily be
    walked both directions
1999-10-26 12:30:40 +00:00

2725 lines
100 KiB
ObjectPascal

{
$Id$
Copyright (c) 1998 by Florian Klaempfl
Does parsing of expression for Free Pascal
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************
}
unit pexpr;
interface
uses symtable,tree;
{ reads a whole expression }
function expr : ptree;
{ reads an expression without assignements and .. }
function comp_expr(accept_equal : boolean):Ptree;
{ reads a single factor }
function factor(getaddr : boolean) : ptree;
{ the ID token has to be consumed before calling this function }
procedure do_member_read(getaddr : boolean;const sym : psym;var p1 : ptree;
var pd : pdef;var again : boolean);
function get_intconst:longint;
function get_stringconst:string;
implementation
uses
globtype,systems,tokens,
cobjects,globals,scanner,
symconst,aasm,
{$ifdef newcg}
cgbase,
{$else}
hcodegen,
{$endif}
types,verbose,strings,
{$ifndef newcg}
tccal,
{$endif newcg}
pass_1,
{ parser specific stuff }
pbase,ptype,
{ processor specific stuff }
cpubase,cpuinfo;
const
allow_type : boolean = true;
got_addrn : boolean = false;
function parse_paras(__colon,in_prop_paras : boolean) : ptree;
var
p1,p2 : ptree;
end_of_paras : ttoken;
begin
if in_prop_paras then
end_of_paras:=_RECKKLAMMER
else
end_of_paras:=_RKLAMMER;
if token=end_of_paras then
begin
parse_paras:=nil;
exit;
end;
p2:=nil;
inc(parsing_para_level);
while true do
begin
p1:=comp_expr(true);
p2:=gencallparanode(p1,p2);
{ it's for the str(l:5,s); }
if __colon and (token=_COLON) then
begin
consume(_COLON);
p1:=comp_expr(true);
p2:=gencallparanode(p1,p2);
p2^.is_colon_para:=true;
if token=_COLON then
begin
consume(_COLON);
p1:=comp_expr(true);
p2:=gencallparanode(p1,p2);
p2^.is_colon_para:=true;
end
end;
if token=_COMMA then
consume(_COMMA)
else
break;
end;
dec(parsing_para_level);
parse_paras:=p2;
end;
procedure check_tp_procvar(var p : ptree);
var
p1 : ptree;
Store_valid : boolean;
begin
if (m_tp_procvar in aktmodeswitches) and
(not got_addrn) and
(not in_args) and
(p^.treetype=loadn) then
begin
{ support if procvar then for tp7 and many other expression like this }
Store_valid:=Must_be_valid;
Must_be_valid:=false;
do_firstpass(p);
Must_be_valid:=Store_valid;
if not(getprocvar) and (p^.resulttype^.deftype=procvardef) then
begin
p1:=gencallnode(nil,nil);
p1^.right:=p;
p1^.resulttype:=pprocvardef(p^.resulttype)^.retdef;
firstpass(p1);
p:=p1;
end;
end;
end;
function statement_syssym(l : longint;var pd : pdef) : ptree;
var
p1,p2,paras : ptree;
prev_in_args : boolean;
Store_valid : boolean;
begin
prev_in_args:=in_args;
Store_valid:=Must_be_valid;
case l of
in_ord_x :
begin
consume(_LKLAMMER);
in_args:=true;
Must_be_valid:=true;
p1:=comp_expr(true);
consume(_RKLAMMER);
do_firstpass(p1);
p1:=geninlinenode(in_ord_x,false,p1);
do_firstpass(p1);
statement_syssym := p1;
pd:=p1^.resulttype;
end;
in_break :
begin
statement_syssym:=genzeronode(breakn);
pd:=voiddef;
end;
in_continue :
begin
statement_syssym:=genzeronode(continuen);
pd:=voiddef;
end;
in_typeof_x :
begin
consume(_LKLAMMER);
in_args:=true;
{allow_type:=true;}
p1:=comp_expr(true);
{allow_type:=false;}
consume(_RKLAMMER);
pd:=voidpointerdef;
if p1^.treetype=typen then
begin
if (p1^.typenodetype=nil) then
begin
Message(type_e_mismatch);
statement_syssym:=genzeronode(errorn);
end
else
if p1^.typenodetype^.deftype=objectdef then
begin
{ we can use resulttype in pass_2 (PM) }
p1^.resulttype:=p1^.typenodetype;
statement_syssym:=geninlinenode(in_typeof_x,false,p1);
end
else
begin
Message(type_e_mismatch);
disposetree(p1);
statement_syssym:=genzeronode(errorn);
end;
end
else { not a type node }
begin
Must_be_valid:=false;
do_firstpass(p1);
if (p1^.resulttype=nil) then
begin
Message(type_e_mismatch);
disposetree(p1);
statement_syssym:=genzeronode(errorn)
end
else
if p1^.resulttype^.deftype=objectdef then
statement_syssym:=geninlinenode(in_typeof_x,false,p1)
else
begin
Message(type_e_mismatch);
statement_syssym:=genzeronode(errorn);
disposetree(p1);
end;
end;
end;
in_sizeof_x :
begin
consume(_LKLAMMER);
in_args:=true;
{allow_type:=true;}
p1:=comp_expr(true);
{allow_type:=false; }
consume(_RKLAMMER);
pd:=s32bitdef;
if p1^.treetype=typen then
begin
statement_syssym:=genordinalconstnode(p1^.typenodetype^.size,pd);
{ p1 not needed !}
disposetree(p1);
end
else
begin
Must_be_valid:=false;
do_firstpass(p1);
if ((p1^.resulttype^.deftype=objectdef) and
(oo_has_constructor in pobjectdef(p1^.resulttype)^.objectoptions)) or
is_open_array(p1^.resulttype) or
is_open_string(p1^.resulttype) then
statement_syssym:=geninlinenode(in_sizeof_x,false,p1)
else
begin
statement_syssym:=genordinalconstnode(p1^.resulttype^.size,pd);
{ p1 not needed !}
disposetree(p1);
end;
end;
end;
in_assigned_x :
begin
consume(_LKLAMMER);
in_args:=true;
p1:=comp_expr(true);
Must_be_valid:=true;
do_firstpass(p1);
if not codegenerror then
begin
case p1^.resulttype^.deftype of
pointerdef,
procvardef,
classrefdef : ;
objectdef :
if not(pobjectdef(p1^.resulttype)^.is_class) then
Message(parser_e_illegal_parameter_list);
else
Message(parser_e_illegal_parameter_list);
end;
end;
p2:=gencallparanode(p1,nil);
p2:=geninlinenode(in_assigned_x,false,p2);
consume(_RKLAMMER);
pd:=booldef;
statement_syssym:=p2;
end;
in_ofs_x :
begin
consume(_LKLAMMER);
in_args:=true;
p1:=comp_expr(true);
p1:=gensinglenode(addrn,p1);
Must_be_valid:=false;
do_firstpass(p1);
{ Ofs() returns a longint, not a pointer }
p1^.resulttype:=u32bitdef;
pd:=p1^.resulttype;
consume(_RKLAMMER);
statement_syssym:=p1;
end;
in_addr_x :
begin
consume(_LKLAMMER);
in_args:=true;
p1:=comp_expr(true);
p1:=gensinglenode(addrn,p1);
Must_be_valid:=false;
do_firstpass(p1);
pd:=p1^.resulttype;
consume(_RKLAMMER);
statement_syssym:=p1;
end;
in_seg_x :
begin
consume(_LKLAMMER);
in_args:=true;
p1:=comp_expr(true);
do_firstpass(p1);
if p1^.location.loc<>LOC_REFERENCE then
Message(cg_e_illegal_expression);
p1:=genordinalconstnode(0,s32bitdef);
Must_be_valid:=false;
pd:=s32bitdef;
consume(_RKLAMMER);
statement_syssym:=p1;
end;
in_high_x,
in_low_x :
begin
consume(_LKLAMMER);
in_args:=true;
{allow_type:=true;}
p1:=comp_expr(true);
{allow_type:=false;}
do_firstpass(p1);
if p1^.treetype=typen then
p1^.resulttype:=p1^.typenodetype;
Must_be_valid:=false;
p2:=geninlinenode(l,false,p1);
consume(_RKLAMMER);
pd:=s32bitdef;
statement_syssym:=p2;
end;
in_succ_x,
in_pred_x :
begin
consume(_LKLAMMER);
in_args:=true;
p1:=comp_expr(true);
do_firstpass(p1);
Must_be_valid:=false;
p2:=geninlinenode(l,false,p1);
consume(_RKLAMMER);
pd:=p1^.resulttype;
statement_syssym:=p2;
end;
in_inc_x,
in_dec_x :
begin
consume(_LKLAMMER);
in_args:=true;
p1:=comp_expr(true);
Must_be_valid:=false;
if token=_COMMA then
begin
consume(_COMMA);
p2:=gencallparanode(comp_expr(true),nil);
end
else
p2:=nil;
p2:=gencallparanode(p1,p2);
statement_syssym:=geninlinenode(l,false,p2);
consume(_RKLAMMER);
pd:=voiddef;
end;
in_concat_x :
begin
consume(_LKLAMMER);
in_args:=true;
p2:=nil;
while true do
begin
p1:=comp_expr(true);
Must_be_valid:=true;
do_firstpass(p1);
if not((p1^.resulttype^.deftype=stringdef) or
((p1^.resulttype^.deftype=orddef) and
(porddef(p1^.resulttype)^.typ=uchar))) then
Message(parser_e_illegal_parameter_list);
if p2<>nil then
p2:=gennode(addn,p2,p1)
else
p2:=p1;
if token=_COMMA then
consume(_COMMA)
else
break;
end;
consume(_RKLAMMER);
pd:=cshortstringdef;
statement_syssym:=p2;
end;
in_read_x,
in_readln_x :
begin
if token=_LKLAMMER then
begin
consume(_LKLAMMER);
in_args:=true;
Must_be_valid:=false;
paras:=parse_paras(false,false);
consume(_RKLAMMER);
end
else
paras:=nil;
pd:=voiddef;
p1:=geninlinenode(l,false,paras);
do_firstpass(p1);
statement_syssym := p1;
end;
in_write_x,
in_writeln_x :
begin
if token=_LKLAMMER then
begin
consume(_LKLAMMER);
in_args:=true;
Must_be_valid:=true;
paras:=parse_paras(true,false);
consume(_RKLAMMER);
end
else
paras:=nil;
pd:=voiddef;
p1 := geninlinenode(l,false,paras);
do_firstpass(p1);
statement_syssym := p1;
end;
in_str_x_string :
begin
consume(_LKLAMMER);
in_args:=true;
paras:=parse_paras(true,false);
consume(_RKLAMMER);
p1 := geninlinenode(l,false,paras);
do_firstpass(p1);
statement_syssym := p1;
pd:=voiddef;
end;
in_val_x:
Begin
consume(_LKLAMMER);
in_args := true;
p1:= gencallparanode(comp_expr(true), nil);
Must_be_valid := False;
consume(_COMMA);
p2 := gencallparanode(comp_expr(true),p1);
if (token = _COMMA) then
Begin
consume(_COMMA);
p2 := gencallparanode(comp_expr(true),p2)
End;
consume(_RKLAMMER);
p2 := geninlinenode(l,false,p2);
do_firstpass(p2);
statement_syssym := p2;
pd := voiddef;
End;
in_include_x_y,
in_exclude_x_y :
begin
consume(_LKLAMMER);
in_args:=true;
p1:=comp_expr(true);
Must_be_valid:=false;
consume(_COMMA);
p2:=comp_expr(true);
statement_syssym:=geninlinenode(l,false,gencallparanode(p1,gencallparanode(p2,nil)));
consume(_RKLAMMER);
pd:=voiddef;
end;
in_assert_x_y :
begin
consume(_LKLAMMER);
in_args:=true;
p1:=comp_expr(true);
if token=_COMMA then
begin
consume(_COMMA);
p2:=comp_expr(true);
end
else
begin
{ then insert an empty string }
p2:=genstringconstnode('');
end;
statement_syssym:=geninlinenode(l,false,gencallparanode(p1,gencallparanode(p2,nil)));
consume(_RKLAMMER);
pd:=voiddef;
end;
else
internalerror(15);
end;
in_args:=prev_in_args;
Must_be_valid:=Store_valid;
end;
{ reads the parameter for a subroutine call }
procedure do_proc_call(getaddr : boolean;var again : boolean;var p1:Ptree;var pd:Pdef);
var
prev_in_args : boolean;
prevafterassn : boolean;
Store_valid : boolean;
begin
prev_in_args:=in_args;
prevafterassn:=afterassignment;
afterassignment:=false;
{ want we only determine the address of }
{ a subroutine ? }
if not(getaddr) then
begin
if token=_LKLAMMER then
begin
consume(_LKLAMMER);
in_args:=true;
p1^.left:=parse_paras(false,false);
consume(_RKLAMMER);
end
else p1^.left:=nil;
{ do firstpass because we need the }
{ result type }
Store_valid:=Must_be_valid;
Must_be_valid:=false;
do_firstpass(p1);
Must_be_valid:=Store_valid;
end
else
begin
{ address operator @: }
p1^.left:=nil;
{ forget pd }
pd:=nil;
if (p1^.symtableproc^.symtabletype=withsymtable) and
(p1^.symtableproc^.defowner^.deftype=objectdef) then
begin
p1^.methodpointer:=getcopy(pwithsymtable(p1^.symtableproc)^.withrefnode);
end
else if not(assigned(p1^.methodpointer)) then
begin
{ we must provide a method pointer, if it isn't given, }
{ it is self }
if assigned(procinfo) then
begin
p1^.methodpointer:=genselfnode(procinfo^._class);
p1^.methodpointer^.resulttype:=procinfo^._class;
end
else
begin
p1^.methodpointer:=genselfnode(nil);
p1^.methodpointer^.resulttype:=nil;
end;
end;
{ no postfix operators }
again:=false;
end;
pd:=p1^.resulttype;
in_args:=prev_in_args;
afterassignment:=prevafterassn;
end;
procedure handle_procvar(pv : pprocvardef;var p2 : ptree);
procedure doconv(procvar : pprocvardef;var t : ptree);
var
hp : ptree;
begin
hp:=nil;
if (proc_to_procvar_equal(pprocsym(t^.symtableentry)^.definition,procvar)) then
begin
if (po_methodpointer in procvar^.procoptions) then
hp:=genloadmethodcallnode(pprocsym(t^.symtableprocentry),t^.symtable,getcopy(t^.methodpointer))
else
hp:=genloadcallnode(pprocsym(t^.symtableprocentry),t^.symtable);
end;
if assigned(hp) then
begin
disposetree(t);
t:=hp;
end;
end;
begin
if (p2^.treetype=calln) then
doconv(pv,p2)
else
if (p2^.treetype=typeconvn) and
(p2^.left^.treetype=calln) then
doconv(pv,p2^.left);
end;
{ the following procedure handles the access to a property symbol }
procedure handle_propertysym(sym : psym;st : psymtable;var p1 : ptree;
var pd : pdef);
var
paras : ptree;
p2 : ptree;
plist : ppropsymlist;
begin
paras:=nil;
{ property parameters? }
if token=_LECKKLAMMER then
begin
consume(_LECKKLAMMER);
paras:=parse_paras(false,true);
consume(_RECKKLAMMER);
end;
{ indexed property }
if (ppo_indexed in ppropertysym(sym)^.propoptions) then
begin
p2:=genordinalconstnode(ppropertysym(sym)^.index,s32bitdef);
paras:=gencallparanode(p2,paras);
end;
{ we need only a write property if a := follows }
{ if not(afterassignment) and not(in_args) then }
if token=_ASSIGNMENT then
begin
{ write property: }
{ no result }
pd:=voiddef;
if assigned(ppropertysym(sym)^.writeaccesssym) then
begin
case ppropertysym(sym)^.writeaccesssym^.sym^.typ of
procsym :
begin
{ generate the method call }
p1:=genmethodcallnode(pprocsym(ppropertysym(sym)^.writeaccesssym^.sym),st,p1);
{ we know the procedure to call, so
force the usage of that procedure }
p1^.procdefinition:=pprocdef(ppropertysym(sym)^.writeaccessdef);
p1^.left:=paras;
consume(_ASSIGNMENT);
{ read the expression }
getprocvar:=ppropertysym(sym)^.proptype^.deftype=procvardef;
p2:=comp_expr(true);
if getprocvar then
handle_procvar(pprocvardef(ppropertysym(sym)^.proptype),p2);
p1^.left:=gencallparanode(p2,p1^.left);
p1^.isproperty:=true;
getprocvar:=false;
end;
varsym :
begin
if assigned(paras) then
message(parser_e_no_paras_allowed);
{ subscribed access? }
plist:=ppropertysym(sym)^.writeaccesssym;
while assigned(plist) do
begin
if p1=nil then
p1:=genloadnode(pvarsym(plist^.sym),st)
else
p1:=gensubscriptnode(pvarsym(plist^.sym),p1);
plist:=plist^.next;
end;
p1^.isproperty:=true;
consume(_ASSIGNMENT);
{ read the expression }
p2:=comp_expr(true);
p1:=gennode(assignn,p1,p2);
end
else
begin
p1:=genzeronode(errorn);
Message(parser_e_no_procedure_to_access_property);
end;
end;
end
else
begin
p1:=genzeronode(errorn);
Message(parser_e_no_procedure_to_access_property);
end;
end
else
begin
{ read property: }
pd:=ppropertysym(sym)^.proptype;
if assigned(ppropertysym(sym)^.readaccesssym) then
begin
case ppropertysym(sym)^.readaccesssym^.sym^.typ of
varsym :
begin
if assigned(paras) then
message(parser_e_no_paras_allowed);
{ subscribed access? }
plist:=ppropertysym(sym)^.readaccesssym;
while assigned(plist) do
begin
if p1=nil then
p1:=genloadnode(pvarsym(plist^.sym),st)
else
p1:=gensubscriptnode(pvarsym(plist^.sym),p1);
plist:=plist^.next;
end;
p1^.isproperty:=true;
end;
procsym :
begin
{ generate the method call }
p1:=genmethodcallnode(pprocsym(ppropertysym(sym)^.readaccesssym^.sym),st,p1);
{ we know the procedure to call, so
force the usage of that procedure }
p1^.procdefinition:=pprocdef(ppropertysym(sym)^.readaccessdef);
{ insert paras }
p1^.left:=paras;
p1^.isproperty:=true;
end
else
begin
p1:=genzeronode(errorn);
Message(type_e_mismatch);
end;
end;
end
else
begin
{ error, no function to read property }
p1:=genzeronode(errorn);
Message(parser_e_no_procedure_to_access_property);
end;
end;
end;
{ the ID token has to be consumed before calling this function }
procedure do_member_read(getaddr : boolean;const sym : psym;var p1 : ptree;
var pd : pdef;var again : boolean);
var
static_name : string;
isclassref : boolean;
begin
if sym=nil then
begin
{ pattern is still valid unless
there is another ID just after the ID of sym }
Message1(sym_e_id_no_member,pattern);
disposetree(p1);
p1:=genzeronode(errorn);
{ try to clean up }
pd:=generrordef;
again:=false;
end
else
begin
isclassref:=pd^.deftype=classrefdef;
{ check protected and private members }
{ please leave this code as it is, }
{ it has now the same behaviaor as TP/Delphi }
if (sp_private in sym^.symoptions) and
(pobjectdef(pd)^.owner^.symtabletype=unitsymtable) then
Message(parser_e_cant_access_private_member);
if (sp_protected in sym^.symoptions) and
(pobjectdef(pd)^.owner^.symtabletype=unitsymtable) then
begin
if assigned(aktprocsym^.definition^._class) then
begin
if not aktprocsym^.definition^._class^.is_related(pobjectdef(sym^.owner^.defowner)) then
Message(parser_e_cant_access_protected_member);
end
else
Message(parser_e_cant_access_protected_member);
end;
{ we assume, that only procsyms and varsyms are in an object }
{ symbol table, for classes, properties are allowed }
case sym^.typ of
procsym:
begin
p1:=genmethodcallnode(pprocsym(sym),srsymtable,p1);
do_proc_call(getaddr or
(getprocvar and
((block_type=bt_const) or
((m_tp_procvar in aktmodeswitches) and
proc_to_procvar_equal(pprocsym(sym)^.definition,getprocvardef)
)
)
),again,p1,pd);
if (block_type=bt_const) and
getprocvar then
handle_procvar(getprocvardef,p1);
{ now we know the real method e.g. we can check for a class method }
if isclassref and
assigned(p1^.procdefinition) and
not(po_classmethod in p1^.procdefinition^.procoptions) and
not(p1^.procdefinition^.proctypeoption=potype_constructor) then
Message(parser_e_only_class_methods_via_class_ref);
end;
varsym:
begin
if isclassref then
Message(parser_e_only_class_methods_via_class_ref);
if (sp_static in sym^.symoptions) then
begin
{ static_name:=lower(srsymtable^.name^)+'_'+sym^.name;
this is wrong for static field in with symtable (PM) }
static_name:=lower(srsym^.owner^.name^)+'_'+sym^.name;
getsym(static_name,true);
disposetree(p1);
p1:=genloadnode(pvarsym(srsym),srsymtable);
end
else
p1:=gensubscriptnode(pvarsym(sym),p1);
pd:=pvarsym(sym)^.definition;
end;
propertysym:
begin
if isclassref then
Message(parser_e_only_class_methods_via_class_ref);
handle_propertysym(sym,srsymtable,p1,pd);
end;
else internalerror(16);
end;
end;
end;
{****************************************************************************
Factor
****************************************************************************}
function factor(getaddr : boolean) : ptree;
var
l : longint;
oldp1,
p1,p2,p3 : ptree;
code : integer;
pd,pd2 : pdef;
possible_error,
unit_specific,
again : boolean;
sym : pvarsym;
classh : pobjectdef;
d : bestreal;
static_name : string;
propsym : ppropertysym;
filepos : tfileposinfo;
{---------------------------------------------
Is_func_ret
---------------------------------------------}
function is_func_ret(sym : psym) : boolean;
var
p : pprocinfo;
storesymtablestack : psymtable;
begin
is_func_ret:=false;
if not assigned(procinfo) or
((sym^.typ<>funcretsym) and ((procinfo^.flags and pi_operator)=0)) then
exit;
p:=procinfo;
while assigned(p) do
begin
{ is this an access to a function result? Accessing _RESULT is
always allowed and funcretn is generated }
if assigned(p^.funcretsym) and
((pfuncretsym(sym)=p^.resultfuncretsym) or
((pfuncretsym(sym)=p^.funcretsym) or
((pvarsym(sym)=opsym) and ((p^.flags and pi_operator)<>0))) and
(p^.retdef<>pdef(voiddef)) and
(token<>_LKLAMMER) and
(not ((m_tp in aktmodeswitches) and (afterassignment or in_args)))
) then
begin
if ((pvarsym(sym)=opsym) and
((p^.flags and pi_operator)<>0)) then
inc(opsym^.refs);
if ((pvarsym(sym)=opsym) and
((p^.flags and pi_operator)<>0)) then
inc(opsym^.refs);
p1:=genzeronode(funcretn);
pd:=p^.retdef;
p1^.funcretprocinfo:=p;
p1^.retdef:=pd;
is_func_ret:=true;
exit;
end;
p:=p^.parent;
end;
{ we must use the function call }
if(sym^.typ=funcretsym) then
begin
storesymtablestack:=symtablestack;
symtablestack:=srsymtable^.next;
getsym(sym^.name,true);
if srsym^.typ<>procsym then
Message(cg_e_illegal_expression);
symtablestack:=storesymtablestack;
end;
end;
{---------------------------------------------
Factor_read_id
---------------------------------------------}
procedure factor_read_id;
var
pc : pchar;
len : longint;
begin
{ allow post fix operators }
again:=true;
begin
if lastsymknown then
begin
srsym:=lastsrsym;
srsymtable:=lastsrsymtable;
lastsymknown:=false;
end
else
getsym(pattern,true);
consume(_ID);
if not is_func_ret(srsym) then
{ else it's a normal symbol }
begin
{ is it defined like UNIT.SYMBOL ? }
if srsym^.typ=unitsym then
begin
consume(_POINT);
getsymonlyin(punitsym(srsym)^.unitsymtable,pattern);
unit_specific:=true;
consume(_ID);
end
else
unit_specific:=false;
if not assigned(srsym) then
Begin
p1:=genzeronode(errorn);
{ try to clean up }
pd:=generrordef;
end
else
Begin
{ check semantics of private }
if (srsym^.typ in [propertysym,procsym,varsym]) and
(srsymtable^.symtabletype=objectsymtable) then
begin
if (sp_private in srsym^.symoptions) and
(pobjectdef(srsym^.owner^.defowner)^.owner^.symtabletype=unitsymtable) then
Message(parser_e_cant_access_private_member);
end;
case srsym^.typ of
absolutesym : begin
p1:=genloadnode(pvarsym(srsym),srsymtable);
pd:=pabsolutesym(srsym)^.definition;
end;
varsym : begin
{ are we in a class method ? }
if (srsymtable^.symtabletype=objectsymtable) and
assigned(aktprocsym) and
(po_classmethod in aktprocsym^.definition^.procoptions) then
Message(parser_e_only_class_methods);
if (sp_static in srsym^.symoptions) then
begin
static_name:=lower(srsym^.owner^.name^)+'_'+srsym^.name;
getsym(static_name,true);
end;
p1:=genloadnode(pvarsym(srsym),srsymtable);
if pvarsym(srsym)^.varstate=vs_declared then
begin
p1^.is_first := true;
{ set special between first loaded until checked in firstpass }
pvarsym(srsym)^.varstate:=vs_declared2;
end;
pd:=pvarsym(srsym)^.definition;
end;
typedconstsym : begin
p1:=gentypedconstloadnode(ptypedconstsym(srsym),srsymtable);
pd:=ptypedconstsym(srsym)^.definition;
end;
syssym : p1:=statement_syssym(psyssym(srsym)^.number,pd);
typesym : begin
pd:=ptypesym(srsym)^.definition;
if not assigned(pd) then
begin
pd:=generrordef;
again:=false;
end
else
begin
{ if we read a type declaration }
{ we have to return the type and }
{ nothing else }
if block_type=bt_type then
begin
{ we don't need sym reference when it's in the
current unit or system unit, because those
units are always loaded (PFV) }
if (pd^.owner^.unitid=0) or
(pd^.owner^.unitid=1) then
p1:=gentypenode(pd,nil)
else
p1:=gentypenode(pd,ptypesym(srsym));
{ here we can also set resulttype !! }
p1^.resulttype:=pd;
pd:=voiddef;
end
else { not type block }
begin
if token=_LKLAMMER then
begin
consume(_LKLAMMER);
p1:=comp_expr(true);
consume(_RKLAMMER);
p1:=gentypeconvnode(p1,pd);
p1^.explizit:=true;
end
else { not LKLAMMER}
if (token=_POINT) and
(pd^.deftype=objectdef) and
not(pobjectdef(pd)^.is_class) then
begin
consume(_POINT);
if assigned(procinfo) and
assigned(procinfo^._class) and
not(getaddr) then
begin
if procinfo^._class^.is_related(pobjectdef(pd)) then
begin
p1:=gentypenode(pd,ptypesym(srsym));
p1^.resulttype:=pd;
{ search also in inherited methods }
repeat
srsymtable:=pobjectdef(pd)^.symtable;
sym:=pvarsym(srsymtable^.search(pattern));
if assigned(sym) then
break;
pd:=pobjectdef(pd)^.childof;
until not assigned(pd);
consume(_ID);
do_member_read(false,sym,p1,pd,again);
end
else
begin
Message(parser_e_no_super_class);
pd:=generrordef;
again:=false;
end;
end
else
begin
{ allows @TObject.Load }
{ also allows static methods and variables }
p1:=genzeronode(typen);
p1^.resulttype:=pd;
{ TP allows also @TMenu.Load if Load is only }
{ defined in an anchestor class }
sym:=pvarsym(search_class_member(pobjectdef(pd),pattern));
if not assigned(sym) then
Message1(sym_e_id_no_member,pattern)
else if not(getaddr) and not(sp_static in sym^.symoptions) then
Message(sym_e_only_static_in_static)
else
begin
consume(_ID);
do_member_read(getaddr,sym,p1,pd,again);
end;
end;
end
else
begin
{ class reference ? }
if (pd^.deftype=objectdef)
and pobjectdef(pd)^.is_class then
begin
p1:=gentypenode(pd,nil);
p1^.resulttype:=pd;
pd:=new(pclassrefdef,init(pd));
p1:=gensinglenode(loadvmtn,p1);
p1^.resulttype:=pd;
end
else
begin
{ generate a type node }
{ (for typeof etc) }
if allow_type then
begin
p1:=gentypenode(pd,nil);
{ here we must use typenodetype explicitly !! PM
p1^.resulttype:=pd; }
pd:=voiddef;
end
else
Message(parser_e_no_type_not_allowed_here);
end;
end;
end;
end;
end;
enumsym : begin
p1:=genenumnode(penumsym(srsym));
pd:=p1^.resulttype;
end;
constsym : begin
case pconstsym(srsym)^.consttype of
constint :
p1:=genordinalconstnode(pconstsym(srsym)^.value,s32bitdef);
conststring :
begin
len:=pconstsym(srsym)^.len;
if not(cs_ansistrings in aktlocalswitches) and (len>255) then
len:=255;
getmem(pc,len+1);
move(pchar(pconstsym(srsym)^.value)^,pc^,len);
pc[len]:=#0;
p1:=genpcharconstnode(pc,len);
end;
constchar :
p1:=genordinalconstnode(pconstsym(srsym)^.value,cchardef);
constreal :
p1:=genrealconstnode(pbestreal(pconstsym(srsym)^.value)^,bestrealdef^);
constbool :
p1:=genordinalconstnode(pconstsym(srsym)^.value,booldef);
constset :
p1:=gensetconstnode(pconstset(pconstsym(srsym)^.value),
psetdef(pconstsym(srsym)^.definition));
constord :
p1:=genordinalconstnode(pconstsym(srsym)^.value,
pconstsym(srsym)^.definition);
constpointer :
p1:=genpointerconstnode(pconstsym(srsym)^.value,
pconstsym(srsym)^.definition);
constnil :
p1:=genzeronode(niln);
constresourcestring:
begin
p1:=genloadnode(pvarsym(srsym),srsymtable);
p1^.resulttype:=cansistringdef;
end;
end;
pd:=p1^.resulttype;
end;
procsym : begin
{ are we in a class method ? }
possible_error:=(srsymtable^.symtabletype=objectsymtable) and
assigned(aktprocsym) and
(po_classmethod in aktprocsym^.definition^.procoptions);
p1:=gencallnode(pprocsym(srsym),srsymtable);
p1^.unit_specific:=unit_specific;
do_proc_call(getaddr or
(getprocvar and
((block_type=bt_const) or
((m_tp_procvar in aktmodeswitches) and
proc_to_procvar_equal(pprocsym(srsym)^.definition,getprocvardef)
)
)
),again,p1,pd);
if (block_type=bt_const) and
getprocvar then
handle_procvar(getprocvardef,p1);
if possible_error and
not(po_classmethod in p1^.procdefinition^.procoptions) then
Message(parser_e_only_class_methods);
end;
propertysym : begin
{ access to property in a method }
{ are we in a class method ? }
if (srsymtable^.symtabletype=objectsymtable) and
assigned(aktprocsym) and
(po_classmethod in aktprocsym^.definition^.procoptions) then
Message(parser_e_only_class_methods);
{ no method pointer }
p1:=nil;
handle_propertysym(srsym,srsymtable,p1,pd);
end;
errorsym : begin
p1:=genzeronode(errorn);
p1^.resulttype:=generrordef;
pd:=generrordef;
if token=_LKLAMMER then
begin
consume(_LKLAMMER);
parse_paras(false,false);
consume(_RKLAMMER);
end;
end;
else
begin
p1:=genzeronode(errorn);
pd:=generrordef;
Message(cg_e_illegal_expression);
end;
end; { end case }
end;
end;
end;
end;
{---------------------------------------------
Factor_Read_Set
---------------------------------------------}
{ Read a set between [] }
function factor_read_set:ptree;
var
p1,
lastp,
buildp : ptree;
begin
buildp:=nil;
{ be sure that a least one arrayconstructn is used, also for an
empty [] }
if token=_RECKKLAMMER then
buildp:=gennode(arrayconstructn,nil,buildp)
else
begin
while true do
begin
p1:=comp_expr(true);
if token=_POINTPOINT then
begin
consume(_POINTPOINT);
p2:=comp_expr(true);
p1:=gennode(arrayconstructrangen,p1,p2);
end;
{ insert at the end of the tree, to get the correct order }
if not assigned(buildp) then
begin
buildp:=gennode(arrayconstructn,p1,nil);
lastp:=buildp;
end
else
begin
lastp^.right:=gennode(arrayconstructn,p1,nil);
lastp:=lastp^.right;
end;
{ there could be more elements }
if token=_COMMA then
consume(_COMMA)
else
break;
end;
end;
factor_read_set:=buildp;
end;
{---------------------------------------------
Helpers
---------------------------------------------}
procedure check_tokenpos;
begin
if (p1<>oldp1) then
begin
if assigned(p1) then
set_tree_filepos(p1,filepos);
oldp1:=p1;
filepos:=tokenpos;
end;
end;
{---------------------------------------------
PostFixOperators
---------------------------------------------}
procedure postfixoperators;
var
store_static : boolean;
{ p1 and p2 must contain valid value_str }
begin
check_tokenpos;
while again do
begin
{ prevent crashes with unknown types }
if not assigned(pd) then
begin
{ try to recover }
repeat
case token of
_CARET:
consume(_CARET);
_POINT:
begin
consume(_POINT);
consume(_ID);
end;
_LECKKLAMMER:
begin
repeat
consume(token);
until token in [_RECKKLAMMER,_SEMICOLON];
end;
else
break;
end;
until false;
exit;
end;
{ handle token }
case token of
_CARET:
begin
consume(_CARET);
if (pd^.deftype<>pointerdef) then
begin
{ ^ as binary operator is a problem!!!! (FK) }
again:=false;
Message(cg_e_invalid_qualifier);
disposetree(p1);
p1:=genzeronode(errorn);
end
else
begin
p1:=gensinglenode(derefn,p1);
pd:=ppointerdef(pd)^.definition;
end;
end;
_LECKKLAMMER:
begin
if (pd^.deftype=objectdef) and pobjectdef(pd)^.is_class then
begin
{ default property }
propsym:=search_default_property(pobjectdef(pd));
if not(assigned(propsym)) then
begin
disposetree(p1);
p1:=genzeronode(errorn);
again:=false;
message(parser_e_no_default_property_available);
end
else
handle_propertysym(propsym,propsym^.owner,p1,pd);
end
else
begin
consume(_LECKKLAMMER);
repeat
case pd^.deftype of
pointerdef:
begin
p2:=comp_expr(true);
p1:=gennode(vecn,p1,p2);
pd:=ppointerdef(pd)^.definition;
end;
stringdef : begin
p2:=comp_expr(true);
p1:=gennode(vecn,p1,p2);
pd:=cchardef
end;
arraydef : begin
p2:=comp_expr(true);
{ support SEG:OFS for go32v2 Mem[] }
if (target_info.target=target_i386_go32v2) and
(p1^.treetype=loadn) and
assigned(p1^.symtableentry) and
assigned(p1^.symtableentry^.owner^.name) and
(p1^.symtableentry^.owner^.name^='SYSTEM') and
((p1^.symtableentry^.name='MEM') or
(p1^.symtableentry^.name='MEMW') or
(p1^.symtableentry^.name='MEML')) then
begin
if (token=_COLON) then
begin
consume(_COLON);
p3:=gennode(muln,genordinalconstnode($10,s32bitdef),p2);
p2:=comp_expr(true);
p2:=gennode(addn,p2,p3);
p1:=gennode(vecn,p1,p2);
p1^.memseg:=true;
p1^.memindex:=true;
end
else
begin
p1:=gennode(vecn,p1,p2);
p1^.memindex:=true;
end;
end
else
p1:=gennode(vecn,p1,p2);
pd:=parraydef(pd)^.definition;
end;
else
begin
Message(cg_e_invalid_qualifier);
disposetree(p1);
p1:=genzeronode(errorn);
again:=false;
end;
end;
if token=_COMMA then
consume(_COMMA)
else
break;
until false;
consume(_RECKKLAMMER);
end;
end;
_POINT : begin
consume(_POINT);
if (pd^.deftype=pointerdef) and
(m_autoderef in aktmodeswitches) then
begin
p1:=gensinglenode(derefn,p1);
pd:=ppointerdef(pd)^.definition;
end;
case pd^.deftype of
recorddef:
begin
sym:=pvarsym(precorddef(pd)^.symtable^.search(pattern));
if sym=nil then
begin
Message1(sym_e_illegal_field,pattern);
disposetree(p1);
p1:=genzeronode(errorn);
end
else
begin
p1:=gensubscriptnode(sym,p1);
pd:=sym^.definition;
end;
consume(_ID);
end;
classrefdef:
begin
classh:=pobjectdef(pclassrefdef(pd)^.definition);
sym:=nil;
while assigned(classh) do
begin
sym:=pvarsym(classh^.symtable^.search(pattern));
srsymtable:=classh^.symtable;
if assigned(sym) then
break;
classh:=classh^.childof;
end;
consume(_ID);
do_member_read(getaddr,sym,p1,pd,again);
end;
objectdef:
begin
classh:=pobjectdef(pd);
sym:=nil;
store_static:=allow_only_static;
allow_only_static:=false;
while assigned(classh) do
begin
sym:=pvarsym(classh^.symtable^.search(pattern));
srsymtable:=classh^.symtable;
if assigned(sym) then
break;
classh:=classh^.childof;
end;
allow_only_static:=store_static;
consume(_ID);
do_member_read(getaddr,sym,p1,pd,again);
end;
pointerdef:
begin
Message(cg_e_invalid_qualifier);
if ppointerdef(pd)^.definition^.deftype in [recorddef,objectdef,classrefdef] then
Message(parser_h_maybe_deref_caret_missing);
end;
else
begin
Message(cg_e_invalid_qualifier);
disposetree(p1);
p1:=genzeronode(errorn);
end;
end;
end;
else
begin
{ is this a procedure variable ? }
if assigned(pd) then
begin
if (pd^.deftype=procvardef) then
begin
if getprocvar and is_equal(pd,getprocvardef) then
again:=false
else
if (token=_LKLAMMER) or
((pprocvardef(pd)^.para^.empty) and
(not((token in [_ASSIGNMENT,_UNEQUAL,_EQUAL]))) and
(not afterassignment) and
(not in_args)) then
begin
{ do this in a strange way }
{ it's not a clean solution }
p2:=p1;
p1:=gencallnode(nil,nil);
p1^.right:=p2;
p1^.unit_specific:=unit_specific;
p1^.symtableprocentry:=pprocsym(sym);
if token=_LKLAMMER then
begin
consume(_LKLAMMER);
p1^.left:=parse_paras(false,false);
consume(_RKLAMMER);
end;
pd:=pprocvardef(pd)^.retdef;
{ proc():= is never possible }
if token=_ASSIGNMENT then
begin
Message(cg_e_illegal_expression);
p1:=genzeronode(errorn);
again:=false;
end;
p1^.resulttype:=pd;
end
else
again:=false;
p1^.resulttype:=pd;
end
else
again:=false;
end
else
again:=false;
end;
end;
check_tokenpos;
end; { while again }
end;
{---------------------------------------------
Factor (Main)
---------------------------------------------}
begin
oldp1:=nil;
p1:=nil;
filepos:=tokenpos;
if token=_ID then
begin
factor_read_id;
{ handle post fix operators }
postfixoperators;
end
else
case token of
_NEW : begin
consume(_NEW);
consume(_LKLAMMER);
{allow_type:=true;}
p1:=factor(false);
{allow_type:=false;}
if p1^.treetype<>typen then
begin
Message(type_e_type_id_expected);
disposetree(p1);
pd:=generrordef;
end
else
pd:=p1^.typenodetype;
pd2:=pd;
if (pd^.deftype<>pointerdef) then
Message1(type_e_pointer_type_expected,pd^.typename)
else if {(ppointerdef(pd)^.definition^.deftype<>objectdef)}
token=_RKLAMMER then
begin
if (ppointerdef(pd)^.definition^.deftype=objectdef) and
(oo_has_vmt in pobjectdef(ppointerdef(pd)^.definition)^.objectoptions) then
Message(parser_w_use_extended_syntax_for_objects);
p1:=gensinglenode(newn,nil);
p1^.resulttype:=pd2;
consume(_RKLAMMER);
(*Message(parser_e_pointer_to_class_expected);
{ if an error occurs, read til the end of
the new statement }
p1:=genzeronode(errorn);
l:=1;
while true do
begin
case token of
_LKLAMMER : inc(l);
_RKLAMMER : dec(l);
end;
consume(token);
if l=0 then
break;
end;*)
end
else
begin
disposetree(p1);
p1:=genzeronode(hnewn);
p1^.resulttype:=ppointerdef(pd)^.definition;
consume(_COMMA);
afterassignment:=false;
{ determines the current object defintion }
classh:=pobjectdef(ppointerdef(pd)^.definition);
{ check for an abstract class }
if (oo_has_abstract in classh^.objectoptions) then
Message(sym_e_no_instance_of_abstract_object);
{ search the constructor also in the symbol tables of
the parents }
{ no constructor found }
sym:=nil;
while assigned(classh) do
begin
sym:=pvarsym(classh^.symtable^.search(pattern));
srsymtable:=classh^.symtable;
if assigned(sym) then
break;
classh:=classh^.childof;
end;
consume(_ID);
do_member_read(false,sym,p1,pd,again);
if (p1^.treetype<>calln) or
(assigned(p1^.procdefinition) and
(p1^.procdefinition^.proctypeoption<>potype_constructor)) then
Message(parser_e_expr_have_to_be_constructor_call);
p1:=gensinglenode(newn,p1);
{ set the resulttype }
p1^.resulttype:=pd2;
consume(_RKLAMMER);
end;
postfixoperators;
end;
_SELF : begin
again:=true;
consume(_SELF);
if not assigned(procinfo^._class) then
begin
p1:=genzeronode(errorn);
pd:=generrordef;
again:=false;
Message(parser_e_self_not_in_method);
end
else
begin
if (po_classmethod in aktprocsym^.definition^.procoptions) then
begin
{ self in class methods is a class reference type }
pd:=new(pclassrefdef,init(procinfo^._class));
p1:=genselfnode(pd);
p1^.resulttype:=pd;
end
else
begin
p1:=genselfnode(procinfo^._class);
p1^.resulttype:=procinfo^._class;
end;
pd:=p1^.resulttype;
postfixoperators;
end;
end;
_INHERITED : begin
again:=true;
consume(_INHERITED);
if assigned(procinfo^._class) then
begin
classh:=procinfo^._class^.childof;
while assigned(classh) do
begin
srsymtable:=pobjectdef(classh)^.symtable;
sym:=pvarsym(srsymtable^.search(pattern));
if assigned(sym) then
begin
p1:=genzeronode(typen);
p1^.resulttype:=classh;
pd:=p1^.resulttype;
consume(_ID);
do_member_read(false,sym,p1,pd,again);
break;
end;
classh:=classh^.childof;
end;
if classh=nil then
begin
Message1(sym_e_id_no_member,pattern);
again:=false;
pd:=generrordef;
p1:=genzeronode(errorn);
end;
end
else
begin
Message(parser_e_generic_methods_only_in_methods);
again:=false;
pd:=generrordef;
p1:=genzeronode(errorn);
end;
postfixoperators;
end;
_INTCONST : begin
valint(pattern,l,code);
if code<>0 then
begin
val(pattern,d,code);
if code<>0 then
begin
Message(cg_e_invalid_integer);
consume(_INTCONST);
l:=1;
p1:=genordinalconstnode(l,s32bitdef);
end
else
begin
consume(_INTCONST);
p1:=genrealconstnode(d,bestrealdef^);
end;
end
else
begin
consume(_INTCONST);
p1:=genordinalconstnode(l,s32bitdef);
end;
end;
_REALNUMBER : begin
val(pattern,d,code);
if code<>0 then
begin
Message(parser_e_error_in_real);
d:=1.0;
end;
consume(_REALNUMBER);
p1:=genrealconstnode(d,bestrealdef^);
end;
_STRING : begin
pd:=string_dec;
{ STRING can be also a type cast }
if token=_LKLAMMER then
begin
consume(_LKLAMMER);
p1:=comp_expr(true);
consume(_RKLAMMER);
p1:=gentypeconvnode(p1,pd);
p1^.explizit:=true;
{ handle postfix operators here e.g. string(a)[10] }
again:=true;
postfixoperators;
end
else
p1:=gentypenode(pd,nil);
end;
_FILE : begin
pd:=cfiledef;
consume(_FILE);
{ FILE can be also a type cast }
if token=_LKLAMMER then
begin
consume(_LKLAMMER);
p1:=comp_expr(true);
consume(_RKLAMMER);
p1:=gentypeconvnode(p1,pd);
p1^.explizit:=true;
{ handle postfix operators here e.g. string(a)[10] }
again:=true;
postfixoperators;
end
else
p1:=gentypenode(pd,nil);
end;
_CSTRING : begin
p1:=genstringconstnode(pattern);
consume(_CSTRING);
end;
_CCHAR : begin
p1:=genordinalconstnode(ord(pattern[1]),cchardef);
consume(_CCHAR);
end;
_KLAMMERAFFE : begin
consume(_KLAMMERAFFE);
got_addrn:=true;
{ support both @<x> and @(<x>) }
if token=_LKLAMMER then
begin
consume(_LKLAMMER);
p1:=factor(true);
consume(_RKLAMMER);
if token in [_CARET,_POINT,_LECKKLAMMER] then
begin
{ we need the resulttype }
{ of the expression in pd }
do_firstpass(p1);
pd:=p1^.resulttype;
again:=true;
postfixoperators;
end;
end
else
p1:=factor(true);
got_addrn:=false;
p1:=gensinglenode(addrn,p1);
end;
_LKLAMMER : begin
consume(_LKLAMMER);
p1:=comp_expr(true);
consume(_RKLAMMER);
{ it's not a good solution }
{ but (a+b)^ makes some problems }
if token in [_CARET,_POINT,_LECKKLAMMER] then
begin
{ we need the resulttype }
{ of the expression in pd }
do_firstpass(p1);
pd:=p1^.resulttype;
again:=true;
postfixoperators;
end;
end;
_LECKKLAMMER : begin
consume(_LECKKLAMMER);
p1:=factor_read_set;
consume(_RECKKLAMMER);
end;
_PLUS : begin
consume(_PLUS);
p1:=factor(false);
end;
_MINUS : begin
consume(_MINUS);
p1:=factor(false);
p1:=gensinglenode(umminusn,p1);
end;
_NOT : begin
consume(_NOT);
p1:=factor(false);
p1:=gensinglenode(notn,p1);
end;
_TRUE : begin
consume(_TRUE);
p1:=genordinalconstnode(1,booldef);
end;
_FALSE : begin
consume(_FALSE);
p1:=genordinalconstnode(0,booldef);
end;
_NIL : begin
consume(_NIL);
p1:=genzeronode(niln);
end;
else
begin
p1:=genzeronode(errorn);
consume(token);
Message(cg_e_illegal_expression);
end;
end;
{ generate error node if no node is created }
if not assigned(p1) then
p1:=genzeronode(errorn);
{ tp7 procvar handling, but not if the next token
will be a := }
if (m_tp_procvar in aktmodeswitches) and
(token<>_ASSIGNMENT) then
check_tp_procvar(p1);
factor:=p1;
check_tokenpos;
end;
{****************************************************************************
Sub_Expr
****************************************************************************}
type
Toperator_precedence=(opcompare,opaddition,opmultiply);
Ttok2nodeRec=record
tok : ttoken;
nod : ttreetyp;
end;
const
tok2nodes=23;
tok2node:array[1..tok2nodes] of ttok2noderec=(
(tok:_PLUS ;nod:addn),
(tok:_MINUS ;nod:subn),
(tok:_STAR ;nod:muln),
(tok:_SLASH ;nod:slashn),
(tok:_EQUAL ;nod:equaln),
(tok:_GT ;nod:gtn),
(tok:_LT ;nod:ltn),
(tok:_GTE ;nod:gten),
(tok:_LTE ;nod:lten),
(tok:_SYMDIF ;nod:symdifn),
(tok:_STARSTAR;nod:starstarn),
(tok:_CARET ;nod:caretn),
(tok:_UNEQUAL ;nod:unequaln),
(tok:_AS ;nod:asn),
(tok:_IN ;nod:inn),
(tok:_IS ;nod:isn),
(tok:_OR ;nod:orn),
(tok:_AND ;nod:andn),
(tok:_DIV ;nod:divn),
(tok:_MOD ;nod:modn),
(tok:_SHL ;nod:shln),
(tok:_SHR ;nod:shrn),
(tok:_XOR ;nod:xorn)
);
operator_levels:array[Toperator_precedence] of set of Ttoken=
([_LT,_LTE,_GT,_GTE,_EQUAL,_UNEQUAL,_IN,_IS],
[_PLUS,_MINUS,_OR,_XOR],
[_CARET,_SYMDIF,_STARSTAR,_STAR,_SLASH,_DIV,_MOD,_AND,_SHL,_SHR,_AS]);
function sub_expr(pred_level:Toperator_precedence;accept_equal : boolean):Ptree;
{Reads a subexpression while the operators are of the current precedence
level, or any higher level. Replaces the old term, simpl_expr and
simpl2_expr.}
var
low,high,mid : longint;
p1,p2 : Ptree;
oldt : Ttoken;
filepos : tfileposinfo;
begin
if pred_level=opmultiply then
p1:=factor(false)
else
p1:=sub_expr(succ(pred_level),true);
repeat
if (token in operator_levels[pred_level]) and
((token<>_EQUAL) or accept_equal) then
begin
oldt:=token;
filepos:=tokenpos;
consume(token);
if pred_level=opmultiply then
p2:=factor(false)
else
p2:=sub_expr(succ(pred_level),true);
low:=1;
high:=tok2nodes;
while (low<high) do
begin
mid:=(low+high+1) shr 1;
if oldt<tok2node[mid].tok then
high:=mid-1
else
low:=mid;
end;
if tok2node[high].tok=oldt then
p1:=gennode(tok2node[high].nod,p1,p2)
else
p1:=gennode(nothingn,p1,p2);
set_tree_filepos(p1,filepos);
end
else
break;
until false;
sub_expr:=p1;
end;
function comp_expr(accept_equal : boolean):Ptree;
var
oldafterassignment : boolean;
p1 : ptree;
begin
oldafterassignment:=afterassignment;
afterassignment:=true;
p1:=sub_expr(opcompare,accept_equal);
afterassignment:=oldafterassignment;
comp_expr:=p1;
end;
function expr : ptree;
var
p1,p2 : ptree;
oldafterassignment : boolean;
oldp1 : ptree;
filepos : tfileposinfo;
begin
oldafterassignment:=afterassignment;
p1:=sub_expr(opcompare,true);
filepos:=tokenpos;
if (m_tp_procvar in aktmodeswitches) and
(token<>_ASSIGNMENT) then
check_tp_procvar(p1);
if token in [_ASSIGNMENT,_PLUSASN,_MINUSASN,_STARASN,_SLASHASN] then
afterassignment:=true;
oldp1:=p1;
case token of
_POINTPOINT : begin
consume(_POINTPOINT);
p2:=sub_expr(opcompare,true);
p1:=gennode(rangen,p1,p2);
end;
_ASSIGNMENT : begin
consume(_ASSIGNMENT);
{ avoid a firstpass of a procedure if
it must be assigned to a procvar }
{ should be recursive for a:=b:=c !!! }
if (p1^.resulttype<>nil) and (p1^.resulttype^.deftype=procvardef) then
begin
getprocvar:=true;
getprocvardef:=pprocvardef(p1^.resulttype);
end;
p2:=sub_expr(opcompare,true);
if getprocvar then
handle_procvar(getprocvardef,p2);
getprocvar:=false;
p1:=gennode(assignn,p1,p2);
end;
{ this is the code for C like assignements }
{ from an improvement of Peter Schaefer }
_PLUSASN : begin
consume(_PLUSASN );
p2:=sub_expr(opcompare,true);
p1:=gennode(assignn,p1,gennode(addn,getcopy(p1),p2));
{ was first
p1:=gennode(assignn,p1,gennode(addn,p1,p2));
but disposetree assumes that we have a real
*** tree *** }
end;
_MINUSASN : begin
consume(_MINUSASN );
p2:=sub_expr(opcompare,true);
p1:=gennode(assignn,p1,gennode(subn,getcopy(p1),p2));
end;
_STARASN : begin
consume(_STARASN );
p2:=sub_expr(opcompare,true);
p1:=gennode(assignn,p1,gennode(muln,getcopy(p1),p2));
end;
_SLASHASN : begin
consume(_SLASHASN );
p2:=sub_expr(opcompare,true);
p1:=gennode(assignn,p1,gennode(slashn,getcopy(p1),p2));
end;
end;
afterassignment:=oldafterassignment;
if p1<>oldp1 then
set_tree_filepos(p1,filepos);
expr:=p1;
end;
function get_intconst:longint;
{Reads an expression, tries to evalute it and check if it is an integer
constant. Then the constant is returned.}
var
p:Ptree;
begin
p:=comp_expr(true);
do_firstpass(p);
if not codegenerror then
begin
if (p^.treetype<>ordconstn) and
(p^.resulttype^.deftype=orddef) and
not(Porddef(p^.resulttype)^.typ in [uvoid,uchar,bool8bit,bool16bit,bool32bit]) then
Message(cg_e_illegal_expression)
else
get_intconst:=p^.value;
end;
disposetree(p);
end;
function get_stringconst:string;
{Reads an expression, tries to evaluate it and checks if it is a string
constant. Then the constant is returned.}
var
p:Ptree;
begin
get_stringconst:='';
p:=comp_expr(true);
do_firstpass(p);
if p^.treetype<>stringconstn then
begin
if (p^.treetype=ordconstn) and is_char(p^.resulttype) then
get_stringconst:=char(p^.value)
else
Message(cg_e_illegal_expression);
end
else
get_stringconst:=strpas(p^.value_str);
disposetree(p);
end;
end.
{
$Log$
Revision 1.151 1999-10-26 12:30:44 peter
* const parameter is now checked
* better and generic check if a node can be used for assigning
* export fixes
* procvar equal works now (it never had worked at least from 0.99.8)
* defcoll changed to linkedlist with pparaitem so it can easily be
walked both directions
Revision 1.150 1999/10/22 14:37:30 peter
* error when properties are passed to var parameters
Revision 1.149 1999/10/22 10:39:34 peter
* split type reading from pdecl to ptype unit
* parameter_dec routine is now used for procedure and procvars
Revision 1.148 1999/10/14 14:57:52 florian
- removed the hcodegen use in the new cg, use cgbase instead
Revision 1.147 1999/09/28 11:03:54 peter
* fixed result access in 'if result = XXX then'
* fixed const cr=chr(13)
Revision 1.146 1999/09/27 23:44:54 peter
* procinfo is now a pointer
* support for result setting in sub procedure
Revision 1.145 1999/09/27 11:59:42 peter
* fix for pointer reading in const with @type.method
Revision 1.144 1999/09/26 21:30:19 peter
+ constant pointer support which can happend with typecasting like
const p=pointer(1)
* better procvar parsing in typed consts
Revision 1.143 1999/09/15 20:35:41 florian
* small fix to operator overloading when in MMX mode
+ the compiler uses now fldz and fld1 if possible
+ some fixes to floating point registers
+ some math. functions (arctan, ln, sin, cos, sqrt, sqr, pi) are now inlined
* .... ???
Revision 1.142 1999/09/13 16:26:32 peter
* fix crash with empty object as childs
Revision 1.141 1999/09/11 19:47:26 florian
* bug fix for @tobject.method, fixes bug 557, 605 and 606
Revision 1.140 1999/09/11 09:08:33 florian
* fixed bug 596
* fixed some problems with procedure variables and procedures of object,
especially in TP mode. Procedure of object doesn't apply only to classes,
it is also allowed for objects !!
Revision 1.139 1999/09/10 18:48:07 florian
* some bug fixes (e.g. must_be_valid and procinfo^.funcret_is_valid)
* most things for stored properties fixed
Revision 1.138 1999/09/07 08:01:20 peter
* @(<x>) support
Revision 1.137 1999/09/01 22:08:58 peter
* fixed crash with assigned()
Revision 1.136 1999/08/15 22:47:45 peter
* fixed property writeaccess which was buggy after my previous
subscribed property access
Revision 1.135 1999/08/14 00:38:56 peter
* hack to support property with record fields
Revision 1.134 1999/08/09 22:16:29 peter
* fixed crash after wrong para's with class contrustor
Revision 1.133 1999/08/05 16:53:04 peter
* V_Fatal=1, all other V_ are also increased
* Check for local procedure when assigning procvar
* fixed comment parsing because directives
* oldtp mode directives better supported
* added some messages to errore.msg
Revision 1.132 1999/08/04 13:49:45 florian
* new(...)^. is now allowed
Revision 1.131 1999/08/04 13:02:55 jonas
* all tokens now start with an underscore
* PowerPC compiles!!
Revision 1.130 1999/08/04 00:23:12 florian
* renamed i386asm and i386base to cpuasm and cpubase
Revision 1.129 1999/08/03 22:02:59 peter
* moved bitmask constants to sets
* some other type/const renamings
Revision 1.128 1999/08/03 13:50:17 michael
+ Changes for alpha
Revision 1.127 1999/08/01 18:28:13 florian
* modifications for the new code generator
Revision 1.126 1999/07/30 12:28:40 peter
* fixed crash with unknown id and colon parameter in write
Revision 1.125 1999/07/27 23:42:14 peter
* indirect type referencing is now allowed
Revision 1.124 1999/07/23 21:31:42 peter
* fixed crash with resourcestring
Revision 1.123 1999/07/23 11:37:46 peter
* error for illegal type reference, instead of 10998
Revision 1.122 1999/07/22 09:37:52 florian
+ resourcestring implemented
+ start of longstring support
Revision 1.121 1999/07/16 10:04:35 peter
* merged
Revision 1.120 1999/07/06 22:38:11 florian
* another fix for TP/Delphi styled procedure variables
Revision 1.119 1999/07/05 20:13:16 peter
* removed temp defines
Revision 1.118 1999/07/01 21:33:57 peter
* merged
Revision 1.117 1999/06/30 15:43:20 florian
* two bugs regarding method variables fixed
- if you take in a method the address of another method
don't need self anymore
- if the class pointer was in a register, wrong code for a method
variable load was generated
Revision 1.116 1999/06/26 00:24:53 pierre
* mereg from fixes-0_99_12 branch
Revision 1.112.2.8 1999/07/16 09:54:57 peter
* @procvar support in tp7 mode works again
Revision 1.112.2.7 1999/07/07 07:53:10 michael
+ Merged patches from florian
Revision 1.112.2.6 1999/07/01 21:31:59 peter
* procvar fixes again
Revision 1.112.2.5 1999/07/01 15:17:17 peter
* methoidpointer fixes from florian
Revision 1.112.2.4 1999/06/26 00:22:30 pierre
* wrong warnings in -So mode suppressed
Revision 1.112.2.3 1999/06/17 12:51:44 pierre
* changed is_assignment_overloaded into
function assignment_overloaded : pprocdef
to allow overloading of assignment with only different result type
Revision 1.112.2.2 1999/06/15 18:54:52 peter
* more procvar fixes
Revision 1.112.2.1 1999/06/13 22:38:09 peter
* tp_procvar check for loading of procvars when getaddr=false
Revision 1.112 1999/06/02 22:44:11 pierre
* previous wrong log corrected
Revision 1.111 1999/06/02 22:25:43 pierre
* changed $ifdef FPC @ into $ifndef TP
* changes for correct procvar handling under tp mode
Revision 1.110 1999/06/01 19:27:55 peter
* better checks for procvar and methodpointer
Revision 1.109 1999/05/27 19:44:46 peter
* removed oldasm
* plabel -> pasmlabel
* -a switches to source writing automaticly
* assembler readers OOPed
* asmsymbol automaticly external
* jumptables and other label fixes for asm readers
Revision 1.108 1999/05/18 14:15:54 peter
* containsself fixes
* checktypes()
Revision 1.107 1999/05/18 09:52:18 peter
* procedure of object and addrn fixes
Revision 1.106 1999/05/16 17:06:31 peter
* remove firstcallparan which looks obsolete
Revision 1.105 1999/05/12 22:36:09 florian
* override isn't allowed in objects!
Revision 1.104 1999/05/07 10:35:23 florian
* first fix for a problem with method pointer properties, still doesn't work
with WITH
Revision 1.103 1999/05/06 21:40:16 peter
* fixed crash
Revision 1.101 1999/05/06 09:05:21 peter
* generic write_float and str_float
* fixed constant float conversions
Revision 1.100 1999/05/04 21:44:57 florian
* changes to compile it with Delphi 4.0
Revision 1.99 1999/05/01 13:24:31 peter
* merged nasm compiler
* old asm moved to oldasm/
Revision 1.98 1999/04/26 18:29:56 peter
* farpointerdef moved into pointerdef.is_far
Revision 1.97 1999/04/19 09:27:48 peter
* removed my property fix
Revision 1.96 1999/04/19 09:13:47 peter
* class property without write support
Revision 1.95 1999/04/19 06:10:08 florian
* property problem fixed: a propertysym is only a write
access if it is followed by a assignment token
Revision 1.94 1999/04/17 13:12:17 peter
* addr() internal
Revision 1.93 1999/04/15 09:00:08 peter
* fixed property write
Revision 1.92 1999/04/08 20:59:43 florian
* fixed problem with default properties which are a class
* case bug (from the mailing list with -O2) fixed, the
distance of the case labels can be greater than the positive
range of a longint => it is now a dword for fpc
Revision 1.91 1999/04/06 11:21:56 peter
* more use of ttoken
Revision 1.90 1999/03/31 13:55:12 peter
* assembler inlining working for ag386bin
Revision 1.89 1999/03/26 00:05:36 peter
* released valintern
+ deffile is now removed when compiling is finished
* ^( compiles now correct
+ static directive
* shrd fixed
Revision 1.88 1999/03/24 23:17:15 peter
* fixed bugs 212,222,225,227,229,231,233
Revision 1.87 1999/03/16 17:52:52 jonas
* changes for internal Val code (do a "make cycle OPT=-dvalintern" to test)
* in cgi386inl: also range checking for subrange types (compile with "-dreadrangecheck")
* in cgai386: also small fixes to emitrangecheck
Revision 1.86 1999/03/04 13:55:44 pierre
* some m68k fixes (still not compilable !)
* new(tobj) does not give warning if tobj has no VMT !
Revision 1.85 1999/02/22 15:09:39 florian
* behaviaor of PROTECTED and PRIVATE fixed, works now like TP/Delphi
Revision 1.84 1999/02/22 02:15:26 peter
* updates for ag386bin
Revision 1.83 1999/02/11 09:46:25 pierre
* fix for normal method calls inside static methods :
WARNING there were both parser and codegen errors !!
added static_call boolean to calln tree
Revision 1.82 1999/01/28 14:06:47 florian
* small fix for method pointers
* found the annoying strpas bug, mainly nested call to type cast which
use ansistrings crash
Revision 1.81 1999/01/27 00:13:55 florian
* "procedure of object"-stuff fixed
Revision 1.80 1999/01/21 16:41:01 pierre
* fix for constructor inside with statements
Revision 1.79 1998/12/30 22:15:48 peter
+ farpointer type
* absolutesym now also stores if its far
Revision 1.78 1998/12/11 00:03:32 peter
+ globtype,tokens,version unit splitted from globals
Revision 1.77 1998/12/04 10:18:09 florian
* some stuff for procedures of object added
* bug with overridden virtual constructors fixed (reported by Italo Gomes)
Revision 1.76 1998/11/27 14:50:40 peter
+ open strings, $P switch support
Revision 1.75 1998/11/25 19:12:51 pierre
* var:=new(pointer_type) support added
Revision 1.74 1998/11/13 10:18:11 peter
+ nil constants
Revision 1.73 1998/11/05 12:02:52 peter
* released useansistring
* removed -Sv, its now available in fpc modes
Revision 1.72 1998/11/04 10:11:41 peter
* ansistring fixes
Revision 1.71 1998/10/22 23:57:29 peter
* fixed filedef for typenodetype
Revision 1.70 1998/10/21 15:12:54 pierre
* bug fix for IOCHECK inside a procedure with iocheck modifier
* removed the GPF for unexistant overloading
(firstcall was called with procedinition=nil !)
* changed typen to what Florian proposed
gentypenode(p : pdef) sets the typenodetype field
and resulttype is only set if inside bt_type block !
Revision 1.69 1998/10/20 15:10:19 pierre
* type ptree only allowed inside expression
if following sizeof typeof low high or as first arg of new !!
Revision 1.68 1998/10/20 11:15:44 pierre
* calling of private method allowed inside child object method
Revision 1.67 1998/10/19 08:54:57 pierre
* wrong stabs info corrected once again !!
+ variable vmt offset with vmt field only if required
implemented now !!!
Revision 1.66 1998/10/15 15:13:28 pierre
+ added oo_hasconstructor and oo_hasdestructor
for objects options
Revision 1.65 1998/10/13 13:10:24 peter
* new style for m68k/i386 infos and enums
Revision 1.64 1998/10/12 12:20:55 pierre
+ added tai_const_symbol_offset
for r : pointer = @var.field;
* better message for different arg names on implementation
of function
Revision 1.63 1998/10/12 10:28:30 florian
+ auto dereferencing of pointers to structured types in delphi mode
Revision 1.62 1998/10/12 10:05:41 peter
* fixed mem leak with arrayconstrutor
Revision 1.61 1998/10/05 13:57:15 peter
* crash preventions
Revision 1.60 1998/10/05 12:32:46 peter
+ assert() support
Revision 1.59 1998/10/01 14:56:24 peter
* crash preventions
Revision 1.58 1998/09/30 07:40:35 florian
* better error recovering
Revision 1.57 1998/09/28 16:18:16 florian
* two fixes to get ansi strings work
Revision 1.56 1998/09/26 17:45:36 peter
+ idtoken and only one token table
Revision 1.55 1998/09/24 23:49:10 peter
+ aktmodeswitches
Revision 1.54 1998/09/23 15:46:39 florian
* problem with with and classes fixed
Revision 1.53 1998/09/23 09:58:54 peter
* first working array of const things
Revision 1.52 1998/09/20 09:38:45 florian
* hasharray for defs fixed
* ansistring code generation corrected (init/final, assignement)
Revision 1.51 1998/09/18 16:03:43 florian
* some changes to compile with Delphi
Revision 1.50 1998/09/17 13:41:18 pierre
sizeof(TPOINT) problem
Revision 1.49.2.1 1998/09/17 08:42:31 pierre
TPOINT sizeof fix
Revision 1.49 1998/09/09 11:50:53 pierre
* forward def are not put in record or objects
+ added check for forwards also in record and objects
* dummy parasymtable for unit initialization removed from
symtable stack
Revision 1.48 1998/09/07 22:25:53 peter
* fixed str(boolean,string) which was allowed
* fixed write(' ':<int expression>) only constants where allowed :(
Revision 1.47 1998/09/07 18:46:10 peter
* update smartlinking, uses getdatalabel
* renamed ptree.value vars to value_str,value_real,value_set
Revision 1.46 1998/09/04 08:42:03 peter
* updated some error messages
Revision 1.45 1998/09/01 17:39:49 peter
+ internal constant functions
Revision 1.44 1998/08/28 10:54:24 peter
* fixed smallset generation from elements, it has never worked before!
Revision 1.43 1998/08/23 16:07:24 florian
* internalerror with mod/div fixed
Revision 1.42 1998/08/21 14:08:50 pierre
+ TEST_FUNCRET now default (old code removed)
works also for m68k (at least compiles)
Revision 1.41 1998/08/20 21:36:39 peter
* fixed 'with object do' bug
Revision 1.40 1998/08/20 09:26:41 pierre
+ funcret setting in underproc testing
compile with _dTEST_FUNCRET
Revision 1.39 1998/08/18 16:48:48 pierre
* bug for -So proc assignment to p^rocvar fixed
Revision 1.38 1998/08/18 14:17:09 pierre
* bug about assigning the return value of a function to
a procvar fixed : warning
assigning a proc to a procvar need @ in FPC mode !!
* missing file/line info restored
Revision 1.37 1998/08/18 09:24:43 pierre
* small warning position bug fixed
* support_mmx switches splitting was missing
* rhide error and warning output corrected
Revision 1.36 1998/08/15 16:50:29 peter
* fixed proc()=expr which was not allowed anymore by my previous fix
Revision 1.35 1998/08/14 18:18:46 peter
+ dynamic set contruction
* smallsets are now working (always longint size)
Revision 1.34 1998/08/13 11:00:12 peter
* fixed procedure<>procedure construct
Revision 1.33 1998/08/11 15:31:39 peter
* write extended to ppu file
* new version 0.99.7
Revision 1.32 1998/08/11 14:05:32 peter
* fixed sizeof(array of char)
Revision 1.31 1998/08/10 14:50:11 peter
+ localswitches, moduleswitches, globalswitches splitting
Revision 1.30 1998/07/28 21:52:54 florian
+ implementation of raise and try..finally
+ some misc. exception stuff
Revision 1.29 1998/07/27 21:57:13 florian
* fix to allow tv like stream registration:
@tmenu.load doesn't work if load had parameters or if load was only
declared in an anchestor class of tmenu
Revision 1.28 1998/07/14 21:46:51 peter
* updated messages file
Revision 1.27 1998/06/25 14:04:23 peter
+ internal inc/dec
Revision 1.26 1998/06/09 16:01:46 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.25 1998/06/05 14:37:33 pierre
* fixes for inline for operators
* inline procedure more correctly restricted
Revision 1.24 1998/06/04 23:51:52 peter
* m68k compiles
+ .def file creation moved to gendef.pas so it could also be used
for win32
Revision 1.23 1998/06/04 09:55:40 pierre
* demangled name of procsym reworked to become independant of the mangling scheme
Revision 1.22 1998/06/02 17:03:03 pierre
* with node corrected for objects
* small bugs for SUPPORT_MMX fixed
Revision 1.21 1998/05/27 19:45:05 peter
* symtable.pas splitted into includefiles
* symtable adapted for $ifdef NEWPPU
Revision 1.20 1998/05/26 07:53:59 pierre
* bug fix for empty sets (nil pd was dereferenced )
Revision 1.19 1998/05/25 17:11:43 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.18 1998/05/23 01:21:20 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.17 1998/05/22 12:37:03 carl
* crash bugfix (patched msanually to main branch)
Revision 1.16 1998/05/21 19:33:32 peter
+ better procedure directive handling and only one table
Revision 1.15 1998/05/20 09:42:35 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.14 1998/05/11 13:07:56 peter
+ $ifdef NEWPPU for the new ppuformat
+ $define GDB not longer required
* removed all warnings and stripped some log comments
* no findfirst/findnext anymore to remove smartlink *.o files
Revision 1.13 1998/05/06 08:38:45 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.12 1998/05/05 12:05:42 florian
* problems with properties fixed
* crash fixed: i:=l when i and l are undefined, was a problem with
implementation of private/protected
Revision 1.11 1998/05/04 11:22:26 florian
* problem with DOM solved: it crashes when accessing a property in a method
Revision 1.10 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.9 1998/04/29 10:33:58 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.8 1998/04/14 23:27:03 florian
+ exclude/include with constant second parameter added
Revision 1.7 1998/04/09 23:02:15 florian
* small problems solved to get remake3 work
Revision 1.6 1998/04/09 22:16:35 florian
* problem with previous REGALLOC solved
* improved property support
Revision 1.5 1998/04/08 10:26:09 florian
* correct error handling of virtual constructors
* problem with new type declaration handling fixed
Revision 1.4 1998/04/07 22:45:05 florian
* bug0092, bug0115 and bug0121 fixed
+ packed object/class/array
Revision 1.3 1998/04/07 13:19:46 pierre
* bugfixes for reset_gdb_info
in MEM parsing for go32v2
better external symbol creation
support for rhgdb.exe (lowercase file names)
}