Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
M
menhir
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
12
Issues
12
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Packages & Registries
Packages & Registries
Container Registry
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
POTTIER Francois
menhir
Commits
74b133ce
Commit
74b133ce
authored
Jul 02, 2015
by
POTTIER Francois
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Replaced the old FOLLOW computation with the new one.
parent
8e270475
Changes
1
Hide whitespace changes
Inline
Sidebyside
Showing
1 changed file
with
37 additions
and
146 deletions
+37
146
src/grammar.ml
src/grammar.ml
+37
146
No files found.
src/grammar.ml
View file @
74b133ce
...
...
@@ 936,38 +936,6 @@ let solve (eqs : equations) : Nonterminal.t > TerminalSet.t =
F
.
lfp
nonterminal
(*  *)
(* Generic support for fixpoint computations.
A fixpoint computation associates a property with every nonterminal.
A monotone function tells how properties are computed. [compute nt]
updates the property associated with nonterminal [nt] and returns a
flag that tells whether the property actually needed an update. The
state of the computation is maintained entirely inside [compute] and
is invisible here.
Whenever a property of [nt] is updated, the properties of the
terminals whose definitions depend on [nt] are updated. The
dependency graph must be explicitly supplied. *)
let
fixpoint
(
dependencies
:
NonterminalSet
.
t
array
)
(
compute
:
Nonterminal
.
t
>
bool
)
:
unit
=
let
queue
:
Nonterminal
.
t
Queue
.
t
=
Queue
.
create
()
in
let
onqueue
:
bool
array
=
Array
.
make
Nonterminal
.
n
true
in
for
i
=
0
to
Nonterminal
.
n

