2022-12-04 15:01:19 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2023 Roberto Fernandez Bautista <roberto.fer.bau@gmail.com>
|
|
|
|
* Copyright (C) 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, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
#include "cadstar_parts_lib_parser.h"
|
|
|
|
#include "cadstar_parts_lib_grammar.h"
|
|
|
|
|
|
|
|
#include <fmt.h>
|
|
|
|
#include <set>
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
using namespace CADSTAR_PARTS_LIB;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Struture that will be populated by the PEGTL parser
|
|
|
|
*/
|
|
|
|
struct CADSTAR_LIB_PARSER_STATE
|
|
|
|
{
|
2023-02-23 21:41:32 +00:00
|
|
|
std::string m_CurrentString;
|
|
|
|
std::string m_CurrentAttrName;
|
2023-03-12 00:18:22 +00:00
|
|
|
std::string m_CurrentSignalName;
|
2023-02-23 21:41:32 +00:00
|
|
|
long m_CurrentLong = 0;
|
2023-03-12 15:12:03 +00:00
|
|
|
CADSTAR_PART_NODE m_CurrentNode;
|
|
|
|
long m_CurrentNodeIdx = 0;
|
2023-02-23 21:41:32 +00:00
|
|
|
std::vector<long> m_CurrentPinEquivalenceGroup;
|
|
|
|
std::set<std::string> m_CurrentElementsParsed;
|
|
|
|
bool m_ReadOnly = false;
|
|
|
|
CADSTAR_SWAP_GROUP m_CurrentSwapGroup;
|
|
|
|
CADSTAR_PART_PIN m_CurrentPin;
|
|
|
|
std::vector<CADSTAR_PART_PIN> m_CurrentPinList;
|
|
|
|
CADSTAR_PART_SYMBOL_ENTRY m_CurrentSymbol;
|
|
|
|
CADSTAR_PART_ENTRY m_CurrentPart;
|
|
|
|
|
2022-12-04 15:01:19 +00:00
|
|
|
CADSTAR_PARTS_LIB_MODEL m_ParsedModel;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Default action: Do nothing
|
|
|
|
template <typename Rule>
|
|
|
|
struct CADSTAR_LIB_PARSER_ACTION : tao::pegtl::nothing<Rule>
|
|
|
|
{
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
long helperStringToLong( std::string aString )
|
|
|
|
{
|
|
|
|
std::stringstream ss( aString );
|
|
|
|
long number;
|
|
|
|
ss >> number;
|
|
|
|
return number;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// CONTENT TO NUMBER ACTIONS:
|
|
|
|
// Take the current content string, convert it to a long and store it in StateVariable
|
|
|
|
//
|
|
|
|
#define DEFINE_CONTENT_TO_NUMBER_ACTION( Rule, StateVariable ) \
|
|
|
|
template <> \
|
|
|
|
struct CADSTAR_LIB_PARSER_ACTION<Rule> \
|
|
|
|
{ \
|
|
|
|
template <typename ActionInput> \
|
|
|
|
static void apply( const ActionInput& in, CADSTAR_LIB_PARSER_STATE& s ) \
|
|
|
|
{ \
|
|
|
|
assert( s.m_CurrentString == "" && s.m_CurrentAttrName == "" ); \
|
|
|
|
s.StateVariable = helperStringToLong( in.string() ); \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
DEFINE_CONTENT_TO_NUMBER_ACTION( CURRENT_FORMAT_NUMBER, m_ParsedModel.m_FormatNumber );
|
|
|
|
DEFINE_CONTENT_TO_NUMBER_ACTION( PINNUM, m_CurrentLong );
|
|
|
|
DEFINE_CONTENT_TO_NUMBER_ACTION( MAX_PIN_COUNT, m_CurrentPart.m_MaxPinCount );
|
2023-02-23 21:41:32 +00:00
|
|
|
DEFINE_CONTENT_TO_NUMBER_ACTION( PIN_IDENTIFIER, m_CurrentPin.m_Identifier );
|
|
|
|
DEFINE_CONTENT_TO_NUMBER_ACTION( PIN_LOADING, m_CurrentPin.m_Loading );
|
2023-03-12 15:12:03 +00:00
|
|
|
DEFINE_CONTENT_TO_NUMBER_ACTION( HIERARCHY_NODE_INDEX, m_CurrentLong );
|
2023-02-23 21:41:32 +00:00
|
|
|
|
2022-12-04 15:01:19 +00:00
|
|
|
|
|
|
|
// unfortunately the one below needs to be defined separately
|
|
|
|
template <>
|
|
|
|
struct CADSTAR_LIB_PARSER_ACTION<EQUIVALENT_PIN>
|
|
|
|
{
|
|
|
|
template <typename ActionInput>
|
|
|
|
static void apply( const ActionInput& in, CADSTAR_LIB_PARSER_STATE& s )
|
|
|
|
{
|
|
|
|
assert( s.m_CurrentString == "" && s.m_CurrentAttrName == "" );
|
|
|
|
s.m_CurrentPinEquivalenceGroup.push_back( helperStringToLong( in.string() ) );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// CONTENT TO CURRENT STRING ACTIONS:
|
|
|
|
// Take the current content string, store it in the state current string
|
|
|
|
//
|
|
|
|
#define DEFINE_CONTENT_TO_STRING_ACTION( Rule ) \
|
|
|
|
template <> \
|
|
|
|
struct CADSTAR_LIB_PARSER_ACTION<Rule> \
|
|
|
|
{ \
|
|
|
|
template <typename ActionInput> \
|
|
|
|
static void apply( const ActionInput& in, CADSTAR_LIB_PARSER_STATE& s ) \
|
|
|
|
{ \
|
|
|
|
assert( s.m_CurrentString == "" && s.m_CurrentAttrName == "" ); \
|
|
|
|
s.m_CurrentString = in.string(); \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
DEFINE_CONTENT_TO_STRING_ACTION( PINNAME );
|
|
|
|
|
|
|
|
//
|
|
|
|
// STRING REPLACEMENT ACTIONS:
|
|
|
|
// Take the current string in the parser state and store it in StateVariable
|
|
|
|
//
|
|
|
|
#define DEFINE_STRING_ACTION( Rule, StateVariable ) \
|
|
|
|
template <> \
|
|
|
|
struct CADSTAR_LIB_PARSER_ACTION<Rule> \
|
|
|
|
{ \
|
|
|
|
/* @todo : convert to use apply0 to improve performance( once fully tested ) */ \
|
|
|
|
template <typename ActionInput> \
|
|
|
|
static void apply( const ActionInput& in, CADSTAR_LIB_PARSER_STATE& s ) \
|
|
|
|
{ \
|
|
|
|
assert( in.string().size() >= s.m_CurrentString.size() ); \
|
|
|
|
s.StateVariable = s.m_CurrentString; \
|
|
|
|
s.m_CurrentString = ""; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
|
|
|
|
DEFINE_STRING_ACTION( PART_NAME, m_CurrentPart.m_Name );
|
|
|
|
DEFINE_STRING_ACTION( PART_VERSION, m_CurrentPart.m_Version );
|
|
|
|
DEFINE_STRING_ACTION( PART_NUMBER, m_CurrentPart.m_Number );
|
|
|
|
DEFINE_STRING_ACTION( PART_DESCRIPTION, m_CurrentPart.m_Description );
|
|
|
|
DEFINE_STRING_ACTION( PCB_COMPONENT, m_CurrentPart.m_Pcb_component );
|
|
|
|
DEFINE_STRING_ACTION( PCB_ALTERNATE, m_CurrentPart.m_Pcb_alternate );
|
|
|
|
DEFINE_STRING_ACTION( VALUE, m_CurrentPart.m_Value );
|
|
|
|
DEFINE_STRING_ACTION( DEFINITION_NAME, m_CurrentPart.m_PartDefinitionName );
|
|
|
|
DEFINE_STRING_ACTION( STEM, m_CurrentPart.m_ComponentStem );
|
|
|
|
DEFINE_STRING_ACTION( SYM_ELEMENT_NAME, m_CurrentSwapGroup.m_Name );
|
|
|
|
DEFINE_STRING_ACTION( USER_PART_ATTRIBUTE_NAME, m_CurrentAttrName );
|
|
|
|
DEFINE_STRING_ACTION( ATTRIBUTE_NAME, m_CurrentAttrName );
|
2023-03-12 00:18:22 +00:00
|
|
|
DEFINE_STRING_ACTION( PIN_SIGNAL_NAME, m_CurrentSignalName );
|
2022-12-04 15:01:19 +00:00
|
|
|
DEFINE_STRING_ACTION( ACCEPTANCE_PART_NAME, m_CurrentPart.m_AcceptancePartName );
|
|
|
|
DEFINE_STRING_ACTION( ACCEPTANCE_TEXT, m_CurrentPart.m_AcceptanceText );
|
|
|
|
DEFINE_STRING_ACTION( SPICE_PART_NAME, m_CurrentPart.m_SpicePartName );
|
2023-03-07 21:38:15 +00:00
|
|
|
DEFINE_STRING_ACTION( SPICE_MODEL, m_CurrentPart.m_SpiceModel );
|
2023-02-23 21:41:32 +00:00
|
|
|
DEFINE_STRING_ACTION( SCH_NAME, m_CurrentSymbol.m_SymbolName );
|
|
|
|
DEFINE_STRING_ACTION( SCH_ALTERNATE, m_CurrentSymbol.m_SymbolAlternateName );
|
2022-12-04 15:01:19 +00:00
|
|
|
|
|
|
|
|
|
|
|
// STRING SEGMENT action
|
|
|
|
// Any strings we match, append to the current state string (the state string gets
|
|
|
|
// reset after we extract the string to store somewhere else).
|
|
|
|
// The reason we append is because in the fileformat, there can be line continuations,
|
|
|
|
// which we don't want to have in the final string - saves post-processing.
|
|
|
|
template <typename... EXCLUSION_RULES>
|
|
|
|
struct CADSTAR_LIB_PARSER_ACTION<STR_SEGMENT_EXCLUDING<EXCLUSION_RULES...>>
|
|
|
|
{
|
|
|
|
template <typename ActionInput>
|
|
|
|
static void apply( const ActionInput& in, CADSTAR_LIB_PARSER_STATE& s )
|
|
|
|
{
|
|
|
|
s.m_CurrentString += in.string();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-03-12 15:12:03 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// HIERARCHY actions
|
|
|
|
//
|
|
|
|
template <>
|
|
|
|
struct CADSTAR_LIB_PARSER_ACTION<HIERARCHY_NODE_ENTRY>
|
|
|
|
{
|
|
|
|
static void apply0( CADSTAR_LIB_PARSER_STATE& s )
|
|
|
|
{
|
|
|
|
assert( s.m_CurrentString == "" && s.m_CurrentAttrName == "" );
|
|
|
|
s.m_ParsedModel.m_HierarchyNodes.insert(
|
|
|
|
{ s.m_CurrentNodeIdx, std::move( s.m_CurrentNode ) } );
|
|
|
|
s.m_CurrentNode = CADSTAR_PART_NODE();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
struct CADSTAR_LIB_PARSER_ACTION<HIERARCHY_CURRENT_NODE>
|
|
|
|
{
|
|
|
|
static void apply0( CADSTAR_LIB_PARSER_STATE& s )
|
|
|
|
{
|
|
|
|
assert( s.m_CurrentString == "" && s.m_CurrentAttrName == "" );
|
|
|
|
s.m_CurrentNodeIdx = s.m_CurrentLong;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
struct CADSTAR_LIB_PARSER_ACTION<HIERARCHY_PARENT_NODE>
|
|
|
|
{
|
|
|
|
static void apply0( CADSTAR_LIB_PARSER_STATE& s )
|
|
|
|
{
|
|
|
|
assert( s.m_CurrentString == "" && s.m_CurrentAttrName == "" );
|
|
|
|
s.m_CurrentNode.m_ParentNodeIdx = s.m_CurrentLong;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
struct CADSTAR_LIB_PARSER_ACTION<HIERARCHY_NODE_NAME>
|
|
|
|
{
|
|
|
|
static void apply0( CADSTAR_LIB_PARSER_STATE& s )
|
|
|
|
{
|
|
|
|
assert( s.m_CurrentAttrName == "" );
|
|
|
|
s.m_CurrentNode.m_Name = std::move( s.m_CurrentString );
|
|
|
|
s.m_CurrentString = "";
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
struct CADSTAR_LIB_PARSER_ACTION<HIERARCHY_PART_NAME>
|
|
|
|
{
|
|
|
|
static void apply0( CADSTAR_LIB_PARSER_STATE& s )
|
|
|
|
{
|
|
|
|
assert( s.m_CurrentAttrName == "" );
|
|
|
|
s.m_CurrentNode.m_PartNames.push_back( std::move( s.m_CurrentString ) );
|
|
|
|
s.m_CurrentString = "";
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2022-12-04 15:01:19 +00:00
|
|
|
// PART_ENTRY action
|
|
|
|
// We just push the part to the vector of parts in our state
|
|
|
|
template <>
|
|
|
|
struct CADSTAR_LIB_PARSER_ACTION<PART_ENTRY>
|
|
|
|
{
|
|
|
|
static void apply0( CADSTAR_LIB_PARSER_STATE& s )
|
|
|
|
{
|
|
|
|
assert( s.m_CurrentString == "" && s.m_CurrentAttrName == "" );
|
|
|
|
//Finish the entry
|
|
|
|
s.m_ParsedModel.m_PartEntries.push_back( s.m_CurrentPart );
|
|
|
|
s.m_CurrentPart = CADSTAR_PART_ENTRY();
|
|
|
|
s.m_CurrentElementsParsed.clear();
|
|
|
|
// Todo-we could add progress reporting here?
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
struct CADSTAR_LIB_PARSER_ACTION<READONLY>
|
|
|
|
{
|
|
|
|
static void apply0( CADSTAR_LIB_PARSER_STATE& s )
|
|
|
|
{
|
|
|
|
assert( s.m_CurrentString == "" && s.m_CurrentAttrName == "" );
|
|
|
|
s.m_ReadOnly = true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// SINGLE RULE ACTIONS:
|
|
|
|
// Make sure that this rule is only matched once per part and throw a parse error
|
|
|
|
// when this is not the case.
|
|
|
|
//
|
|
|
|
#define DECLARE_SINGLE_MATCH_RULE( Rule, ExtraCode ) \
|
|
|
|
template <> \
|
|
|
|
struct CADSTAR_LIB_PARSER_ACTION<Rule> \
|
|
|
|
{ \
|
|
|
|
template <typename ActionInput> \
|
|
|
|
static void apply( const ActionInput& in, CADSTAR_LIB_PARSER_STATE& s ) \
|
|
|
|
{ \
|
|
|
|
assert( s.m_CurrentString == "" && s.m_CurrentAttrName == "" ); \
|
|
|
|
\
|
|
|
|
if( s.m_CurrentElementsParsed.count( #Rule ) ) \
|
|
|
|
{ \
|
|
|
|
throw parse_error( #Rule \
|
|
|
|
" was already defined for this part!", \
|
|
|
|
in ); \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
s.m_CurrentElementsParsed.insert( #Rule ); \
|
|
|
|
ExtraCode; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
|
|
|
|
DECLARE_SINGLE_MATCH_RULE( PART_VALUE, );
|
|
|
|
DECLARE_SINGLE_MATCH_RULE( DFN_LINE, );
|
|
|
|
DECLARE_SINGLE_MATCH_RULE( NGS_LINE, s.m_CurrentPart.m_GateSwappingAllowed = false );
|
|
|
|
DECLARE_SINGLE_MATCH_RULE( NPV_LINE, s.m_CurrentPart.m_PinsVisible = false );
|
|
|
|
DECLARE_SINGLE_MATCH_RULE( STM_LINE, );
|
|
|
|
DECLARE_SINGLE_MATCH_RULE( MXP_LINE, );
|
|
|
|
DECLARE_SINGLE_MATCH_RULE( SPI_LINE, );
|
|
|
|
DECLARE_SINGLE_MATCH_RULE( PAC_LINE, );
|
|
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
struct CADSTAR_LIB_PARSER_ACTION<PINNAME_ENTRY>
|
|
|
|
{
|
|
|
|
static void apply0( CADSTAR_LIB_PARSER_STATE& s )
|
|
|
|
{
|
|
|
|
assert( s.m_CurrentAttrName == "" );
|
|
|
|
// m_CurrentLong should have been parsed as part of the PINNUM action
|
|
|
|
// m_CurrentString should have been parsed as part of the PINNAME action
|
|
|
|
s.m_CurrentPart.m_PinNamesMap.insert( { s.m_CurrentLong, s.m_CurrentString } );
|
|
|
|
s.m_CurrentString = "";
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
struct CADSTAR_LIB_PARSER_ACTION<PINLABEL_ENTRY>
|
|
|
|
{
|
|
|
|
static void apply0( CADSTAR_LIB_PARSER_STATE& s )
|
|
|
|
{
|
|
|
|
assert( s.m_CurrentAttrName == "" );
|
|
|
|
// m_CurrentLong should have been parsed as part of the PINNUM action
|
|
|
|
// m_CurrentString should have been parsed as part of the PINLABEL action
|
|
|
|
s.m_CurrentPart.m_PinLabelsMap.insert( { s.m_CurrentLong, s.m_CurrentString } );
|
|
|
|
s.m_CurrentString = "";
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//
|
|
|
|
// PIN EQUIVALENCE GROUP ACTIONS:
|
|
|
|
// Take the current m_CurrentPinEquivalenceGroup in the parser state and store it in StateVariable
|
|
|
|
// then clear m_CurrentPinEquivalenceGroup.
|
|
|
|
// Note that m_CurrentPinEquivalenceGroup should have been parsed as part of EQUIVALENT_PIN action
|
|
|
|
//
|
|
|
|
#define DEFINE_PIN_GROUP_ACTION( Rule, StateVariable ) \
|
|
|
|
template <> \
|
|
|
|
struct CADSTAR_LIB_PARSER_ACTION<Rule> \
|
|
|
|
{ \
|
|
|
|
static void apply0( CADSTAR_LIB_PARSER_STATE& s ) \
|
|
|
|
{ \
|
|
|
|
assert( s.m_CurrentString == "" && s.m_CurrentAttrName == "" ); \
|
|
|
|
s.StateVariable.push_back( s.m_CurrentPinEquivalenceGroup ); \
|
|
|
|
s.m_CurrentPinEquivalenceGroup.clear(); \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
|
|
|
|
DEFINE_PIN_GROUP_ACTION( EQUIVALENT_PINS_GROUP, m_CurrentPart.m_PinEquivalences );
|
|
|
|
DEFINE_PIN_GROUP_ACTION( INTERNAL_SWAP_GATE, m_CurrentSwapGroup.m_Gates );
|
|
|
|
DEFINE_PIN_GROUP_ACTION( EXTERNAL_SWAP_GATE, m_CurrentSwapGroup.m_Gates );
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// SWAP GROUP ACTIONS:
|
|
|
|
// Take the current m_CurrentSwapGroup in the parser state and store it in StateVariable
|
|
|
|
// then reset m_CurrentSwapGroup.
|
|
|
|
//
|
|
|
|
#define DEFINE_SWAP_GROUP_ACTION( Rule, StateVariable ) \
|
|
|
|
template <> \
|
|
|
|
struct CADSTAR_LIB_PARSER_ACTION<Rule> \
|
|
|
|
{ \
|
|
|
|
static void apply0( CADSTAR_LIB_PARSER_STATE& s ) \
|
|
|
|
{ \
|
|
|
|
assert( s.m_CurrentString == "" && s.m_CurrentAttrName == "" ); \
|
|
|
|
s.StateVariable.push_back( s.m_CurrentSwapGroup ); \
|
|
|
|
s.m_CurrentSwapGroup = CADSTAR_SWAP_GROUP(); \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
|
|
|
|
DEFINE_SWAP_GROUP_ACTION( INTERNAL_SWAP_GROUP, m_CurrentPart.m_InternalSwapGroup );
|
|
|
|
DEFINE_SWAP_GROUP_ACTION( EXTERNAL_SWAP_GROUP, m_CurrentPart.m_ExternalSwapGroup );
|
|
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
struct CADSTAR_LIB_PARSER_ACTION<USER_PART_ATTRIBUTE>
|
|
|
|
{
|
|
|
|
template <typename ActionInput>
|
|
|
|
static void apply( const ActionInput& in, CADSTAR_LIB_PARSER_STATE& s )
|
|
|
|
{
|
2023-02-23 21:41:32 +00:00
|
|
|
// The format allows user defined "part" attrbutes, but the ones listed here are in-built
|
|
|
|
// with special meaning
|
|
|
|
static const std::set<std::string> reservedWordsStarLines = { "VALUE", "PNM", "PLB", "EQU",
|
|
|
|
"SYM", "INT", "EXT", "DFN",
|
|
|
|
"NGS", "NPV", "STM", "MXP",
|
|
|
|
"SPI", "PAC" };
|
|
|
|
|
2022-12-04 15:01:19 +00:00
|
|
|
if( s.m_CurrentPart.m_UserAttributes.count( s.m_CurrentAttrName ) )
|
|
|
|
{
|
|
|
|
throw parse_error( fmt::format( "Duplicate attribute name '{}'", s.m_CurrentAttrName ),
|
|
|
|
in );
|
|
|
|
}
|
|
|
|
|
2023-02-23 21:41:32 +00:00
|
|
|
if( reservedWordsStarLines.count( s.m_CurrentAttrName ) )
|
2022-12-04 15:01:19 +00:00
|
|
|
{
|
2023-02-23 21:41:32 +00:00
|
|
|
throw parse_error(
|
|
|
|
fmt::format(
|
|
|
|
"Invalid use of in-built attribute name '{}'. Either the attribute "
|
|
|
|
"was already defined for this part or it has an unexpected syntax.",
|
|
|
|
s.m_CurrentAttrName ),
|
|
|
|
in );
|
2022-12-04 15:01:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
s.m_CurrentPart.m_UserAttributes.insert( { s.m_CurrentAttrName, s.m_CurrentString } );
|
|
|
|
s.m_CurrentAttrName = "";
|
|
|
|
s.m_CurrentString = "";
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
#define DEFINE_ATTRIBUTE_ACTION( Rule, StateVariable ) \
|
|
|
|
template <> \
|
|
|
|
struct CADSTAR_LIB_PARSER_ACTION<Rule> \
|
|
|
|
{ \
|
|
|
|
template <typename ActionInput> \
|
|
|
|
static void apply( const ActionInput& in, CADSTAR_LIB_PARSER_STATE& s ) \
|
|
|
|
{ \
|
|
|
|
if( s.StateVariable.count( s.m_CurrentAttrName ) ) \
|
|
|
|
{ \
|
|
|
|
throw parse_error( \
|
|
|
|
fmt::format( "Duplicate attribute name '{}'", s.m_CurrentAttrName ), \
|
|
|
|
in ); \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
CADSTAR_ATTRIBUTE_VALUE val; \
|
|
|
|
val.m_ReadOnly = s.m_ReadOnly; \
|
|
|
|
val.m_Value = s.m_CurrentString; \
|
|
|
|
\
|
|
|
|
s.StateVariable.insert( { s.m_CurrentAttrName, val } ); \
|
|
|
|
s.m_CurrentAttrName = ""; \
|
|
|
|
s.m_CurrentString = ""; \
|
|
|
|
s.m_ReadOnly = false; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
|
|
|
|
DEFINE_ATTRIBUTE_ACTION( SCM_ATTRIBUTE, m_CurrentPart.m_SchAttributes );
|
|
|
|
DEFINE_ATTRIBUTE_ACTION( PCB_ATTRIBUTE, m_CurrentPart.m_PcbAttributes );
|
|
|
|
DEFINE_ATTRIBUTE_ACTION( PART_ATTRIBUTE, m_CurrentPart.m_PartAttributes );
|
|
|
|
DEFINE_ATTRIBUTE_ACTION( SCH_PCB_ATTRIBUTE, m_CurrentPart.m_SchAndPcbAttributes );
|
|
|
|
|
2023-02-23 21:41:32 +00:00
|
|
|
|
|
|
|
template <>
|
|
|
|
struct CADSTAR_LIB_PARSER_ACTION<SYMBOL_ENTRY>
|
|
|
|
{
|
|
|
|
static void apply0( CADSTAR_LIB_PARSER_STATE& s )
|
|
|
|
{
|
|
|
|
s.m_CurrentSymbol.m_Pins.swap( s.m_CurrentPinList );
|
|
|
|
s.m_CurrentPart.m_Symbols.push_back( std::move( s.m_CurrentSymbol ) );
|
|
|
|
s.m_CurrentSymbol = CADSTAR_PART_SYMBOL_ENTRY();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
struct CADSTAR_LIB_PARSER_ACTION<PIN_ENTRY>
|
|
|
|
{
|
|
|
|
static void apply0( CADSTAR_LIB_PARSER_STATE& s )
|
|
|
|
{
|
|
|
|
s.m_CurrentPinList.push_back( std::move( s.m_CurrentPin ) );
|
|
|
|
s.m_CurrentPin = CADSTAR_PART_PIN();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
struct CADSTAR_LIB_PARSER_ACTION<HIDDEN_PIN_ENTRY>
|
|
|
|
{
|
|
|
|
static void apply0( CADSTAR_LIB_PARSER_STATE& s )
|
|
|
|
{
|
2023-03-12 00:18:22 +00:00
|
|
|
s.m_CurrentPart.m_HiddenPins.insert(
|
|
|
|
{ std::move( s.m_CurrentSignalName ), std::move( s.m_CurrentPinList ) } );
|
2023-02-23 21:41:32 +00:00
|
|
|
s.m_CurrentPinList.clear();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
struct CADSTAR_LIB_PARSER_ACTION<PIN_POSITION>
|
|
|
|
{
|
|
|
|
template <typename ActionInput>
|
|
|
|
static void apply( const ActionInput& in, CADSTAR_LIB_PARSER_STATE& s )
|
|
|
|
{
|
|
|
|
s.m_CurrentPin.m_Position = CADSTAR_PIN_POSITION( helperStringToLong( in.string() ) );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
struct CADSTAR_LIB_PARSER_ACTION<PIN_TYPE>
|
|
|
|
{
|
|
|
|
template <typename ActionInput>
|
|
|
|
static void apply( const ActionInput& in, CADSTAR_LIB_PARSER_STATE& s )
|
|
|
|
{
|
|
|
|
// The format allows user defined "part" attrbutes, but the ones listed here are in-built
|
|
|
|
// with special meaning
|
|
|
|
static const std::map<std::string, CADSTAR_PIN_TYPE> tokenToPinType = {
|
|
|
|
{ "U", CADSTAR_PIN_TYPE::UNCOMMITTED },
|
|
|
|
{ "I", CADSTAR_PIN_TYPE::INPUT },
|
|
|
|
{ "N", CADSTAR_PIN_TYPE::OUTPUT_NOT_OR },
|
|
|
|
{ "Y", CADSTAR_PIN_TYPE::OUTPUT_OR },
|
|
|
|
{ "Q", CADSTAR_PIN_TYPE::OUTPUT_NOT_NORM_OR },
|
|
|
|
{ "P", CADSTAR_PIN_TYPE::POWER },
|
|
|
|
{ "G", CADSTAR_PIN_TYPE::GROUND },
|
|
|
|
{ "T", CADSTAR_PIN_TYPE::TRISTATE_BIDIR },
|
|
|
|
{ "TI", CADSTAR_PIN_TYPE::TRISTATE_INPUT },
|
|
|
|
{ "TD", CADSTAR_PIN_TYPE::TRISTATE_DRIVER }
|
|
|
|
};
|
|
|
|
|
|
|
|
if( !tokenToPinType.count( in.string() ) )
|
|
|
|
throw parse_error( fmt::format( "Unexpected pin type '{}'", in.string() ), in );
|
|
|
|
|
|
|
|
s.m_CurrentPin.m_Type = tokenToPinType.at( in.string() );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2022-12-04 15:01:19 +00:00
|
|
|
template <typename INPUT_TYPE>
|
|
|
|
bool checkHeaderHelper( INPUT_TYPE& aInput )
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if( !parse<VALID_HEADER>( aInput ) )
|
|
|
|
return false;
|
|
|
|
}
|
2023-04-11 08:53:35 +00:00
|
|
|
catch( const parse_error& )
|
2022-12-04 15:01:19 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CADSTAR_PARTS_LIB_PARSER::CheckContentHeader( const std::string& aSource ) const
|
|
|
|
{
|
|
|
|
string_input in( aSource, "from_content" );
|
|
|
|
return checkHeaderHelper( in );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CADSTAR_PARTS_LIB_PARSER::CheckFileHeader( const std::filesystem::path& aPath ) const
|
|
|
|
{
|
|
|
|
file_input in( aPath );
|
|
|
|
return checkHeaderHelper( in );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<typename INPUT_TYPE>
|
|
|
|
CADSTAR_PARTS_LIB_MODEL readCadstarHelper( INPUT_TYPE& aInput )
|
|
|
|
{
|
|
|
|
CADSTAR_LIB_PARSER_STATE s;
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// Todo: We could reserve space for the partEntries vector
|
|
|
|
// to improve performance? E.g.:
|
|
|
|
// s.m_ParsedModel.m_PartEntries.reserve( expectedNumParts );
|
|
|
|
|
|
|
|
if( !parse<GRAMMAR, CADSTAR_LIB_PARSER_ACTION>( aInput, s ) )
|
|
|
|
printf( "Some error occurred!\n" );
|
|
|
|
}
|
|
|
|
catch( const parse_error& e )
|
|
|
|
{
|
|
|
|
const auto p = e.positions().front();
|
|
|
|
std::cerr << "Error at line " << p.line << ", column " << p.column << std::endl
|
|
|
|
<< aInput.line_at( p ) << std::endl
|
|
|
|
<< std::setw( p.column ) << '^' << std::endl
|
|
|
|
<< e.message() << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
return s.m_ParsedModel;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CADSTAR_PARTS_LIB_MODEL CADSTAR_PARTS_LIB_PARSER::ReadContent( const std::string& aSource ) const
|
|
|
|
{
|
|
|
|
string_input in( aSource, "from_content" );
|
|
|
|
return readCadstarHelper( in );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CADSTAR_PARTS_LIB_MODEL
|
|
|
|
CADSTAR_PARTS_LIB_PARSER::ReadFile( const std::filesystem::path& aPath ) const
|
|
|
|
{
|
|
|
|
file_input in( aPath );
|
|
|
|
return readCadstarHelper( in );
|
|
|
|
}
|