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#xx0xx

    Wobei 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.


Anmelden zum Antworten