Re: Decision Tables



On Jan 30, 7:15 pm, Ben Bacarisse <ben.use...@xxxxxxxxx> wrote:
kwikius <a...@xxxxxxxxxxxxxxxxxxxxxxxxx> writes:
On Jan 30, 3:46 pm, Ben Bacarisse <ben.use...@xxxxxxxxx> wrote:
<snip>
Much easier to read but you can't store it in a data structure.  

I don't see why not.
<snip>
Heres a simple hack version.

Sure.  I was only saying that we were (originally) talking about
different things.

<sniped code to store an execute a match query>

Whatever...

Anyway I found the bugs (and errors in the grammar).
Main bug was I was using && and || which of course lazily evaluates
which meant that the parser didnt parse !

Also reckon that record to record matching doesnt seem very intuitive
so it now changed to do a comparison of field with name e.g:

first_name = John && !( last_name != Smith || country = England )

Also added a basic datafile mockup so there are a few records to match
for testing

What would be nice is to add match againt regular expressions. It
would be quite useful then..

Anyway, it seems to work OK now:

regards
Andy Little

#include <string>
#include <vector>
#include <cstring>
#include <stdexcept>

namespace my{
// data records
struct D{
D(std::string const & fn,
std::string const & ln,
std::string const & c
): first_name(fn),last_name(ln),country(c){}
D(){}
std::string first_name;
std::string last_name;
std::string country;
};

}//my


/*
query grammar
//terminals
string : //
field_match : string = string
field_match : string != string
End //end of input
//
not_expr : field_match
not_expr : !not_expr
not_expr : ( expr )

expr : End
expr : and_expr
expr : expr || and_expr

and_expr : not_expr
and_expr : and_expr && not_expr

*/

#include <iostream>
#include <map>

namespace parser{

std::string cur_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,EQ,NEQ,END};
token cur_tok = END;

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 '!':
in.get(ch);
if (ch == '='){
return cur_tok = NEQ;
}
else{
in.putback(ch);
return cur_tok = NOT;
}
case '=':
return cur_tok = EQ;
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::cur_name = ch;
while(in.get(ch) && (isalnum(ch) || ch == '_')){
parser::cur_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 & d);
bool and_expr(std::istream & in,my::D const & d);
bool expr( std::istream & in,my::D const & d);

template <typename T, typename V>
inline
bool match ( T const & lhs, V T::* ps, V const & v)
{
return lhs.*ps == v;
}

bool not_expr(std::istream & in,my::D const & d)
{
switch (lexer::tok(in)){
case lexer::MATCH : {
std::string field = cur_name;
if ( members.find(field) != members.end()){
if ( (lexer::tok(in) == lexer::EQ)
|| (lexer::cur_tok == lexer::NEQ) ){
bool is_eq = lexer::cur_tok == lexer::EQ;
if (lexer::tok(in) == lexer::MATCH){
bool b = match(d,members[field],cur_name);
return is_eq ? b :!b;
}
else {
throw std::runtime_error(
"Expected literal match string"
);
}
}

else {
throw std::runtime_error("expected '='");
}
}
else{
throw std::runtime_error(
"field name not found \"" + field + "\""
);
}
}
case lexer::NOT :
return ! not_expr(in,d);
case lexer::LB:{
bool b = expr(in,d);
if ( lexer::tok(in) != lexer::RB){
throw std::runtime_error("expected ')'");
}
return b;
}
default:
throw std::runtime_error("expected not_expr");
}
}

bool and_expr( std::istream & in,my::D const & d)
{
bool left = not_expr(in,d);
for(;;){
switch ( lexer::tok(in)){
case lexer::AND:{
left = not_expr(in,d) && left;
break;
}
default:
lexer::putback();
return left;
}
}
}

bool expr( std::istream & in,my::D const & d)
{
lexer::detail::putback_ = false;
bool left = and_expr(in,d);
for(;;){
switch ( lexer::tok(in)){
case lexer::OR:{
left = and_expr(in,d) || left;
break;
}
default:
lexer::putback();
return left;
}
}
}

}//parser

#include <sstream>
#include <vector>

int main()
{
parser::members["first_name"] = &my::D::first_name;
parser::members["last_name"] = &my::D::last_name;
parser::members["country"] = &my::D::country;

std::cout <<
"..... ASQE (Andy's Simple Query Engine)....\n"
"See source grammar for query syntax\n"
"............................................\n\n";

//simulate reading in data from database...
std::string file =
"John Smith England\n"
"John Jones England\n"
"Mary Smith Wales\n"
"Jim McGregor Scotland\n"
"John McGregor Scotland\n"
"John Smith Wales\n"
"John McGregor Wales\n"
"Mary Smith England\n"
"Mary McGregor England\n";

std::vector<my::D> records;

std::istringstream fin(file);
while( fin){
my::D t;
if ((fin >> t.first_name >> t.last_name >> t.country) ){
records.push_back(t);
}
else{
std::cout << "found "
<< static_cast<unsigned int>(records.size())
<< " file records\n\n";
break;
}
}

std::cout << "Example query\n\"first_name = John && "
" !( last_name != Smith || country = England )\"\n"
"(Empty query to quit)\n\n";

for(;;){
std::cout
<< "Enter query on fields first_name, last_name, country\n ";
std::string query;
getline(std::cin,query);
if( query == ""){
std::cout << "Quitting....\n";
break;
}
std::vector<my::D> results;
try{
for ( std::size_t i = 0; i != records.size() ;++i){
std::istringstream in(query);
if (parser::expr(in,records[i])){
results.push_back(records[i]);
}
}
if (!results.size()){
std::cout << "no matches found\n";
}
else{
for( std::size_t i =0; i != results.size();++i){
std::cout << results[i].first_name
<< ' ' << results[i].last_name
<< ' ' << results[i].country
<< '\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;
}
}
}
}



.



Relevant Pages

  • Re: comma in a list box
    ... Thanks John, but I want to avoid using another table or a query if I can. ... The text goes into the list box from string variables. ... Static qNum As Long ...
    (microsoft.public.access.formscoding)
  • Re: rename files in directory
    ... When I run your script I get an error: " Microsoft VBScript runtime error: ... contain a " - " string. ... as part of the query. ...
    (microsoft.public.scripting.vbscript)
  • Re: Cant figure out how to use [ Querystring(arg) ] in data view
    ... string seems like the answer at first glance. ... > This is easiest to accomplish by using Web Part connections instead of the ... > John Jansen ... >> query string. ...
    (microsoft.public.sharepoint.windowsservices)
  • Multi field search
    ... Is there a way to construct one query that will search across more than one ... I want to find all instances of the word string "John" which can ... John Johnson ...
    (microsoft.public.access.forms)
  • Re: Problems with Delete Command
    ... The SQL could get fairly messy if you need to construct it in code, ... ContactID, and WebComID, and create your on-the-fly SQL on that saved query, ... to find the list of ContactIDs from the junction table, ... This is a style/readability thing: if you are going to use string ...
    (microsoft.public.access.tablesdbdesign)