cgal/Algebraic_kernel_d/include/CGAL/RS/polynomial_1_parser.h

362 lines
9.5 KiB
C++

// Copyright (c) 2007-2010 Inria Lorraine (France). All rights reserved.
//
// This file is part of CGAL (www.cgal.org); you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 3 of the License,
// or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
//
// Author: Luis Peñaranda <luis.penaranda@gmx.com>
//
// (the first version of this file was written by Elias Tsigaridas)
#ifndef CGAL_RS_PARSER_1_H
#define CGAL_RS_PARSER_1_H
#include <iostream>
#include <string>
#include <algorithm>
// if boost version is 1.38 or newer, we use the new version of spirit
#include <boost/version.hpp>
#if BOOST_VERSION >= 103800
#include <boost/spirit/include/classic_core.hpp>
#define CGAL_BOOST_SPIRIT boost::spirit::classic
#else
#include <boost/spirit/core.hpp>
#define CGAL_BOOST_SPIRIT boost::spirit
#endif
namespace CGAL{
// The semantics.
// In this class we store the current pair and the whole result;
struct Semantics
{
typedef std::pair< int, std::string > pair_t;
std::string variable;
pair_t current;
std::vector< pair_t > result;
std::string sign;
Semantics( const std::string& var) : variable( var) { }
void set_variable( const std::string& var)
{
variable = var;
}
std::string get_variable() const
{
return variable;
}
bool is_first() const
{
return current == pair_t(-1, "F");
}
void add()
{
result.push_back( current);
current = pair_t(-1, "F");
}
void init()
{
result.clear();
current = pair_t(-1, "F");
sign = "";
}
};
//------------- Semantic actions -----------------------------------
// Add a new monomial at the result
struct AddMonomial
{
void operator()( char const* first, char const* last) const
{
if (!sem.is_first()) {
sem.add();
}
}
AddMonomial( Semantics& sem_) : sem( sem_) { }
Semantics& sem;
};
// Set the coefficient of the current monomial
struct SetCoeff
{
void operator() ( char const* first, char const* last) const
{
sem.current.second = std::string( first, last);
if (sem.current.first == -1) {
sem.current.first = 0;
}
}
SetCoeff( Semantics& sem_) : sem( sem_) { }
Semantics& sem;
};
// Set the exponent of the current monomial
struct SetExp
{
void
operator()( const char* first, const char* last) const
{
sem.current.first = 1;
if (sem.current.second == "F") sem.current.second = "1";
}
void operator()( unsigned num) const
{
sem.current.first = num;
if (sem.current.second == "F") sem.current.second = "1";
}
SetExp( Semantics& sem_) : sem( sem_) { }
Semantics& sem;
};
// Set the sign of the current monomial
struct SetSign
{
void
operator()( char const* first, char const* last) const
{
std::string str( first, last);
sem.sign = str;
}
SetSign( Semantics& sem_) : sem( sem_) { }
Semantics& sem;
};
// Adjust the sign of the coefficient of the current monomial
struct AdjustCoeff
{
void
operator()( char const* first, char const* last) const
{
if (sem.sign == "-") {
if (sem.current.second[0] == '-') {
sem.current.second[0] = '+';
} else if (sem.current.second[0] == '+') {
sem.current.second[0] = '-';
} else {
sem.current.second = '-' + sem.current.second;
}
}
}
AdjustCoeff( Semantics& sem_) : sem( sem_) { }
Semantics& sem;
};
//---------------- Grammar -------------------------------------
// The grammar of the polynomial parser.
// The coefficient of the polynomial can also be rationals.
struct polynomial_p : public CGAL_BOOST_SPIRIT::grammar<polynomial_p>
{
template < typename ScannerT >
struct definition
{
definition(polynomial_p const& self)
{
CGAL_BOOST_SPIRIT::chlit<> lpar('(');
CGAL_BOOST_SPIRIT::chlit<> rpar(')');
CGAL_BOOST_SPIRIT::chlit<> plus('+');
CGAL_BOOST_SPIRIT::chlit<> minus('-');
CGAL_BOOST_SPIRIT::chlit<> mul('*');
CGAL_BOOST_SPIRIT::strlit<>
varX(self.sem.get_variable().c_str());
poly = (
(monomial | smonomial) [ AddMonomial( self.sem) ] >>
*( smonomial [ AddMonomial( self.sem) ] )
);
monomial
= ( unumber [ SetCoeff( self.sem) ] >> !( mul >> X ) )
| ( lpar >> number[ SetCoeff( self.sem) ] >> rpar >> !( mul >> X) )
| ( X >> mul >> number [ SetCoeff( self.sem) ] )
| ( X >> mul >> lpar >> number [ SetCoeff( self.sem) ] >> rpar )
| X;
smonomial = ( ( plus | minus ) [ SetSign( self.sem) ] >>
monomial) [ AdjustCoeff( self.sem) ];
X = ( (varX)[ SetExp( self.sem) ] >>
!(
CGAL_BOOST_SPIRIT::ch_p('^') >>
( (CGAL_BOOST_SPIRIT::uint_p) [ SetExp( self.sem) ]
| (lpar >>
CGAL_BOOST_SPIRIT::uint_p [ SetExp( self.sem) ] >>
rpar))
)
);
unumber = +(CGAL_BOOST_SPIRIT::digit_p) >>
!(CGAL_BOOST_SPIRIT::ch_p("/") >>
+(CGAL_BOOST_SPIRIT::digit_p));
number = ( (plus | minus) >> unumber );
}
CGAL_BOOST_SPIRIT::rule<ScannerT>
poly, monomial, smonomial, X, unumber, number;
CGAL_BOOST_SPIRIT::rule<ScannerT> const& start() const
{
return poly;
}
};
polynomial_p( Semantics& sem_) : sem(sem_) { }
Semantics& sem;
};
// The polynomial parser.
// The constructor takes the name of the variable.
struct Polynomial_parser_1
{
protected:
// internal::Semantics sem;
Semantics sem;
// internal::polynomial_p poly_p;
polynomial_p poly_p;
CGAL_BOOST_SPIRIT::parse_info<> info;
// The default conversion is to int
struct Converter
{
int operator()( const std::string str) const
{
return atoi( str.c_str());
}
};
public:
Polynomial_parser_1( const std::string& var = "x")
: sem( var), poly_p( sem)
{
}
void parse( const std::string& in_str)
{
// Eliminate spaces
std::string str(in_str);
while (str.find(" ") < str.size() )
{
size_t pos = str.find(" ");
str.erase( pos, 1);
}
sem.init();
info = CGAL_BOOST_SPIRIT::parse(str.c_str(),
poly_p,
CGAL_BOOST_SPIRIT::space_p);
std::sort( sem.result.begin(), sem.result.end());
}
bool is_correct() const
{
return info.full;
}
std::string error() const
{
if (!is_correct()) {
return info.stop;
}
return "";
}
std::string get_variable() const
{
return sem.get_variable();
}
void set_variable( const std::string& var)
{
sem.set_variable( var);
}
template < typename OutputIterator,
typename ConverterFunction>
OutputIterator
result( OutputIterator oi, ConverterFunction conv) const
{
//for (int i = 0; i < sem.result.size(); ++i) {
// std::cout << "(" << sem.result[i].first << ", " <<
// sem.result[i].second << ") ";
//}
//std::cout << std::endl;
for (unsigned i = 0, j = 0; j < sem.result.size(); ++i) {
if (sem.result[j].first == static_cast<int>( i)) {
*oi++ = conv( sem.result[j].second);
++j;
} else {
*oi++ = conv( "0");
}
}
return oi;
}
template < typename OutputIterator >
OutputIterator
result( OutputIterator oi) const
{
return this->result( oi, Converter());
}
};
template < typename T >
struct Convert_to
{
T
operator()( const std::string str) const {
return static_cast<T>( atoi( str.c_str()));
}
};
struct Convert_to_Gmpz
{
Gmpz
operator()( const std::string str) const {
return Gmpz(str.c_str());
}
};
} // namespace CGAL
#undef CGAL_BOOST_SPIRIT
#endif // CGAL_RS_PARSER_1_H