Branch data Line data Source code
1 : : /*
2 : : * check_netlist.cpp - checker for the Qucs netlist
3 : : *
4 : : * Copyright (C) 2003-2009 Stefan Jahn <stefan@lkcc.org>
5 : : *
6 : : * This is free software; you can redistribute it and/or modify
7 : : * it under the terms of the GNU General Public License as published by
8 : : * the Free Software Foundation; either version 2, or (at your option)
9 : : * any later version.
10 : : *
11 : : * This software is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : : * GNU General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU General Public License
17 : : * along with this package; see the file COPYING. If not, write to
18 : : * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19 : : * Boston, MA 02110-1301, USA.
20 : : *
21 : : * $Id$
22 : : *
23 : : */
24 : :
25 : : #if HAVE_CONFIG_H
26 : : # include <config.h>
27 : : #endif
28 : :
29 : : #include <stdio.h>
30 : : #include <stdlib.h>
31 : : #include <string.h>
32 : : #include <cmath>
33 : : #include <assert.h>
34 : : #include <float.h>
35 : :
36 : : #include "logging.h"
37 : : #include "strlist.h"
38 : : #include "netdefs.h"
39 : : #include "equation.h"
40 : : #include "check_netlist.h"
41 : : #include "constants.h"
42 : : #include "environment.h"
43 : : #include "variable.h"
44 : : #include "module.h"
45 : :
46 : : using namespace qucs;
47 : : using namespace qucs::eqn;
48 : :
49 : : /* Global definitions for parser and checker. */
50 : : struct definition_t * definition_root = NULL;
51 : : struct definition_t * subcircuit_root = NULL;
52 : : environment * env_root = NULL;
53 : :
54 : : /* The function counts the nodes in a definition line. */
55 : 1157 : static int checker_count_nodes (struct definition_t * def)
56 : : {
57 : 1157 : int count = 0;
58 [ + + ]: 3472 : for (struct node_t * node = def->nodes; node != NULL; node = node->next)
59 : 2315 : count++;
60 : 1157 : return count;
61 : : }
62 : :
63 : : /* The function returns an available definition line for the given
64 : : type. If there is no such definition type the function returns
65 : : NULL. */
66 : 1098 : static struct define_t * checker_find_definition (char * type, int action)
67 : : {
68 : 1098 : struct define_t * def = module::getModule (type);
69 [ + - ][ + - ]: 1098 : if (def != NULL && action == def->action) return def;
70 : 1098 : return NULL;
71 : : }
72 : :
73 : : /* The function returns the number of properties in a definition line
74 : : specified by the given key. */
75 : 10960 : static int checker_find_property (const char * key, struct pair_t * pp)
76 : : {
77 : 10960 : int count = 0;
78 [ + + ]: 840530 : while (pp != NULL)
79 : : {
80 [ + + ]: 829570 : if (!strcmp (pp->key, key))
81 : 10433 : count++;
82 : 829570 : pp = pp->next;
83 : : }
84 : 10960 : return count;
85 : : }
86 : :
87 : : /* Checks if the given property key is either optional or required for
88 : : the given definition type and returns the type of the property. */
89 : 12004 : static int checker_is_property (struct define_t * available,
90 : : const char * key)
91 : : {
92 : : int i;
93 [ + + ]: 393027 : for (i = 0; PROP_IS_PROP (available->required[i]); i++)
94 : : {
95 [ + + ]: 386514 : if (!strcmp (available->required[i].key, key))
96 : 5491 : return available->required[i].type;
97 : : }
98 [ + + ]: 52526 : for (i = 0; PROP_IS_PROP (available->optional[i]); i++)
99 : : {
100 [ + + ]: 50788 : if (!strcmp (available->optional[i].key, key))
101 : 4775 : return available->optional[i].type;
102 : : }
103 : 12004 : return PROP_NONE;
104 : : }
105 : :
106 : : /* Counts the number of definitions given by the specified type and
107 : : instance name in the definition list. */
108 : 1122 : static int checker_count_definition (struct definition_t * root,
109 : : const char * type, char * instance)
110 : : {
111 : 1122 : int count = 0;
112 [ + + ]: 14292 : for (struct definition_t * def = root; def != NULL; def = def->next)
113 : : {
114 [ + + ][ + + ]: 13170 : if (!strcmp (def->type, type) && !strcmp (def->instance, instance))
115 : : {
116 [ - + ]: 1122 : if (++count > 1)
117 : 0 : def->duplicate = 1;
118 : : }
119 : : }
120 : 1122 : return count;
121 : : }
122 : :
123 : : /* Returns the value for a given definition type, key and variable
124 : : identifier if it is in the list of definitions. Otherwise the
125 : : function returns NULL. */
126 : 5640 : static struct value_t * checker_find_variable (struct definition_t * root,
127 : : const char * type,
128 : : const char * key,
129 : : char * ident)
130 : : {
131 : : struct pair_t * pair;
132 [ + + ]: 68500 : for (struct definition_t * def = root; def != NULL; def = def->next)
133 : : {
134 [ + + ]: 63078 : if (!strcmp (def->type, type))
135 : : {
136 [ + + ]: 8711 : for (pair = def->pairs; pair != NULL; pair = pair->next)
137 : : {
138 [ + + ]: 7405 : if (!strcmp (pair->key, key))
139 [ + - ][ + - ]: 1524 : if (pair->value->ident != NULL && ident != NULL &&
[ + + ]
140 : 1524 : strcmp (pair->value->ident, ident) == 0)
141 : 218 : return pair->value;
142 : : }
143 : : }
144 : : }
145 : 5640 : return NULL;
146 : : }
147 : :
148 : : /* The function returns the appropriate value for a given key within
149 : : the given netlist definition if the value is a reference (a
150 : : string). If there is no such key value pair the function returns
151 : : NULL. */
152 : 471 : static struct value_t * checker_find_reference (struct definition_t * def,
153 : : const char * key)
154 : : {
155 : : struct pair_t * pair;
156 [ + - ]: 648 : for (pair = def->pairs; pair != NULL; pair = pair->next)
157 : : {
158 [ + + ]: 648 : if (!strcmp (pair->key, key))
159 [ + - ]: 471 : if (pair->value->ident != NULL)
160 : 471 : return pair->value;
161 : : }
162 : 471 : return NULL;
163 : : }
164 : :
165 : : /* The function looks for the given property key within the properties
166 : : of the given definition line and returns its value if the property
167 : : is not an identifier. Otherwise the function returns NULL. */
168 : 98 : static struct value_t * checker_find_prop_value (struct definition_t * def,
169 : : const char * key)
170 : : {
171 : : struct pair_t * pair;
172 [ + - ]: 110 : for (pair = def->pairs; pair != NULL; pair = pair->next)
173 : : {
174 [ + + ]: 110 : if (!strcmp (pair->key, key))
175 [ + - ]: 98 : if (pair->value->ident == NULL)
176 : 98 : return pair->value;
177 : : }
178 : 98 : return NULL;
179 : : }
180 : :
181 : : /* The function returns the number of properties in a definition line
182 : : specified by the given key. */
183 : 376 : static int checker_find_property (struct definition_t * def,
184 : : const char * key)
185 : : {
186 : 376 : return checker_find_property (key, def->pairs);
187 : : }
188 : :
189 : : /* This function looks for the specified property 'key' in the given
190 : : definition and return its value (a string reference) if it is a
191 : : reference. Otherwise the function returns NULL and emits an
192 : : appropriate error message. */
193 : 102 : static struct value_t * checker_validate_reference (struct definition_t * def,
194 : : const char * key)
195 : : {
196 : : struct value_t * val;
197 [ - + ]: 102 : if ((val = checker_find_reference (def, key)) == NULL)
198 : : {
199 : : logprint (LOG_ERROR, "line %d: checker error, not a valid `%s' property "
200 : 0 : "found in `%s:%s'\n", def->line, key, def->type, def->instance);
201 : : }
202 : 102 : return val;
203 : : }
204 : :
205 : : /* This function checks whether the given definition is a known
206 : : microstrip component with a substrate definition. If the given
207 : : identifier equals this substrate definition then the function
208 : : returns the appropriate value. Otherwise it returns NULL. */
209 : 940 : static struct value_t * checker_find_substrate (struct definition_t * def,
210 : : char * ident)
211 : : {
212 : : struct value_t * val;
213 [ + + ]: 940 : if (checker_is_property (def->define, "Subst") == PROP_STR)
214 : : {
215 [ + - ]: 82 : if ((val = checker_find_reference (def, "Subst")) != NULL)
216 : : {
217 [ + - ][ + + ]: 82 : if (ident != NULL && !strcmp (val->ident, ident))
218 : 24 : return val;
219 : : }
220 : : }
221 : 940 : return NULL;
222 : : }
223 : :
224 : : /* Puts the given double value variable into an environment. */
225 : 81 : static variable * checker_add_variable (environment * env,
226 : : char * var, int type, bool pass)
227 : : {
228 [ + - ]: 81 : variable * v = new variable (var);
229 [ + - ]: 81 : eqn::constant * c = new eqn::constant (type);
230 [ + - - ]: 81 : switch (type)
231 : : {
232 : : case TAG_DOUBLE:
233 : 81 : c->d = 0.0; // initialize the variable
234 : 81 : break;
235 : : case TAG_VECTOR:
236 [ # # ]: 0 : c->v = new qucs::vector ();
237 : 0 : break;
238 : : }
239 : 81 : v->setConstant (c);
240 : 81 : env->addVariable (v, pass);
241 : 81 : return v;
242 : : }
243 : :
244 : : /* Resolves the variable of a property value. Returns non-zero on
245 : : success, otherwise zero. */
246 : 10160 : static int checker_resolve_variable (struct definition_t * root,
247 : : struct definition_t * def,
248 : : struct pair_t * pair, int type)
249 : : {
250 : : struct value_t * val;
251 : 10160 : struct value_t * value = pair->value;
252 [ + + ]: 10160 : if (value->ident != NULL)
253 : : {
254 : 940 : int found = 0;
255 : : /* 1. find variable in parameter sweeps */
256 [ + + ]: 940 : if ((val = checker_find_variable (root, "SW", "Param", value->ident)))
257 : : {
258 : : /* add parameter sweep variable to environment */
259 [ + + ][ + - ]: 140 : if (!strcmp (def->type, "SW") && !strcmp (pair->key, "Param"))
260 : : {
261 : 59 : checker_add_variable (root->env, value->ident, TAG_DOUBLE, true);
262 : : }
263 : : /* mark both the variable identifier and the parameter sweep
264 : : variable to be actually variables */
265 : 140 : val->var = TAG_DOUBLE;
266 : 140 : value->var = TAG_DOUBLE;
267 : 140 : found++;
268 : : }
269 : : /* 2. find analysis in parameter sweeps */
270 [ + + ]: 940 : if ((val = checker_find_variable (root, "SW", "Sim", value->ident)))
271 : : {
272 : 59 : found++;
273 : : }
274 : : /* 3. find substrate in microstrip components */
275 [ + + ]: 940 : if ((val = checker_find_substrate (def, value->ident)))
276 : : {
277 : 24 : value->subst = 1;
278 : 24 : found++;
279 : : }
280 : : /* 4. find subcircuit definition in subcircuit components */
281 [ + + ]: 940 : if ((val = checker_find_variable (root, "Sub", "Type", value->ident)))
282 : : {
283 : 19 : found++;
284 : : }
285 : : /* 5. find special identifiers in certain properties */
286 [ + + ]: 940 : if (value->range)
287 : : {
288 : 672 : found++;
289 : : }
290 : : /* 6. find file reference in S-parameter file components */
291 [ - + ]: 940 : if ((val = checker_find_variable (root, "SPfile", "File", value->ident)))
292 : : {
293 : 0 : found++;
294 : : }
295 : : /* 7. find variable in equation */
296 [ + - ]: 940 : if (root->env)
297 : : {
298 [ + + ]: 940 : if (root->env->getChecker()->containsVariable (value->ident))
299 : : {
300 : : variable * v;
301 [ - + ]: 26 : value->var = (type == PROP_LIST) ? TAG_VECTOR : TAG_DOUBLE;
302 [ + + ]: 26 : if ((v = root->env->getVariable (value->ident)) == NULL)
303 : : {
304 : : // put variable into the environment
305 : 22 : checker_add_variable (root->env, value->ident, value->var, false);
306 : : }
307 : 26 : found++;
308 : : }
309 : : }
310 : : /* 8. find file reference in file based sources */
311 [ - + ]: 940 : if ((val = checker_find_variable (root, "Vfile", "File", value->ident)))
312 : : {
313 : 0 : found++;
314 : : }
315 [ - + ]: 940 : if ((val = checker_find_variable (root, "Ifile", "File", value->ident)))
316 : : {
317 : 0 : found++;
318 : : }
319 : : /* 9. find property reference in the instance */
320 [ - + # # ]: 940 : if (!found &&
[ - + ]
321 : 0 : checker_is_property (def->define, value->ident) != PROP_NONE)
322 : : {
323 [ # # ]: 0 : if (root->env)
324 : : {
325 : :
326 : : // create reference variable names
327 : : char * txt = (char *)
328 : 0 : malloc (strlen (def->instance) + 1 + strlen (value->ident) + 1);
329 : 0 : sprintf (txt, "%s.%s", def->instance, value->ident);
330 : : char * ref = (char *)
331 : 0 : malloc (strlen (def->instance) + 5 + strlen (value->ident) + 1);
332 : 0 : sprintf (ref, "%s.%s.ref", def->instance, value->ident);
333 : :
334 : : // replace property string
335 : 0 : free (value->ident);
336 : 0 : value->ident = strdup (ref);
337 : 0 : value->var = TAG_DOUBLE;
338 : :
339 : : // already done previously?
340 : : variable * v;
341 [ # # ]: 0 : if ((v = root->env->getVariable (ref)) == NULL)
342 : : {
343 : : // put variable into the environment
344 : 0 : checker_add_variable (root->env, ref, TAG_DOUBLE, false);
345 : : // also add reference equation into environment
346 : 0 : root->env->getChecker()->addReference ("#propref", ref, txt);
347 : : }
348 : :
349 : : // done
350 : 0 : free (txt);
351 : 0 : free (ref);
352 : 0 : found++;
353 : : }
354 : : }
355 : : /* not found */
356 [ - + ]: 940 : if (!found)
357 : : {
358 : : logprint (LOG_ERROR, "line %d: checker error, no such variable `%s' "
359 : : "used in a `%s:%s' property\n", def->line, value->ident,
360 : 0 : def->type, def->instance);
361 : 0 : return 0;
362 : : }
363 : : }
364 : 10160 : return 1;
365 : : }
366 : :
367 : : /* Evaluates the unit scale in a property value. It adjusts the
368 : : actual value and omits the scale. The function returns non-zero
369 : : on success and zero otherwise. */
370 : 10194 : static int checker_evaluate_scale (struct value_t * value)
371 : : {
372 : 10194 : double val = value->value, factor = 1.0;
373 : : char * scale;
374 [ + + ]: 10194 : if (value->scale != NULL)
375 : : {
376 : 1660 : scale = value->scale;
377 [ - - - + : 1660 : switch (*scale)
+ + + + +
+ + - + -
- + ]
378 : : {
379 : : case 'E':
380 : 0 : scale++;
381 : 0 : factor = 1e18;
382 : 0 : break;
383 : : case 'P':
384 : 0 : scale++;
385 : 0 : factor = 1e15;
386 : 0 : break;
387 : : case 'T':
388 : 0 : scale++;
389 : 0 : factor = 1e12;
390 : 0 : break;
391 : : case 'G':
392 : 82 : scale++;
393 : 82 : factor = 1e9;
394 : 82 : break;
395 : : case 'M':
396 : 40 : scale++;
397 : 40 : factor = 1e6;
398 : 40 : break;
399 : : case 'k':
400 : 118 : scale++;
401 : 118 : factor = 1e3;
402 : 118 : break;
403 : : case 'm':
404 : 144 : scale++;
405 [ - + ]: 144 : if (*scale == 'i')
406 : : {
407 : 0 : scale++;
408 [ # # ]: 0 : if (*scale == 'l')
409 : : {
410 : 0 : scale++;
411 : 0 : factor = 2.54e-5;
412 : : }
413 : : }
414 : : else
415 : 144 : factor = 1e-3;
416 : 144 : break;
417 : : case 'u':
418 : 219 : scale++;
419 : 219 : factor = 1e-6;
420 : 219 : break;
421 : : case 'n':
422 : 143 : scale++;
423 : 143 : factor = 1e-9;
424 : 143 : break;
425 : : case 'p':
426 : 231 : scale++;
427 : 231 : factor = 1e-12;
428 : 231 : break;
429 : : case 'f':
430 : 93 : scale++;
431 [ - + ]: 93 : if (*scale == 't')
432 : : {
433 : 0 : scale++;
434 : 0 : factor = 0.3048;
435 : : }
436 : : else
437 : 93 : factor = 1e-15;
438 : 93 : break;
439 : : case 'a':
440 : 0 : scale++;
441 : 0 : factor = 1e-18;
442 : 0 : break;
443 : : case 'd':
444 : 41 : scale++;
445 [ + - ]: 41 : if (*scale == 'B')
446 : : {
447 : 41 : scale++;
448 : 41 : val = std::pow (10.0, val / 10.0);
449 [ + + ]: 41 : if (*scale == 'm')
450 : : {
451 : 38 : scale++;
452 : 38 : factor = 1e-3;
453 : : }
454 [ - + ]: 3 : else if (*scale == 'u')
455 : : {
456 : 0 : scale++;
457 : 0 : factor = 1e-6;
458 : : }
459 : : }
460 : 41 : break;
461 : : case 'i':
462 : 0 : scale++;
463 [ # # ]: 0 : if (*scale == 'n')
464 : : {
465 : 0 : scale++;
466 : 0 : factor = 2.54e-2;
467 : : }
468 : 0 : break;
469 : : case 'y':
470 : 0 : scale++;
471 [ # # ]: 0 : if (*scale == 'd')
472 : : {
473 : 0 : scale++;
474 : 0 : factor = 0.9144;
475 : : }
476 : 0 : break;
477 : : }
478 [ + + ]: 1660 : if (*scale != '\0')
479 : : {
480 : 1353 : value->unit = strdup (scale);
481 : : }
482 : 1660 : free (value->scale);
483 : 1660 : value->scale = NULL;
484 : : }
485 : 10194 : value->value = val * factor;
486 : 10194 : return 1;
487 : : }
488 : :
489 : : /* The function returns the number of instances of the given type within
490 : : the list of definitions. */
491 : 430 : static int checker_count_definitions (struct definition_t * root,
492 : : const char * type, int action)
493 : : {
494 : 430 : int count = 0;
495 [ + + ]: 4636 : for (struct definition_t * def = root; def != NULL; def = def->next)
496 : : {
497 [ + + ]: 4206 : if (def->action == action)
498 : : {
499 [ + + ]: 910 : if (type == NULL)
500 : 181 : count++;
501 [ + + ]: 729 : else if (!strcmp (def->type, type))
502 : 123 : count++;
503 : : }
504 : : }
505 : 430 : return count;
506 : : }
507 : :
508 : : /* This function looks for the specified subcircuit type in the list
509 : : of available subcircuits and returns its definition. If there is
510 : : no such subcircuit the function returns NULL: */
511 : 73 : static struct definition_t * checker_find_subcircuit (char * n)
512 : : {
513 : : struct definition_t * def;
514 [ + - ]: 101 : for (def = subcircuit_root; def != NULL; def = def->next)
515 [ + - ][ + + ]: 101 : if (n != NULL && !strcmp (def->instance, n)) return def;
516 : 73 : return NULL;
517 : : }
518 : :
519 : : /* The function returns the subcircuit definition for the given
520 : : subcircuit instance. */
521 : : static struct definition_t *
522 : 46 : checker_get_subcircuit (struct definition_t * def)
523 : : {
524 : : struct value_t * val;
525 : 46 : struct definition_t * sub = NULL;
526 [ + - ]: 46 : if ((val = checker_find_reference (def, "Type")) != NULL)
527 : 46 : sub = checker_find_subcircuit (val->ident);
528 : 46 : return sub;
529 : : }
530 : :
531 : : // Global variable indicating cycles in subcircuit definitions.
532 : : static int checker_sub_cycles = 0;
533 : :
534 : : /* The following function returns the number of circuit instances
535 : : requiring a DC analysis (being nonlinear) in the list of definitions. */
536 : 126 : static int checker_count_nonlinearities (struct definition_t * root)
537 : : {
538 : 126 : int count = 0;
539 : : struct definition_t * sub;
540 [ + + ]: 1268 : for (struct definition_t * def = root; def != NULL; def = def->next)
541 : : {
542 [ + + ]: 1142 : if (def->nonlinear != 0) count++;
543 : : // also recurse into subcircuits if possible
544 [ + - ]: 1142 : if (checker_sub_cycles <= 0)
545 : : {
546 [ + + ]: 1142 : if (!strcmp (def->type, "Sub"))
547 : : {
548 [ + - ]: 23 : if ((sub = checker_get_subcircuit (def)) != NULL)
549 : : {
550 : 23 : count += checker_count_nonlinearities (sub->sub);
551 : : }
552 : : }
553 : : }
554 : : }
555 : 126 : return count;
556 : : }
557 : :
558 : : /* This function returns the number of action definitions with the
559 : : given instance name. */
560 : 59 : static int checker_count_action (struct definition_t * root, char * instance)
561 : : {
562 : 59 : int count = 0;
563 [ + + ]: 620 : for (struct definition_t * def = root; def != NULL; def = def->next)
564 : : {
565 [ + + ][ + + ]: 561 : if (def->action == 1 && !strcmp (def->instance, instance))
566 : 59 : count++;
567 : : }
568 : 59 : return count;
569 : : }
570 : :
571 : : /* This (recursive) function detects any kind of cyclic definitions of
572 : : parameter sweeps for the given instance name. The string list
573 : : argument is used to pass the dependencies. The function returns
574 : : zero if the parameter sweep in non-cyclic. */
575 : 79 : static int checker_validate_para_cycles (struct definition_t * root,
576 : : char * instance, strlist * deps)
577 : : {
578 : 79 : int errors = 0;
579 : : struct value_t * val;
580 [ + + ]: 768 : for (struct definition_t * def = root; def != NULL; def = def->next)
581 : : {
582 : : /* find the appropriate definition for the given instance */
583 [ + + ][ + + ]: 709 : if (def->action == 1 && !strcmp (def->instance, instance))
584 : : {
585 : : /* emit error message if the instance is already in the dependencies */
586 [ - + ]: 79 : if (deps->contains (instance))
587 : : {
588 : : logprint (LOG_ERROR, "checker error, cyclic definition of `%s' "
589 : 0 : "detected, involves: %s\n", instance, deps->toString ());
590 : 0 : return ++errors;
591 : : }
592 : 79 : deps->append (instance);
593 : : /* recurse into parameter sweeps */
594 [ + + ]: 79 : if (!strcmp (def->type, "SW"))
595 : : {
596 [ + - ]: 20 : if ((val = checker_find_reference (def, "Sim")) != NULL)
597 : : {
598 : 20 : return checker_validate_para_cycles (root, val->ident, deps);
599 : : }
600 : : }
601 : : }
602 : : }
603 : 79 : return errors;
604 : : }
605 : :
606 : : /* This function validates each parameter sweep within the list of
607 : : definitions and return non-zero on errors. Emits appropriate error
608 : : messages. */
609 : 103 : static int checker_validate_para (struct definition_t * root)
610 : : {
611 : 103 : int errors = 0;
612 : : struct value_t * val;
613 [ + + ]: 1102 : for (struct definition_t * def = root; def != NULL; def = def->next)
614 : : {
615 : : /* find parameter sweep */
616 [ + + ][ + + ]: 999 : if (def->action == 1 && !strcmp (def->type, "SW"))
617 : : {
618 : : /* the 'Sim' property must be an identifier */
619 [ - + ]: 59 : if ((val = checker_validate_reference (def, "Sim")) == NULL)
620 : : {
621 : 0 : errors++;
622 : : }
623 : : else
624 : : {
625 : : /* check for self-referring sweeps */
626 [ - + ]: 59 : if (!strcmp (def->instance, val->ident))
627 : : {
628 : : logprint (LOG_ERROR, "line %d: checker error, definition `%s:%s' "
629 : 0 : "refers to itself\n", def->line, def->type, def->instance);
630 : 0 : errors++;
631 : : }
632 : : /* look for the referred analysis action definition */
633 [ - + ]: 59 : if (checker_count_action (root, val->ident) != 1)
634 : : {
635 : : logprint (LOG_ERROR, "line %d: checker error, no such action `%s' "
636 : : "found as referred in `%s:%s'\n", def->line, val->ident,
637 : 0 : def->type, def->instance);
638 : 0 : errors++;
639 : : }
640 : : /* finally detect cyclic definitions */
641 [ + - ]: 59 : strlist * deps = new strlist ();
642 : 59 : errors += checker_validate_para_cycles (root, val->ident, deps);
643 [ + - ]: 59 : delete deps;
644 : : }
645 : : }
646 : : }
647 : 103 : return errors;
648 : : }
649 : :
650 : : /* This function returns the next port definition in the given list of
651 : : definitions or NULL if there is no such definition. */
652 : 277 : static struct definition_t * checker_find_port (struct definition_t * root)
653 : : {
654 [ + + ]: 1594 : for (struct definition_t * def = root; def != NULL; def = def->next)
655 : : {
656 [ + + ][ + + ]: 1451 : if (def->action == PROP_COMPONENT && !strcmp (def->type, "Pac"))
657 : : {
658 : 134 : return def;
659 : : }
660 : : }
661 : 277 : return NULL;
662 : : }
663 : :
664 : : /* This function checks whether the port numbers for the S-parameter
665 : : analysis are unique or not. It returns zero on success and
666 : : non-zero if it detected duplicate entries. */
667 : 103 : static int checker_validate_ports (struct definition_t * root)
668 : : {
669 : 103 : int p, errors = 0;
670 : : struct value_t * val;
671 : 103 : struct definition_t * port, * def = root;
672 : 103 : const char * prop = "Num";
673 [ + + ]: 143 : while ((def = checker_find_port (def)) != NULL)
674 : : {
675 [ + - ]: 40 : if ((val = checker_find_prop_value (def, prop)) != NULL)
676 : : {
677 : 40 : p = (int) val->value;
678 : 40 : port = root;
679 [ + + ]: 134 : while ((port = checker_find_port (port)) != NULL)
680 : : {
681 [ + + ]: 94 : if (port != def)
682 : : {
683 [ + - ]: 54 : if ((val = checker_find_prop_value (port, prop)) != NULL)
684 : : {
685 [ - + ]: 54 : if (p == (int) val->value)
686 : : {
687 : : logprint (LOG_ERROR, "line %d: checker error, `%s' definitions "
688 : : "with duplicate `%s=%d' property found: `%s:%s' and "
689 : : "`%s:%s'\n", def->line, def->type, prop, p, def->type,
690 : 0 : def->instance, port->type, port->instance);
691 : 0 : errors++;
692 : : }
693 : : }
694 : : }
695 : 94 : port = port->next;
696 : : }
697 : : }
698 : 40 : def = def->next;
699 : : }
700 : 103 : return errors;
701 : : }
702 : :
703 : : /* The following function checks whether the parametric sweeps in the
704 : : netlist are valid or not. It returns zero on success and non-zero
705 : : otherwise. */
706 : 103 : static int checker_validate_lists (struct definition_t * root)
707 : : {
708 : 103 : int errors = 0;
709 : : // go through each definition
710 [ + + ]: 1102 : for (struct definition_t * def = root; def != NULL; def = def->next)
711 : : {
712 : : /* sweeps possible in parameter sweep, ac-analysis and
713 : : s-parameter analysis */
714 [ + + ][ + + ]: 999 : if (def->action == 1 && (!strcmp (def->type, "SW") ||
[ + + ][ + + ]
715 : 122 : !strcmp (def->type, "AC") ||
716 : 104 : !strcmp (def->type, "SP")))
717 : : {
718 : 95 : struct value_t * val = checker_find_reference (def, "Type");
719 : 95 : char * type = val->ident;
720 : : // list of constant values and constant values
721 [ + - ][ + - ]: 95 : if (type && (!strcmp (type, "const") || !strcmp (type, "list")))
[ + + ]
722 : : {
723 : : // property 'Values' is required
724 [ - + ]: 4 : if ((val = checker_find_prop_value (def, "Values")) == NULL)
725 : : {
726 [ # # ]: 0 : if (!strcmp (type, "const"))
727 : : {
728 [ # # ]: 0 : if ((val = checker_validate_reference (def, "Values")) == NULL)
729 : : {
730 : 0 : errors++;
731 : : }
732 : : }
733 : : else
734 : : {
735 : : logprint (LOG_ERROR, "line %d: checker error, required property "
736 : : "`%s' not found in `%s:%s'\n", def->line, "Values",
737 : 0 : def->type, def->instance);
738 : 0 : errors++;
739 : : }
740 : : }
741 : : else
742 : : {
743 [ - + ]: 4 : if (!strcmp (type, "const"))
744 : : {
745 : : // in constant sweeps only one value allowed
746 [ # # ]: 0 : if (val->next != NULL)
747 : : {
748 : : logprint (LOG_ERROR, "line %d: checker error, value of `%s' "
749 : : "needs to be a single constant value in `%s:%s', no "
750 : : "lists possible\n", def->line, "Values",
751 : 0 : def->type, def->instance);
752 : 0 : errors++;
753 : : }
754 : 0 : val->var = TAG_UNKNOWN;
755 : : }
756 [ + - ]: 4 : if (!strcmp (type, "list"))
757 : : {
758 : 4 : val->var = TAG_VECTOR;
759 : : }
760 : : // check and evaluate the unit scale in a value list
761 [ + + ]: 20 : for (; val != NULL; val = val->next)
762 : : {
763 [ - + ]: 16 : if (!checker_evaluate_scale (val))
764 : 0 : errors++;
765 : : }
766 : : }
767 : : // property 'Start' is invalid
768 [ - + ]: 4 : if (checker_find_property (def, "Start") > 0)
769 : : {
770 : : logprint (LOG_ERROR, "line %d: checker error, extraneous property "
771 : : "`%s' is invalid in `%s:%s'\n", def->line, "Start",
772 : 0 : def->type, def->instance);
773 : 0 : errors++;
774 : : }
775 : : // property 'Stop' is invalid
776 [ - + ]: 4 : if (checker_find_property (def, "Stop") > 0)
777 : : {
778 : : logprint (LOG_ERROR, "line %d: checker error, extraneous property "
779 : : "`%s' is invalid in `%s:%s'\n", def->line, "Stop",
780 : 0 : def->type, def->instance);
781 : 0 : errors++;
782 : : }
783 : : // property 'Points' is also invalid
784 [ - + ]: 4 : if (checker_find_property (def, "Points") > 0)
785 : : {
786 : : logprint (LOG_ERROR, "line %d: checker error, extraneous property "
787 : : "`%s' is invalid in `%s:%s'\n", def->line, "Points",
788 : 0 : def->type, def->instance);
789 : 0 : errors++;
790 : : }
791 : : }
792 : : // linearly and logarithmically stepped sweeps
793 [ + - ][ + + ]: 91 : else if (type && (!strcmp (type, "lin") || !strcmp (type, "log")))
[ + - ]
794 : : {
795 : : // property 'Start' required
796 [ - + ]: 91 : if (checker_find_property (def, "Start") <= 0)
797 : : {
798 : : logprint (LOG_ERROR, "line %d: checker error, required property "
799 : : "`%s' not found in `%s:%s'\n", def->line, "Start",
800 : 0 : def->type, def->instance);
801 : 0 : errors++;
802 : : }
803 : : // property 'Stop' required
804 [ - + ]: 91 : if (checker_find_property (def, "Stop") <= 0)
805 : : {
806 : : logprint (LOG_ERROR, "line %d: checker error, required property "
807 : : "`%s' not found in `%s:%s'\n", def->line, "Stop",
808 : 0 : def->type, def->instance);
809 : 0 : errors++;
810 : : }
811 : : // property 'Points' is also required
812 [ - + ]: 91 : if (checker_find_property (def, "Points") <= 0)
813 : : {
814 : : logprint (LOG_ERROR, "line %d: checker error, required property "
815 : : "`%s' not found in `%s:%s'\n", def->line, "Points",
816 : 0 : def->type, def->instance);
817 : 0 : errors++;
818 : : }
819 : : // property 'Values' is invalid
820 [ - + ]: 91 : if (checker_find_property (def, "Values") > 0)
821 : : {
822 : : logprint (LOG_ERROR, "line %d: checker error, extraneous property "
823 : : "`%s' is invalid in `%s:%s'\n", def->line, "Values",
824 : 0 : def->type, def->instance);
825 : 0 : errors++;
826 : : }
827 : : }
828 : : }
829 : : }
830 : 103 : return errors;
831 : : }
832 : :
833 : : /* This function checks the actions to be taken in the netlist. It
834 : : returns zero on success, non-zero otherwise. */
835 : 103 : static int checker_validate_actions (struct definition_t * root)
836 : : {
837 : 103 : int a, c, n, errors = 0;
838 [ - + ]: 103 : if ((n = checker_count_definitions (root, NULL, 1)) < 1)
839 : : {
840 : 0 : logprint (LOG_ERROR, "checker error, no actions defined: nothing to do\n");
841 : 0 : errors++;
842 : : }
843 : : else
844 : : {
845 : : // check requirements for s-parameter analysis
846 [ + + ]: 103 : if ((a = checker_count_definitions (root, "SP", 1)) >= 1)
847 : : {
848 [ - + ]: 18 : if ((n = checker_count_definitions (root, "Pac", 0)) < 1)
849 : : {
850 : : logprint (LOG_ERROR, "checker error, %d `Pac' definitions found, at "
851 : 0 : "least 1 required\n", n);
852 : 0 : errors++;
853 : : }
854 : : }
855 : : // count analyses requiring a DC solution
856 : 103 : a += checker_count_definitions (root, "AC", 1);
857 : : // check dc-analysis requirements
858 : 103 : c = checker_count_nonlinearities (root);
859 : 103 : n = checker_count_definitions (root, "DC", 1);
860 [ - + ]: 103 : if (n > 1)
861 : : {
862 : : logprint (LOG_ERROR, "checker error, the .DC action is defined %dx, "
863 : 0 : "single or none required\n", n);
864 : 0 : errors++;
865 : : }
866 [ + + ][ + + ]: 103 : if (a >= 1 && c >= 1 && n < 1)
[ - + ]
867 : : {
868 : : logprint (LOG_ERROR, "checker error, a .DC action is required for this "
869 : 0 : "circuit definition (accounted %d non-linearities)\n", c);
870 : 0 : errors++;
871 : : }
872 : : }
873 : 103 : errors += checker_validate_para (root);
874 : 103 : errors += checker_validate_ports (root);
875 : 103 : errors += checker_validate_lists (root);
876 : 103 : return errors;
877 : : }
878 : :
879 : : /* This function checks the validity of each microstrip component and
880 : : its substrate and model references. It returns zero on success,
881 : : emit error messages if necessary and returns non-zero on errors. */
882 : 219 : static int checker_validate_strips (struct definition_t * root)
883 : : {
884 : 219 : int errors = 0;
885 : : struct value_t * val;
886 [ + + ]: 1317 : for (struct definition_t * def = root; def != NULL; def = def->next)
887 : : {
888 [ + + ]: 1098 : if (!def->action)
889 : : {
890 : : /* find components with substrate property */
891 [ + + ]: 904 : if (checker_is_property (def->define, "Subst") == PROP_STR)
892 : : {
893 : : /* check validity of 'Subst' property */
894 [ - + ]: 24 : if ((val = checker_validate_reference (def, "Subst")) == NULL)
895 : : {
896 : 0 : errors++;
897 : : }
898 : : else
899 : : {
900 [ - + ]: 24 : if (checker_count_definition (root, "SUBST", val->ident) != 1)
901 : : {
902 : : logprint (LOG_ERROR, "line %d: checker error, no such substrate "
903 : : "`%s' found as specified in `%s:%s'\n", def->line,
904 : 0 : val->ident, def->type, def->instance);
905 : 0 : errors++;
906 : : }
907 : : }
908 : : /* check validity of 'Model' property */
909 : : #if DISABLE_FOR_NOW /* ThinkME!!! */
910 : : if ((val = checker_validate_reference (def, "Model")) == NULL)
911 : : {
912 : : errors++;
913 : : }
914 : : #endif
915 : : }
916 : : }
917 : : }
918 : 219 : return errors;
919 : : }
920 : :
921 : : /* This function counts the number of occurrences of the given node
922 : : name in the given netlist definition root. */
923 : 2 : static int checker_count_nodes (struct definition_t * root, char * n)
924 : : {
925 : 2 : int count = 0;
926 : : struct node_t * node;
927 [ + + ]: 34 : for (struct definition_t * def = root; def != NULL; def = def->next)
928 : : {
929 [ + + ][ + + ]: 32 : if (!def->action && !def->nodeset)
930 : : {
931 [ + + ]: 84 : for (node = def->nodes; node != NULL; node = node->next)
932 [ + + ]: 58 : if (!strcmp (node->node, n)) count++;
933 : : }
934 : : }
935 : 2 : return count;
936 : : }
937 : :
938 : : /* The function identifies duplicate nodesets for the same node which
939 : : is not allowed. It returns the number of duplications. */
940 : 2 : static int checker_count_nodesets (struct definition_t * root, char * n)
941 : : {
942 : 2 : int count = 0;
943 [ + + ]: 34 : for (struct definition_t * def = root; def != NULL; def = def->next)
944 : : {
945 [ + + ][ + - ]: 32 : if (def->nodeset && !def->duplicate)
946 : : {
947 : 4 : char * node = def->nodes->node;
948 [ + + ]: 4 : if (!strcmp (node, n))
949 : : {
950 [ - + ]: 2 : if (++count > 1) def->duplicate = 1;
951 : : }
952 : : }
953 : : }
954 : 2 : return count;
955 : : }
956 : :
957 : : /* The following function checks whether the nodes specified by the
958 : : nodeset functionality is valid in its current scope. It does not
959 : : check across subcircuit boundaries. */
960 : 219 : static int checker_validate_nodesets (struct definition_t * root)
961 : : {
962 : 219 : int errors = 0;
963 [ + + ]: 1317 : for (struct definition_t * def = root; def != NULL; def = def->next)
964 : : {
965 [ + + ][ + - ]: 1098 : if (def->nodeset && checker_count_nodes (def) == 1)
[ + + ]
966 : : {
967 : 2 : char * node = def->nodes->node;
968 [ - + ]: 2 : if (checker_count_nodes (root, node) <= 0)
969 : : {
970 : : logprint (LOG_ERROR, "line %d: checker error, no such node `%s' found "
971 : : "as referenced by `%s:%s'\n", def->line, node, def->type,
972 : 0 : def->instance);
973 : 0 : errors++;
974 : : }
975 [ - + ]: 2 : if (checker_count_nodesets (root, node) > 1)
976 : : {
977 : : logprint (LOG_ERROR, "line %d: checker error, the node `%s' is not "
978 : : "uniquely defined by `%s:%s'\n", def->line, node, def->type,
979 : 0 : def->instance);
980 : 0 : errors++;
981 : : }
982 : : }
983 : : }
984 : 219 : return errors;
985 : : }
986 : :
987 : : /* This function should be called after the netlist and the equation
988 : : list have been checked. It verifies that parameter sweep
989 : : definitions and equation variable identifiers are unique. The
990 : : function returns zero on success and non-zero otherwise. */
991 : 103 : static int netlist_checker_variables_intern (struct definition_t * root,
992 : : environment * env)
993 : : {
994 : 103 : int errors = 0, pos;
995 : : struct value_t * para, * ref;
996 : 103 : strlist * eqnvars = env->getChecker()->variables ();
997 [ + - ]: 103 : strlist * instances = new strlist ();
998 [ + - ]: 103 : strlist * vars = new strlist ();
999 [ + - ]: 103 : strlist * refs = new strlist ();
1000 : : // go through list of netlist definitions
1001 [ + + ]: 1222 : for (struct definition_t * def = root; def != NULL; def = def->next)
1002 : : {
1003 : : // find parameters sweeps
1004 [ + + ][ + + ]: 1119 : if (def->action == 1 && !strcmp (def->type, "SW"))
1005 : : {
1006 : 59 : para = checker_find_reference (def, "Param");
1007 : 59 : ref = checker_find_reference (def, "Sim");
1008 [ + - ][ + - ]: 59 : if (para != NULL && ref != NULL)
1009 : : {
1010 : : // check whether sweep variable collides with equations
1011 [ + - ][ - + ]: 59 : if (eqnvars && eqnvars->contains (para->ident))
[ - + ]
1012 : : {
1013 : : logprint (LOG_ERROR, "checker error, equation variable `%s' "
1014 : : "already defined by `%s:%s'\n", para->ident,
1015 : 0 : def->type, def->instance);
1016 : 0 : errors++;
1017 : : }
1018 : : // check for duplicate parameter names in parameter sweeps, but
1019 : : // allow them in same order sweeps
1020 [ - + ]: 59 : if ((pos = vars->index (para->ident)) != -1)
1021 : : {
1022 [ # # ]: 0 : if (strcmp (ref->ident, refs->get (pos)))
1023 : : {
1024 : : logprint (LOG_ERROR, "checker error, variable `%s' in `%s:%s' "
1025 : : "already defined by `%s:%s'\n", para->ident, def->type,
1026 : 0 : def->instance, def->type, instances->get (pos));
1027 : 0 : errors++;
1028 : : }
1029 : : }
1030 : : // check for duplicate simulations in parameter sweeps (same order
1031 : : // sweep) and allow same parameter name only
1032 [ - + ]: 59 : if ((pos = refs->index (ref->ident)) != -1)
1033 : : {
1034 [ # # ]: 0 : if (strcmp (para->ident, vars->get (pos)))
1035 : : {
1036 : : logprint (LOG_ERROR, "checker error, conflicting variables `%s' "
1037 : : "in `%s:%s' and `%s' in `%s:%s' for `%s'\n",
1038 : : para->ident, def->type, def->instance,
1039 : : vars->get (pos), def->type, instances->get (pos),
1040 : 0 : ref->ident);
1041 : 0 : errors++;
1042 : : }
1043 : : }
1044 : : // collect parameter sweep variables for the above two checks
1045 : 59 : instances->add (def->instance);
1046 : 59 : vars->add (para->ident);
1047 : 59 : refs->add (ref->ident);
1048 : : }
1049 : : }
1050 : : }
1051 [ + - ]: 103 : delete eqnvars;
1052 [ + - ]: 103 : delete refs;
1053 [ + - ]: 103 : delete vars;
1054 [ + - ]: 103 : delete instances;
1055 : 103 : return errors;
1056 : : }
1057 : :
1058 : : /* This is the overall variable checker for the parsed netlist. See
1059 : : the above function for details. */
1060 : 103 : int netlist_checker_variables (environment * env)
1061 : : {
1062 : 103 : return netlist_checker_variables_intern (definition_root, env);
1063 : : }
1064 : :
1065 : : /* The function checks whether the given key-value combination is
1066 : : inside the allowed range defined by the given property definition
1067 : : and returns the number of error or zero otherwise. */
1068 : 10160 : static int checker_value_in_prop_range (char * instance, struct define_t * def,
1069 : : struct pair_t * pp,
1070 : : struct property_t * prop)
1071 : : {
1072 : 10160 : int errors = 0;
1073 : : // check values
1074 [ + + ]: 10160 : if (PROP_IS_VAL (*prop))
1075 : : {
1076 [ + + ]: 9327 : if (!PROP_IS_LST (*prop))
1077 : : {
1078 : : // lists of values possible?
1079 [ - + ]: 9321 : if (pp->value->next != NULL)
1080 : : {
1081 : : logprint (LOG_ERROR,
1082 : : "checker error, value of `%s' needs to be "
1083 : : "a single value in `%s:%s', no lists possible\n",
1084 : 0 : pp->key, def->type, instance);
1085 : 0 : errors++;
1086 : : }
1087 : : }
1088 : : else
1089 : : {
1090 : : // a value list
1091 : 6 : struct value_t * val = pp->value;
1092 : 6 : val->var = TAG_VECTOR;
1093 : : // check and evaluate the unit scale in a value list
1094 [ + + ]: 24 : for (; val != NULL; val = val->next)
1095 : : {
1096 [ - + ]: 18 : if (!checker_evaluate_scale (val))
1097 : 0 : errors++;
1098 : : }
1099 : : }
1100 : : // check range of all values
1101 [ + + ][ + + ]: 9327 : if (PROP_HAS_RANGE (*prop))
[ + + ][ + + ]
1102 : : {
1103 : 5617 : struct value_t * val = pp->value;
1104 [ + + ]: 5617 : if (val->ident)
1105 : : {
1106 : : /* no range checking on variable identifier */
1107 : : logprint (LOG_STATUS,
1108 : : "checker notice, value of `%s' (variable `%s') could be "
1109 : : "out of range `%c%g,%g%c' in `%s:%s'\n",
1110 : : pp->key, val->ident, prop->range.il, prop->range.l,
1111 : 22 : prop->range.h, prop->range.ih, def->type, instance);
1112 : 22 : val = NULL;
1113 : : }
1114 [ + + ]: 11212 : for (; val != NULL; val = val->next)
1115 : : {
1116 : 5595 : int rerror = 0;
1117 [ + + ][ - + ]: 5595 : if (prop->range.il == '[' && (val->value < prop->range.l))
1118 : 0 : rerror++;
1119 [ + + ][ - + ]: 5595 : if (prop->range.il == ']' && !(val->value > prop->range.l))
1120 : 0 : rerror++;
1121 [ + + ][ - + ]: 5595 : if (prop->range.ih == '[' && !(val->value < prop->range.h))
1122 : 0 : rerror++;
1123 [ + + ][ - + ]: 5595 : if (prop->range.ih == ']' && (val->value > prop->range.h))
1124 : 0 : rerror++;
1125 [ - + ]: 5595 : if (rerror)
1126 : : {
1127 : : logprint (LOG_ERROR,
1128 : : "checker error, value of `%s' (%g) is out of "
1129 : : "range `%c%g,%g%c' in `%s:%s'\n",
1130 : : pp->key, val->value, prop->range.il, prop->range.l,
1131 : 0 : prop->range.h, prop->range.ih, def->type, instance);
1132 : 0 : errors++;
1133 : : }
1134 : : }
1135 : : }
1136 : : // check fraction of integers
1137 [ + + ]: 9327 : if (PROP_IS_INT (*prop))
1138 : : {
1139 : : double integral;
1140 [ - + ]: 349 : if (modf (pp->value->value, &integral) != 0)
1141 : : {
1142 : : logprint (LOG_ERROR,
1143 : : "checker error, value of `%s' (%g) needs to be "
1144 : : "an integer in `%s:%s'\n",
1145 [ # # ]: 0 : pp->key, pp->value->value, def->type, instance);
1146 : 349 : errors++;
1147 : : }
1148 : : }
1149 : : }
1150 : : // check identifiers
1151 : : else
1152 : : {
1153 : : // no identifier given
1154 [ - + ]: 833 : if (pp->value->ident == NULL)
1155 : : {
1156 : : logprint (LOG_ERROR,
1157 : : "checker error, value of `%s' (%g) needs to be "
1158 : : "an identifier in `%s:%s'\n",
1159 : 0 : pp->key, pp->value->value, def->type, instance);
1160 : 0 : errors++;
1161 : : }
1162 : : // check identifier range
1163 : : else
1164 : : {
1165 [ + + ]: 833 : if (PROP_HAS_STR (*prop))
1166 : : {
1167 : 672 : int i, found = 0;
1168 : : char range[256];
1169 : 672 : sprintf (range, "[");
1170 [ + + ]: 2843 : for (i = 0; prop->range.str[i]; i++)
1171 : : {
1172 : 2171 : strcat (range, prop->range.str[i]);
1173 : 2171 : strcat (range, ",");
1174 [ + + ]: 2171 : if (!strcmp (prop->range.str[i], pp->value->ident)) found++;
1175 : : }
1176 [ - + ]: 672 : if (!found)
1177 : : {
1178 : 0 : range[strlen (range) - 1] = ']';
1179 : : logprint (LOG_ERROR,
1180 : : "checker error, value of `%s' (%s) needs to be "
1181 : : "in %s in `%s:%s'\n",
1182 [ # # ]: 0 : pp->key, pp->value->ident, range, def->type, instance);
1183 : 0 : errors++;
1184 : : }
1185 : 672 : else pp->value->range = 1;
1186 : : }
1187 : : }
1188 : : }
1189 : 10160 : return errors;
1190 : : }
1191 : :
1192 : : /* The function checks whether the given key-value combination being
1193 : : part of the available definition is inside the allowed range and
1194 : : returns zero if not. Otherwise the function returns non-zero. */
1195 : 10160 : static int checker_value_in_range (char * instance, struct define_t * def,
1196 : : struct pair_t * pp)
1197 : : {
1198 : 10160 : int i, errors = 0;
1199 : : // go through required properties
1200 [ + + ]: 724777 : for (i = 0; PROP_IS_PROP (def->required[i]); i++)
1201 : : {
1202 [ + + ]: 714617 : if (!strcmp (def->required[i].key, pp->key))
1203 : : {
1204 : : errors += checker_value_in_prop_range (instance, def, pp,
1205 : 5385 : &def->required[i]);
1206 : : }
1207 : : }
1208 : : // go through optional properties
1209 [ + + ]: 122737 : for (i = 0; PROP_IS_PROP (def->optional[i]); i++)
1210 : : {
1211 [ + + ]: 112577 : if (!strcmp (def->optional[i].key, pp->key))
1212 : : {
1213 : : errors += checker_value_in_prop_range (instance, def, pp,
1214 : 4775 : &def->optional[i]);
1215 : : }
1216 : : }
1217 : 10160 : return errors ? 0 : 1;
1218 : : }
1219 : :
1220 : : /* The function determines the subcircuit definitions defined in the
1221 : : original netlist and builds an appropriate subcircuit definition
1222 : : list. It returns the given definition list with the subcircuits
1223 : : removed. */
1224 : : static struct definition_t *
1225 : 116 : checker_build_subcircuits (struct definition_t * root)
1226 : : {
1227 : : struct definition_t * def, * next, * prev;
1228 [ + + ]: 1282 : for (prev = NULL, def = root; def != NULL; def = next)
1229 : : {
1230 : 1166 : next = def->next;
1231 [ + + ]: 1166 : if (!strcmp (def->type, "Def"))
1232 : : {
1233 [ - + ]: 13 : if (prev)
1234 : : {
1235 : 0 : prev->next = next;
1236 : : }
1237 : : else
1238 : : {
1239 : 13 : root = next;
1240 : : }
1241 : 13 : def->sub = checker_build_subcircuits (def->sub);
1242 : 13 : def->next = subcircuit_root;
1243 : 13 : subcircuit_root = def;
1244 : : }
1245 : 1153 : else prev = def;
1246 : : }
1247 : 116 : return root;
1248 : : }
1249 : :
1250 : : /* The function produces a copy of the given circuit definition and
1251 : : marks it as a copy. The node definition are not included within
1252 : : the copy. */
1253 : : static struct definition_t *
1254 : 135 : checker_copy_subcircuit (struct definition_t * sub)
1255 : : {
1256 : : struct definition_t * copy;
1257 : 135 : copy = (struct definition_t *) calloc (sizeof (struct definition_t), 1);
1258 : 135 : copy->action = sub->action;
1259 : 135 : copy->nonlinear = sub->nonlinear;
1260 : 135 : copy->substrate = sub->substrate;
1261 : 135 : copy->nodeset = sub->nodeset;
1262 : 135 : copy->define = sub->define;
1263 : 135 : copy->pairs = sub->pairs;
1264 : 135 : copy->ncount = sub->ncount;
1265 : 135 : copy->type = strdup (sub->type);
1266 : 135 : copy->copy = 1;
1267 : 135 : return copy;
1268 : : }
1269 : :
1270 : : /* This function translates the node definitions of the given
1271 : : subcircuit element 'sub'. The translation is based upon the node
1272 : : definitions of the subcircuit 'type' and the instance 'inst' of
1273 : : such a subcircuit. The translated nodes are saved in an extra
1274 : : 'xlate' field of each node of the subcircuit element 'sub'. */
1275 : 143 : static void checker_xlat_subcircuit_nodes (struct definition_t * type,
1276 : : struct definition_t * inst,
1277 : : struct definition_t * sub)
1278 : : {
1279 : : struct node_t * n, * ninst, * ntype;
1280 : : int i;
1281 : : // go through nodes of the subcircuit 'type' and 'inst'
1282 [ + + ]: 691 : for (i = 1, ntype = type->nodes, ninst = inst->nodes; ntype != NULL;
1283 : : ntype = ntype->next, ninst = ninst->next, i++)
1284 : : {
1285 [ + + ]: 1906 : for (n = sub->nodes; n != NULL; n = n->next)
1286 : : {
1287 : : /* check whether a node in the subcircuit element 'sub' corresponds
1288 : : with the 'type', then assign the 'inst's node name */
1289 [ + + ]: 1358 : if (!strcmp (n->node, ntype->node))
1290 : : {
1291 : 149 : n->xlate = strdup (ninst->node);
1292 : 149 : n->xlatenr = i;
1293 : : }
1294 : : }
1295 : : }
1296 : 143 : }
1297 : :
1298 : : /* The function creates a subcircuit node name consisting of the given
1299 : : arguments. If the given 'instances' is NULL it is left out. The
1300 : : caller is responsible to free() the returned string. */
1301 : 219 : static char * checker_subcircuit_node (char * type, char * instances,
1302 : : char * instance, char * node)
1303 : : {
1304 : : char * txt = (char *)
1305 : 438 : calloc (1, strlen (type) + strlen (instance) + strlen (node) +
1306 [ + + ]: 219 : (instances ? strlen (instances) : 0) + 4);
1307 [ + + ]: 219 : if (instances)
1308 : 128 : sprintf (txt, "%s.%s.%s.%s", type, instances, instance, node);
1309 : : else
1310 : 91 : sprintf (txt, "%s.%s.%s", type, instance, node);
1311 : 219 : return txt;
1312 : : }
1313 : :
1314 : : /* The function reverses the order of the given node list and returns
1315 : : the reversed list. */
1316 : 135 : struct node_t * netlist_reverse_nodes (struct node_t * nodes)
1317 : : {
1318 : : struct node_t * root, * next;
1319 [ + + ]: 455 : for (root = NULL; nodes != NULL; nodes = next)
1320 : : {
1321 : 320 : next = nodes->next;
1322 : 320 : nodes->next = root;
1323 : 320 : root = nodes;
1324 : : }
1325 : 135 : return root;
1326 : : }
1327 : :
1328 : : /* This function assigns new node names to the subcircuit element
1329 : : 'copy' based upon the previous node translation between the
1330 : : subcircuit 'type' and the instance 'inst' of this type. The global
1331 : : 'gnd' node is not touched. */
1332 : : static void
1333 : 135 : checker_copy_subcircuit_nodes (struct definition_t * type,
1334 : : struct definition_t * inst,
1335 : : struct definition_t * sub,
1336 : : struct definition_t * copy,
1337 : : char * instances)
1338 : : {
1339 : 135 : struct node_t * n, * ncopy, * root = NULL;
1340 : :
1341 : : // go through the list of the subcircuit element's 'sub' nodes
1342 [ + + ]: 455 : for (n = sub->nodes; n != NULL; n = n->next)
1343 : : {
1344 : :
1345 : : // create new node based upon the node translation
1346 : 320 : ncopy = (struct node_t *) calloc (sizeof (struct node_t), 1);
1347 : 320 : ncopy->xlatenr = n->xlatenr;
1348 [ + + ]: 320 : if (n->xlate) // translated node
1349 : : {
1350 [ + + ]: 125 : if (instances == NULL)
1351 : 45 : ncopy->node = strdup (n->xlate);
1352 : : else
1353 : 80 : ncopy->node = NULL; // leave it blank yet, indicates translation
1354 : : }
1355 [ + + ]: 195 : else if (!strcmp (n->node, "gnd")) // ground node
1356 : : {
1357 : 8 : ncopy->node = strdup (n->node);
1358 : : }
1359 [ - + ]: 187 : else if (n->node[strlen (n->node) - 1] == '!') // global node
1360 : : {
1361 : 0 : ncopy->node = strdup (n->node);
1362 : : }
1363 : : else // internal subcircuit element node
1364 : : {
1365 : : ncopy->node = checker_subcircuit_node (type->instance, instances,
1366 : 187 : inst->instance, n->node);
1367 : : }
1368 : : // chain the new node list
1369 : 320 : ncopy->next = root;
1370 : 320 : root = ncopy;
1371 : : }
1372 : :
1373 : : /* and finally reverse the created node list and assign it to the
1374 : : subcircuit element's 'copy' */
1375 : 135 : copy->nodes = netlist_reverse_nodes (root);
1376 : 135 : }
1377 : :
1378 : : // Returns the node at the given position.
1379 : 80 : static struct node_t * checker_get_circuit_node (struct node_t * root, int n)
1380 : : {
1381 [ + + ]: 224 : for (int i = 1; i < n; i++)
1382 : : {
1383 : 144 : root = root->next;
1384 [ - + ]: 144 : assert (root != NULL);
1385 : : }
1386 : 80 : return root;
1387 : : }
1388 : :
1389 : : // The function cleans the translated nodes of a subcircuit template.
1390 : 143 : static void checker_cleanup_xlat_nodes (struct definition_t * sub)
1391 : : {
1392 [ + + ]: 495 : for (struct node_t * n = sub->nodes; n != NULL; n = n->next)
1393 : : {
1394 [ + + ]: 352 : if (n->xlate) free (n->xlate);
1395 : 352 : n->xlate = NULL;
1396 : 352 : n->xlatenr = 0;
1397 : : }
1398 : 143 : }
1399 : :
1400 : : /* The function is used to assign the nodes of the 'copy' subcircuit
1401 : : element which were left blank intentionally by the element copy in
1402 : : order to indicate that it is an external node. Again, if the
1403 : : current node translation indicates an external node it is blanked
1404 : : again, otherwise the node gets a unique internal name. If the
1405 : : 'instances' list is NULL, then this indicates the root circuit list
1406 : : and node translations are done though they are 'external'. */
1407 : : static void
1408 : 96 : checker_copy_circuit_nodes (struct definition_t * type,
1409 : : struct definition_t * inst,
1410 : : struct definition_t * sub,
1411 : : struct definition_t * copy,
1412 : : char * instances)
1413 : : {
1414 : : struct node_t * n, * ncopy;
1415 : :
1416 : : // go through the list of the subcircuit element's 'copy' nodes
1417 [ + + ]: 304 : for (ncopy = copy->nodes; ncopy != NULL; ncopy = ncopy->next)
1418 : : {
1419 : : // these NULL nodes have intentionally been blanked
1420 [ + + ]: 208 : if (ncopy->node == NULL)
1421 : : {
1422 [ - + ]: 80 : assert (ncopy->xlatenr != 0);
1423 : : // get translated node
1424 : 80 : n = checker_get_circuit_node (sub->nodes, ncopy->xlatenr);
1425 : 80 : ncopy->xlatenr = n->xlatenr;
1426 [ + + ]: 80 : if (n->xlate) // translated node
1427 : : {
1428 [ + - ]: 48 : if (instances == NULL)
1429 : : // external node indicated by no instances given
1430 : 48 : ncopy->node = strdup (n->xlate);
1431 : : else
1432 : 0 : ncopy->node = NULL; // keep blank
1433 : : }
1434 [ - + ]: 32 : else if (!strcmp (n->node, "gnd")) // global ground node
1435 : : {
1436 : 0 : ncopy->node = strdup (n->node);
1437 : : }
1438 [ - + ]: 32 : else if (n->node[strlen (n->node) - 1] == '!') // other global node
1439 : : {
1440 : 0 : ncopy->node = strdup (n->node);
1441 : : }
1442 : : else // internal subcircuit element node
1443 : : {
1444 : : ncopy->node = checker_subcircuit_node (type->instance, instances,
1445 : 32 : inst->instance, n->node);
1446 : : }
1447 : : }
1448 : : }
1449 : 96 : }
1450 : :
1451 : : /* This function returns the last entry of the given list of
1452 : : definitions or NULL if there is no such element. */
1453 : : static struct definition_t *
1454 : 23 : checker_find_last_definition (struct definition_t * root)
1455 : : {
1456 [ + - ]: 231 : for (struct definition_t * def = root; def != NULL; def = def->next)
1457 [ + + ]: 231 : if (def->next == NULL) return def;
1458 : 23 : return NULL;
1459 : : }
1460 : :
1461 : : /* Based upon the the given subcircuit instance identifier list the
1462 : : function returns a "." - concatenated string or NULL. */
1463 : 143 : static char * checker_subcircuit_instance_list (strlist * instances)
1464 : : {
1465 [ + + ][ + + ]: 143 : if (instances && instances->length () > 0)
[ + + ]
1466 : 96 : return instances->toString (".");
1467 : 143 : return NULL;
1468 : : }
1469 : :
1470 : : /* The function creates a subcircuit instance name consisting of the
1471 : : given arguments. If the given 'instances' is NULL it is left out.
1472 : : The caller is responsible to free() the returned string. */
1473 : 135 : static char * checker_subcircuit_instance (char * type, char * instances,
1474 : : char * instance, char * base)
1475 : : {
1476 : : char * txt = (char *)
1477 : 270 : calloc (1, strlen (type) + strlen (instance) + strlen (base) +
1478 [ + + ]: 135 : (instances ? strlen (instances) : 0) + 4);
1479 [ + + ]: 135 : if (instances)
1480 : 96 : sprintf (txt, "%s.%s.%s.%s", type, instances, instance, base);
1481 : : else
1482 : 39 : sprintf (txt, "%s.%s.%s", type, instance, base);
1483 : 135 : return txt;
1484 : : }
1485 : :
1486 : : /* This function produces a copy of the given subcircuit 'type'
1487 : : containing the subcircuit elements. Based upon the instance 'inst'
1488 : : definitions (node names and instance name) it assign new element
1489 : : instances and node names. The function returns a NULL terminated
1490 : : circuit element list in reverse order. */
1491 : : static struct definition_t *
1492 : 23 : checker_copy_subcircuits (struct definition_t * type,
1493 : : struct definition_t * inst, strlist * * instances,
1494 : : environment * parent)
1495 : : {
1496 : : struct definition_t * def, * copy;
1497 : 23 : struct definition_t * root = NULL;
1498 : : strlist * instcopy;
1499 : : char * list;
1500 : :
1501 : : // create environment for subcircuit instance
1502 [ + - ]: 23 : environment * child = new environment (*(type->env));
1503 : 23 : parent->push_front_Child (child);
1504 : :
1505 : : // put instance properties into subcircuit environment
1506 [ + + ]: 46 : for (struct pair_t * pair = inst->pairs; pair != NULL; pair = pair->next)
1507 : : {
1508 : : // anything else than the 'Type'
1509 [ - + ]: 23 : if (strcmp (pair->key, "Type"))
1510 : : {
1511 [ # # ]: 0 : if (pair->value->ident == NULL)
1512 : : {
1513 : : // simple value
1514 : 0 : child->setDoubleConstant (pair->key, pair->value->value);
1515 : 0 : child->setDouble (pair->key, pair->value->value);
1516 : : }
1517 : : else
1518 : : {
1519 : : // reference to variable in upper environment
1520 : 0 : child->setDoubleReference (pair->key, pair->value->ident);
1521 : : }
1522 : : }
1523 : : }
1524 : :
1525 : : // go through element list of subcircuit
1526 [ + + ]: 166 : for (def = type->sub; def != NULL; def = def->next)
1527 : : {
1528 : :
1529 : : // translate the node list
1530 : 143 : checker_xlat_subcircuit_nodes (type, inst, def);
1531 : :
1532 : : // allow recursive subcircuits
1533 [ + + ]: 143 : if (!strcmp (def->type, "Sub"))
1534 : : {
1535 : : // get subcircuit template definition
1536 : 8 : struct definition_t * sub = checker_get_subcircuit (def);
1537 : : // create a copy of the current subcircuit instance list
1538 [ + - ][ + - ]: 8 : if ((*instances) == NULL) (*instances) = new strlist ();
1539 [ + - ]: 8 : instcopy = new strlist (*(*instances));
1540 : : // append instance name to recursive instance list
1541 : 8 : (*instances)->append (inst->instance);
1542 : 8 : copy = checker_copy_subcircuits (sub, def, instances, child);
1543 : : // put the expanded definitions into the sublist
1544 [ + - ]: 8 : if (copy)
1545 : : {
1546 : 8 : list = checker_subcircuit_instance_list (instcopy);
1547 : : // assign blanked node names to each subcircuit
1548 [ + + ]: 104 : for (struct definition_t * c = copy; c != NULL; c = c->next)
1549 : : {
1550 : 96 : checker_copy_circuit_nodes (type, inst, def, c, list);
1551 : : }
1552 : : // append the copies to the subcircuit list
1553 : 8 : struct definition_t * last = checker_find_last_definition (copy);
1554 : 8 : last->next = root;
1555 : 8 : root = copy;
1556 : : }
1557 : : // restore original instance list
1558 [ + - ]: 8 : delete *instances;
1559 : 8 : *instances = instcopy;
1560 : : }
1561 : : else
1562 : : {
1563 : : // element copy
1564 : 135 : copy = checker_copy_subcircuit (def);
1565 : : // assign new instance name to the element
1566 : 135 : list = checker_subcircuit_instance_list (*instances);
1567 : : copy->instance =
1568 : : checker_subcircuit_instance (type->instance, list,
1569 : 135 : inst->instance, def->instance);
1570 : 135 : copy->subcircuit = strdup (type->instance);
1571 : : // assign node list
1572 : 135 : checker_copy_subcircuit_nodes (type, inst, def, copy, list);
1573 : : // apply environment
1574 : 135 : copy->env = child;
1575 : : // chain definition (circuit) list
1576 : 135 : copy->next = root;
1577 : 135 : root = copy;
1578 : : }
1579 : :
1580 : : // cleanup translated nodes
1581 : 143 : checker_cleanup_xlat_nodes (def);
1582 : : }
1583 : :
1584 : : // try giving child environment a unique name
1585 [ + - ]: 23 : strlist * icopy = new strlist ();
1586 : 23 : icopy->append (type->instance);
1587 : 23 : icopy->append (*(instances));
1588 : 23 : icopy->append (inst->instance);
1589 [ + - ][ + - ]: 23 : child->setName (std::string(icopy->toString (".")));
[ + - ]
1590 [ + - ]: 23 : delete icopy;
1591 : :
1592 : 23 : return root;
1593 : : }
1594 : :
1595 : : /* The function checks whether the subcircuit 'instance' with the
1596 : : subcircuit 'type' is defined in cycles. It recursively goes
1597 : : through the definitions and emits an appropriate error message if
1598 : : necessary. The function returns zero if there are no cycles
1599 : : detected and non-zero with cycles found. */
1600 : 27 : static int checker_validate_sub_cycles (struct definition_t * root,
1601 : : char * type, char * instance,
1602 : : strlist * * deps)
1603 : : {
1604 : 27 : int errors = 0, error;
1605 : : struct value_t * val;
1606 : :
1607 : : /* emit an appropriate error message if the subcircuit type is already
1608 : : in the dependencies */
1609 [ - + ]: 27 : if ((*deps)->contains (type))
1610 : : {
1611 : : logprint (LOG_ERROR, "checker error, cyclic definition of `%s:%s' "
1612 : : "detected, involves: %s\n",
1613 : 0 : type, instance, (*deps)->toString ());
1614 : 0 : return ++errors;
1615 : : }
1616 : 27 : (*deps)->append (type);
1617 : :
1618 : : // create temporary list of subcircuit types already tested
1619 [ + - ]: 27 : strlist * checked = new strlist ();
1620 : : // go through the list of circuit elements of the subcircuit
1621 [ + + ]: 218 : for (struct definition_t * def = root->sub; def != NULL; def = def->next)
1622 : : {
1623 : : // find the appropriate definitions
1624 [ + + ]: 191 : if (!strcmp (def->type, "Sub"))
1625 : : {
1626 : : // recurse into subcircuit instances
1627 [ + - ]: 8 : if ((val = checker_find_reference (def, "Type")) != NULL)
1628 : : {
1629 [ + - ]: 8 : if (!checked->contains (val->ident)) // only if not already checked
1630 : : {
1631 : : struct definition_t * sub;
1632 : 8 : checked->append (val->ident);
1633 : : // copy current dependencies
1634 [ + - ]: 8 : strlist * copy = new strlist (*(*deps));
1635 : : // validate subcircuit
1636 : 8 : sub = checker_find_subcircuit (val->ident);
1637 [ + - ]: 8 : if (sub != NULL) // if possible
1638 : : error = checker_validate_sub_cycles (sub, sub->instance,
1639 : 8 : instance, deps);
1640 : : else
1641 : 0 : error = 1;
1642 : : // on errors: go on
1643 [ - + ]: 8 : if (error)
1644 : : {
1645 : 0 : errors += error;
1646 [ # # ]: 0 : delete copy;
1647 : : }
1648 : : // no errors: restore original dependencies
1649 : : else
1650 : : {
1651 [ + - ]: 8 : delete *deps;
1652 : 8 : *deps = copy;
1653 : : }
1654 : : }
1655 : : }
1656 : : }
1657 : : }
1658 [ + - ]: 27 : delete checked;
1659 : 27 : return errors;
1660 : : }
1661 : :
1662 : : /* This function dynamically creates a circuit definition based on a
1663 : : given subcircuit definition including type, number of nodes and the
1664 : : properties. */
1665 : 19 : static struct define_t * netlist_create_define (struct definition_t * def)
1666 : : {
1667 : : int o, r;
1668 : : struct pair_t * p;
1669 : : struct define_t * d =
1670 : 19 : (struct define_t *) calloc (sizeof (struct define_t), 1);
1671 : 19 : d->type = strdup (def->instance);
1672 : 19 : d->nodes = checker_count_nodes (def);
1673 : 19 : d->action = PROP_COMPONENT;
1674 : :
1675 : : // determine number of required and optional parameters
1676 [ - + ]: 19 : for (o = r = 0, p = def->pairs; p != NULL; p = p->next)
1677 : : {
1678 [ # # ]: 0 : if (p->value == NULL)
1679 : 0 : r++;
1680 : : else
1681 : 0 : o++;
1682 : : }
1683 : : d->required =
1684 : 19 : (struct property_t *) calloc (sizeof (struct property_t), r + 2);
1685 : : d->optional =
1686 : 19 : (struct property_t *) calloc (sizeof (struct property_t), o + 1);
1687 : :
1688 : : // fill in parameters
1689 [ - + ]: 19 : for (o = r = 0, p = def->pairs; p != NULL; p = p->next)
1690 : : {
1691 [ # # ]: 0 : if (p->value == NULL)
1692 : : {
1693 : : // required
1694 : 0 : d->required[r].key = strdup (p->key);
1695 : 0 : d->required[r].type = PROP_REAL;
1696 : 0 : d->required[r].defaultval.d = PROP_NO_VAL;
1697 : 0 : d->required[r].defaultval.s = PROP_NO_STR;
1698 : 0 : d->required[r].range.il = '.';
1699 : 0 : d->required[r].range.l = 0;
1700 : 0 : d->required[r].range.h = 0;
1701 : 0 : d->required[r].range.ih = '.';
1702 : 0 : r++;
1703 : : }
1704 : : else
1705 : : {
1706 : : // optional
1707 : 0 : d->optional[o].key = strdup (p->key);
1708 : 0 : d->optional[o].type = PROP_REAL;
1709 : 0 : d->optional[o].defaultval.d = p->value->value;
1710 : 0 : d->optional[o].defaultval.s = PROP_NO_STR;
1711 : 0 : d->optional[o].range.il = '.';
1712 : 0 : d->optional[o].range.l = 0;
1713 : 0 : d->optional[o].range.h = 0;
1714 : 0 : d->optional[o].range.ih = '.';
1715 : 0 : o++;
1716 : : }
1717 : : }
1718 : :
1719 : : // extra required
1720 : 19 : d->required[r].key = strdup ("Type");
1721 : 19 : d->required[r].type = PROP_STR;
1722 : 19 : d->required[r].defaultval.d = PROP_NO_VAL;
1723 : 19 : d->required[r].defaultval.s = PROP_NO_STR;
1724 : 19 : d->required[r].range.il = '.';
1725 : 19 : d->required[r].range.l = 0;
1726 : 19 : d->required[r].range.h = 0;
1727 : 19 : d->required[r].range.ih = '.';
1728 : 19 : return d;
1729 : : }
1730 : :
1731 : : /* The function destroys the given circuit definition which must have
1732 : : been dynamically created before. */
1733 : 19 : static void netlist_free_define (struct define_t * d)
1734 : : {
1735 : : int i;
1736 : : struct property_t * p;
1737 : 19 : free ((char *) d->type);
1738 : : // free required properties
1739 [ + + ]: 38 : for (i = 0, p = d->required; p[i].key != NULL; i++)
1740 : : {
1741 : 19 : free ((char *) p[i].key);
1742 : : }
1743 : 19 : free (d->required);
1744 : : // free optional properties
1745 [ - + ]: 19 : for (i = 0, p = d->optional; p[i].key != NULL; i++)
1746 : : {
1747 : 0 : free ((char *) p[i].key);
1748 : : }
1749 : 19 : free (d->optional);
1750 : 19 : free (d);
1751 : 19 : }
1752 : :
1753 : : /* The function checks the presence of required and optional
1754 : : properties as well as their content in the given definition. It
1755 : : returns zero on success and non-zero otherwise. */
1756 : 1098 : static int checker_validate_properties (struct definition_t * root,
1757 : : struct definition_t * def,
1758 : : struct define_t * available)
1759 : : {
1760 : : struct pair_t * pair;
1761 : 1098 : int i, n, errors = 0;
1762 : :
1763 : : /* check whether the required properties are given */
1764 [ + + ]: 6483 : for (i = 0; PROP_IS_PROP (available->required[i]); i++)
1765 : : {
1766 : 5385 : n = checker_find_property (available->required[i].key, def->pairs);
1767 [ - + ]: 5385 : if (n != 1)
1768 : : {
1769 : : logprint (LOG_ERROR, "line %d: checker error, required property "
1770 : : "`%s' occurred %dx in `%s:%s'\n", def->line,
1771 : 0 : available->required[i].key, n, def->type, def->instance);
1772 : 0 : errors++;
1773 : : }
1774 : : }
1775 : : /* check whether the optional properties are given zero/once */
1776 [ + + ]: 6297 : for (i = 0; PROP_IS_PROP (available->optional[i]); i++)
1777 : : {
1778 : 5199 : n = checker_find_property (available->optional[i].key, def->pairs);
1779 [ - + ]: 5199 : if (n >= 2)
1780 : : {
1781 : : logprint (LOG_ERROR, "line %d: checker error, optional property "
1782 : : "`%s' occurred %dx in `%s:%s'\n", def->line,
1783 : 0 : available->optional[i].key, n, def->type, def->instance);
1784 : 0 : errors++;
1785 : : }
1786 : : }
1787 : :
1788 : : /* check the property content */
1789 [ + + ]: 11258 : for (pair = def->pairs; pair != NULL; pair = pair->next)
1790 : : {
1791 : : /* check whether properties are either required or optional */
1792 : 10160 : int type = checker_is_property (available, pair->key);
1793 [ - + ]: 10160 : if (type == PROP_NONE)
1794 : : {
1795 [ # # ]: 0 : if (strcmp (def->type, "Def"))
1796 : : {
1797 : : logprint (LOG_ERROR,
1798 : : "line %d: checker error, extraneous property `%s' is "
1799 : : "invalid in `%s:%s'\n", def->line,
1800 : 0 : pair->key, def->type, def->instance);
1801 : 0 : errors++;
1802 : : }
1803 : : }
1804 : : // do not check zero-length lists
1805 [ + - ]: 10160 : if (pair->value != NULL)
1806 : : {
1807 : : /* check and evaluate the unit scale in a property */
1808 [ - + ]: 10160 : if (!checker_evaluate_scale (pair->value))
1809 : 0 : errors++;
1810 : : /* check whether properties are in range */
1811 [ - + ]: 10160 : if (!checker_value_in_range (def->instance, available, pair))
1812 : : {
1813 : 0 : errors++;
1814 : : }
1815 : : /* check variables in properties */
1816 [ - + ]: 10160 : if (!checker_resolve_variable (root, def, pair, type))
1817 : 0 : errors++;
1818 : : }
1819 : : }
1820 : 1098 : return errors;
1821 : : }
1822 : :
1823 : : /* This function is used by the netlist checker to validate the
1824 : : subcircuits. It returns zero with no errors and non-zero on
1825 : : errors. */
1826 : 219 : static int checker_validate_subcircuits (struct definition_t * root)
1827 : : {
1828 : 219 : int errors = 0;
1829 : : // go through list of definitions
1830 [ + + ]: 1317 : for (struct definition_t * def = root; def != NULL; def = def->next)
1831 : : {
1832 : : // check subcircuit instances
1833 [ + + ]: 1098 : if (!strcmp (def->type, "Sub"))
1834 : : {
1835 : : struct value_t * val;
1836 : : // validate the 'Type' reference
1837 [ - + ]: 19 : if ((val = checker_validate_reference (def, "Type")) == NULL)
1838 : : {
1839 : 0 : errors++;
1840 : : }
1841 : : else
1842 : : {
1843 : : // find an appropriate subcircuit type
1844 : 19 : struct definition_t * sub = checker_find_subcircuit (val->ident);
1845 [ - + ]: 19 : if (sub == NULL)
1846 : : {
1847 : : logprint (LOG_ERROR, "line %d: checker error, no such subcircuit "
1848 : : "`%s' found as referred in `%s:%s'\n", def->line,
1849 : 0 : val->ident, def->type, def->instance);
1850 : 0 : errors++;
1851 : : }
1852 : : else
1853 : : {
1854 : : // check the number of nodes of the instance and the type
1855 : 19 : int n1 = checker_count_nodes (def);
1856 : 19 : int n2 = checker_count_nodes (sub);
1857 [ - + ]: 19 : if (n1 != n2)
1858 : : {
1859 : : logprint (LOG_ERROR, "line %d: checker error, subcircuit type "
1860 : : "`%s' requires %d nodes in `%s:%s', found %d\n",
1861 : : def->line, sub->instance, n2,
1862 [ # # ]: 0 : def->type, def->instance, n1);
1863 : 0 : errors++;
1864 : : }
1865 : : // check the subcircuit instance properties
1866 [ + - ]: 19 : struct define_t * available = netlist_create_define (sub);
1867 [ + - ]: 19 : errors += checker_validate_properties (root, def, available);
1868 : 19 : netlist_free_define (available);
1869 : : // and finally check for cyclic definitions
1870 [ + - ][ + - ]: 19 : strlist * deps = new strlist ();
1871 : : int err = checker_validate_sub_cycles (sub, sub->instance,
1872 [ + - ]: 19 : def->instance, &deps);
1873 : 19 : errors += err;
1874 : 19 : checker_sub_cycles = err;
1875 [ + - ][ + - ]: 19 : delete deps;
1876 : : }
1877 : : }
1878 : : }
1879 : : }
1880 : 219 : return errors;
1881 : : }
1882 : :
1883 : : /* Deletes node list of a definition. */
1884 : 1301 : static void netlist_free_nodes (struct node_t * node)
1885 : : {
1886 : : struct node_t * n;
1887 [ + + ]: 3736 : for (; node != NULL; node = n)
1888 : : {
1889 : 2435 : n = node->next;
1890 : 2435 : free (node->node);
1891 : 2435 : free (node);
1892 : : }
1893 : 1301 : }
1894 : :
1895 : : /* The following function free()'s the given value. */
1896 : 10172 : static void netlist_free_value (struct value_t * value)
1897 : : {
1898 [ + + ]: 10172 : if (value->ident) free (value->ident);
1899 [ + + ]: 10172 : if (value->unit) free (value->unit);
1900 [ - + ]: 10172 : if (value->scale) free (value->scale);
1901 : 10172 : free (value);
1902 : 10172 : }
1903 : :
1904 : : /* Deletes pair list of a definition. */
1905 : 1166 : static void netlist_free_pairs (struct pair_t * pp)
1906 : : {
1907 : : struct pair_t * np;
1908 [ + + ]: 11326 : for (; pp != NULL; pp = np)
1909 : : {
1910 : 10160 : np = pp->next;
1911 : : struct value_t * nv, * value;
1912 [ + + ]: 20332 : for (value = pp->value; value != NULL; value = nv)
1913 : : {
1914 : 10172 : nv = value->next;
1915 : 10172 : netlist_free_value (value);
1916 : : }
1917 : 10160 : free (pp->key);
1918 : 10160 : free (pp);
1919 : : }
1920 : 1166 : }
1921 : :
1922 : : /* Deletes the given definition. */
1923 : 1301 : static void netlist_free_definition (struct definition_t * def)
1924 : : {
1925 : 1301 : netlist_free_nodes (def->nodes);
1926 [ + + ]: 1301 : if (!def->copy) netlist_free_pairs (def->pairs);
1927 [ + + ]: 1301 : if (def->subcircuit) free (def->subcircuit);
1928 : 1301 : free (def->type);
1929 : 1301 : free (def->instance);
1930 : 1301 : free (def);
1931 : 1301 : }
1932 : :
1933 : : /* The function removes the given definition 'cand' from the
1934 : : definition root. It returns the new definition root. */
1935 : : struct definition_t *
1936 : 1119 : netlist_unchain_definition (struct definition_t * root,
1937 : : struct definition_t * cand)
1938 : : {
1939 : : struct definition_t * prev;
1940 [ + + ]: 1119 : if (cand == root)
1941 : : {
1942 : 937 : root = cand->next;
1943 : 937 : netlist_free_definition (cand);
1944 : : }
1945 : : else
1946 : : {
1947 : : // find previous to the candidate to be deleted
1948 [ + - ][ + + ]: 1512 : for (prev = root; prev != NULL && prev->next != cand; prev = prev->next) ;
[ + + ]
1949 [ + - ]: 182 : if (prev != NULL)
1950 : : {
1951 : 182 : prev->next = cand->next;
1952 : 182 : netlist_free_definition (cand);
1953 : : }
1954 : : }
1955 : 1119 : return root;
1956 : : }
1957 : :
1958 : : /* The function expands the subcircuits within the given definition
1959 : : list and returns the expanded list with the subcircuit definitions
1960 : : removed. */
1961 : : static struct definition_t *
1962 : 103 : checker_expand_subcircuits (struct definition_t * root, environment * parent)
1963 : : {
1964 : : struct definition_t * def, * sub, * copy, * next, * prev;
1965 : 103 : strlist * instances = NULL;
1966 : :
1967 : : // go through the list of definitions
1968 [ + + ]: 1102 : for (prev = NULL, def = root; def != NULL; def = next)
1969 : : {
1970 : 999 : next = def->next;
1971 : : // is this a subcircuit instance definition ?
1972 [ + + ]: 999 : if (!strcmp (def->type, "Sub"))
1973 : : {
1974 : : // get the subcircuit type definition
1975 : 15 : sub = checker_get_subcircuit (def);
1976 : : // and make a copy of it
1977 [ + - ]: 15 : copy = checker_copy_subcircuits (sub, def, &instances, parent);
1978 [ + + ]: 15 : if (instances)
1979 : : {
1980 [ + - ][ + - ]: 8 : delete instances;
1981 : 8 : instances = NULL;
1982 : : }
1983 : : // remove the subcircuit instance from the original list
1984 [ + + ]: 15 : if (prev)
1985 : : {
1986 : 12 : prev->next = next;
1987 : : }
1988 : : else
1989 : : {
1990 : 3 : root = next;
1991 : : }
1992 : 15 : netlist_free_definition (def);
1993 : : // put the expanded definitions into the netlist
1994 [ + - ]: 15 : if (copy)
1995 : : {
1996 : 15 : struct definition_t * last = checker_find_last_definition (copy);
1997 : 15 : last->next = root;
1998 [ + + ]: 15 : if (!prev) prev = last;
1999 : 15 : root = copy;
2000 : : }
2001 : : }
2002 : : // component in the root environment
2003 : : else
2004 : : {
2005 : 984 : prev = def;
2006 : 984 : def->env = parent;
2007 : : }
2008 : : }
2009 : 103 : return root;
2010 : : }
2011 : :
2012 : : /* This function is the checker routine for a parsed netlist. It
2013 : : returns zero on success or non-zero if the parsed netlist contained
2014 : : errors. */
2015 : 219 : static int netlist_checker_intern (struct definition_t * root)
2016 : : {
2017 : : struct definition_t * def;
2018 : : struct define_t * available;
2019 : 219 : int n, errors = 0;
2020 : :
2021 : : /* go through all definitions */
2022 [ + + ]: 1317 : for (def = root; def != NULL; def = def->next)
2023 : : {
2024 : :
2025 : : /* check whether the definition type is known */
2026 : 1098 : available = checker_find_definition (def->type, def->action);
2027 [ - + ]: 1098 : if (available == NULL)
2028 : : {
2029 : : logprint (LOG_ERROR, "line %d: checker error, invalid definition type "
2030 : 0 : "`%s'\n", def->line, def->type);
2031 : 0 : errors++;
2032 : : }
2033 : : else
2034 : : {
2035 : : /* mark nodeset definitions */
2036 [ + + ]: 1098 : def->nodeset = !strcmp (def->type, "NodeSet") ? 1 : 0;
2037 : : /* mark nonlinear circuit definitions */
2038 : 1098 : def->nonlinear = available->nonlinear;
2039 : : /* mark substrate definitions */
2040 : 1098 : def->substrate = available->substrate;
2041 : : /* save available definition */
2042 : 1098 : def->define = available;
2043 : : /* check whether the number of nodes is correct and save the
2044 : : number of given nodes */
2045 : 1098 : n = def->ncount = checker_count_nodes (def);
2046 [ + + ]: 1098 : if (available->nodes == PROP_NODES)
2047 : : {
2048 [ - + ]: 32 : if (n < 1)
2049 : : {
2050 : : logprint (LOG_ERROR,
2051 : : "line %d: checker error, at least 1 node required in "
2052 : : "`%s:%s', found %d\n", def->line, def->type,
2053 : 0 : def->instance, n);
2054 : 0 : errors++;
2055 : : }
2056 : : }
2057 [ - + ]: 1066 : else if (available->nodes != n)
2058 : : {
2059 : : logprint (LOG_ERROR,
2060 : : "line %d: checker error, %d node(s) required in `%s:%s', "
2061 : : "found %d\n", def->line,
2062 : 0 : available->nodes, def->type, def->instance, n);
2063 : 0 : errors++;
2064 : : }
2065 : : /* check the properties except for subcircuits */
2066 [ + + ]: 1098 : if (strcmp (def->type, "Sub"))
2067 : : {
2068 : 1079 : errors += checker_validate_properties (root, def, available);
2069 : : }
2070 : : }
2071 : : /* check the number of definitions */
2072 : 1098 : n = checker_count_definition (root, def->type, def->instance);
2073 [ - + ][ # # ]: 1098 : if (n != 1 && def->duplicate == 0)
2074 : : {
2075 : : logprint (LOG_ERROR, "checker error, found %d definitions of `%s:%s'\n",
2076 : 0 : n, def->type, def->instance);
2077 : 0 : errors++;
2078 : : }
2079 : : }
2080 : : /* check microstrip definitions */
2081 : 219 : errors += checker_validate_strips (root);
2082 : : /* check subcircuit definitions */
2083 : 219 : errors += checker_validate_subcircuits (root);
2084 : : /* check nodeset definitions */
2085 : 219 : errors += checker_validate_nodesets (root);
2086 : 219 : return errors;
2087 : : }
2088 : :
2089 : : #if DEBUG
2090 : : /* Debug function: Prints value representation. */
2091 : 10974 : static void netlist_list_value (struct value_t * value)
2092 : : {
2093 [ - + ]: 10974 : if (value == NULL)
2094 : 0 : logprint (LOG_STATUS, "[]");
2095 [ + + ]: 10974 : else if (value->ident)
2096 : 941 : logprint (LOG_STATUS, "%s", value->ident);
2097 [ + + ]: 10033 : else if (value->next)
2098 : : {
2099 : 4 : logprint (LOG_STATUS, "[");
2100 [ + + ]: 20 : for (; value != NULL; value = value->next)
2101 [ + + ]: 16 : logprint (LOG_STATUS, "%g%s", value->value, value->next ? ";" : "");
2102 : 4 : logprint (LOG_STATUS, "]");
2103 : : }
2104 : : else
2105 : : {
2106 : 10029 : logprint (LOG_STATUS, "%g", value->value);
2107 [ - + ]: 10029 : if (value->scale)
2108 : 0 : logprint (LOG_STATUS, "%s", value->scale);
2109 [ + + ]: 10029 : if (value->unit)
2110 : 1475 : logprint (LOG_STATUS, "%s", value->unit);
2111 : : }
2112 : 10974 : }
2113 : :
2114 : : /* Debug function: Prints definition list representation. */
2115 : 116 : static void netlist_lister (struct definition_t * root, const char * prefix)
2116 : : {
2117 : : struct definition_t * def;
2118 : : struct node_t * node;
2119 : : struct pair_t * pair;
2120 [ + + ]: 1321 : for (def = root; def != NULL; def = def->next)
2121 : : {
2122 : 1205 : logprint (LOG_STATUS, "%s%s:%s", prefix, def->type, def->instance);
2123 [ + + ]: 3544 : for (node = def->nodes; node != NULL; node = node->next)
2124 : : {
2125 : 2339 : logprint (LOG_STATUS, " %s", node->node);
2126 : : }
2127 [ + + ]: 12179 : for (pair = def->pairs; pair != NULL; pair = pair->next)
2128 : : {
2129 : 10974 : logprint (LOG_STATUS, " %s=\"", pair->key);
2130 : 10974 : netlist_list_value (pair->value);
2131 : 10974 : logprint (LOG_STATUS, "\"");
2132 : : }
2133 : 1205 : logprint (LOG_STATUS, "\n");
2134 : : }
2135 : 116 : }
2136 : :
2137 : : /* Debug function: Prints the overall netlist representation. */
2138 : 103 : void netlist_list (void)
2139 : : {
2140 : : struct definition_t * def;
2141 : 103 : logprint (LOG_STATUS, "subcircuit %s\n", "root");
2142 : 103 : netlist_lister (definition_root, " ");
2143 [ + + ]: 116 : for (def = subcircuit_root; def != NULL; def = def->next)
2144 : : {
2145 : 13 : logprint (LOG_STATUS, "subcircuit %s\n", def->instance);
2146 : 13 : netlist_lister (def->sub, " ");
2147 : : }
2148 : 103 : }
2149 : : #endif /* DEBUG */
2150 : :
2151 : : /* The function logs the content of the current netlist by telling how
2152 : : many instances of which kind of components are used in the netlist. */
2153 : 103 : void netlist_status (void)
2154 : : {
2155 : : struct define_t * def;
2156 : : struct definition_t * cir;
2157 : : int count;
2158 [ + - ]: 103 : logprint (LOG_STATUS, "netlist content\n");
2159 : 103 : hashiterator<module> it;
2160 [ + - ][ + - ]: 16274 : for (it = hashiterator<module> (module::modules); *it; ++it)
[ + + ]
2161 : : {
2162 : 16171 : def = it.currentVal()->definition;
2163 [ + + ]: 191854 : for (count = 0, cir = definition_root; cir != NULL; cir = cir->next)
2164 : : {
2165 [ + + ]: 175683 : if (!strcmp (def->type, cir->type)) count++;
2166 : : }
2167 [ + + ]: 16171 : if (count > 0)
2168 : : {
2169 [ + - ]: 605 : logprint (LOG_STATUS, " %5d %s instances\n", count, def->type);
2170 : : }
2171 : 103 : }
2172 : 103 : }
2173 : :
2174 : : /* The function builds the equation list for a given list of
2175 : : definition and removes the definition containing the equations from
2176 : : the list. */
2177 : : static struct definition_t *
2178 : 116 : checker_build_equations (struct definition_t * root, eqn::node ** eroot)
2179 : : {
2180 : : struct definition_t * def, * next, * prev;
2181 : : eqn::node * eqns, * last;
2182 : 116 : *eroot = NULL;
2183 : : // go through list of definitions
2184 [ + + ]: 1269 : for (prev = NULL, def = root; def != NULL; def = next)
2185 : : {
2186 : 1153 : next = def->next;
2187 [ + + ]: 1153 : if (!strcmp (def->type, "Eqn"))
2188 : : {
2189 : : // rechain definition list
2190 [ + - ]: 68 : if (prev)
2191 : : {
2192 : 68 : prev->next = next;
2193 : : }
2194 : : else
2195 : : {
2196 : 0 : root = next;
2197 : : }
2198 : : // append equations
2199 : 68 : eqns = (eqn::node *) def->eqns;
2200 : 68 : last = eqn::checker::lastEquation (eqns);
2201 : 68 : last->setNext (*eroot);
2202 : 68 : *eroot = eqns;
2203 : : // free this definition
2204 : 68 : netlist_free_definition (def);
2205 : : }
2206 : 1085 : else prev = def;
2207 : : }
2208 : 116 : return root;
2209 : : }
2210 : :
2211 : : /* The function creates an environment for the given definition root
2212 : : including equation checker and solver. */
2213 : 116 : static void checker_setup_env (struct definition_t * root,
2214 : : environment * env, eqn::node * eqns)
2215 : : {
2216 : : // create equation checker
2217 [ + - ]: 116 : eqn::checker * checkee = new eqn::checker ();
2218 : : // pass equations to the checker
2219 : 116 : checkee->setEquations (eqns);
2220 : : // add constants to the list of equations
2221 : 116 : checkee->constants ();
2222 : : // pass checker
2223 : 116 : env->setChecker (checkee);
2224 : : // create equation solver
2225 [ + - ]: 116 : eqn::solver * solvee = new eqn::solver (checkee);
2226 : : // pass solver
2227 : 116 : env->setSolver (solvee);
2228 : : // apply environment to the netlist root
2229 [ + - ]: 116 : if (root) root->env = env;
2230 : 116 : }
2231 : :
2232 : : /* Adds the arguments of a subcircuit into the equation checker of the
2233 : : given environment. */
2234 : 13 : static void checker_subcircuit_args (struct definition_t * def,
2235 : : environment * env)
2236 : : {
2237 [ - + ]: 13 : for (struct pair_t * pair = def->pairs; pair != NULL; pair = pair->next)
2238 : : {
2239 : : // anything else than the 'Type'
2240 [ # # ]: 0 : if (strcmp (pair->key, "Type"))
2241 : : {
2242 : : // put it into the equation checker
2243 : : env->getChecker()->addDouble ("#subcircuit",
2244 : 0 : pair->key, pair->value->value);
2245 : : // also put it into the environment
2246 : 0 : variable * v = checker_add_variable (env, pair->key, TAG_DOUBLE, true);
2247 : 0 : v->getConstant()->d = pair->value->value;
2248 : : }
2249 : : }
2250 : 13 : }
2251 : :
2252 : : /* This is the global netlist checker. It returns zero on success and
2253 : : non-zero on errors. */
2254 : 103 : int netlist_checker (environment * env)
2255 : : {
2256 : 103 : int errors = 0;
2257 : : eqn::node * eqns;
2258 : : struct definition_t * def;
2259 : :
2260 : : // create top-level environment
2261 [ + - ][ + - ]: 103 : env_root = new environment (env->getName ());
2262 : : // create the subcircuit list
2263 [ + - ]: 103 : definition_root = checker_build_subcircuits (definition_root);
2264 : : // get equation list
2265 [ + - ]: 103 : definition_root = checker_build_equations (definition_root, &eqns);
2266 : : // setup the root environment
2267 [ + - ]: 103 : checker_setup_env (definition_root, env_root, eqns);
2268 : : // check list of subcircuits
2269 [ + - ]: 103 : errors += netlist_checker_intern (subcircuit_root);
2270 : : // check global netlist
2271 [ + - ]: 103 : errors += netlist_checker_intern (definition_root);
2272 : : // check equations in root
2273 : 103 : env_root->setDefinitions (definition_root);
2274 [ + - ]: 103 : errors += env_root->equationChecker (0);
2275 : 103 : env_root->setDefinitions (NULL);
2276 : :
2277 : : // then check each subcircuit list
2278 [ + + ]: 116 : for (def = subcircuit_root; def != NULL; def = def->next)
2279 : : {
2280 : : // get equation list
2281 [ + - ]: 13 : def->sub = checker_build_equations (def->sub, &eqns);
2282 : : // setup the subcircuit environment
2283 [ + - ][ + - ]: 13 : environment * subenv = new environment (def->instance);
[ + - ]
2284 [ + - ]: 13 : env_root->push_front_Child (subenv);
2285 [ + - ]: 13 : checker_setup_env (def, subenv, eqns);
2286 [ + - ]: 13 : if (def->sub) def->sub->env = subenv;
2287 : : // add subcircuit parameters to equations
2288 [ + - ]: 13 : checker_subcircuit_args (def, subenv);
2289 : : // check subcircuit netlist
2290 [ + - ]: 13 : errors += netlist_checker_intern (def->sub);
2291 : : // check equations in subcircuit
2292 : 13 : subenv->setDefinitions (def->sub);
2293 [ + - ]: 13 : errors += subenv->equationChecker (0);
2294 : 13 : subenv->setDefinitions (NULL);
2295 : : }
2296 : :
2297 : : // check actions
2298 [ + - ]: 103 : errors += checker_validate_actions (definition_root);
2299 : :
2300 [ + - ]: 103 : if (!errors)
2301 : : {
2302 : : // create actual root environment
2303 [ + - ]: 103 : env->copy (*env_root);
2304 : : // and finally expand the subcircuits into the global netlist
2305 [ + - ]: 103 : definition_root = checker_expand_subcircuits (definition_root, env);
2306 : : }
2307 : :
2308 [ - + ]: 103 : return errors ? -1 : 0;
2309 : : }
2310 : :
2311 : : /* The function deletes the given definition list. */
2312 : 219 : static void netlist_destroy_intern (struct definition_t * root)
2313 : : {
2314 : : struct definition_t * def, * next;
2315 [ + + ]: 318 : for (def = root; def != NULL; def = next)
2316 : : {
2317 : 99 : next = def->next;
2318 : 99 : netlist_free_definition (def);
2319 : : }
2320 : 219 : }
2321 : :
2322 : : /* Deletes all available definition lists. */
2323 : 103 : void netlist_destroy (void)
2324 : : {
2325 : 103 : netlist_destroy_intern (definition_root);
2326 [ + + ]: 116 : for (struct definition_t * def = subcircuit_root; def; def = def->next)
2327 : : {
2328 : 13 : netlist_destroy_intern (def->sub);
2329 : : }
2330 : 103 : netlist_destroy_intern (subcircuit_root);
2331 : 103 : definition_root = subcircuit_root = NULL;
2332 : 103 : netlist_lex_destroy ();
2333 : 103 : }
2334 : :
2335 : : /* Delete root environment(s) if necessary. */
2336 : 103 : void netlist_destroy_env (void)
2337 : : {
2338 [ + - ]: 103 : if (env_root != NULL)
2339 : : {
2340 [ + - ]: 103 : delete env_root;
2341 : 103 : env_root = NULL;
2342 : : }
2343 : 103 : }
2344 : :
|