123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291(******************************************************************************)(* *)(* Menhir *)(* *)(* Copyright Inria. All rights reserved. This file is distributed under *)(* the terms of the GNU Library General Public License version 2, with a *)(* special exception on linking, as described in the file LICENSE. *)(* *)(******************************************************************************)(* -------------------------------------------------------------------------- *)(* The type functor. *)moduleSymbols(T:sigtype'aterminaltype'anonterminalend)=structopenT(* This should be the only place in the whole library (and generator!)
where these types are defined. *)type'asymbol=|T:'aterminal->'asymbol|N:'anonterminal->'asymboltypexsymbol=|X:'asymbol->xsymbolend(* -------------------------------------------------------------------------- *)(* The code functor. *)moduleMake(TT:TableFormat.TABLES)(IT:InspectionTableFormat.TABLESwithtype'alr1state=int)(ET:EngineTypes.TABLEwithtypeterminal=intandtypenonterminal=intandtypesemantic_value=Obj.t)(E:sigtype'aenv=(ET.state,ET.semantic_value,ET.token)EngineTypes.envend)=struct(* Including [IT] is an easy way of inheriting the definitions of the types
[symbol] and [xsymbol]. *)includeIT(* This auxiliary function decodes a symbol. The encoding was done by
[encode_symbol] or [encode_symbol_option] in the table back-end. *)letdecode_symbol(symbol:int):IT.xsymbol=(* If [symbol] is 0, then we have no symbol. This could mean e.g.
that the function [incoming_symbol] has been applied to an
initial state. In principle, this cannot happen. *)assert(symbol>0);(* The low-order bit distinguishes terminal and nonterminal symbols. *)letkind=symbolland1inletsymbol=symbollsr1inifkind=0thenIT.terminal(symbol-1)elseIT.nonterminalsymbol(* These auxiliary functions convert a symbol to its integer code. For speed
and for convenience, we use an unsafe type cast. This relies on the fact
that the data constructors of the [terminal] and [nonterminal] GADTs are
declared in an order that reflects their internal code. In the case of
nonterminal symbols, we add [start] to account for the presence of the
start symbols. *)let[@inline]n2i(nt:'aIT.nonterminal):int=letanswer=TT.start+Obj.magicntin(* For safety, check that the above cast produced a correct result. *)assert(IT.nonterminalanswer=X(Nnt));answerlet[@inline]t2i(t:'aIT.terminal):int=letanswer=Obj.magictin(* For safety, check that the above cast produced a correct result. *)assert(IT.terminalanswer=X(Tt));answer(* Ordering functions. *)let[@inline]compare_terminalst1t2=(* Subtraction is safe because overflow is impossible. *)t2it1-t2it2let[@inline]compare_nonterminalsnt1nt2=(* Subtraction is safe because overflow is impossible. *)n2int1-n2int2letcompare_symbolssymbol1symbol2=matchsymbol1,symbol2with|X(T_),X(N_)->-1|X(N_),X(T_)->1|X(Tt1),X(Tt2)->compare_terminalst1t2|X(Nnt1),X(Nnt2)->compare_nonterminalsnt1nt2let[@inline]compare_productionsprod1prod2=(* Subtraction is safe because overflow is impossible. *)prod1-prod2letcompare_items(prod1,index1)(prod2,index2)=letc=compare_productionsprod1prod2in(* Subtraction is safe because overflow is impossible. *)ifc<>0thencelseindex1-index2(* The function [incoming_symbol] goes through the tables [IT.lr0_core] and
[IT.lr0_incoming]. This yields a representation of type [xsymbol], out of
which we strip the [X] quantifier, so as to get a naked symbol. This last
step is ill-typed and potentially dangerous. It is safe only because this
function is used at type ['a lr1state -> 'a symbol], which forces an
appropriate choice of ['a]. *)letincoming_symbol(s:'aIT.lr1state):'aIT.symbol=letcore=IT.lr0_coresinletsymbol=decode_symbol(IT.lr0_incomingcore)inmatchsymbolwith|IT.Xsymbol->Obj.magicsymbol(* The function [lhs] reads the table [TT.lhs] and uses [IT.nonterminal]
to decode the symbol. *)letlhsprod=IT.nonterminal(TT.lhsprod)(* The function [rhs] reads the table [IT.rhs] and uses [decode_symbol]
to decode the symbol. *)letrhsprod=List.mapdecode_symbol(IT.rhsprod)(* The function [items] maps the LR(1) state [s] to its LR(0) core,
then uses [core] as an index into the table [IT.lr0_items]. The
items are then decoded by the function [export] below, which is
essentially a copy of [Item.export]. *)typeitem=int*intletlow_bits=10letlow_limit=1lsllow_bitslet[@inline]exportt:item=(tlsrlow_bits,tmodlow_limit)letitemss=(* Map [s] to its LR(0) core. *)letcore=IT.lr0_coresin(* Now use [core] to look up the table [IT.lr0_items]. *)List.mapexport(IT.lr0_itemscore)(* The function [nullable] maps the nonterminal symbol [nt] to its
integer code, which it uses to look up the array [IT.nullable].
This yields 0 or 1, which we map back to a Boolean result. *)let[@inline]decode_booli=assert(i=0||i=1);i=1letnullablent=decode_bool(IT.nullable(n2int))(* The function [first] maps the symbols [nt] and [t] to their integer
codes, which it uses to look up the matrix [IT.first]. *)letfirstntt=decode_bool(IT.first(n2int)(t2it))letxfirstsymbolt=matchsymbolwith|X(Tt')->compare_terminalstt'=0|X(Nnt)->firstnttletrecfoldijijfaccu=ifi=jthenaccuelsefoldij(i+1)jf(fiaccu)letforeach_terminalfaccu=letn=TT.terminal_countinfoldij0n(funiaccu->f(IT.terminali)accu)acculetforeach_terminal_but_errorfaccu=letn=TT.terminal_countinfoldij0n(funiaccu->ifi=TT.error_terminalthenaccuelsef(IT.terminali)accu)accu(* ------------------------------------------------------------------------ *)(* The following is the implementation of the function [feed]. This function
is logically part of the LR engine, so it would be nice if it were placed
in the module [Engine], but it must be placed here because, to ensure
type safety, its arguments must be a symbol of type ['a symbol] and a
semantic value of type ['a]. The type ['a symbol] is not available in
[Engine]. It is available here. *)openEngineTypesopenETopenE(* [feed] fails if the current state does not have an outgoing transition
labeled with the desired symbol. This check is carried out at runtime. *)letfeed_failure()=invalid_arg"feed: outgoing transition does not exist"(* Feeding a nonterminal symbol [nt]. Here, [nt] has type [nonterminal],
which is a synonym for [int], and [semv] has type [semantic_value],
which is a synonym for [Obj.t]. This type is unsafe, because pushing
a semantic value of arbitrary type into the stack can later cause a
semantic action to crash and burn. The function [feed] is given a safe
type below. *)letfeed_nonterminal(nt:nonterminal)startp(semv:semantic_value)endp(env:'benv):'benv=(* Check if the source state has an outgoing transition labeled [nt].
This is done by consulting the [goto] table. *)letsource=env.currentinmatchET.maybe_goto_ntsourcentwith|None->feed_failure()|Sometarget->(* Push a new cell onto the stack, containing the identity of the state
that we are leaving. The semantic value [semv] and positions [startp]
and [endp] contained in the new cell are provided by the caller. *)letstack={state=source;semv;startp;endp;next=env.stack}in(* Move to the target state. *){envwithstack;current=target}letreduce_env_prod=feed_failure()letinitiate_env=feed_failure()letfeed_terminal(terminal:terminal)startp(semv:semantic_value)endp(env:'benv):'benv=(* Check if the source state has an outgoing transition labeled [terminal].
This is done by consulting the [action] table. *)letsource=env.currentinET.actionsourceterminalsemv(funenv_please_discard_terminalsemvtarget->(* There is indeed a transition toward the state [target].
Push a new cell onto the stack and move to the target state. *)letstack={state=source;semv;startp;endp;next=env.stack}in{envwithstack;current=target})reduceinitiateenv(* The type assigned to [feed] ensures that the type of the semantic value
[semv] is appropriate: it must be the semantic-value type of the symbol
[symbol]. *)letfeed(symbol:'asymbol)startp(semv:'a)endpenv=letsemv:semantic_value=Obj.reprsemvinmatchsymbolwith|Nnt->feed_nonterminal(n2int)startpsemvendpenv|Tterminal->feed_terminal(t2iterminal)startpsemvendpenvend