Add PEGTL playground tool
This commit is contained in:
parent
bce1fd337b
commit
80c8cfbbda
|
@ -137,6 +137,10 @@ option( KICAD_DRC_PROTO
|
|||
"Build the DRC prototype QA tool"
|
||||
OFF )
|
||||
|
||||
option( KICAD_BUILD_PEGTL_DEBUG_TOOL
|
||||
"Build the PEGTL parser debugging/playground QA tool"
|
||||
OFF )
|
||||
|
||||
option( KICAD_BUILD_PNS_DEBUG_TOOL
|
||||
"Build the P&S debugging/playground QA tool"
|
||||
OFF )
|
||||
|
|
|
@ -30,6 +30,10 @@ endif()
|
|||
add_subdirectory( common_tools )
|
||||
add_subdirectory( pcbnew_tools )
|
||||
|
||||
if( KICAD_BUILD_PEGTL_DEBUG_TOOL )
|
||||
add_subdirectory( pegtl )
|
||||
endif()
|
||||
|
||||
if( KICAD_BUILD_PNS_DEBUG_TOOL )
|
||||
add_subdirectory( pns )
|
||||
endif()
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
#
|
||||
# This program source code file is part of KiCad, a free EDA CAD application.
|
||||
#
|
||||
# Copyright (C) 2022 Roberto Fernandez Bautista <roberto.fer.bau@gmail.com>
|
||||
# Copyright (C) 2022 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 2
|
||||
# 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:
|
||||
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
# or you may search the http://www.gnu.org website for the version 2 license,
|
||||
# or you may write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
|
||||
add_executable( test_pegtl
|
||||
main.cpp
|
||||
)
|
||||
|
||||
add_dependencies( test_pegtl pegtl )
|
||||
|
||||
include_directories( BEFORE ${INC_BEFORE} )
|
||||
include_directories(
|
||||
${CMAKE_SOURCE_DIR}
|
||||
${CMAKE_SOURCE_DIR}/thirdparty/pegtl/
|
||||
${INC_AFTER}
|
||||
)
|
||||
|
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2022 Roberto Fernandez Bautista <roberto.fer.bau@gmail.com>
|
||||
* Copyright (C) 2022 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/>.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* A program to test a PEGTL grammar
|
||||
*/
|
||||
|
||||
#include <pegtl.hpp>
|
||||
#include <pegtl/contrib/analyze.hpp>
|
||||
#include <pegtl/contrib/parse_tree.hpp>
|
||||
#include <pegtl/contrib/parse_tree_to_dot.hpp>
|
||||
#include <pegtl/contrib/trace.hpp>
|
||||
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
|
||||
using namespace tao::pegtl;
|
||||
|
||||
//-------------------- Grammar definition ----------------------------------------------------
|
||||
|
||||
struct LINE_CONTINUATION : seq<one<'&'>, eol>{}; ///< Any text can span multiple lines using '&'
|
||||
|
||||
/**
|
||||
* String segment( no line continuation ), with exclusion rules
|
||||
*/
|
||||
template <typename... EXCLUSION_RULES>
|
||||
struct STR_SEGMENT_EXCLUDING : plus<not_at<sor<eolf, LINE_CONTINUATION, EXCLUSION_RULES...>>, any>{};
|
||||
|
||||
/**
|
||||
* String with optional line continuation and exclusion rules
|
||||
*/
|
||||
template <typename... EXCLUSION_RULES>
|
||||
struct STRING_EXCLUDING : plus<STR_SEGMENT_EXCLUDING<EXCLUSION_RULES...>, opt<LINE_CONTINUATION>> {};
|
||||
|
||||
/**
|
||||
* Control character with or without preceding whitespace
|
||||
*/
|
||||
template <char... CHAR_TO_FIND>
|
||||
struct spaced_ch : seq<star<space>, one<CHAR_TO_FIND...>>{};
|
||||
|
||||
// Definition of "Format"
|
||||
// # Format <current format number>
|
||||
struct CURRENT_FORMAT_NUMBER : plus<digit> {};
|
||||
struct FORMAT : seq<bol, TAO_PEGTL_STRING( "# FORMAT" ), star<space>, CURRENT_FORMAT_NUMBER>{};
|
||||
|
||||
|
||||
// Definition of part
|
||||
//.<Part name>_[(<Part number>)][:<Part version>][;<Description>]
|
||||
// string filters:
|
||||
struct PART_NAME_FILTER : sor<spaced_ch<'('>, spaced_ch<':'>, spaced_ch<';'>>{};
|
||||
struct PART_NUMBER_FILTER : one<')'>{};
|
||||
struct PART_VERSION_FILTER : spaced_ch<';'>{};
|
||||
|
||||
// part elements:
|
||||
struct PART_NAME : STRING_EXCLUDING<PART_NAME_FILTER> {};
|
||||
struct PART_NUMBER : STRING_EXCLUDING<PART_NUMBER_FILTER> {};
|
||||
struct PART_VERSION : STRING_EXCLUDING<PART_VERSION_FILTER> {};
|
||||
struct PART_DESCRIPTION : STRING_EXCLUDING<> {};
|
||||
|
||||
// the part itself
|
||||
struct PART : seq
|
||||
<
|
||||
bol,
|
||||
one<'.'>,
|
||||
PART_NAME,
|
||||
opt<seq<spaced_ch<'('>, PART_NUMBER, one<')'>>>,
|
||||
opt<seq<spaced_ch<':'>, PART_VERSION>>,
|
||||
opt<seq<spaced_ch<';'>, PART_DESCRIPTION>>
|
||||
>
|
||||
{};
|
||||
|
||||
|
||||
struct UNMATCHED_CONTENT : STRING_EXCLUDING<FORMAT, PART> {}; //@todo remove once parser is complete
|
||||
|
||||
|
||||
struct GRAMMAR : plus
|
||||
<
|
||||
sor<FORMAT, PART, UNMATCHED_CONTENT>,
|
||||
opt<eolf>
|
||||
>
|
||||
{};
|
||||
|
||||
//--------------------------Simple selector definition -----------------------------
|
||||
// disable all parse nodes by default
|
||||
template< typename PEGTL_RULE > struct SIMPLE_SELECTOR : std::false_type {};
|
||||
// enable only nodes that match certain rules:
|
||||
template<> struct SIMPLE_SELECTOR< STR_SEGMENT_EXCLUDING< PART_NAME_FILTER > > : std::true_type {};
|
||||
template<> struct SIMPLE_SELECTOR< STR_SEGMENT_EXCLUDING< PART_NUMBER_FILTER > > : std::true_type {};
|
||||
template<> struct SIMPLE_SELECTOR< STR_SEGMENT_EXCLUDING< PART_VERSION_FILTER > > : std::true_type {};
|
||||
template<> struct SIMPLE_SELECTOR< STR_SEGMENT_EXCLUDING<> > : std::true_type {};
|
||||
template<> struct SIMPLE_SELECTOR< CURRENT_FORMAT_NUMBER > : std::true_type {};
|
||||
template<> struct SIMPLE_SELECTOR< FORMAT > : std::true_type {};
|
||||
template<> struct SIMPLE_SELECTOR< PART > : std::true_type {};
|
||||
template<> struct SIMPLE_SELECTOR< PART_NAME > : std::true_type {};
|
||||
template<> struct SIMPLE_SELECTOR< PART_NUMBER > : std::true_type {};
|
||||
template<> struct SIMPLE_SELECTOR< PART_VERSION > : std::true_type {};
|
||||
template<> struct SIMPLE_SELECTOR< PART_DESCRIPTION > : std::true_type {};
|
||||
template<> struct SIMPLE_SELECTOR< UNMATCHED_CONTENT > : std::true_type {}; //@todo remove
|
||||
|
||||
|
||||
//--------------------------Complex selector definition -----------------------------
|
||||
// Helper function to clean up the tree
|
||||
struct FOLD_CONTENT : parse_tree::apply<FOLD_CONTENT>
|
||||
{
|
||||
template <typename Node>
|
||||
static void transform( Node& n )
|
||||
{
|
||||
if( n->children.size() == 1 )
|
||||
{
|
||||
n->children.pop_back();
|
||||
}
|
||||
else if( n->children.size() != 0 )
|
||||
{
|
||||
n->remove_content();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename PEGTL_RULE>
|
||||
using COMPLEX_SELECTOR = parse_tree::selector<
|
||||
PEGTL_RULE,
|
||||
parse_tree::store_content::on<
|
||||
STR_SEGMENT_EXCLUDING< PART_NAME_FILTER >,
|
||||
STR_SEGMENT_EXCLUDING< PART_NUMBER_FILTER >,
|
||||
STR_SEGMENT_EXCLUDING< PART_VERSION_FILTER >,
|
||||
STR_SEGMENT_EXCLUDING<>,
|
||||
CURRENT_FORMAT_NUMBER,
|
||||
UNMATCHED_CONTENT //@todo remove when parser complete. For debugging only
|
||||
>,
|
||||
parse_tree::remove_content::on<
|
||||
FORMAT,
|
||||
PART
|
||||
>,
|
||||
parse_tree::apply< FOLD_CONTENT >::on<
|
||||
PART_NAME,
|
||||
PART_NUMBER,
|
||||
PART_VERSION,
|
||||
PART_DESCRIPTION
|
||||
>
|
||||
>;
|
||||
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
// .\test_pegtl.exe complex my_file.lib | dot -Tsvg > output.svg; .\output.svg
|
||||
|
||||
if( argc != 3 )
|
||||
{
|
||||
printf( "usage: %s <complex|simple> <filename>", argv[0] );
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string chosen_selector = argv[1];
|
||||
std::filesystem::path filepath( argv[2] );
|
||||
|
||||
file_input in( filepath );
|
||||
|
||||
const std::size_t issues = tao::pegtl::analyze<GRAMMAR>();
|
||||
|
||||
if( issues > 0 )
|
||||
{
|
||||
std::cout << "\n***ERROR***: " << issues << " issues found in the grammar!\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::unique_ptr<parse_tree::node> root;
|
||||
|
||||
if( chosen_selector == "complex" )
|
||||
{
|
||||
root = parse_tree::parse<GRAMMAR, COMPLEX_SELECTOR>( in );
|
||||
}
|
||||
else if( chosen_selector == "simple" )
|
||||
{
|
||||
root = parse_tree::parse<GRAMMAR, SIMPLE_SELECTOR>( in );
|
||||
}
|
||||
else
|
||||
{
|
||||
printf( "Invalid selector '%s' requested. Valid values are: complex or simple. \n",
|
||||
argv[1] );
|
||||
printf( "usage: %s <complex|simple> <filename>\n", argv[0] );
|
||||
}
|
||||
|
||||
|
||||
if( root )
|
||||
{
|
||||
parse_tree::print_dot( std::cout, *root );
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "\n***ERROR***: No root tree node!\n";
|
||||
|
||||
// lets print out the trace for debugging
|
||||
standard_trace<GRAMMAR>( in );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue