Finally rid myself of the C preprocessor. Took a moderately-developed

preproc.py script from another project.  Had to further develop it to
get around the amazingly complicated preprocessor usage in the scmos
subdirectory.  Needed to add handling of parameterized definitions;
could not figure out how to align the syntax used in scmos/extract_template
with any consistent syntax.  Gave up and rewrote some of the contents of
extract_template to avoid the more ambiguous usage.  All of this is to
support a completely deprecated scmos.tech.  However, it does avoid both
the M4 and cpp preprocessors altogether.  Also did auto-detection of
python3 in the configure script for use of the preproc.py preprocessor,
and applied the same preprocessor to the macro definitions.
This commit is contained in:
Tim Edwards
2020-02-19 14:25:58 -05:00
parent 6049b7e00e
commit 2db6a6849a
15 changed files with 436 additions and 3577 deletions
+99 -125
View File
@@ -628,7 +628,7 @@ OA_LIBS
OA
MAGIC_REVISION
MAGIC_VERSION
SCPP
MSED
MCPP
LD_RUN_PATH
SHLIB_CFLAGS
@@ -672,12 +672,11 @@ X_LIBS
X_PRE_LIBS
X_CFLAGS
XMKMF
PYTHON3
CSH
GCORE
EGREP
GREP
PYTHON3
M4
RANLIB
INSTALL_DATA
INSTALL_SCRIPT
@@ -4038,114 +4037,6 @@ else
fi
for ac_prog in gm4 gnum4 m4
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_path_M4+:} false; then :
$as_echo_n "(cached) " >&6
else
case $M4 in
[\\/]* | ?:[\\/]*)
ac_cv_path_M4="$M4" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_path_M4="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
fi
M4=$ac_cv_path_M4
if test -n "$M4"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $M4" >&5
$as_echo "$M4" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
test -n "$M4" && break
done
test -n "$M4" || M4="no"
if test x$M4 = xno; then
as_fn_error $? "M4 is required" "$LINENO" 5
fi
# Extract the first word of "python3", so it can be a program name with args.
set dummy python3; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_path_PYTHON3+:} false; then :
$as_echo_n "(cached) " >&6
else
case $PYTHON3 in
[\\/]* | ?:[\\/]*)
ac_cv_path_PYTHON3="$PYTHON3" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_path_PYTHON3="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
test -z "$ac_cv_path_PYTHON3" && ac_cv_path_PYTHON3="no"
;;
esac
fi
PYTHON3=$ac_cv_path_PYTHON3
if test -n "$PYTHON3"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON3" >&5
$as_echo "$PYTHON3" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
if test "x${PYTHON3}" == "x"; then
if test "$CPP" = "$CC -E" ; then
MCPP="$CPP -x c"
fi
else
MCPP="\${MAGICDIR}/scripts/preproc.py"
fi
if test "$CPP" = "$CC -E" ; then
SCPP="$CPP -x c"
else
SCPP="$CPP"
fi
#------------------------------------------------------------
# AC_PROG_LD - find the path to the GNU or non-GNU linker
@@ -5343,6 +5234,7 @@ use_libglu="-lGLU"
usingTcl=1
usingOA=0
usingCairo=1
usingPython3=1
# Extract the first word of "gcore", so it can be a program name with args.
@@ -5434,6 +5326,65 @@ if test "x${CSH}" = "x"; then
as_fn_error $? "cannot find /bin/csh---cannot compile!" "$LINENO" 5
fi
# Extract the first word of "python3", so it can be a program name with args.
set dummy python3; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_path_PYTHON3+:} false; then :
$as_echo_n "(cached) " >&6
else
case $PYTHON3 in
[\\/]* | ?:[\\/]*)
ac_cv_path_PYTHON3="$PYTHON3" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_path_PYTHON3="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
test -z "$ac_cv_path_PYTHON3" && ac_cv_path_PYTHON3="no"
;;
esac
fi
PYTHON3=$ac_cv_path_PYTHON3
if test -n "$PYTHON3"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON3" >&5
$as_echo "$PYTHON3" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
if test "x${PYTHON3}" == "x"; then
usingPython3=
if test "$CPP" = "$CC -E" ; then
MCPP="$CPP -x c"
MSED="sed -e 's/\\/\\\\/'"
else
MCPP="$CPP"
MSED="sed -e 's/\\/\\\\/'"
fi
else
MCPP="\${MAGICDIR}/scripts/preproc.py -ccomm"
MSED="cat"
usingPython3=1
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for X" >&5
$as_echo_n "checking for X... " >&6; }
@@ -9470,6 +9421,19 @@ else
echo
fi
${ECHO_N} "Python3: "
if test $usingPython3 ; then
echo "yes"
else
echo "no"
echo
echo " Magic installation will use the gcc preprocessor for forming"
echo " the default SCMOS technology files and the macro definitions."
echo " This usually works, but in case of preprocessor failure, you"
echo " may need python3 installed."
echo
fi
${ECHO_N} "OpenGL: "
if test $usingOGL ; then
echo "yes"
@@ -9482,14 +9446,18 @@ if test $usingOGL ; then
else
echo "no"
echo
echo " OpenGL graphics are considerably better than the standard 8-bit"
echo " and 24-bit X11 graphics, provided that you have a video card and"
echo " driver supporting accelerated OpenGL graphics. If you get this"
echo " message, you may need to download OpenGL libraries and header"
echo " files, which are usually available from the video card manufacturer."
echo " Magic with un-accelerated OpenGL, such as using Mesa GL without"
echo " a supported graphics card, is usually a very bad combination."
echo
if test $usingCairo ; then
echo " Cairo graphics are available so OpenGL is purely optional."
else
echo " OpenGL graphics are considerably better than the standard 8-bit"
echo " and 24-bit X11 graphics, provided that you have a video card and"
echo " driver supporting accelerated OpenGL graphics. If you get this"
echo " message, you may need to download OpenGL libraries and header"
echo " files, which are usually available from the video card manufacturer."
echo " Magic with un-accelerated OpenGL, such as using Mesa GL without"
echo " a supported graphics card, is usually a very bad combination."
echo
fi
fi
${ECHO_N} "Cairo: "
@@ -9498,12 +9466,18 @@ if test $usingCairo ; then
else
echo "no"
echo
echo " Cairo graphics are considerably better than the standard 8-bit"
echo " and 24-bit X11 graphics, provided that you have a video card and"
echo " driver supporting hardware-accelerated graphics. If you get this"
echo " message, you may need to download Cairo and fontconfig libraries"
echo " and header files, which are usually found in package cairo-devel."
echo
if test $usingOGL ; then
echo " OpenGL graphics are available so Cairo is purely optional"
echo " unless there are issues with the video card driver's"
echo " implementation of OpenGL."
else
echo " Cairo graphics are considerably better than the standard 8-bit"
echo " and 24-bit X11 graphics, provided that you have a video card and"
echo " driver supporting hardware-accelerated graphics. If you get this"
echo " message, you may need to download Cairo and fontconfig libraries"
echo " and header files, which are usually found in package cairo-devel."
echo
fi
fi
if test $usingTcl ; then
+65 -46
View File
@@ -28,37 +28,6 @@ AC_ISC_POSIX
AC_PROG_INSTALL
AC_PROG_RANLIB
dnl GNU M4 is preferred due to some of the option switches.
AC_PATH_PROGS([M4], [gm4 gnum4 m4], [no])
if test x$M4 = xno; then
AC_MSG_ERROR([M4 is required])
fi
dnl Python3 is preferred for running the preprocessor script
dnl but CPP can be used instead.
AC_PATH_PROG([PYTHON3], [python3], [no])
if test "x${PYTHON3}" == "x"; then
dnl check size of pointer for correct behavior on 64-bit systems
dnl If the C preprocessor is GCC, we need to force the flag to
dnl assert that input files are of type C, or else the preprocessing
dnl stage will not execute correctly on the ".in" files in the scmos
dnl directory.
if test "$CPP" = "$CC -E" ; then
MCPP="$CPP -x c"
fi
else
MCPP="\${MAGICDIR}/scripts/preproc.py"
fi
if test "$CPP" = "$CC -E" ; then
SCPP="$CPP -x c"
else
SCPP="$CPP"
fi
dnl check if the linker is a GNU linker
#------------------------------------------------------------
@@ -306,6 +275,7 @@ use_libglu="-lGLU"
usingTcl=1
usingOA=0
usingCairo=1
usingPython3=1
dnl Check for gcore, used by niceabort.c
@@ -321,6 +291,32 @@ if test "x${CSH}" = "x"; then
AC_MSG_ERROR([cannot find /bin/csh---cannot compile!])
fi
dnl Python3 is preferred for running the preprocessor script
dnl but CPP can be used instead.
AC_PATH_PROG([PYTHON3], [python3], [no])
if test "x${PYTHON3}" == "x"; then
dnl check size of pointer for correct behavior on 64-bit systems
dnl If the C preprocessor is GCC, we need to force the flag to
dnl assert that input files are of type C, or else the preprocessing
dnl stage will not execute correctly on the ".in" files in the scmos
dnl directory.
usingPython3=
if test "$CPP" = "$CC -E" ; then
MCPP="$CPP -x c"
MSED="sed -e 's/\\/\\\\/'"
else
MCPP="$CPP"
MSED="sed -e 's/\\/\\\\/'"
fi
else
MCPP="\${MAGICDIR}/scripts/preproc.py -ccomm"
MSED="cat"
usingPython3=1
fi
dnl Check for X enabled/disabled
AC_PATH_XTRA
@@ -1802,7 +1798,7 @@ AC_SUBST(DEPEND_FLAG)
AC_SUBST(SHLIB_CFLAGS)
AC_SUBST(LD_RUN_PATH)
AC_SUBST(MCPP)
AC_SUBST(SCPP)
AC_SUBST(MSED)
AC_SUBST(MAGIC_VERSION)
AC_SUBST(MAGIC_REVISION)
@@ -1839,6 +1835,19 @@ else
echo
fi
${ECHO_N} "Python3: "
if test $usingPython3 ; then
echo "yes"
else
echo "no"
echo
echo " Magic installation will use the gcc preprocessor for forming"
echo " the default SCMOS technology files and the macro definitions."
echo " This usually works, but in case of preprocessor failure, you"
echo " may need python3 installed."
echo
fi
${ECHO_N} "OpenGL: "
if test $usingOGL ; then
echo "yes"
@@ -1851,14 +1860,18 @@ if test $usingOGL ; then
else
echo "no"
echo
echo " OpenGL graphics are considerably better than the standard 8-bit"
echo " and 24-bit X11 graphics, provided that you have a video card and"
echo " driver supporting accelerated OpenGL graphics. If you get this"
echo " message, you may need to download OpenGL libraries and header"
echo " files, which are usually available from the video card manufacturer."
echo " Magic with un-accelerated OpenGL, such as using Mesa GL without"
echo " a supported graphics card, is usually a very bad combination."
echo
if test $usingCairo ; then
echo " Cairo graphics are available so OpenGL is purely optional."
else
echo " OpenGL graphics are considerably better than the standard 8-bit"
echo " and 24-bit X11 graphics, provided that you have a video card and"
echo " driver supporting accelerated OpenGL graphics. If you get this"
echo " message, you may need to download OpenGL libraries and header"
echo " files, which are usually available from the video card manufacturer."
echo " Magic with un-accelerated OpenGL, such as using Mesa GL without"
echo " a supported graphics card, is usually a very bad combination."
echo
fi
fi
${ECHO_N} "Cairo: "
@@ -1867,12 +1880,18 @@ if test $usingCairo ; then
else
echo "no"
echo
echo " Cairo graphics are considerably better than the standard 8-bit"
echo " and 24-bit X11 graphics, provided that you have a video card and"
echo " driver supporting hardware-accelerated graphics. If you get this"
echo " message, you may need to download Cairo and fontconfig libraries"
echo " and header files, which are usually found in package cairo-devel."
echo
if test $usingOGL ; then
echo " OpenGL graphics are available so Cairo is purely optional"
echo " unless there are issues with the video card driver's"
echo " implementation of OpenGL."
else
echo " Cairo graphics are considerably better than the standard 8-bit"
echo " and 24-bit X11 graphics, provided that you have a video card and"
echo " driver supporting hardware-accelerated graphics. If you get this"
echo " message, you may need to download Cairo and fontconfig libraries"
echo " and header files, which are usually found in package cairo-devel."
echo
fi
fi
if test $usingTcl ; then
+1 -2
View File
@@ -58,9 +58,8 @@ AR = ar
ARFLAGS = crv
LINK = ld -r
LD = @LD@
M4 = @M4@
MCPP = @MCPP@
SCPP = @SCPP@
MSED = @MSED@
RANLIB = @RANLIB@
SHDLIB_EXT = @SHDLIB_EXT@
LDDL_FLAGS = ${LDFLAGS} @LDDL_FLAGS@
+177 -53
View File
@@ -1,4 +1,4 @@
#!/usr/bin/python3
#!/usr/bin/env python3
#--------------------------------------------------------------------
#
# preproc.py
@@ -25,6 +25,7 @@
# #endif
#
# #define <variable> [...]
# #define <variable>(<parameters>) [...]
# #undef <variable>
#
# #include <filename>
@@ -146,10 +147,27 @@ def solve_condition(condition, keys, defines, keyrex):
else:
return 0
def sortkeys(keys):
newkeys = []
for i in range(0, len(keys)):
keyword = keys[i]
found = False
for j in range(0, len(newkeys)):
inword = newkeys[j]
if inword in keyword:
# Insert keyword before inword
newkeys.insert(j, keyword)
found = True
break
if not found:
newkeys.append(keyword)
return newkeys
def runpp(keys, keyrex, defines, ccomm, incdirs, inputfile, ofile):
includerex = re.compile('^[ \t]*#include[ \t]+"*([^ \t\n\r"]+)')
definerex = re.compile('^[ \t]*#define[ \t]+([^ \t]+)[ \t]+(.+)')
paramrex = re.compile('^([^\(]+)\(([^\)]+)\)')
defrex = re.compile('^[ \t]*#define[ \t]+([^ \t\n\r]+)')
undefrex = re.compile('^[ \t]*#undef[ \t]+([^ \t\n\r]+)')
ifdefrex = re.compile('^[ \t]*#ifdef[ \t]+(.+)')
@@ -160,7 +178,8 @@ def runpp(keys, keyrex, defines, ccomm, incdirs, inputfile, ofile):
endifrex = re.compile('^[ \t]*#endif')
commentrex = re.compile('^###[^#]*$')
ccstartrex = re.compile('/\*') # C-style comment start
ccendrex = re.compile('\*/') # C-style comment end
ccendrex = re.compile('\*/') # C-style comment end
contrex = re.compile('.*\\\\$') # Backslash continuation line
badifrex = re.compile('^[ \t]*#if[ \t]*.*')
badelserex = re.compile('^[ \t]*#else[ \t]*.*')
@@ -187,7 +206,7 @@ def runpp(keys, keyrex, defines, ccomm, incdirs, inputfile, ofile):
break
if not ifile:
print("Error: Cannot open file " + inputfile + " for reading.\n")
print("Error: Cannot open file " + inputfile + " for reading.\n", file=sys.stderr)
return
ccblock = -1
@@ -196,6 +215,8 @@ def runpp(keys, keyrex, defines, ccomm, incdirs, inputfile, ofile):
lineno = 0
filetext = ifile.readlines()
lastline = []
for line in filetext:
lineno += 1
@@ -206,7 +227,7 @@ def runpp(keys, keyrex, defines, ccomm, incdirs, inputfile, ofile):
if pmatch:
ematch = ccendrex.search(line[pmatch.end(0):])
if ematch:
line = line[0:pmatch.start(0)] + line[ematch.end(0)+2:]
line = line[0:pmatch.start(0)] + line[pmatch.end(0) + ematch.end(0):]
else:
line = line[0:pmatch.start(0)]
ccblock = 1
@@ -218,55 +239,31 @@ def runpp(keys, keyrex, defines, ccomm, incdirs, inputfile, ofile):
else:
continue
# Handle continuation detected in previous line
if lastline:
# Note: Apparently there is a character retained after the backslash,
# so strip the last two characters from the line.
line = lastline[0:-2] + line
lastline = []
# Continuation lines have the next highest priority. However, this
# script will attempt to keep continuation lines in the body of the
# text and only collapse lines where continuation lines occur in
# a preprocessor statement.
cmatch = contrex.match(line)
# Ignore lines beginning with "###"
pmatch = commentrex.match(line)
if pmatch:
continue
# Handle include. Note that this code does not expect or
# handle 'if' blocks that cross file boundaries.
pmatch = includerex.match(line)
if pmatch:
inclfile = pmatch.group(1)
runpp(keys, keyrex, defines, ccomm, incdirs, inclfile, ofile)
continue
# Handle define (with value)
pmatch = definerex.match(line)
if pmatch:
condition = pmatch.group(1)
value = pmatch.group(2)
defines[condition] = value
keyrex[condition] = re.compile(condition)
if condition not in keys:
keys.append(condition)
continue
# Handle define (simple case, no value)
pmatch = defrex.match(line)
if pmatch:
condition = pmatch.group(1)
print("Defrex condition is " + condition)
defines[condition] = '1'
keyrex[condition] = re.compile(condition)
if condition not in keys:
keys.append(condition)
print("Defrex value is " + defines[condition])
continue
# Handle undef
pmatch = undefrex.match(line)
if pmatch:
condition = pmatch.group(1)
if condition in keys:
defines.pop(condition)
keyrex.pop(condition)
keys.remove(condition)
continue
# Handle ifdef
pmatch = ifdefrex.match(line)
if pmatch:
if cmatch:
lastline = line
continue
if ifblock != -1:
ifstack.append(ifblock)
@@ -280,6 +277,9 @@ def runpp(keys, keyrex, defines, ccomm, incdirs, inputfile, ofile):
# Handle ifndef
pmatch = ifndefrex.match(line)
if pmatch:
if cmatch:
lastline = line
continue
if ifblock != -1:
ifstack.append(ifblock)
@@ -294,6 +294,9 @@ def runpp(keys, keyrex, defines, ccomm, incdirs, inputfile, ofile):
# Handle if
pmatch = ifrex.match(line)
if pmatch:
if cmatch:
lastline = line
continue
if ifblock != -1:
ifstack.append(ifblock)
@@ -307,8 +310,11 @@ def runpp(keys, keyrex, defines, ccomm, incdirs, inputfile, ofile):
# Handle elseif
pmatch = elseifrex.match(line)
if pmatch:
if cmatch:
lastline = line
continue
if ifblock == -1:
print("Error: #elseif without preceding #if at line " + str(lineno) + ".")
print("Error: #elseif without preceding #if at line " + str(lineno) + ".", file=sys.stderr)
ifblock = 0
if ifblock == 1:
@@ -321,8 +327,11 @@ def runpp(keys, keyrex, defines, ccomm, incdirs, inputfile, ofile):
# Handle else
pmatch = elserex.match(line)
if pmatch:
if cmatch:
lastline = line
continue
if ifblock == -1:
print("Error: #else without preceding #if at line " + str(lineno) + ".")
print("Error: #else without preceding #if at line " + str(lineno) + ".", file=sys.stderr)
ifblock = 0
if ifblock == 1:
@@ -334,8 +343,11 @@ def runpp(keys, keyrex, defines, ccomm, incdirs, inputfile, ofile):
# Handle endif
pmatch = endifrex.match(line)
if pmatch:
if cmatch:
lastline = line
continue
if ifblock == -1:
print("Error: #endif outside of #if block at line " + str(lineno) + " (ignored)")
print("Error: #endif outside of #if block at line " + str(lineno) + " (ignored)", file=sys.stderr)
elif ifstack:
ifblock = ifstack.pop()
else:
@@ -345,7 +357,7 @@ def runpp(keys, keyrex, defines, ccomm, incdirs, inputfile, ofile):
# Check for 'if' or 'else' that were not properly formed
pmatch = badifrex.match(line)
if pmatch:
print("Error: Badly formed #if statement at line " + str(lineno) + " (ignored)")
print("Error: Badly formed #if statement at line " + str(lineno) + " (ignored)", file=sys.stderr)
if ifblock != -1:
ifstack.append(ifblock)
@@ -357,7 +369,7 @@ def runpp(keys, keyrex, defines, ccomm, incdirs, inputfile, ofile):
pmatch = badelserex.match(line)
if pmatch:
print("Error: Badly formed #else statement at line " + str(lineno) + " (ignored)")
print("Error: Badly formed #else statement at line " + str(lineno) + " (ignored)", file=sys.stderr)
ifblock = 2
continue
@@ -365,15 +377,120 @@ def runpp(keys, keyrex, defines, ccomm, incdirs, inputfile, ofile):
if ifblock == 0 or ifblock == 2:
continue
# Handle include. Note that this code does not expect or
# handle 'if' blocks that cross file boundaries.
pmatch = includerex.match(line)
if pmatch:
if cmatch:
lastline = line
continue
inclfile = pmatch.group(1)
runpp(keys, keyrex, defines, ccomm, incdirs, inclfile, ofile)
continue
# Handle define (with value)
pmatch = definerex.match(line)
if pmatch:
if cmatch:
lastline = line
continue
condition = pmatch.group(1)
# Additional handling of definition w/parameters: #define X(a,b,c) ..."
rmatch = paramrex.match(condition)
if rmatch:
# 'condition' as a key into keyrex only needs to be unique.
# Use the definition word without everything in parentheses
condition = rmatch.group(1)
# 'pcondition' is the actual search regexp and must capture all
# the parameters individually for substitution
parameters = rmatch.group(2).split(',')
# Generate the regexp string to match comma-separate values
# Note that this is based on the cpp preprocessor, which
# apparently allows commas in arguments if surrounded by
# parentheses; e.g., "def(a, b, (c1,c2))". This is NOT
# handled.
pcondition = condition + '\('
for param in parameters[0:-1]:
pcondition += '(.*),'
pcondition += '(.*)\)'
# Generate the substitution string with group substitutions
pvalue = pmatch.group(2)
idx = 1
for param in parameters:
pvalue = pvalue.replace(param, '\g<' + str(idx) + '>')
idx = idx + 1
defines[condition] = pvalue
keyrex[condition] = re.compile(pcondition)
else:
parameters = []
value = pmatch.group(2)
# Note: Need to check for infinite recursion here, but it's tricky.
defines[condition] = value
keyrex[condition] = re.compile(condition)
if condition not in keys:
# Parameterized keys go to the front of the list
if parameters:
keys.insert(0, condition)
else:
keys.append(condition)
keys = sortkeys(keys)
continue
# Handle define (simple case, no value)
pmatch = defrex.match(line)
if pmatch:
if cmatch:
lastline = line
continue
condition = pmatch.group(1)
defines[condition] = '1'
keyrex[condition] = re.compile(condition)
if condition not in keys:
keys.append(condition)
keys = sortkeys(keys)
continue
# Handle undef
pmatch = undefrex.match(line)
if pmatch:
if cmatch:
lastline = line
continue
condition = pmatch.group(1)
if condition in keys:
defines.pop(condition)
keyrex.pop(condition)
keys.remove(condition)
continue
# Now do definition replacement on what's left (if anything)
for keyword in keys:
line = keyrex[keyword].sub(defines[keyword], line)
# This must be done repeatedly from the top until there are no
# more substitutions to make.
while True:
origline = line
for keyword in keys:
newline = keyrex[keyword].sub(defines[keyword], line)
if newline != line:
line = newline
break
if line == origline:
break
# Output the line
print(line, file=ofile, end='')
if ifblock != -1 or ifstack != []:
print("Error: input file ended with an unterminated #if block.")
print("Error: input file ended with an unterminated #if block.", file=sys.stderr)
if ifile != sys.stdin:
ifile.close()
@@ -433,6 +550,7 @@ if __name__ == '__main__':
defines[keyword] = value
keyrex[keyword] = re.compile(keyword)
keys.append(keyword)
keys = sortkeys(keys)
else:
print('Bad option ' + item + ', options are -help, -ccomm, -D<def> -I<dir>\n')
sys.exit(1)
@@ -446,6 +564,12 @@ if __name__ == '__main__':
print("Error: Cannot open file " + output_file + " for writing.")
sys.exit(1)
# Sort keys so that if any definition contains another definition, the
# subset word is handled last; otherwise the subset word will get
# substituted, screwing up the definition names in which it occurs.
keys = sortkeys(keys)
runpp(keys, keyrex, defines, ccomm, incdirs, inputfile, ofile)
if ofile != sys.stdout:
ofile.close()