diff options
Diffstat (limited to 'tools/preprocessor.py')
-rw-r--r-- | tools/preprocessor.py | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/tools/preprocessor.py b/tools/preprocessor.py new file mode 100644 index 00000000..f5409cad --- /dev/null +++ b/tools/preprocessor.py @@ -0,0 +1,161 @@ +# -*- coding: utf-8 -*- + +# preprocessor.py - simple preprocessor for plugin template files +# This file is part of pluma +# +# Copyright (C) 2006 - Steve Frécinaux +# +# pluma is free software; you can redistribute it and/or modify +# 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. +# +# pluma is distributed in the hope that it will be useful, +# 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 +# along with pluma; if not, write to the Free Software +# 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: |