/* -*-c++-*- */ %{ /* * parse_netlist.y - parser for the Qucs netlist * * Copyright (C) 2003, 2004, 2005, 2006, 2007 Stefan Jahn * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this package; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. * * $Id$ * */ #if HAVE_CONFIG_H # include #endif #include #include #include #define YYERROR_VERBOSE 42 #define YYDEBUG 1 #define YYMAXDEPTH 1000000 #include "check_netlist.h" #include "logging.h" #include "equation.h" #include "range.h" using namespace qucs; %} %name-prefix "netlist_" %token InvalidCharacter %token Identifier %token Assign %token ScaleOrUnit %token Eol %token Eqn %token DefSub %token EndSub %token REAL %token IMAG %token COMPLEX %token Character %token STRING %right '=' %right '?' ':' %left Or %left And %left NotEqual Equal %left Less Greater LessOrEqual GreaterOrEqual %left '-' '+' %left '*' '/' '%' %right Not %left NEG /* unary negation */ %left POS /* unary non-negation */ %right '^' %union { char * ident; char * str; double d; char chr; struct definition_t * definition; struct definition_t * subcircuit; struct node_t * node; struct pair_t * pair; struct value_t * value; struct { double r; double i; } c; qucs::eqn::node * eqn; qucs::eqn::constant * con; qucs::eqn::reference * ref; qucs::eqn::application * app; qucs::eqn::assignment * assign; } %type Identifier Assign NodeIdentifier InstanceIdentifier %type ScaleOrUnit %type REAL IMAG %type COMPLEX %type Character %type STRING %type DefinitionLine ActionLine DefBody DefBodyLine EquationLine %type InputList InputLine %type DefBegin SubcircuitBody %type NodeList %type PairList %type PropertyValue ValueList Value PropertyReal %type EquationList Expression ExpressionList %type Equation %type Constant %type Reference %type Application Range Matrix Vector %type ExpressionMatrix ExpressionVector %type ExpressionRowList ExpressionCol ExpressionColList %% Input: InputList { definition_root = $1; } ; InputList: /* nothing */ { $$ = NULL; } | InputLine InputList { if ($1) { $1->next = $2; $$ = $1; } else { $$ = $2; } } ; InputLine: SubcircuitBody { $$ = $1; } | EquationLine | ActionLine | DefinitionLine | Eol { $$ = NULL; } ; /* An action line in the netlist, i.e. the specification of the type of simulation to be performed */ ActionLine: '.' Identifier ':' InstanceIdentifier PairList Eol { $$ = (struct definition_t *) calloc (sizeof (struct definition_t), 1); $$->action = PROP_ACTION; $$->type = $2; $$->instance = $4; $$->pairs = $5; $$->line = netlist_lineno; } ; /* A definition line in the netlist, i.e. a component specification such as R:R1 _net0 gnd R="50 Ohm" Temp="26.85" Tc1="0.0" Tc2="0.0" Tnom="26.85" */ DefinitionLine: Identifier ':' InstanceIdentifier NodeList PairList Eol { $$ = (struct definition_t *) calloc (sizeof (struct definition_t), 1); $$->action = PROP_COMPONENT; $$->type = $1; $$->instance = $3; $$->nodes = $4; $$->pairs = $5; $$->line = netlist_lineno; } ; InstanceIdentifier: Identifier { $$ = $1; } | ScaleOrUnit { $$ = $1; } ; NodeIdentifier: Identifier { $$ = $1; } | ScaleOrUnit { $$ = $1; } ; /* List of nodes for a component */ NodeList: /* nothing */ { $$ = NULL; } | NodeIdentifier NodeList { $$ = (struct node_t *) calloc (sizeof (struct node_t), 1); $$->node = $1; $$->next = $2; } ; /* Assigns the list of key-value pairs x="y" */ PairList: /* nothing */ { $$ = NULL; } | Assign Value PairList { $$ = (struct pair_t *) calloc (sizeof (struct pair_t), 1); $$->key = $1; $$->value = $2; $$->next = $3; } | Assign NoneValue PairList { if (0) { $$ = (struct pair_t *) calloc (sizeof (struct pair_t), 1); $$->key = $1; $$->value = NULL; $$->next = $3; } else { free ($1); $$ = $3; } } ; /* A empty value in a pair list */ NoneValue: { /* nothing */ } | '"' '"' { /* also nothing */ } ; /* A property value, can either be on its own or enclosed in quotes */ Value: PropertyValue { $$ = $1; } | '"' PropertyValue '"' { $$ = $2; } ; PropertyReal: REAL { $$ = create_value (); $$->value = $1; } | REAL ScaleOrUnit { $$ = create_value (); $$->value = $1; $$->scale = $2; } | REAL ScaleOrUnit ScaleOrUnit { $$ = create_value (); $$->value = $1; $$->scale = $2; $$->unit = $3; } ; PropertyValue: PropertyReal { $$ = $1; } | InstanceIdentifier { $$ = create_value (); $$->ident = $1; } | '[' InstanceIdentifier ']' { $$ = create_value (); $$->ident = $2; } | '[' ValueList ']' { $$ = $2; } ; ValueList: /* nothing */ { $$ = NULL; } | PropertyReal { $1->next = NULL; $$ = $1; } | PropertyReal ';' ValueList { $1->next = $3; $$ = $1; } ; EquationLine: Eqn ':' InstanceIdentifier Equation EquationList Eol { /* create equation definition */ $$ = (struct definition_t *) calloc (sizeof (struct definition_t), 1); $$->type = strdup ("Eqn"); $$->instance = $3; $$->action = PROP_ACTION; $$->line = netlist_lineno; $4->setInstance ($3); $4->setNext ($5); $4->applyInstance (); $$->eqns = $4; } ; EquationList: /* nothing */ { $$ = NULL; } | Equation EquationList { $1->setNext ($2); $$ = $1; } ; Equation: Assign '"' Expression '"' { $$ = new eqn::assignment (); $$->result = $1; $$->body = $3; } ; Expression: Constant { $$ = $1; } | Reference { $$ = $1; } | Application { $$ = $1; } | '(' Expression ')' { $$ = $2; } | '[' Vector ']' { $$ = $2; } | '[' Matrix ']' { $$ = $2; } ; ExpressionCol: Expression ExpressionColList { $1->appendNodes ($2); $$ = $1; } ; ExpressionColList: /* nothing */ { $$ = NULL; } | ',' Expression ExpressionColList { $2->appendNodes ($3); $$ = $2; } ; ExpressionVector: ExpressionCol ; Vector: ExpressionVector { $$ = new eqn::application (); $$->n = strdup ("vector"); $$->nargs = $1->count (); $$->args = $1; } ; ExpressionRowList: /* nothing */ { $$ = NULL; } | ';' ExpressionCol ExpressionRowList { eqn::constant * c = new eqn::constant (eqn::TAG_CHAR); c->chr = ';'; c->appendNodes ($2); $2->appendNodes ($3); $$ = c; } ; ExpressionMatrix: ExpressionCol ';' ExpressionCol ExpressionRowList { eqn::constant * c = new eqn::constant (eqn::TAG_CHAR); c->chr = ';'; c->appendNodes ($3); $3->appendNodes ($4); $1->appendNodes (c); $$ = $1; } ; Matrix: ExpressionMatrix { $$ = new eqn::application (); $$->n = strdup ("matrix"); $$->nargs = $1->count (); $$->args = $1; } ; Constant: REAL { $$ = new eqn::constant (eqn::TAG_DOUBLE); $$->d = $1; } | IMAG { $$ = new eqn::constant (eqn::TAG_COMPLEX); $$->c = new nr_complex_t (0.0, $1); } | Character { $$ = new eqn::constant (eqn::TAG_CHAR); $$->chr = $1; } | STRING { $$ = new eqn::constant (eqn::TAG_STRING); $$->s = $1; } ; Range: Expression ':' Expression { $$ = new eqn::application (); $$->n = strdup ("range"); $$->nargs = 2; $1->append ($3); $$->args = $1; } | ':' Expression { $$ = new eqn::application (); $$->n = strdup ("range"); $$->nargs = 2; eqn::constant * c = new eqn::constant (eqn::TAG_CHAR); c->chr = '?'; c->append ($2); $$->args = c; } | Expression ':' { $$ = new eqn::application (); $$->n = strdup ("range"); $$->nargs = 2; eqn::constant * c = new eqn::constant (eqn::TAG_CHAR); c->chr = '?'; $1->append (c); $$->args = $1; } | ':' { $$ = new eqn::application (); $$->n = strdup ("range"); $$->nargs = 2; eqn::constant * c1 = new eqn::constant (eqn::TAG_CHAR); eqn::constant * c2 = new eqn::constant (eqn::TAG_CHAR); c1->chr = '?'; c2->chr = '?'; c1->append (c2); $$->args = c1; } ; Reference: Identifier { $$ = new eqn::reference (); $$->n = $1; } ; Application: Identifier '(' ExpressionList ')' { $$ = new eqn::application (); $$->n = $1; $$->nargs = $3->count (); $$->args = $3; } | Reference '[' ExpressionList ']' { $$ = new eqn::application (); $$->n = strdup ("array"); $$->nargs = 1 + $3->count (); $1->setNext ($3); $$->args = $1; } | Expression '+' Expression { $$ = new eqn::application (); $$->n = strdup ("+"); $$->nargs = 2; $1->append ($3); $$->args = $1; } | Expression '-' Expression { $$ = new eqn::application (); $$->n = strdup ("-"); $$->nargs = 2; $1->append ($3); $$->args = $1; } | Expression '*' Expression { $$ = new eqn::application (); $$->n = strdup ("*"); $$->nargs = 2; $1->append ($3); $$->args = $1; } | Expression '/' Expression { $$ = new eqn::application (); $$->n = strdup ("/"); $$->nargs = 2; $1->append ($3); $$->args = $1; } | Expression '%' Expression { $$ = new eqn::application (); $$->n = strdup ("%"); $$->nargs = 2; $1->append ($3); $$->args = $1; } | '+' Expression %prec POS { $$ = new eqn::application (); $$->n = strdup ("+"); $$->nargs = 1; $$->args = $2; } | '-' Expression %prec NEG { $$ = new eqn::application (); $$->n = strdup ("-"); $$->nargs = 1; $$->args = $2; } | Expression '^' Expression { $$ = new eqn::application (); $$->n = strdup ("^"); $$->nargs = 2; $1->append ($3); $$->args = $1; } | Expression '?' Expression ':' Expression { $$ = new eqn::application (); $$->n = strdup ("?:"); $$->nargs = 3; $1->append ($3); $1->append ($5); $$->args = $1; } | Expression Less Expression { $$ = new eqn::application (); $$->n = strdup ("<"); $$->nargs = 2; $1->append ($3); $$->args = $1; } | Expression Greater Expression { $$ = new eqn::application (); $$->n = strdup (">"); $$->nargs = 2; $1->append ($3); $$->args = $1; } | Expression GreaterOrEqual Expression { $$ = new eqn::application (); $$->n = strdup (">="); $$->nargs = 2; $1->append ($3); $$->args = $1; } | Expression LessOrEqual Expression { $$ = new eqn::application (); $$->n = strdup ("<="); $$->nargs = 2; $1->append ($3); $$->args = $1; } | Expression Equal Expression { $$ = new eqn::application (); $$->n = strdup ("=="); $$->nargs = 2; $1->append ($3); $$->args = $1; } | Expression NotEqual Expression { $$ = new eqn::application (); $$->n = strdup ("!="); $$->nargs = 2; $1->append ($3); $$->args = $1; } | Not Expression { $$ = new eqn::application (); $$->n = strdup ("!"); $$->nargs = 1; $$->args = $2; } | Expression And Expression { $$ = new eqn::application (); $$->n = strdup ("&&"); $$->nargs = 2; $1->append ($3); $$->args = $1; } | Expression Or Expression { $$ = new eqn::application (); $$->n = strdup ("||"); $$->nargs = 2; $1->append ($3); $$->args = $1; } ; ExpressionList: /* nothing */ { $$ = NULL; } | Expression { $$ = $1; } | Range { $$ = $1; } | Expression ',' ExpressionList { $1->setNext ($3); $$ = $1; } | Range ',' ExpressionList { $1->setNext ($3); $$ = $1; } ; SubcircuitBody: DefBegin DefBody DefEnd { /* a full subcircuit definition found */ $1->sub = $2; $$ = $1; $2 = NULL; } ; DefBegin: DefSub InstanceIdentifier NodeList PairList Eol { /* create subcircuit definition right here */ $$ = (struct definition_t *) calloc (sizeof (struct definition_t), 1); $$->type = strdup ("Def"); $$->instance = $2; $$->nodes = $3; $$->pairs = $4; $$->action = PROP_ACTION; $$->line = netlist_lineno; } ; DefBody: /* nothing */ { $$ = NULL; } | DefBodyLine DefBody { /* chain definitions here */ if ($1) { $1->next = $2; $$ = $1; } else { $$ = $2; } } ; DefEnd: EndSub Eol { /* nothing to do */ } ; DefBodyLine: DefinitionLine { /* chain definitions here */ $1->next = $$; $$ = $1; } | EquationLine { /* chain definitions here */ $1->next = $$; $$ = $1; } | SubcircuitBody { /* do nothing here, see subcircuit rule */ } | Eol { $$ = NULL; } ; %% int netlist_error (const char * error) { logprint (LOG_ERROR, "line %d: %s\n", netlist_lineno, error); return 0; }