Implement "KiCad s-epression" support for boost::property_tree's ptree, the 8
bit string version of property_tree. The ram resident structure of the ptree is mostly compatible with one created using the xml_parser from boost::property_tree, with slight differences in the way atoms are stored. The result is you can use Format() to convert from xml to s-expression, but not the other way around. You can write a simple s-expression beautifier in just a few lines of code. The main value however is the s-expression parser, i.e. Scan(), which is an alternative to crafting a custom recursive descent parser for a particular grammar. The tipping point depends on whether you want to read only a small portion of a much larger document. If so, then using the ptree will likely be a "faster to code" route. Documentation on how to navigate a ptree can be found on the boost website and there are a number of examples in the pcbnew/eagle_plugin.cpp file in this project. Powerful path navigation support makes it easy to extract a subset of a ptree.
This commit is contained in:
parent
7bb04c8f63
commit
6bf3d7cdc3
|
@ -71,6 +71,7 @@ set(COMMON_SRCS
|
||||||
netlist_keywords.cpp
|
netlist_keywords.cpp
|
||||||
newstroke_font.cpp
|
newstroke_font.cpp
|
||||||
projet_config.cpp
|
projet_config.cpp
|
||||||
|
ptree.cpp
|
||||||
richio.cpp
|
richio.cpp
|
||||||
selcolor.cpp
|
selcolor.cpp
|
||||||
string.cpp
|
string.cpp
|
||||||
|
|
|
@ -0,0 +1,226 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||||
|
* Copyright (C) 2013 KiCad Developers, see CHANGELOG.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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <boost/property_tree/ptree.hpp>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <macros.h>
|
||||||
|
#include <ptree.h>
|
||||||
|
|
||||||
|
typedef PTREE::const_iterator CITER;
|
||||||
|
typedef PTREE::iterator ITER;
|
||||||
|
|
||||||
|
#if defined(DEBUG)
|
||||||
|
#define D(x) x
|
||||||
|
#else
|
||||||
|
#define D(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CTL_OMIT_NL (1<<0)
|
||||||
|
#define CTL_IN_ATTRS (1<<1)
|
||||||
|
|
||||||
|
|
||||||
|
//-----<Scan>------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function scanList
|
||||||
|
* reads a sexpr list from the input stream into a new node with key
|
||||||
|
* aLexer->CurText().
|
||||||
|
*/
|
||||||
|
inline void scanList( PTREE* aTree, DSNLEXER* aLexer )
|
||||||
|
{
|
||||||
|
assert( aLexer->CurTok() == DSN_LEFT );
|
||||||
|
|
||||||
|
int tok = aLexer->NextTok();
|
||||||
|
|
||||||
|
const char* key = aLexer->CurText();
|
||||||
|
|
||||||
|
//D(printf( "%s: '%s'\n", __func__, key );)
|
||||||
|
|
||||||
|
PTREE* list = &aTree->push_back( PTREE::value_type( key, PTREE() ) )->second;
|
||||||
|
|
||||||
|
if( tok != DSN_RIGHT )
|
||||||
|
{
|
||||||
|
while( ( tok = aLexer->NextTok() ) != DSN_RIGHT )
|
||||||
|
{
|
||||||
|
if( tok == DSN_EOF )
|
||||||
|
aLexer->Unexpected( DSN_EOF );
|
||||||
|
|
||||||
|
Scan( list, aLexer );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void scanAtom( PTREE* aTree, DSNLEXER* aLexer )
|
||||||
|
{
|
||||||
|
const char* key = aLexer->CurText();
|
||||||
|
|
||||||
|
//D(printf( "%s: '%s'\n", __func__, key );)
|
||||||
|
|
||||||
|
aTree->push_back( PTREE::value_type( key, PTREE() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Scan( PTREE* aTree, DSNLEXER* aLexer ) throw( IO_ERROR )
|
||||||
|
{
|
||||||
|
int tok = aLexer->CurTok();
|
||||||
|
|
||||||
|
// conditionally read first token.
|
||||||
|
if( tok == DSN_NONE )
|
||||||
|
tok = aLexer->NextTok();
|
||||||
|
|
||||||
|
if( tok == DSN_EOF )
|
||||||
|
{
|
||||||
|
aLexer->Unexpected( DSN_EOF );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( tok == DSN_LEFT )
|
||||||
|
{
|
||||||
|
scanList( aTree, aLexer );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scanAtom( aTree, aLexer );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----<Format>------------------------------------------------------------------
|
||||||
|
|
||||||
|
inline bool isAtom( CPTREE& aTree )
|
||||||
|
{
|
||||||
|
return aTree.size()==0 && aTree.data().size()==0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool isLast( CPTREE& aTree, CITER it )
|
||||||
|
{
|
||||||
|
CITER next = it;
|
||||||
|
++next;
|
||||||
|
return next == aTree.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline CITER next( CITER it )
|
||||||
|
{
|
||||||
|
CITER n = it;
|
||||||
|
return ++n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void formatNode( OUTPUTFORMATTER* out, int aNestLevel, int aCtl,
|
||||||
|
const std::string& aKey, CPTREE& aTree ) throw( IO_ERROR );
|
||||||
|
|
||||||
|
|
||||||
|
static void formatList( OUTPUTFORMATTER* out, int aNestLevel, int aCtl, CPTREE& aTree )
|
||||||
|
throw( IO_ERROR )
|
||||||
|
{
|
||||||
|
for( CITER it = aTree.begin(); it != aTree.end(); ++it )
|
||||||
|
{
|
||||||
|
// Processing a tree which was read in with xml_parser?
|
||||||
|
if( it->first == "<xmlattr>" )
|
||||||
|
{
|
||||||
|
formatList( out, aNestLevel, aCtl | CTL_IN_ATTRS, it->second );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ctl = 0;
|
||||||
|
|
||||||
|
#if defined(DEBUG)
|
||||||
|
if( it->first == "field" )
|
||||||
|
{
|
||||||
|
int breakhere = 1;
|
||||||
|
(void) breakhere;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( isLast( aTree, it ) ) // is "it" the last one?
|
||||||
|
{
|
||||||
|
//if( !( aCtl & CTL_IN_ATTRS ) )
|
||||||
|
ctl = CTL_OMIT_NL;
|
||||||
|
}
|
||||||
|
else if( isAtom( next( it )->second ) )
|
||||||
|
{
|
||||||
|
/* if( !( aCtl & CTL_IN_ATTRS ) ) */
|
||||||
|
ctl = CTL_OMIT_NL;
|
||||||
|
}
|
||||||
|
|
||||||
|
formatNode( out, aNestLevel+1, ctl, it->first, it->second );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void formatNode( OUTPUTFORMATTER* out, int aNestLevel, int aCtl,
|
||||||
|
const std::string& aKey, CPTREE& aTree )
|
||||||
|
throw( IO_ERROR )
|
||||||
|
{
|
||||||
|
if( !isAtom( aTree ) ) // is a list, not an atom
|
||||||
|
{
|
||||||
|
int ctl = CTL_OMIT_NL;
|
||||||
|
|
||||||
|
// aTree is list and its first child is a list
|
||||||
|
if( aTree.size() && !isAtom( aTree.begin()->second ) && !aTree.data().size() )
|
||||||
|
ctl = 0;
|
||||||
|
|
||||||
|
out->Print( aNestLevel, "(%s%s", out->Quotes( aKey ).c_str(), ctl & CTL_OMIT_NL ? "" : "\n" );
|
||||||
|
|
||||||
|
if( aTree.data().size() ) // only xml typically uses "data()", not sexpr.
|
||||||
|
{
|
||||||
|
out->Print( 0, " %s%s",
|
||||||
|
out->Quotes( aTree.data() ).c_str(),
|
||||||
|
aTree.size() ? "\n" : ""
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
formatList( out, aNestLevel, aCtl, aTree );
|
||||||
|
|
||||||
|
out->Print( 0, ")%s", aCtl & CTL_OMIT_NL ? "" : "\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
else // is an atom, not a list
|
||||||
|
{
|
||||||
|
const char* atom = out->Quotes( aKey ).c_str();
|
||||||
|
out->Print( 0, " %s", atom );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Format( OUTPUTFORMATTER* out, int aNestLevel, int aCtl, CPTREE& aTree ) throw( IO_ERROR )
|
||||||
|
{
|
||||||
|
if( aTree.size() == 1 && !aTree.data().size() )
|
||||||
|
{
|
||||||
|
// The topmost node is basically only a container for the document root.
|
||||||
|
// It anchors the paths which traverse the tree deeper.
|
||||||
|
CITER it = aTree.begin();
|
||||||
|
formatNode( out, aNestLevel, aCtl, it->first, it->second );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This is not expected, neither for sexpr nor xml.
|
||||||
|
formatNode( out, aNestLevel, aCtl, "", aTree );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
#ifndef PTREE_H_
|
||||||
|
#define PTREE_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||||
|
* Copyright (C) 2013 KiCad Developers, see CHANGELOG.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
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Implement "KiCad s-epression" support for boost::property_tree's ptree, the 8
|
||||||
|
bit string version of property_tree. The ram resident structure of the ptree is
|
||||||
|
mostly compatible with one created using the xml_parser from
|
||||||
|
boost::property_tree, with slight differences in the way atoms are stored. The
|
||||||
|
result is you can use Format() to convert from xml to s-expression, but not the
|
||||||
|
other way around. You can write a simple s-expression beautifier in just a few
|
||||||
|
lines of code.
|
||||||
|
|
||||||
|
The main value however is the s-expression parser, i.e. Scan(), which is an
|
||||||
|
alternative to crafting a custom recursive descent parser for a particular
|
||||||
|
grammar. The tipping point depends on whether you want to read only a small
|
||||||
|
portion of a much larger document. If so, then using the ptree will likely be a
|
||||||
|
"faster to code" route. Documentation on how to navigate a ptree can be found on
|
||||||
|
the boost website and there are a number of examples in the
|
||||||
|
pcbnew/eagle_plugin.cpp file in this project. Powerful path navigation support
|
||||||
|
makes it easy to extract a subset of a ptree.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <boost/property_tree/ptree_fwd.hpp>
|
||||||
|
#include <richio.h>
|
||||||
|
#include <dsnlexer.h>
|
||||||
|
|
||||||
|
typedef boost::property_tree::ptree PTREE;
|
||||||
|
typedef const PTREE CPTREE;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function Scan
|
||||||
|
* fills an empty PTREE with information from a KiCad s-expresion stream. Use
|
||||||
|
* a DSNLEXER with an empty keyword table as @a aLexer. Useful for parsing
|
||||||
|
* s-expression files or strings of arbitrary grammars, say from a file or clipboard.
|
||||||
|
* The s-expression must be "KiCad compatible". See Documentation/s-expressions.txt
|
||||||
|
* for this KiCad compatible definition (it is the non-specctra mode).
|
||||||
|
* And also see in tools/property_tree.cpp for example usage.
|
||||||
|
*
|
||||||
|
* <code>
|
||||||
|
*
|
||||||
|
* FILE* fp = fopen( argv[1], "r" );
|
||||||
|
*
|
||||||
|
* static const KEYWORD empty_keywords[1] = {};
|
||||||
|
*
|
||||||
|
* DSNLEXER lexer( empty_keywords, 0, fp, wxString( FROM_UTF8( argv[1] ) ) );
|
||||||
|
*
|
||||||
|
* try
|
||||||
|
* {
|
||||||
|
* PTREE doc;
|
||||||
|
* Scan( &doc, &lexer );
|
||||||
|
* }
|
||||||
|
* catch( IO_ERROR ioe )
|
||||||
|
* {
|
||||||
|
* fprintf( stderr, "%s\n", TO_UTF8( ioe.errorText ) );
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* </code>
|
||||||
|
*/
|
||||||
|
void Scan( PTREE* aTree, DSNLEXER* aLexer ) throw ( IO_ERROR );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function Format
|
||||||
|
* outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
|
||||||
|
*/
|
||||||
|
void Format( OUTPUTFORMATTER* out, int aNestLevel, int aCtl, CPTREE& aTree ) throw( IO_ERROR );
|
||||||
|
|
||||||
|
#endif // PTREE_H_
|
|
@ -65,13 +65,14 @@ add_executable( test-nm-biu-to-ascii-mm-round-tripping
|
||||||
test-nm-biu-to-ascii-mm-round-tripping.cpp
|
test-nm-biu-to-ascii-mm-round-tripping.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable( parser_gen
|
add_executable( property_tree
|
||||||
EXCLUDE_FROM_ALL
|
EXCLUDE_FROM_ALL
|
||||||
parser_gen.cpp
|
property_tree.cpp
|
||||||
../common/richio.cpp
|
../common/richio.cpp
|
||||||
../common/dsnlexer.cpp
|
../common/dsnlexer.cpp
|
||||||
|
../common/ptree.cpp
|
||||||
)
|
)
|
||||||
target_link_libraries( parser_gen
|
target_link_libraries( property_tree
|
||||||
${wxWidgets_LIBRARIES}
|
${wxWidgets_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,290 +0,0 @@
|
||||||
/*
|
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
|
||||||
* Copyright (C) 2012 KiCad Developers, see CHANGELOG.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
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
// This is wanting to be an s-expression C++ parser generator. Feed it a sample
|
|
||||||
// file and maybe someday it will generate a C++ file which uses DSNLEXER to
|
|
||||||
// parse the described grammar OK.
|
|
||||||
|
|
||||||
// Until then, it is a non-specctra mode s-expression beautifier.
|
|
||||||
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <richio.h>
|
|
||||||
#include <dsnlexer.h>
|
|
||||||
#include <macros.h>
|
|
||||||
#include <boost/ptr_container/ptr_vector.hpp>
|
|
||||||
|
|
||||||
|
|
||||||
// http://sexpr.sourceforge.net/ see comments about graphviz
|
|
||||||
// http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
|
|
||||||
|
|
||||||
#define D(x) x
|
|
||||||
//#define D(x)
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class ELEM
|
|
||||||
*/
|
|
||||||
class ELEM
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
int token;
|
|
||||||
std::string text;
|
|
||||||
|
|
||||||
typedef boost::ptr_vector<ELEM> ELEMS;
|
|
||||||
typedef ELEMS::const_iterator ELEMS_CITER;
|
|
||||||
typedef ELEMS::iterator ELEMS_ITER;
|
|
||||||
|
|
||||||
ELEMS kids; ///< ELEM pointers
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
// there are two constructors, one for a list, one for an atom
|
|
||||||
|
|
||||||
/// List constructor
|
|
||||||
ELEM( int aToken ) :
|
|
||||||
token( aToken ),
|
|
||||||
text( "" )
|
|
||||||
{
|
|
||||||
// D( printf( "ELEM%p: list\n", this ); )
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Atom constructor
|
|
||||||
ELEM( const std::string& aText, int aToken ) :
|
|
||||||
token( aToken ),
|
|
||||||
text( aText )
|
|
||||||
{
|
|
||||||
// D( printf( "ELEM%p: '%s'\n", this, text.c_str() ); )
|
|
||||||
}
|
|
||||||
|
|
||||||
int Token() const { return token; }
|
|
||||||
|
|
||||||
const char* Text() { return text.c_str(); }
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function Format
|
|
||||||
* writes this object as ASCII out to an OUTPUTFORMATTER
|
|
||||||
* @param out The formatter to write to.
|
|
||||||
* @param nestLevel A multiple of the number of spaces to preceed the output with.
|
|
||||||
* @throw IO_ERROR if a system error writing the output, such as a full disk.
|
|
||||||
*/
|
|
||||||
void Format( OUTPUTFORMATTER* aFormatter, int aNestLevel = 0, int aControlBits = 0 );
|
|
||||||
|
|
||||||
#define CTL_OMIT_NL (1<<0)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function Length
|
|
||||||
* returns the number of ELEMs in this ELEM.
|
|
||||||
* @return int - the count of children
|
|
||||||
*/
|
|
||||||
int Length() const
|
|
||||||
{
|
|
||||||
return kids.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Append( ELEM* aElem )
|
|
||||||
{
|
|
||||||
kids.push_back( aElem );
|
|
||||||
}
|
|
||||||
|
|
||||||
ELEM* Replace( int aIndex, ELEM* aElem )
|
|
||||||
{
|
|
||||||
ELEMS::auto_type ret = kids.replace( aIndex, aElem );
|
|
||||||
return ret.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
ELEM* Remove( int aIndex )
|
|
||||||
{
|
|
||||||
ELEMS::auto_type ret = kids.release( kids.begin()+aIndex );
|
|
||||||
return ret.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Insert( int aIndex, ELEM* aElem )
|
|
||||||
{
|
|
||||||
kids.insert( kids.begin()+aIndex, aElem );
|
|
||||||
}
|
|
||||||
|
|
||||||
ELEM* At( int aIndex ) const
|
|
||||||
{
|
|
||||||
const ELEM& ref = kids.at( aIndex );
|
|
||||||
return (ELEM*) &ref;
|
|
||||||
}
|
|
||||||
|
|
||||||
ELEM* operator[]( int aIndex ) const
|
|
||||||
{
|
|
||||||
return At( aIndex );
|
|
||||||
}
|
|
||||||
|
|
||||||
void Delete( int aIndex )
|
|
||||||
{
|
|
||||||
kids.erase( kids.begin()+aIndex );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void ELEM::Format( OUTPUTFORMATTER* out, int nestLevel, int ctl )
|
|
||||||
{
|
|
||||||
if( token == DSN_LEFT ) // this is a list
|
|
||||||
{
|
|
||||||
out->Print( nestLevel, "(" );
|
|
||||||
|
|
||||||
const int count = Length();
|
|
||||||
for( int i=0; i<count; ++i )
|
|
||||||
{
|
|
||||||
ELEM* cur = At( i );
|
|
||||||
ELEM* next = i < count-1 ? At( i+1 ) : NULL;
|
|
||||||
|
|
||||||
if( i > 0 )
|
|
||||||
out->Print( 0, " " );
|
|
||||||
|
|
||||||
if( next && next->token == DSN_LEFT )
|
|
||||||
{
|
|
||||||
cur->Format( out, nestLevel+1, 0 );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cur->Format( out, nestLevel+1, CTL_OMIT_NL );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out->Print( 0, ")%s", ctl & CTL_OMIT_NL ? "" : "\n" );
|
|
||||||
}
|
|
||||||
else // this is an atom
|
|
||||||
{
|
|
||||||
const char* s = out->Quotes( text ).c_str();
|
|
||||||
out->Print( 0, "%s%s", s, ctl & CTL_OMIT_NL ? "" : "\n" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ELEM* Scan( DSNLEXER* lex );
|
|
||||||
ELEM* ScanList( DSNLEXER* lex );
|
|
||||||
ELEM* ScanAtom( DSNLEXER* lex );
|
|
||||||
|
|
||||||
|
|
||||||
void usage()
|
|
||||||
{
|
|
||||||
fprintf( stderr, "Usage: parser_gen <grammar_s-expression_file>\n" );
|
|
||||||
exit( 1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static KEYWORD empty_keywords[1] = {};
|
|
||||||
|
|
||||||
|
|
||||||
ELEM* Scan( DSNLEXER* lex )
|
|
||||||
{
|
|
||||||
ELEM* elem = NULL;
|
|
||||||
int tok = lex->CurTok();
|
|
||||||
|
|
||||||
// conditionally read first token.
|
|
||||||
if( tok == DSN_NONE )
|
|
||||||
tok = lex->NextTok();
|
|
||||||
|
|
||||||
if( tok == DSN_EOF )
|
|
||||||
{
|
|
||||||
lex->Unexpected( DSN_EOF );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( tok == DSN_LEFT )
|
|
||||||
{
|
|
||||||
elem = ScanList( lex );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
elem = ScanAtom( lex );
|
|
||||||
}
|
|
||||||
|
|
||||||
return elem;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function ScanList
|
|
||||||
* reads and returns a sexpList from the input stream.
|
|
||||||
*/
|
|
||||||
ELEM* ScanList( DSNLEXER* lex )
|
|
||||||
{
|
|
||||||
int tok;
|
|
||||||
ELEM* list = NULL;
|
|
||||||
|
|
||||||
assert( lex->CurTok() == DSN_LEFT );
|
|
||||||
|
|
||||||
list = new ELEM( DSN_LEFT );
|
|
||||||
|
|
||||||
while( ( tok = lex->NextTok() ) != DSN_RIGHT )
|
|
||||||
{
|
|
||||||
if( tok == DSN_EOF )
|
|
||||||
lex->Unexpected( DSN_EOF );
|
|
||||||
|
|
||||||
ELEM* elem = Scan( lex );
|
|
||||||
list->Append( elem );
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ELEM* ScanAtom( DSNLEXER* lex )
|
|
||||||
{
|
|
||||||
return new ELEM( lex->CurText(), lex->CurTok() );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int main( int argc, char** argv )
|
|
||||||
{
|
|
||||||
if( argc != 2 )
|
|
||||||
{
|
|
||||||
usage();
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE* fp = fopen( argv[1], "rt" );
|
|
||||||
if( !fp )
|
|
||||||
{
|
|
||||||
fprintf( stderr, "Unable to open '%s'\n", argv[1] );
|
|
||||||
usage();
|
|
||||||
}
|
|
||||||
|
|
||||||
DSNLEXER lexer( empty_keywords, 0, fp, wxString( FROM_UTF8( argv[1] ) ) );
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ELEM* elem = Scan( &lexer );
|
|
||||||
|
|
||||||
if( elem )
|
|
||||||
{
|
|
||||||
STRING_FORMATTER sf;
|
|
||||||
|
|
||||||
elem->Format( &sf, 0 );
|
|
||||||
|
|
||||||
printf( "%s", sf.GetString().c_str() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch( IO_ERROR ioe )
|
|
||||||
{
|
|
||||||
fprintf( stderr, "%s\n", TO_UTF8( ioe.errorText ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||||
|
* Copyright (C) 2012 KiCad Developers, see CHANGELOG.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
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// This is a propertytree test utility.
|
||||||
|
// It can convert XML to sexpressions or beautify s-expressions in non-specctra mode.
|
||||||
|
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ptree.h>
|
||||||
|
#include <richio.h>
|
||||||
|
#include <dsnlexer.h>
|
||||||
|
#include <macros.h>
|
||||||
|
#include <boost/property_tree/xml_parser.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
void usage()
|
||||||
|
{
|
||||||
|
fprintf( stderr, "Usage: parser_gen <grammar_s-expression_file>\n" );
|
||||||
|
exit( 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main( int argc, char** argv )
|
||||||
|
{
|
||||||
|
if( argc != 2 )
|
||||||
|
{
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE* fp = fopen( argv[1], "r" );
|
||||||
|
if( !fp )
|
||||||
|
{
|
||||||
|
fprintf( stderr, "Unable to open '%s'\n", argv[1] );
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const KEYWORD empty_keywords[1] = {};
|
||||||
|
|
||||||
|
DSNLEXER lexer( empty_keywords, 0, fp, wxString( FROM_UTF8( argv[1] ) ) );
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PTREE doc;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
using namespace boost::property_tree;
|
||||||
|
|
||||||
|
read_xml( argv[1], doc, xml_parser::trim_whitespace | xml_parser::no_comments );
|
||||||
|
#else
|
||||||
|
Scan( &doc, &lexer );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
STRING_FORMATTER sf;
|
||||||
|
Format( &sf, 0, 0, doc );
|
||||||
|
printf( "%s", sf.GetString().c_str() );
|
||||||
|
#else
|
||||||
|
// writing the unchanged ptree in file2.xml
|
||||||
|
boost::property_tree::xml_writer_settings<char> settings( ' ', 2 );
|
||||||
|
write_xml( "/tmp/output.xml", doc, std::locale(), settings );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
catch( IO_ERROR ioe )
|
||||||
|
{
|
||||||
|
fprintf( stderr, "%s\n", TO_UTF8( ioe.errorText ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue