Added a script that parses a SPICE file and prints the parameters that
are on the .subckt line, and the parameters that are internal to the
subcircuit in a .param statement.  Also, corrected spectre_to_spice.py
to not add braces around an expression that is already encapsulated by
single quotes, as that causes grief to ngspice.
diff --git a/common/print_subckt_params.py b/common/print_subckt_params.py
new file mode 100755
index 0000000..c8f75eb
--- /dev/null
+++ b/common/print_subckt_params.py
@@ -0,0 +1,243 @@
+#!/bin/env python3
+#
+# print_subckt_params.py --
+#
+# Print a list of subcircuit parameters, dividing them into those which
+# are declared on the subcircuit line, and those that are declared inside
+# the scope of the subcircuit.
+# 
+# The single argument is <path_to_input>
+# <path_to_input> should be the path to a single file.
+
+import os
+import sys
+import re
+import glob
+
+def usage():
+    print('print_subckt_params.py <path_to_input>')
+    print('where:')
+    print('   <path_to_input> is the path to the input file to parse')
+
+def parse_pins(line, debug):
+    # Regexp patterns
+    subrex = re.compile('\.subckt[ \t]+[^ \t]+[ \t]+(.*)')
+    parm1rex = re.compile('([^= \t]+)[ \t]*=[ \t]*[^ \t]+[ \t]*(.*)')
+    parm2rex = re.compile('([^= \t]+)[ \t]*(.*)')
+
+    params = []
+
+    pmatch = subrex.match(line)
+    if pmatch:
+        rest = pmatch.group(1)
+    else:
+        # Could not parse
+        return []
+
+    while rest != '':
+        if rest.startswith('$ '):
+            break
+        pmatch = parm1rex.match(rest)
+        if pmatch:
+            rest = pmatch.group(2)
+            params.append(pmatch.group(1))
+        else:
+            pmatch = parm2rex.match(rest)
+            if pmatch:
+                # This is a pin, so don't list it
+                rest = pmatch.group(2)
+
+    return params
+
+# Parse a parameter line for parameters, and divide into two parts,
+# returned as a list.  If a parameter name matches an entry in 'params',
+# it goes in the second list.  Otherwise, it goes in the first list.
+# The first list is returned as-is minus any parameters that were split
+# into the second list.  The second list must begin with '+', as it will
+# be output as a continuation line for the subcircuit.
+
+def param_parse(line, debug):
+    # Regexp patterns
+    parm1rex = re.compile('\.param[ \t]+(.*)')
+    parm2rex = re.compile('\+[ \t]*(.*)')
+    parm3rex = re.compile('([^= \t]+)[ \t]*=[ \t]*[^ \t]+[ \t]*(.*)')
+    parm4rex = re.compile('([^= \t]+)[ \t]*(.*)')
+
+    if debug:
+        print('Diagnostic:  param line in = "' + line + '"')
+
+    params = []
+
+    pmatch = parm1rex.match(line)
+    if pmatch:
+        rest = pmatch.group(1)
+    else:
+        pmatch = parm2rex.match(line)
+        if pmatch:
+            rest = pmatch.group(1)
+        else:
+            # Could not parse;  return list with line and empty string
+            return []
+
+    while rest != '':
+        if rest.startswith('$ '):
+            break
+        pmatch = parm3rex.match(rest)
+        if pmatch:
+            rest = pmatch.group(2)
+            params.append(pmatch.group(1))
+        else:
+            pmatch = parm4rex.match(rest)
+            if pmatch:
+                rest = pmatch.group(2)
+                params.append(pmatch.group(1))
+
+    return params
+
+def parse_file(in_file, debug):
+
+    # Regexp patterns
+    paramrex = re.compile('\.param[ \t]+(.*)')
+    subrex = re.compile('\.subckt[ \t]+([^ \t]+)[ \t]+([^ \t]*)')
+    modelrex = re.compile('\.model[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]+(.*)')
+    endsubrex = re.compile('\.ends[ \t]+(.+)')
+    increx = re.compile('\.include[ \t]+')
+
+    with open(in_file, 'r') as ifile:
+        inplines = ifile.read().splitlines()
+
+    insubckt = False
+    inparam = False
+    inmodel = False
+    inpinlist = False
+
+    pinparams = []
+    paramlist = []
+    subname = ''
+
+    for line in inplines:
+
+        # Item 1.  Handle comment lines
+        if line.startswith('*'):
+            continue
+
+        # Item 2.  Flag continuation lines.
+        if line.startswith('+'):
+            contline = True
+        else:
+            contline = False
+            if line.strip() != '':
+                if inpinlist:
+                    inpinlist = False
+                if inparam:
+                    inparam = False
+
+        # Item 3.  Handle blank lines like comment lines
+        if line.strip() == '':
+            continue
+
+        # Item 4.  Handle continuation lines
+        # Remove lines that have a continuation mark and nothing else.
+        if contline:
+            if inparam:
+                # Continue handling parameters
+                if insubckt:
+                    # Find subcircuit parameters and record what line they were found on
+                    if inpinlist:
+                        pinparams.extend(param_parse(line, debug))
+                    else:
+                        paramlist.extend(param_parse(line, debug))
+                            
+            continue
+
+        # Item 5.  Regexp matching
+
+        # parameters
+        pmatch = paramrex.match(line)
+        if pmatch:
+            inparam = True
+            if insubckt:
+                if inpinlist:
+                    inpinlist = False
+                # Find subcircuit parameters and record what line they were found on
+                paramlist.extend(param_parse(line, debug))
+            continue
+
+        # model
+        mmatch = modelrex.match(line)
+        if mmatch:
+            inmodel = 2
+            continue
+
+        if not insubckt:
+            # Things to parse if not in a subcircuit
+
+            imatch = subrex.match(line)
+            if imatch:
+                insubckt = True
+                inpinlist = True
+                subname = imatch.group(1)
+                pinparams = parse_pins(line, debug)
+                paramlist = []
+                continue
+
+        else:
+            ematch = endsubrex.match(line)
+            if ematch:
+                insubckt = False
+                inmodel = False
+                # Print out results
+                if debug:
+                    print('File: ', end='')
+                print(in_file)
+                if debug:
+                    print('Subcircuit: ', end='')
+                print(subname)
+                if debug:
+                    print('Callable parameters: ', end='')
+                if len(pinparams) > 0:
+                    print(' '.join(pinparams))
+                else:
+                    print('----')
+                if debug:
+                    print('Internal parameters: ', end='')
+                if len(paramlist) > 0:
+                    print(' '.join(paramlist))
+                else:
+                    print('----')
+                print()
+                continue
+
+if __name__ == '__main__':
+    debug = False
+
+    if len(sys.argv) == 1:
+        print("No options given to print_subckt_params.py.")
+        usage()
+        sys.exit(0)
+
+    optionlist = []
+    arguments = []
+
+    for option in sys.argv[1:]:
+        if option.find('-', 0) == 0:
+            optionlist.append(option)
+        else:
+            arguments.append(option)
+
+    if len(arguments) < 1:
+        print("Wrong number of arguments given to print_subckt_params.py.")
+        usage()
+        sys.exit(0)
+
+    if '-debug' in optionlist:
+        debug = True
+
+    inpath = arguments[0]
+
+    if not os.path.exists(inpath):
+        print('No such source file ' + inpath)
+        sys.exit(1)
+
+    parse_file(inpath, debug)
+    exit(0)