#!/usr/bin/env python import os import re import sys import string from pprint import * #os.sapn*p* hack #swiped from Alexey Borzenkov snaury at gmail.com if (not (hasattr(os, 'spawnvpe') or hasattr(os, 'spawnvp')) and hasattr(os, 'spawnve') and hasattr(os, 'spawnv')): def _os__spawnvpe(mode, file, args, env=None): import sys from errno import ENOENT, ENOTDIR from os import path, spawnve, spawnv, environ, defpath, pathsep, error if env is not None: func = spawnve argrest = (args, env) else: func = spawnv argrest = (args,) env = environ head, tail = path.split(file) if head: return func(mode, file, *argrest) if 'PATH' in env: envpath = env['PATH'] else: envpath = defpath PATH = envpath.split(pathsep) if os.name == 'nt' or os.name == 'os2': PATH.insert(0, '') saved_exc = None saved_tb = None for dir in PATH: fullname = path.join(dir, file) try: return func(mode, fullname, *argrest) except error, e: tb = sys.exc_info()[2] if (e.errno != ENOENT and e.errno != ENOTDIR and saved_exc is None): saved_exc = e saved_tb = tb if saved_exc: raise error, saved_exc, saved_tb raise error, e, tb def _os_spawnvp(mode, file, args): return os._spawnvpe(mode, file, args) def _os_spawnvpe(mode, file, args, env): return os._spawnvpe(mode, file, args, env) def _os_spawnlp(mode, file, *args): return os._spawnvpe(mode, file, args) def _os_spawnlpe(mode, file, *args): return os._spawnvpe(mode, file, args[:-1], args[-1]) os._spawnvpe = _os__spawnvpe os.spawnvp = _os_spawnvp os.spawnvpe = _os_spawnvpe os.spawnlp = _os_spawnlp os.spawnlpe = _os_spawnlpe os.__all__.extend(["spawnvp", "spawnvpe", "spawnlp", "spawnlpe"]) #end os.sapn*p* hack string_re = re.compile (r'"(\\.|[^"\\])*"') comment_whole = re.compile (r'((/\*.*\*/)|//.*)') comment_start = re.compile (r'(/\*.*)') comment_end = re.compile (r'(.*\*/)') directive_re = re.compile ( r'^\s*#\s*(define|undef|include|includelist|endlist|ifdef|ifndef|endif|else|pragma)\b' + r'((\s*("[^"]*"|[^ \t\n\r\f\v/]+|/(?!/))+)?)' + r'((\s*("[^"]*"|[^ \t\n\r\f\v/]+|/(?!/))+)*)') macro_re = re.compile (r'#([A-Za-z_][0-9A-Za-z_]*)') arg_re = re.compile ( r'((\s*("[^"]*"|[^ \t\n\r\f\v/]+|/(?!/))+)?)' + r'((\s*("[^"]*"|[^ \t\n\r\f\v/]+|/(?!/))+)*)') current_file = [] source_list = [] qcc_list = [] defines = {} progs_dat = "progs.dat" progs_src = "progs.src" compile_this_file = 1 keep_newlines = 1 check_redefines = 1 verbose = 0 def append_file (filename): global current_file f = open (filename, "rb") lines = f.readlines () f.close () current_file.append ('# 1 "' + filename + '"') for i in range (len (lines)): lines[i] = string.rstrip (lines[i]) current_file = current_file + lines def parse_filename (args): m = arg_re.match (args) fname = string.strip (m.groups()[0]) if fname: if fname[0] == '"': fname = fname[1:] if fname[-1] == '"': fname = fname[:-1] return fname def parse_pragma (pragma, args): global progs_dat, progs_dat global compile_this_file, keep_newlines, check_redefines if pragma == 'PROGS_DAT': progs_dat = parse_filename (args) elif pragma == 'PROGS_SRC': progs_src = parse_filename (args) elif pragma == 'DONT_COMPILE_THIS_FILE': compile_this_file = 0 elif pragma == 'COMPILE_THIS_FILE': compile_this_file = 1 elif pragma == 'KEEP_NEWLINES': keep_newlines = parse_on_off (args) elif pragma == 'CHECK_REDEFINES': check_redefines = parse_on_off (args) elif pragma == 'CHECK_UNUSED_ON': pass elif pragma == 'CHECK_UNUSED_OFF': pass else: print "ignoring " + pragma def comment_string (string_list, start, end): i = 0 while i < len (string_list): if start <= string_list[i][1] and end >= string_list[i][2]: del string_list[i] continue i += 1 return string_list def parse_strings_and_comments (l, incomment): #print source_file + ":" + `i` + ":" + l string_list = [] s = string_re.search (l) while s: string_list.append ((l[s.start():s.end()], s.start(), s.end())) l = l[:s.start()] + ((s.end() - s.start()) * ' ') + l[s.end():] s = string_re.search (l) if incomment: s = comment_end.search (l) if s: l = (s.end() * ' ') + l[s.end():] incomment = 0 string_list = comment_string (string_list, s.start(), s.end()) else: string_list = comment_string (string_list, 0, len(l)) l = "" s = comment_whole.search (l) if s: l = l[:s.start()] + ((s.end() - s.start()) * ' ') + l[s.end():] string_list = comment_string (string_list, s.start(), s.end()) s = comment_start.search (l) if s: l = l[:s.start()] + ((s.end() - s.start()) * ' ') string_list = comment_string (string_list, s.start(), s.end()) incomment = 1 for str in string_list: l = l[:str[1]] + str[0] + l[str[2]:] #print l return l, incomment def do_preprogs_src (): global current_file current_file = [] condition = [1] incomment = 0 append_file ("preprogs.src") preprogs = current_file for p in preprogs: p, incomment = parse_strings_and_comments (p, incomment) m = directive_re.match (p) if (m): g = m.groups() directive = g[0] arg1 = string.strip (g[1]) margs = string.strip (g[4]) #pprint ((directive, arg1, margs)) if directive == 'pragma': if condition[-1]: parse_pragma (arg1, margs) elif directive == 'includelist': if condition[-1]: fname = parse_filename (arg1) if fname: source_list.append (fname) elif directive == 'endlist': pass elif directive == 'ifdef': condition.append (condition[-1]) if not defines.has_key (arg1): condition[-1]=0 elif directive == 'ifndef': condition.append (condition[-1]) if defines.has_key (arg1): condition[-1]=0 elif directive == 'else': condition[-1] = condition [-2] and not condition[-1] elif directive == 'endif': del condition[-1] else: if condition[-1]: print "ignoring " + p else: if condition[-1]: fname = parse_filename (p) if fname: source_list.append (fname) def include_file (fname): global current_file fname = parse_filename (fname) if fname: append_file (fname) def process_source (source_file): global compile_this_file, current_file if verbose: print source_file compile_this_file = 1 includelist = 0 incomment = 0 current_file = [] output = [] condition = [1] append_file (source_file) i = 0 while i < len (current_file): l = current_file[i] l, incomment = parse_strings_and_comments (l, incomment) m = directive_re.match (l) if (m): g = m.groups() directive = g[0] arg1 = string.strip (g[1]) margs = string.strip (g[4]) #pprint ((directive, arg1, margs)) if directive == 'pragma': if condition[-1]: parse_pragma (arg1, margs) elif directive == 'include': if condition[-1]: include_file (arg1) elif directive == 'includelist': if condition[-1]: include_file (arg1) includelist = 1 elif directive == 'endlist': if condition[-1]: includelist = 0 elif directive == 'define': if condition[-1]: defines[arg1] = margs elif directive == 'undef': if condition[-1]: if defines.has_key (arg1): del defines[arg1] elif directive == 'ifdef': condition.append (condition[-1]) if not defines.has_key (arg1): condition[-1]=0 elif directive == 'ifndef': condition.append (condition[-1]) if defines.has_key (arg1): condition[-1]=0 elif directive == 'else': condition[-1] = condition [-2] and not condition[-1] elif directive == 'endif': del condition[-1] else: if condition[-1]: print "ignoring " + l output.append ('//' + l) else: if (includelist): fname = parse_filename (l) if fname: include_file (fname) output.append ('//' + l) else: if not condition[-1]: l = '//##' + l else: s = macro_re.search (l) while s: id = s.groups()[0] if defines.has_key (id): l = (l[:s.start()] + defines[id] + l[s.end():]) s = macro_re.search (l) else: s = macro_re.search (l, s.start(1)) output.append (l) i = i + 1 if compile_this_file: fname = source_file + '.pqc' qcc_list.append (fname) f = open (fname, "wb") for l in output: f.write(l + '\n') f.close () no_delete = 0 use_cpp = 0 i = 0 while i < len (sys.argv): if sys.argv[i] == '--keep': no_delete = 1 del sys.argv[i] continue elif sys.argv[i] == '--verbose': verbose = 1; del sys.argv[i] continue elif sys.argv[i] == '--cpp': use_cpp = 1; del sys.argv[i] continue i = i + 1 do_preprogs_src () for s in source_list: if s[0]=='#': continue # preprocessor directive process_source (s) f = open (progs_src, "wb") f.write (progs_dat + '\n\n') for l in qcc_list: f.write(l + '\n') f.close () args = sys.argv[1:] if not verbose: args = ["--quiet"] + args if not use_cpp: args = ["-C", "no-cpp"] + args args = ["qfcc"] + args os.spawnvp (os.P_WAIT, "qfcc", args) if not no_delete: for l in qcc_list: os.unlink (l) os.unlink (progs_src)