Skip to content

Commit 73287f8

Browse files
Refactor OpenMP grammar for LALR parsing (#66)
1 parent 3ba9138 commit 73287f8

4 files changed

Lines changed: 58 additions & 14 deletions

File tree

src/numba/openmp/omp_grammar.py

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,41 @@
5454
| ordered_construct
5555
for_simd_construct: for_simd_directive
5656
for_simd_directive: FOR SIMD [for_simd_clause*]
57-
for_simd_clause: for_clause
58-
| simd_clause
57+
// LALR: avoid ambiguity from overlapping expansions in for_clause vs simd_clause
58+
for_simd_clause: ORDERED
59+
| schedule_clause
60+
| collapse_clause
61+
| private_clause
62+
| copyprivate_clause
63+
| firstprivate_clause
64+
| lastprivate_clause
65+
| data_sharing_clause
66+
| data_default_clause
67+
| copyin_clause
68+
| reduction_clause
69+
| NOWAIT
70+
| aligned_clause
71+
| linear_clause
72+
| uniform_clause
73+
| inbranch_clause
5974
parallel_for_simd_construct: parallel_for_simd_directive
6075
parallel_for_simd_directive: PARALLEL FOR SIMD [parallel_for_simd_clause*]
61-
parallel_for_simd_clause: parallel_for_clause
62-
| simd_clause
76+
// LALR: avoid ambiguity from overlapping expansions in parallel_for_clause vs simd_clause
77+
parallel_for_simd_clause: if_clause
78+
| num_threads_clause
79+
| ORDERED
80+
| schedule_clause
81+
| collapse_clause
82+
| data_default_clause
83+
| private_clause
84+
| firstprivate_clause
85+
| lastprivate_clause
86+
| data_sharing_clause
87+
| reduction_clause
88+
| aligned_clause
89+
| linear_clause
90+
| uniform_clause
91+
| inbranch_clause
6392
distribute_construct: distribute_directive
6493
distribute_simd_construct: distribute_simd_directive
6594
distribute_directive: DISTRIBUTE [distribute_clause*]
@@ -509,10 +538,9 @@
509538
| device_clause
510539
| if_clause
511540
motion_clause: update_motion_type "(" variable_array_section_list ")"
512-
variable_array_section_list: PYTHON_NAME
541+
// LALR: name_slice already covers bare PYTHON_NAME, so avoid the ambiguous PYTHON_NAME alternatives.
542+
variable_array_section_list: name_slice
513543
// | array_section
514-
| name_slice
515-
| variable_array_section_list "," PYTHON_NAME
516544
| variable_array_section_list "," name_slice
517545
// | variable_array_section_list "," array_section
518546
//array_section: PYTHON_NAME array_section_subscript
@@ -690,7 +718,3 @@
690718
%import common.WS
691719
%ignore WS
692720
"""
693-
694-
"""
695-
name_slice: PYTHON_NAME [ "[" slice ["," slice]* "]" ]
696-
"""

src/numba/openmp/omp_lower.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2867,6 +2867,15 @@ def name_slice(self, args):
28672867
else:
28682868
return NameSlice(args[0], args[1:])
28692869

2870+
def variable_array_section_list(self, args):
2871+
if DEBUG_OPENMP >= 1:
2872+
print("visit variable_array_section_list", args, type(args))
2873+
if len(args) == 1:
2874+
return args
2875+
else:
2876+
args[0].append(args[1])
2877+
return args[0]
2878+
28702879
def var_list(self, args):
28712880
if DEBUG_OPENMP >= 1:
28722881
print("visit var_list", args, type(args))

src/numba/openmp/parser.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,9 @@
22

33
from .omp_grammar import openmp_grammar
44

5-
openmp_parser = Lark(openmp_grammar, start="openmp_statement")
6-
var_collector_parser = Lark(openmp_grammar, start="openmp_statement")
5+
# Use Lark's contextual lexer with LALR to resolve keyword-vs-identifier
6+
# overlaps (e.g. `TO` vs `PYTHON_NAME`) without reserving words.
7+
_LARK_KWARGS = dict(parser="lalr", lexer="contextual")
8+
9+
openmp_parser = Lark(openmp_grammar, start="openmp_statement", **_LARK_KWARGS)
10+
var_collector_parser = Lark(openmp_grammar, start="openmp_statement", **_LARK_KWARGS)

src/numba/openmp/tests/test_openmp.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1926,7 +1926,14 @@ def test_impl(nt):
19261926

19271927
with self.assertRaises(Exception) as raises:
19281928
test_impl(12)
1929-
self.assertIn("No terminal matches", str(raises.exception))
1929+
# Lark error text differs across versions: lexer failure ("No terminal matches")
1930+
# vs parser failure ("Unexpected token") for unsupported clauses like NOWAIT here.
1931+
err = str(raises.exception)
1932+
self.assertIn("nowait", err.lower())
1933+
self.assertTrue(
1934+
"No terminal matches" in err or "Unexpected token" in err,
1935+
err,
1936+
)
19301937

19311938
def test_parallel_double_num_threads(self):
19321939
@njit

0 commit comments

Comments
 (0)