4 require
"fa_algorithms"
5 require
"bootstrap/rtn"
8 function find_state(rule
, slotnum
)
13 for s
in each(rule
:states()) do
14 for edge_val
, dest_state
, properties
in s
:transitions() do
15 if properties
.slotnum
== slotnum
then
21 error(string.format("No such slotnum (%d) for rule %s", slotnum
, rule_str
))
24 function get_target_for_slotnum(state
, slotnum
)
25 for edge_val
, dest_state
, properties
in state
:transitions() do
26 if properties
.slotnum
== slotnum
then
27 return {edge_val
, dest_state
}
30 error(string.format("Slotnum %d not found for state %s", slotnum
, serialize(state
, 4, " ")))
33 function parse_gla(str
, rtn_state
)
34 local stream
= CharStream
:new(str
)
35 stream
:ignore("whitespace")
36 local gla
= fa
.GLA
:new()
37 gla
.rtn_state
= rtn_state
38 local states
= {[1]=gla
.start
}
39 while not stream
:eof() do
40 local statenum
= tonumber(stream
:consume_pattern("%d+"))
41 local state
= states
[statenum
]
43 error(string.format("GLA refers to state %d before it is used as a target",
46 while stream
:lookahead(1) ~= ";" do
48 local term
= stream
:consume_pattern("%w+")
50 local dest_state_num
= tonumber(stream
:consume_pattern("%d+"))
51 states
[dest_state_num
] = states
[dest_state_num
] or fa
.GLAState
:new()
52 local dest_state
= states
[dest_state_num
]
54 state
:add_transition(fa
.eof
, dest_state
)
56 state
:add_transition(term
, dest_state
)
58 if stream
:lookahead(1) == "(" then
60 local final_state_slotnum
= tonumber(stream
:consume_pattern("%d+"))
62 dest_state
.final
= get_target_for_slotnum(rtn_state
, final_state_slotnum
)
72 function assert_lookahead(grammar_str
, rule_str
, slotnum
, expected_gla_str
)
73 grammar
= parse_grammar(CharStream
:new(grammar_str
))
74 grammar
:determinize_rtns()
75 grammar
:minimize_rtns()
77 local rule
= grammar
.rtns
:get(rule_str
)
78 state
= find_state(rule
, slotnum
)
79 expected_gla
= parse_gla(expected_gla_str
, state
)
81 compute_lookahead(grammar
)
83 if not fa_isequal(expected_gla
, state
.gla
) then
84 local bad
= io
.open("bad.dot", "w")
85 bad
:write("digraph untitled {\n")
86 bad
:write(state
.gla
:to_dot())
90 local good
= io
.open("good.dot", "w")
91 good
:write("digraph untitled {\n")
92 good
:write(expected_gla
:to_dot())
96 os
.execute("dot -Tpng -o good.png good.dot")
97 os
.execute("dot -Tpng -o bad.png bad.dot")
99 error("GLAs were not equal: expected and actual are " ..
100 "in good.png and bad.png, respectively")
105 function TestSimple
:test1()
119 function TestSimple
:test_multiple_recursions()
135 function TestEpsilon
:test1()
150 function TestEpsilon
:test2()
165 function TestEpsilon
:test3()
181 function TestEpsilon
:test4()
198 function TestEpsilon
:test5()
216 TODO
: add this test when GLAs that tell RTNs to
return are supported
.
217 function TestEpsilon
:test5()
232 TestMultipleNonterms
= {}
233 function TestMultipleNonterms
:test1()
250 function TestMultipleNonterms
:test22()
270 function TestLL2
:test1()
273 s -> "X" "Y" | "X" "Z";
284 function TestLL2
:test2()
299 function TestLL2
:test3()
315 function TestLL2
:test3()
318 s -> "X"? "Y" | "X" "Z";
331 function TestLL3
:test1()
335 a -> ("P" | "Q") ("P" | "Q");
349 function TestLL3
:test2()
353 a -> ("P" | "Q")? ("P" | "Q")?;
372 function TestEOF
:test1()
386 function TestEOF
:test2()
387 -- this is the example used by Terence Parr in his discussion of ANTLR 3.0's
388 -- lookahead analysis: http://www.antlr.org/blog/antlr3/lookahead.tml
405 -- -- Test lookahead that we can only compute correctly if we apply the
406 -- -- tail-recursion optimization.
407 -- TestTailRecursion = {}
408 -- function TestTailRecursion:test1()
411 -- s -> a "X" | a "Y";
424 function TestFollow
:test1()
439 -- Won't work until lookahead can instruct an RTN to return.
440 -- function TestFollow:test1()