mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-24 13:21:11 +00:00
297 lines
7.3 KiB
Python
Executable file
297 lines
7.3 KiB
Python
Executable file
#!/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)
|