You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

290 lines
6.5 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  5. * Copyright (C) 2012 KiCad Developers, see CHANGELOG.TXT for contributors.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. // This is wanting to be an s-expression C++ parser generator. Feed it a sample
  25. // file and maybe someday it will generate a C++ file which uses DSNLEXER to
  26. // parse the described grammar OK.
  27. // Until then, it is a non-specctra mode s-expression beautifier.
  28. #include <assert.h>
  29. #include <richio.h>
  30. #include <dsnlexer.h>
  31. #include <macros.h>
  32. #include <boost/ptr_container/ptr_vector.hpp>
  33. // http://sexpr.sourceforge.net/ see comments about graphviz
  34. // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
  35. #define D(x) x
  36. //#define D(x)
  37. /**
  38. * Class ELEM
  39. */
  40. class ELEM
  41. {
  42. protected:
  43. int token;
  44. std::string text;
  45. typedef boost::ptr_vector<ELEM> ELEMS;
  46. typedef ELEMS::const_iterator ELEMS_CITER;
  47. typedef ELEMS::iterator ELEMS_ITER;
  48. ELEMS kids; ///< ELEM pointers
  49. public:
  50. // there are two constructors, one for a list, one for an atom
  51. /// List constructor
  52. ELEM( int aToken ) :
  53. token( aToken ),
  54. text( "" )
  55. {
  56. // D( printf( "ELEM%p: list\n", this ); )
  57. }
  58. /// Atom constructor
  59. ELEM( const std::string& aText, int aToken ) :
  60. token( aToken ),
  61. text( aText )
  62. {
  63. // D( printf( "ELEM%p: '%s'\n", this, text.c_str() ); )
  64. }
  65. int Token() const { return token; }
  66. const char* Text() { return text.c_str(); }
  67. /**
  68. * Function Format
  69. * writes this object as ASCII out to an OUTPUTFORMATTER
  70. * @param out The formatter to write to.
  71. * @param nestLevel A multiple of the number of spaces to preceed the output with.
  72. * @throw IO_ERROR if a system error writing the output, such as a full disk.
  73. */
  74. void Format( OUTPUTFORMATTER* aFormatter, int aNestLevel = 0, int aControlBits = 0 );
  75. #define CTL_OMIT_NL (1<<0)
  76. /**
  77. * Function Length
  78. * returns the number of ELEMs in this ELEM.
  79. * @return int - the count of children
  80. */
  81. int Length() const
  82. {
  83. return kids.size();
  84. }
  85. void Append( ELEM* aElem )
  86. {
  87. kids.push_back( aElem );
  88. }
  89. ELEM* Replace( int aIndex, ELEM* aElem )
  90. {
  91. ELEMS::auto_type ret = kids.replace( aIndex, aElem );
  92. return ret.release();
  93. }
  94. ELEM* Remove( int aIndex )
  95. {
  96. ELEMS::auto_type ret = kids.release( kids.begin()+aIndex );
  97. return ret.release();
  98. }
  99. void Insert( int aIndex, ELEM* aElem )
  100. {
  101. kids.insert( kids.begin()+aIndex, aElem );
  102. }
  103. ELEM* At( int aIndex ) const
  104. {
  105. const ELEM& ref = kids.at( aIndex );
  106. return (ELEM*) &ref;
  107. }
  108. ELEM* operator[]( int aIndex ) const
  109. {
  110. return At( aIndex );
  111. }
  112. void Delete( int aIndex )
  113. {
  114. kids.erase( kids.begin()+aIndex );
  115. }
  116. };
  117. void ELEM::Format( OUTPUTFORMATTER* out, int nestLevel, int ctl )
  118. {
  119. if( token == DSN_LEFT ) // this is a list
  120. {
  121. out->Print( nestLevel, "(" );
  122. const int count = Length();
  123. for( int i=0; i<count; ++i )
  124. {
  125. ELEM* cur = At( i );
  126. ELEM* next = i < count-1 ? At( i+1 ) : NULL;
  127. if( i > 0 )
  128. out->Print( 0, " " );
  129. if( next && next->token == DSN_LEFT )
  130. {
  131. cur->Format( out, nestLevel+1, 0 );
  132. }
  133. else
  134. {
  135. cur->Format( out, nestLevel+1, CTL_OMIT_NL );
  136. }
  137. }
  138. out->Print( 0, ")%s", ctl & CTL_OMIT_NL ? "" : "\n" );
  139. }
  140. else // this is an atom
  141. {
  142. const char* s = out->Quotes( text ).c_str();
  143. out->Print( 0, "%s%s", s, ctl & CTL_OMIT_NL ? "" : "\n" );
  144. }
  145. }
  146. ELEM* Scan( DSNLEXER* lex );
  147. ELEM* ScanList( DSNLEXER* lex );
  148. ELEM* ScanAtom( DSNLEXER* lex );
  149. void usage()
  150. {
  151. fprintf( stderr, "Usage: parser_gen <grammar_s-expression_file>\n" );
  152. exit( 1 );
  153. }
  154. static KEYWORD empty_keywords[1] = {};
  155. ELEM* Scan( DSNLEXER* lex )
  156. {
  157. ELEM* elem = NULL;
  158. int tok = lex->CurTok();
  159. // conditionally read first token.
  160. if( tok == DSN_NONE )
  161. tok = lex->NextTok();
  162. if( tok == DSN_EOF )
  163. {
  164. lex->Unexpected( DSN_EOF );
  165. }
  166. if( tok == DSN_LEFT )
  167. {
  168. elem = ScanList( lex );
  169. }
  170. else
  171. {
  172. elem = ScanAtom( lex );
  173. }
  174. return elem;
  175. }
  176. /**
  177. * Function ScanList
  178. * reads and returns a sexpList from the input stream.
  179. */
  180. ELEM* ScanList( DSNLEXER* lex )
  181. {
  182. int tok;
  183. ELEM* list = NULL;
  184. assert( lex->CurTok() == DSN_LEFT );
  185. list = new ELEM( DSN_LEFT );
  186. while( ( tok = lex->NextTok() ) != DSN_RIGHT )
  187. {
  188. if( tok == DSN_EOF )
  189. lex->Unexpected( DSN_EOF );
  190. ELEM* elem = Scan( lex );
  191. list->Append( elem );
  192. }
  193. return list;
  194. }
  195. ELEM* ScanAtom( DSNLEXER* lex )
  196. {
  197. return new ELEM( lex->CurText(), lex->CurTok() );
  198. }
  199. int main( int argc, char** argv )
  200. {
  201. if( argc != 2 )
  202. {
  203. usage();
  204. }
  205. FILE* fp = fopen( argv[1], "rt" );
  206. if( !fp )
  207. {
  208. fprintf( stderr, "Unable to open '%s'\n", argv[1] );
  209. usage();
  210. }
  211. DSNLEXER lexer( empty_keywords, 0, fp, wxString( FROM_UTF8( argv[1] ) ) );
  212. try
  213. {
  214. ELEM* elem = Scan( &lexer );
  215. if( elem )
  216. {
  217. STRING_FORMATTER sf;
  218. elem->Format( &sf, 0 );
  219. printf( "%s", sf.GetString().c_str() );
  220. }
  221. }
  222. catch( IO_ERROR ioe )
  223. {
  224. fprintf( stderr, "%s\n", TO_UTF8( ioe.errorText ) );
  225. }
  226. }