diff --git a/lark/parsers/cyk.py b/lark/parsers/cyk.py index d65d485b..ee9ea8ec 100644 --- a/lark/parsers/cyk.py +++ b/lark/parsers/cyk.py @@ -199,7 +199,8 @@ def __init__(self, grammar): for r in self.rules: # Validate that the grammar is CNF and populate auxiliary data structures. assert isinstance(r.lhs, NT), r - assert len(r.rhs) in [1, 2], r + if len(r.rhs) not in [1, 2]: + raise ParseError("CYK doesn't support empty rules") if len(r.rhs) == 1 and isinstance(r.rhs[0], T): self.terminal_rules[r.rhs[0]].append(r) elif len(r.rhs) == 2 and all(isinstance(x, NT) for x in r.rhs): diff --git a/lark/parsers/grammar_analysis.py b/lark/parsers/grammar_analysis.py index 3568414f..9cab90c7 100644 --- a/lark/parsers/grammar_analysis.py +++ b/lark/parsers/grammar_analysis.py @@ -92,7 +92,7 @@ def calculate_sets(rules): for rule in rules: for i, sym in enumerate(rule.expansion): - if i==len(rule.expansion)-1 or set(rule.expansion[i:]) <= NULLABLE: + if i==len(rule.expansion)-1 or set(rule.expansion[i+1:]) <= NULLABLE: if update_set(FOLLOW[sym], FOLLOW[rule.origin]): changed = True diff --git a/tests/test_parser.py b/tests/test_parser.py index 948f56f0..3a4a60ac 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -1237,6 +1237,17 @@ def test_line_counting(self): self.assertEqual(tok.end_line, 2) self.assertEqual(tok.end_column, 6) + @unittest.skipIf(PARSER=='cyk', "Empty rules") + def test_empty_end(self): + p = _Lark(""" + start: b c d + b: "B" + c: | "C" + d: | "D" + """) + res = p.parse('B') + self.assertEqual(len(res.children), 3) + _NAME = "Test" + PARSER.capitalize() + LEXER.capitalize()