/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2022 Mikolaj Wielgus * Copyright (C) 2022-2023 KiCad Developers, see AUTHORS.txt for contributors. * * This program 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 3 * of the License, or (at your option) any later version. * * This program 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 program; if not, you may find one here: * https://www.gnu.org/licenses/gpl-3.0.html * or you may search the http://www.gnu.org website for the version 3 license, * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef SPICE_GRAMMAR_H #define SPICE_GRAMMAR_H #include namespace SPICE_GRAMMAR { using namespace SIM_VALUE_GRAMMAR; struct garbage : plus> {}; struct leaders : plus> {}; struct trailers : plus> {}; struct garbageOrEolf : sor {}; // 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. // Ngspice supports '//' for comments. struct eolfCommentStart : sor, string<'/', '/'>> {}; struct eolfComment : seq> {}; struct commentLine : seq, one<'*'>, until> {}; struct newline : seq, not_at>> {}; struct backslashContinuation : seq, opt, eolf> {}; struct commentBackslashContinuation : seq, not_at, opt, eolf>, any>, string<'\\', '\\'>, opt, eolf>> {}; struct plusContinuation : seq, star, opt, one<'+'>> {}; struct continuation : seq, sor, opt> {}; // Token separator. struct sep : sor, garbage> {}; struct modelName : plus, any> {}; struct dotModelType : sor>, plus, any>> {}; struct vectorExpr : seq, star>, one<']'>> {}; struct bracedExpr : seq, star>>, one<'}'>> {}; // Ngspice has some heuristic logic to allow + and - in tokens. We replicate that here. struct tokenStart : seq>, opt>>, one<'e', 'E'>, opt>>>> {}; struct token : seq, not_at, not_one<' ', '\t', '=', '(', ')', ',', ';'>>> {}; // Param names cannot be `token` because LTspice models contain spurious values without // parameter names, which we need to skip, and because tokens can include a very limited // subset of un-braced expressions struct param : identifier {}; struct paramValue : sor {}; struct paramValuePair : seq {}; struct paramValuePairs : list {}; struct dotModelAko : seq, if_must, opt, modelName, opt, opt, opt, newline>> {}; struct dotModel : seq, if_must, opt, newline>> {}; struct dotSubcktParamValuePair : seq`s match Ngspice's // behavior. star, opt, one<'='>, opt, star, paramValue> {}; struct dotSubcktParamValuePairs : list {}; struct dotSubcktParams : seq>, dotSubcktParamValuePairs> {}; struct dotSubcktPinName : seq, plus, any>> {}; struct dotSubcktPinSequence : list {}; struct dotSubcktEnd : seq> {}; struct spiceUnit; struct dotSubckt : seq, if_must, opt, opt, newline, until>> {}; struct modelUnit : seq, sor> {}; // Intentionally no if_must<>. struct dotControl : seq, TAO_PEGTL_ISTRING( ".control" ), until, until> {}; struct dotTitleTitle : star, any> {}; // Intentionally no if_must<>. struct dotTitle : seq, TAO_PEGTL_ISTRING( ".title" ), sep, dotTitleTitle, newline> {}; struct dotIncludePathWithoutQuotes : star> {}; struct dotIncludePathWithoutApostrophes : star> {}; struct dotIncludePath : star, any> {}; // Intentionally no if_must<>. struct dotInclude : seq, TAO_PEGTL_ISTRING( ".inc" ), star, any>, sep, sor, dotIncludePathWithoutQuotes, one<'\"'>>, seq, dotIncludePathWithoutApostrophes, one<'\''>>, dotIncludePath>, opt, newline> {}; // Intentionally no if_must<>. struct dotLine : seq, one<'.'>, until> {}; // Intentionally no if_must<>. struct kLine : seq, one<'K'>, until, one<'L'>, until, one<'L'>, until, until> {}; struct unknownLine : seq, any>, until> {}; struct spiceUnit : sor {}; struct spiceUnitGrammar : must {}; struct spiceSource : star {}; struct spiceSourceGrammar : must {}; template inline constexpr const char* errorMessage = nullptr; template <> inline constexpr auto errorMessage = "expected newline"; template <> inline constexpr auto errorMessage = "expected token separator (one or more whitespace, parenthesis, '=', ',', or line continuation)"; template <> inline constexpr auto errorMessage> = ""; template <> inline constexpr auto errorMessage = "expected model name"; template <> inline constexpr auto errorMessage = "expected model type"; template <> inline constexpr auto errorMessage> = ""; template <> inline constexpr auto errorMessage> = ""; template <> inline constexpr auto errorMessage> = ""; template <> inline constexpr auto errorMessage> = ""; template <> inline constexpr auto errorMessage> = "expected (possibly empty) sequence of Spice lines followed by an .ends line"; template <> inline constexpr auto errorMessage = "expected Spice directive, item, subcircuit definitions, or empty or commented-out line"; template <> inline constexpr auto errorMessage = "expected zero or more Spice directives, items, subcircuit definitions, or empty or commented-out lines"; // We create a custom PEGTL control to modify the parser error messages. struct error { template static constexpr bool raise_on_failure = false; template static constexpr auto message = errorMessage; }; template using control = must_if::control; } #endif // SPICE_GRAMMAR_H