blob: 66786ca8512cf3416a44d31f70ff41be6c30ce4e [file] [log] [blame]
Tim Edwards9d3debb2020-10-20 20:52:18 -04001#!/usr/bin/env python3
Tim Edwards37d35dd2020-08-19 21:41:14 -04002#
3# print_subckt_params.py --
4#
5# Print a list of subcircuit parameters, dividing them into those which
6# are declared on the subcircuit line, and those that are declared inside
7# the scope of the subcircuit.
8#
9# The single argument is <path_to_input>
10# <path_to_input> should be the path to a single file.
11
12import os
13import sys
14import re
15import glob
16
17def usage():
18 print('print_subckt_params.py <path_to_input>')
19 print('where:')
20 print(' <path_to_input> is the path to the input file to parse')
21
22def parse_pins(line, debug):
23 # Regexp patterns
24 subrex = re.compile('\.subckt[ \t]+[^ \t]+[ \t]+(.*)')
25 parm1rex = re.compile('([^= \t]+)[ \t]*=[ \t]*[^ \t]+[ \t]*(.*)')
26 parm2rex = re.compile('([^= \t]+)[ \t]*(.*)')
27
28 params = []
29
30 pmatch = subrex.match(line)
31 if pmatch:
32 rest = pmatch.group(1)
33 else:
34 # Could not parse
35 return []
36
37 while rest != '':
38 if rest.startswith('$ '):
39 break
40 pmatch = parm1rex.match(rest)
41 if pmatch:
42 rest = pmatch.group(2)
43 params.append(pmatch.group(1))
44 else:
45 pmatch = parm2rex.match(rest)
46 if pmatch:
47 # This is a pin, so don't list it
48 rest = pmatch.group(2)
49
50 return params
51
52# Parse a parameter line for parameters, and divide into two parts,
53# returned as a list. If a parameter name matches an entry in 'params',
54# it goes in the second list. Otherwise, it goes in the first list.
55# The first list is returned as-is minus any parameters that were split
56# into the second list. The second list must begin with '+', as it will
57# be output as a continuation line for the subcircuit.
58
59def param_parse(line, debug):
60 # Regexp patterns
61 parm1rex = re.compile('\.param[ \t]+(.*)')
62 parm2rex = re.compile('\+[ \t]*(.*)')
63 parm3rex = re.compile('([^= \t]+)[ \t]*=[ \t]*[^ \t]+[ \t]*(.*)')
64 parm4rex = re.compile('([^= \t]+)[ \t]*(.*)')
65
66 if debug:
67 print('Diagnostic: param line in = "' + line + '"')
68
69 params = []
70
71 pmatch = parm1rex.match(line)
72 if pmatch:
73 rest = pmatch.group(1)
74 else:
75 pmatch = parm2rex.match(line)
76 if pmatch:
77 rest = pmatch.group(1)
78 else:
79 # Could not parse; return list with line and empty string
80 return []
81
82 while rest != '':
83 if rest.startswith('$ '):
84 break
85 pmatch = parm3rex.match(rest)
86 if pmatch:
87 rest = pmatch.group(2)
88 params.append(pmatch.group(1))
89 else:
90 pmatch = parm4rex.match(rest)
91 if pmatch:
92 rest = pmatch.group(2)
93 params.append(pmatch.group(1))
94
95 return params
96
97def parse_file(in_file, debug):
98
99 # Regexp patterns
100 paramrex = re.compile('\.param[ \t]+(.*)')
101 subrex = re.compile('\.subckt[ \t]+([^ \t]+)[ \t]+([^ \t]*)')
102 modelrex = re.compile('\.model[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]+(.*)')
103 endsubrex = re.compile('\.ends[ \t]+(.+)')
104 increx = re.compile('\.include[ \t]+')
105
106 with open(in_file, 'r') as ifile:
107 inplines = ifile.read().splitlines()
108
109 insubckt = False
110 inparam = False
111 inmodel = False
112 inpinlist = False
113
114 pinparams = []
115 paramlist = []
116 subname = ''
117
118 for line in inplines:
119
120 # Item 1. Handle comment lines
121 if line.startswith('*'):
122 continue
123
124 # Item 2. Flag continuation lines.
125 if line.startswith('+'):
126 contline = True
127 else:
128 contline = False
129 if line.strip() != '':
130 if inpinlist:
131 inpinlist = False
132 if inparam:
133 inparam = False
134
135 # Item 3. Handle blank lines like comment lines
136 if line.strip() == '':
137 continue
138
139 # Item 4. Handle continuation lines
140 # Remove lines that have a continuation mark and nothing else.
141 if contline:
142 if inparam:
143 # Continue handling parameters
144 if insubckt:
145 # Find subcircuit parameters and record what line they were found on
146 if inpinlist:
147 pinparams.extend(param_parse(line, debug))
148 else:
149 paramlist.extend(param_parse(line, debug))
150
151 continue
152
153 # Item 5. Regexp matching
154
155 # parameters
156 pmatch = paramrex.match(line)
157 if pmatch:
158 inparam = True
159 if insubckt:
160 if inpinlist:
161 inpinlist = False
162 # Find subcircuit parameters and record what line they were found on
163 paramlist.extend(param_parse(line, debug))
164 continue
165
166 # model
167 mmatch = modelrex.match(line)
168 if mmatch:
169 inmodel = 2
170 continue
171
172 if not insubckt:
173 # Things to parse if not in a subcircuit
174
175 imatch = subrex.match(line)
176 if imatch:
177 insubckt = True
178 inpinlist = True
179 subname = imatch.group(1)
180 pinparams = parse_pins(line, debug)
181 paramlist = []
182 continue
183
184 else:
185 ematch = endsubrex.match(line)
186 if ematch:
187 insubckt = False
188 inmodel = False
189 # Print out results
190 if debug:
191 print('File: ', end='')
192 print(in_file)
193 if debug:
194 print('Subcircuit: ', end='')
195 print(subname)
196 if debug:
197 print('Callable parameters: ', end='')
198 if len(pinparams) > 0:
199 print(' '.join(pinparams))
200 else:
201 print('----')
202 if debug:
203 print('Internal parameters: ', end='')
204 if len(paramlist) > 0:
205 print(' '.join(paramlist))
206 else:
207 print('----')
208 print()
209 continue
210
211if __name__ == '__main__':
212 debug = False
213
214 if len(sys.argv) == 1:
215 print("No options given to print_subckt_params.py.")
216 usage()
217 sys.exit(0)
218
219 optionlist = []
220 arguments = []
221
222 for option in sys.argv[1:]:
223 if option.find('-', 0) == 0:
224 optionlist.append(option)
225 else:
226 arguments.append(option)
227
228 if len(arguments) < 1:
229 print("Wrong number of arguments given to print_subckt_params.py.")
230 usage()
231 sys.exit(0)
232
233 if '-debug' in optionlist:
234 debug = True
235
236 inpath = arguments[0]
237
238 if not os.path.exists(inpath):
239 print('No such source file ' + inpath)
240 sys.exit(1)
241
242 parse_file(inpath, debug)
243 exit(0)