Sim: Spice grammar fixes

- Fix parsing .model lines with model names containingnon-alphanumeric
  characters like - and _,
- Fix parsing libraries in which EOF is not preceded by a newline.

Fixes https://gitlab.com/kicad/code/kicad/issues/12394
This commit is contained in:
Mikolaj Wielgus 2022-09-12 03:59:42 +02:00
parent d95847ae79
commit 0e0d1a34f5
6 changed files with 31 additions and 27 deletions

View File

@ -198,7 +198,7 @@ void NETLIST_EXPORTER_SPICE::ReadDirectives( unsigned aNetlistOptions )
else else
continue; continue;
tao::pegtl::string_input<> in( ( text + "\n" ).ToUTF8(), "from_content" ); tao::pegtl::string_input<> in( text.ToUTF8(), "from_content" );
std::unique_ptr<tao::pegtl::parse_tree::node> root; std::unique_ptr<tao::pegtl::parse_tree::node> root;
try try

View File

@ -36,7 +36,7 @@ namespace SIM_LIBRARY_SPICE_PARSER
// TODO: unknownLine is already handled in spiceUnit. // TODO: unknownLine is already handled in spiceUnit.
struct library : spiceSource {}; struct library : spiceSource {};
struct libraryGrammar : must<library, tao::pegtl::eof> {}; struct libraryGrammar : must<library> {};
template <typename Rule> struct librarySelector : std::false_type {}; template <typename Rule> struct librarySelector : std::false_type {};

View File

@ -886,9 +886,9 @@ void SIM_MODEL::ReadSpiceCode( const wxString& aSpiceCode )
if( !SetParamFromSpiceCode( paramName, subnode->string() ) ) if( !SetParamFromSpiceCode( paramName, subnode->string() ) )
{ {
THROW_IO_ERROR( wxString::Format( THROW_IO_ERROR( wxString::Format(
_( "Failed to set parameter '%s' to '%s'" ), _( "Failed to set parameter '%s' to '%s'" ),
paramName, paramName,
subnode->string() ) ); subnode->string() ) );
} }
} }
else else

View File

