11
11
import imp
12
12
import io
13
13
import collections
14
+ import re
14
15
15
16
#support for <=0.7.7
16
17
class customDict (dict ):
17
18
def append (self , var ):
18
- self [var ]= None
19
+ self [var ]= True
19
20
20
21
21
22
class preprocessor :
22
23
def __init__ (self , inFile = sys .argv [0 ], outFile = '' , defines = {}, removeMeta = False ,
23
- escapeChar = None , mode = None , escape = '#' , run = True , resume = False , save = True ):
24
+ escapeChar = None , mode = None , escape = '#' , run = True , resume = False ,
25
+ save = True , overload = True ):
24
26
# public variables
25
27
self .defines = customDict ()
26
28
#support for <=0.7.7
27
29
if isinstance (defines , collections .Sequence ):
28
30
for x in defines :
29
- self .defines . append (x )
31
+ self .define (x )
30
32
else :
31
33
for x ,y in defines :
32
34
self .define (x ,y )
@@ -39,6 +41,7 @@ def __init__(self, inFile=sys.argv[0], outFile='', defines={}, removeMeta=False,
39
41
self .run = run
40
42
self .resume = resume
41
43
self .save = save
44
+ self .overload = overload
42
45
self .readEncoding = sys .stdin .encoding
43
46
self .writeEncoding = sys .stdout .encoding
44
47
@@ -88,15 +91,20 @@ def __reset_internal(self):
88
91
self .__ifblocks = [] # contains the evaluated if conditions
89
92
self .__ifconditions = [] # contains the if conditions
90
93
self .__outputBuffer = ''
94
+ self .__overloaded = list (self .defines .keys ()) if self .overload else []
91
95
92
- def define (self , define , val = None ):
96
+
97
+ def define (self , name , val = True ):
93
98
"""
94
- Adds variable definition to the store as expected from a #defined directive.
99
+ Adds variable definition to the store as expected from a #define directive.
95
100
The directive can contains no value as it would be tested with a #ifdef directive or
96
101
with a value for an evaluation as in an #if directive.
102
+
103
+ Note: if the `name` was part of the initial definition and `overload` was set to
104
+ True, this new definition will be skipped
97
105
98
106
:params
99
- define (str): definition name
107
+ name (str): definition name
100
108
101
109
val (str): definition value when it exists. Default is None
102
110
"""
@@ -106,7 +114,8 @@ def define(self, define, val=None):
106
114
except :
107
115
# assume val is string
108
116
pass
109
- self .defines [define ]= val
117
+ if name not in self .__overloaded :
118
+ self .defines [name ]= val
110
119
111
120
def undefine (self , define ):
112
121
"""
@@ -119,7 +128,7 @@ def undefine(self, define):
119
128
if define in self .defines :
120
129
self .defines .pop (define )
121
130
122
- def search_defines (self , define ):
131
+ def __is_defined (self , define ):
123
132
"""
124
133
Checks variable is defined as used in #ifdef, #ifnotdef & #elseif directives
125
134
@@ -129,7 +138,7 @@ def search_defines(self, define):
129
138
"""
130
139
return define in self .defines
131
140
132
- def evaluate (self , line ):
141
+ def __evaluate_if (self , line ):
133
142
"""
134
143
Evaluate the content of a #if, #elseif, #elif directive
135
144
@@ -138,7 +147,9 @@ def evaluate(self, line):
138
147
139
148
"""
140
149
try :
141
- return eval (line , self .defines )
150
+ # replace C-style bool format by Python's
151
+ line = line .replace ('&&' , 'and' ).replace ('||' , 'or' ).replace ('!' ,'not ' )
152
+ return eval (line , self .defines ) or False
142
153
except BaseException as e :
143
154
print (str (e ))
144
155
self .exit_error (self .escape + 'if' )
@@ -173,6 +184,21 @@ def __is_directive(self, line, directive, *size):
173
184
return True
174
185
return False
175
186
187
+ def __cleanup_line (self , line ):
188
+ """
189
+ Clean a line of anything that should not impact parsing such as C-style comment
190
+
191
+ :params:
192
+ line (str): line to check
193
+
194
+ :return
195
+ line (str): cleaned line
196
+
197
+ """
198
+ line = re .sub ('\s*/\*.*\*/\s+' , '' , line ) #remove /* */ C-style comment
199
+ line = re .sub ('\s*//.*' , '' , line ) #remove // C-style comment
200
+ return line
201
+
176
202
def lexer (self , line ):
177
203
"""
178
204
Analyse the `line`. This method attempts to find a known directive and, when found, to
@@ -187,6 +213,7 @@ def lexer(self, line):
187
213
metadata (bool): is this line a directive?
188
214
189
215
"""
216
+ line = line .strip ()
190
217
if not (self .__ifblocks or self .__excludeblock ):
191
218
if 'pypreprocessor.parse()' in line :
192
219
return True , True
@@ -196,7 +223,10 @@ def lexer(self, line):
196
223
# exclude=True if we are in an exclude block or the ifs are not validated
197
224
return self .__excludeblock or not self .__validate_ifs (), False
198
225
199
- elif self .__is_directive (line , 'define' , 2 ,3 ):
226
+ # strip line of any C-style comment
227
+ line = self .__cleanup_line (line )
228
+
229
+ if self .__is_directive (line , 'define' , 2 ,3 ):
200
230
self .define (* line .split ()[1 :])
201
231
202
232
elif self .__is_directive (line , 'undef' , 2 ):
@@ -212,15 +242,15 @@ def lexer(self, line):
212
242
elif self .__is_directive (line , 'ifdefnot' , 2 ) or \
213
243
self .__is_directive (line , 'ifnotdef' , 2 ) or \
214
244
self .__is_directive (line , 'ifndef' , 2 ):
215
- self .__ifblocks .append (not self .search_defines (line .split ()[1 ]))
245
+ self .__ifblocks .append (not self .__is_defined (line .split ()[1 ]))
216
246
self .__ifconditions .append (line .split ()[1 ])
217
247
218
248
elif self .__is_directive (line , 'ifdef' , 2 ):
219
- self .__ifblocks .append (self .search_defines (line .split ()[1 ]))
249
+ self .__ifblocks .append (self .__is_defined (line .split ()[1 ]))
220
250
self .__ifconditions .append (line .split ()[1 ])
221
251
222
252
elif self .__is_directive (line , 'if' ):
223
- self .__ifblocks .append (self .evaluate (' ' .join (line .split ()[1 :])))
253
+ self .__ifblocks .append (self .__evaluate_if (' ' .join (line .split ()[1 :])))
224
254
self .__ifconditions .append (' ' .join (line .split ()[1 :]))
225
255
226
256
# since in version <=0.7.7, it didn't handle #if it should be #elseifdef instead.
@@ -232,18 +262,18 @@ def lexer(self, line):
232
262
# do if
233
263
if len (line .split ()) == 2 :
234
264
#old behaviour
235
- self .__ifblocks . append ( self .search_defines (line .split ()[1 ]))
265
+ self .__ifblocks [ - 1 ] = self .__is_defined (line .split ()[1 ])
236
266
else :
237
267
#new behaviour
238
- self .__ifblocks . append ( self .evaluate (' ' .join (line .split ()[1 :]) ))
268
+ self .__ifblocks [ - 1 ] = self .__evaluate_if (' ' .join (line .split ()[1 :]))
239
269
self .__ifconditions .append (' ' .join (line .split ()[1 :]))
240
270
241
271
elif self .__is_directive (line , 'elseifdef' , 2 ):
242
272
# do else
243
273
self .__ifblocks [- 1 ] = not self .__ifblocks [- 1 ]
244
- # do ifdef
245
- self .__ifblocks . append ( self .search_defines (line .split ()[1 ]) )
246
- self .__ifconditions .append (line .split ()[1 ] )
274
+ # do if
275
+ self .__ifblocks [ - 1 ] = self .__is_defined (line .split ()[1 ])
276
+ self .__ifconditions .append (' ' . join ( line .split ()[1 :]) )
247
277
248
278
elif self .__is_directive (line , 'else' , 1 ):
249
279
self .__ifblocks [- 1 ] = not self .__ifblocks [- 1 ] #opposite of last if
@@ -254,7 +284,7 @@ def lexer(self, line):
254
284
self .__ifblocks .pop (- 1 )
255
285
self .__ifconditions .pop (- 1 )
256
286
# do ifdef
257
- self .__ifblocks .append (self .search_defines (line .split ()[1 ]))
287
+ self .__ifblocks .append (self .__is_defined (line .split ()[1 ]))
258
288
self .__ifconditions .append (line .split ()[1 ])
259
289
260
290
elif self .__is_directive (line , 'endifall' , 1 ):
0 commit comments