- remove unused isInVector

- move AFP stuff into its own namespace
- move utf8 and equivset into seperate modules
- parser should understand /* */ comments
This commit is contained in:
River Tarnell 2008-08-08 03:23:34 +00:00
parent 81343c86c7
commit ff2465007f
15 changed files with 285 additions and 448 deletions

View file

@ -6,18 +6,18 @@
#include <iostream>
#include <ctype.h>
#include <unicode/utf8.h>
#include <unicode/ustring.h>
#include "utf8.h"
#include "equiv.h"
#define EQUIVSET_LOC "equivset.txt"
namespace afp {
AFPData
af_count(std::vector<AFPData> const &args) {
datum
af_count(std::vector<datum> const &args) {
if (!args.size()) {
throw AFPException( "Not enough arguments to count" );
throw exception( "Not enough arguments to count" );
}
string needle, haystack;
std::string needle, haystack;
if (args.size() < 2) {
needle = ",";
@ -40,52 +40,48 @@ af_count(std::vector<AFPData> const &args) {
count--;
}
return AFPData((long int)count);
return datum((long int)count);
}
AFPData
af_norm(vector<AFPData> const &args) {
datum
af_norm(std::vector<datum> const &args) {
if (!args.size()) {
throw AFPException( "Not enough arguments to norm" );
throw exception( "Not enough arguments to norm" );
}
string orig = args[0].toString();
std::string orig = args[0].toString();
string::const_iterator p, charStart, end;
int chr = 0,lastchr = 0;
map<int,int> const &equivSet = getEquivSet();
string result;
std::string::const_iterator p, charStart, end;
int chr = 0, lastchr = 0;
equiv_set const &equivs = equiv_set::instance();
std::string result;
p = orig.begin();
end = orig.end();
while (chr = next_utf8_char( p, charStart, end )) {
std::map<int, int>::const_iterator it;
if ((it = equivSet.find(chr)) != equivSet.end()) {
chr = it->second;
}
while (chr = utf8::next_utf8_char( p, charStart, end )) {
chr = equivs.get(chr);
if (chr != lastchr && isalnum(chr)) {
result.append(codepointToUtf8(chr));
}
if (chr != lastchr && isalnum(chr))
result.append(utf8::codepoint_to_utf8(chr));
lastchr = chr;
}
return AFPData(result);
return datum(result);
}
string
std::string
rmdoubles(std::string const &orig) {
string::const_iterator p, charStart, end;
std::string::const_iterator p, charStart, end;
int chr,lastchr = 0;
string result;
std::string result;
p = orig.begin();
end = orig.end();
while (chr = next_utf8_char( p, charStart, end )) {
while (chr = utf8::next_utf8_char( p, charStart, end )) {
if (chr != lastchr) {
result.append(codepointToUtf8(chr));
result.append(utf8::codepoint_to_utf8(chr));
}
lastchr = chr;
@ -94,277 +90,108 @@ rmdoubles(std::string const &orig) {
return result;
}
AFPData
af_specialratio(std::vector<AFPData> const &args) {
datum
af_specialratio(std::vector<datum> const &args) {
if (!args.size()) {
throw AFPException( "Not enough arguments to specialratio" );
throw exception( "Not enough arguments to specialratio" );
}
string orig = args[0].toString();
string::const_iterator p, charStart, end;
int chr,lastchr = 0;
std::string orig = args[0].toString();
std::string::const_iterator p, charStart, end;
int chr;
int specialcount = 0;
p = orig.begin();
end = orig.end();
while (chr = next_utf8_char( p, charStart, end )) {
while (chr = utf8::next_utf8_char( p, charStart, end )) {
if (!isalnum(chr)) {
specialcount++;
}
}
double ratio = (float)(specialcount) / (float)(utf8_strlen(orig));
double ratio = (float)(specialcount) / (float)(utf8::utf8_strlen(orig));
return AFPData(ratio);
return datum(ratio);
}
AFPData
af_rmspecials(std::vector<AFPData> const &args) {
datum
af_rmspecials(std::vector<datum> const &args) {
if (!args.size()) {
throw AFPException( "Not enough arguments to rmspecials" );
throw exception( "Not enough arguments to rmspecials" );
}
return AFPData(rmspecials(args[0].toString()));
return datum(rmspecials(args[0].toString()));
}
std::string
rmspecials(std::string const &orig) {
string::const_iterator p, charStart, end;
std::string::const_iterator p, charStart, end;
int chr = 0;
string result;
std::string result;
p = orig.begin();
end = orig.end();
while (chr = next_utf8_char( p, charStart, end )) {
while (chr = utf8::next_utf8_char( p, charStart, end )) {
if (isalnum(chr)) {
result.append(codepointToUtf8(chr));
result.append(utf8::codepoint_to_utf8(chr));
}
}
return result;
}
AFPData
af_ccnorm(std::vector<AFPData> const &args) {
datum
af_ccnorm(std::vector<datum> const &args) {
if (!args.size()) {
throw AFPException( "Not enough arguments to ccnorm" );
throw exception( "Not enough arguments to ccnorm" );
}
return AFPData( confusable_character_normalise( args[0].toString() ) );
return datum( confusable_character_normalise( args[0].toString() ) );
}
AFPData
af_rmdoubles(std::vector<AFPData> const &args) {
datum
af_rmdoubles(std::vector<datum> const &args) {
if (!args.size()) {
throw AFPException( "Not enough arguments to rmdoubles" );
throw exception( "Not enough arguments to rmdoubles" );
}
return AFPData(rmdoubles(args[0].toString()));
return datum(rmdoubles(args[0].toString()));
}
AFPData
af_length(std::vector<AFPData> const &args) {
datum
af_length(std::vector<datum> const &args) {
if (!args.size()) {
throw AFPException( "Not enough arguments to lcase" );
throw exception( "Not enough arguments to lcase" );
}
return AFPData( (long int)utf8_strlen(args[0].toString()) );
return datum( (long int)utf8::utf8_strlen(args[0].toString()) );
}
AFPData
af_lcase(std::vector<AFPData> const &args) {
datum
af_lcase(std::vector<datum> const &args) {
if (!args.size()) {
throw AFPException( "Not enough arguments to lcase" );
throw exception( "Not enough arguments to lcase" );
}
return AFPData(utf8_tolower(args[0].toString()));
return datum(utf8::utf8_tolower(args[0].toString()));
}
std::string
confusable_character_normalise(std::string const &orig) {
string::const_iterator p, charStart, end;
std::string::const_iterator p, charStart, end;
int chr;
map<int,int> const &equivSet = getEquivSet();
string result;
equiv_set const &equivs = equiv_set::instance();
std::string result;
p = orig.begin();
end = orig.end();
while (chr = next_utf8_char( p, charStart, end )) {
map<int, int>::const_iterator it;
if ((it = equivSet.find(chr)) != equivSet.end()) {
chr = it->second;
}
result.append(codepointToUtf8(chr));
while (chr = utf8::next_utf8_char( p, charStart, end )) {
chr = equivs.get(chr);
result.append(utf8::codepoint_to_utf8(chr));
}
return result;
}
map<int,int> const &
getEquivSet() {
static map<int,int> equivSet;
// Map of codepoint:codepoint
if (equivSet.empty()) {
ifstream eqsFile( EQUIVSET_LOC );
if (!eqsFile) {
throw AFPException( "Unable to open equivalence sets!" );
}
string line;
while (getline(eqsFile,line)) {
size_t pos = line.find_first_of( ":", 0 );
if (pos != line.npos) {
// We have a codepoint:codepoint thing.
int actual = 0;
int canonical = 0;
istringstream actual_buffer(line.substr(0,pos));
istringstream canon_buffer( line.substr(pos+1));
actual_buffer >> actual;
canon_buffer >> canonical;
if (actual != 0 && canonical != 0) {
equivSet[actual] = canonical;
}
}
}
eqsFile.close();
}
return equivSet;
}
// Weak UTF-8 decoder
// Will return garbage on invalid input (overshort sequences, overlong sequences, etc.)
// Stolen from wikidiff2 extension by Tim Starling (no point in reinventing the wheel)
int
next_utf8_char(std::string::const_iterator & p, std::string::const_iterator & charStart,
std::string::const_iterator end)
{
int c=0;
unsigned char byte;
int bytes = 0;
charStart = p;
if (p == end) {
return 0;
}
do {
byte = (unsigned char)*p;
if (byte < 0x80) {
c = byte;
bytes = 0;
} else if (byte >= 0xc0) {
// Start of UTF-8 character
// If this is unexpected, due to an overshort sequence, we ignore the invalid
// sequence and resynchronise here
if (byte < 0xe0) {
bytes = 1;
c = byte & 0x1f;
} else if (byte < 0xf0) {
bytes = 2;
c = byte & 0x0f;
} else {
bytes = 3;
c = byte & 7;
}
} else if (bytes) {
c <<= 6;
c |= byte & 0x3f;
--bytes;
} else {
// Unexpected continuation, ignore
}
++p;
} while (bytes && p != end);
return c;
}
std::size_t
utf8_strlen(std::string const &s)
{
std::size_t ret = 0;
for (std::string::const_iterator it = s.begin(), end = s.end();
it < end; ++it)
{
int skip = 1;
skip = U8_LENGTH(*it);
if (it + skip >= end)
return ret; /* end of string */
it += skip;
}
return ret;
}
/*
* This could almost certainly be done in a nicer way.
*/
std::string
utf8_tolower(std::string const &s)
{
std::vector<UChar> ustring;
UErrorCode error = U_ZERO_ERROR;
for (int i = 0; i < s.size(); ) {
UChar32 c;
U8_NEXT(s.data(), i, s.size(), c);
ustring.push_back(c);
}
std::vector<UChar> dest;
u_strToLower(&dest[0], dest.size(), &ustring[0], ustring.size(),
NULL, &error);
if (U_FAILURE(error))
return s;
std::vector<unsigned char> u8string;
int i, j;
for (i = 0, j = 0; i < dest.size(); j++) {
U8_APPEND_UNSAFE(&u8string[0], i, dest[j]);
}
return std::string(u8string.begin(), u8string.begin() + i);
}
// Ported from MediaWiki core function in PHP.
string
codepointToUtf8(int codepoint) {
string ret;
if(codepoint < 0x80) {
ret.append(1, codepoint);
return ret;
}
if(codepoint < 0x800) {
ret.append(1, codepoint >> 6 & 0x3f | 0xc0);
ret.append(1, codepoint & 0x3f | 0x80);
return ret;
}
if(codepoint < 0x10000) {
ret.append(1, codepoint >> 12 & 0x0f | 0xe0);
ret.append(1, codepoint >> 6 & 0x3f | 0x80);
ret.append(1, codepoint & 0x3f | 0x80);
return ret;
}
if(codepoint < 0x110000) {
ret.append(1, codepoint >> 18 & 0x07 | 0xf0);
ret.append(1, codepoint >> 12 & 0x3f | 0x80);
ret.append(1, codepoint >> 6 & 0x3f | 0x80);
ret.append(1, codepoint & 0x3f | 0x80);
return ret;
}
throw AFPException("Asked for code outside of range ($codepoint)\n");
}
} // namespace afp

View file

@ -1,28 +1,26 @@
#ifndef AFFUNCTIONS_H
#define AFFUNCTIONS_H
#include "aftypes.h"
#include <map>
#include <vector>
AFPData af_length(std::vector<AFPData> const &args);
AFPData af_lcase(std::vector<AFPData> const &args);
AFPData af_ccnorm(std::vector<AFPData> const &args);
AFPData af_rmdoubles(std::vector<AFPData> const &args);
AFPData af_specialratio(std::vector<AFPData> const &args);
AFPData af_rmspecials(std::vector<AFPData> const &args);
AFPData af_norm(std::vector<AFPData> const &args);
AFPData af_count(std::vector<AFPData> const &args);
#include "aftypes.h"
map<int,int> const &getEquivSet();
int next_utf8_char(std::string::const_iterator & p, std::string::const_iterator & charStart, std::string::const_iterator end);
string codepointToUtf8( int codepoint );
string confusable_character_normalise(std::string const &orig);
vector<AFPData> makeFuncArgList( AFPData arg );
AFPData callFunction(string const &name, AFPData arg);
string rmdoubles(string const &orig);
string rmspecials(string const &orig);
std::size_t utf8_strlen(std::string const &s);
std::string utf8_tolower(std::string const &s);
namespace afp {
datum af_length (std::vector<datum> const &args);
datum af_lcase (std::vector<datum> const &args);
datum af_ccnorm (std::vector<datum> const &args);
datum af_rmdoubles (std::vector<datum> const &args);
datum af_specialratio (std::vector<datum> const &args);
datum af_rmspecials (std::vector<datum> const &args);
datum af_norm (std::vector<datum> const &args);
datum af_count (std::vector<datum> const &args);
std::string confusable_character_normalise(std::string const &orig);
std::string rmdoubles(std::string const &orig);
std::string rmspecials(std::string const &orig);
} // namespace afp
#endif /* !AFFUNCTIONS_H */

View file

@ -1,30 +1,27 @@
#include "aftypes.h"
#include <sstream>
#include <ios>
#include <iostream>
#include <cassert>
#include <algorithm>
#include <cmath>
#include <boost/lexical_cast.hpp>
AFPToken::AFPToken(unsigned int new_type, string new_value, unsigned int new_pos) {
type = new_type;
value = new_value;
pos = new_pos;
}
#include "aftypes.h"
namespace afp {
AFPData::AFPData(std::string const &var) {
datum::datum(std::string const &var) {
_init_from_string(var);
}
AFPData::AFPData(char const *var)
datum::datum(char const *var)
{
_init_from_string(var);
}
void
AFPData::_init_from_string(std::string const &var)
datum::_init_from_string(std::string const &var)
{
// Try integer
try {
@ -39,35 +36,35 @@ AFPData::_init_from_string(std::string const &var)
}
}
AFPData::AFPData() {
datum::datum() {
}
AFPData::AFPData(AFPData const &other)
datum::datum(datum const &other)
: value_(other.value_)
{
}
AFPData::AFPData(long int var)
datum::datum(long int var)
: value_(var)
{
}
AFPData::AFPData(double var)
datum::datum(double var)
: value_(var)
{
}
AFPData::AFPData(float var)
datum::datum(float var)
: value_(var)
{
}
AFPData::AFPData(bool var)
datum::datum(bool var)
: value_((long int) var)
{
}
AFPData & AFPData::operator= (AFPData const &other) {
datum & datum::operator= (datum const &other) {
// Protect against self-assignment
if (this == &other) {
return *this;
@ -77,10 +74,6 @@ AFPData & AFPData::operator= (AFPData const &other) {
return *this;
}
bool isInVector(std::string const &needle, std::vector<std::string> const &haystack) {
return std::find(haystack.begin(), haystack.end(), needle) != haystack.end();
}
/*
* Convert a string to an integer value.
*/
@ -108,7 +101,7 @@ struct from_string_converter<std::string> {
};
/*
* Conversions from AFPData to other types.
* Conversions from datum to other types.
*/
struct to_string_visitor : boost::static_visitor<std::string> {
std::string operator() (std::string const &v) const {
@ -156,17 +149,17 @@ struct to_double_visitor : boost::static_visitor<double> {
};
std::string
AFPData::toString() const {
datum::toString() const {
return boost::apply_visitor(to_string_visitor(), value_);
}
long int
AFPData::toInt() const {
datum::toInt() const {
return boost::apply_visitor(to_int_visitor(), value_);
}
double
AFPData::toFloat() const {
datum::toFloat() const {
return boost::apply_visitor(to_double_visitor(), value_);
}
@ -213,13 +206,13 @@ struct afpmodulus<double> {
* after doing appropriate int->double promotion.
*/
template<template<typename V> class Operator>
struct arith_visitor : boost::static_visitor<AFPData> {
struct arith_visitor : boost::static_visitor<datum> {
/*
* Anything involving a double returns a double.
* Otherwise, int is returned.
*/
template<typename T, typename U>
AFPData operator() (T const &a, U const &b) const {
datum operator() (T const &a, U const &b) const {
typedef typename from_string_converter<T>::type a_type;
typedef typename from_string_converter<U>::type b_type;
@ -272,7 +265,7 @@ struct compare_visitor : boost::static_visitor<bool> {
* For comparisons that only work on integers - strings will be converted.
*/
template<template<typename V> class Operator>
struct arith_compare_visitor : boost::static_visitor<AFPData> {
struct arith_compare_visitor : boost::static_visitor<datum> {
template<typename T, typename U>
bool operator() (T const &a, U const &b) const {
typedef typename from_string_converter<T>::type a_type;
@ -285,83 +278,83 @@ struct arith_compare_visitor : boost::static_visitor<AFPData> {
}
};
AFPData &
AFPData::operator+=(AFPData const &other)
datum &
datum::operator+=(datum const &other)
{
AFPData result = boost::apply_visitor(arith_visitor<std::plus>(), value_, other.value_);
datum result = boost::apply_visitor(arith_visitor<std::plus>(), value_, other.value_);
*this = result;
return *this;
}
AFPData &
AFPData::operator-=(AFPData const &other)
datum &
datum::operator-=(datum const &other)
{
AFPData result = boost::apply_visitor(arith_visitor<std::minus>(), value_, other.value_);
datum result = boost::apply_visitor(arith_visitor<std::minus>(), value_, other.value_);
*this = result;
return *this;
}
AFPData &
AFPData::operator*=(AFPData const &other)
datum &
datum::operator*=(datum const &other)
{
AFPData result = boost::apply_visitor(arith_visitor<std::multiplies>(), value_, other.value_);
datum result = boost::apply_visitor(arith_visitor<std::multiplies>(), value_, other.value_);
*this = result;
return *this;
}
AFPData&
AFPData::operator/=(AFPData const &other)
datum&
datum::operator/=(datum const &other)
{
AFPData result = boost::apply_visitor(arith_visitor<std::divides>(), value_, other.value_);
datum result = boost::apply_visitor(arith_visitor<std::divides>(), value_, other.value_);
*this = result;
return *this;
}
AFPData&
AFPData::operator%=(AFPData const &other)
datum&
datum::operator%=(datum const &other)
{
AFPData result = boost::apply_visitor(arith_visitor<afpmodulus>(), value_, other.value_);
datum result = boost::apply_visitor(arith_visitor<afpmodulus>(), value_, other.value_);
*this = result;
return *this;
}
AFPData
operator+(AFPData const &a, AFPData const &b) {
return AFPData(a) += b;
datum
operator+(datum const &a, datum const &b) {
return datum(a) += b;
}
AFPData
operator-(AFPData const &a, AFPData const &b) {
return AFPData(a) -= b;
datum
operator-(datum const &a, datum const &b) {
return datum(a) -= b;
}
AFPData
operator*(AFPData const &a, AFPData const &b) {
return AFPData(a) *= b;
datum
operator*(datum const &a, datum const &b) {
return datum(a) *= b;
}
AFPData
operator/(AFPData const &a, AFPData const &b) {
return AFPData(a) /= b;
datum
operator/(datum const &a, datum const &b) {
return datum(a) /= b;
}
AFPData
operator%(AFPData const &a, AFPData const &b) {
return AFPData(a) %= b;
datum
operator%(datum const &a, datum const &b) {
return datum(a) %= b;
}
bool
operator==(AFPData const &a, AFPData const &b) {
operator==(datum const &a, datum const &b) {
return a.compare(b);
}
bool
AFPData::compare(AFPData const &other) const {
datum::compare(datum const &other) const {
return boost::apply_visitor(compare_visitor<std::equal_to>(), value_, other.value_);
}
bool
AFPData::compare_with_type(AFPData const &other) const {
datum::compare_with_type(datum const &other) const {
if (value_.which() != other.value_.which())
return false;
@ -369,36 +362,38 @@ AFPData::compare_with_type(AFPData const &other) const {
}
bool
AFPData::less_than(AFPData const &other) const {
datum::less_than(datum const &other) const {
return boost::apply_visitor(arith_compare_visitor<std::less>(), value_, other.value_);
}
bool
operator< (AFPData const &a, AFPData const &b) {
operator< (datum const &a, datum const &b) {
return a.less_than(b);
}
bool
operator<= (AFPData const &a, AFPData const &b) {
operator<= (datum const &a, datum const &b) {
return a.less_than(b) || a == b;
}
bool
operator> (AFPData const &a, AFPData const &b) {
operator> (datum const &a, datum const &b) {
return !(a <= b);
}
bool
operator>= (AFPData const &a, AFPData const &b) {
operator>= (datum const &a, datum const &b) {
return !(a < b);
}
bool
operator!= (AFPData const &a, AFPData const &b) {
operator!= (datum const &a, datum const &b) {
return !(a == b);
}
bool
AFPData::operator! () const {
datum::operator! () const {
return !(int) *this;
}
} // namespace afp

View file

@ -8,71 +8,46 @@
#include <boost/variant.hpp>
#include <boost/lexical_cast.hpp>
using namespace std;
namespace afp {
#define T_NONE 0
#define T_ID 1
#define T_KEYWORD 2
#define T_STRING 3
#define T_NUMBER 4
#define T_OP 5
#define T_BRACE 6
#define T_COMMA 7
#define D_NULL 0
#define D_INTEGER 1
#define D_FLOAT 2
#define D_STRING 3
#define DATATYPE_MAX 3
class AFPToken {
class datum {
public:
AFPToken() {}
AFPToken(unsigned int type, string value, unsigned int pos);
unsigned int type;
string value;
unsigned int pos;
};
class AFPData {
public:
AFPData();
datum();
/*
* Generic ctor tries to convert to an int.
*/
template<typename T>
AFPData(T const &v)
datum(T const &v)
: value_(boost::lexical_cast<long int>(v))
{
}
// Specific type constructors
AFPData( std::string const &var );
AFPData( char const *var );
AFPData( long int var );
AFPData( float var );
AFPData( double var );
AFPData( bool var );
datum( std::string const &var );
datum( char const *var );
datum( long int var );
datum( float var );
datum( double var );
datum( bool var );
AFPData( const AFPData & oldData );
datum( const datum & oldData );
// Assignment operator
AFPData &operator= (const AFPData & other);
datum &operator= (const datum & other);
AFPData &operator+=(AFPData const &other);
AFPData &operator-=(AFPData const &other);
AFPData &operator*=(AFPData const &other);
AFPData &operator/=(AFPData const &other);
AFPData &operator%=(AFPData const &other);
datum &operator+=(datum const &other);
datum &operator-=(datum const &other);
datum &operator*=(datum const &other);
datum &operator/=(datum const &other);
datum &operator%=(datum const &other);
bool operator!() const;
bool compare(AFPData const &other) const;
bool compare_with_type(AFPData const &other) const;
bool less_than(AFPData const &other) const;
bool compare(datum const &other) const;
bool compare_with_type(datum const &other) const;
bool less_than(datum const &other) const;
string toString() const;
std::string toString() const;
long int toInt() const;
double toFloat() const;
bool toBool() const {
@ -108,38 +83,40 @@ protected:
valuetype value_;
};
class AFPException :exception {
public:
const char* what() {return this->s;}
AFPException( const char* str ) {s = str;}
AFPException( string str, string var ) { char* s1 = new char[1024]; sprintf( s1, str.c_str(), var.c_str() ); s = s1; }
AFPException( string str, int var ) { char* s1 = new char[1024]; sprintf( s1, str.c_str(), var ); s = s1; }
AFPException( string str, string svar, int ivar ) { char* s1 = new char[1024]; sprintf( s1, str.c_str(), ivar, svar.c_str() ); s = s1; }
private:
const char* s;
class exception : std::exception {
public:
exception(std::string const &what)
: what_(what) {}
~exception() throw() {}
char const *what() const throw() {
return what_.c_str();
}
private:
std::string what_;
};
AFPData operator+(AFPData const &a, AFPData const &b);
AFPData operator-(AFPData const &a, AFPData const &b);
AFPData operator*(AFPData const &a, AFPData const &b);
AFPData operator/(AFPData const &a, AFPData const &b);
AFPData operator%(AFPData const &a, AFPData const &b);
datum operator+(datum const &a, datum const &b);
datum operator-(datum const &a, datum const &b);
datum operator*(datum const &a, datum const &b);
datum operator/(datum const &a, datum const &b);
datum operator%(datum const &a, datum const &b);
bool operator==(AFPData const &a, AFPData const &b);
bool operator!=(AFPData const &a, AFPData const &b);
bool operator<(AFPData const &a, AFPData const &b);
bool operator>(AFPData const &a, AFPData const &b);
bool operator<=(AFPData const &a, AFPData const &b);
bool operator>=(AFPData const &a, AFPData const &b);
bool operator==(datum const &a, datum const &b);
bool operator!=(datum const &a, datum const &b);
bool operator<(datum const &a, datum const &b);
bool operator>(datum const &a, datum const &b);
bool operator<=(datum const &a, datum const &b);
bool operator>=(datum const &a, datum const &b);
template<typename char_type, typename traits>
std::basic_ostream<char_type, traits> &
operator<<(std::basic_ostream<char_type, traits> &s, AFPData const &d) {
operator<<(std::basic_ostream<char_type, traits> &s, datum const &d) {
d.print_to(s);
return s;
}
bool isInVector(std::string const &needle, std::vector<std::string> const &haystack);
} // namespace afp
#endif /* !AFTYPES_H */

View file

@ -2,15 +2,15 @@
#include "affunctions.h"
int main( int argc, char** argv ) {
filter_evaluator f;
afp::filter_evaluator f;
bool result = false;
for(int i=0;i<=100;i++) {
try {
f.add_variable( "foo", AFPData(string("love")) );
f.add_variable("foo", afp::datum("love"));
result = f.evaluate( "specialratio('foo;') == 0.25" );
} catch (AFPException* excep) {
} catch (afp::exception* excep) {
printf( "Exception: %s\n", excep->what() );
}
}

View file

@ -1,25 +1,24 @@
#include <cstdlib>
#include <iostream>
#include <string>
#include <sstream>
#include <map>
#include "filter_evaluator.h"
#include "request.h"
int main( int argc, char** argv ) {
request r;
string result;
int main(int argc, char** argv)
{
afp::request r;
std::string result;
try {
if (!r.load(std::cin))
return 1;
result = r.evaluate();
} catch (AFPException excep) {
cout << "EXCEPTION: " << excep.what() << endl;
cerr << "EXCEPTION: " << excep.what() << endl;
} catch (afp::exception &excep) {
std::cout << "EXCEPTION: " << excep.what() << std::endl;
std::cerr << "EXCEPTION: " << excep.what() << std::endl;
}
cout << result << "\0";
std::cout << result << "\0";
}

View file

@ -2,6 +2,8 @@
#include "parser.h"
#include "affunctions.h"
namespace afp {
filter_evaluator::filter_evaluator()
{
e.add_function("length", af_length);
@ -26,8 +28,9 @@ filter_evaluator::evaluate(std::string const &filter) const
}
void
filter_evaluator::add_variable(std::string const &key, AFPData value)
filter_evaluator::add_variable(std::string const &key, datum value)
{
e.add_variable(key, value);
}
} // namespace afp

View file

@ -7,15 +7,19 @@
#include "aftypes.h"
#include "parser.h"
namespace afp {
struct filter_evaluator {
filter_evaluator();
bool evaluate(std::string const &filter) const;
void add_variable(std::string const &key, AFPData value);
void add_variable(std::string const &key, datum value);
private:
expressor e;
};
} // namespace afp
#endif /* !FILTER_EVALUATOR_H */

View file

@ -15,7 +15,7 @@
int main( int argc, char** argv ) {
while (true) {
request r;
afp::request r;
bool result = false;
try {
@ -35,11 +35,11 @@ int main( int argc, char** argv ) {
}
result = r.evaluate();
} catch (AFPException &excep) {
cerr << "EXCEPTION: " << excep.what() << endl;
} catch (afp::exception &excep) {
std::cerr << "EXCEPTION: " << excep.what() << std::endl;
}
cout << ( result ? "MATCH\n" : "NOMATCH\n" );
std::cout << ( result ? "MATCH\n" : "NOMATCH\n" );
}
}

View file

@ -13,6 +13,8 @@ af_expr_objs = \
af_expr-parser.o \
af_expr-filter_evaluator.o \
af_expr-eval.o \
af_expr-utf8.o \
af_expr-equiv.o \
af_expr-request.o
af_parser_objs = \
@ -21,6 +23,8 @@ af_parser_objs = \
af_parser-main.o \
af_parser-parser.o \
af_parser-request.o \
af_parser-utf8.o \
af_parser-equiv.o \
af_parser-filter_evaluator.o
check_objs = \
@ -28,6 +32,8 @@ check_objs = \
check-aftypes.o \
check-check.o \
check-parser.o \
check-utf8.o \
check-equiv.o \
check-filter_evaluator.o
syntax_check_objs = \
@ -35,6 +41,8 @@ syntax_check_objs = \
syntax_check-aftypes.o \
syntax_check-filter_evaluator.o \
syntax_check-parser.o \
syntax_check-utf8.o \
syntax_check-equiv.o \
syntax_check-syntax_check.o
expr_objs = \

View file

@ -8,6 +8,7 @@
#include <boost/spirit/phoenix/operators.hpp>
#include <boost/function.hpp>
#include <boost/noncopyable.hpp>
#include <boost/format.hpp>
#include "aftypes.h"
#include "parser.h"
@ -17,30 +18,32 @@ using namespace phoenix;
namespace px = phoenix;
namespace afp {
struct parse_error : std::runtime_error {
parse_error(char const *what) : std::runtime_error(what) {}
};
struct parser_closure : boost::spirit::closure<parser_closure, AFPData>
struct parser_closure : boost::spirit::closure<parser_closure, datum>
{
member1 val;
};
namespace {
AFPData f_in(AFPData const &a, AFPData const &b)
datum f_in(datum const &a, datum const &b)
{
std::string sa = a, sb = b;
return AFPData(std::search(sb.begin(), sb.end(), sa.begin(), sa.end()) != sb.end());
return datum(std::search(sb.begin(), sb.end(), sa.begin(), sa.end()) != sb.end());
}
}
struct function_closure : boost::spirit::closure<
function_closure,
AFPData,
boost::function<AFPData (std::vector<AFPData>)>,
std::vector<AFPData> >
datum,
boost::function<datum (std::vector<datum>)>,
std::vector<datum> >
{
member1 val;
member2 func;
@ -49,14 +52,14 @@ struct function_closure : boost::spirit::closure<
struct parser_grammar : public grammar<parser_grammar, parser_closure::context_t>
{
symbols<AFPData> variables;
symbols<boost::function<AFPData (std::vector<AFPData>)> > functions;
symbols<datum> variables;
symbols<boost::function<datum (std::vector<datum>)> > functions;
void add_variable(std::string const &name, AFPData const &value) {
void add_variable(std::string const &name, datum const &value) {
variables.add(name.c_str(), value);
}
void add_function(std::string const &name, boost::function<AFPData (std::vector<AFPData>)> func) {
void add_function(std::string const &name, boost::function<datum (std::vector<datum>)> func) {
functions.add(name.c_str(), func);
}
@ -84,11 +87,11 @@ struct parser_grammar : public grammar<parser_grammar, parser_closure::context_t
struct call_function_impl {
template<typename F, typename A>
struct result {
typedef AFPData type;
typedef datum type;
};
template<typename F, typename A>
AFPData operator() (F const &func, A const &args) const {
datum operator() (F const &func, A const &args) const {
return func(args);
}
};
@ -173,9 +176,9 @@ struct parser_grammar : public grammar<parser_grammar, parser_closure::context_t
"==" >> eq_expr[eq2_expr.val = eq2_expr.val == arg1]
| "!=" >> eq_expr[eq2_expr.val = eq2_expr.val != arg1]
| "===" >> eq_expr[eq2_expr.val =
bind(&AFPData::compare_with_type)(eq2_expr.val, arg1)]
bind(&datum::compare_with_type)(eq2_expr.val, arg1)]
| "!==" >> eq_expr[eq2_expr.val =
!bind(&AFPData::compare_with_type)(eq2_expr.val, arg1)]
!bind(&datum::compare_with_type)(eq2_expr.val, arg1)]
)
;
@ -198,7 +201,7 @@ struct parser_grammar : public grammar<parser_grammar, parser_closure::context_t
}
rule_t value, variable, basic, bool_expr,
eq_expr, eq2_expr, mult_expr, plus_expr, in_expr, not_expr, expr;
eq_expr, eq2_expr, mult_expr, plus_expr, in_expr, expr;
rule<ScannerT, function_closure::context_t> function;
};
};
@ -213,12 +216,13 @@ expressor::~expressor()
delete grammar_;
}
AFPData
datum
expressor::evaluate(std::string const &filter) const
{
AFPData ret;
datum ret;
parse_info<std::string::const_iterator> info =
parse(filter.begin(), filter.end(), (*grammar_)[var(ret) = arg1], space_p);
parse(filter.begin(), filter.end(), (*grammar_)[var(ret) = arg1],
comment_p("/*", "*/") | chset<>("\n\t "));
if (info.full) {
return ret;
} else {
@ -228,7 +232,7 @@ expressor::evaluate(std::string const &filter) const
}
void
expressor::add_variable(std::string const &name, AFPData value)
expressor::add_variable(std::string const &name, datum value)
{
grammar_->add_variable(name, value);
}
@ -239,13 +243,17 @@ expressor::add_function(std::string const &name, func_t value)
grammar_->add_function(name, value);
}
} // namespace afp
#ifdef TEST_PARSER
AFPData f_add(std::vector<AFPData> const &args)
afp::datum
f_add(std::vector<afp::datum> const &args)
{
return args[0] + args[1];
}
AFPData f_norm(std::vector<AFPData> const &args)
afp::datum
f_norm(std::vector<afp::datum> const &args)
{
return args[0];
}
@ -253,7 +261,13 @@ AFPData f_norm(std::vector<AFPData> const &args)
int
main(int argc, char **argv)
{
expressor e;
if (argc != 2) {
std::cerr << boost::format("usage: %s <expr>\n")
% argv[0];
return 1;
}
afp::expressor e;
e.add_variable("ONE", 1);
e.add_variable("TWO", 2);
e.add_variable("THREE", 3);

View file

@ -9,21 +9,25 @@
#include "aftypes.h"
namespace afp {
struct parser_grammar;
struct expressor : boost::noncopyable {
typedef boost::function<AFPData (std::vector<AFPData>)> func_t;
typedef boost::function<datum (std::vector<datum>)> func_t;
expressor();
~expressor();
AFPData evaluate(std::string const &expr) const;
datum evaluate(std::string const &expr) const;
void add_variable(std::string const &name, AFPData value);
void add_variable(std::string const &name, datum value);
void add_function(std::string const &name, func_t value);
private:
parser_grammar *grammar_;
};
} // namespace afp
#endif /* !EXPRESSOR_H */

View file

@ -1,11 +1,13 @@
#include "request.h"
namespace afp {
// Protocol:
// code NULL <key> NULL <value> NULL ... <value> NULL NULL
bool
request::load(std::istream &inp) {
inp.unsetf(ios_base::skipws);
inp.unsetf(std::ios_base::skipws);
std::istream_iterator<char> it(inp), p, end;
@ -55,7 +57,7 @@ request::load(std::istream &inp) {
it++;
f.add_variable(key, AFPData(value));
f.add_variable(key, datum(value));
}
return true;
@ -67,3 +69,4 @@ request::evaluate()
return f.evaluate(filter);
}
} // namespace afp

View file

@ -6,6 +6,8 @@
#include "filter_evaluator.h"
namespace afp {
struct request {
bool load(std::istream &);
bool evaluate(void);
@ -15,4 +17,6 @@ private:
std::string filter;
};
} // namespace afp
#endif /* !REQUEST_H */

View file

@ -5,21 +5,22 @@
#include "filter_evaluator.h"
int main( int argc, char** argv ) {
stringbuf ss( ios::in | ios::out );
int main(int argc, char** argv)
{
std::stringbuf ss( std::ios::in | std::ios::out );
// Fill the stringstream
cin.get(ss,'\x04');
std::cin.get(ss,'\x04');
string filter = ss.str();
std::string filter = ss.str();
try {
filter_evaluator f;
afp::filter_evaluator f;
f.evaluate(filter);
} catch (AFPException excep) {
cout << "PARSERR: " << excep.what() << endl;
exit(0);
} catch (afp::exception &excep) {
std::cout << "PARSERR: " << excep.what() << std::endl;
std::exit(0);
}
cout << "SUCCESS" << endl;
std::cout << "SUCCESS" << std::endl;
}