/* -*-c++-*- */
%{
/*
* parse_netlist.y - parser for the Qucs netlist
*
* Copyright (C) 2003, 2004, 2005, 2006, 2007 Stefan Jahn <stefan@lkcc.org>
*
* 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 <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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;
%}
%define api.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 <ident> Identifier Assign NodeIdentifier InstanceIdentifier
%type <str> ScaleOrUnit
%type <d> REAL IMAG
%type <c> COMPLEX
%type <chr> Character
%type <str> STRING
%type <definition> DefinitionLine ActionLine DefBody DefBodyLine EquationLine
%type <definition> InputList InputLine
%type <subcircuit> DefBegin SubcircuitBody
%type <node> NodeList
%type <pair> PairList
%type <value> PropertyValue ValueList Value PropertyReal
%type <eqn> EquationList Expression ExpressionList
%type <assign> Equation
%type <con> Constant
%type <ref> Reference
%type <app> Application Range Matrix Vector
%type <eqn> ExpressionMatrix ExpressionVector
%type <eqn> 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;
}