Qucs-core  0.0.19
scan_netlist.l
Go to the documentation of this file.
00001 /* -*-c-*- */
00002 
00003 %{
00004 /*
00005  * scan_netlist.l - scanner for the Qucs netlist
00006  *
00007  * Copyright (C) 2003-2009 Stefan Jahn <stefan@lkcc.org>
00008  *
00009  * This is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2, or (at your option)
00012  * any later version.
00013  *
00014  * This software is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this package; see the file COPYING.  If not, write to
00021  * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
00022  * Boston, MA 02110-1301, USA.
00023  *
00024  * $Id$
00025  *
00026  */
00027 
00028 #if defined(__clang__)
00029 #pragma clang diagnostic push
00030 #pragma clang diagnostic ignored "-Wdeprecated-register"
00031 #endif
00032 
00033 #if HAVE_CONFIG_H
00034 # include <config.h>
00035 #endif
00036 
00037 #include <stdio.h>
00038 #include <stdlib.h>
00039 #include <string.h>
00040 #include <ctype.h>
00041 
00042 #ifdef __MINGW32__
00043 #include <io.h>
00044 #endif
00045 
00046 #ifdef HAVE_UNISTD_H
00047 #include <unistd.h>
00048 #endif
00049 
00050 #include "logging.h"
00051 #include "equation.h"
00052 #include "check_netlist.h"
00053 #include "tokens_netlist.h"
00054 
00055 #if !HAVE_STRCHR
00056 # define strchr  index
00057 # define strrchr rindex
00058 #endif
00059 
00060 using namespace qucs;
00061 
00062 static double netlist_evaluate_scale (double val, char * scale) {
00063   double factor = 1.0;
00064   while (isspace (scale[0])) scale++;
00065   switch (scale[0]) {
00066   case 'E': factor = 1e+18; break;
00067   case 'P': factor = 1e+15; break;
00068   case 'T': factor = 1e+12; break;
00069   case 'G': factor = 1e+09; break;
00070   case 'M': factor = 1e+06; break;
00071   case 'k': factor = 1e+03; break;
00072   case 'm':
00073     if (scale[1] == 'i' && scale[2] == 'l')
00074       factor = 2.54e-5;
00075     else
00076       factor = 1e-03;
00077     break;
00078   case 'u': factor = 1e-06; break;
00079   case 'n': factor = 1e-09; break;
00080   case 'p': factor = 1e-12; break;
00081   case 'f':
00082     if (scale[1] == 't')
00083       factor = 0.3048;
00084     else
00085       factor = 1e-15;
00086     break;
00087   case 'a': factor = 1e-18; break;
00088   case 'd':
00089     if (scale[1] == 'B') {
00090       val = std::pow (10.0, val / 10.0);
00091       if (scale[2] == 'm')
00092         factor = 1e-03;
00093       else if (scale[2] == 'u')
00094         factor = 1e-06;
00095     }
00096     break;
00097   case 'i':
00098     if (scale[1] == 'n')
00099       factor = 2.54e-2;
00100     break;
00101   case 'y':
00102     if (scale[1] == 'd')
00103       factor = 0.9144;
00104     break;
00105   }
00106   return val * factor;
00107 }
00108 
00109 %}
00110 
00111 WS       [ \t\n\r]
00112 SIMPLEID [a-zA-Z_][a-zA-Z0-9_]*
00113 POSTID   "."[a-zA-Z0-9_]+
00114 ID       {SIMPLEID}{POSTID}*
00115 NODE     {SIMPLEID}\!?
00116 FILE     "{"[^\t\n\r\}]+"}"
00117 CHR      "'"[^\n\r\']{1}"'"
00118 STR      "'"[^\n\r\']*"'"
00119 DIGIT    [0-9]
00120 EXPONENT [Ee][+-]?{DIGIT}+
00121 PFX1     ("E"|"P"|"T"|"G"|"M"|"k"|"m"|"u"|"n"|"p"|"f"|"a")
00122 PFX2     ("mil"|"in"|"ft"|"yd")
00123 PFX3     ("dBu"|"dBm"|"dB")
00124 PFX      ({PFX1}|{PFX3})
00125 UNT      ("Ohm"|"S"|"s"|"K"|"H"|"F"|"Hz"|"V"|"A"|"W"|"m")
00126 EXCEPT   ("mm"|{PFX2})
00127 SU       ({PFX}|{UNT}|{PFX}{UNT}|{EXCEPT})
00128 SPACE    [ \t]
00129 RINT     [+-]?{DIGIT}+
00130 IINT     [+-]?[ij]{1}{DIGIT}*
00131 RFLOAT1  [+-]?{DIGIT}+{EXPONENT}
00132 RFLOAT2  [+-]?{DIGIT}*"."{DIGIT}+({EXPONENT})?
00133 IFLOAT1  [+-]?[ij]{1}{DIGIT}+{EXPONENT}
00134 IFLOAT2  [+-]?[ij]{1}{DIGIT}*"."{DIGIT}+({EXPONENT})?
00135 CREAL    ({RFLOAT1}|{RFLOAT2}|{RINT})
00136 CIMAG    ({IFLOAT1}|{IFLOAT2}|{IINT})
00137 COMPLEX  {CREAL}{CIMAG}
00138 URINT    {DIGIT}+
00139 UIINT    [ij]{1}{DIGIT}*
00140 URFLOAT1 {DIGIT}+{EXPONENT}
00141 URFLOAT2 {DIGIT}*"."{DIGIT}+({EXPONENT})?
00142 UIFLOAT1 [ij]{1}{DIGIT}+{EXPONENT}
00143 UIFLOAT2 [ij]{1}{DIGIT}*"."{DIGIT}+({EXPONENT})?
00144 UCREAL   ({URFLOAT1}|{URFLOAT2}|{URINT})({SPACE})*({PFX})?
00145 UCIMAG   ({UIFLOAT1}|{UIFLOAT2}|{UIINT})({SPACE})*({PFX})?
00146 UCOMPLEX {UCREAL}{UCIMAG}
00147 
00148 
00149 %x COMMENT STR EQN
00150 %option yylineno noyywrap nounput noinput prefix="netlist_"
00151 
00152 %%
00153 
00154 <INITIAL,STR>{SU} { /* identify scale and/or unit */
00155     netlist_lval.str = strdup (netlist_text);
00156     return ScaleOrUnit;
00157   }
00158 <INITIAL>"Eqn" { /* special equation case */
00159     BEGIN(EQN);
00160     return Eqn;
00161   }
00162 <INITIAL>"."{SPACE}*"Def"{SPACE}*":" {
00163     /* subcircuit definition begins */
00164     return DefSub;
00165   }
00166 <INITIAL>"."{SPACE}*"Def"{SPACE}*":"{SPACE}*"End" {
00167     /* subcircuit definition ends */
00168     return EndSub;
00169   }
00170 <INITIAL,STR>{ID} { /* identify identifier */
00171     netlist_lval.ident = strdup (netlist_text);
00172     return Identifier;
00173   }
00174 <INITIAL>{NODE} { /* identify node identifier */
00175     netlist_lval.ident = strdup (netlist_text);
00176     return Identifier;
00177   }
00178 <INITIAL,STR>{FILE} { /* identify file reference */
00179     char * p = strrchr (netlist_text, '}');
00180     if (!p) {
00181       return InvalidCharacter;
00182     }
00183     //size_t len = (size_t)p - (size_t)&netlist_text[1];
00184     //netlist_lval.ident = strndup (&netlist_text[1], len);
00185     *p = '\0';
00186     netlist_lval.ident = strdup (&netlist_text[1]);
00187     return Identifier;
00188   }
00189 <INITIAL,STR>{CREAL} { /* identify (signed) real float */
00190     netlist_lval.d = strtod (netlist_text, NULL);
00191     return REAL;
00192   }
00193 <INITIAL,STR>{CIMAG} { /* identify (signed) imaginary float */
00194     if (netlist_text[0] == 'i' || netlist_text[0] == 'j')
00195       netlist_text[0] = (netlist_text[1] == '\0') ? '1' : '0';
00196     else
00197       netlist_text[1] = '0';
00198     netlist_lval.d = strtod (netlist_text, NULL);
00199     return IMAG;
00200   }
00201 <INITIAL,STR>{COMPLEX} { /* identify complete (signed) complex number */
00202     int i = 0;
00203     while (netlist_text[i] != 'i' && netlist_text[i] != 'j') i++;
00204     netlist_text[i] = netlist_text[i - 1];
00205     netlist_text[i - 1] = '\0';
00206     netlist_lval.c.r = strtod (netlist_text, NULL);
00207     netlist_lval.c.i = strtod (&netlist_text[i], NULL);
00208     return COMPLEX;
00209   }
00210 <INITIAL,EQN>{ID}{SPACE}*=[^=] {  /* identify 'identifier =' assign */
00211     int len = netlist_leng - 3;
00212     while (isspace (netlist_text[len])) len--;
00213     netlist_lval.ident = (char *) calloc (len + 2, 1);
00214     memcpy (netlist_lval.ident, netlist_text, len + 1);
00215     yyless (netlist_leng - 1); /* push back last character */
00216     return Assign;
00217   }
00218 
00219 <INITIAL,STR>"[" { /* special token for the value list */ return '['; }
00220 <INITIAL,STR>"]" { /* special token for the value list */ return ']'; }
00221 <INITIAL,STR>";" { /* special token for the value list */ return ';'; }
00222 
00223 <INITIAL>"."   { /* pass the '.' to the parser */ return '.'; }
00224 <INITIAL>":"   { /* pass the ':' to the parser */ return ':'; }
00225 <INITIAL>"="   { /* pass the '=' to the parser */ return '='; }
00226 <INITIAL>\r?\n { /* detect end of line */ return Eol; }
00227 
00228 <INITIAL,EQN>{SPACE}|\\\r?\n /* skip spaces and the trailing '\' */
00229 
00230 <INITIAL>"#" { /* leave these characters */
00231     BEGIN(COMMENT);
00232   }
00233 <INITIAL>\" { /* string constant starts here */
00234     BEGIN(STR);
00235     return '"';
00236   }
00237 <INITIAL>. { /* any other character in invalid */
00238     logprint (LOG_ERROR,
00239               "line %d: syntax error, unrecognized character: `%s'\n",
00240               netlist_lineno, netlist_text);
00241     return InvalidCharacter;
00242   }
00243 
00244 <COMMENT>. { /* skip any character in here */ }
00245 <COMMENT>\r?\n { BEGIN(INITIAL); /* skipping ends here */ }
00246 
00247 <STR>\" { /* string constant ends here */
00248     BEGIN(INITIAL);
00249     return '"';
00250   }
00251 <STR>\r?\n { /* string in a single line only */
00252     logprint (LOG_ERROR,
00253               "line %d: syntax error, unterminated string constant\n",
00254               netlist_lineno);
00255     return Eol;
00256   }
00257 <STR,EQN>{SPACE} /* skip spaces */
00258 
00259 <STR>. { /* any other character is invalid */
00260     logprint (LOG_ERROR,
00261               "line %d: syntax error, unrecognized character: `%s'\n",
00262               netlist_lineno, netlist_text);
00263     return InvalidCharacter;
00264   }
00265 
00266 <EQN>[-+*/%(),^:\"\[\]\?] { /* return operators unchanged */
00267     return netlist_text[0];
00268   }
00269 
00270 <EQN>">=" { return GreaterOrEqual; }
00271 <EQN>"<=" { return LessOrEqual; }
00272 <EQN>"!=" { return NotEqual; }
00273 <EQN>"==" { return Equal; }
00274 <EQN>"&&" { return And; }
00275 <EQN>"||" { return Or; }
00276 <EQN>"<"  { return Less; }
00277 <EQN>">"  { return Greater; }
00278 <EQN>"!"  { return Not; }
00279 
00280 <EQN>[,;] { /* special tokens for vectors / matrices */
00281     return netlist_text[0];
00282   }
00283 
00284 <EQN>{UCREAL} { /* identify unsigned real float */
00285     char * endptr = NULL;
00286     netlist_lval.d = strtod (netlist_text, &endptr);
00287     netlist_lval.d = netlist_evaluate_scale (netlist_lval.d, endptr);
00288     return REAL;
00289   }
00290 <EQN>{UCIMAG} { /* identify unsigned imaginary float */
00291     if (netlist_text[0] == 'i' || netlist_text[0] == 'j')
00292       netlist_text[0] = (netlist_text[1] == '\0') ? '1' : '0';
00293     else
00294       netlist_text[1] = '0';
00295     char * endptr = NULL;
00296     netlist_lval.d = strtod (netlist_text, &endptr);
00297     netlist_lval.d = netlist_evaluate_scale (netlist_lval.d, endptr);
00298     return IMAG;
00299   }
00300 <EQN>{ID} { /* identify identifier */
00301     netlist_lval.ident = strdup (netlist_text);
00302     return Identifier;
00303   }
00304 <EQN>{CHR} {
00305     netlist_lval.chr = netlist_text[1];
00306     return Character;
00307   }
00308 <EQN>{STR} {
00309     netlist_lval.str = strdup (&netlist_text[1]);
00310     netlist_lval.str[strlen (netlist_lval.str) - 1] = '\0';
00311     return STRING;
00312   }
00313 <EQN>\r?\n { /* detect end of line */ BEGIN(INITIAL); return Eol; }
00314 
00315 <EQN>. { /* any other character in invalid */
00316     logprint (LOG_ERROR,
00317               "line %d: syntax error, unrecognized character: `%s'\n",
00318               netlist_lineno, netlist_text);
00319     return InvalidCharacter;
00320   }
00321 
00322 %%