print.sa


Generated by gen_html_sa_files from ICSI. Contact gomes@icsi.berkeley.edu for details
 
---------------------------> Sather 1.1 source file <--------------------------
-- Copyright (C) International Computer Science Institute, 1995.  COPYRIGHT  --
-- NOTICE: This code is provided "AS IS" WITHOUT ANY WARRANTY and is subject --
-- to the terms of the SATHER LIBRARY GENERAL PUBLIC LICENSE contained in    --
-- the file "Doc/License" of the Sather distribution.  The license is also   --
-- available from ICSI, 1947 Center St., Suite 600, Berkeley CA 94704, USA.  --
--------> Please email comments to sather-bugs@icsi.berkeley.edu. <----------


class ATTRSORT < $IS_LT{ATTRSORT}

class ATTRSORT < $IS_LT{ATTRSORT} is include COMPARABLE; attr name:STR; attr elt:ELT; create(n:STR,e:ELT):ATTRSORT is r::=new; r.name:=n;-- ATTRSORT::name r.elt:=e;-- ATTRSORT::elt return r; end; is_lt(b:SAME):BOOL is return name.is_lt(b.name); end;-- ATTRSORT::name STR::is_lt ATTRSORT::name is_eq(b:SAME):BOOL is return name.is_eq(b.name); end;-- ATTRSORT::name STR::is_eq ATTRSORT::name end;

class PRINT_OB

