Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
allendowney
GitHub Repository: allendowney/cpython
Path: blob/main/Tools/c-analyzer/c_parser/parser/_global.py
12 views
1
import re
2
3
from ._regexes import (
4
GLOBAL as _GLOBAL,
5
)
6
from ._common import (
7
log_match,
8
parse_var_decl,
9
set_capture_groups,
10
)
11
from ._compound_decl_body import DECL_BODY_PARSERS
12
from ._func_body import parse_function_statics as parse_function_body
13
14
15
GLOBAL = set_capture_groups(_GLOBAL, (
16
'EMPTY',
17
'COMPOUND_LEADING',
18
'COMPOUND_KIND',
19
'COMPOUND_NAME',
20
'FORWARD_KIND',
21
'FORWARD_NAME',
22
'MAYBE_INLINE_ACTUAL',
23
'TYPEDEF_DECL',
24
'TYPEDEF_FUNC_PARAMS',
25
'VAR_STORAGE',
26
'FUNC_INLINE',
27
'VAR_DECL',
28
'FUNC_PARAMS',
29
'FUNC_DELIM',
30
'FUNC_LEGACY_PARAMS',
31
'VAR_INIT',
32
'VAR_ENDING',
33
))
34
GLOBAL_RE = re.compile(rf'^ \s* {GLOBAL}', re.VERBOSE)
35
36
37
def parse_globals(source, anon_name):
38
for srcinfo in source:
39
m = GLOBAL_RE.match(srcinfo.text)
40
if not m:
41
# We need more text.
42
continue
43
for item in _parse_next(m, srcinfo, anon_name):
44
if callable(item):
45
parse_body = item
46
yield from parse_body(source)
47
else:
48
yield item
49
else:
50
# We ran out of lines.
51
if srcinfo is not None:
52
srcinfo.done()
53
return
54
55
56
def _parse_next(m, srcinfo, anon_name):
57
(
58
empty,
59
# compound type decl (maybe inline)
60
compound_leading, compound_kind, compound_name,
61
forward_kind, forward_name, maybe_inline_actual,
62
# typedef
63
typedef_decl, typedef_func_params,
64
# vars and funcs
65
storage, func_inline, decl,
66
func_params, func_delim, func_legacy_params,
67
var_init, var_ending,
68
) = m.groups()
69
remainder = srcinfo.text[m.end():]
70
71
if empty:
72
log_match('global empty', m)
73
srcinfo.advance(remainder)
74
75
elif maybe_inline_actual:
76
log_match('maybe_inline_actual', m)
77
# Ignore forward declarations.
78
# XXX Maybe return them too (with an "isforward" flag)?
79
if not maybe_inline_actual.strip().endswith(';'):
80
remainder = maybe_inline_actual + remainder
81
yield srcinfo.resolve(forward_kind, None, forward_name)
82
if maybe_inline_actual.strip().endswith('='):
83
# We use a dummy prefix for a fake typedef.
84
# XXX Ideally this case would not be caught by MAYBE_INLINE_ACTUAL.
85
_, name, data = parse_var_decl(f'{forward_kind} {forward_name} fake_typedef_{forward_name}')
86
yield srcinfo.resolve('typedef', data, name, parent=None)
87
remainder = f'{name} {remainder}'
88
srcinfo.advance(remainder)
89
90
elif compound_kind:
91
kind = compound_kind
92
name = compound_name or anon_name('inline-')
93
# Immediately emit a forward declaration.
94
yield srcinfo.resolve(kind, name=name, data=None)
95
96
# un-inline the decl. Note that it might not actually be inline.
97
# We handle the case in the "maybe_inline_actual" branch.
98
srcinfo.nest(
99
remainder,
100
f'{compound_leading or ""} {compound_kind} {name}',
101
)
102
def parse_body(source):
103
_parse_body = DECL_BODY_PARSERS[compound_kind]
104
105
data = [] # members
106
ident = f'{kind} {name}'
107
for item in _parse_body(source, anon_name, ident):
108
if item.kind == 'field':
109
data.append(item)
110
else:
111
yield item
112
# XXX Should "parent" really be None for inline type decls?
113
yield srcinfo.resolve(kind, data, name, parent=None)
114
115
srcinfo.resume()
116
yield parse_body
117
118
elif typedef_decl:
119
log_match('typedef', m)
120
kind = 'typedef'
121
_, name, data = parse_var_decl(typedef_decl)
122
if typedef_func_params:
123
return_type = data
124
# This matches the data for func declarations.
125
data = {
126
'storage': None,
127
'inline': None,
128
'params': f'({typedef_func_params})',
129
'returntype': return_type,
130
'isforward': True,
131
}
132
yield srcinfo.resolve(kind, data, name, parent=None)
133
srcinfo.advance(remainder)
134
135
elif func_delim or func_legacy_params:
136
log_match('function', m)
137
kind = 'function'
138
_, name, return_type = parse_var_decl(decl)
139
func_params = func_params or func_legacy_params
140
data = {
141
'storage': storage,
142
'inline': func_inline,
143
'params': f'({func_params})',
144
'returntype': return_type,
145
'isforward': func_delim == ';',
146
}
147
148
yield srcinfo.resolve(kind, data, name, parent=None)
149
srcinfo.advance(remainder)
150
151
if func_delim == '{' or func_legacy_params:
152
def parse_body(source):
153
yield from parse_function_body(source, name, anon_name)
154
yield parse_body
155
156
elif var_ending:
157
log_match('global variable', m)
158
kind = 'variable'
159
_, name, vartype = parse_var_decl(decl)
160
data = {
161
'storage': storage,
162
'vartype': vartype,
163
}
164
yield srcinfo.resolve(kind, data, name, parent=None)
165
166
if var_ending == ',':
167
# It was a multi-declaration, so queue up the next one.
168
_, qual, typespec, _ = vartype.values()
169
remainder = f'{storage or ""} {qual or ""} {typespec} {remainder}'
170
srcinfo.advance(remainder)
171
172
if var_init:
173
_data = f'{name} = {var_init.strip()}'
174
yield srcinfo.resolve('statement', _data, name=None)
175
176
else:
177
# This should be unreachable.
178
raise NotImplementedError
179
180