Qucs-core  0.0.19
check_netlist.cpp
Go to the documentation of this file.
00001 /*
00002  * check_netlist.cpp - checker for the Qucs netlist
00003  *
00004  * Copyright (C) 2003-2009 Stefan Jahn <stefan@lkcc.org>
00005  *
00006  * This is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2, or (at your option)
00009  * any later version.
00010  *
00011  * This software is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this package; see the file COPYING.  If not, write to
00018  * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020  *
00021  * $Id$
00022  *
00023  */
00024 
00025 #if HAVE_CONFIG_H
00026 # include <config.h>
00027 #endif
00028 
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <string.h>
00032 #include <cmath>
00033 #include <assert.h>
00034 #include <float.h>
00035 
00036 #include "logging.h"
00037 #include "strlist.h"
00038 #include "netdefs.h"
00039 #include "equation.h"
00040 #include "check_netlist.h"
00041 #include "constants.h"
00042 #include "environment.h"
00043 #include "variable.h"
00044 #include "module.h"
00045 
00046 using namespace qucs;
00047 using namespace qucs::eqn;
00048 
00049 /* Global definitions for parser and checker. */
00050 struct definition_t * definition_root = NULL;
00051 struct definition_t * subcircuit_root = NULL;
00052 environment * env_root = NULL;
00053 
00054 /* The function counts the nodes in a definition line. */
00055 static int checker_count_nodes (struct definition_t * def)
00056 {
00057     int count = 0;
00058     for (struct node_t * node = def->nodes; node != NULL; node = node->next)
00059         count++;
00060     return count;
00061 }
00062 
00063 /* The function returns an available definition line for the given
00064    type.  If there is no such definition type the function returns
00065    NULL. */
00066 static struct define_t * checker_find_definition (char * type, int action)
00067 {
00068     struct define_t * def = module::getModule (type);
00069     if (def != NULL && action == def->action) return def;
00070     return NULL;
00071 }
00072 
00073 /* The function returns the number of properties in a definition line
00074    specified by the given key. */
00075 static int checker_find_property (const char * key, struct pair_t * pp)
00076 {
00077     int count = 0;
00078     while (pp != NULL)
00079     {
00080         if (!strcmp (pp->key, key))
00081             count++;
00082         pp = pp->next;
00083     }
00084     return count;
00085 }
00086 
00087 /* Checks if the given property key is either optional or required for
00088    the given definition type and returns the type of the property. */
00089 static int checker_is_property (struct define_t * available,
00090                                 const char * key)
00091 {
00092     int i;
00093     for (i = 0; PROP_IS_PROP (available->required[i]); i++)
00094     {
00095         if (!strcmp (available->required[i].key, key))
00096             return available->required[i].type;
00097     }
00098     for (i = 0; PROP_IS_PROP (available->optional[i]); i++)
00099     {
00100         if (!strcmp (available->optional[i].key, key))
00101             return available->optional[i].type;
00102     }
00103     return PROP_NONE;
00104 }
00105 
00106 /* Counts the number of definitions given by the specified type and
00107    instance name in the definition list. */
00108 static int checker_count_definition (struct definition_t * root,
00109                                      const char * type, char * instance)
00110 {
00111     int count = 0;
00112     for (struct definition_t * def = root; def != NULL; def = def->next)
00113     {
00114         if (!strcmp (def->type, type) && !strcmp (def->instance, instance))
00115         {
00116             if (++count > 1)
00117                 def->duplicate = 1;
00118         }
00119     }
00120     return count;
00121 }
00122 
00123 /* Returns the value for a given definition type, key and variable
00124    identifier if it is in the list of definitions.  Otherwise the
00125    function returns NULL. */
00126 static struct value_t * checker_find_variable (struct definition_t * root,
00127         const char * type,
00128         const char * key,
00129         char * ident)
00130 {
00131     struct pair_t * pair;
00132     for (struct definition_t * def = root; def != NULL; def = def->next)
00133     {
00134         if (!strcmp (def->type, type))
00135         {
00136             for (pair = def->pairs; pair != NULL; pair = pair->next)
00137             {
00138                 if (!strcmp (pair->key, key))
00139                     if (pair->value->ident != NULL && ident != NULL &&
00140                             strcmp (pair->value->ident, ident) == 0)
00141                         return pair->value;
00142             }
00143         }
00144     }
00145     return NULL;
00146 }
00147 
00148 /* The function returns the appropriate value for a given key within
00149    the given netlist definition if the value is a reference (a
00150    string).  If there is no such key value pair the function returns
00151    NULL. */
00152 static struct value_t * checker_find_reference (struct definition_t * def,
00153         const char * key)
00154 {
00155     struct pair_t * pair;
00156     for (pair = def->pairs; pair != NULL; pair = pair->next)
00157     {
00158         if (!strcmp (pair->key, key))
00159             if (pair->value->ident != NULL)
00160                 return pair->value;
00161     }
00162     return NULL;
00163 }
00164 
00165 /* The function looks for the given property key within the properties
00166    of the given definition line and returns its value if the property
00167    is not an identifier.  Otherwise the function returns NULL. */
00168 static struct value_t * checker_find_prop_value (struct definition_t * def,
00169         const char * key)
00170 {
00171     struct pair_t * pair;
00172     for (pair = def->pairs; pair != NULL; pair = pair->next)
00173     {
00174         if (!strcmp (pair->key, key))
00175             if (pair->value->ident == NULL)
00176                 return pair->value;
00177     }
00178     return NULL;
00179 }
00180 
00181 /* The function returns the number of properties in a definition line
00182    specified by the given key. */
00183 static int checker_find_property (struct definition_t * def,
00184                                   const char * key)
00185 {
00186     return checker_find_property (key, def->pairs);
00187 }
00188 
00189 /* This function looks for the specified property 'key' in the given
00190    definition and return its value (a string reference) if it is a
00191    reference.  Otherwise the function returns NULL and emits an
00192    appropriate error message. */
00193 static struct value_t * checker_validate_reference (struct definition_t * def,
00194         const char * key)
00195 {
00196     struct value_t * val;
00197     if ((val = checker_find_reference (def, key)) == NULL)
00198     {
00199         logprint (LOG_ERROR, "line %d: checker error, not a valid `%s' property "
00200                   "found in `%s:%s'\n", def->line, key, def->type, def->instance);
00201     }
00202     return val;
00203 }
00204 
00205 /* This function checks whether the given definition is a known
00206    microstrip component with a substrate definition.  If the given
00207    identifier equals this substrate definition then the function
00208    returns the appropriate value.  Otherwise it returns NULL. */
00209 static struct value_t * checker_find_substrate (struct definition_t * def,
00210         char * ident)
00211 {
00212     struct value_t * val;
00213     if (checker_is_property (def->define, "Subst") == PROP_STR)
00214     {
00215         if ((val = checker_find_reference (def, "Subst")) != NULL)
00216         {
00217             if (ident != NULL && !strcmp (val->ident, ident))
00218                 return val;
00219         }
00220     }
00221     return NULL;
00222 }
00223 
00224 /* Puts the given double value variable into an environment. */
00225 static variable * checker_add_variable (environment * env,
00226                                         char * var, int type, bool pass)
00227 {
00228     variable * v = new variable (var);
00229     eqn::constant * c = new eqn::constant (type);
00230     switch (type)
00231     {
00232     case TAG_DOUBLE:
00233         c->d = 0.0; // initialize the variable
00234         break;
00235     case TAG_VECTOR:
00236           c->v = new qucs::vector ();
00237         break;
00238     }
00239     v->setConstant (c);
00240     env->addVariable (v, pass);
00241     return v;
00242 }
00243 
00244 /* Resolves the variable of a property value.  Returns non-zero on
00245    success, otherwise zero. */
00246 static int checker_resolve_variable (struct definition_t * root,
00247                                      struct definition_t * def,
00248                                      struct pair_t * pair, int type)
00249 {
00250     struct value_t * val;
00251     struct value_t * value = pair->value;
00252     if (value->ident != NULL)
00253     {
00254         int found = 0;
00255         /* 1. find variable in parameter sweeps */
00256         if ((val = checker_find_variable (root, "SW", "Param", value->ident)))
00257         {
00258             /* add parameter sweep variable to environment */
00259             if (!strcmp (def->type, "SW") && !strcmp (pair->key, "Param"))
00260             {
00261                 checker_add_variable (root->env, value->ident, TAG_DOUBLE, true);
00262             }
00263             /* mark both the variable identifier and the parameter sweep
00264             variable to be actually variables */
00265             val->var = TAG_DOUBLE;
00266             value->var = TAG_DOUBLE;
00267             found++;
00268         }
00269         /* 2. find analysis in parameter sweeps */
00270         if ((val = checker_find_variable (root, "SW", "Sim", value->ident)))
00271         {
00272             found++;
00273         }
00274         /* 3. find substrate in microstrip components */
00275         if ((val = checker_find_substrate (def, value->ident)))
00276         {
00277             value->subst = 1;
00278             found++;
00279         }
00280         /* 4. find subcircuit definition in subcircuit components */
00281         if ((val = checker_find_variable (root, "Sub", "Type", value->ident)))
00282         {
00283             found++;
00284         }
00285         /* 5. find special identifiers in certain properties */
00286         if (value->range)
00287         {
00288             found++;
00289         }
00290         /* 6. find file reference in S-parameter file components */
00291         if ((val = checker_find_variable (root, "SPfile", "File", value->ident)))
00292         {
00293             found++;
00294         }
00295         /* 7. find variable in equation */
00296         if (root->env)
00297         {
00298             if (root->env->getChecker()->containsVariable (value->ident))
00299             {
00300                 variable * v;
00301                 value->var = (type == PROP_LIST) ? TAG_VECTOR : TAG_DOUBLE;
00302                 if ((v = root->env->getVariable (value->ident)) == NULL)
00303                 {
00304                     // put variable into the environment
00305                     checker_add_variable (root->env, value->ident, value->var, false);
00306                 }
00307                 found++;
00308             }
00309         }
00310         /* 8. find file reference in file based sources */
00311         if ((val = checker_find_variable (root, "Vfile", "File", value->ident)))
00312         {
00313             found++;
00314         }
00315         if ((val = checker_find_variable (root, "Ifile", "File", value->ident)))
00316         {
00317             found++;
00318         }
00319         /* 9. find property reference in the instance */
00320         if (!found &&
00321                 checker_is_property (def->define, value->ident) != PROP_NONE)
00322         {
00323             if (root->env)
00324             {
00325 
00326                 // create reference variable names
00327                 char * txt = (char *)
00328                              malloc (strlen (def->instance) + 1 + strlen (value->ident) + 1);
00329                 sprintf (txt, "%s.%s", def->instance, value->ident);
00330                 char * ref = (char *)
00331                              malloc (strlen (def->instance) + 5 + strlen (value->ident) + 1);
00332                 sprintf (ref, "%s.%s.ref", def->instance, value->ident);
00333 
00334                 // replace property string
00335                 free (value->ident);
00336                 value->ident = strdup (ref);
00337                 value->var = TAG_DOUBLE;
00338 
00339                 // already done previously?
00340                 variable * v;
00341                 if ((v = root->env->getVariable (ref)) == NULL)
00342                 {
00343                     // put variable into the environment
00344                     checker_add_variable (root->env, ref, TAG_DOUBLE, false);
00345                     // also add reference equation into environment
00346                     root->env->getChecker()->addReference ("#propref", ref, txt);
00347                 }
00348 
00349                 // done
00350                 free (txt);
00351                 free (ref);
00352                 found++;
00353             }
00354         }
00355         /* not found */
00356         if (!found)
00357         {
00358             logprint (LOG_ERROR, "line %d: checker error, no such variable `%s' "
00359                       "used in a `%s:%s' property\n", def->line, value->ident,
00360                       def->type, def->instance);
00361             return 0;
00362         }
00363     }
00364     return 1;
00365 }
00366 
00367 /* Evaluates the unit scale in a property value.  It adjusts the
00368    actual value and omits the scale.  The function returns non-zero
00369    on success and zero otherwise. */
00370 static int checker_evaluate_scale (struct value_t * value)
00371 {
00372     double val = value->value, factor = 1.0;
00373     char * scale;
00374     if (value->scale != NULL)
00375     {
00376         scale = value->scale;
00377         switch (*scale)
00378         {
00379         case 'E':
00380             scale++;
00381             factor = 1e18;
00382             break;
00383         case 'P':
00384             scale++;
00385             factor = 1e15;
00386             break;
00387         case 'T':
00388             scale++;
00389             factor = 1e12;
00390             break;
00391         case 'G':
00392             scale++;
00393             factor = 1e9;
00394             break;
00395         case 'M':
00396             scale++;
00397             factor = 1e6;
00398             break;
00399         case 'k':
00400             scale++;
00401             factor = 1e3;
00402             break;
00403         case 'm':
00404             scale++;
00405             if (*scale == 'i')
00406             {
00407                 scale++;
00408                 if (*scale == 'l')
00409                 {
00410                     scale++;
00411                     factor = 2.54e-5;
00412                 }
00413             }
00414             else
00415                 factor = 1e-3;
00416             break;
00417         case 'u':
00418             scale++;
00419             factor = 1e-6;
00420             break;
00421         case 'n':
00422             scale++;
00423             factor = 1e-9;
00424             break;
00425         case 'p':
00426             scale++;
00427             factor = 1e-12;
00428             break;
00429         case 'f':
00430             scale++;
00431             if (*scale == 't')
00432             {
00433                 scale++;
00434                 factor = 0.3048;
00435             }
00436             else
00437                 factor = 1e-15;
00438             break;
00439         case 'a':
00440             scale++;
00441             factor = 1e-18;
00442             break;
00443         case 'd':
00444             scale++;
00445             if (*scale == 'B')
00446             {
00447                 scale++;
00448                 val = std::pow (10.0, val / 10.0);
00449                 if (*scale == 'm')
00450                 {
00451                     scale++;
00452                     factor = 1e-3;
00453                 }
00454                 else if (*scale == 'u')
00455                 {
00456                     scale++;
00457                     factor = 1e-6;
00458                 }
00459             }
00460             break;
00461         case 'i':
00462             scale++;
00463             if (*scale == 'n')
00464             {
00465                 scale++;
00466                 factor = 2.54e-2;
00467             }
00468             break;
00469         case 'y':
00470             scale++;
00471             if (*scale == 'd')
00472             {
00473                 scale++;
00474                 factor = 0.9144;
00475             }
00476             break;
00477         }
00478         if (*scale != '\0')
00479         {
00480             value->unit = strdup (scale);
00481         }
00482         free (value->scale);
00483         value->scale = NULL;
00484     }
00485     value->value = val * factor;
00486     return 1;
00487 }
00488 
00489 /* The function returns the number of instances of the given type within
00490    the list of definitions. */
00491 static int checker_count_definitions (struct definition_t * root,
00492                                       const char * type, int action)
00493 {
00494     int count = 0;
00495     for (struct definition_t * def = root; def != NULL; def = def->next)
00496     {
00497         if (def->action == action)
00498         {
00499             if (type == NULL)
00500                 count++;
00501             else if (!strcmp (def->type, type))
00502                 count++;
00503         }
00504     }
00505     return count;
00506 }
00507 
00508 /* This function looks for the specified subcircuit type in the list
00509    of available subcircuits and returns its definition.  If there is
00510    no such subcircuit the function returns NULL: */
00511 static struct definition_t * checker_find_subcircuit (char * n)
00512 {
00513     struct definition_t * def;
00514     for (def = subcircuit_root; def != NULL; def = def->next)
00515         if (n != NULL && !strcmp (def->instance, n)) return def;
00516     return NULL;
00517 }
00518 
00519 /* The function returns the subcircuit definition for the given
00520    subcircuit instance. */
00521 static struct definition_t *
00522 checker_get_subcircuit (struct definition_t * def)
00523 {
00524     struct value_t * val;
00525     struct definition_t * sub = NULL;
00526     if ((val = checker_find_reference (def, "Type")) != NULL)
00527         sub = checker_find_subcircuit (val->ident);
00528     return sub;
00529 }
00530 
00531 // Global variable indicating cycles in subcircuit definitions.
00532 static int checker_sub_cycles = 0;
00533 
00534 /* The following function returns the number of circuit instances
00535    requiring a DC analysis (being nonlinear) in the list of definitions. */
00536 static int checker_count_nonlinearities (struct definition_t * root)
00537 {
00538     int count = 0;
00539     struct definition_t * sub;
00540     for (struct definition_t * def = root; def != NULL; def = def->next)
00541     {
00542         if (def->nonlinear != 0) count++;
00543         // also recurse into subcircuits if possible
00544         if (checker_sub_cycles <= 0)
00545         {
00546             if (!strcmp (def->type, "Sub"))
00547             {
00548                 if ((sub = checker_get_subcircuit (def)) != NULL)
00549                 {
00550                     count += checker_count_nonlinearities (sub->sub);
00551                 }
00552             }
00553         }
00554     }
00555     return count;
00556 }
00557 
00558 /* This function returns the number of action definitions with the
00559    given instance name. */
00560 static int checker_count_action (struct definition_t * root, char * instance)
00561 {
00562     int count = 0;
00563     for (struct definition_t * def = root; def != NULL; def = def->next)
00564     {
00565         if (def->action == 1 && !strcmp (def->instance, instance))
00566             count++;
00567     }
00568     return count;
00569 }
00570 
00571 /* This (recursive) function detects any kind of cyclic definitions of
00572    parameter sweeps for the given instance name.  The string list
00573    argument is used to pass the dependencies.  The function returns
00574    zero if the parameter sweep in non-cyclic. */
00575 static int checker_validate_para_cycles (struct definition_t * root,
00576         char * instance, strlist * deps)
00577 {
00578     int errors = 0;
00579     struct value_t * val;
00580     for (struct definition_t * def = root; def != NULL; def = def->next)
00581     {
00582         /* find the appropriate definition for the given instance */
00583         if (def->action == 1 && !strcmp (def->instance, instance))
00584         {
00585             /* emit error message if the instance is already in the dependencies */
00586             if (deps->contains (instance))
00587             {
00588                 logprint (LOG_ERROR, "checker error, cyclic definition of `%s' "
00589                           "detected, involves: %s\n", instance, deps->toString ());
00590                 return ++errors;
00591             }
00592             deps->append (instance);
00593             /* recurse into parameter sweeps */
00594             if (!strcmp (def->type, "SW"))
00595             {
00596                 if ((val = checker_find_reference (def, "Sim")) != NULL)
00597                 {
00598                     return checker_validate_para_cycles (root, val->ident, deps);
00599                 }
00600             }
00601         }
00602     }
00603     return errors;
00604 }
00605 
00606 /* This function validates each parameter sweep within the list of
00607    definitions and return non-zero on errors.  Emits appropriate error
00608    messages. */
00609 static int checker_validate_para (struct definition_t * root)
00610 {
00611     int errors = 0;
00612     struct value_t * val;
00613     for (struct definition_t * def = root; def != NULL; def = def->next)
00614     {
00615         /* find parameter sweep */
00616         if (def->action == 1 && !strcmp (def->type, "SW"))
00617         {
00618             /* the 'Sim' property must be an identifier */
00619             if ((val = checker_validate_reference (def, "Sim")) == NULL)
00620             {
00621                 errors++;
00622             }
00623             else
00624             {
00625                 /* check for self-referring sweeps */
00626                 if (!strcmp (def->instance, val->ident))
00627                 {
00628                     logprint (LOG_ERROR, "line %d: checker error, definition `%s:%s' "
00629                               "refers to itself\n", def->line, def->type, def->instance);
00630                     errors++;
00631                 }
00632                 /* look for the referred analysis action definition */
00633                 if (checker_count_action (root, val->ident) != 1)
00634                 {
00635                     logprint (LOG_ERROR, "line %d: checker error, no such action `%s' "
00636                               "found as referred in `%s:%s'\n", def->line, val->ident,
00637                               def->type, def->instance);
00638                     errors++;
00639                 }
00640                 /* finally detect cyclic definitions */
00641                 strlist * deps = new strlist ();
00642                 errors += checker_validate_para_cycles (root, val->ident, deps);
00643                 delete deps;
00644             }
00645         }
00646     }
00647     return errors;
00648 }
00649 
00650 /* This function returns the next port definition in the given list of
00651    definitions or NULL if there is no such definition. */
00652 static struct definition_t * checker_find_port (struct definition_t * root)
00653 {
00654     for (struct definition_t * def = root; def != NULL; def = def->next)
00655     {
00656         if (def->action == PROP_COMPONENT && !strcmp (def->type, "Pac"))
00657         {
00658             return def;
00659         }
00660     }
00661     return NULL;
00662 }
00663 
00664 /* This function checks whether the port numbers for the S-parameter
00665    analysis are unique or not.  It returns zero on success and
00666    non-zero if it detected duplicate entries. */
00667 static int checker_validate_ports (struct definition_t * root)
00668 {
00669     int p, errors = 0;
00670     struct value_t * val;
00671     struct definition_t * port, * def = root;
00672     const char * prop = "Num";
00673     while ((def = checker_find_port (def)) != NULL)
00674     {
00675         if ((val = checker_find_prop_value (def, prop)) != NULL)
00676         {
00677             p = (int) val->value;
00678             port = root;
00679             while ((port = checker_find_port (port)) != NULL)
00680             {
00681                 if (port != def)
00682                 {
00683                     if ((val = checker_find_prop_value (port, prop)) != NULL)
00684                     {
00685                         if (p == (int) val->value)
00686                         {
00687                             logprint (LOG_ERROR, "line %d: checker error, `%s' definitions "
00688                                       "with duplicate `%s=%d' property found: `%s:%s' and "
00689                                       "`%s:%s'\n", def->line, def->type, prop, p, def->type,
00690                                       def->instance, port->type, port->instance);
00691                             errors++;
00692                         }
00693                     }
00694                 }
00695                 port = port->next;
00696             }
00697         }
00698         def = def->next;
00699     }
00700     return errors;
00701 }
00702 
00703 /* The following function checks whether the parametric sweeps in the
00704    netlist are valid or not.  It returns zero on success and non-zero
00705    otherwise. */
00706 static int checker_validate_lists (struct definition_t * root)
00707 {
00708     int errors = 0;
00709     // go through each definition
00710     for (struct definition_t * def = root; def != NULL; def = def->next)
00711     {
00712         /* sweeps possible in parameter sweep, ac-analysis and
00713            s-parameter analysis */
00714         if (def->action == 1 && (!strcmp (def->type, "SW") ||
00715                                  !strcmp (def->type, "AC") ||
00716                                  !strcmp (def->type, "SP")))
00717         {
00718             struct value_t * val;
00719             if((val = checker_find_reference (def, "Type")) == NULL) {
00720                 logprint (LOG_ERROR, "line %d: checker error, required property "
00721                           "`%s' is invalid in `%s:%s'\n", def->line, "Type",
00722                           def->type, def->instance);
00723                 errors++;
00724                 continue;
00725             }
00726             char * type = val->ident;
00727             // list of constant values and constant values
00728             if (type && (!strcmp (type, "const") || !strcmp (type, "list")))
00729             {
00730                 // property 'Values' is required
00731                 if ((val = checker_find_prop_value (def, "Values")) == NULL)
00732                 {
00733                     if (!strcmp (type, "const"))
00734                     {
00735                         if ((val = checker_validate_reference (def, "Values")) == NULL)
00736                         {
00737                             errors++;
00738                         }
00739                     }
00740                     else
00741                     {
00742                         logprint (LOG_ERROR, "line %d: checker error, required property "
00743                                   "`%s' not found in `%s:%s'\n", def->line, "Values",
00744                                   def->type, def->instance);
00745                         errors++;
00746                     }
00747                 }
00748                 else
00749                 {
00750                     if (!strcmp (type, "const"))
00751                     {
00752                         // in constant sweeps only one value allowed
00753                         if (val->next != NULL)
00754                         {
00755                             logprint (LOG_ERROR, "line %d: checker error, value of `%s' "
00756                                       "needs to be a single constant value in `%s:%s', no "
00757                                       "lists possible\n", def->line, "Values",
00758                                       def->type, def->instance);
00759                             errors++;
00760                         }
00761                         val->var = TAG_UNKNOWN;
00762                     }
00763                     if (!strcmp (type, "list"))
00764                     {
00765                         val->var = TAG_VECTOR;
00766                     }
00767                     // check and evaluate the unit scale in a value list
00768                     for (; val != NULL; val = val->next)
00769                     {
00770                         if (!checker_evaluate_scale (val))
00771                             errors++;
00772                     }
00773                 }
00774                 // property 'Start' is invalid
00775                 if (checker_find_property (def, "Start") > 0)
00776                 {
00777                     logprint (LOG_ERROR, "line %d: checker error, extraneous property "
00778                               "`%s' is invalid in `%s:%s'\n", def->line, "Start",
00779                               def->type, def->instance);
00780                     errors++;
00781                 }
00782                 // property 'Stop' is invalid
00783                 if (checker_find_property (def, "Stop") > 0)
00784                 {
00785                     logprint (LOG_ERROR, "line %d: checker error, extraneous property "
00786                               "`%s' is invalid in `%s:%s'\n", def->line, "Stop",
00787                               def->type, def->instance);
00788                     errors++;
00789                 }
00790                 // property 'Points' is also invalid
00791                 if (checker_find_property (def, "Points") > 0)
00792                 {
00793                     logprint (LOG_ERROR, "line %d: checker error, extraneous property "
00794                               "`%s' is invalid in `%s:%s'\n", def->line, "Points",
00795                               def->type, def->instance);
00796                     errors++;
00797                 }
00798             }
00799             // linearly and logarithmically stepped sweeps
00800             else if (type && (!strcmp (type, "lin") || !strcmp (type, "log")))
00801             {
00802                 // property 'Start' required
00803                 if (checker_find_property (def, "Start") <= 0)
00804                 {
00805                     logprint (LOG_ERROR, "line %d: checker error, required property "
00806                               "`%s' not found in `%s:%s'\n", def->line, "Start",
00807                               def->type, def->instance);
00808                     errors++;
00809                 }
00810                 // property 'Stop' required
00811                 if (checker_find_property (def, "Stop") <= 0)
00812                 {
00813                     logprint (LOG_ERROR, "line %d: checker error, required property "
00814                               "`%s' not found in `%s:%s'\n", def->line, "Stop",
00815                               def->type, def->instance);
00816                     errors++;
00817                 }
00818                 // property 'Points' is also required
00819                 if (checker_find_property (def, "Points") <= 0)
00820                 {
00821                     logprint (LOG_ERROR, "line %d: checker error, required property "
00822                               "`%s' not found in `%s:%s'\n", def->line, "Points",
00823                               def->type, def->instance);
00824                     errors++;
00825                 }
00826                 // property 'Values' is invalid
00827                 if (checker_find_property (def, "Values") > 0)
00828                 {
00829                     logprint (LOG_ERROR, "line %d: checker error, extraneous property "
00830                               "`%s' is invalid in `%s:%s'\n", def->line, "Values",
00831                               def->type, def->instance);
00832                     errors++;
00833                 }
00834             }
00835         }
00836     }
00837     return errors;
00838 }
00839 
00840 /* This function checks the actions to be taken in the netlist.  It
00841    returns zero on success, non-zero otherwise. */
00842 static int checker_validate_actions (struct definition_t * root)
00843 {
00844     int a, c, n, errors = 0;
00845     if ((n = checker_count_definitions (root, NULL, 1)) < 1)
00846     {
00847         logprint (LOG_ERROR, "checker error, no actions defined: nothing to do\n");
00848         errors++;
00849     }
00850     else
00851     {
00852         // check requirements for s-parameter analysis
00853         if ((a = checker_count_definitions (root, "SP", 1)) >= 1)
00854         {
00855             if ((n = checker_count_definitions (root, "Pac", 0)) < 1)
00856             {
00857                 logprint (LOG_ERROR, "checker error, %d `Pac' definitions found, at "
00858                           "least 1 required\n", n);
00859                 errors++;
00860             }
00861         }
00862         // count analyses requiring a DC solution
00863         a += checker_count_definitions (root, "AC", 1);
00864         // check dc-analysis requirements
00865         c = checker_count_nonlinearities (root);
00866         n = checker_count_definitions (root, "DC", 1);
00867         if (n > 1)
00868         {
00869             logprint (LOG_ERROR, "checker error, the .DC action is defined %dx, "
00870                       "single or none required\n", n);
00871             errors++;
00872         }
00873         if (a >= 1 && c >= 1 && n < 1)
00874         {
00875             logprint (LOG_ERROR, "checker error, a .DC action is required for this "
00876                       "circuit definition (accounted %d non-linearities)\n", c);
00877             errors++;
00878         }
00879     }
00880     errors += checker_validate_para (root);
00881     errors += checker_validate_ports (root);
00882     errors += checker_validate_lists (root);
00883     return errors;
00884 }
00885 
00886 /* This function checks the validity of each microstrip component and
00887    its substrate and model references.  It returns zero on success,
00888    emit error messages if necessary and returns non-zero on errors. */
00889 static int checker_validate_strips (struct definition_t * root)
00890 {
00891     int errors = 0;
00892     struct value_t * val;
00893     for (struct definition_t * def = root; def != NULL; def = def->next)
00894     {
00895         if (!def->action)
00896         {
00897             /* find components with substrate property */
00898             if (def->define && (checker_is_property (def->define, "Subst") == PROP_STR))
00899             {
00900                 /* check validity of 'Subst' property */
00901                 if ((val = checker_validate_reference (def, "Subst")) == NULL)
00902                 {
00903                     errors++;
00904                 }
00905                 else
00906                 {
00907                     if (checker_count_definition (root, "SUBST", val->ident) != 1)
00908                     {
00909                         logprint (LOG_ERROR, "line %d: checker error, no such substrate "
00910                                   "`%s' found as specified in `%s:%s'\n", def->line,
00911                                   val->ident, def->type, def->instance);
00912                         errors++;
00913                     }
00914                 }
00915                 /* check validity of 'Model' property */
00916 #if DISABLE_FOR_NOW /* ThinkME!!! */
00917                 if ((val = checker_validate_reference (def, "Model")) == NULL)
00918                 {
00919                     errors++;
00920                 }
00921 #endif
00922             }
00923         }
00924     }
00925     return errors;
00926 }
00927 
00928 /* This function counts the number of occurrences of the given node
00929    name in the given netlist definition root. */
00930 static int checker_count_nodes (struct definition_t * root, char * n)
00931 {
00932     int count = 0;
00933     struct node_t * node;
00934     for (struct definition_t * def = root; def != NULL; def = def->next)
00935     {
00936         if (!def->action && !def->nodeset)
00937         {
00938             for (node = def->nodes; node != NULL; node = node->next)
00939                 if (!strcmp (node->node, n)) count++;
00940         }
00941     }
00942     return count;
00943 }
00944 
00945 /* The function identifies duplicate nodesets for the same node which
00946    is not allowed.  It returns the number of duplications. */
00947 static int checker_count_nodesets (struct definition_t * root, char * n)
00948 {
00949     int count = 0;
00950     for (struct definition_t * def = root; def != NULL; def = def->next)
00951     {
00952         if (def->nodeset && !def->duplicate && def->nodes)
00953         {
00954             char * node = def->nodes->node;
00955             if (!strcmp (node, n))
00956             {
00957                 if (++count > 1) def->duplicate = 1;
00958             }
00959         }
00960     }
00961     return count;
00962 }
00963 
00964 /* The following function checks whether the nodes specified by the
00965    nodeset functionality is valid in its current scope.  It does not
00966    check across subcircuit boundaries. */
00967 static int checker_validate_nodesets (struct definition_t * root)
00968 {
00969     int errors = 0;
00970     for (struct definition_t * def = root; def != NULL; def = def->next)
00971     {
00972         if (def->nodeset && checker_count_nodes (def) == 1)
00973         {
00974             char * node = def->nodes->node;
00975             if (checker_count_nodes (root, node) <= 0)
00976             {
00977                 logprint (LOG_ERROR, "line %d: checker error, no such node `%s' found "
00978                           "as referenced by `%s:%s'\n", def->line, node, def->type,
00979                           def->instance);
00980                 errors++;
00981             }
00982             if (checker_count_nodesets (root, node) > 1)
00983             {
00984                 logprint (LOG_ERROR, "line %d: checker error, the node `%s' is not "
00985                           "uniquely defined by `%s:%s'\n", def->line, node, def->type,
00986                           def->instance);
00987                 errors++;
00988             }
00989         }
00990     }
00991     return errors;
00992 }
00993 
00994 /* This function should be called after the netlist and the equation
00995    list have been checked.  It verifies that parameter sweep
00996    definitions and equation variable identifiers are unique.  The
00997    function returns zero on success and non-zero otherwise. */
00998 static int netlist_checker_variables_intern (struct definition_t * root,
00999         environment * env)
01000 {
01001     int errors = 0, pos;
01002     struct value_t * para, * ref;
01003     strlist * eqnvars = env->getChecker()->variables ();
01004     strlist * instances = new strlist ();
01005     strlist * vars = new strlist ();
01006     strlist * refs = new strlist ();
01007     // go through list of netlist definitions
01008     for (struct definition_t * def = root; def != NULL; def = def->next)
01009     {
01010         // find parameters sweeps
01011         if (def->action == 1 && !strcmp (def->type, "SW"))
01012         {
01013             para = checker_find_reference (def, "Param");
01014             ref = checker_find_reference (def, "Sim");
01015             if (para != NULL && ref != NULL)
01016             {
01017                 // check whether sweep variable collides with equations
01018                 if (eqnvars && eqnvars->contains (para->ident))
01019                 {
01020                     logprint (LOG_ERROR, "checker error, equation variable `%s' "
01021                               "already defined by `%s:%s'\n", para->ident,
01022                               def->type, def->instance);
01023                     errors++;
01024                 }
01025                 // check for duplicate parameter names in parameter sweeps, but
01026                 // allow them in same order sweeps
01027                 if ((pos = vars->index (para->ident)) != -1)
01028                 {
01029                     if (strcmp (ref->ident, refs->get (pos)))
01030                     {
01031                         logprint (LOG_ERROR, "checker error, variable `%s' in `%s:%s' "
01032                                   "already defined by `%s:%s'\n", para->ident, def->type,
01033                                   def->instance, def->type, instances->get (pos));
01034                         errors++;
01035                     }
01036                 }
01037                 // check for duplicate simulations in parameter sweeps (same order
01038                 // sweep) and allow same parameter name only
01039                 if ((pos = refs->index (ref->ident)) != -1)
01040                 {
01041                     if (strcmp (para->ident, vars->get (pos)))
01042                     {
01043                         logprint (LOG_ERROR, "checker error, conflicting variables `%s' "
01044                                   "in `%s:%s' and `%s' in `%s:%s' for `%s'\n",
01045                                   para->ident, def->type, def->instance,
01046                                   vars->get (pos), def->type, instances->get (pos),
01047                                   ref->ident);
01048                         errors++;
01049                     }
01050                 }
01051                 // collect parameter sweep variables for the above two checks
01052                 instances->add (def->instance);
01053                 vars->add (para->ident);
01054                 refs->add (ref->ident);
01055             }
01056         }
01057     }
01058     delete eqnvars;
01059     delete refs;
01060     delete vars;
01061     delete instances;
01062     return errors;
01063 }
01064 
01065 /* This is the overall variable checker for the parsed netlist.  See
01066    the above function for details. */
01067 int netlist_checker_variables (environment * env)
01068 {
01069     return netlist_checker_variables_intern (definition_root, env);
01070 }
01071 
01072 /* The function checks whether the given key-value combination is
01073    inside the allowed range defined by the given property definition
01074    and returns the number of error or zero otherwise. */
01075 static int checker_value_in_prop_range (char * instance, struct define_t * def,
01076                                         struct pair_t * pp,
01077                                         struct property_t * prop)
01078 {
01079     int errors = 0;
01080     // check values
01081     if (PROP_IS_VAL (*prop))
01082     {
01083         if (!PROP_IS_LST (*prop))
01084         {
01085             // lists of values possible?
01086             if (pp->value->next != NULL)
01087             {
01088                 logprint (LOG_ERROR,
01089                           "checker error, value of `%s' needs to be "
01090                           "a single value in `%s:%s', no lists possible\n",
01091                           pp->key, def->type, instance);
01092                 errors++;
01093             }
01094         }
01095         else
01096         {
01097             // a value list
01098             struct value_t * val = pp->value;
01099             val->var = TAG_VECTOR;
01100             // check and evaluate the unit scale in a value list
01101             for (; val != NULL; val = val->next)
01102             {
01103                 if (!checker_evaluate_scale (val))
01104                     errors++;
01105             }
01106         }
01107         // check range of all values
01108         if (PROP_HAS_RANGE (*prop))
01109         {
01110             struct value_t * val = pp->value;
01111             if (val->ident)
01112             {
01113                 /* no range checking on variable identifier */
01114                 logprint (LOG_STATUS,
01115                           "checker notice, value of `%s' (variable `%s') could be "
01116                           "out of range `%c%g,%g%c' in `%s:%s'\n",
01117                           pp->key, val->ident, prop->range.il, prop->range.l,
01118                           prop->range.h, prop->range.ih, def->type, instance);
01119                 val = NULL;
01120             }
01121             for (; val != NULL; val = val->next)
01122             {
01123                 int rerror = 0;
01124                 if (prop->range.il == '[' &&  (val->value < prop->range.l))
01125                     rerror++;
01126                 if (prop->range.il == ']' && !(val->value > prop->range.l))
01127                     rerror++;
01128                 if (prop->range.ih == '[' && !(val->value < prop->range.h))
01129                     rerror++;
01130                 if (prop->range.ih == ']' &&  (val->value > prop->range.h))
01131                     rerror++;
01132                 if (rerror)
01133                 {
01134                     logprint (LOG_ERROR,
01135                               "checker error, value of `%s' (%g) is out of "
01136                               "range `%c%g,%g%c' in `%s:%s'\n",
01137                               pp->key, val->value, prop->range.il, prop->range.l,
01138                               prop->range.h, prop->range.ih, def->type, instance);
01139                     errors++;
01140                 }
01141             }
01142         }
01143         // check fraction of integers
01144         if (PROP_IS_INT (*prop))
01145         {
01146             double integral;
01147             if (modf (pp->value->value, &integral) != 0)
01148             {
01149                 logprint (LOG_ERROR,
01150                           "checker error, value of `%s' (%g) needs to be "
01151                           "an integer in `%s:%s'\n",
01152                           pp->key, pp->value->value, def->type, instance);
01153                 errors++;
01154             }
01155         }
01156     }
01157     // check identifiers
01158     else
01159     {
01160         // no identifier given
01161         if (pp->value->ident == NULL)
01162         {
01163             logprint (LOG_ERROR,
01164                       "checker error, value of `%s' (%g) needs to be "
01165                       "an identifier in `%s:%s'\n",
01166                       pp->key, pp->value->value, def->type, instance);
01167             errors++;
01168         }
01169         // check identifier range
01170         else
01171         {
01172             if (PROP_HAS_STR (*prop))
01173             {
01174                 int i, found = 0;
01175                 char range[256];
01176                 sprintf (range, "[");
01177                 for (i = 0; prop->range.str[i]; i++)
01178                 {
01179                     strcat (range, prop->range.str[i]);
01180                     strcat (range, ",");
01181                     if (!strcmp (prop->range.str[i], pp->value->ident)) found++;
01182                 }
01183                 if (!found)
01184                 {
01185                     range[strlen (range) - 1] = ']';
01186                     logprint (LOG_ERROR,
01187                               "checker error, value of `%s' (%s) needs to be "
01188                               "in %s in `%s:%s'\n",
01189                               pp->key, pp->value->ident, range, def->type, instance);
01190                     errors++;
01191                 }
01192                 else pp->value->range = 1;
01193             }
01194         }
01195     }
01196     return errors;
01197 }
01198 
01199 /* The function checks whether the given key-value combination being
01200    part of the available definition is inside the allowed range and
01201    returns zero if not.  Otherwise the function returns non-zero. */
01202 static int checker_value_in_range (char * instance, struct define_t * def,
01203                                    struct pair_t * pp)
01204 {
01205     int i, errors = 0;
01206     // go through required properties
01207     for (i = 0; PROP_IS_PROP (def->required[i]); i++)
01208     {
01209         if (!strcmp (def->required[i].key, pp->key))
01210         {
01211             errors += checker_value_in_prop_range (instance, def, pp,
01212                                                    &def->required[i]);
01213         }
01214     }
01215     // go through optional properties
01216     for (i = 0; PROP_IS_PROP (def->optional[i]); i++)
01217     {
01218         if (!strcmp (def->optional[i].key, pp->key))
01219         {
01220             errors += checker_value_in_prop_range (instance, def, pp,
01221                                                    &def->optional[i]);
01222         }
01223     }
01224     return errors ? 0 : 1;
01225 }
01226 
01227 /* The function determines the subcircuit definitions defined in the
01228    original netlist and builds an appropriate subcircuit definition
01229    list.  It returns the given definition list with the subcircuits
01230    removed. */
01231 static struct definition_t *
01232 checker_build_subcircuits (struct definition_t * root)
01233 {
01234     struct definition_t * def, * next, * prev;
01235     for (prev = NULL, def = root; def != NULL; def = next)
01236     {
01237         next = def->next;
01238         if (!strcmp (def->type, "Def"))
01239         {
01240             if (prev)
01241             {
01242                 prev->next = next;
01243             }
01244             else
01245             {
01246                 root = next;
01247             }
01248             def->sub = checker_build_subcircuits (def->sub);
01249             def->next = subcircuit_root;
01250             subcircuit_root = def;
01251         }
01252         else prev = def;
01253     }
01254     return root;
01255 }
01256 
01257 /* The function produces a copy of the given circuit definition and
01258    marks it as a copy.  The node definition are not included within
01259    the copy. */
01260 static struct definition_t *
01261 checker_copy_subcircuit (struct definition_t * sub)
01262 {
01263     struct definition_t * copy;
01264     copy = (struct definition_t *) calloc (sizeof (struct definition_t), 1);
01265     copy->action = sub->action;
01266     copy->nonlinear = sub->nonlinear;
01267     copy->substrate = sub->substrate;
01268     copy->nodeset = sub->nodeset;
01269     copy->define = sub->define;
01270     copy->pairs = sub->pairs;
01271     copy->ncount = sub->ncount;
01272     copy->type = strdup (sub->type);
01273     copy->copy = 1;
01274     return copy;
01275 }
01276 
01277 /* This function translates the node definitions of the given
01278    subcircuit element 'sub'.  The translation is based upon the node
01279    definitions of the subcircuit 'type' and the instance 'inst' of
01280    such a subcircuit.  The translated nodes are saved in an extra
01281    'xlate' field of each node of the subcircuit element 'sub'. */
01282 static void checker_xlat_subcircuit_nodes (struct definition_t * type,
01283         struct definition_t * inst,
01284         struct definition_t * sub)
01285 {
01286     struct node_t * n, * ninst, * ntype;
01287     int i;
01288     // go through nodes of the subcircuit 'type' and 'inst'
01289     for (i = 1, ntype = type->nodes, ninst = inst->nodes; ntype != NULL;
01290             ntype = ntype->next, ninst = ninst->next, i++)
01291     {
01292         for (n = sub->nodes; n != NULL; n = n->next)
01293         {
01294             /* check whether a node in the subcircuit element 'sub' corresponds
01295             with the 'type', then assign the 'inst's node name */
01296             if (!strcmp (n->node, ntype->node))
01297             {
01298                 n->xlate = strdup (ninst->node);
01299                 n->xlatenr = i;
01300             }
01301         }
01302     }
01303 }
01304 
01305 /* The function creates a subcircuit node name consisting of the given
01306    arguments.  If the given 'instances' is NULL it is left out.  The
01307    caller is responsible to free() the returned string. */
01308 static char * checker_subcircuit_node (char * type, char * instances,
01309                                        char * instance, char * node)
01310 {
01311     char * txt = (char *)
01312                  calloc (1, strlen (type) + strlen (instance) + strlen (node) +
01313                          (instances ? strlen (instances) : 0) + 4);
01314     if (instances)
01315         sprintf (txt, "%s.%s.%s.%s", type, instances, instance, node);
01316     else
01317         sprintf (txt, "%s.%s.%s", type, instance, node);
01318     return txt;
01319 }
01320 
01321 /* The function reverses the order of the given node list and returns
01322    the reversed list. */
01323 struct node_t * netlist_reverse_nodes (struct node_t * nodes)
01324 {
01325     struct node_t * root, * next;
01326     for (root = NULL; nodes != NULL; nodes = next)
01327     {
01328         next = nodes->next;
01329         nodes->next = root;
01330         root = nodes;
01331     }
01332     return root;
01333 }
01334 
01335 /* This function assigns new node names to the subcircuit element
01336    'copy' based upon the previous node translation between the
01337    subcircuit 'type' and the instance 'inst' of this type.  The global
01338    'gnd' node is not touched. */
01339 static void
01340 checker_copy_subcircuit_nodes (struct definition_t * type,
01341                                struct definition_t * inst,
01342                                struct definition_t * sub,
01343                                struct definition_t * copy,
01344                                char * instances)
01345 {
01346     struct node_t * n, * ncopy, * root = NULL;
01347 
01348     // go through the list of the subcircuit element's 'sub' nodes
01349     for (n = sub->nodes; n != NULL; n = n->next)
01350     {
01351 
01352         // create new node based upon the node translation
01353         ncopy = (struct node_t *) calloc (sizeof (struct node_t), 1);
01354         ncopy->xlatenr = n->xlatenr;
01355         if (n->xlate)   // translated node
01356         {
01357             if (instances == NULL)
01358                 ncopy->node = strdup (n->xlate);
01359             else
01360                 ncopy->node = NULL; // leave it blank yet, indicates translation
01361         }
01362         else if (!strcmp (n->node, "gnd"))   // ground node
01363         {
01364             ncopy->node = strdup (n->node);
01365         }
01366         else if (n->node[strlen (n->node) - 1] == '!')   // global node
01367         {
01368             ncopy->node = strdup (n->node);
01369         }
01370         else   // internal subcircuit element node
01371         {
01372             ncopy->node = checker_subcircuit_node (type->instance, instances,
01373                                                    inst->instance, n->node);
01374         }
01375         // chain the new node list
01376         ncopy->next = root;
01377         root = ncopy;
01378     }
01379 
01380     /* and finally reverse the created node list and assign it to the
01381        subcircuit element's 'copy' */
01382     copy->nodes = netlist_reverse_nodes (root);
01383 }
01384 
01385 // Returns the node at the given position.
01386 static struct node_t * checker_get_circuit_node (struct node_t * root, int n)
01387 {
01388     for (int i = 1; i < n; i++)
01389     {
01390         root = root->next;
01391         assert (root != NULL);
01392     }
01393     return root;
01394 }
01395 
01396 // The function cleans the translated nodes of a subcircuit template.
01397 static void checker_cleanup_xlat_nodes (struct definition_t * sub)
01398 {
01399     for (struct node_t * n = sub->nodes; n != NULL; n = n->next)
01400     {
01401         free (n->xlate);
01402         n->xlate = NULL;
01403         n->xlatenr = 0;
01404     }
01405 }
01406 
01407 /* The function is used to assign the nodes of the 'copy' subcircuit
01408    element which were left blank intentionally by the element copy in
01409    order to indicate that it is an external node.  Again, if the
01410    current node translation indicates an external node it is blanked
01411    again, otherwise the node gets a unique internal name.  If the
01412    'instances' list is NULL, then this indicates the root circuit list
01413    and node translations are done though they are 'external'. */
01414 static void
01415 checker_copy_circuit_nodes (struct definition_t * type,
01416                             struct definition_t * inst,
01417                             struct definition_t * sub,
01418                             struct definition_t * copy,
01419                             char * instances)
01420 {
01421     struct node_t * n, * ncopy;
01422 
01423     // go through the list of the subcircuit element's 'copy' nodes
01424     for (ncopy = copy->nodes; ncopy != NULL; ncopy = ncopy->next)
01425     {
01426         // these NULL nodes have intentionally been blanked
01427         if (ncopy->node == NULL)
01428         {
01429             assert (ncopy->xlatenr != 0);
01430             // get translated node
01431             n = checker_get_circuit_node (sub->nodes, ncopy->xlatenr);
01432             ncopy->xlatenr = n->xlatenr;
01433             if (n->xlate)   // translated node
01434             {
01435                 if (instances == NULL)
01436                     // external node indicated by no instances given
01437                     ncopy->node = strdup (n->xlate);
01438                 else
01439                     ncopy->node = NULL; // keep blank
01440             }
01441             else if (!strcmp (n->node, "gnd"))   // global ground node
01442             {
01443                 ncopy->node = strdup (n->node);
01444             }
01445             else if (n->node[strlen (n->node) - 1] == '!')   // other global node
01446             {
01447                 ncopy->node = strdup (n->node);
01448             }
01449             else   // internal subcircuit element node
01450             {
01451                 ncopy->node = checker_subcircuit_node (type->instance, instances,
01452                                                        inst->instance, n->node);
01453             }
01454         }
01455     }
01456 }
01457 
01458 /* This function returns the last entry of the given list of
01459    definitions or NULL if there is no such element. */
01460 static struct definition_t *
01461 checker_find_last_definition (struct definition_t * root)
01462 {
01463     for (struct definition_t * def = root; def != NULL; def = def->next)
01464         if (def->next == NULL) return def;
01465     return NULL;
01466 }
01467 
01468 /* Based upon the the given subcircuit instance identifier list the
01469    function returns a "." - concatenated string or NULL. */
01470 static char * checker_subcircuit_instance_list (strlist * instances)
01471 {
01472     if (instances && instances->length () > 0)
01473         return instances->toString (".");
01474     return NULL;
01475 }
01476 
01477 /* The function creates a subcircuit instance name consisting of the
01478    given arguments.  If the given 'instances' is NULL it is left out.
01479    The caller is responsible to free() the returned string. */
01480 static char * checker_subcircuit_instance (char * type, char * instances,
01481         char * instance, char * base)
01482 {
01483     char * txt = (char *)
01484                  calloc (1, strlen (type) + strlen (instance) + strlen (base) +
01485                          (instances ? strlen (instances) : 0) + 4);
01486     if (instances)
01487         sprintf (txt, "%s.%s.%s.%s", type, instances, instance, base);
01488     else
01489         sprintf (txt, "%s.%s.%s", type, instance, base);
01490     return txt;
01491 }
01492 
01493 /* This function produces a copy of the given subcircuit 'type'
01494    containing the subcircuit elements.  Based upon the instance 'inst'
01495    definitions (node names and instance name) it assign new element
01496    instances and node names.  The function returns a NULL terminated
01497    circuit element list in reverse order. */
01498 static struct definition_t *
01499 checker_copy_subcircuits (struct definition_t * type,
01500                           struct definition_t * inst, strlist * * instances,
01501                           environment * parent)
01502 {
01503     struct definition_t * def, * copy;
01504     struct definition_t * root = NULL;
01505     strlist * instcopy;
01506     char * list;
01507 
01508     // create environment for subcircuit instance
01509     environment * child = new environment (*(type->env));
01510     parent->push_front_Child (child);
01511 
01512     // put instance properties into subcircuit environment
01513     for (struct pair_t * pair = inst->pairs; pair != NULL; pair = pair->next)
01514     {
01515         // anything else than the 'Type'
01516         if (strcmp (pair->key, "Type"))
01517         {
01518             if (pair->value->ident == NULL)
01519             {
01520                 // simple value
01521                 child->setDoubleConstant (pair->key, pair->value->value);
01522                 child->setDouble (pair->key, pair->value->value);
01523             }
01524             else
01525             {
01526                 // reference to variable in upper environment
01527                 child->setDoubleReference (pair->key, pair->value->ident);
01528             }
01529         }
01530     }
01531 
01532     // go through element list of subcircuit
01533     for (def = type->sub; def != NULL; def = def->next)
01534     {
01535 
01536         // translate the node list
01537         checker_xlat_subcircuit_nodes (type, inst, def);
01538 
01539         // allow recursive subcircuits
01540         if (!strcmp (def->type, "Sub"))
01541         {
01542             // get subcircuit template definition
01543             struct definition_t * sub = checker_get_subcircuit (def);
01544             // create a copy of the current subcircuit instance list
01545             if ((*instances) == NULL) (*instances) = new strlist ();
01546             instcopy = new strlist (*(*instances));
01547             // append instance name to recursive instance list
01548             (*instances)->append (inst->instance);
01549             copy = checker_copy_subcircuits (sub, def, instances, child);
01550             // put the expanded definitions into the sublist
01551             if (copy)
01552             {
01553                 list = checker_subcircuit_instance_list (instcopy);
01554                 // assign blanked node names to each subcircuit
01555                 for (struct definition_t * c = copy; c != NULL; c = c->next)
01556                 {
01557                     checker_copy_circuit_nodes (type, inst, def, c, list);
01558                 }
01559                 // append the copies to the subcircuit list
01560                 struct definition_t * last = checker_find_last_definition (copy);
01561                 last->next = root;
01562                 root = copy;
01563             }
01564             // restore original instance list
01565             delete *instances;
01566             *instances = instcopy;
01567         }
01568         else
01569         {
01570             // element copy
01571             copy = checker_copy_subcircuit (def);
01572             // assign new instance name to the element
01573             list = checker_subcircuit_instance_list (*instances);
01574             copy->instance =
01575                 checker_subcircuit_instance (type->instance, list,
01576                                              inst->instance, def->instance);
01577             copy->subcircuit = strdup (type->instance);
01578             // assign node list
01579             checker_copy_subcircuit_nodes (type, inst, def, copy, list);
01580             // apply environment
01581             copy->env = child;
01582             // chain definition (circuit) list
01583             copy->next = root;
01584             root = copy;
01585         }
01586 
01587         // cleanup translated nodes
01588         checker_cleanup_xlat_nodes (def);
01589     }
01590 
01591     // try giving child environment a unique name
01592     strlist * icopy = new strlist ();
01593     icopy->append (type->instance);
01594     icopy->append (*(instances));
01595     icopy->append (inst->instance);
01596     child->setName (std::string(icopy->toString (".")));
01597     delete icopy;
01598 
01599     return root;
01600 }
01601 
01602 /* The function checks whether the subcircuit 'instance' with the
01603    subcircuit 'type' is defined in cycles.  It recursively goes
01604    through the definitions and emits an appropriate error message if
01605    necessary.  The function returns zero if there are no cycles
01606    detected and non-zero with cycles found. */
01607 static int checker_validate_sub_cycles (struct definition_t * root,
01608                                         char * type, char * instance,
01609                                         strlist * * deps)
01610 {
01611     int errors = 0, error;
01612     struct value_t * val;
01613 
01614     /* emit an appropriate error message if the subcircuit type is already
01615        in the dependencies */
01616     if ((*deps)->contains (type))
01617     {
01618         logprint (LOG_ERROR, "checker error, cyclic definition of `%s:%s' "
01619                   "detected, involves: %s\n",
01620                   type, instance, (*deps)->toString ());
01621         return ++errors;
01622     }
01623     (*deps)->append (type);
01624 
01625     // create temporary list of subcircuit types already tested
01626     strlist * checked = new strlist ();
01627     // go through the list of circuit elements of the subcircuit
01628     for (struct definition_t * def = root->sub; def != NULL; def = def->next)
01629     {
01630         // find the appropriate definitions
01631         if (!strcmp (def->type, "Sub"))
01632         {
01633             // recurse into subcircuit instances
01634             if ((val = checker_find_reference (def, "Type")) != NULL)
01635             {
01636                 if (!checked->contains (val->ident))   // only if not already checked
01637                 {
01638                     struct definition_t * sub;
01639                     checked->append (val->ident);
01640                     // copy current dependencies
01641                     strlist * copy = new strlist (*(*deps));
01642                     // validate subcircuit
01643                     sub = checker_find_subcircuit (val->ident);
01644                     if (sub != NULL) // if possible
01645                         error = checker_validate_sub_cycles (sub, sub->instance,
01646                                                              instance, deps);
01647                     else
01648                         error = 1;
01649                     // on errors: go on
01650                     if (error)
01651                     {
01652                         errors += error;
01653                         delete copy;
01654                     }
01655                     // no errors: restore original dependencies
01656                     else
01657                     {
01658                         delete *deps;
01659                         *deps = copy;
01660                     }
01661                 }
01662             }
01663         }
01664     }
01665     delete checked;
01666     return errors;
01667 }
01668 
01669 /* This function dynamically creates a circuit definition based on a
01670    given subcircuit definition including type, number of nodes and the
01671    properties. */
01672 static struct define_t * netlist_create_define (struct definition_t * def)
01673 {
01674     int o, r;
01675     struct pair_t * p;
01676     struct define_t * d =
01677         (struct define_t *) calloc (sizeof (struct define_t), 1);
01678     d->type = strdup (def->instance);
01679     d->nodes = checker_count_nodes (def);
01680     d->action = PROP_COMPONENT;
01681 
01682     // determine number of required and optional parameters
01683     for (o = r = 0, p = def->pairs; p != NULL; p = p->next)
01684     {
01685         if (p->value == NULL)
01686             r++;
01687         else
01688             o++;
01689     }
01690     d->required =
01691         (struct property_t *) calloc (sizeof (struct property_t), r + 2);
01692     d->optional =
01693         (struct property_t *) calloc (sizeof (struct property_t), o + 1);
01694 
01695     // fill in parameters
01696     for (o = r = 0, p = def->pairs; p != NULL; p = p->next)
01697     {
01698         if (p->value == NULL)
01699         {
01700             // required
01701             d->required[r].key = strdup (p->key);
01702             d->required[r].type = PROP_REAL;
01703             d->required[r].defaultval.d = PROP_NO_VAL;
01704             d->required[r].defaultval.s = PROP_NO_STR;
01705             d->required[r].range.il = '.';
01706             d->required[r].range.l = 0;
01707             d->required[r].range.h = 0;
01708             d->required[r].range.ih = '.';
01709             r++;
01710         }
01711         else
01712         {
01713             // optional
01714             d->optional[o].key = strdup (p->key);
01715             d->optional[o].type = PROP_REAL;
01716             d->optional[o].defaultval.d = p->value->value;
01717             d->optional[o].defaultval.s = PROP_NO_STR;
01718             d->optional[o].range.il = '.';
01719             d->optional[o].range.l = 0;
01720             d->optional[o].range.h = 0;
01721             d->optional[o].range.ih = '.';
01722             o++;
01723         }
01724     }
01725 
01726     // extra required
01727     d->required[r].key = strdup ("Type");
01728     d->required[r].type = PROP_STR;
01729     d->required[r].defaultval.d = PROP_NO_VAL;
01730     d->required[r].defaultval.s = PROP_NO_STR;
01731     d->required[r].range.il = '.';
01732     d->required[r].range.l = 0;
01733     d->required[r].range.h = 0;
01734     d->required[r].range.ih = '.';
01735     return d;
01736 }
01737 
01738 /* The function destroys the given circuit definition which must have
01739    been dynamically created before. */
01740 static void netlist_free_define (struct define_t * d)
01741 {
01742     int i;
01743     struct property_t * p;
01744     free ((char *) d->type);
01745     // free required properties
01746     for (i = 0, p = d->required; p[i].key != NULL; i++)
01747     {
01748         free ((char *) p[i].key);
01749     }
01750     free (d->required);
01751     // free optional properties
01752     for (i = 0, p = d->optional; p[i].key != NULL; i++)
01753     {
01754         free ((char *) p[i].key);
01755     }
01756     free (d->optional);
01757     free (d);
01758 }
01759 
01760 /* The function checks the presence of required and optional
01761    properties as well as their content in the given definition.  It
01762    returns zero on success and non-zero otherwise. */
01763 static int checker_validate_properties (struct definition_t * root,
01764                                         struct definition_t * def,
01765                                         struct define_t * available)
01766 {
01767     struct pair_t * pair;
01768     int i, n, errors = 0;
01769 
01770     /* check whether the required properties are given */
01771     for (i = 0; PROP_IS_PROP (available->required[i]); i++)
01772     {
01773         n = checker_find_property (available->required[i].key, def->pairs);
01774         if (n != 1)
01775         {
01776             logprint (LOG_ERROR, "line %d: checker error, required property "
01777                       "`%s' occurred %dx in `%s:%s'\n", def->line,
01778                       available->required[i].key, n, def->type, def->instance);
01779             errors++;
01780         }
01781     }
01782     /* check whether the optional properties are given zero/once */
01783     for (i = 0; PROP_IS_PROP (available->optional[i]); i++)
01784     {
01785         n = checker_find_property (available->optional[i].key, def->pairs);
01786         if (n >= 2)
01787         {
01788             logprint (LOG_ERROR, "line %d: checker error, optional property "
01789                       "`%s' occurred %dx in `%s:%s'\n", def->line,
01790                       available->optional[i].key, n, def->type, def->instance);
01791             errors++;
01792         }
01793     }
01794 
01795     /* check the property content */
01796     for (pair = def->pairs; pair != NULL; pair = pair->next)
01797     {
01798         /* check whether properties are either required or optional */
01799         int type = checker_is_property (available, pair->key);
01800         if (type == PROP_NONE)
01801         {
01802             if (strcmp (def->type, "Def"))
01803             {
01804                 logprint (LOG_ERROR,
01805                           "line %d: checker error, extraneous property `%s' is "
01806                           "invalid in `%s:%s'\n", def->line,
01807                           pair->key, def->type, def->instance);
01808                 errors++;
01809             }
01810         }
01811         // do not check zero-length lists
01812         if (pair->value != NULL)
01813         {
01814             /* check and evaluate the unit scale in a property */
01815             if (!checker_evaluate_scale (pair->value))
01816                 errors++;
01817             /* check whether properties are in range */
01818             if (!checker_value_in_range (def->instance, available, pair))
01819             {
01820                 errors++;
01821             }
01822             /* check variables in properties */
01823             if (!checker_resolve_variable (root, def, pair, type))
01824                 errors++;
01825         }
01826     }
01827     return errors;
01828 }
01829 
01830 /* This function is used by the netlist checker to validate the
01831    subcircuits.  It returns zero with no errors and non-zero on
01832    errors. */
01833 static int checker_validate_subcircuits (struct definition_t * root)
01834 {
01835     int errors = 0;
01836     // go through list of definitions
01837     for (struct definition_t * def = root; def != NULL; def = def->next)
01838     {
01839         // check subcircuit instances
01840         if (!strcmp (def->type, "Sub"))
01841         {
01842             struct value_t * val;
01843             // validate the 'Type' reference
01844             if ((val = checker_validate_reference (def, "Type")) == NULL)
01845             {
01846                 errors++;
01847             }
01848             else
01849             {
01850                 // find an appropriate subcircuit type
01851                 struct definition_t * sub = checker_find_subcircuit (val->ident);
01852                 if (sub == NULL)
01853                 {
01854                     logprint (LOG_ERROR, "line %d: checker error, no such subcircuit "
01855                               "`%s' found as referred in `%s:%s'\n", def->line,
01856                               val->ident, def->type, def->instance);
01857                     errors++;
01858                 }
01859                 else
01860                 {
01861                     // check the number of nodes of the instance and the type
01862                     int n1 = checker_count_nodes (def);
01863                     int n2 = checker_count_nodes (sub);
01864                     if (n1 != n2)
01865                     {
01866                         logprint (LOG_ERROR, "line %d: checker error, subcircuit type "
01867                                   "`%s' requires %d nodes in `%s:%s', found %d\n",
01868                                   def->line, sub->instance, n2,
01869                                   def->type, def->instance, n1);
01870                         errors++;
01871                     }
01872                     // check the subcircuit instance properties
01873                     struct define_t * available = netlist_create_define (sub);
01874                     errors += checker_validate_properties (root, def, available);
01875                     netlist_free_define (available);
01876                     // and finally check for cyclic definitions
01877                     strlist * deps = new strlist ();
01878                     int err = checker_validate_sub_cycles (sub, sub->instance,
01879                                                            def->instance, &deps);
01880                     errors += err;
01881                     checker_sub_cycles = err;
01882                     delete deps;
01883                 }
01884             }
01885         }
01886     }
01887     return errors;
01888 }
01889 
01890 /* Deletes node list of a definition. */
01891 static void netlist_free_nodes (struct node_t * node)
01892 {
01893     struct node_t * n;
01894     for (; node != NULL; node = n)
01895     {
01896         n = node->next;
01897         free (node->node);
01898         free (node);
01899     }
01900 }
01901 
01902 /* The following function free()'s the given value. */
01903 static void netlist_free_value (struct value_t * value)
01904 {
01905     free (value->ident);
01906     if (value->unit)  free (value->unit);
01907     free (value->scale);
01908     free (value);
01909 }
01910 
01911 /* Deletes pair list of a definition. */
01912 static void netlist_free_pairs (struct pair_t * pp)
01913 {
01914     struct pair_t * np;
01915     for (; pp != NULL; pp = np)
01916     {
01917         np = pp->next;
01918         struct value_t * nv, * value;
01919         for (value = pp->value; value != NULL; value = nv)
01920         {
01921             nv = value->next;
01922             netlist_free_value (value);
01923         }
01924         free (pp->key);
01925         free (pp);
01926     }
01927 }
01928 
01929 /* Deletes the given definition. */
01930 static void netlist_free_definition (struct definition_t * def)
01931 {
01932     netlist_free_nodes (def->nodes);
01933     if (!def->copy) netlist_free_pairs (def->pairs);
01934     free (def->subcircuit);
01935     free (def->type);
01936     free (def->instance);
01937     free (def);
01938 }
01939 
01940 /* The function removes the given definition 'cand' from the
01941    definition root.  It returns the new definition root. */
01942 struct definition_t *
01943 netlist_unchain_definition (struct definition_t * root,
01944                             struct definition_t * cand)
01945 {
01946     struct definition_t * prev;
01947     if (cand == root)
01948     {
01949         root = cand->next;
01950         netlist_free_definition (cand);
01951     }
01952     else
01953     {
01954         // find previous to the candidate to be deleted
01955         for (prev = root; prev != NULL && prev->next != cand; prev = prev->next) ;
01956         if (prev != NULL)
01957         {
01958             prev->next = cand->next;
01959             netlist_free_definition (cand);
01960         }
01961     }
01962     return root;
01963 }
01964 
01965 /* The function expands the subcircuits within the given definition
01966    list and returns the expanded list with the subcircuit definitions
01967    removed. */
01968 static struct definition_t *
01969 checker_expand_subcircuits (struct definition_t * root, environment * parent)
01970 {
01971     struct definition_t * def, * sub, * copy, * next, * prev;
01972     strlist * instances = NULL;
01973 
01974     // go through the list of definitions
01975     for (prev = NULL, def = root; def != NULL; def = next)
01976     {
01977         next = def->next;
01978         // is this a subcircuit instance definition ?
01979         if (!strcmp (def->type, "Sub"))
01980         {
01981             // get the subcircuit type definition
01982             sub = checker_get_subcircuit (def);
01983             // and make a copy of it
01984             copy = checker_copy_subcircuits (sub, def, &instances, parent);
01985             if (instances)
01986             {
01987                 delete instances;
01988                 instances = NULL;
01989             }
01990             // remove the subcircuit instance from the original list
01991             if (prev)
01992             {
01993                 prev->next = next;
01994             }
01995             else
01996             {
01997                 root = next;
01998             }
01999             netlist_free_definition (def);
02000             // put the expanded definitions into the netlist
02001             if (copy)
02002             {
02003                 struct definition_t * last = checker_find_last_definition (copy);
02004                 last->next = root;
02005                 if (!prev) prev = last;
02006                 root = copy;
02007             }
02008         }
02009         // component in the root environment
02010         else
02011         {
02012             prev = def;
02013             def->env = parent;
02014         }
02015     }
02016     return root;
02017 }
02018 
02019 /* This function is the checker routine for a parsed netlist.  It
02020    returns zero on success or non-zero if the parsed netlist contained
02021    errors. */
02022 static int netlist_checker_intern (struct definition_t * root)
02023 {
02024     struct definition_t * def;
02025     struct define_t * available;
02026     int n, errors = 0;
02027 
02028     /* go through all definitions */
02029     for (def = root; def != NULL; def = def->next)
02030     {
02031 
02032         /* check whether the definition type is known */
02033         available = checker_find_definition (def->type, def->action);
02034         if (available == NULL)
02035         {
02036             logprint (LOG_ERROR, "line %d: checker error, invalid definition type "
02037                       "`%s'\n", def->line, def->type);
02038             errors++;
02039         }
02040         else
02041         {
02042             /* mark nodeset definitions */
02043             def->nodeset = !strcmp (def->type, "NodeSet") ? 1 : 0;
02044             /* mark nonlinear circuit definitions */
02045             def->nonlinear = available->nonlinear;
02046             /* mark substrate definitions */
02047             def->substrate = available->substrate;
02048             /* save available definition */
02049             def->define = available;
02050             /* check whether the number of nodes is correct and save the
02051                number of given nodes */
02052             n = def->ncount = checker_count_nodes (def);
02053             if (available->nodes == PROP_NODES)
02054             {
02055                 if (n < 1)
02056                 {
02057                     logprint (LOG_ERROR,
02058                               "line %d: checker error, at least 1 node required in "
02059                               "`%s:%s', found %d\n", def->line, def->type,
02060                               def->instance, n);
02061                     errors++;
02062                 }
02063             }
02064             else if (available->nodes != n)
02065             {
02066                 logprint (LOG_ERROR,
02067                           "line %d: checker error, %d node(s) required in `%s:%s', "
02068                           "found %d\n", def->line,
02069                           available->nodes, def->type, def->instance, n);
02070                 errors++;
02071             }
02072             /* check the properties except for subcircuits */
02073             if (strcmp (def->type, "Sub"))
02074             {
02075                 errors += checker_validate_properties (root, def, available);
02076             }
02077         }
02078         /* check the number of definitions */
02079         n = checker_count_definition (root, def->type, def->instance);
02080         if (n != 1 && def->duplicate == 0)
02081         {
02082             logprint (LOG_ERROR, "checker error, found %d definitions of `%s:%s'\n",
02083                       n, def->type, def->instance);
02084             errors++;
02085         }
02086     }
02087     /* check microstrip definitions */
02088     errors += checker_validate_strips (root);
02089     /* check subcircuit definitions */
02090     errors += checker_validate_subcircuits (root);
02091     /* check nodeset definitions */
02092     errors += checker_validate_nodesets (root);
02093     return errors;
02094 }
02095 
02096 #if DEBUG
02097 /* Debug function: Prints value representation. */
02098 static void netlist_list_value (struct value_t * value)
02099 {
02100     if (value == NULL)
02101         logprint (LOG_STATUS, "[]");
02102     else if (value->ident)
02103         logprint (LOG_STATUS, "%s", value->ident);
02104     else if (value->next)
02105     {
02106         logprint (LOG_STATUS, "[");
02107         for (; value != NULL; value = value->next)
02108             logprint (LOG_STATUS, "%g%s", value->value, value->next ? ";" : "");
02109         logprint (LOG_STATUS, "]");
02110     }
02111     else
02112     {
02113         logprint (LOG_STATUS, "%g", value->value);
02114         if (value->scale)
02115             logprint (LOG_STATUS, "%s", value->scale);
02116         if (value->unit)
02117             logprint (LOG_STATUS, "%s", value->unit);
02118     }
02119 }
02120 
02121 /* Debug function: Prints definition list representation. */
02122 static void netlist_lister (struct definition_t * root, const char * prefix)
02123 {
02124     struct definition_t * def;
02125     struct node_t * node;
02126     struct pair_t * pair;
02127     for (def = root; def != NULL; def = def->next)
02128     {
02129         logprint (LOG_STATUS, "%s%s:%s", prefix, def->type, def->instance);
02130         for (node = def->nodes; node != NULL; node = node->next)
02131         {
02132             logprint (LOG_STATUS, " %s", node->node);
02133         }
02134         for (pair = def->pairs; pair != NULL; pair = pair->next)
02135         {
02136             logprint (LOG_STATUS, " %s=\"", pair->key);
02137             netlist_list_value (pair->value);
02138             logprint (LOG_STATUS, "\"");
02139         }
02140         logprint (LOG_STATUS, "\n");
02141     }
02142 }
02143 
02144 /* Debug function: Prints the overall netlist representation. */
02145 void netlist_list (void)
02146 {
02147     struct definition_t * def;
02148     logprint (LOG_STATUS, "subcircuit %s\n", "root");
02149     netlist_lister (definition_root, "  ");
02150     for (def = subcircuit_root; def != NULL; def = def->next)
02151     {
02152         logprint (LOG_STATUS, "subcircuit %s\n", def->instance);
02153         netlist_lister (def->sub, "  ");
02154     }
02155 }
02156 #endif /* DEBUG */
02157 
02158 /* The function logs the content of the current netlist by telling how
02159    many instances of which kind of components are used in the netlist. */
02160 void netlist_status (void)
02161 {
02162     struct define_t * def;
02163     struct definition_t * cir;
02164     int count;
02165     logprint (LOG_STATUS, "netlist content\n");
02166     hashiterator<module> it;
02167     for (it = hashiterator<module> (module::modules); *it; ++it)
02168     {
02169         def = it.currentVal()->definition;
02170         for (count = 0, cir = definition_root; cir != NULL; cir = cir->next)
02171         {
02172             if (!strcmp (def->type, cir->type)) count++;
02173         }
02174         if (count > 0)
02175         {
02176             logprint (LOG_STATUS, "  %5d %s instances\n", count, def->type);
02177         }
02178     }
02179 }
02180 
02181 /* The function builds the equation list for a given list of
02182    definition and removes the definition containing the equations from
02183    the list. */
02184 static struct definition_t *
02185 checker_build_equations (struct definition_t * root, eqn::node ** eroot)
02186 {
02187     struct definition_t * def, * next, * prev;
02188     eqn::node * eqns, * last;
02189     *eroot = NULL;
02190     // go through list of definitions
02191     for (prev = NULL, def = root; def != NULL; def = next)
02192     {
02193         next = def->next;
02194         if (!strcmp (def->type, "Eqn"))
02195         {
02196             // rechain definition list
02197             if (prev)
02198             {
02199                 prev->next = next;
02200             }
02201             else
02202             {
02203                 root = next;
02204             }
02205             // append equations
02206             eqns = (eqn::node *) def->eqns;
02207             last = eqn::checker::lastEquation (eqns);
02208             last->setNext (*eroot);
02209             *eroot = eqns;
02210             // free this definition
02211             netlist_free_definition (def);
02212         }
02213         else prev = def;
02214     }
02215     return root;
02216 }
02217 
02218 /* The function creates an environment for the given definition root
02219    including equation checker and solver. */
02220 static void checker_setup_env (struct definition_t * root,
02221                                environment * env, eqn::node * eqns)
02222 {
02223     // create equation checker
02224     eqn::checker * checkee = new eqn::checker ();
02225     // pass equations to the checker
02226     checkee->setEquations (eqns);
02227     // add constants to the list of equations
02228     checkee->constants ();
02229     // pass checker
02230     env->setChecker (checkee);
02231     // create equation solver
02232     eqn::solver * solvee = new eqn::solver (checkee);
02233     // pass solver
02234     env->setSolver (solvee);
02235     // apply environment to the netlist root
02236     if (root) root->env = env;
02237 }
02238 
02239 /* Adds the arguments of a subcircuit into the equation checker of the
02240    given environment. */
02241 static void checker_subcircuit_args (struct definition_t * def,
02242                                      environment * env)
02243 {
02244     for (struct pair_t * pair = def->pairs; pair != NULL; pair = pair->next)
02245     {
02246         // anything else than the 'Type'
02247         if (strcmp (pair->key, "Type"))
02248         {
02249             // put it into the equation checker
02250             env->getChecker()->addDouble ("#subcircuit",
02251                                           pair->key, pair->value->value);
02252             // also put it into the environment
02253             variable * v = checker_add_variable (env, pair->key, TAG_DOUBLE, true);
02254             v->getConstant()->d = pair->value->value;
02255         }
02256     }
02257 }
02258 
02259 /* This is the global netlist checker.  It returns zero on success and
02260    non-zero on errors. */
02261 int netlist_checker (environment * env)
02262 {
02263     int errors = 0;
02264     eqn::node * eqns;
02265     struct definition_t * def;
02266 
02267     // create top-level environment
02268     env_root = new environment (env->getName ());
02269     // create the subcircuit list
02270     definition_root = checker_build_subcircuits (definition_root);
02271     // get equation list
02272     definition_root = checker_build_equations (definition_root, &eqns);
02273     // setup the root environment
02274     checker_setup_env (definition_root, env_root, eqns);
02275     // check list of subcircuits
02276     errors += netlist_checker_intern (subcircuit_root);
02277     // check global netlist
02278     errors += netlist_checker_intern (definition_root);
02279     // check equations in root
02280     env_root->setDefinitions (definition_root);
02281     errors += env_root->equationChecker (0);
02282     env_root->setDefinitions (NULL);
02283 
02284     // then check each subcircuit list
02285     for (def = subcircuit_root; def != NULL; def = def->next)
02286     {
02287         // get equation list
02288         def->sub = checker_build_equations (def->sub, &eqns);
02289         // setup the subcircuit environment
02290         environment * subenv = new environment (def->instance);
02291         env_root->push_front_Child (subenv);
02292         checker_setup_env (def, subenv, eqns);
02293         if (def->sub) def->sub->env = subenv;
02294         // add subcircuit parameters to equations
02295         checker_subcircuit_args (def, subenv);
02296         // check subcircuit netlist
02297         errors += netlist_checker_intern (def->sub);
02298         // check equations in subcircuit
02299         subenv->setDefinitions (def->sub);
02300         errors += subenv->equationChecker (0);
02301         subenv->setDefinitions (NULL);
02302     }
02303 
02304     // check actions
02305     errors += checker_validate_actions (definition_root);
02306 
02307     if (!errors)
02308     {
02309         // create actual root environment
02310         env->copy (*env_root);
02311         // and finally expand the subcircuits into the global netlist
02312         definition_root = checker_expand_subcircuits (definition_root, env);
02313     }
02314 
02315     return errors ? -1 : 0;
02316 }
02317 
02318 /* The function deletes the given definition list. */
02319 static void netlist_destroy_intern (struct definition_t * root)
02320 {
02321     struct definition_t * def, * next;
02322     for (def = root; def != NULL; def = next)
02323     {
02324         next = def->next;
02325         netlist_free_definition (def);
02326     }
02327 }
02328 
02329 /* Deletes all available definition lists. */
02330 void netlist_destroy (void)
02331 {
02332     netlist_destroy_intern (definition_root);
02333     for (struct definition_t * def = subcircuit_root; def; def = def->next)
02334     {
02335         netlist_destroy_intern (def->sub);
02336     }
02337     netlist_destroy_intern (subcircuit_root);
02338     definition_root = subcircuit_root = NULL;
02339     netlist_lex_destroy ();
02340 }
02341 
02342 /* Delete root environment(s) if necessary. */
02343 void netlist_destroy_env (void)
02344 {
02345     if (env_root != NULL)
02346     {
02347         delete env_root;
02348         env_root = NULL;
02349     }
02350 }
02351