Boost.Spirit und Parser mit Templates



  • Hallo zusammen,

    ich brauche einen Parser, der mathematische Formeln parsen kann, mit Ziffern und Variablen. Ich wollte Boost.Spirit verwenden, aber leider hab ich zu wenig Wissen, als das ich sowas hinbekommen würde. Deshalb möchte ich gern um Hilfe bitten.

    Anstatt Strukturen, wollte ich Klassen verwenden ...

    Deklaration:

    #ifndef MATHFORMULAPARSER_H_
    #define MATHFORMULAPARSER_H_
    
    #include <boost/spirit/include/classic.hpp>
    #include <boost/spirit/include/qi.hpp>
    #include <stdlib.h>
    #include <iostream>
    #include <map>
    #include <utility>
    #include <string>
    
    namespace calc {
    
    namespace qi = boost::spirit::qi;
    
    template <class Iterator>
    class MathFormulaParser : qi::grammar<Iterator,qi::space_type>
    {
    protected:
    	 qi::rule<Iterator,std::string, qi::space_type> search_var;
    	 qi::rule<Iterator, std::string, qi::space_type> var;
    	 qi::rule<Iterator, double> constants;
    	 qi::rule<Iterator> factor, term, expression;
    	 std::vector<std::string> parse_result;
    
    public:
    	MathFormulaParser ()
    	      : MathFormulaParser::base_type(expression)
    	    {
    
    			search_var = +(qi::char_("a-zA-Z_")) >> qi::char_('=');
    			var = +(qi::char_("a-zA-Z_")) - search_var;
    			constants = qi::double_;
    			expression = term >> *((qi::char_('+') >> term) | (qi::char_('-')>>term));
    			term = factor >> *((qi::char_('*') | qi::char_('/'))>>factor);
    			factor = (var | constants)
    					| ('(' >> expression >> ')')
    					| (qi::char_('+')>>factor)
    					| (qi::char_('-')>>factor);
    	    };
    
    	void parse_forms (std::string &form);
    
    	virtual ~MathFormulaParser(){};
    };
    
    };
    
    #endif /* MATHFORMULAPARSER_H_ */
    

    Das Problem ist die Methode parse_form. Bei der Definition kommt folgender Fehler:

    Fehler: »template<class Iterator> class calc::MathFormulaParser« ohne Template-Parameter verwendet	MathFormulaParser.cpp
    

    Ich habe mit Templates bisher keine Erfahrung ...

    #include "MathFormulaParser.h"
    
    namespace calc {
    
    void MathFormulaParser::parse_forms(std::string &form)
    {
    	/*if ((qi::parse(form.begin(),form.end(),expression)).full)
    	{
    		std::cout << "Parse complete\n";
    		return;
    	}else{
    		std::cout << "Parse not complete\n";
    		return;
    	}*/
    }
    
    } /* namespace calc */
    

    Was mache ich falsch ?

    Vielen Dank.

    Senifor



  • Du darfst bei Templates die Implementierung und die Deklaration nicht trennen. Implementiere die Methode im Header direkt in der Klasse, oder nach der Klasse.

    Variante 1:

    template <class Iterator>
    class MathFormulaParser : qi::grammar<Iterator,qi::space_type>
    {
    protected:
         qi::rule<Iterator,std::string, qi::space_type> search_var;
         qi::rule<Iterator, std::string, qi::space_type> var;
         qi::rule<Iterator, double> constants;
         qi::rule<Iterator> factor, term, expression;
         std::vector<std::string> parse_result;
    
    public:
        MathFormulaParser ()
              : MathFormulaParser::base_type(expression)
            {
    
                search_var = +(qi::char_("a-zA-Z_")) >> qi::char_('=');
                var = +(qi::char_("a-zA-Z_")) - search_var;
                constants = qi::double_;
                expression = term >> *((qi::char_('+') >> term) | (qi::char_('-')>>term));
                term = factor >> *((qi::char_('*') | qi::char_('/'))>>factor);
                factor = (var | constants)
                        | ('(' >> expression >> ')')
                        | (qi::char_('+')>>factor)
                        | (qi::char_('-')>>factor);
            };
    
        void parse_forms (std::string &form)
        {
           if ((qi::parse(form.begin(),form.end(),expression)).full)
           {
              std::cout << "Parse complete\n";
              return;
           }
           else
           {
              std::cout << "Parse not complete\n";
              return;
           }
        }
    
        virtual ~MathFormulaParser(){};
    };
    

    Variante 2:

    template <class Iterator>
    class MathFormulaParser : qi::grammar<Iterator,qi::space_type>
    {
    protected:
         qi::rule<Iterator,std::string, qi::space_type> search_var;
         qi::rule<Iterator, std::string, qi::space_type> var;
         qi::rule<Iterator, double> constants;
         qi::rule<Iterator> factor, term, expression;
         std::vector<std::string> parse_result;
    
    public:
        MathFormulaParser ()
              : MathFormulaParser::base_type(expression)
            {
    
                search_var = +(qi::char_("a-zA-Z_")) >> qi::char_('=');
                var = +(qi::char_("a-zA-Z_")) - search_var;
                constants = qi::double_;
                expression = term >> *((qi::char_('+') >> term) | (qi::char_('-')>>term));
                term = factor >> *((qi::char_('*') | qi::char_('/'))>>factor);
                factor = (var | constants)
                        | ('(' >> expression >> ')')
                        | (qi::char_('+')>>factor)
                        | (qi::char_('-')>>factor);
            };
    
        void parse_forms (std::string &form);
    
        virtual ~MathFormulaParser(){};
    };
    
    template <typename Iterator>
    void MathFormularParser<Iterator>::parse_forms(std::string& form)
    {
           if ((qi::parse(form.begin(),form.end(),expression)).full)
           {
              std::cout << "Parse complete\n";
              return;
           }
           else
           {
              std::cout << "Parse not complete\n";
              return;
           }
    }
    


  • Vielen Dank. So funktioniert es.
    Jetzt hab ich allerdings einen anderen Fehler beim Erstellen eines Objektes:

    #include <iostream>
    #include "MathFormulaParser.h"
    
    typedef std::string::const_iterator iterator_type;
    typedef calc::MathFormulaParser<iterator_type> formparser;
    
    int main() {
    	formparser parseObj;
    	return 0;
    }
    

    Die rules habe ich geändert in:

    search_var = +(qi::char_("a-zA-Z_")) >> qi::char_('=');
    			var = +(qi::char_("a-zA-Z_")) - search_var;
    			integer = +(qi::char_("0-9"));
    			constants = integer >> *(qi::char_('.')>>integer);
    			expression = term >> *((qi::char_('+') >> term) | (qi::char_('-')>>term));
    			term = factor >> *((qi::char_('*') | qi::char_('/'))>>factor);
    			factor = ((var | constants)
    					| ('(' >> expression >> ')')
    					| (qi::char_('+')>>factor)
    					| (qi::char_('-')>>factor));
    

    Fehler bei:

    MathFormulaParser ()
    	      : MathFormulaParser::base_type(expression)
    
    • Fehler 1 Calculator C/C++ Problem
    • Anmerkung: Kandidat erwartet 1 Argument, 0 angegeben line 27, external location: /usr/include/boost/spirit/home/qi/reference.hpp C/C++ Problem
    • Anmerkung: boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >, 0l>, boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> >::reference(const boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >, 0l>, boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> >&) BioChemCalculator line 27, external location: /usr/include/boost/spirit/home/qi/reference.hpp C/C++ Problem

    • ...

    Hat jemand eine Idee was da schief läuft ? Ich wollte anstatt einer Struktur wie bei den Beispielen, eine Klasse verwenden ...



  • Ich vermute, dass er Probleme damit hat,

    constants = integer >> *(qi::char_('.')>>integer);
    

    in

    qi::rule<Iterator, double> constants;
    

    zu quetschen, weil std::vector<int> nicht so gut in einen double passt.

    Mit Sicherheit kann ich das aber ohne den ganzen Code und derart extrem gekürzter Fehlermeldung natürlich nicht sagen.


Anmelden zum Antworten