Skip to content

Commit

Permalink
solved issue #31
Browse files Browse the repository at this point in the history
  • Loading branch information
Laurent Pinson committed Dec 21, 2021
1 parent 40d0192 commit 2d05991
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 40 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ set the options of the preprocessor:
* resume: Return after a file is preprocessed and can preprocess a next file if true. Default is false
* save: Save preprocessed code if true. Default is true
* overload: Any defines added to the preprocessor will overload existing defines. Default is false
* quiet: no warning about ununderstood directives or missing #indef
* quiet: no warning about not understood directives or missing #indef

```python
pypreprocessor.input = 'inputFile.py'
Expand Down
66 changes: 36 additions & 30 deletions pypreprocessor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

__author__ = 'Evan Plaice'
__coauthor__ = 'Hendi O L, Epikem, Laurent Pinson'
__version__ = '0.8'
__version__ = '1.0'

import sys
import os
Expand All @@ -20,17 +20,19 @@ def append(self, var):


class preprocessor:
__overloaded = []
defines = customDict()

def __init__(self, inFile=sys.argv[0], outFile='', defines={}, removeMeta=False,
escapeChar=None, mode=None, escape='#', run=True, resume=False,
save=True, overload=True, quiet=False):
# public variables
self.defines = customDict()
#support for <=0.7.7
# support for <=0.7.7
if isinstance(defines, collections.Sequence):
for x in defines:
self.define(x)
self.define(*x.split(':'))
else:
for x,y in defines:
for x,y in defines.items():
self.define(x,y)
self.input = inFile
self.output = outFile
Expand Down Expand Up @@ -89,12 +91,16 @@ def deprecation(message):
def __reset_internal(self):
self.__linenum = 0
self.__excludeblock = False
self.__ifblocks = [] # contains the evaluated if conditions
self.__ifconditions = [] # contains the if conditions
# contains the evaluated if conditions
# due to the introduction of #elif, elements of __ifblocks are duos of boolean
# the 1st is the evaluation of the current #if or #elif or #else
# the 2nd indicates if at least one #if or #elif was True in the whole #if/#endif block
self.__ifblocks = []
# contains the if conditions
self.__ifconditions = []
self.__outputBuffer = ''
self.__overloaded = list(self.defines.keys()) if self.overload else []


def define(self, name, val=True):
"""
Adds variable definition to the store as expected from a #define directive.
Expand Down Expand Up @@ -164,7 +170,7 @@ def __validate_ifs(self):
"""
# no ifs mean we pass else check all ifs are True
return not self.__ifblocks or all(self.__ifblocks)
return not self.__ifblocks or all(x[0] for x in self.__ifblocks)

def __is_directive(self, line, directive, *size):
"""
Expand Down Expand Up @@ -243,41 +249,43 @@ def lexer(self, line):
elif self.__is_directive(line, 'ifdefnot', 2) or \
self.__is_directive(line, 'ifnotdef', 2) or \
self.__is_directive(line, 'ifndef', 2):
self.__ifblocks.append(not self.__is_defined(line.split()[1]))
_check = not self.__is_defined(line.split()[1])
self.__ifblocks.append([ _check, _check])
self.__ifconditions.append(line.split()[1])

elif self.__is_directive(line, 'ifdef', 2):
self.__ifblocks.append(self.__is_defined(line.split()[1]))
_check = self.__is_defined(line.split()[1])
self.__ifblocks.append([ _check, _check])
self.__ifconditions.append(line.split()[1])

elif self.__is_directive(line, 'if'):
self.__ifblocks.append(self.__evaluate_if(' '.join(line.split()[1:])))
_check = self.__evaluate_if(' '.join(line.split()[1:]))
self.__ifblocks.append([ _check, _check])
self.__ifconditions.append(' '.join(line.split()[1:]))

# since in version <=0.7.7, it didn't handle #if it should be #elseifdef instead.
# kept elseif with 2 elements for retro-compatibility (equivalent to #elseifdef).
elif self.__is_directive(line, 'elseif') or \
self.__is_directive(line, 'elif'):
# do else
self.__ifblocks[-1] = not self.__ifblocks[-1]
# do if
_cur, _whole = self.__ifblocks[-1]
if len(line.split()) == 2:
#old behaviour
self.__ifblocks[-1] = self.__is_defined(line.split()[1])
_check = self.__is_defined(line.split()[1])
else:
#new behaviour
self.__ifblocks[-1] = self.__evaluate_if(' '.join(line.split()[1:]))
self.__ifconditions.append(' '.join(line.split()[1:]))
_check = self.__evaluate_if(' '.join(line.split()[1:]))
self.__ifblocks[-1]=[ not _whole and _check, _whole or _check ]
self.__ifconditions[-1]=' '.join(line.split()[1:])

elif self.__is_directive(line, 'elseifdef', 2):
# do else
self.__ifblocks[-1] = not self.__ifblocks[-1]
# do if
self.__ifblocks[-1]=self.__is_defined(line.split()[1])
self.__ifconditions.append(' '.join(line.split()[1:]))
_cur, _whole = self.__ifblocks[-1]
_check = self.__is_defined(line.split()[1])
self.__ifblocks[-1]=[ not _whole and _check, _whole or _check ]
self.__ifconditions[-1]=' '.join(line.split()[1:])

elif self.__is_directive(line, 'else', 1):
self.__ifblocks[-1] = not self.__ifblocks[-1] #opposite of last if
_cur, _whole = self.__ifblocks[-1]
self.__ifblocks[-1] = [not _whole, not _whole] #opposite of the whole if/elif block

elif self.__is_directive(line, 'endififdef', 2):
# do endif
Expand All @@ -299,19 +307,17 @@ def lexer(self, line):
except ValueError as VE:
number = 1

if len(self.__ifconditions) >= number:
for i in range(0, number):
try:
while number:
self.__ifblocks.pop(-1)
self.__ifconditions.pop(-1)
else:
number-=1
except:
if not self.quiet:
print('Warning trying to remove more blocks than present',
self.input, self.__linenum)
self.__ifblocks = []
self.__ifconditions = []

else:
# unknown directive or comment
# escapechar + space ==> comment
# starts with #!/ ==> shebang
# else print warning
Expand Down
14 changes: 5 additions & 9 deletions pypreprocessor/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,26 @@
python -m """+__package__+""" table.json --escape #@ -d NUM:4 ID:1
""",
formatter_class=argparse.RawDescriptionHelpFormatter,
usage=' python -m '+__package__+' input [output] [-h] [-r] [-m] [-e ESCAPE] [-d [DEFINE ...]]',
usage=' python -m '+__package__+' input [output] [-h] [-r] [-m] [-e ESCAPE] [-o] [-q] [-d [DEFINE ...]]',
)
parser.add_argument("-r", "--run", help="Run on the fly",
parser.add_argument("-r", "--run", help="run on the fly",
action='store_true', default=False)
parser.add_argument("-m", "--removeMeta", help="remove meta lines from the output",
action='store_true', default=False)
parser.add_argument("-e", "--escape", help="define the escape sequence to use. Default is #")
parser.add_argument("-d", "--define", help="list of variable to define", nargs='*')
parser.add_argument("-d", "--define", help="list of constants to define", nargs='*', default=[])
parser.add_argument("-o", "--overload", help="overload variable definition in the file by those \
provided by --define", action='store_true', default=False)
parser.add_argument("-q", "--quiet", help="No warning on ununderstable directives and missign ending",
parser.add_argument("-q", "--quiet", help="No warning on not understood directives and missign ending",
action='store_true', default=False)
parser.add_argument("input", help="input file.")
parser.add_argument("output", nargs='?', help="output file. Default is <input_basename>_out.<input_extension>")
args = parser.parse_args()

p=preprocessor(inFile=args.input, mode=None, removeMeta=args.removeMeta, escapeChar=None,
p=preprocessor(inFile=args.input, defines=args.define, mode=None, removeMeta=args.removeMeta, escapeChar=None,
run=args.run, resume=False, save=True, overload=args.overload, quiet=args.quiet)
if args.output:
p.define = args.output
if args.define:
for elem in args.define:
p.define(*elem.split(':'))
self.__reset_internal() # not very pythonic
if args.escape:
p.escape = args.escape

Expand Down

0 comments on commit 2d05991

Please sign in to comment.