xed/tools/preprocessor.py

162 lines
5.2 KiB
Python
Raw Permalink Normal View History

2014-01-29 09:07:41 -06:00
# -*- coding: utf-8 -*-
# preprocessor.py - simple preprocessor for plugin template files
2016-01-25 08:13:49 -06:00
# This file is part of xedit
2014-01-29 09:07:41 -06:00
#
# Copyright (C) 2006 - Steve Frécinaux
#
2016-01-25 08:13:49 -06:00
# xedit is free software; you can redistribute it and/or modify
2014-01-29 09:07:41 -06:00
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
2016-01-25 08:13:49 -06:00
# xedit is distributed in the hope that it will be useful,
2014-01-29 09:07:41 -06:00
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
2016-01-25 08:13:49 -06:00
# along with xedit; if not, write to the Free Software
2014-01-29 09:07:41 -06:00
# Foundation, Inc., 51 Franklin St, Fifth Floor,
# Boston, MA 02110-1301 USA
import sys
import re
class DeepnessException(Exception):
def __init__(self):
Exception.__init__(self)
statements = [re.compile("^##\s*%s\s*$" % pattern) for pattern in
['(?P<stmt>ifdef|ifndef)\s+(?P<key>[^\s]+)',
'(?P<stmt>elif|if)\s+(?P<expr>.+)',
'(?P<stmt>else|endif)',
'(?P<stmt>define)\s+(?P<key>[^\s]+)(\s+(?P<val>.+))?',
'(?P<stmt>undef)\s+(?P<key>[^\s]+)']]
variable = re.compile("##\((?P<name>[a-zA-Z_][a-zA-Z0-9_]*)(?P<mods>(\.[a-z]+)+)?\)")
def _eval(expr, macros):
return eval(expr,
{'defined': lambda x: macros.has_key(x)},
macros)
def _subvar(match, macros):
name = match.group('name')
if name in macros:
val = str(macros[name])
if val is None:
return ''
else:
return ''
mods = match.group('mods')
if mods is not None:
for mod in mods[1:].split('.'):
if mod == 'lower':
val = val.lower()
elif mod == 'upper':
val = val.upper()
elif mod == 'camel':
val = ''.join(i.capitalize()
for i in val.split('_'))
return val
def process(infile = sys.stdin, outfile = sys.stdout, macros = {}):
if not isinstance(infile, file):
infile = open(infile, mode = 'r')
close_infile = True
else:
close_infile = False
if not isinstance(outfile, file):
outfile = open(outfile, mode = 'w')
close_outfile = True
else:
close_outfile = False
deepness = 0
writing_disabled = None
for line in infile:
# Skip comments
if line[0:3].lower() == '##c':
continue
# Check whether current line is a preprocessor directive
for statement in statements:
match = statement.match(line)
if match: break
if match is not None:
stmt = match.group('stmt')
if stmt == "define":
if writing_disabled is None:
key = match.group('key')
val = match.group('val')
macros[key] = val
elif stmt == "undef":
if writing_disabled is None:
key = match.group('key')
if key in macros:
del macros[key]
elif stmt == "ifdef":
deepness += 1
if writing_disabled is None and \
match.group('key') not in macros:
writing_disabled = deepness
elif stmt == "ifndef":
deepness += 1
if writing_disabled is None and \
match.group('key') in macros:
writing_disabled = deepness
elif stmt == "if":
deepness += 1
if writing_disabled is None and \
not _eval(match.group('expr'), macros):
writing_disabled = deepness
elif stmt == "elif":
if deepness == 0:
raise DeepnessException()
if writing_disabled is None and \
not _eval(match.group('expr'), macros):
writing_disabled = deepness
elif writing_disabled == deepness:
writing_disabled = None
elif stmt == "else":
if deepness == 0:
raise DeepnessException()
if writing_disabled is None:
writing_disabled = deepness
elif writing_disabled == deepness:
writing_disabled = None
elif stmt == "endif":
if deepness == 0:
raise DeepnessException()
if writing_disabled is not None and \
writing_disabled == deepness:
writing_disabled = None
deepness -= 1
# Do variable substitution in the remaining lines
elif writing_disabled is None:
outfile.write(re.sub(variable,
lambda m: _subvar(m, macros),
line))
if deepness != 0:
raise DeepnessException()
if close_infile: infile.close()
if close_outfile: outfile.close()
# ex:ts=4:et: