class Gram def memo_no if !@memo_no if @name=="Amethyst" @memo_no=111 else @memo_no=Compiler.grammars[parent].memo_no+2 end else @memo_no end end def memo_inc @memo_no=memo_no+2 end end class AmethystCTranslator < Amethyst def addcallback2(cb) return @rcallbacks[cb] if @rcallbacks[cb] n="#{@grammar}_#{signature(cb)}" i=1 i+=1 while @callbacks[n+(i>1 ? i.to_s : "")] n=n+i.to_s if i>1 @rcallbacks[cb]=n @callbacks[n]=cb n end def desc(s) a=s[0];i=1 while @locls[a] && @locls[a]!=s i+=1;a=s[0]+"_"+i.to_s end @locls[a]=s return a end def bget(s) cm=s[0] s=desc(s) return "_#{s}" end def bset(s,e) cm=s[0] s=desc(s) "_#{s}=#{e};" end def rbbget(s) return "bind[#{@binds[s]}]" if @binds[s] @bindno+=1 @binds[s]=@bindno rbbget(s) end def symb(str) str=str.gsub("@","_at_"); sy="sy_#{str}" @header<<"static VALUE #{sy};" @init<<"#{sy}=rb_intern(#{str.inspect});" sy end def resetlabels @labels=Hash.new(0) end def label(s) @labels[s]+=1 "#{s}#{@labels[s]}" end def rbcall(name,args) "rb_funcall(self,#{symb(name)},#{args.size}#{args.map{|a| ",#{a}"}*""})" end def callrule(name,argc) margs=argc.times.map{|a| ",arg#{a}"} grammar=resolvegrammar(@grammar,name) if grammar @header<<"VALUE #{grammar}_#{name}(VALUE self #{",VALUE"*argc});" "#{grammar}_#{name}(self #{margs*""})" else rbcall(name,argc.times.map{|a| "arg#{a}"}) end end def failwhen(cond) "if (#{cond}){it=failobj;goto #{@faillabel};}" end end def gc_mark_var(v) "rb_global_variable(&#{v});" end $classlabels=Hash.new(0) amethyst AmethystCTranslator { itrans = {[]}:ruby {[]}:c {[]}:init ( char:[ruby] | trans:{c<<it[0];init<<it[1];ruby<<it[2]} )* -> [c,init,ruby] rbtrans = Local[.* {rbbget(@self)}] | Args[rbtrans2] | Array[rbtrans2] | Key[.:name rbtrans:args] -> (name=="self") ? "src" : "src.#{name}#{args!="" ? "(#{args})":""}" | Global[:name] -> "@#{name}" | Lambda[addlambda ] | Result[ {"#{@name}.create( {#{@vars.size.times.map{|i| ":#{@varnames[i]}=>#{rbbget(@vars[i])}" }.sort*","} })"} ] | . rbtrans2 = rbtrans*:{it*""} rbcode = {"class #{@>grammar} < #{@>parent}\n"}:s {s<<@@defs.sort*"\n";s<<"\n"} {@@callbacks.to_a.sort}=>[([:k :v] {"def #{k}(bind)\n#{v}\nend\n"})*:x ] {s+=x*""} {s+="\nend"; s} trans = Grammar[ {@>grammar=@@grammar=@name;@>parent=@parent} {@@lambdas=[] ;@@rcallbacks={};@@cbhash={}} {@@defs=[];@@defmethods=[];@@profile_report=[]} {@@faillabel="fail"} {@@callbacks={}} {@@header=[]} {@@init=[]} @rules=>[trans*]:t rbcode:rbcode { "VALUE cls_#{@name};\n" }:s { s<<@@header.uniq.sort*"\n"+"\n" s<<"\n memo_struct *mem_#{@name}=NULL;VALUE memo_val_#{@name};" if CurrentParser[:memoize] s<<"VALUE profile_report_#{@name}(VALUE self){cstruct *ptr; Data_Get_Struct(self,cstruct,ptr); #{@@profile_report*""} return Qnil;}" @@init<<"rb_define_method(cls_#{@name},\"profile_report\",profile_report_#{@name},0);" @@init<<"mem_#{@name}=memo_init();memo_val_#{@name}=Data_Wrap_Struct(rb_cObject,memo_mark,memo_free,mem_#{@name});rb_global_variable(&memo_val_#{@name});" if CurrentParser[:global_memo] s<<t.sort*"\n" s<<@@lambdas*"\n" init="\n cls_#{@name}=rb_define_class(\"#{@name}\",rb_const_get(rb_cObject,rb_intern(\"#{@>parent}\"))); failobj=rb_eval_string(\"FAIL\"); #{@@init.uniq.sort*"\n"} #{@@defmethods.sort*"\n" } " [s,init,rbcode] } ] | Rule[@name:name {@>rulename=name; Local.resetnumbering;resetlabels;@@locls={}} {(CurrentParser[:memoize] && ((CurrentParser[:memoize]==:all)||CurrentParser[:memoize].include?(name))) ? Memo[@body] : @body}=>trans:body { h="VALUE #{@>grammar}_#{name}(VALUE self #{map_index(@args){|i| ",VALUE a#{i}"}*""})" @@header<<h+";" @@defs<< "def self.#{name}(*args);self.new.parse(:#{name},*args);end;def self._selector_#{name};#{@>grammar};end" @@defmethods<< "rb_define_method(cls_#{@>grammar},\"#{@name}\",#{@>grammar}_#{@name},#{@varargs ? -2 : @args.size});" s=h+"{VALUE vals[#{@args.size}]; VALUE it #{@@locls.map{|k,v| ",_#{k}"}*""};VALUE bind2=bind_new2(16); #{map_index(@args){|i| bset(@args[i],"a#{i}")+";"}*""} int x;VALUE arg0,arg1,arg2,arg3; cstruct *ptr; Data_Get_Struct(self,cstruct,ptr);" s+="#{body}\n" s+="fail: return it;\n}" s } ] | Memo[ rw('memo_fail',`trans`):t ] {s="" if CurrentParser[:global_memo] s+="if (ptr->mem==NULL){ptr->mem=mem_#{@>grammar};}" else s+="if (ptr->mem==NULL){ptr->mem=memo_init();ptr->memgc=Data_Wrap_Struct(rb_cObject,memo_mark,memo_free,ptr->mem);}" end memo_no=Compiler.grammars[@>grammar].memo_inc s+="time_struct time_old=memo_get(ptr->mem,#{memo_no},ptr->src,ptr->pos); if (time_old.pos!=-1) {ptr->pos=time_old.pos;return time_old.result;} int oldpos=ptr->pos;" s+=t s+="memo_fail: memo_add(ptr->mem,#{memo_no},ptr->src,oldpos,it,ptr->pos,time_old); return it;\n" @@profile_report << "if(ptr->mem){fprintf(profile_report,\"memo #{@>grammar}::#{@>rulename} hit: %i miss: %i ticks: %i\\n\",((memo_struct *)ptr->mem)->hits[#{memo_no}],((memo_struct *)ptr->mem)->miss[#{memo_no}],((memo_struct *)ptr->mem)->ticks[#{memo_no}]);((memo_struct *)ptr->mem)->hits[#{memo_no}]=0;((memo_struct *)ptr->mem)->miss[#{memo_no}]=0;((memo_struct *)ptr->mem)->ticks[#{memo_no}]=0;}" s} | Act[ .:a &{a=="_append("} Local:x . Local:y . ] -> "it=AmethystCore_append(self,#{bget(x)},#{bget(y)});" | Act[ {@@bindno=0;@@binds={}} .*:it addcallback(@pred ? ["(",it,") || FAIL"] : it):cbno {@@binds.map{|k,v| "bind_aset(bind2,#{v},#{bget(k)});"}*"" + "it=#{rbcall(cbno,["bind2"])};"+@@binds.map{|k,v|"#{bset(k,"bind_aget(bind2,#{v})")};"}*"" +"#{@pred ? "#{failwhen("it==failobj")};" :"" }"} ] | CAct[.* {ar=*@ccode; @@header<<ar[0] if ar[0] @@init<<ar[1] if ar[1] "it=#{ar[2]};" }] | Apply[ ["_find"] {raise "TODO"} ] | Apply[ ["_test_size"] CAct[.:s] ] -> "if(ptr->pos+#{s}>=ptr->len) #{failwhen("1")}" | Apply[ ["fails"] {"#{failwhen("1")}"} ] | Apply[ ["eof"] {"it=Qnil;#{failwhen("ptr->pos<ptr->len")}"} ] | Apply[ ["empty"] {"it=Qnil;"} ] | Apply[ ["advance_char"] {"it=rb_str_new(ptr->str+ptr->pos,1);ptr->pos++;"} ] | Apply[ ["advance_clas"] {"it=ptr->ary[ptr->pos]; ;ptr->pos++;"} ] | Apply[ ["_seq"] CAct[.:s] {"if (#{ary=s.split("");map_index(ary){|i| "ame_curstr2(ptr)[#{i}]==#{Lattice_Char.new.cchar(ary[i])}" }*"&&" }) ptr->pos+=#{s.size}; else #{failwhen("1")}"}] | Apply[ .:name {0}:ii ( trans:aa {ii+=1} {"#{aa} arg#{ii-1}=it;"})*:args @self:app] -> r=" #{args*""} it=#{callrule(name,ii)};"; cant_fail?(app) ? r : "#{r} #{failwhen("it==failobj")}" | Bind[ trans:e {"#{e} #{bset(@name,"it")};\n" } ] | Seq[ trans*:t {t*""} ] | Or[ {label("accept")}:accept {label("oldpos")}:oldpos label("alt"):alt {1}:altno {@@cutlabel}:oldcutlabel {@@cuts}:oldcuts {@@cuts=nil;@@cutlabel=label("cut")} {"int #{oldpos}=ptr->pos;int #{@@cutlabel}=0;\n#{alt}_#{altno}:;"}:s ( &(.) {altno+=1} rw("#{alt}_#{altno}",`trans`):t {s+="#{t}\n;goto #{accept};\n"} {s+="#{alt}_#{altno}: ptr->pos=#{oldpos};#{@@cuts ? (@@cuts=nil;failwhen(@@cutlabel)): ""}"} )* {@@cutlabel=oldcutlabel;@@cuts=oldcuts;s+"#{failwhen(1)};\n #{accept}:;\n"} ] | Cut[] {@@cuts=true; @@cutlabel ? "#{@@cutlabel}=1;" : ""} | Many[ Or[ Apply[ ["anything"] ] Stop[] ]] -> "ptr->pos=ptr->len;" | Many[ {@@stops}:oldstops {@@stoplabel}:oldstoplabel {@@stops=nil} {@@stoplabel=label("stop")} trans:t { s="int #{@@stoplabel}=0; while(!#{@@stoplabel}){ #{t} } " @@stops=oldstops; @@stoplabel=oldstoplabel s } ] | Stop[] {@@stops=true; @@stoplabel? "#{@@stoplabel}=1;" : ""} | Lookahead[ {label("accept")}:accept {label("reject")}:reject {label("oldpos")}:oldpos rw(reject,`trans:t`) {"int #{oldpos}=ptr->pos;\n #{t} x=1; goto #{accept}; #{reject}: x=0; #{accept}: it=Qnil; ptr->pos=#{oldpos}; #{failwhen("x==0")}"} ] | Local[ .* { "it=#{bget(@self)};" } ] | Pass[ label("pass"):pass label("oldpass"):oldpass label("success"):success rw(pass,`@to=>trans:to`) { "cstruct #{oldpass}=*ptr; ptr->pos=ptr->len=0; ptr->ary=NULL; #{@enter ? "ame_setsrc2(self,#{bget(@var)});" : "ptr->src=failobj;ptr->ary=alloca(sizeof(VALUE));ptr->ary[0]=#{bget(@var)};ptr->len=1;" } #{to} goto #{success}; #{pass}: *ptr=#{oldpass};#{failwhen("1")} #{success}: *ptr=#{oldpass}; " } ] | Switch_Char[ {"switch((unsigned char)*ame_curstr2(ptr)){"}:s ( [.:c trans:t] {s+=c.cases() + " #{t} break;\n"})* {s+"}"} ] | Switch_Clas[ {"switchhash_#{@>grammar}_#{$classlabels[@>grammar]+=1}"}:sh {0}:ii {""}:init {@@header<< "VALUE #{sh};"} {"switch(FIX2LONG(rb_hash_aref(#{sh},rb_obj_class(ame_curobj2(ptr))))){"}:s ( [.:c trans:t]{c.ary.each{|al| init+="next h[k]=#{ii} if k<=#{al}\\n";s+="case #{ii}/*#{al}*/:";ii+=1}} {s+="; #{t} break;\n"})* {@@init <<"#{sh}=rb_eval_string(\"Hash.new{|h,k|#{init}}\");#{gc_mark_var(sh)};"} {s+"}"} ] addlambda = {"#{@>grammar}_#{@>rulename}_#{label("lambda")}"}:lambd rw('fail',`trans:body`) { h="VALUE #{lambd}(VALUE self,VALUE bind)" @@header<<h+";" @@defmethods<<"rb_define_method(cls_#{@>grammar},\"#{lambd}\",#{lambd},1);" @@lambdas<< h+"{VALUE vals[0]; /*todo unify with rule and get args*/ cstruct *ptr; int x;VALUE it;VALUE arg0,arg1,arg2,arg3;\n#{body}\nreturn it;\nfail: return failobj; }" } {"AmethystLambda.new(:#{lambd},self,bind)" } rw(word,prc) = {@@faillabel}:rwo {@@faillabel=word } apply(prc):x {@@faillabel=rwo; x } addcallback(s) = {s}=>rbtrans2:s {addcallback2(s)} }