#!/usr/bin/env python import os import re import sys import string from pprint import * 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_]\w*)') 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, "rt") 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, "wt") 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, "wt") 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 if not os.fork(): os.execvp ("qfcc", args) else: os.wait() if not no_delete: for l in qcc_list: os.unlink (l) os.unlink (progs_src)