#include <iostream>
#include <fstream>
#include <stack>
#include <boost/spirit/core.hpp>
#include "TextQuery.h"
#include "Query.h"
using namespace std;
using namespace boost::spirit;
namespace
{
stack<Query> queryStack;
void do_string(char const* str, char const* end)
{
string s(str, end);
queryStack.push(Query(s));
}
void do_add(char const*, char const*)
{
Query rhs=queryStack.top();
queryStack.pop();
Query lhs=queryStack.top();
queryStack.pop();
Query result=lhs & rhs;
queryStack.push(result);
}
void do_or(char const*, char const*)
{
Query rhs=queryStack.top();
queryStack.pop();
Query lhs=queryStack.top();
queryStack.pop();
Query result=lhs | rhs;
queryStack.push(result);
}
void do_not(char const*, char const*)
{
Query rhs=queryStack.top();
queryStack.pop();
Query result=~rhs;
queryStack.push(result);
}
}
struct calculator : public grammar<calculator>
{
template <typename ScannerT>
struct definition
{
definition(calculator const& /*self*/)
{
expression
= factor
>> *( ('&' >> factor)[&do_add]
| ('|' >> factor)[&do_or]
)
;
factor
= lexeme_d[(+alpha_p)[&do_string]]
| '(' >> expression >> ')'
| ('~' >> factor)[&do_not]
;
}
rule<ScannerT> expression, term, factor;
rule<ScannerT> const&
start() const { return expression; }
};
};
inline string make_plural(size_t ctr, const string& word, const string& ending)
{
return (ctr==1)?word:word+ending;
}
void print_results(const set<TextQuery::line_no>& locs, const string& sought, const TextQuery &file)
{
//if the word was found, then print count and all occurrences
typedef set<TextQuery::line_no> line_nums;
line_nums::size_type size=locs.size();
cout<</*"\n"<<sought<<*/" occurs "
<<size<<" "
<<make_plural(size, "time", "s")<<endl;
//print each line in which the word appeared
line_nums::const_iterator it=locs.begin();
for(;it!=locs.end(); ++it)
{
cout<<"\t(line "
//don't confound user with text lines starting at ()
<<(*it)+1<<" ) "
<<file.text_line(*it)<<endl;
}
}
//program takes single argument specifying the file to query
int main(int argc, char **argv)
{
//open the file from which user will query words
if(argc<2)
{
cerr<<"no input file!"<<endl;
return EXIT_FAILURE;
}
ifstream infile(argv[1]);
if(infile.fail())
{
cerr<<"no input file!"<<endl;
return EXIT_FAILURE;
}
TextQuery tq;
tq.read_file(infile); //builds query map
//iterate with the user: prompt for a word to find and print results
//loop indefinitely: the loop exit is inside the while
calculator calc;
while(true)
{
cout<<"enter word to look for, or q to quit: ";
string s;
getline(cin,s);
//stop if hit eof on input or a 'q' is entered
if(!cin || s=="q" || s=="Q") break;
//get the set of line numbers on which this word appears
parse_info<> info = parse(s.c_str(), calc, space_p);
if (info.full)
{
Query query=queryStack.top();
set<TextQuery::line_no> locs=query.eval(tq);
query.display(cout);
print_results(locs, s, tq);
}
else
{
cout << "-------------------------\n";
cout << "Parsing failed\n";
cout << "stopped at: \": " << info.stop << "\"\n";
cout << "-------------------------\n";
}
}
return 0;
}