@ -40,39 +40,39 @@ namespace SPICE_GRAMMAR
// NOTE: In Ngspice, a '$' opening a comment must be preceded by ' ', ',', or '\t'. We don't // NOTE: In Ngspice, a '$' opening a comment must be preceded by ' ', ',', or '\t'. We don't
// implement that here - this may cause problems in the future. // implement that here - this may cause problems in the future.
// Ngspice supports '//' for comments. // Ngspice supports '//' for comments.
struct eolCommentStart : sor<one<';', '$'>, struct eolfCommentStart : sor<one<';', '$'>,
string<'/', '/'>> {}; string<'/', '/'>> {};
struct eolComment : seq<eolCommentStart, struct eolfComment : seq<eolfCommentStart,
until<eol>> {}; until<eolf>> {};
struct commentLine : seq<opt<garbage>, struct commentLine : seq<opt<garbage>,
one<'*'>, one<'*'>,
until<eol>> {}; until<eolf>> {};
struct newline : seq<sor<eol, struct newline : seq<sor<eolf,
eolComment>, eolfComment>,
not_at<one<'+'>>> {}; not_at<one<'+'>>> {};
struct backslashContinuation : seq<string<'\\', '\\'>, struct backslashContinuation : seq<string<'\\', '\\'>,
opt<trailers>, opt<trailers>,
eol> {}; eolf> {};
struct commentBackslashContinuation : seq<eolCommentStart, struct commentBackslashContinuation : seq<eolfCommentStart,
seq<star<not_at<eol>, seq<star<not_at<eolf>,
not_at<string<'\\', '\\'>, not_at<string<'\\', '\\'>,
opt<trailers>, opt<trailers>,
eol>, eolf>,
any>, any>,
string<'\\', '\\'>, string<'\\', '\\'>,
opt<trailers>, opt<trailers>,
eol>> {}; eolf>> {};
struct plusContinuation : seq<sor<eol, struct plusContinuation : seq<sor<eolf,
eolComment>, eolfComment>,
star<commentLine>, star<commentLine>,
opt<leaders>, opt<leaders>,
one<'+'>> {}; one<'+'>> {};
@ -96,7 +96,7 @@ namespace SPICE_GRAMMAR
opt<one<'+', '-'>>>>> {}; opt<one<'+', '-'>>>>> {};
struct token : seq<tokenStart, struct token : seq<tokenStart,
star<not_at<eol>, star<not_at<eolf>,
not_at<backslashContinuation>, not_at<backslashContinuation>,
not_one<' ', '\t', '=', '(', ')', ',', '+', '-', '*', '/', '^', ';'>>> not_one<' ', '\t', '=', '(', ')', ',', '+', '-', '*', '/', '^', ';'>>>
{}; {};
@ -111,8 +111,9 @@ namespace SPICE_GRAMMAR
struct paramValuePairs : seq<opt<paramValuePair>, struct paramValuePairs : seq<opt<paramValuePair>,
star<sep, star<sep,
paramValuePair>> {}; paramValuePair>> {};
struct modelName : star<sor<alnum, struct modelName : plus<not_at<garbage>, any> {};
one<'!', '#', '$', '%', '[', ']', '_'>>> {}; /*sor<alnum,
one<'!', '#', '$', '%', '[', ']', '_'>>> {};*/
/*seq<alpha, /*seq<alpha,
star<sor<alnum, star<sor<alnum,
one<'!', '#', '$', '%', '[', ']', '_'>>>> {};*/ one<'!', '#', '$', '%', '[', ']', '_'>>>> {};*/
@ -175,7 +176,8 @@ namespace SPICE_GRAMMAR
dotSubcktParams>, dotSubcktParams>,
opt<sep>, opt<sep>,
newline, newline,
until<dotSubcktEnd, spiceUnit>> {}; until<dotSubcktEnd,
spiceUnit>> {};
struct modelUnit : sor<dotModel, struct modelUnit : sor<dotModel,
@ -227,7 +229,7 @@ namespace SPICE_GRAMMAR
one<'.'>, one<'.'>,
until<newline>> {}; until<newline>> {};
struct unknownLine : until<newline> {}; struct unknownLine : seq<plus<not_at<newline>, any>, until<newline>> {};
struct spiceUnit : sor<modelUnit, struct spiceUnit : sor<modelUnit,
@ -236,12 +238,13 @@ namespace SPICE_GRAMMAR
dotInclude, dotInclude,
dotLine, dotLine,
kLine, kLine,
eol, // Empty line. This is necessary to terminate on EOF.
unknownLine> {}; unknownLine> {};
struct spiceUnitGrammar : must<spiceUnit, tao::pegtl::eof> {}; struct spiceUnitGrammar : must<spiceUnit> {};
struct spiceSource : star<spiceUnit> {}; struct spiceSource : star<spiceUnit> {};
struct spiceSourceGrammar : must<spiceSource, tao::pegtl::eof> {}; struct spiceSourceGrammar : must<spiceSource> {};
} }
#endif // SPICE_GRAMMAR_H #endif // SPICE_GRAMMAR_H

View File

@ -99,7 +99,8 @@
+ N = 6.6G ; + N = 6.6G ;
* All valid combinations of + - signs. * All valid combinations of + - signs.
.model D18 D * Non-alphanumeric characters in model name.
.model D<>/?:\|[]!@#$%^&-_18 D
+ N -1.1, MJ +2.2, JS -3.3e-3, IBV +4.4e+4, CJ0 5.5e-5, BV 6.6e+6 + N -1.1, MJ +2.2, JS -3.3e-3, IBV +4.4e+4, CJ0 5.5e-5, BV 6.6e+6
* Multiple empty-line continuations. * Multiple empty-line continuations.

View File

@ -203,7 +203,7 @@ BOOST_AUTO_TEST_CASE( Diodes )
break; break;
case 18: case 18:
BOOST_CHECK_EQUAL( modelName, "D18" ); BOOST_CHECK_EQUAL( modelName, "D<>/?:\\|[]!@#$%^&-_18" );
BOOST_CHECK_EQUAL( model.FindParam( "n" )->value->ToString(), "-1.1" ); BOOST_CHECK_EQUAL( model.FindParam( "n" )->value->ToString(), "-1.1" );
BOOST_CHECK_EQUAL( model.FindParam( "m_" )->value->ToString(), "2.2" ); BOOST_CHECK_EQUAL( model.FindParam( "m_" )->value->ToString(), "2.2" );
BOOST_CHECK_EQUAL( model.FindParam( "is" )->value->ToString(), "-3.3m" ); BOOST_CHECK_EQUAL( model.FindParam( "is" )->value->ToString(), "-3.3m" );