123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275(******************************************************************************)(* *)(* 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. *)(* *)(******************************************************************************)moduleMakeEngineTable(T:TableFormat.TABLES)=structtypestate=intletnumbers=stypetoken=T.tokentypeterminal=inttypenonterminal=inttypesemantic_value=Obj.tlettoken2terminal=T.token2terminallettoken2value=T.token2valueleterror_terminal=T.error_terminalleterror_value=Obj.repr()(* There is similar code in [InspectionTableInterpreter]. The
code there contains an additional conversion of the type
[terminal] to the type [xsymbol]. *)letrecfoldijijfaccu=ifi=jthenaccuelsefoldij(i+1)jf(fiaccu)letforeach_terminalfaccu=letn=T.terminal_countinfoldij0n(funiaccu->fiaccu)accutypeproduction=int(* In principle, only non-start productions are exposed to the user,
at type [production] or at type [int]. This is checked dynamically. *)letnon_start_productioni=assert(T.start<=i&&i-T.start<Array.lengthT.semantic_action)letproduction_indexi=non_start_productioni;iletfind_productioni=non_start_productioni;iletdefault_reductionstatedefrednodefredenv=letcode=T.default_reductionstateinifcode=0then(* no default reduction *)nodefredenvelse(* default reduction *)letprod=code-1indefredenvprodletis_startprod=prod<T.startletactionstateterminalvalueshiftreducefailenv=matchT.errorstateterminalwith|1->letaction=T.actionstateterminalinletopcode=actionland0b11andparam=actionlsr2inifopcode>=0b10then(* 0b10 : shift/discard *)(* 0b11 : shift/nodiscard *)letplease_discard=(opcode=0b10)inshiftenvplease_discardterminalvalueparamelse(* 0b01 : reduce *)(* 0b00 : cannot happen *)reduceenvparam|c->assert(c=0);failenvletmaybe_shift_tstateterminal=matchT.errorstateterminalwith|1->letaction=T.actionstateterminalinletopcode=actionland0b11inifopcode>=0b10then(* 0b10 : shift/discard *)(* 0b11 : shift/nodiscard *)letstate'=actionlsr2inSomestate'else(* 0b01 : reduce *)(* 0b00 : cannot happen *)None|c->assert(c=0);Noneletmay_reduce_prodstateterminalprod=letcode=T.default_reductionstateinifcode=0then(* no default reduction *)matchT.errorstateterminalwith|1->letaction=T.actionstateterminalinletopcode=actionland0b11inifopcode>=0b10then(* 0b10 : shift/discard *)(* 0b11 : shift/nodiscard *)falseelse(* 0b01 : reduce *)(* 0b00 : cannot happen *)letprod'=actionlsr2inprod=prod'|c->assert(c=0);falseelse(* default reduction *)letprod'=code-1inprod=prod'letgoto_ntstatent=letcode=T.gotostatentin(* code = 1 + state *)code-1let[@inline]lhsprod=T.lhsprodletgoto_prodstateprod=goto_ntstate(lhsprod)letmaybe_goto_ntstatent=letcode=T.gotostatentin(* If [code] is 0, there is no outgoing transition.
If [code] is [1 + state], there is a transition towards [state]. *)assert(0<=code);ifcode=0thenNoneelseSome(code-1)exceptionError=T.Errortypesemantic_action=(state,semantic_value,token)EngineTypes.env->(state,semantic_value)EngineTypes.stackletsemantic_actionprod=(* Indexing into the array [T.semantic_action] is off by [T.start],
because the start productions do not have entries in this array. *)T.semantic_action.(prod-T.start)(* [may_reduce state prod] tests whether the state [state] is capable of
reducing the production [prod]. This information could be determined
in constant time if we were willing to create a bitmap for it, but
that would take up a lot of space. Instead, we obtain this information
by iterating over a line in the action table. This is costly, but this
function is not normally used by the LR engine anyway; it is supposed
to be used only by programmers who wish to develop error recovery
strategies. *)(* In the future, if desired, we could memoize this function, so as
to pay the cost in (memory) space only if and where this function
is actually used. We could also replace [foreach_terminal] with a
function [exists_terminal] which stops as soon as the accumulator
is [true]. *)letmay_reducestateprod=(* Test if there is a default reduction of [prod]. *)default_reductionstate(fun()prod'->prod=prod')(fun()->(* If not, then for each terminal [t], ... *)foreach_terminal(funtaccu->accu||(* ... test if there is a reduction of [prod] on [t]. *)actionstatet()(* shift: *)(fun()__()_->false)(* reduce: *)(fun()prod'->prod=prod')(* fail: *)(fun()->false)())false)()(* If [T.trace] is [None], then the logging functions do nothing. *)letlog=matchT.tracewithSome_->true|None->falsemoduleLog=structopenPrintfletstatestate=matchT.tracewith|Some_->fprintfstderr"State %d:\n%!"state|None->()letshiftterminalstate=matchT.tracewith|Some(terminals,_)->fprintfstderr"Shifting (%s) to state %d\n%!"terminals.(terminal)state|None->()letreduce_or_acceptprod=matchT.tracewith|Some(_,productions)->fprintfstderr"%s\n%!"productions.(prod)|None->()letlookahead_tokentokenstartpendp=matchT.tracewith|Some(terminals,_)->fprintfstderr"Lookahead token is now %s (%d-%d)\n%!"terminals.(token)startp.Lexing.pos_cnumendp.Lexing.pos_cnum|None->()letinitiating_error_handling()=matchT.tracewith|Some_->fprintfstderr"Initiating error handling\n%!"|None->()letresuming_error_handling()=matchT.tracewith|Some_->fprintfstderr"Resuming error handling\n%!"|None->()lethandling_errorstate=matchT.tracewith|Some_->fprintfstderr"Handling error in state %d\n%!"state|None->()endend