Re: Decision Tables



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;
}
}
}
}






.



Relevant Pages

  • Re: Simple xpath query with default namespace
    ... query (a prefix that's no actually in the xml) in order for the library ... whether it's the default namespace. ... then when you have your XPath query you will need to tell XPath which Account ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: [OT-ish] Design principles: no bool arguments
    ... Python does not have) versus keyword-optional or keyword only. ... callers always have the 'keyword = BOOL' option. ... def spam_off: ... Note that naming the function 'switch' and putting the bool as ...
    (comp.lang.python)
  • Building a Dataset with Access
    ... I have another question about this process of getting a connection set up ... and then populating a drop-down list box with a query. ... "The type or namespace name 'dsStatements' does not exist in the class or ... namespace 'TrainOfThought.TrainOfThought' (are you missing an assembly ...
    (microsoft.public.dotnet.framework.aspnet)
  • Building a Dataset with Access
    ... I have another question about this process of getting a connection set up ... and then populating a drop-down list box with a query. ... "The type or namespace name 'dsStatements' does not exist in the class or ... namespace 'TrainOfThought.TrainOfThought' (are you missing an assembly ...
    (microsoft.public.dotnet.framework.adonet)
  • Re: Using Access with Data Object Connections
    ... I have another question about this process of getting a connection set ... up and then populating a drop-down list box with a query. ... "The type or namespace name 'dsStatements' does not exist in the class ...
    (microsoft.public.dotnet.framework.adonet)