class PRINT_OB is -- generates several functions that can be called from the -- debugger or from a Sather program to visualize objects, -- function frames and stack traces, either graphically -- or textually. See the file Debugging in the Doc -- directory on how to use those functions. -- Original version by Claudio Fleiner <fleiner@icsi.berkeley.edu> 1.11.95 shared mangler:MANGLE; shared funcs:FLIST{SIG}; private mang(ob:$OB):STR is return mangler.mangle(ob,void);-- PRINT_OB::mangler MANGLE::mangle end; private mang(ob,ns:$OB):STR is return mangler.mangle(ob,ns);-- PRINT_OB::mangler MANGLE::mangle end; mkfname(cl:$TP):FSTR is return mang(cl).fstr;-- PRINT_OB::mang STR::fstr end; private get_ref_offsets(p:CODE_FILE,cl:$TP,el:$TP,prefix:STR) is loop e::=el.impl.elts.elt!;-- IMPL::elts ELT_TBL::elt! if e.is_attr_reader then-- ELT::is_attr_reader if ~e.ret.is_immutable and ~e.ret.is_bound and ~e.ret.is_external then-- ELT::ret BOOL::not ELT::ret BOOL::not ELT::ret BOOL::not p+prefix+mang(e.name,el)+",";-- CODE_FILE::plus CODE_FILE::plus PRINT_OB::mang ELT::name CODE_FILE::plus elsif e.ret.is_immutable then-- ELT::ret get_ref_offsets(p,cl,e.ret,prefix+mang(e.name,el)+".");-- PRINT_OB::get_ref_offsets ELT::ret STR::plus PRINT_OB::mang ELT::name STR::plus end end; end; if el.is_immutable and ~void(el.impl) and ~void(el.impl.arr) then -- BOOL::not IMPL::arr BOOL::not arr::=el.impl.arr.params[0];-- IMPL::arr TP_CLASS::params ARRAY{1}::aget if ~arr.is_immutable and ~arr.is_bound and ~arr.is_external then-- BOOL::not BOOL::not BOOL::not loop i::=0.upto!(el.impl.asize_val-1);-- INT::upto! IMPL::asize_val INT::minus p+prefix+"arr_part["+i+"]"+",";-- CODE_FILE::plus CODE_FILE::plus CODE_FILE::plus CODE_FILE::plus CODE_FILE::plus end; elsif arr.is_immutable then loop i::=0.upto!(el.impl.asize_val-1);-- INT::upto! IMPL::asize_val INT::minus get_ref_offsets(p,cl,arr,prefix+"arr_part["+i+"].");-- PRINT_OB::get_ref_offsets STR::plus STR::plus STR::plus end; end; end; end; shared num_attr:INT:=0; print(prog:PROG,cgen:CGEN):FSTR is -- p:FSTR:=#(10000); dec:FSTR:=#(1000);-- FSTR::create mangler:=cgen.mangler;-- PRINT_OB::mangler CGEN::mangler file_count::=0; fc:INT; -- count number of function (we don't want too many, as -- the declarations may be way to big if the file is split p::=#CODE_FILE("Print"+file_count.str+".c");-- CODE_FILE::create STR::plus INT::str STR::plus p.is_c_code:=true;-- CODE_FILE::is_c_code clt::=prog.tp_tbl.class_tbl;-- PROG::tp_tbl TP_TBL::class_tbl smallest_tag::=0; largest_tag::=0; loop n::=cgen.tags.targets!;-- CGEN::tags FMAP{2}::targets! if n<smallest_tag then smallest_tag:=n; end;-- INT::is_lt if n>largest_tag then largest_tag:=n; end;-- INT::is_lt end; last_largest::=0; last_smallest::=0; tg::=0; loop -- we want to create the tables for all tags, unfortunatly, -- new tags can be touched during the loop if tg>0 then-- INT::is_lt if tg<largest_tag then-- INT::is_lt tg:=tg+1;-- INT::plus else tg:=0; end; elsif tg<0 then-- INT::is_lt if tg>smallest_tag then-- INT::is_lt tg:=tg-1;-- INT::minus else tg:=0; end; end; if tg=0 then-- INT::is_eq if last_smallest=smallest_tag and last_largest=largest_tag then-- INT::is_eq INT::is_eq if ~cgen.adjust_tag_table then break!; end;-- CGEN::adjust_tag_table BOOL::not last_smallest:=smallest_tag; last_largest:=largest_tag; loop n::=cgen.tags.targets!;-- CGEN::tags FMAP{2}::targets! if n<smallest_tag then smallest_tag:=n; end;-- INT::is_lt if n>largest_tag then largest_tag:=n; end;-- INT::is_lt end; end; if last_largest<largest_tag then-- INT::is_lt tg:=last_largest+1;-- INT::plus last_largest:=largest_tag; elsif last_smallest>smallest_tag then-- INT::is_lt tg:=last_smallest-1;-- INT::minus last_smallest:=smallest_tag; else break!; end; end; cl:$TP:=void; if tg/=0 then-- INT::is_eq BOOL::not loop pr::=cgen.tags.pairs!;-- CGEN::tags FMAP{2}::pairs! if pr.t2=tg then-- TUP{2}::t2 INT::is_eq cl:=pr.t1;-- TUP{2}::t1 break!; end; end; if void(cl) then prog.barf("there seems to be no type for tag "+tg+"\n");-- PROG::barf STR::plus STR::plus end; if fc=30 then-- INT::is_eq file_count:=file_count+1;-- INT::plus p:=#CODE_FILE("Print"+file_count.str+".c");-- CODE_FILE::create STR::plus INT::str STR::plus p.is_c_code:=true;-- CODE_FILE::is_c_code fc:=0; end; fc:=fc+1;-- INT::plus if ~void(cl) then-- BOOL::not p.uses_tp(cl);-- CODE_FILE::uses_tp fname::=mkfname(cl);-- PRINT_OB::mkfname as:ARRAY{ATTRSORT}; attrs::=0; if ~cl.is_abstract and ~void(cl.impl) then-- BOOL::not BOOL::not as:=#ARRAY{ATTRSORT}(cl.impl.elts.size);-- ARRAY{1}::create IMPL::elts ELT_TBL::size loop n::=cl.impl.elts.elt!.name.str;-- IMPL::elts ELT_TBL::elt! ELT::name IDENT::str c::=cl.impl.elts.elt!;-- IMPL::elts ELT_TBL::elt! if c.is_attr_reader then-- ELT::is_attr_reader as.set!(#(n,c)); -- ARRAY{1}::set! ATTRSORT::create attrs:=attrs+1;-- INT::plus end; end; as:=as.resize(attrs);-- ARRAY{1}::resize as.sort;-- ARRAY{1}::sort end; p:=p+"\n/* type information for "+cl.str+" */\n";-- CODE_FILE::plus CODE_FILE::plus CODE_FILE::plus p:=p+"static int "+fname+"_ref_offsets[]= {";-- CODE_FILE::plus CODE_FILE::plus CODE_FILE::plus if cl.is_subtype(TP_BUILTIN::dollar_lock) then-- TP_BUILTIN::dollar_lock p:=p+"LOCK_HEADER_STRUCT_REFS ";-- CODE_FILE::plus end; if ~cl.is_abstract and ~cl.is_bound and ~cl.is_external then -- BOOL::not BOOL::not BOOL::not tps:STR; if cl.is_immutable then tps:="\n (int)&(*("+mang(cl)+"*)0).";-- STR::plus PRINT_OB::mang STR::plus else tps:="\n (int)&(*("+mang(cl)+")0)."; end;-- STR::plus PRINT_OB::mang STR::plus get_ref_offsets(p,cl,cl,tps); -- PRINT_OB::get_ref_offsets end; p:=p+"\t-1};\n";-- CODE_FILE::plus p:=p+"struct { int *refs;char *sn,*cn;long src;int sz,bx,at;\n"+-- CODE_FILE::plus " unsigned is_val:1,is_ref:1,is_abs:1,is_bnd:1,is_ext:1,is_aref:1;";-- CODE_FILE::plus if ~void(cl.impl) and ~void(cl.impl.arr) then attrs:=attrs+2; end;-- BOOL::not IMPL::arr BOOL::not INT::plus if attrs>0 then-- INT::is_lt p:=p+"\n struct sather_attribute attr["+attrs+"];";-- CODE_FILE::plus CODE_FILE::plus CODE_FILE::plus end; p:=p+" } "+fname+"_type_table = {\n";-- CODE_FILE::plus CODE_FILE::plus CODE_FILE::plus p:=p+" "+fname+"_ref_offsets,\n"-- CODE_FILE::plus CODE_FILE::plus +" \""+cl.str+"\", \"";-- CODE_FILE::plus CODE_FILE::plus CODE_FILE::plus CODE_FILE::plus if ~cl.is_external then p:=p+mang(cl); end;-- BOOL::not CODE_FILE::plus PRINT_OB::mang typecase cl when TP_CLASS then p:=p+"\",\n "+filepos(prog.parse.tree_for(cl.name,cl.params.size).source)+",\n";-- CODE_FILE::plus CODE_FILE::plus PRINT_OB::filepos PROG::parse TP_CLASS::name TP_CLASS::params ARRAY{1}::size AS_CLASS_DEF::source CODE_FILE::plus else p:=p+"\",\n 0,\n";-- CODE_FILE::plus end; if cl.is_immutable then p:=p+" sizeof("+mang(cl)+"),(int)&((*("+mang(cl)+"_boxed)NULL).immutable_part),";-- CODE_FILE::plus CODE_FILE::plus PRINT_OB::mang CODE_FILE::plus CODE_FILE::plus PRINT_OB::mang CODE_FILE::plus else if cl.str="EXT_OB" then-- STR::is_eq p+" 0,0, /* sizeof *EXT_OB is unkown */\n";-- CODE_FILE::plus elsif cl.is_external then p:=p+" 0,0, /* externals have no size */\n";-- CODE_FILE::plus elsif ~void(cl.impl) and ~void(cl.impl.arr) then-- BOOL::not IMPL::arr BOOL::not p:=p+" (int)(*("+mang(cl)+")0).arr_part,0, /* size without array */\n"-- CODE_FILE::plus CODE_FILE::plus PRINT_OB::mang else-- CODE_FILE::plus p:=p+" sizeof(*("+mang(cl)+")0),0,\n";-- CODE_FILE::plus CODE_FILE::plus PRINT_OB::mang CODE_FILE::plus end; end; if ~void(cl.impl) and ~void(cl.impl.arr) then p+" "+(attrs-2); else p+" "+attrs; end;-- BOOL::not IMPL::arr BOOL::not CODE_FILE::plus CODE_FILE::plus INT::minus CODE_FILE::plus CODE_FILE::plus if cl.is_immutable then p:=p+" ,1"; else p:=p+" ,0"; end;-- CODE_FILE::plus CODE_FILE::plus if ~cl.is_immutable and ~cl.is_abstract and ~cl.is_bound and ~cl.is_external then p:=p+",1"; else p:=p+",0"; end;-- BOOL::not BOOL::not BOOL::not BOOL::not CODE_FILE::plus CODE_FILE::plus if cl.is_abstract then p:=p+",1"; else p:=p+",0"; end;-- CODE_FILE::plus CODE_FILE::plus if cl.is_bound then p:=p+",1"; else p:=p+",0"; end;-- CODE_FILE::plus CODE_FILE::plus if cl.is_external then p:=p+",1"; else p:=p+",0"; end;-- CODE_FILE::plus CODE_FILE::plus if ~void(cl.impl) and ~void(cl.impl.arr) then p:=p+",1"; else p:=p+",0"; end;-- BOOL::not IMPL::arr BOOL::not CODE_FILE::plus CODE_FILE::plus if ~cl.is_abstract and ~void(cl.impl) and attrs>0 then-- BOOL::not BOOL::not INT::is_lt p+",\n {\n";-- CODE_FILE::plus first::=true; i::=1; loop e::=as.elt!.elt;-- ARRAY{1}::elt! ATTRSORT::elt if e.is_attr_reader then-- ELT::is_attr_reader if first then first:=false else p+",\n"; end;-- CODE_FILE::plus p+" { \""+ e.name.str+"\",\""+mang(e.name,cl)+"\","-- CODE_FILE::plus CODE_FILE::plus ELT::name IDENT::str CODE_FILE::plus CODE_FILE::plus PRINT_OB::mang ELT::name +cgen.tag_for(e.ret)+",(int)&(*("+mang(cl);-- CODE_FILE::plus CODE_FILE::plus CGEN::tag_for ELT::ret CODE_FILE::plus CODE_FILE::plus PRINT_OB::mang if cl.is_immutable then p:=p+"*"; end;-- CODE_FILE::plus p:=p+")0)."+mang(e.name,cl);-- CODE_FILE::plus CODE_FILE::plus PRINT_OB::mang ELT::name p:=p+","+filepos(e.as.source)+" }";-- CODE_FILE::plus CODE_FILE::plus PRINT_OB::filepos ELT::as CODE_FILE::plus end end; if ~void(cl.impl.arr) then-- IMPL::arr BOOL::not if first then first:=false else p+",\n"; end;-- CODE_FILE::plus -- note that for value arrays the offset is the -- size of the array! (asize is not an attribute of a -- value array) p:=p+" { \"asize\",\"asize\",INT_tag,";-- CODE_FILE::plus if cl.is_immutable then p:=p+mang(cl)+"_ASIZE,";-- CODE_FILE::plus PRINT_OB::mang CODE_FILE::plus else p:=p+"(int)&(*("+mang(cl)+")0).asize,";-- CODE_FILE::plus CODE_FILE::plus PRINT_OB::mang CODE_FILE::plus end; p:=p+"0 }";-- CODE_FILE::plus arr::=cl.impl.arr.params[0];-- IMPL::arr TP_CLASS::params ARRAY{1}::aget p:=p+",\n { \"[]\",\"arr_part[]\","+cgen.tag_for(arr)+-- CODE_FILE::plus CODE_FILE::plus CGEN::tag_for ",(int)(*("+mang(cl);-- CODE_FILE::plus CODE_FILE::plus PRINT_OB::mang if cl.is_immutable then p:=p+"*"; end;-- CODE_FILE::plus p:=p+")0).arr_part,0 }";-- CODE_FILE::plus end; p:=p+"\n }";-- CODE_FILE::plus end; p:=p+"\n};\n";-- CODE_FILE::plus p.good_place_to_split;-- CODE_FILE::good_place_to_split end; end; end; dec:=dec+"\n#define NUM_OF_ATTR "+num_attr+"\n";-- FSTR::plus PRINT_OB::num_attr FSTR::plus print_sather_type(prog,cgen,smallest_tag,largest_tag);-- PRINT_OB::print_sather_type print_file_list(prog,cgen,p);-- PRINT_OB::print_file_list if cgen.func_tables then print_sather_func(prog,cgen); end;-- CGEN::func_tables PRINT_OB::print_sather_func return dec; end; print_sather_type(prog:PROG,cgen:CGEN,sm:INT,lg:INT) is c::=#CODE_FILE("sather_type.c");-- CODE_FILE::create c.is_c_code:=true;-- CODE_FILE::is_c_code c.do_not_merge:=true;-- CODE_FILE::do_not_merge decl:FSTR:=#(1000);-- FSTR::create p:FSTR:=#(10000);-- FSTR::create p:=p+"static struct sather_type_description *sather_types_static[] = {\n";-- FSTR::plus decl:=decl+"#define ESS extern struct sather_type_description\n";-- FSTR::plus loop tg::=sm.upto!(lg);-- INT::upto! if tg=0 then-- INT::is_eq p:=p+" NULL, /* no type has tag 0 */\n";-- FSTR::plus else cl:$TP; loop pr::=cgen.tags.pairs!;-- CGEN::tags FMAP{2}::pairs! if pr.t2=tg then-- TUP{2}::t2 INT::is_eq cl:=pr.t1;-- TUP{2}::t1 break!; end; end; if void(cl) then prog.barf("there seems to be no type for tag "+tg+"\n");-- PROG::barf STR::plus STR::plus end; fname::=mkfname(cl);-- PRINT_OB::mkfname decl:=decl+"ESS "+fname+"_type_table;\n";-- FSTR::plus FSTR::plus FSTR::plus p:=p+" &"+fname+"_type_table,\n";-- FSTR::plus FSTR::plus FSTR::plus end; end; p:=p+" NULL };\n";-- FSTR::plus -- p:=p+"int sather_type_offset= ("+(-sm)+");\n"; p:=p+"struct sather_type_description **sather_types = sather_types_static+"+(-sm)+";\n";-- FSTR::plus FSTR::plus INT::negate FSTR::plus c+decl+"\n"+p;-- CODE_FILE::plus CODE_FILE::plus CODE_FILE::plus end; sort(t1,t2:TUP{SIG,INT}):BOOL is return t1.t1.str<t2.t1.str;-- TUP{2}::t1 SIG::str STR::is_lt TUP{2}::t1 SIG::str end; print_sather_func(prog:PROG,cgen:CGEN) is -- Generate FUNC() c::=#CODE_FILE("sather_func.c");-- CODE_FILE::create c.is_c_code:=true;-- CODE_FILE::is_c_code c.do_not_merge:=true;-- CODE_FILE::do_not_merge cs:ARRAY{TUP{SIG,INT}}:=#(funcs.size);-- ARRAY{1}::create PRINT_OB::funcs FLIST{1}::size loop cs.set!(#TUP{SIG,INT}(funcs.elt!,0.up!));-- ARRAY{1}::set! TUP{2}::create PRINT_OB::funcs FLIST{1}::elt! INT::up! end; cs.insertion_sort_by(bind(sort(_,_)));-- ARRAY{1}::insertion_sort_by PRINT_OB::sort loop cgen.tags_h+("#define F_tag_"+cs.elt!.t2+" "+0.up!+"\n");-- CGEN::tags_h CODE_FILE::plus STR::plus ARRAY{1}::elt! TUP{2}::t2 STR::plus STR::plus INT::up! STR::plus end; c+"#define ES extern struct sather_function_definition\n";-- CODE_FILE::plus loop c+("ES "+mang(cs.elt!.t1)+"_iframe;\n");-- CODE_FILE::plus STR::plus PRINT_OB::mang ARRAY{1}::elt! TUP{2}::t1 STR::plus end; c+"\n";-- CODE_FILE::plus c+"struct sather_function_definition *sather_functions[] = {\n";-- CODE_FILE::plus loop c+(" &"+mang(cs.elt!.t1)+"_iframe,\n");-- CODE_FILE::plus STR::plus PRINT_OB::mang ARRAY{1}::elt! TUP{2}::t1 STR::plus end; c+" NULL\n};\n";-- CODE_FILE::plus end; -- print out the list of source files as an array print_file_list(prog:PROG,cgen:CGEN,p:CODE_FILE) is p+"char *source_files[] = {\n";-- CODE_FILE::plus loop p+(" \""+SFILE_ID::files.elt!+"\",\n");-- CODE_FILE::plus STR::plus SFILE_ID::files FLIST{1}::elt! STR::plus end; p+"};\n";-- CODE_FILE::plus end; filepos(s:SFILE_ID):INT is return s.index*1048576+s.line_num_in;-- SFILE_ID::index INT::times INT::plus SFILE_ID::line_num_in end; register(s:SIG):STR is funcs:=funcs.push(s); -- PRINT_OB::funcs PRINT_OB::funcs FLIST{1}::push return "F_tag_"+(funcs.size-1);-- STR::plus PRINT_OB::funcs FLIST{1}::size INT::minus end; print_frame(prog:PROG,cgen:CGEN,p:CODE_FILE,o:AM_ROUT_DEF,iout:FLIST{AM_LOCAL_EXPR}) is mangler:=cgen.mangler;-- PRINT_OB::mangler CGEN::mangler n::=0; args::=o.size;-- AM_ROUT_DEF::size locals::=0; loop l::=o.locals.elt!;-- AM_ROUT_DEF::locals FLIST{1}::elt! if l/=o.rres and ~void(l.name) then-- AM_LOCAL_EXPR::is_eq AM_ROUT_DEF::rres BOOL::not AM_LOCAL_EXPR::name BOOL::not locals:=locals+1;-- INT::plus end; end; p+"\nstruct { void (*cf)();long src;char *sn,*cn;int args,lc;";-- CODE_FILE::plus if args+locals>0 then-- INT::plus INT::is_lt p+"\n struct sather_attribute attr["+(locals+args)+"];";-- CODE_FILE::plus CODE_FILE::plus INT::plus CODE_FILE::plus end; p+" } "+mang(o.sig)+"_iframe = {\n";-- CODE_FILE::plus CODE_FILE::plus PRINT_OB::mang AM_ROUT_DEF::sig CODE_FILE::plus p+" (void (*)())"+mang(o.sig)+",\n";-- CODE_FILE::plus CODE_FILE::plus PRINT_OB::mang AM_ROUT_DEF::sig CODE_FILE::plus p+" "+filepos(o.source)+",\n";-- CODE_FILE::plus CODE_FILE::plus PRINT_OB::filepos AM_ROUT_DEF::source CODE_FILE::plus p+" \""+o.sig.str+"\",\""+mang(o.sig)+"\",\n";-- CODE_FILE::plus CODE_FILE::plus AM_ROUT_DEF::sig SIG::str CODE_FILE::plus CODE_FILE::plus PRINT_OB::mang AM_ROUT_DEF::sig CODE_FILE::plus p+" "+args+", "+locals;-- CODE_FILE::plus CODE_FILE::plus CODE_FILE::plus CODE_FILE::plus if args+locals>0 then-- INT::plus INT::is_lt p+",\n {";-- CODE_FILE::plus first::=true; loop i::=o.ind!;-- AM_ROUT_DEF::ind! n:=n+1;-- INT::plus if ~first then p+","; end;-- BOOL::not CODE_FILE::plus first:=false; s::=o[i].expr;-- AM_ROUT_DEF::aget AM_FORMAL_ARG::expr if o.sig.is_iter and (o[i].mode=MODES::inout_mode or o[i].mode=MODES::out_mode) then-- AM_ROUT_DEF::sig SIG::is_iter AM_ROUT_DEF::aget AM_FORMAL_ARG::mode MODES::inout_mode AM_ROUT_DEF::aget AM_FORMAL_ARG::mode MODES::out_mode s:=iout.elt!;-- FLIST{1}::elt! end; p+"\n { \""+o[i].name.str+"\",\""+mang(s,o.sig)+"\",";-- CODE_FILE::plus CODE_FILE::plus AM_ROUT_DEF::aget AM_FORMAL_ARG::name IDENT::str CODE_FILE::plus CODE_FILE::plus PRINT_OB::mang AM_ROUT_DEF::sig CODE_FILE::plus p+cgen.tag_for(o[i].tp)+",0,"+filepos(o.source)+" }";-- CODE_FILE::plus CGEN::tag_for AM_ROUT_DEF::aget AM_FORMAL_ARG::tp CODE_FILE::plus CODE_FILE::plus PRINT_OB::filepos AM_ROUT_DEF::source CODE_FILE::plus end; loop l::=o.locals.elt!;-- AM_ROUT_DEF::locals FLIST{1}::elt! if l/=o.rres and ~void(l.name) then-- AM_LOCAL_EXPR::is_eq AM_ROUT_DEF::rres BOOL::not AM_LOCAL_EXPR::name BOOL::not n:=n+1;-- INT::plus if ~first then p+","; end;-- BOOL::not CODE_FILE::plus first:=false; p+"\n { \""+l.name.str+"\",\""+mang(l,o.sig)+"\",";-- CODE_FILE::plus CODE_FILE::plus AM_LOCAL_EXPR::name IDENT::str CODE_FILE::plus CODE_FILE::plus PRINT_OB::mang AM_ROUT_DEF::sig CODE_FILE::plus p+cgen.tag_for(l.tp)+",0,"+filepos(l.source)+" }";-- CODE_FILE::plus CGEN::tag_for AM_LOCAL_EXPR::tp CODE_FILE::plus CODE_FILE::plus PRINT_OB::filepos AM_LOCAL_EXPR::source CODE_FILE::plus end; end; p+"\n }";-- CODE_FILE::plus end; p+"\n};\n";-- CODE_FILE::plus if n>num_attr then num_attr:=n; end;-- PRINT_OB::num_attr PRINT_OB::num_attr end; end; -- vim:sw=3:nosmartindent