1
do
Queue
.
add
i
queue
done
;
Misc
.
qiter
(
fun
nt
>
onqueue
.
(
nt
)
<
false
;
let
changed
=
compute
nt
in
if
changed
then
NonterminalSet
.
iter
(
fun
nt
>
if
not
onqueue
.
(
nt
)
then
begin
Queue
.
add
nt
queue
;
onqueue
.
(
nt
)
<
true
end
)
dependencies
.
(
nt
)
)
queue
(*  *)
(* Compute which nonterminals are nonempty, that is, recognize a
nonempty language. Also, compute which nonterminals are
...
...
@@ 1080,76 +1048,49 @@ let () =
this is useful for the SLR(1) test. Thus, we perform this analysis only
on demand. *)
let
follow
:
TerminalSet
.
t
array
Lazy
.
t
=
lazy
(
let
follow
=
Array
.
make
Nonterminal
.
n
TerminalSet
.
empty
and
forward
:
NonterminalSet
.
t
array
=
Array
.
make
Nonterminal
.
n
NonterminalSet
.
empty
and
backward
:
NonterminalSet
.
t
array
=
Array
.
make
Nonterminal
.
n
NonterminalSet
.
empty
in
(* Iterate over all start symbols. *)
for
nt
=
0
to
Nonterminal
.
start

1
do
assert
(
Nonterminal
.
is_start
nt
);
(* Add # to FOLLOW(nt). *)
follow
.
(
nt
)
<
TerminalSet
.
singleton
Terminal
.
sharp
done
;
(* We need to do this explicitly because our start productions are
of the form S' > S, not S' > S #, so # will not automatically
appear into FOLLOW(S) when the start productions are examined. *)
(* Iterate over all productions. *)
Array
.
iteri
(
fun
prod
(
nt1
,
rhs
)
>
(* Iterate over all nonterminal symbols [nt2] in the righthand side. *)
Array
.
iteri
(
fun
i
symbol
>
match
symbol
with

Symbol
.
T
_
>
()

Symbol
.
N
nt2
>
let
nullable
=
NULLABLE
.
production
prod
(
i
+
1
)
and
first
=
FIRST
.
production
prod
(
i
+
1
)
in
(* The FIRST set of the remainder of the righthand side
contributes to the FOLLOW set of [nt2]. *)
follow
.
(
nt2
)
<
TerminalSet
.
union
first
follow
.
(
nt2
);
(* If the remainder of the righthand side is nullable,
FOLLOW(nt1) contributes to FOLLOW(nt2). *)
if
nullable
then
begin
forward
.
(
nt1
)
<
NonterminalSet
.
add
nt2
forward
.
(
nt1
);
backward
.
(
nt2
)
<
NonterminalSet
.
add
nt1
backward
.
(
nt2
)
end
)
rhs
)
Production
.
table
;
let
follow
:
Nonterminal
.
t
>
TerminalSet
.
t
=
(* The fixpoint computation used here is not the most efficient
algorithm  one could do better by first collapsing the
strongly connected components, then walking the graph in
topological order. But this will do. *)
(* First pass. Build a system of equations between sets of nonterminal
symbols. *)
fixpoint
forward
(
fun
nt
>
let
original
=
follow
.
(
nt
)
in
(* union over all contributors *)
let
updated
=
NonterminalSet
.
fold
(
fun
nt'
accu
>
TerminalSet
.
union
follow
.
(
nt'
)
accu
)
backward
.
(
nt
)
original
in
follow
.
(
nt
)
<
updated
;
TerminalSet
.
compare
original
updated
<>
0
);
let
follow
:
equations
=
Array
.
make
Nonterminal
.
n
[]
in
follow
(* Iterate over all start symbols. *)
let
sharp
=
MemberConstant
(
TerminalSet
.
singleton
Terminal
.
sharp
)
in
for
nt
=
0
to
Nonterminal
.
start

1
do
assert
(
Nonterminal
.
is_start
nt
);
(* Add # to FOLLOW(nt). *)
follow
.
(
nt
)
<
sharp
::
follow
.
(
nt
)
done
;
(* We need to do this explicitly because our start productions are
of the form S' > S, not S' > S #, so # will not automatically
appear into FOLLOW(S) when the start productions are examined. *)
)
(* Iterate over all productions. *)
Array
.
iteri
(
fun
prod
(
nt1
,
rhs
)
>
(* Iterate over all nonterminal symbols [nt2] in the righthand side. *)
Array
.
iteri
(
fun
i
symbol
>
match
symbol
with

Symbol
.
T
_
>
()

Symbol
.
N
nt2
>
let
nullable
=
NULLABLE
.
production
prod
(
i
+
1
)
and
first
=
FIRST
.
production
prod
(
i
+
1
)
in
(* The FIRST set of the remainder of the righthand side
contributes to the FOLLOW set of [nt2]. *)
follow
.
(
nt2
)
<
MemberConstant
first
::
follow
.
(
nt2
);
(* If the remainder of the righthand side is nullable,
FOLLOW(nt1) contributes to FOLLOW(nt2). *)
if
nullable
then
follow
.
(
nt2
)
<
MemberVar
nt1
::
follow
.
(
nt2
)
)
rhs
)
Production
.
table
;
(* Define an accessor that triggers the computation of the FOLLOW sets
if it has not been performed already. *)
(* Second pass. Solve the equations (on demand). *)
let
follow
nt
=
(
Lazy
.
force
follow
)
.
(
nt
)
solve
follow
(* At log level 2, display the FOLLOW sets. *)
...
...
@@ 1213,56 +1154,6 @@ let () =
done
)
(*  *)
(* Compute FOLLOW sets. *)
let
follow'
=
let
follow
:
equations
=
Array
.
make
Nonterminal
.
n
[]
in
(* Iterate over all start symbols. *)
let
sharp
=
MemberConstant
(
TerminalSet
.
singleton
Terminal
.
sharp
)
in
for
nt
=
0
to
Nonterminal
.
start

1
do
assert
(
Nonterminal
.
is_start
nt
);
(* Add # to FOLLOW(nt). *)
follow
.
(
nt
)
<
sharp
::
follow
.
(
nt
)
done
;
(* We need to do this explicitly because our start productions are
of the form S' > S, not S' > S #, so # will not automatically
appear into FOLLOW(S) when the start productions are examined. *)
(* Iterate over all productions. *)
Array
.
iteri
(
fun
prod
(
nt1
,
rhs
)
>
(* Iterate over all nonterminal symbols [nt2] in the righthand side. *)
Array
.
iteri
(
fun
i
symbol
>
match
symbol
with

Symbol
.
T
_
>
()

Symbol
.
N
nt2
>
let
nullable
=
NULLABLE
.
production
prod
(
i
+
1
)
and
first
=
FIRST
.
production
prod
(
i
+
1
)
in
(* The FIRST set of the remainder of the righthand side
contributes to the FOLLOW set of [nt2]. *)
follow
.
(
nt2
)
<
MemberConstant
first
::
follow
.
(
nt2
);
(* If the remainder of the righthand side is nullable,
FOLLOW(nt1) contributes to FOLLOW(nt2). *)
if
nullable
then
follow
.
(
nt2
)
<
MemberVar
nt1
::
follow
.
(
nt2
)
)
rhs
)
Production
.
table
;
solve
follow
(* Sanity check. *)
let
()
=
for
nt
=
0
to
Nonterminal
.
n

1
do
let
f
=
follow
nt
and
f'
=
follow'
nt
in
assert
(
TerminalSet
.
equal
f
f'
)
done
(*  *)
(* Provide explanations about FIRST sets. *)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment