/* -*-c-*- */ %{ /* * scan_netlist.l - scanner for the Qucs netlist * * Copyright (C) 2003-2009 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 defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-register" #endif #if HAVE_CONFIG_H # include #endif #include #include #include #include #ifdef __MINGW32__ #include #endif #ifdef HAVE_UNISTD_H #include #endif #include "logging.h" #include "equation.h" #include "check_netlist.h" #include "parse_netlist.hpp" #if !HAVE_STRCHR # define strchr index # define strrchr rindex #endif using namespace qucs; static double netlist_evaluate_scale (double val, char * scale) { double factor = 1.0; while (isspace (scale[0])) scale++; switch (scale[0]) { case 'E': factor = 1e+18; break; case 'P': factor = 1e+15; break; case 'T': factor = 1e+12; break; case 'G': factor = 1e+09; break; case 'M': factor = 1e+06; break; case 'k': factor = 1e+03; break; case 'm': if (scale[1] == 'i' && scale[2] == 'l') factor = 2.54e-5; else factor = 1e-03; break; case 'u': factor = 1e-06; break; case 'n': factor = 1e-09; break; case 'p': factor = 1e-12; break; case 'f': if (scale[1] == 't') factor = 0.3048; else factor = 1e-15; break; case 'a': factor = 1e-18; break; case 'd': if (scale[1] == 'B') { val = std::pow (10.0, val / 10.0); if (scale[2] == 'm') factor = 1e-03; else if (scale[2] == 'u') factor = 1e-06; } break; case 'i': if (scale[1] == 'n') factor = 2.54e-2; break; case 'y': if (scale[1] == 'd') factor = 0.9144; break; } return val * factor; } %} WS [ \t\n\r] SIMPLEID [a-zA-Z_][a-zA-Z0-9_]* POSTID "."[a-zA-Z0-9_]+ ID {SIMPLEID}{POSTID}* NODE {SIMPLEID}\!? FILE "{"[^\t\n\r\}]+"}" CHR "'"[^\n\r\']{1}"'" STR "'"[^\n\r\']*"'" DIGIT [0-9] EXPONENT [Ee][+-]?{DIGIT}+ PFX1 ("E"|"P"|"T"|"G"|"M"|"k"|"m"|"u"|"n"|"p"|"f"|"a") PFX2 ("mil"|"in"|"ft"|"yd") PFX3 ("dBu"|"dBm"|"dB") PFX ({PFX1}|{PFX3}) UNT ("Ohm"|"S"|"s"|"K"|"H"|"F"|"Hz"|"V"|"A"|"W"|"m") EXCEPT ("mm"|{PFX2}) SU ({PFX}|{UNT}|{PFX}{UNT}|{EXCEPT}) SPACE [ \t] RINT [+-]?{DIGIT}+ IINT [+-]?[ij]{1}{DIGIT}* RFLOAT1 [+-]?{DIGIT}+{EXPONENT} RFLOAT2 [+-]?{DIGIT}*"."{DIGIT}+({EXPONENT})? IFLOAT1 [+-]?[ij]{1}{DIGIT}+{EXPONENT} IFLOAT2 [+-]?[ij]{1}{DIGIT}*"."{DIGIT}+({EXPONENT})? CREAL ({RFLOAT1}|{RFLOAT2}|{RINT}) CIMAG ({IFLOAT1}|{IFLOAT2}|{IINT}) COMPLEX {CREAL}{CIMAG} URINT {DIGIT}+ UIINT [ij]{1}{DIGIT}* URFLOAT1 {DIGIT}+{EXPONENT} URFLOAT2 {DIGIT}*"."{DIGIT}+({EXPONENT})? UIFLOAT1 [ij]{1}{DIGIT}+{EXPONENT} UIFLOAT2 [ij]{1}{DIGIT}*"."{DIGIT}+({EXPONENT})? UCREAL ({URFLOAT1}|{URFLOAT2}|{URINT})({SPACE})*({PFX})? UCIMAG ({UIFLOAT1}|{UIFLOAT2}|{UIINT})({SPACE})*({PFX})? UCOMPLEX {UCREAL}{UCIMAG} %x COMMENT STR EQN %option yylineno noyywrap nounput noinput prefix="netlist_" %% {SU} { /* identify scale and/or unit */ netlist_lval.str = strdup (netlist_text); return ScaleOrUnit; } "Eqn" { /* special equation case */ BEGIN(EQN); return Eqn; } "."{SPACE}*"Def"{SPACE}*":" { /* subcircuit definition begins */ return DefSub; } "."{SPACE}*"Def"{SPACE}*":"{SPACE}*"End" { /* subcircuit definition ends */ return EndSub; } {ID} { /* identify identifier */ netlist_lval.ident = strdup (netlist_text); return Identifier; } {NODE} { /* identify node identifier */ netlist_lval.ident = strdup (netlist_text); return Identifier; } {FILE} { /* identify file reference */ char * p = strrchr (netlist_text, '}'); if (!p) { return InvalidCharacter; } //size_t len = (size_t)p - (size_t)&netlist_text[1]; //netlist_lval.ident = strndup (&netlist_text[1], len); *p = '\0'; netlist_lval.ident = strdup (&netlist_text[1]); return Identifier; } {CREAL} { /* identify (signed) real float */ netlist_lval.d = strtod (netlist_text, NULL); return REAL; } {CIMAG} { /* identify (signed) imaginary float */ if (netlist_text[0] == 'i' || netlist_text[0] == 'j') netlist_text[0] = (netlist_text[1] == '\0') ? '1' : '0'; else netlist_text[1] = '0'; netlist_lval.d = strtod (netlist_text, NULL); return IMAG; } {COMPLEX} { /* identify complete (signed) complex number */ int i = 0; while (netlist_text[i] != 'i' && netlist_text[i] != 'j') i++; netlist_text[i] = netlist_text[i - 1]; netlist_text[i - 1] = '\0'; netlist_lval.c.r = strtod (netlist_text, NULL); netlist_lval.c.i = strtod (&netlist_text[i], NULL); return COMPLEX; } {ID}{SPACE}*=[^=] { /* identify 'identifier =' assign */ int len = netlist_leng - 3; while (isspace (netlist_text[len])) len--; netlist_lval.ident = (char *) calloc (len + 2, 1); memcpy (netlist_lval.ident, netlist_text, len + 1); yyless (netlist_leng - 1); /* push back last character */ return Assign; } "[" { /* special token for the value list */ return '['; } "]" { /* special token for the value list */ return ']'; } ";" { /* special token for the value list */ return ';'; } "." { /* pass the '.' to the parser */ return '.'; } ":" { /* pass the ':' to the parser */ return ':'; } "=" { /* pass the '=' to the parser */ return '='; } \r?\n { /* detect end of line */ return Eol; } {SPACE}|\\\r?\n /* skip spaces and the trailing '\' */ "#" { /* leave these characters */ BEGIN(COMMENT); } \" { /* string constant starts here */ BEGIN(STR); return '"'; } . { /* any other character in invalid */ logprint (LOG_ERROR, "line %d: syntax error, unrecognized character: `%s'\n", netlist_lineno, netlist_text); return InvalidCharacter; } . { /* skip any character in here */ } \r?\n { BEGIN(INITIAL); /* skipping ends here */ } \" { /* string constant ends here */ BEGIN(INITIAL); return '"'; } \r?\n { /* string in a single line only */ logprint (LOG_ERROR, "line %d: syntax error, unterminated string constant\n", netlist_lineno); return Eol; } {SPACE} /* skip spaces */ . { /* any other character is invalid */ logprint (LOG_ERROR, "line %d: syntax error, unrecognized character: `%s'\n", netlist_lineno, netlist_text); return InvalidCharacter; } [-+*/%(),^:\"\[\]\?] { /* return operators unchanged */ return netlist_text[0]; } ">=" { return GreaterOrEqual; } "<=" { return LessOrEqual; } "!=" { return NotEqual; } "==" { return Equal; } "&&" { return And; } "||" { return Or; } "<" { return Less; } ">" { return Greater; } "!" { return Not; } [,;] { /* special tokens for vectors / matrices */ return netlist_text[0]; } {UCREAL} { /* identify unsigned real float */ char * endptr = NULL; netlist_lval.d = strtod (netlist_text, &endptr); netlist_lval.d = netlist_evaluate_scale (netlist_lval.d, endptr); return REAL; } {UCIMAG} { /* identify unsigned imaginary float */ if (netlist_text[0] == 'i' || netlist_text[0] == 'j') netlist_text[0] = (netlist_text[1] == '\0') ? '1' : '0'; else netlist_text[1] = '0'; char * endptr = NULL; netlist_lval.d = strtod (netlist_text, &endptr); netlist_lval.d = netlist_evaluate_scale (netlist_lval.d, endptr); return IMAG; } {ID} { /* identify identifier */ netlist_lval.ident = strdup (netlist_text); return Identifier; } {CHR} { netlist_lval.chr = netlist_text[1]; return Character; } {STR} { netlist_lval.str = strdup (&netlist_text[1]); netlist_lval.str[strlen (netlist_lval.str) - 1] = '\0'; return STRING; } \r?\n { /* detect end of line */ BEGIN(INITIAL); return Eol; } . { /* any other character in invalid */ logprint (LOG_ERROR, "line %d: syntax error, unrecognized character: `%s'\n", netlist_lineno, netlist_text); return InvalidCharacter; } %%