Initial commit of public repository open_pdks.
diff --git a/common/preproc.py b/common/preproc.py
new file mode 100755
index 0000000..1fca5be
--- /dev/null
+++ b/common/preproc.py
@@ -0,0 +1,576 @@
+#!/usr/bin/env python3
+#--------------------------------------------------------------------
+#
+# preproc.py
+#
+# General purpose macro preprocessor
+#
+#--------------------------------------------------------------------
+# Usage:
+#
+# preproc.py input_file [output_file] [-D<variable> ...]
+#
+# Where <variable> may be a keyword or a key=value pair
+#
+# Syntax: Basically like cpp. However, this preprocessor handles
+# only a limited set of keywords, so it does not otherwise mangle
+# the file in the belief that it must be C code. Handling of boolean
+# relations is important, so these are thoroughly defined (see below)
+#
+# #if defined(<variable>) [...]
+# #ifdef <variable>
+# #ifndef <variable>
+# #elseif <variable>
+# #else
+# #endif
+#
+# #define <variable> [...]
+# #define <variable>(<parameters>) [...]
+# #undef <variable>
+#
+# #include <filename>
+#
+# <variable> may be
+# <keyword>
+# <keyword>=<value>
+#
+# <keyword> without '=' is effectively the same as <keyword>=1
+# Lack of a keyword is equivalent to <keyword>=0, in a conditional.
+#
+# Boolean operators (in order of precedence):
+# ! NOT
+# && AND
+# || OR
+#
+# Comments:
+# Most comments (C-like or Tcl-like) are output as-is. A
+# line beginning with "###" is treated as a preprocessor
+# comment and is not copied to the output.
+#
+# Examples;
+# #if defined(X) || defined(Y)
+# #else
+# #if defined(Z)
+# #endif
+#--------------------------------------------------------------------
+
+import re
+import sys
+
+def solve_statement(condition):
+
+ defrex = re.compile('defined[ \t]*\(([^\)]+)\)')
+ orrex = re.compile('(.+)\|\|(.+)')
+ andrex = re.compile('(.+)&&(.+)')
+ notrex = re.compile('!([^&\|]+)')
+ parenrex = re.compile('\(([^\)]+)\)')
+ leadspacerex = re.compile('^[ \t]+(.*)')
+ endspacerex = re.compile('(.*)[ \t]+$')
+
+ matchfound = True
+ while matchfound:
+ matchfound = False
+
+ # Search for defined(K) (K must be a single keyword)
+ # If the keyword was defined, then it should have been replaced by 1
+ lmatch = defrex.search(condition)
+ if lmatch:
+ key = lmatch.group(1)
+ if key == 1 or key == '1' or key == True:
+ repl = 1
+ else:
+ repl = 0
+
+ condition = defrex.sub(str(repl), condition)
+ matchfound = True
+
+ # Search for (X) recursively
+ lmatch = parenrex.search(condition)
+ if lmatch:
+ repl = solve_statement(lmatch.group(1))
+ condition = parenrex.sub(str(repl), condition)
+ matchfound = True
+
+ # Search for !X recursively
+ lmatch = notrex.search(condition)
+ if lmatch:
+ only = solve_statement(lmatch.group(1))
+ if only == '1':
+ repl = '0'
+ else:
+ repl = '1'
+ condition = notrex.sub(str(repl), condition)
+ matchfound = True
+
+ # Search for A&&B recursively
+ lmatch = andrex.search(condition)
+ if lmatch:
+ first = solve_statement(lmatch.group(1))
+ second = solve_statement(lmatch.group(2))
+ if first == '1' and second == '1':
+ repl = '1'
+ else:
+ repl = '0'
+ condition = andrex.sub(str(repl), condition)
+ matchfound = True
+
+ # Search for A||B recursively
+ lmatch = orrex.search(condition)
+ if lmatch:
+ first = solve_statement(lmatch.group(1))
+ second = solve_statement(lmatch.group(2))
+ if first == '1' or second == '1':
+ repl = '1'
+ else:
+ repl = '0'
+ condition = orrex.sub(str(repl), condition)
+ matchfound = True
+
+ # Remove whitespace
+ lmatch = leadspacerex.match(condition)
+ if lmatch:
+ condition = lmatch.group(1)
+ lmatch = endspacerex.match(condition)
+ if lmatch:
+ condition = lmatch.group(1)
+
+ return condition
+
+def solve_condition(condition, keys, defines, keyrex):
+ # Do definition replacement on the conditional
+ for keyword in keys:
+ condition = keyrex[keyword].sub(defines[keyword], condition)
+
+ value = solve_statement(condition)
+ if value == '1':
+ return 1
+ 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]+(.+)')
+ ifndefrex = re.compile('^[ \t]*#ifndef[ \t]+(.+)')
+ ifrex = re.compile('^[ \t]*#if[ \t]+(.+)')
+ elseifrex = re.compile('^[ \t]*#elseif[ \t]+(.+)')
+ elserex = re.compile('^[ \t]*#else')
+ endifrex = re.compile('^[ \t]*#endif')
+ commentrex = re.compile('^###[^#]*$')
+ ccstartrex = re.compile('/\*') # C-style comment start
+ 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]*.*')
+
+ # This code is not designed to operate on huge files. Neither is it designed to be
+ # efficient.
+
+ # ifblock state:
+ # -1 : not in an if/else block
+ # 0 : no condition satisfied yet
+ # 1 : condition satisfied
+ # 2 : condition was handled, waiting for endif
+
+ ifile = False
+ try:
+ ifile = open(inputfile, 'r')
+ except FileNotFoundError:
+ for dir in incdirs:
+ try:
+ ifile = open(dir + '/' + inputfile, 'r')
+ except FileNotFoundError:
+ pass
+ else:
+ break
+
+ if not ifile:
+ print("Error: Cannot open file " + inputfile + " for reading.\n", file=sys.stderr)
+ return
+
+ ccblock = -1
+ ifblock = -1
+ ifstack = []
+ lineno = 0
+
+ filetext = ifile.readlines()
+ lastline = []
+
+ for line in filetext:
+ lineno += 1
+
+ # C-style comments override everything else
+ if ccomm:
+ if ccblock == -1:
+ pmatch = ccstartrex.search(line)
+ if pmatch:
+ ematch = ccendrex.search(line[pmatch.end(0):])
+ if ematch:
+ line = line[0:pmatch.start(0)] + line[pmatch.end(0) + ematch.end(0):]
+ else:
+ line = line[0:pmatch.start(0)]
+ ccblock = 1
+ elif ccblock == 1:
+ ematch = ccendrex.search(line)
+ if ematch:
+ line = line[ematch.end(0)+2:]
+ ccblock = -1
+ 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 ifdef
+ pmatch = ifdefrex.match(line)
+ if pmatch:
+ if cmatch:
+ lastline = line
+ continue
+ if ifblock != -1:
+ ifstack.append(ifblock)
+
+ if ifblock == 1 or ifblock == -1:
+ condition = pmatch.group(1)
+ ifblock = solve_condition(condition, keys, defines, keyrex)
+ else:
+ ifblock = 2
+ continue
+
+ # Handle ifndef
+ pmatch = ifndefrex.match(line)
+ if pmatch:
+ if cmatch:
+ lastline = line
+ continue
+ if ifblock != -1:
+ ifstack.append(ifblock)
+
+ if ifblock == 1 or ifblock == -1:
+ condition = pmatch.group(1)
+ ifblock = solve_condition(condition, keys, defines, keyrex)
+ ifblock = 1 if ifblock == 0 else 0
+ else:
+ ifblock = 2
+ continue
+
+ # Handle if
+ pmatch = ifrex.match(line)
+ if pmatch:
+ if cmatch:
+ lastline = line
+ continue
+ if ifblock != -1:
+ ifstack.append(ifblock)
+
+ if ifblock == 1 or ifblock == -1:
+ condition = pmatch.group(1)
+ ifblock = solve_condition(condition, keys, defines, keyrex)
+ else:
+ ifblock = 2
+ continue
+
+ # 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) + ".", file=sys.stderr)
+ ifblock = 0
+
+ if ifblock == 1:
+ ifblock = 2
+ elif ifblock != 2:
+ condition = pmatch.group(1)
+ ifblock = solve_condition(condition, keys, defines, keyrex)
+ continue
+
+ # 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) + ".", file=sys.stderr)
+ ifblock = 0
+
+ if ifblock == 1:
+ ifblock = 2
+ elif ifblock == 0:
+ ifblock = 1
+ continue
+
+ # 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)", file=sys.stderr)
+ elif ifstack:
+ ifblock = ifstack.pop()
+ else:
+ ifblock = -1
+ continue
+
+ # 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)", file=sys.stderr)
+ if ifblock != -1:
+ ifstack.append(ifblock)
+
+ if ifblock == 1 or ifblock == -1:
+ ifblock = 0
+ else:
+ ifblock = 2
+ continue
+
+ pmatch = badelserex.match(line)
+ if pmatch:
+ print("Error: Badly formed #else statement at line " + str(lineno) + " (ignored)", file=sys.stderr)
+ ifblock = 2
+ continue
+
+ # Ignore all lines that are not satisfied by a conditional
+ 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)
+ # 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.", file=sys.stderr)
+
+ if ifile != sys.stdin:
+ ifile.close()
+ return
+
+def printusage(progname):
+ print('Usage: ' + progname + ' input_file [output_file] [-options]')
+ print(' Options are:')
+ print(' -help Print this help text.')
+ print(' -ccomm Remove C comments in /* ... */ delimiters.')
+ print(' -D<def> Define word <def> and set its value to 1.')
+ print(' -D<def>=<val> Define word <def> and set its value to <val>.')
+ print(' -I<dir> Add <dir> to search path for input files.')
+ return
+
+if __name__ == '__main__':
+
+ # Parse command line for options and arguments
+ options = []
+ arguments = []
+ for item in sys.argv[1:]:
+ if item.find('-', 0) == 0:
+ options.append(item)
+ else:
+ arguments.append(item)
+
+ if len(arguments) > 0:
+ inputfile = arguments[0]
+ if len(arguments) > 1:
+ outputfile = arguments[1]
+ else:
+ outputfile = []
+ else:
+ printusage(sys.argv[0])
+ sys.exit(0)
+
+ defines = {}
+ keyrex = {}
+ keys = []
+ incdirs = []
+ ccomm = False
+ for item in options:
+ result = item.split('=')
+ if result[0] == '-help':
+ printusage(sys.argv[0])
+ sys.exit(0)
+ elif result[0] == '-ccomm':
+ ccomm = True
+ elif result[0][0:2] == '-I':
+ incdirs.append(result[0][2:])
+ elif result[0][0:2] == '-D':
+ keyword = result[0][2:]
+ try:
+ value = result[1]
+ except:
+ value = '1'
+ 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)
+
+ if outputfile:
+ ofile = open(outputfile, 'w')
+ else:
+ ofile = sys.stdout
+
+ if not ofile:
+ 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()
+ sys.exit(0)