Skip to content

Commit 084c70e

Browse files
committed
Add C emitters with local rule and output state
1 parent 9065df6 commit 084c70e

2 files changed

Lines changed: 441 additions & 0 deletions

File tree

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
"""Emit a complete C parser from an immutable plan and local output state."""
2+
3+
from collections.abc import Iterator
4+
from contextlib import contextmanager
5+
from typing import IO
6+
7+
from pegen.c_generator_model import CParser
8+
from pegen.c_generator_rules import CRuleEmitter
9+
10+
11+
class CParserEmitter:
12+
def __init__(self, parser: CParser, file: IO[str] | None):
13+
self._parser = parser
14+
self._file = file
15+
self._level = 0
16+
17+
def emit(self) -> None:
18+
self._emit_headers()
19+
self._emit_keywords()
20+
self._emit_declarations()
21+
self._emit_rules()
22+
if self._parser.trailer is not None:
23+
self.print(self._parser.trailer)
24+
25+
def _emit_headers(self) -> None:
26+
self.print(f"// @generated by pegen from {self._parser.source_name}")
27+
for header in self._parser.headers:
28+
self.print(header)
29+
30+
def _emit_keywords(self) -> None:
31+
groups = self._parser.keyword_groups
32+
self.print(f"static const int n_keyword_lists = {len(groups)};")
33+
self.print("static KeywordToken *reserved_keywords[] = {")
34+
with self.indent():
35+
for group in groups or ((),):
36+
if not group:
37+
self.print("(KeywordToken[]) {{NULL, -1}},")
38+
else:
39+
self.print("(KeywordToken[]) {")
40+
with self.indent():
41+
for keyword, token_type in group:
42+
self.print(f'{{"{keyword}", {token_type}}},')
43+
self.print("{NULL, -1},")
44+
self.print("},")
45+
self.print("};")
46+
self.print("static char *soft_keywords[] = {")
47+
with self.indent():
48+
for keyword in self._parser.soft_keywords:
49+
self.print(f'"{keyword}",')
50+
self.print("NULL,")
51+
self.print("};")
52+
53+
def _emit_declarations(self) -> None:
54+
for rule_id, rule in enumerate(self._parser.rules, 1000):
55+
comment = " // Left-recursive" if rule.left_recursive else ""
56+
self.print(f"#define {rule.signature.name}_type {rule_id}{comment}")
57+
self.print()
58+
for rule in self._parser.rules:
59+
self.print(rule.signature.declaration())
60+
self.print()
61+
62+
def _emit_rules(self) -> None:
63+
for rule in self._parser.rules:
64+
self.print()
65+
if rule.left_recursive:
66+
self.print("// Left-recursive")
67+
CRuleEmitter(self, rule, debug=self._parser.debug).emit()
68+
69+
def print(self, *args: object) -> None:
70+
if not args:
71+
print(file=self._file)
72+
else:
73+
print(" " * self._level, end="", file=self._file)
74+
print(*args, file=self._file)
75+
76+
@contextmanager
77+
def indent(self) -> Iterator[None]:
78+
self._level += 1
79+
try:
80+
yield
81+
finally:
82+
self._level -= 1

0 commit comments

Comments
 (0)