1 --[[--------------------------------------------------------------------
3 Gazelle: a system for building fast, reusable parsers
7 Construct NFAs based on primitives of concatenation, alternation,
8 and repetition/kleene-star. The construction is as given in
9 "Programming Language Pragmatics," by Michael L. Scott (see
10 BIBLIOGRAPHY for more info).
12 Copyright (c) 2007 Joshua Haberman. See LICENSE for details.
14 --------------------------------------------------------------------]]--
18 module("nfa_construct", package
.seeall
)
20 --[[--------------------------------------------------------------------
22 concat(nfa1, nfa2): Returns a concatenations of two NFAs.
23 eg. for the NFAs A and B:
28 B ...becomes: o ---> o ---> o ---> *
31 --------------------------------------------------------------------]]--
33 function concat(nfa1
, nfa2
)
34 nfa1
.final
:add_transition(fa
.e
, nfa2
.start
)
35 return nfa1
:new_graph
{start
= nfa1
.start
, final
= nfa2
.final
}
39 --[[--------------------------------------------------------------------
41 alt([nfa1, nfa2, ...]): Returns an alternation of the given NFAs.
42 eg. for the NFAs A, B, and C:
45 o ---> * ,----> o ---> o -----,
48 o ---> * ...becomes: o ---> o ---> o ---> *
51 o ---> * +----> o ---> o -----'
53 --------------------------------------------------------------------]]--
55 function alt(nfas
, prioritized
)
56 local new_nfa
= nfas
[1]:new_graph()
57 local priority_class
= {}
63 priority_class
= priority_class
,
64 priority
= #nfas
- i
+ 1 -- priorities count down from #nfas to 0
68 new_nfa
.start
:add_transition(fa
.e
, nfas
[i
].start
, properties
)
69 nfas
[i
].final
:add_transition(fa
.e
, new_nfa
.final
)
75 -- alt2(nfa1, nfa2): a convenience wrapper for alternation of 2 NFAs.
76 function alt2(nfa1
, nfa2
, prioritized
)
77 return alt({nfa1
, nfa2
}, prioritized
)
80 function get_repeating_properties(favor_repeating
)
81 local repeat_properties
82 local finish_properties
84 if favor_repeating
~= nil then
85 local priority_class
= {} -- just a unique value
86 repeat_properties
= {priority_class
=priority_class
}
87 finish_properties
= {priority_class
=priority_class
}
88 if favor_repeating
then
89 repeat_properties
.priority
= 2
90 finish_properties
.priority
= 1
92 repeat_properties
.priority
= 1
93 finish_properties
.priority
= 2
97 return repeat_properties
, finish_properties
100 --[[--------------------------------------------------------------------
102 rep(nfa): Returns the given NFA repeated one or more times.
107 o ---> * ...becomes: o ---> o ---> o ---> *
112 Note: This construction isn't strictly necessary: we could always
113 rewrite A+ as AA*, therefore using the kleene star to construct
114 all repetition. However, this makes for less understandable NFAs.
115 The difference would disappear in the minimization state, but it's
116 nice to keep the FAs as understandable as possible at every stage.
118 --------------------------------------------------------------------]]--
120 function rep(nfa
, favor_repeat
)
121 local new_nfa
= nfa
:new_graph()
122 local repeat_properties
, finish_properties
= get_repeating_properties(favor_repeating
)
123 new_nfa
.start
:add_transition(fa
.e
, nfa
.start
)
124 nfa
.final
:add_transition(fa
.e
, nfa
.start
, repeat_properties
)
125 nfa
.final
:add_transition(fa
.e
, new_nfa
.final
, finish_properties
)
130 --[[--------------------------------------------------------------------
132 kleene(nfa): Returns the given NFA repeated zero or more times.
133 eg. for the regular expression A* :
136 +--------------------+
139 o ---> * ...becomes: o ---> o ---> o ---> *
144 --------------------------------------------------------------------]]--
146 function kleene(nfa
, favor_repeat
)
147 local new_nfa
= rep(nfa
)
148 local repeat_properties
, finish_properties
= get_repeating_properties(favor_repeat
)
149 new_nfa
.start
:add_transition(fa
.e
, nfa
.start
)
150 new_nfa
.start
:add_transition(fa
.e
, new_nfa
.final
, finish_properties
)
151 nfa
.final
:add_transition(fa
.e
, nfa
.start
, repeat_properties
)
152 nfa
.final
:add_transition(fa
.e
, new_nfa
.final
, finish_properties
)