kicad/qa/common_tools/tools/sexpr_parser/sexpr_parse.cpp

161 lines
4.4 KiB
C++

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019 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
*/
/**
* @file
* Utility tool for parsing S-Expression data with the SEXPR class
* for benchmarking, testing, etc.
*/
#include <sexpr/sexpr_parser.h>
#include <qa_utils/utility_registry.h>
#include <common.h>
#include <profile.h>
#include <wx/cmdline.h>
#include <fstream>
#include <iostream>
class QA_SEXPR_PARSER
{
public:
QA_SEXPR_PARSER( bool aVerbose ) : m_verbose( aVerbose )
{
}
bool Parse( std::istream& aStream )
{
// Don't let the parser handle stream reading - we don't want to
// see how long the disk IO takes. Read to memory first (event the
// biggest files will fit in)
const std::string sexpr_str( std::istreambuf_iterator<char>( aStream ), {} );
PROF_COUNTER timer;
// Perform the parse
std::unique_ptr<SEXPR::SEXPR> sexpr( m_parser.Parse( sexpr_str ) );
if( m_verbose )
std::cout << "S-Expression Parsing took " << timer.msecs() << "ms" << std::endl;
return sexpr != nullptr;
}
private:
bool m_verbose;
SEXPR::PARSER m_parser;
};
static const wxCmdLineEntryDesc g_cmdLineDesc[] = {
{
wxCMD_LINE_SWITCH,
"h",
"help",
_( "displays help on the command line parameters" ).mb_str(),
wxCMD_LINE_VAL_NONE,
wxCMD_LINE_OPTION_HELP,
},
{
wxCMD_LINE_SWITCH,
"v",
"verbose",
_( "print parsing information" ).mb_str(),
},
{
wxCMD_LINE_PARAM,
nullptr,
nullptr,
_( "input file" ).mb_str(),
wxCMD_LINE_VAL_STRING,
wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE,
},
{ wxCMD_LINE_NONE }
};
enum PARSER_RET_CODES
{
PARSE_FAILED = KI_TEST::RET_CODES::TOOL_SPECIFIC,
};
int sexpr_parser_func( int argc, char* argv[] )
{
wxCmdLineParser cl_parser( argc, argv );
cl_parser.SetDesc( g_cmdLineDesc );
cl_parser.AddUsageText( _( "Tests parsing of S-Expression files" ) );
int cmd_parsed_ok = cl_parser.Parse();
if( cmd_parsed_ok != 0 )
{
// Help and invalid input both stop here
return ( cmd_parsed_ok == -1 ) ? KI_TEST::RET_CODES::OK : KI_TEST::RET_CODES::BAD_CMDLINE;
}
const auto file_count = cl_parser.GetParamCount();
const bool verbose = cl_parser.Found( "verbose" );
QA_SEXPR_PARSER qa_parser( verbose );
bool ok = true;
if( file_count == 0 )
{
// Parse the file provided on stdin - used by AFL to drive the
// program
qa_parser.Parse( std::cin );
}
else
{
// Parse 'n' files given on the command line
// (this is useful for input minimisation (e.g. afl-tmin) as
// well as manual testing
for( unsigned i = 0; i < file_count; i++ )
{
const auto filename = cl_parser.GetParam( i ).ToStdString();
if( verbose )
std::cout << "Parsing: " << filename << std::endl;
std::ifstream fin;
fin.open( filename );
ok = ok && qa_parser.Parse( fin );
}
}
if( !ok )
return PARSER_RET_CODES::PARSE_FAILED;
return KI_TEST::RET_CODES::OK;
}
static bool registered = UTILITY_REGISTRY::Register( {
"sexpr_parser",
"Benchmark s-expression parsing",
sexpr_parser_func,
} );