Skip to content

Commit

Permalink
Detect left-recursion and error.
Browse files Browse the repository at this point in the history
  • Loading branch information
Joshua Haberman committed Jul 27, 2008
1 parent 660f7e2 commit f000994
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 0 deletions.
29 changes: 29 additions & 0 deletions compiler/ll.lua
Expand Up @@ -31,6 +31,7 @@ require "fa"
function compute_lookahead(grammar)
local gla_needing_rtn_states = grammar:get_rtn_states_needing_gla()
local follow_states = get_follow_states(grammar)
check_for_left_recursion(grammar)
for state in each(gla_needing_rtn_states) do
state.gla = construct_gla(state, grammar, follow_states)
Expand All @@ -39,6 +40,34 @@ function compute_lookahead(grammar)
end
--[[--------------------------------------------------------------------
check_for_left_recursion(grammar): Checks all RTNs in the grammar to
see if they are left recursive. Errors if so.
--------------------------------------------------------------------]]--
function check_for_left_recursion(grammar)
for name, rtn in each(grammar.rtns) do
local states = Set:new()
function children(state, stack)
local children = {}
for edge_val, dest_state in state:transitions() do
if fa.is_nonterm(edge_val) then
if edge_val.name == name then
error("Grammar is not LL(*): it is left-recursive!")
end
table.insert(children, grammar.rtns:get(edge_val.name).start)
end
end
return children
end
depth_first_traversal(rtn.start, children)
end
end
--[[--------------------------------------------------------------------
Expand Down
36 changes: 36 additions & 0 deletions tests/test_ll.lua
Expand Up @@ -484,5 +484,41 @@ function TestFollow:test2()
)
end

function assert_fails_with_error(grammar_str, error_string)
grammar = parse_grammar(CharStream:new(grammar_str))
grammar:determinize_rtns()
grammar:minimize_rtns()

local success, message = pcall(compute_lookahead, grammar)
if success then
error("Failed to fail!")
elseif not message:find(error_string) then
error("Failed with wrong message! Message was supposed to start with "
.. error_string .. ", instead it was: " .. message)
end
end

function assert_left_recursive(grammar_str)
assert_fails_with_error(grammar_str, "Grammar is not LL%(%*%): it is left%-recursive!")
end

TestDetectNonLLStar = {}
function TestDetectNonLLStar:test_left_recursive()
assert_left_recursive(
[[
s -> s? "X";
]]
)
end

function TestDetectNonLLStar:test_left_recursive2()
assert_left_recursive(
[[
s -> a | "X";
a -> s | "Y";
]]
)
end

LuaUnit:run(unpack(arg))

0 comments on commit f000994

Please sign in to comment.