split.h
see Note 6
grammar.txt
<noun> cat
<noun> dog
<noun> table
<noun-phrase> <noun>
<noun-phrase> <adjective> <noun-phrase>
<adjective> large
<adjective> brown
<adjective> absurd
<verb> jumps
<verb> sits
<location> on the stairs
<location> under the sky
<location> wherever it wants
<sentence> the <noun-phrase> <verb> <location>
main.cpp
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include <stdlib.h>
#include <stdexcept>
#include <fstream>
#include "split.h"
using std::cout; using std::endl; using std::domain_error;
using std::string; using std::vector; using std::istream;
using std::map; using std::ifstream; using std::logic_error;
using std::cerr;
typedef vector<string> Rule;
typedef vector<Rule> Rule_collection;
typedef map<string, Rule_collection> Grammar;
Grammar read_grammar(ifstream& infile) {
Grammar ret;
string line;
while(getline(infile, line)) {
vector<string> entry = split(line);
if(!entry.empty()) {
Rule rules(entry.begin() + 1, entry.end());
ret[entry[0]].push_back(rules);
}
}
return ret;
}
int nrand(int n) {
if (n < 0 || n > RAND_MAX)
throw domain_error("Argument to nrand is out of range");
const int bucket_size = RAND_MAX / n;
int r;
do r = rand() / bucket_size;
while (r > n);
return r;
}
bool bracketed(const string& s) {
return s[0] == '<' && s[s.size() - 1] == '>';
}
void gen_aux(const Grammar& g, const string& s, vector<string>& v) {
if (bracketed(s)){
Grammar::const_iterator it = g.find(s);
if (it == g.end())
throw logic_error("empty error");
const Rule_collection& rc = it->second;
const Rule r = rc[nrand(rc.size())];
for (Rule::size_type i = 0; i != r.size(); ++i)
gen_aux(g, r[i], v);
} else
v.push_back(s);
}
vector<string> gen_sentence(const Grammar& g) {
vector<string> ret;
gen_aux(g, "<sentence>", ret);
return ret;
}
int main() {
string ifile = "grammar.txt";
ifstream infile(ifile.c_str());
// check that the open succeede
if (!infile) {
cerr << "error: unable to open input file: "
<< ifile << endl;
return -1;
}
// generate the sentence
Grammar g = read_grammar(infile);
vector<string> sentence = gen_sentence(g);
// write the first word, if any
vector<string>::const_iterator it = sentence.begin();
if(!sentence.empty()) {
cout << *it;
++it;
}
// write the rest of the word, each preceded by a space
while (it != sentence.end()) {
cout << " " << *it;
++it;
}
cout << endl;
return 0;
}