Re: Decision Tables
- From: kwikius <andy@xxxxxxxxxxxxxxxxxxxxxxxxx>
- Date: Wed, 30 Jan 2008 09:18:29 -0800 (PST)
On Jan 30, 3:46 pm, Ben Bacarisse <ben.use...@xxxxxxxxx> wrote:
kwikius <a...@xxxxxxxxxxxxxxxxxxxxxxxxx> writes:
complex_match[] = { match_contry, match_not, match_first_name,
match_or, NULL };
"
which is a static expression, and with the stack machine the language
is something like Forth ?
Just an array of function pointers. I missed out the bit where the
expression would be evaluated bu looping though the array calling the
functions.
<...>
"first_name && (last_name || country)"
which is IMO easier to comprehend than:
"match_country match_not, match_first_name,
match_or"
Much easier to read by you can't store it in a data structure.
I don't see why not. You could use a stack, but my first option would
be to use a tree of nodes representing the expression. You build the
tree from your text script, and then call it on the records you want
to examine.
Heres a simple hack version. Its based very much on the calculator
example in Bjarne Stroustrups The C++ programming language. It has
some bugs unfortunately possibly because the character input and
termination is not clearly specified.
Here the expression is evaluated on the fly, but it would be simple
to modify to create a presistent tree structure which you could call
on lists of records
In fact despite the bugs I find it potentially quite cool. It would be
nice to match against literal strings and regexes though currently it
does only record to record matches, so probably would need a rethink.
Interestingly IIRC SQL doesnt handle regexes.
Any way here is as far as I got FWIW:
Remember it's a hack and has some bugs :-)
regards
Andy Little
#include <string>
#include <vector>
#include <cstring>
#include <stdexcept>
namespace my{
// data entries
struct D{
D(std::string const & fn,std::string const & ln, std::string
const & c)
: first_name(fn),last_name(ln),country(c){}
std::string first_name;
std::string last_name;
std::string country;
};
}//my
/*
query grammar
//terminal
field_name : string // name referring to a field in D
End //end of input
//
not_expr : field_name
not_expr : ! not_expr
not_expr : ( expr )
expr : End
expr : or_expr
expr : expr && or_expr
or_expr : not_expr
or_expr : or_expr || not_expr
*/
#include <iostream>
#include <map>
namespace parser{
std::string field_name;
typedef std::map<std::string, std::string my::D::* > member_map;
member_map members;
}
namespace lexer{
enum token{ MATCH,AND,OR,NOT,LB,RB,END};
token cur_tok;
namespace detail{
bool putback_ = false;
}
void putback()
{
if (detail::putback_){
throw std::logic_error("too many putbacks");
}
detail::putback_ =true;
}
token tok( std::istream & in)
{
if (detail::putback_){
detail::putback_ = false;
return cur_tok;
}
char ch=0;
in >> ch;
switch (ch){
case 0:
return cur_tok = END;
case '!':
return cur_tok = NOT;
case '(':
return cur_tok = LB;
case ')':
return cur_tok = RB;
case '|':
if (in.get() != '|'){
throw std::runtime_error("no bit or ops");
}
return cur_tok = OR;
case '&':
if (in.get() != '&'){
throw std::runtime_error("no bit and ops");
}
return cur_tok = AND;
default:
if( isalpha(ch)){
parser::field_name = ch;
while(in.get(ch) && (isalnum(ch) || ch == '_')){
parser::field_name += ch;
}
in.putback(ch);
return cur_tok = MATCH;
}
else{
throw std::runtime_error("unexpected input");
}
}
}
}
namespace parser{
bool not_expr(std::istream & in,my::D const & d1, my::D const &
d2);
bool or_expr(std::istream & in,my::D const & d1, my::D const & d2);
bool expr( std::istream & in,my::D const & d1, my::D const & d2);
template <typename T, typename V>
inline
bool match ( T const & lhs, T const & rhs, V T::* ps)
{
return lhs.*ps == rhs.*ps;
}
bool not_expr(std::istream & in,my::D const & d1, my::D const & d2)
{
switch (lexer::tok(in)){
case lexer::MATCH : {
if ( members.find(field_name) != members.end()){
return match(d1,d2,members[field_name]);
}
throw std::runtime_error("field name not found \"" +
field_name + "\"");
}
case lexer::NOT :
return ! not_expr(in,d1,d2);
case lexer::LB:{
bool b = expr(in,d1,d2);
int t = lexer::tok(in) ;
if ( t != lexer::RB){
std::cout << "||" << t << "\n";
throw std::runtime_error("expected ')'");
}
return b;
}
default:
throw std::runtime_error("expected not_expr");
}
}
bool or_expr( std::istream & in,my::D const & d1, my::D const & d2)
{
bool left = not_expr(in,d1,d2);
for(;;){
switch ( lexer::tok(in)){
case lexer::OR:
left = left || not_expr(in,d1,d2);
break;
default:
lexer::putback();
return left;
}
}
}
bool expr( std::istream & in,my::D const & d1, my::D const & d2)
{
bool left = or_expr(in,d1,d2);
for(;;){
switch ( lexer::tok(in)){
case lexer::AND:
left = left && or_expr(in,d1,d2);
break;
default:
lexer::putback();
return left;
}
}
}
}//parser
#include <sstream>
int main()
{
parser::members["first_name"] = &my::D::first_name;
parser::members["last_name"] = &my::D::last_name;
parser::members["country"] = &my::D::country;
my::D d1("John","Smith","England");
my::D d2("John","Jones","England");
std::cout <<
"..... ASQE (Andy's Simple Query Engine)....\n"
"See source grammar for query syntax\n"
"Example \"first_name && ( last_name || country )\"\n"
"(Empty query to quit)\n"
"............................................\n\n";
bool quit = false;
while(!quit){
std::cout << "Enter query on first_name, last_name, country\n ";
std::string query;
getline(std::cin,query);
if( query ==""){
std::cout << "Quitting....\n";
break;
}
try{
std::istringstream in(query);
//kludge
lexer::detail::putback_ = false;
bool result = parser::expr(in,d1,d2);
std::cout << " = " << std::boolalpha << result <<'\n';
}catch(std::exception & e){
std::cout << "\nError : " << e.what() <<'\n';
std::cout << "continue y/n? : ";
std::string str;
getline(std::cin,str);
if ( str != "y") {
break;
}
}
}
}
.
- Follow-Ups:
- Re: Decision Tables
- From: Ben Bacarisse
- Re: Decision Tables
- References:
- Decision Tables
- From: Leslie Sanford
- Re: Decision Tables
- From: Ben Bacarisse
- Re: Decision Tables
- From: kwikius
- Re: Decision Tables
- From: kwikius
- Re: Decision Tables
- From: Ben Bacarisse
- Re: Decision Tables
- From: kwikius
- Re: Decision Tables
- From: Ben Bacarisse
- Decision Tables
- Prev by Date: Re: Decision Tables
- Next by Date: Re: Decision Tables
- Previous by thread: Re: Decision Tables
- Next by thread: Re: Decision Tables
- Index(es):
Relevant Pages
|