123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337(******************************************************************************)(* *)(* Menhir *)(* *)(* Copyright Inria. All rights reserved. This file is distributed under *)(* the terms of the GNU General Public License version 2, as described in *)(* the file LICENSE. *)(* *)(******************************************************************************)openCmly_formatopenCmly_api(* ------------------------------------------------------------------------ *)(* Reading a .cmly file. *)exceptionErrorofstringletread(ic:in_channel):grammar=(* .cmly file format: CMLY ++ version string ++ grammar *)letmagic="CMLY"^Version.versionintryletm=really_input_stringic(String.lengthmagic)inifm<>magicthenraise(Error(Printf.sprintf"Invalid magic string in .cmly file.\n\
Expecting %S, but got %S."magicm))else(input_valueic:grammar)with|End_of_file(* [really_input_string], [input_value] *)|Failure_->(* [input_value] *)raise(Error(Printf.sprintf"Invalid or damaged .cmly file."))letread(filename:string):grammar=letic=open_in_binfilenameinmatchreadicwith|x->close_in_noerric;x|exceptionexn->close_in_noerric;raiseexn(* ------------------------------------------------------------------------ *)(* Packaging the interval [0..count) as a module of type [INDEXED]. *)moduleIndex(P:sigvalname:string(* for error messages only *)valcount:intend):INDEXEDwithtypet=int=structtypet=intletcount=P.countletof_intn=if0<=n&&n<countthennelseinvalid_arg(P.name^".of_int: index out of bounds")letto_intn=nletiterf=fori=0tocount-1dofidoneletfoldfx=letr=refxinfori=0tocount-1dor:=fi!rdone;!rlettabulatef=leta=Array.initcountfinArray.getaend(* ------------------------------------------------------------------------ *)(* Packaging a data structure of type [Cmly_format.grammar] as a module
of type [Cmly_api.GRAMMAR]. *)moduleMake(G:sigvalgrammar:grammarend):GRAMMAR=structopenGtypeterminal=inttypenonterminal=inttypeproduction=inttypelr0=inttypelr1=inttypeitem=production*inttypeocamltype=stringtypeocamlexpr=stringmoduleRange=structtypet=Cmly_format.rangeletstartprange=range.r_startletendprange=range.r_endendmoduleAttribute=structtypet=Cmly_format.attributeletlabelattr=attr.a_labellethas_labellabelattr=label=attr.a_labelletpayloadattr=attr.a_payloadletpositionattr=attr.a_positionendmoduleGrammar=structletbasename=grammar.g_basenameletpreludes=grammar.g_preludesletpostludes=grammar.g_postludesletentry_points=grammar.g_entry_pointsletattributes=grammar.g_attributesletparameters=grammar.g_parametersendmoduleTerminal=structlettable=grammar.g_terminalsletnamei=table.(i).t_nameletkindi=table.(i).t_kindlettypi=table.(i).t_typeletattributesi=table.(i).t_attributesincludeIndex(structletname="Terminal"letcount=Array.lengthtableend)endmoduleNonterminal=structlettable=grammar.g_nonterminalsletnamei=table.(i).n_nameletmangled_namei=table.(i).n_mangled_nameletkindi=table.(i).n_kindlettypi=table.(i).n_typeletpositionsi=table.(i).n_positionsletnullablei=table.(i).n_nullableletfirsti=table.(i).n_firstletattributesi=table.(i).n_attributesincludeIndex(structletname="Nonterminal"letcount=Array.lengthtableend)endtypesymbol=Cmly_format.symbol=|Tofterminal|Nofnonterminalletsymbol_name?(mangled=false)=function|Tt->Terminal.namet|Nn->ifmangledthenNonterminal.mangled_namenelseNonterminal.namentypeidentifier=stringmoduleAction=structtypet=actionletexprt=t.a_exprletkeywordst=t.a_keywordsendmoduleProduction=structlettable=grammar.g_productionsletkindi=table.(i).p_kindletlhsi=table.(i).p_lhsletrhsi=table.(i).p_rhsletpositionsi=table.(i).p_positionsletactioni=table.(i).p_actionletattributesi=table.(i).p_attributesincludeIndex(structletname="Production"letcount=Array.lengthtableend)endmoduleLr0=structlettable=grammar.g_lr0_statesletincomingi=table.(i).lr0_incomingletitemsi=table.(i).lr0_itemsincludeIndex(structletname="Lr0"letcount=Array.lengthtableend)endmoduleLr1=structlettable=grammar.g_lr1_statesletlr0i=table.(i).lr1_lr0lettransitionsi=table.(i).lr1_transitionsletreductionsi=table.(i).lr1_reductionsincludeIndex(structletname="Lr1"letcount=Array.lengthtableend)endmodulePrint=structletterminalppft=Format.pp_print_stringppf(Terminal.namet)letnonterminalppft=Format.pp_print_stringppf(Nonterminal.namet)letsymbolppf=function|Tt->terminalppft|Nn->nonterminalppfnletmangled_nonterminalppft=Format.pp_print_stringppf(Nonterminal.namet)letmangled_symbolppf=function|Tt->terminalppft|Nn->mangled_nonterminalppfnletreclengthslacc=function|[]->ifl=-1then[]elsel::lengths(-1)[]acc|[]::rows->lengthslaccrows|(col::cols)::rows->lengths(maxl(String.lengthcol))(cols::acc)rowsletrecadjust_lengthlengthscols=matchlengths,colswith|l::ls,c::cs->letpad=l-String.lengthcinletc=ifpad=0thencelsec^String.makepad' 'inc::adjust_lengthlscs|_,[]->[]|[],_->assertfalseletalign_tabularrows=letlengths=lengths(-1)[]rowsinList.map(adjust_lengthlengths)rowsletprint_lineppf=function|[]->()|x::xs->Format.fprintfppf"%s"x;List.iter(Format.fprintfppf" %s")xsletprint_tableppftable=lettable=align_tabulartableinList.iter(Format.fprintfppf"%a\n"print_line)tableletannot_itemsetannotsppfitems=letlast_lhs=ref(-1)inletprepare(p,pos)annot=letrhs=Array.map(fun(sym,id,_)->ifid<>""&&id.[0]<>'_'then"("^id^" = "^symbol_namesym^")"elsesymbol_namesym)(Production.rhsp)inifpos>=0&&pos<Array.lengthrhsthenrhs.(pos)<-". "^rhs.(pos)elseifpos>0&&pos=Array.lengthrhsthenrhs.(pos-1)<-rhs.(pos-1)^" .";letlhs=Production.lhspinletrhs=Array.to_listrhsinletrhs=if!last_lhs=lhsthen""::" |"::rhselsebeginlast_lhs:=lhs;Nonterminal.namelhs::"::="::rhsendinifannot=[]then[rhs]else[rhs;(""::""::annot)]inletrecprepare_allxsys=matchxs,yswith|[],_->[]|(x::xs),(y::ys)->letz=preparexyinz::prepare_allxsys|(x::xs),[]->letz=preparex[]inz::prepare_allxs[]inprint_tableppf(List.concat(prepare_allitemsannots))letitemsetppft=annot_itemset[]ppftletannot_itemannotppfitem=annot_itemset[annot]ppf[item]letitemppft=annot_item[]ppftletproductionppft=itemppf(t,-1)endendmoduleRead(X:sigvalfilename:stringend)=Make(structletgrammar=readX.filenameend)