1 (**************************************************************************)
5 (* François Pottier, INRIA Rocquencourt *)
6 (* Yann Régis-Gianas, PPS, Université Paris Diderot *)
8 (* Copyright 2005-2008 Institut National de Recherche en Informatique *)
9 (* et en Automatique. All rights reserved. This file is distributed *)
10 (* under the terms of the Q Public License version 1.0, with the change *)
11 (* described in file LICENSE. *)
13 (**************************************************************************)
18 (* Set up all of the information required by the LR engine. Everything is
19 read directly from [Grammar] and [Lr1]. *)
35 let token2terminal (token
: token
) : terminal
=
38 let token2value (token
: token
) : semantic_value
=
50 let default_reduction (s
: state
) defred nodefred env
=
51 match Invariant.has_default_reduction s
with
57 let action (s
: state
) (tok
: terminal
) value shift reduce fail env
=
59 (* Check whether [s] has an outgoing shift transition along [tok]. *)
63 let s'
: state
= SymbolMap.find
(Symbol.T tok
) (Lr1.transitions
s) in
65 (* There is such a transition. Return either [ShiftDiscard] or
66 [ShiftNoDiscard], depending on the existence of a default
67 reduction on [#] at [s']. *)
69 match Invariant.has_default_reduction
s'
with
70 | Some
(_
, toks
) when TerminalSet.mem
Terminal.sharp toks
->
71 shift env
false tok
value s'
73 shift env
true tok
value s'
75 (* There is no such transition. Look for a reduction. *)
80 let prod = Misc.single
(TerminalMap.find tok
(Lr1.reductions
s)) in
83 (* There is no reduction either. Fail. *)
88 let goto (s : state
) (prod : production
) : state
=
90 SymbolMap.find
(Symbol.N
(Production.nt
prod)) (Lr1.transitions
s)
94 open MenhirLib.EngineTypes
96 exception Accept
of semantic_value
99 type semantic_action
=
100 (state
, semantic_value
, token
) env
-> unit
102 let semantic_action (prod : production
) : semantic_action =
105 (* Check whether [prod] is a start production. *)
107 match Production.classify
prod with
109 (* If it is one, accept. Start productions are of the form S' ->
110 S, where S is a non-terminal symbol, so the desired semantic
111 value is found within the top cell of the stack. *)
114 raise
(Accept env
.stack
.semv
)
116 (* If it is not, reduce. Pop a suffix of the stack, and use it
117 to construct a new concrete syntax tree node. *)
121 let n = Production.length
prod in
122 let values : semantic_value array
=
123 Array.make
n CstError
(* dummy *)
124 and startp
: Lexing.position
ref =
126 and endp
: Lexing.position
ref =
130 (* The auxiliary function [pop k stack] pops [k] stack cells
131 and returns a truncated stack. It also updates the automaton's
132 current state, and fills in [values], [startp], and [endp]. *)
134 let rec pop k stack
=
138 (* There are no more stack cells to pop. *)
144 (* Fetch a semantic value. *)
146 values.(k
- 1) <- stack
.semv
;
148 (* Pop one cell. The stack must be non-empty. As we pop a cell,
149 change the automaton's current state to the one stored within
150 the cell. (It is sufficient to do this only when [k] is 1.)
151 If this is the first (last) cell that we pop, update [endp]
154 let next = stack
.next in
155 assert (stack
!= next);
160 env
.current
<- stack
.state
;
161 startp
:= stack
.startp
168 let stack = pop n env
.stack in
170 (* Construct and push a new stack cell. The associated semantic
171 value is a new concrete syntax tree. *)
175 semv
= CstNonTerminal
(prod, values);
181 (* The reference interpreter performs error recovery if and only if this
182 is requested via [--recovery]. *)
191 (* I use a reference as a quick and dirty form of parameter passing. *)
204 fprintf stderr
"State %d:" (Lr1.number
s)
209 fprintf stderr
"Shifting (%s) to state %d" (Terminal.print tok
) (Lr1.number
s'
)
212 let reduce_or_accept prod =
214 match Production.classify
prod with
216 fprintf stderr
"Accepting"
218 fprintf stderr
"Reducing production %s" (Production.print
prod)
221 let lookahead_token lexbuf tok
=
223 fprintf stderr
"Lookahead token is now %s (%d-%d)"
225 lexbuf
.Lexing.lex_start_p
.Lexing.pos_cnum
226 lexbuf
.Lexing.lex_curr_p
.Lexing.pos_cnum
229 let initiating_error_handling () =
231 fprintf stderr
"Initiating error handling"
234 let resuming_error_handling () =
236 fprintf stderr
"Resuming error handling"
239 let handling_error s =
241 fprintf stderr
"Handling error in state %d" (Lr1.number
s)
244 let discarding_last_token tok
=
246 fprintf stderr
"Discarding last token read (%s)" (Terminal.print tok
)
253 (* Instantiate the LR engine with this information. *)
256 MenhirLib.Engine.Make
(T
)
258 (* Define a palatable user entry point. *)
260 let interpret log nt lexer lexbuf
=
262 (* Find the start state that corresponds to [nt] in the automaton. *)
266 ProductionMap.find
(Production.startsymbol2startprod nt
) Lr1.entry
271 (* Run the engine. *)
275 Some
(E.entry
s lexer lexbuf
)