Parser gesucht
-
Heho Leute, suche schonmal vorgreifend für mein derzeitiges Projekt einen Parser für arithmetische Ausdrücke(welche als string vorhanden sein werden).
Selber machen ist a) sinnfrei(will was anderes programmieren) und b) waren meine eigenen Ansätze eh nicht so prall
Anforderungen:
-Alle(muss nochmal genau nachlesen, aber meine ich brauche alle) C-Operatoren parsebar.
-Eigene Funktionen sollten implementiert werden können(muss einige eigentümliche Funktionen basteln).
-Rückgabetyp sollte bool sein(d.h. ergebnis > 0 -> true else false)Wäre super wenn ihr mir ein paar Anregungen geben könntet was da praktisch wäre.
-
Was hältst du von dem da? http://www.c-plusplus.net/forum/p1642138#1642138
Ich habe das für dich angepasst, damit du eigene Funktionen definieren kannst (benötigt C++11, damit es kompiliert):
#include <iostream> #include <algorithm> #include <vector> #include <map> #include <iostream> template <typename T> using function_list = std::map<std::string, std::function<bool(std::vector<T>, T&)> >; // -- liest 'C'; sonst wird 'in' auf Fehler gesetzt template< char C > std::istream& Char( std::istream& in ) { char c; if( in >> c && c != C ) in.setstate( std::ios_base::failbit ); return in; } // -- liefert 'true' falls das Zeichen, das 'in' folgt, Start eines Funktionsnamen sein kann template< typename E, typename Traits > bool funcbegin_test( std::basic_istream< E, Traits >& in ) { if( in.good() ) { const std::ctype< E >& ctype_fac = std::use_facet< std::ctype< E > >( in.getloc() ); for( typename Traits::int_type m = in.rdbuf()->sgetc(); ; m = in.rdbuf()->snextc() ) { if( Traits::eq_int_type( m, Traits::eof() ) ) { in.setstate( std::ios_base::eofbit ); break; } const char c = Traits::to_char_type( m ); if( ctype_fac.is(std::ctype<E>::alpha, c) || c == '_' ) { // -- gesuchtes Zeichen folgt im Stream return true; // ok; Zeichen war da } if( (in.flags() & std::ios_base::skipws) == 0 || !ctype_fac.is( std::ctype< E >::space, c ) ) break; } } return false; } template< typename E, typename Traits > std::basic_istream< E, Traits >& read_funcname( std::basic_istream< E, Traits >& in, std::basic_string<E, Traits>& s) { if( in.good() ) { const std::ctype< E >& ctype_fac = std::use_facet< std::ctype< E > >( in.getloc() ); for( typename Traits::int_type m = in.rdbuf()->sgetc(); ; m = in.rdbuf()->snextc() ) { if( Traits::eq_int_type( m, Traits::eof() ) ) { in.setstate( std::ios_base::eofbit ); break; } const char c = Traits::to_char_type( m ); if( ctype_fac.is(std::ctype<E>::alpha, c) || c == '_' ) { // -- gesuchtes Zeichen folgt im Stream s.push_back(m); } else break; } } return in; } // -- liefert 'true' falls das Zeichen 'e' in 'in' folgt template< typename E, typename Traits > bool ctest( std::basic_istream< E, Traits >& in, E e ) { if( in.good() ) { const std::ctype< E >& ctype_fac = std::use_facet< std::ctype< E > >( in.getloc() ); for( typename Traits::int_type m = in.rdbuf()->sgetc(); ; m = in.rdbuf()->snextc() ) { if( Traits::eq_int_type( m, Traits::eof() ) ) { in.setstate( std::ios_base::eofbit ); break; } const char c = Traits::to_char_type( m ); if( c == e ) { // -- gesuchtes Zeichen folgt im Stream in.rdbuf()->sbumpc(); // Zeichen konsumieren -> ++Lesezeiger return true; // ok; Zeichen war da } if( (in.flags() & std::ios_base::skipws) == 0 || !ctype_fac.is( std::ctype< E >::space, c ) ) break; } } return false; } // -- Der Ausdruck-Parser template< typename T > struct Expression { typedef T value_type; explicit Expression( T& value, function_list<T> const& funcs ) : m_value( value ), funcs(funcs) {} friend std::istream& operator>>( std::istream& in, const Expression& expr ) { expr.parse( in ); return in; } private: void parse( std::istream& in ) const; T& m_value; function_list<T> const& funcs; }; template< typename T > Expression< T > expression( T& value, function_list<T> const& funcs) { return Expression< T >( value, funcs ); } // -- Der Factor-Parser template< typename T > struct Factor { explicit Factor( T& value, function_list<T> funcs ) : m_value( value ), funcs(funcs) {} friend std::istream& operator>>( std::istream& in, const Factor& x ) { // factor = number | "(" expression ")" | f "(" arg1, arg2, ... ")". if( ctest( in, '(' ) ) return in >> expression( x.m_value, x.funcs ) >> Char<')'>; if( funcbegin_test(in) ) { std::string f; if (!(read_funcname(in, f) >> Char<'('> >> std::ws)) return in; std::vector<T> args; while (in) { T t=3.141; if (!(in >> expression(t, x.funcs))) return in; args.push_back(t); if (ctest( in, ')' )) break; in >> Char<','>; } if (in) { typename function_list<T>::const_iterator it = x.funcs.find(f); if (it == x.funcs.end() || !it->second(args, x.m_value)) in.setstate( std::ios_base::failbit ); } return in; } return in >> x.m_value; } private: T& m_value; function_list<T> const& funcs; }; // -- Der Term-Parser template< typename T > struct Term { explicit Term( T& value, function_list<T> const& funcs ) : m_value( value ), funcs(funcs) {} friend std::istream& operator>>( std::istream& in, const Term& x ) { // term = factor {("*"|"/") factor} . in >> Factor< T >( x.m_value, x.funcs ); for( T value2;; ) { if( ctest( in, '*' ) ) { if( in >> Factor< T >( value2, x.funcs ) ) x.m_value *= value2; } else if( ctest( in, '/' ) ) { if( in >> Factor< T >( value2, x.funcs ) ) x.m_value /= value2; } else break; } return in; } private: T& m_value; function_list<T> const& funcs; }; template< typename T > void Expression< T >::parse( std::istream& in ) const { // expression = ["+"|"-"] term {("+"|"-") term} . const bool minus = !ctest( in, '+' ) && ctest( in, '-' ); // @Edit: Multiplikation mit -1 durch operator-() ersetzt in >> Term< T >( m_value, funcs ); if( minus ) m_value = -m_value; for( T value2;; ) { if( ctest( in, '+' ) ) { if( in >> Term< T >( value2, funcs ) ) m_value += value2; } else if( ctest( in, '-' ) ) { if( in >> Term< T >( value2, funcs ) ) m_value -= value2; } else break; } }Beispielnutzung:
bool square(std::vector<double> const& v, double& d) { if (v.size() != 1) return false; d = v[0]*v[0]; return true; } bool mypow(std::vector<double> const& v, double& d) { return !(v.size() == 2 && (d = std::pow(v[0], v[1]), false)); } int main() { using namespace std; cout << "Taschenrechner mit den 4 Grundrechenarten:" << endl; cin >> noskipws; // diese Zeile löschen, wenn Leerzeichen erlaubt function_list<double> f; f["square"] = square; f["pow"] = mypow; for( double d; cout << "> ", cin >> ws >> expression( d, f ); ) cout << " = " << d << endl; }
-
Hey, danke sehr

Muss ich mir anschauen, hatte sonst noch den hier gefunden:
http://www.codeproject.com/Articles/7773/Fast-Mathematical-Expressions-Parser?fid=79444&df=90&mpp=25&noise=3&prof=False&sort=Position&view=Quick&spc=Relaxed&fr=26#xx0xxWobei mir an dem auf den ersten Blick missfällt, dass alles scheinbar double zurückgibt, was nicht ganz C-ig ist.
-
für mein derzeitiges Projekt einen Parser für arithmetische Ausdrücke
Arbeite einfach das Tutorial fuer flex+bison durch. Oder du bindest gleich eine Scriptsprache ein.