- Notifications
You must be signed in to change notification settings - Fork 25
/
Copy pathpreprocess.py
163 lines (131 loc) · 5.22 KB
/
preprocess.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#
# This file is part of the micropython-esp32-ulp project,
# https://github.com/micropython/micropython-esp32-ulp
#
# SPDX-FileCopyrightText: 2018-2023, the micropython-esp32-ulp authors, see AUTHORS file.
# SPDX-License-Identifier: MIT
from . importnocomment
from .utilimportsplit_tokens
from .definesdbimportDefinesDB
classRTC_Macros:
@staticmethod
defREAD_RTC_REG(rtc_reg, low_bit, bit_width):
return'\treg_rd '+', '.join((
rtc_reg,
'%s + %s - 1'% (low_bit, bit_width),
low_bit
))
@staticmethod
defWRITE_RTC_REG(rtc_reg, low_bit, bit_width, value):
return'\treg_wr '+', '.join((
rtc_reg,
'%s + %s - 1'% (low_bit, bit_width),
low_bit,
value
))
@staticmethod
defREAD_RTC_FIELD(rtc_reg, low_bit):
returnRTC_Macros.READ_RTC_REG(rtc_reg, low_bit, 1)
@staticmethod
defWRITE_RTC_FIELD(rtc_reg, low_bit, value):
returnRTC_Macros.WRITE_RTC_REG(rtc_reg, low_bit, 1, value+' & 1')
classPreprocessor:
def__init__(self):
self._defines_db=None
self._defines= {}
defparse_define_line(self, line):
line=line.strip()
ifnotline.startswith("#define"):
# skip lines not containing #define
return {}
line=line[8:].strip() # remove #define
parts=line.split(None, 1)
iflen(parts) !=2:
# skip defines without value
return {}
identifier, value=parts
tmp=identifier.split('(', 1)
iflen(tmp) ==2:
# skip parameterised defines (macros)
return {}
value="".join(nocomment.remove_comments(value)).strip()
return {identifier: value}
defparse_defines(self, content):
forlineincontent.splitlines():
self._defines.update(self.parse_define_line(line))
returnself._defines
defexpand_defines(self, line):
found=True
whilefound: # do as many passed as needed, until nothing was replaced anymore
found=False
tokens=split_tokens(line)
line=""
fortintokens:
lu=self._defines.get(t, t)
iflu==tandself._defines_db:
lu=self._defines_db.get(t, t)
iflu==tandt=='BIT':
# Special hack: BIT(..) translates to a 32-bit mask where only the specified bit is set.
# But the reg_wr and reg_rd opcodes expect actual bit numbers for argument 2 and 3.
# While the real READ_RTC_*/WRITE_RTC_* macros take in the output of BIT(x), they
# ultimately convert these back (via helper macros) to the bit number (x). And since this
# preprocessor does not (aim to) implement "proper" macro-processing, we can simply
# short-circuit this round-trip via macros and replace "BIT" with nothing so that
# "BIT(x)" gets mapped to "(x)".
continue
iflu!=t:
found=True
line+=lu
returnline
defprocess_include_file(self, filename):
withself.open_db() asdb:
withopen(filename, 'r') asf:
forlineinf:
result=self.parse_define_line(line)
db.update(result)
returndb
defexpand_rtc_macros(self, line):
clean_line=line.strip()
ifnotclean_line:
returnline
macro=clean_line.split('(', 1)
iflen(macro) !=2:
returnline
macro_name, macro_args=macro
macro_fn=getattr(RTC_Macros, macro_name, None)
ifmacro_fnisNone:
returnline
macro_args, _=macro_args.rsplit(')', 1) # trim away right bracket. safe as comments already stripped
macro_args=macro_args.split(',') # not safe when args contain ',' but we should not have those
macro_args= [x.strip() forxinmacro_args]
returnmacro_fn(*macro_args)
defuse_db(self, defines_db):
self._defines_db=defines_db
defopen_db(self):
classctx:
def__init__(self, db):
self._db=db
def__enter__(self):
# not opening DefinesDB - it opens itself when needed
returnself._db
def__exit__(self, type, value, traceback):
ifisinstance(self._db, DefinesDB):
self._db.close()
ifself._defines_db:
returnctx(self._defines_db)
returnctx(self._defines)
defpreprocess(self, content):
self.parse_defines(content)
withself.open_db():
lines=nocomment.remove_comments(content)
result= []
forlineinlines:
line=self.expand_defines(line)
line=self.expand_rtc_macros(line)
result.append(line)
result="\n".join(result)
returnresult
defpreprocess(content, use_defines_db=True):
preprocessor=Preprocessor()
preprocessor.use_db(DefinesDB())
returnpreprocessor.preprocess(content)