Skip to content

Commit a74becf

Browse files
author
Laurent Pinson
committed
added overload option, improved evaluation of lines
1 parent b201217 commit a74becf

File tree

2 files changed

+53
-21
lines changed

2 files changed

+53
-21
lines changed

pypreprocessor/__init__.py

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,24 @@
1111
import imp
1212
import io
1313
import collections
14+
import re
1415

1516
#support for <=0.7.7
1617
class customDict(dict):
1718
def append(self, var):
18-
self[var]=None
19+
self[var]=True
1920

2021

2122
class preprocessor:
2223
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):
2426
# public variables
2527
self.defines = customDict()
2628
#support for <=0.7.7
2729
if isinstance(defines, collections.Sequence):
2830
for x in defines:
29-
self.defines.append(x)
31+
self.define(x)
3032
else:
3133
for x,y in defines:
3234
self.define(x,y)
@@ -39,6 +41,7 @@ def __init__(self, inFile=sys.argv[0], outFile='', defines={}, removeMeta=False,
3941
self.run = run
4042
self.resume = resume
4143
self.save = save
44+
self.overload = overload
4245
self.readEncoding = sys.stdin.encoding
4346
self.writeEncoding = sys.stdout.encoding
4447

@@ -88,15 +91,20 @@ def __reset_internal(self):
8891
self.__ifblocks = [] # contains the evaluated if conditions
8992
self.__ifconditions = [] # contains the if conditions
9093
self.__outputBuffer = ''
94+
self.__overloaded = list(self.defines.keys()) if self.overload else []
9195

92-
def define(self, define, val=None):
96+
97+
def define(self, name, val=True):
9398
"""
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.
95100
The directive can contains no value as it would be tested with a #ifdef directive or
96101
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
97105
98106
:params
99-
define (str): definition name
107+
name (str): definition name
100108
101109
val (str): definition value when it exists. Default is None
102110
"""
@@ -106,7 +114,8 @@ def define(self, define, val=None):
106114
except:
107115
# assume val is string
108116
pass
109-
self.defines[define]=val
117+
if name not in self.__overloaded:
118+
self.defines[name]=val
110119

111120
def undefine(self, define):
112121
"""
@@ -119,7 +128,7 @@ def undefine(self, define):
119128
if define in self.defines:
120129
self.defines.pop(define)
121130

122-
def search_defines(self, define):
131+
def __is_defined(self, define):
123132
"""
124133
Checks variable is defined as used in #ifdef, #ifnotdef & #elseif directives
125134
@@ -129,7 +138,7 @@ def search_defines(self, define):
129138
"""
130139
return define in self.defines
131140

132-
def evaluate(self, line):
141+
def __evaluate_if(self, line):
133142
"""
134143
Evaluate the content of a #if, #elseif, #elif directive
135144
@@ -138,7 +147,9 @@ def evaluate(self, line):
138147
139148
"""
140149
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
142153
except BaseException as e:
143154
print(str(e))
144155
self.exit_error(self.escape + 'if')
@@ -173,6 +184,21 @@ def __is_directive(self, line, directive, *size):
173184
return True
174185
return False
175186

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+
176202
def lexer(self, line):
177203
"""
178204
Analyse the `line`. This method attempts to find a known directive and, when found, to
@@ -187,6 +213,7 @@ def lexer(self, line):
187213
metadata (bool): is this line a directive?
188214
189215
"""
216+
line = line.strip()
190217
if not (self.__ifblocks or self.__excludeblock):
191218
if 'pypreprocessor.parse()' in line:
192219
return True, True
@@ -196,7 +223,10 @@ def lexer(self, line):
196223
# exclude=True if we are in an exclude block or the ifs are not validated
197224
return self.__excludeblock or not self.__validate_ifs(), False
198225

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):
200230
self.define(*line.split()[1:])
201231

202232
elif self.__is_directive(line, 'undef', 2):
@@ -212,15 +242,15 @@ def lexer(self, line):
212242
elif self.__is_directive(line, 'ifdefnot', 2) or \
213243
self.__is_directive(line, 'ifnotdef', 2) or \
214244
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]))
216246
self.__ifconditions.append(line.split()[1])
217247

218248
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]))
220250
self.__ifconditions.append(line.split()[1])
221251

222252
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:])))
224254
self.__ifconditions.append(' '.join(line.split()[1:]))
225255

226256
# since in version <=0.7.7, it didn't handle #if it should be #elseifdef instead.
@@ -232,18 +262,18 @@ def lexer(self, line):
232262
# do if
233263
if len(line.split()) == 2:
234264
#old behaviour
235-
self.__ifblocks.append(self.search_defines(line.split()[1]))
265+
self.__ifblocks[-1] = self.__is_defined(line.split()[1])
236266
else:
237267
#new behaviour
238-
self.__ifblocks.append(self.evaluate(' '.join(line.split()[1:])))
268+
self.__ifblocks[-1] = self.__evaluate_if(' '.join(line.split()[1:]))
239269
self.__ifconditions.append(' '.join(line.split()[1:]))
240270

241271
elif self.__is_directive(line, 'elseifdef', 2):
242272
# do else
243273
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:]))
247277

248278
elif self.__is_directive(line, 'else', 1):
249279
self.__ifblocks[-1] = not self.__ifblocks[-1] #opposite of last if
@@ -254,7 +284,7 @@ def lexer(self, line):
254284
self.__ifblocks.pop(-1)
255285
self.__ifconditions.pop(-1)
256286
# do ifdef
257-
self.__ifblocks.append(self.search_defines(line.split()[1]))
287+
self.__ifblocks.append(self.__is_defined(line.split()[1]))
258288
self.__ifconditions.append(line.split()[1])
259289

260290
elif self.__is_directive(line, 'endifall', 1):

pypreprocessor/__main__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@
1616
action='store_true', default=False)
1717
parser.add_argument("-e", "--escape", help="define the escape sequence to use. Default is #")
1818
parser.add_argument("-d", "--define", help="list of variable to define", nargs='*')
19+
parser.add_argument("-o", "--overload", help="overload variable definition in the file by those \
20+
provided by --define", action='store_true', default=False)
1921
parser.add_argument("input", help="input file.")
2022
parser.add_argument("output", nargs='?', help="output file. Default is <input_basename>_out.<input_extension>")
2123
args = parser.parse_args()
2224

2325
p=preprocessor(inFile=args.input, mode=None, removeMeta=args.removeMeta, escapeChar=None,
24-
run=args.run, resume=False, save=True)
26+
run=args.run, resume=False, save=True, overload=args.overload)
2527
if args.output:
2628
p.define = args.output
2729
if args.define:

0 commit comments

Comments
 (0)