about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt6
-rw-r--r--furries.cpp16
-rw-r--r--generator.cpp1303
-rw-r--r--progress.h50
-rw-r--r--schema.sql59
-rw-r--r--verbly/adjective.cpp586
-rw-r--r--verbly/adjective.h126
-rw-r--r--verbly/adverb.cpp364
-rw-r--r--verbly/adverb.h75
-rw-r--r--verbly/data.cpp50
-rw-r--r--verbly/data.h275
-rw-r--r--verbly/noun.cpp916
-rw-r--r--verbly/noun.h171
-rw-r--r--verbly/token.cpp53
-rw-r--r--verbly/token.h82
-rw-r--r--verbly/util.h53
-rw-r--r--verbly/verb.cpp193
-rw-r--r--verbly/verb.h68
-rw-r--r--verbly/verbly.h7
-rw-r--r--verbly/word.cpp32
-rw-r--r--verbly/word.h35
21 files changed, 4043 insertions, 477 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b6d991..3a884b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -8,11 +8,15 @@ pkg_check_modules(YamlCpp yaml-cpp REQUIRED)
8pkg_check_modules(sqlite3 sqlite3 REQUIRED) 8pkg_check_modules(sqlite3 sqlite3 REQUIRED)
9find_package(libxml2 REQUIRED) 9find_package(libxml2 REQUIRED)
10 10
11add_library(verbly verbly/data.cpp verbly/adjective.cpp verbly/noun.cpp verbly/verb.cpp verbly/adverb.cpp verbly/token.cpp verbly/word.cpp)
12set_property(TARGET verbly PROPERTY CXX_STANDARD 11)
13set_property(TARGET verbly PROPERTY CXX_STANDARD_REQUIRED ON)
14
11include_directories(vendor/twitcurl/libtwitcurl ${LIBXML2_INCLUDE_DIR} ${sqlite3_INCLUDE_DIR}) 15include_directories(vendor/twitcurl/libtwitcurl ${LIBXML2_INCLUDE_DIR} ${sqlite3_INCLUDE_DIR})
12add_executable(furries furries.cpp) 16add_executable(furries furries.cpp)
13set_property(TARGET furries PROPERTY CXX_STANDARD 11) 17set_property(TARGET furries PROPERTY CXX_STANDARD 11)
14set_property(TARGET furries PROPERTY CXX_STANDARD_REQUIRED ON) 18set_property(TARGET furries PROPERTY CXX_STANDARD_REQUIRED ON)
15target_link_libraries(furries ${sqlite3_LIBRARIES} ${YamlCpp_LIBRARIES} twitcurl curl) 19target_link_libraries(furries ${sqlite3_LIBRARIES} ${YamlCpp_LIBRARIES} twitcurl curl verbly)
16 20
17add_executable(generator generator.cpp) 21add_executable(generator generator.cpp)
18set_property(TARGET generator PROPERTY CXX_STANDARD 11) 22set_property(TARGET generator PROPERTY CXX_STANDARD 11)
diff --git a/furries.cpp b/furries.cpp index 0cce8bd..55dfb7b 100644 --- a/furries.cpp +++ b/furries.cpp
@@ -20,7 +20,7 @@ class fill_blanks {
20 { 20 {
21 switch (it->token_type()) 21 switch (it->token_type())
22 { 22 {
23 case verbly::type::utterance: 23 case verbly::token::type::utterance:
24 { 24 {
25 auto& action = *dynamic_cast<verbly::utterance_token*>(it.get()); 25 auto& action = *dynamic_cast<verbly::utterance_token*>(it.get());
26 for (auto& tkn : action) 26 for (auto& tkn : action)
@@ -36,14 +36,14 @@ class fill_blanks {
36 break; 36 break;
37 } 37 }
38 38
39 case verbly::type::fillin: 39 case verbly::token::type::fillin:
40 { 40 {
41 auto& tkn = *dynamic_cast<verbly::fillin_token*>(it.get()); 41 auto& tkn = *dynamic_cast<verbly::fillin_token*>(it.get());
42 switch (tkn.fillin_type()) 42 switch (tkn.fillin_type())
43 { 43 {
44 case verbly::fillin_type::participle_phrase: 44 case verbly::fillin_type::participle_phrase:
45 { 45 {
46 const verbly::verb& v = database.verbs().random(true).limit(1).run().front(); 46 verbly::verb v = database.verbs().random(true).limit(1).run().front();
47 /*verbly::utterance_token phrase = verbly::random(v.frames).make_utterance(); 47 /*verbly::utterance_token phrase = verbly::random(v.frames).make_utterance();
48 while (std::begin(phrase)->token_type() != verbly::type::verb) 48 while (std::begin(phrase)->token_type() != verbly::type::verb)
49 { 49 {
@@ -53,7 +53,7 @@ class fill_blanks {
53 *std::begin(phrase) = verbly::verb_token(v).conjugate(verbly::conjugation::present_participle); 53 *std::begin(phrase) = verbly::verb_token(v).conjugate(verbly::conjugation::present_participle);
54 *it = phrase;*/ 54 *it = phrase;*/
55 auto avt = std::make_unique<verbly::verb_token>(v); 55 auto avt = std::make_unique<verbly::verb_token>(v);
56 avt->conjugate(verbly::conjugation::present_participle); 56 avt->inflect(verbly::verb_token::inflection::ing_form);
57 it = std::move(avt); 57 it = std::move(avt);
58 58
59 break; 59 break;
@@ -61,16 +61,16 @@ class fill_blanks {
61 61
62 case verbly::fillin_type::adjective: 62 case verbly::fillin_type::adjective:
63 { 63 {
64 const verbly::adjective& adj = database.adjectives().random(true).limit(1).run().front(); 64 verbly::adjective adj = database.adjectives().random(true).limit(1).run().front();
65 it = std::make_unique<verbly::string_token>(adj.form); 65 it = std::make_unique<verbly::string_token>(adj.base_form());
66 66
67 break; 67 break;
68 } 68 }
69 69
70 case verbly::fillin_type::adverb: 70 case verbly::fillin_type::adverb:
71 { 71 {
72 const verbly::adverb& adv = database.adverbs().random(true).limit(1).run().front(); 72 verbly::adverb adv = database.adverbs().random(true).limit(1).run().front();
73 it = std::make_unique<verbly::string_token>(adv.form); 73 it = std::make_unique<verbly::string_token>(adv.base_form());
74 74
75 break; 75 break;
76 } 76 }
diff --git a/generator.cpp b/generator.cpp index c389963..305d121 100644 --- a/generator.cpp +++ b/generator.cpp
@@ -9,6 +9,8 @@
9#include <sqlite3.h> 9#include <sqlite3.h>
10#include <sstream> 10#include <sstream>
11#include <regex> 11#include <regex>
12#include <list>
13#include "progress.h"
12 14
13struct verb { 15struct verb {
14 std::string infinitive; 16 std::string infinitive;
@@ -18,6 +20,17 @@ struct verb {
18 std::string s_form; 20 std::string s_form;
19}; 21};
20 22
23struct adjective {
24 std::string base;
25 std::string comparative;
26 std::string superlative;
27};
28
29struct noun {
30 std::string singular;
31 std::string plural;
32};
33
21struct group { 34struct group {
22 std::string id; 35 std::string id;
23 std::set<std::string> members; 36 std::set<std::string> members;
@@ -25,21 +38,33 @@ struct group {
25 38
26std::map<std::string, group> groups; 39std::map<std::string, group> groups;
27std::map<std::string, verb> verbs; 40std::map<std::string, verb> verbs;
41std::map<std::string, adjective> adjectives;
42std::map<std::string, noun> nouns;
28std::map<int, std::map<int, int>> wn; 43std::map<int, std::map<int, int>> wn;
44std::map<std::string, std::set<std::string>> pronunciations;
29 45
30void print_usage() 46void print_usage()
31{ 47{
32 std::cout << "Verbly Datafile Generator" << std::endl; 48 std::cout << "Verbly Datafile Generator" << std::endl;
33 std::cout << "-------------------------" << std::endl; 49 std::cout << "-------------------------" << std::endl;
34 std::cout << "Requires exactly four arguments." << std::endl; 50 std::cout << "Requires exactly six arguments." << std::endl;
35 std::cout << "1. The path to a VerbNet data directory." << std::endl; 51 std::cout << "1. The path to a VerbNet data directory." << std::endl;
36 std::cout << "2. The path to a SemLink vnpbMappings file." << std::endl; 52 std::cout << "2. The path to a SemLink vnpbMappings file." << std::endl;
37 std::cout << "3. The path to an AGID infl.txt file." << std::endl; 53 std::cout << "3. The path to an AGID infl.txt file." << std::endl;
38 std::cout << "4. The path to a WordNet prolog data directory." << std::endl; 54 std::cout << "4. The path to a WordNet prolog data directory." << std::endl;
39 std::cout << "5. Datafile output path." << std::endl; 55 std::cout << "5. The path to a CMUDICT pronunciation file." << std::endl;
56 std::cout << "6. Datafile output path." << std::endl;
40 57
41 exit(1); 58 exit(1);
42} 59}
60
61void db_error(sqlite3* ppdb, std::string)
62{
63 std::cout << "Error writing to output database: " << sqlite3_errmsg(ppdb) << std::endl;
64 sqlite3_close_v2(ppdb);
65 print_usage();
66}
67
43/* 68/*
44void parse_group(xmlNodePtr top, std::string filename) 69void parse_group(xmlNodePtr top, std::string filename)
45{ 70{
@@ -87,7 +112,7 @@ void parse_group(xmlNodePtr top, std::string filename)
87 112
88int main(int argc, char** argv) 113int main(int argc, char** argv)
89{ 114{
90 if (argc != 6) 115 if (argc != 7)
91 { 116 {
92 print_usage(); 117 print_usage();
93 } 118 }
@@ -137,7 +162,7 @@ int main(int argc, char** argv)
137 closedir(dir);*/ 162 closedir(dir);*/
138 163
139 // Get verbs from AGID 164 // Get verbs from AGID
140 std::cout << "Reading verb inflection..." << std::endl; 165 std::cout << "Reading inflections..." << std::endl;
141 166
142 std::ifstream agidfile(argv[3]); 167 std::ifstream agidfile(argv[3]);
143 if (!agidfile.is_open()) 168 if (!agidfile.is_open())
@@ -162,11 +187,7 @@ int main(int argc, char** argv)
162 int divider = line.find_first_of(" "); 187 int divider = line.find_first_of(" ");
163 std::string word = line.substr(0, divider); 188 std::string word = line.substr(0, divider);
164 line = line.substr(divider+1); 189 line = line.substr(divider+1);
165 190 char type = line[0];
166 if (line[0] != 'V')
167 {
168 continue;
169 }
170 191
171 if (line[1] == '?') 192 if (line[1] == '?')
172 { 193 {
@@ -174,7 +195,7 @@ int main(int argc, char** argv)
174 } else { 195 } else {
175 line.erase(0, 3); 196 line.erase(0, 3);
176 } 197 }
177 198
178 std::vector<std::string> forms; 199 std::vector<std::string> forms;
179 while (!line.empty()) 200 while (!line.empty())
180 { 201 {
@@ -187,52 +208,129 @@ int main(int argc, char** argv)
187 inflection = line; 208 inflection = line;
188 line = ""; 209 line = "";
189 } 210 }
190 211
191 if ((divider = inflection.find_first_of(",?")) != std::string::npos) 212 if ((divider = inflection.find_first_of(",?")) != std::string::npos)
192 { 213 {
193 inflection = inflection.substr(0, divider); 214 inflection = inflection.substr(0, divider);
194 } 215 }
195 216
196 forms.push_back(inflection); 217 forms.push_back(inflection);
197 } 218 }
198 219
199 verb v; 220 switch (type)
200 v.infinitive = word;
201 if (forms.size() == 4)
202 { 221 {
203 v.past_tense = forms[0]; 222 case 'V':
204 v.past_participle = forms[1]; 223 {
205 v.ing_form = forms[2]; 224 verb v;
206 v.s_form = forms[3]; 225 v.infinitive = word;
207 } else if (forms.size() == 3) 226 if (forms.size() == 4)
227 {
228 v.past_tense = forms[0];
229 v.past_participle = forms[1];
230 v.ing_form = forms[2];
231 v.s_form = forms[3];
232 } else if (forms.size() == 3)
233 {
234 v.past_tense = forms[0];
235 v.past_participle = forms[0];
236 v.ing_form = forms[1];
237 v.s_form = forms[2];
238 } else if (forms.size() == 8)
239 {
240 // As of AGID 2014.08.11, this is only "to be"
241 v.past_tense = forms[0];
242 v.past_participle = forms[2];
243 v.ing_form = forms[3];
244 v.s_form = forms[4];
245 } else {
246 // Words that don't fit the cases above as of AGID 2014.08.11:
247 // - may and shall do not conjugate the way we want them to
248 // - methinks only has a past tense and is an outlier
249 // - wit has five forms, and is archaic/obscure enough that we can ignore it for now
250 std::cout << "Ignoring verb \"" << word << "\" due to non-standard number of forms." << std::endl;
251 }
252
253 verbs[word] = v;
254
255 break;
256 }
257
258 case 'A':
259 {
260 adjective adj;
261 adj.base = word;
262 if (forms.size() == 2)
263 {
264 adj.comparative = forms[0];
265 adj.superlative = forms[1];
266 } else {
267 // As of AGID 2014.08.11, this is only "only", which has only the form "onliest"
268 std::cout << "Ignoring adjective/adverb \"" << word << "\" due to non-standard number of forms." << std::endl;
269 }
270
271 adjectives[word] = adj;
272
273 break;
274 }
275
276 case 'N':
277 {
278 noun n;
279 n.singular = word;
280 if (forms.size() == 1)
281 {
282 n.plural = forms[0];
283 } else {
284 // As of AGID 2014.08.11, this is non-existent.
285 std::cout << "Ignoring noun \"" << word << "\" due to non-standard number of forms." << std::endl;
286 }
287
288 nouns[word] = n;
289
290 break;
291 }
292 }
293 }
294
295 // Pronounciations
296 std::cout << "Reading pronunciations..." << std::endl;
297
298 std::ifstream pronfile(argv[5]);
299 if (!pronfile.is_open())
300 {
301 std::cout << "Could not open CMUDICT file: " << argv[5] << std::endl;
302 print_usage();
303 }
304
305 for (;;)
306 {
307 std::string line;
308 if (!getline(pronfile, line))
208 { 309 {
209 v.past_tense = forms[0]; 310 break;
210 v.past_participle = forms[0]; 311 }
211 v.ing_form = forms[1]; 312
212 v.s_form = forms[2]; 313 if (line.back() == '\r')
213 } else if (forms.size() == 8)
214 { 314 {
215 // As of AGID 2014.08.11, this is only "to be" 315 line.pop_back();
216 v.past_tense = forms[0];
217 v.past_participle = forms[2];
218 v.ing_form = forms[3];
219 v.s_form = forms[4];
220 } else {
221 // Words that don't fit the cases above as of AGID 2014.08.11:
222 // - may and shall do not conjugate the way we want them to
223 // - methinks only has a past tense and is an outlier
224 // - wit has five forms, and is archaic/obscure enough that we can ignore it for now
225 std::cout << "Ignoring verb \"" << word << "\" due to non-standard number of forms." << std::endl;
226 } 316 }
227 317
228 verbs[word] = v; 318 std::regex phoneme("([A-Z][^ \\(]*)(?:\\(\\d+\\))? ([A-Z 0-9]+)");
319 std::smatch phoneme_data;
320 if (std::regex_search(line, phoneme_data, phoneme))
321 {
322 std::string canonical(phoneme_data[1]);
323 std::transform(std::begin(canonical), std::end(canonical), std::begin(canonical), ::tolower);
324
325 pronunciations[canonical].insert(phoneme_data[2]);
326 }
229 } 327 }
230 328
231 // Start writing output 329 // Start writing output
232 std::cout << "Writing output..." << std::endl; 330 std::cout << "Writing schema..." << std::endl;
233 331
234 sqlite3* ppdb; 332 sqlite3* ppdb;
235 if (sqlite3_open_v2(argv[5], &ppdb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL) != SQLITE_OK) 333 if (sqlite3_open_v2(argv[6], &ppdb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL) != SQLITE_OK)
236 { 334 {
237 std::cout << "Error opening output datafile: " << sqlite3_errmsg(ppdb) << std::endl; 335 std::cout << "Error opening output datafile: " << sqlite3_errmsg(ppdb) << std::endl;
238 print_usage(); 336 print_usage();
@@ -278,47 +376,82 @@ int main(int argc, char** argv)
278 sqlite3_stmt* schmstmt; 376 sqlite3_stmt* schmstmt;
279 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &schmstmt, NULL) != SQLITE_OK) 377 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &schmstmt, NULL) != SQLITE_OK)
280 { 378 {
281 std::cout << "Error writing to output database: " << sqlite3_errmsg(ppdb) << std::endl; 379 db_error(ppdb, query);
282 sqlite3_close_v2(ppdb);
283 print_usage();
284 } 380 }
285 381
286 if (sqlite3_step(schmstmt) != SQLITE_DONE) 382 if (sqlite3_step(schmstmt) != SQLITE_DONE)
287 { 383 {
288 std::cout << "Error writing to output database: " << sqlite3_errmsg(ppdb) << std::endl; 384 db_error(ppdb, query);
289 sqlite3_close_v2(ppdb);
290 print_usage();
291 } 385 }
292 386
293 sqlite3_finalize(schmstmt); 387 sqlite3_finalize(schmstmt);
294 } 388 }
295 389
296 std::cout << "Writing verbs..." << std::endl;
297 for (auto& mapping : verbs)
298 { 390 {
299 sqlite3_stmt* ppstmt; 391 progress ppgs("Writing verbs...", verbs.size());
300 std::string query("INSERT INTO verbs (infinitive, past_tense, past_participle, ing_form, s_form) VALUES (?, ?, ?, ?, ?)"); 392 for (auto& mapping : verbs)
301 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
302 { 393 {
303 std::cout << "Error writing to output database: " << sqlite3_errmsg(ppdb) << std::endl; 394 sqlite3_stmt* ppstmt;
304 sqlite3_close_v2(ppdb); 395 std::string query("INSERT INTO verbs (infinitive, past_tense, past_participle, ing_form, s_form) VALUES (?, ?, ?, ?, ?)");
305 print_usage(); 396 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
306 } 397 {
398 db_error(ppdb, query);
399 }
307 400
308 sqlite3_bind_text(ppstmt, 1, mapping.second.infinitive.c_str(), mapping.second.infinitive.length(), SQLITE_STATIC); 401 sqlite3_bind_text(ppstmt, 1, mapping.second.infinitive.c_str(), mapping.second.infinitive.length(), SQLITE_STATIC);
309 sqlite3_bind_text(ppstmt, 2, mapping.second.past_tense.c_str(), mapping.second.past_tense.length(), SQLITE_STATIC); 402 sqlite3_bind_text(ppstmt, 2, mapping.second.past_tense.c_str(), mapping.second.past_tense.length(), SQLITE_STATIC);
310 sqlite3_bind_text(ppstmt, 3, mapping.second.past_participle.c_str(), mapping.second.past_participle.length(), SQLITE_STATIC); 403 sqlite3_bind_text(ppstmt, 3, mapping.second.past_participle.c_str(), mapping.second.past_participle.length(), SQLITE_STATIC);
311 sqlite3_bind_text(ppstmt, 4, mapping.second.ing_form.c_str(), mapping.second.ing_form.length(), SQLITE_STATIC); 404 sqlite3_bind_text(ppstmt, 4, mapping.second.ing_form.c_str(), mapping.second.ing_form.length(), SQLITE_STATIC);
312 sqlite3_bind_text(ppstmt, 5, mapping.second.s_form.c_str(), mapping.second.s_form.length(), SQLITE_STATIC); 405 sqlite3_bind_text(ppstmt, 5, mapping.second.s_form.c_str(), mapping.second.s_form.length(), SQLITE_STATIC);
313 406
314 if (sqlite3_step(ppstmt) != SQLITE_DONE) 407 if (sqlite3_step(ppstmt) != SQLITE_DONE)
315 { 408 {
316 std::cout << "Error writing to output database: " << sqlite3_errmsg(ppdb) << std::endl; 409 db_error(ppdb, query);
317 sqlite3_close_v2(ppdb); 410 }
318 print_usage();
319 }
320 411
321 sqlite3_finalize(ppstmt); 412 sqlite3_finalize(ppstmt);
413
414 std::string canonical(mapping.second.infinitive);
415 std::transform(std::begin(canonical), std::end(canonical), std::begin(canonical), ::tolower);
416 if (pronunciations.count(canonical) == 1)
417 {
418 query = "SELECT last_insert_rowid()";
419 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
420 {
421 db_error(ppdb, query);
422 }
423
424 if (sqlite3_step(ppstmt) != SQLITE_ROW)
425 {
426 db_error(ppdb, query);
427 }
428
429 int rowid = sqlite3_column_int(ppstmt, 0);
430
431 sqlite3_finalize(ppstmt);
432
433 for (auto pronunciation : pronunciations[canonical])
434 {
435 query = "INSERT INTO verb_pronunciations (verb_id, pronunciation) VALUES (?, ?)";
436 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
437 {
438 db_error(ppdb, query);
439 }
440
441 sqlite3_bind_int(ppstmt, 1, rowid);
442 sqlite3_bind_text(ppstmt, 2, pronunciation.c_str(), pronunciation.length(), SQLITE_STATIC);
443
444 if (sqlite3_step(ppstmt) != SQLITE_DONE)
445 {
446 db_error(ppdb, query);
447 }
448
449 sqlite3_finalize(ppstmt);
450 }
451 }
452
453 ppgs.update();
454 }
322 } 455 }
323 456
324 // Get nouns/adjectives/adverbs from WordNet 457 // Get nouns/adjectives/adverbs from WordNet
@@ -342,110 +475,1046 @@ int main(int argc, char** argv)
342 wnpref += '/'; 475 wnpref += '/';
343 } 476 }
344 477
345 std::cout << "Reading words from WordNet..." << std::endl; 478 // s table
346 std::ifstream wnsfile(wnpref + "wn_s.pl");
347 if (!wnsfile.is_open())
348 { 479 {
349 std::cout << "Invalid WordNet data directory." << std::endl; 480 std::ifstream wnsfile(wnpref + "wn_s.pl");
350 print_usage(); 481 if (!wnsfile.is_open())
482 {
483 std::cout << "Invalid WordNet data directory." << std::endl;
484 print_usage();
485 }
486
487 std::list<std::string> lines;
488 for (;;)
489 {
490 std::string line;
491 if (!getline(wnsfile, line))
492 {
493 break;
494 }
495
496 if (line.back() == '\r')
497 {
498 line.pop_back();
499 }
500
501 lines.push_back(line);
502 }
503
504 progress ppgs("Writing nouns, adjectives, and adverbs...", lines.size());
505 for (auto line : lines)
506 {
507 ppgs.update();
508
509 std::regex relation("^s\\(([134]\\d{8}),(\\d+),'([\\w ]+)',");
510 std::smatch relation_data;
511 if (!std::regex_search(line, relation_data, relation))
512 {
513 continue;
514 }
515
516 int synset_id = stoi(relation_data[1]);
517 int wnum = stoi(relation_data[2]);
518 std::string word = relation_data[3];
519
520 std::string query;
521 switch (synset_id / 100000000)
522 {
523 case 1: // Noun
524 {
525 if (nouns.count(word) == 1)
526 {
527 query = "INSERT INTO nouns (singular, plural) VALUES (?, ?)";
528 } else {
529 query = "INSERT INTO nouns (singular) VALUES (?)";
530 }
531
532 break;
533 }
534
535 case 2: // Verb
536 {
537 // Ignore
538
539 break;
540 }
541
542 case 3: // Adjective
543 {
544 if (adjectives.count(word) == 1)
545 {
546 query = "INSERT INTO adjectives (base_form, comparative, superlative) VALUES (?, ?, ?)";
547 } else {
548 query = "INSERT INTO adjectives (base_form) VALUES (?)";
549 }
550
551 break;
552 }
553
554 case 4: // Adverb
555 {
556 if (adjectives.count(word) == 1)
557 {
558 query = "INSERT INTO adverbs (base_form, comparative, superlative) VALUES (?, ?, ?)";
559 } else {
560 query = "INSERT INTO adverbs (base_form) VALUES (?)";
561 }
562
563 break;
564 }
565 }
566
567 sqlite3_stmt* ppstmt;
568 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
569 {
570 db_error(ppdb, query);
571 }
572
573 sqlite3_bind_text(ppstmt, 1, word.c_str(), word.length(), SQLITE_STATIC);
574 switch (synset_id / 100000000)
575 {
576 case 1: // Noun
577 {
578 if (nouns.count(word) == 1)
579 {
580 sqlite3_bind_text(ppstmt, 2, nouns[word].plural.c_str(), nouns[word].plural.length(), SQLITE_STATIC);
581 }
582
583 break;
584 }
585
586 case 3: // Adjective
587 case 4: // Adverb
588 {
589 if (adjectives.count(word) == 1)
590 {
591 sqlite3_bind_text(ppstmt, 2, adjectives[word].comparative.c_str(), adjectives[word].comparative.length(), SQLITE_STATIC);
592 sqlite3_bind_text(ppstmt, 3, adjectives[word].superlative.c_str(), adjectives[word].superlative.length(), SQLITE_STATIC);
593 }
594
595 break;
596 }
597 }
598
599 if (sqlite3_step(ppstmt) != SQLITE_DONE)
600 {
601 db_error(ppdb, query);
602 }
603
604 sqlite3_finalize(ppstmt);
605
606 query = "SELECT last_insert_rowid()";
607 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
608 {
609 db_error(ppdb, query);
610 }
611
612 if (sqlite3_step(ppstmt) != SQLITE_ROW)
613 {
614 db_error(ppdb, query);
615 }
616
617 int rowid = sqlite3_column_int(ppstmt, 0);
618 wn[synset_id][wnum] = rowid;
619
620 sqlite3_finalize(ppstmt);
621
622 std::string canonical(word);
623 std::transform(std::begin(canonical), std::end(canonical), std::begin(canonical), ::tolower);
624 if (pronunciations.count(canonical) == 1)
625 {
626 for (auto pronunciation : pronunciations[canonical])
627 {
628 switch (synset_id / 100000000)
629 {
630 case 1: // Noun
631 {
632 query = "INSERT INTO noun_pronunciations (noun_id, pronunciation) VALUES (?, ?)";
633
634 break;
635 }
636
637 case 3: // Adjective
638 {
639 query = "INSERT INTO adjective_pronunciations (adjective_id, pronunciation) VALUES (?, ?)";
640
641 break;
642 }
643
644 case 4: // Adverb
645 {
646 query = "INSERT INTO adverb_pronunciations (adverb_id, pronunciation) VALUES (?, ?)";
647
648 break;
649 }
650 }
651
652 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
653 {
654 db_error(ppdb, query);
655 }
656
657 sqlite3_bind_int(ppstmt, 1, rowid);
658 sqlite3_bind_text(ppstmt, 2, pronunciation.c_str(), pronunciation.length(), SQLITE_STATIC);
659
660 if (sqlite3_step(ppstmt) != SQLITE_DONE)
661 {
662 db_error(ppdb, query);
663 }
664
665 sqlite3_finalize(ppstmt);
666 }
667 }
668 }
351 } 669 }
352 670
353 for (;;) 671 // While we're working on s
354 { 672 {
355 std::string line; 673 progress ppgs("Writing word synonyms...", wn.size());
356 if (!getline(wnsfile, line)) 674 for (auto sense : wn)
357 { 675 {
358 break; 676 ppgs.update();
677
678 for (auto word1 : sense.second)
679 {
680 for (auto word2 : sense.second)
681 {
682 if (word1 != word2)
683 {
684 std::string query;
685 switch (sense.first / 100000000)
686 {
687 case 1: // Noun
688 {
689 query = "INSERT INTO noun_synonymy (noun_1_id, noun_2_id) VALUES (?, ?)";
690
691 break;
692 }
693
694 case 2: // Verb
695 {
696 // Ignore
697
698 break;
699 }
700
701 case 3: // Adjective
702 {
703 query = "INSERT INTO adjective_synonymy (adjective_1_id, adjective_2_id) VALUES (?, ?)";
704
705 break;
706 }
707
708 case 4: // Adverb
709 {
710 query = "INSERT INTO adverb_synonymy (adverb_1_id, adverb_2_id) VALUES (?, ?)";
711
712 break;
713 }
714 }
715
716 sqlite3_stmt* ppstmt;
717 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
718 {
719 db_error(ppdb, query);
720 }
721
722 sqlite3_bind_int(ppstmt, 1, word1.second);
723 sqlite3_bind_int(ppstmt, 2, word2.second);
724
725 if (sqlite3_step(ppstmt) != SQLITE_DONE)
726 {
727 db_error(ppdb, query);
728 }
729
730 sqlite3_finalize(ppstmt);
731 }
732 }
733 }
734 }
735 }
736
737 // ant table
738 {
739 std::ifstream wnantfile(wnpref + "wn_ant.pl");
740 if (!wnantfile.is_open())
741 {
742 std::cout << "Invalid WordNet data directory." << std::endl;
743 print_usage();
359 } 744 }
745
746 std::list<std::string> lines;
747 for (;;)
748 {
749 std::string line;
750 if (!getline(wnantfile, line))
751 {
752 break;
753 }
360 754
361 if (line.back() == '\r') 755 if (line.back() == '\r')
756 {
757 line.pop_back();
758 }
759
760 lines.push_back(line);
761 }
762
763 progress ppgs("Writing antonyms...", lines.size());
764 for (auto line : lines)
362 { 765 {
363 line.pop_back(); 766 ppgs.update();
767
768 std::regex relation("^ant\\(([134]\\d{8}),(\\d+),([134]\\d{8}),(\\d+)\\)\\.");
769 std::smatch relation_data;
770 if (!std::regex_search(line, relation_data, relation))
771 {
772 continue;
773 }
774
775 int synset_id_1 = stoi(relation_data[1]);
776 int wnum_1 = stoi(relation_data[2]);
777 int synset_id_2 = stoi(relation_data[3]);
778 int wnum_2 = stoi(relation_data[4]);
779
780 std::string query;
781 switch (synset_id_1 / 100000000)
782 {
783 case 1: // Noun
784 {
785 query = "INSERT INTO noun_antonymy (noun_1_id, noun_2_id) VALUES (?, ?)";
786
787 break;
788 }
789
790 case 2: // Verb
791 {
792 // Ignore
793
794 break;
795 }
796
797 case 3: // Adjective
798 {
799 query = "INSERT INTO adjective_antonymy (adjective_1_id, adjective_2_id) VALUES (?, ?)";
800
801 break;
802 }
803
804 case 4: // Adverb
805 {
806 query = "INSERT INTO adverb_antonymy (adverb_1_id, adverb_2_id) VALUES (?, ?)";
807
808 break;
809 }
810 }
811
812 sqlite3_stmt* ppstmt;
813 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
814 {
815 db_error(ppdb, query);
816 }
817
818 sqlite3_bind_int(ppstmt, 1, wn[synset_id_1][wnum_1]);
819 sqlite3_bind_int(ppstmt, 2, wn[synset_id_2][wnum_2]);
820
821 if (sqlite3_step(ppstmt) != SQLITE_DONE)
822 {
823 db_error(ppdb, query);
824 }
825
826 sqlite3_finalize(ppstmt);
827 }
828 }
829
830 // at table
831 {
832 std::ifstream wnatfile(wnpref + "wn_at.pl");
833 if (!wnatfile.is_open())
834 {
835 std::cout << "Invalid WordNet data directory." << std::endl;
836 print_usage();
364 } 837 }
838
839 std::list<std::string> lines;
840 for (;;)
841 {
842 std::string line;
843 if (!getline(wnatfile, line))
844 {
845 break;
846 }
365 847
366 std::regex relation("^s\\(([134]\\d{8}),(\\d+),'([\\w ]+)',"); 848 if (line.back() == '\r')
367 std::smatch relation_data; 849 {
368 if (!std::regex_search(line, relation_data, relation)) 850 line.pop_back();
851 }
852
853 lines.push_back(line);
854 }
855
856 progress ppgs("Writing variations...", lines.size());
857 for (auto line : lines)
369 { 858 {
370 continue; 859 ppgs.update();
860
861 std::regex relation("^at\\((1\\d{8}),(3\\d{8})\\)\\.");
862 std::smatch relation_data;
863 if (!std::regex_search(line, relation_data, relation))
864 {
865 continue;
866 }
867
868 int synset_id_1 = stoi(relation_data[1]);
869 int synset_id_2 = stoi(relation_data[2]);
870 std::string query("INSERT INTO variation (noun_id, adjective_id) VALUES (?, ?)");
871
872 for (auto mapping1 : wn[synset_id_1])
873 {
874 for (auto mapping2 : wn[synset_id_2])
875 {
876 sqlite3_stmt* ppstmt;
877 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.size(), &ppstmt, NULL) != SQLITE_OK)
878 {
879 db_error(ppdb, query);
880 }
881
882 sqlite3_bind_int(ppstmt, 1, mapping1.second);
883 sqlite3_bind_int(ppstmt, 2, mapping2.second);
884
885 if (sqlite3_step(ppstmt) != SQLITE_DONE)
886 {
887 db_error(ppdb, query);
888 }
889
890 sqlite3_finalize(ppstmt);
891 }
892 }
371 } 893 }
894 }
895
896 // hyp table
897 {
898 std::ifstream wnhypfile(wnpref + "wn_hyp.pl");
899 if (!wnhypfile.is_open())
900 {
901 std::cout << "Invalid WordNet data directory." << std::endl;
902 print_usage();
903 }
904
905 std::list<std::string> lines;
906 for (;;)
907 {
908 std::string line;
909 if (!getline(wnhypfile, line))
910 {
911 break;
912 }
372 913
373 int synset_id = stoi(relation_data[1]); 914 if (line.back() == '\r')
374 int wnum = stoi(relation_data[2]); 915 {
375 std::string word = relation_data[3]; 916 line.pop_back();
917 }
918
919 lines.push_back(line);
920 }
376 921
377 std::string query; 922 progress ppgs("Writing hypernyms...", lines.size());
378 switch (synset_id / 100000000) 923 for (auto line : lines)
379 { 924 {
380 case 1: // Noun 925 ppgs.update();
926
927 std::regex relation("^hyp\\((1\\d{8}),(1\\d{8})\\)\\.");
928 std::smatch relation_data;
929 if (!std::regex_search(line, relation_data, relation))
930 {
931 continue;
932 }
933
934 int synset_id_1 = stoi(relation_data[1]);
935 int synset_id_2 = stoi(relation_data[2]);
936 std::string query("INSERT INTO hypernymy (hyponym_id, hypernym_id) VALUES (?, ?)");
937
938 for (auto mapping1 : wn[synset_id_1])
939 {
940 for (auto mapping2 : wn[synset_id_2])
941 {
942 sqlite3_stmt* ppstmt;
943 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.size(), &ppstmt, NULL) != SQLITE_OK)
944 {
945 db_error(ppdb, query);
946 }
947
948 sqlite3_bind_int(ppstmt, 1, mapping1.second);
949 sqlite3_bind_int(ppstmt, 2, mapping2.second);
950
951 if (sqlite3_step(ppstmt) != SQLITE_DONE)
952 {
953 db_error(ppdb, query);
954 }
955
956 sqlite3_finalize(ppstmt);
957 }
958 }
959 }
960 }
961
962 // ins table
963 {
964 std::ifstream wninsfile(wnpref + "wn_ins.pl");
965 if (!wninsfile.is_open())
966 {
967 std::cout << "Invalid WordNet data directory." << std::endl;
968 print_usage();
969 }
970
971 std::list<std::string> lines;
972 for (;;)
973 {
974 std::string line;
975 if (!getline(wninsfile, line))
381 { 976 {
382 query = "INSERT INTO nouns (form) VALUES (?)";
383
384 break; 977 break;
385 } 978 }
979
980 if (line.back() == '\r')
981 {
982 line.pop_back();
983 }
386 984
387 case 2: // Verb 985 lines.push_back(line);
986 }
987
988 progress ppgs("Writing instantiations...", lines.size());
989 for (auto line : lines)
990 {
991 ppgs.update();
992
993 std::regex relation("^ins\\((1\\d{8}),(1\\d{8})\\)\\.");
994 std::smatch relation_data;
995 if (!std::regex_search(line, relation_data, relation))
996 {
997 continue;
998 }
999
1000 int synset_id_1 = stoi(relation_data[1]);
1001 int synset_id_2 = stoi(relation_data[2]);
1002 std::string query("INSERT INTO instantiation (instance_id, class_id) VALUES (?, ?)");
1003
1004 for (auto mapping1 : wn[synset_id_1])
1005 {
1006 for (auto mapping2 : wn[synset_id_2])
1007 {
1008 sqlite3_stmt* ppstmt;
1009 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.size(), &ppstmt, NULL) != SQLITE_OK)
1010 {
1011 db_error(ppdb, query);
1012 }
1013
1014 sqlite3_bind_int(ppstmt, 1, mapping1.second);
1015 sqlite3_bind_int(ppstmt, 2, mapping2.second);
1016
1017 if (sqlite3_step(ppstmt) != SQLITE_DONE)
1018 {
1019 db_error(ppdb, query);
1020 }
1021
1022 sqlite3_finalize(ppstmt);
1023 }
1024 }
1025 }
1026 }
1027
1028 // mm table
1029 {
1030 std::ifstream wnmmfile(wnpref + "wn_mm.pl");
1031 if (!wnmmfile.is_open())
1032 {
1033 std::cout << "Invalid WordNet data directory." << std::endl;
1034 print_usage();
1035 }
1036
1037 std::list<std::string> lines;
1038 for (;;)
1039 {
1040 std::string line;
1041 if (!getline(wnmmfile, line))
388 { 1042 {
389 // Ignore
390
391 break; 1043 break;
392 } 1044 }
1045
1046 if (line.back() == '\r')
1047 {
1048 line.pop_back();
1049 }
1050
1051 lines.push_back(line);
1052 }
1053
1054 progress ppgs("Writing member meronyms...", lines.size());
1055 for (auto line : lines)
1056 {
1057 ppgs.update();
393 1058
394 case 3: // Adjective 1059 std::regex relation("^mm\\((1\\d{8}),(1\\d{8})\\)\\.");
1060 std::smatch relation_data;
1061 if (!std::regex_search(line, relation_data, relation))
1062 {
1063 continue;
1064 }
1065
1066 int synset_id_1 = stoi(relation_data[1]);
1067 int synset_id_2 = stoi(relation_data[2]);
1068 std::string query("INSERT INTO member_meronymy (holonym_id, meronym_id) VALUES (?, ?)");
1069
1070 for (auto mapping1 : wn[synset_id_1])
1071 {
1072 for (auto mapping2 : wn[synset_id_2])
1073 {
1074 sqlite3_stmt* ppstmt;
1075 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.size(), &ppstmt, NULL) != SQLITE_OK)
1076 {
1077 db_error(ppdb, query);
1078 }
1079
1080 sqlite3_bind_int(ppstmt, 1, mapping1.second);
1081 sqlite3_bind_int(ppstmt, 2, mapping2.second);
1082
1083 if (sqlite3_step(ppstmt) != SQLITE_DONE)
1084 {
1085 db_error(ppdb, query);
1086 }
1087
1088 sqlite3_finalize(ppstmt);
1089 }
1090 }
1091 }
1092 }
1093
1094 // ms table
1095 {
1096 std::ifstream wnmsfile(wnpref + "wn_ms.pl");
1097 if (!wnmsfile.is_open())
1098 {
1099 std::cout << "Invalid WordNet data directory." << std::endl;
1100 print_usage();
1101 }
1102
1103 std::list<std::string> lines;
1104 for (;;)
1105 {
1106 std::string line;
1107 if (!getline(wnmsfile, line))
395 { 1108 {
396 query = "INSERT INTO adjectives (form) VALUES (?)";
397
398 break; 1109 break;
399 } 1110 }
1111
1112 if (line.back() == '\r')
1113 {
1114 line.pop_back();
1115 }
400 1116
401 case 4: // Adverb 1117 lines.push_back(line);
1118 }
1119
1120 progress ppgs("Writing substance meronyms...", lines.size());
1121 for (auto line : lines)
1122 {
1123 ppgs.update();
1124
1125 std::regex relation("^ms\\((1\\d{8}),(1\\d{8})\\)\\.");
1126 std::smatch relation_data;
1127 if (!std::regex_search(line, relation_data, relation))
1128 {
1129 continue;
1130 }
1131
1132 int synset_id_1 = stoi(relation_data[1]);
1133 int synset_id_2 = stoi(relation_data[2]);
1134 std::string query("INSERT INTO substance_meronymy (holonym_id, meronym_id) VALUES (?, ?)");
1135
1136 for (auto mapping1 : wn[synset_id_1])
1137 {
1138 for (auto mapping2 : wn[synset_id_2])
1139 {
1140 sqlite3_stmt* ppstmt;
1141 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.size(), &ppstmt, NULL) != SQLITE_OK)
1142 {
1143 db_error(ppdb, query);
1144 }
1145
1146 sqlite3_bind_int(ppstmt, 1, mapping1.second);
1147 sqlite3_bind_int(ppstmt, 2, mapping2.second);
1148
1149 if (sqlite3_step(ppstmt) != SQLITE_DONE)
1150 {
1151 db_error(ppdb, query);
1152 }
1153
1154 sqlite3_finalize(ppstmt);
1155 }
1156 }
1157 }
1158 }
1159
1160 // mm table
1161 {
1162 std::ifstream wnmpfile(wnpref + "wn_mp.pl");
1163 if (!wnmpfile.is_open())
1164 {
1165 std::cout << "Invalid WordNet data directory." << std::endl;
1166 print_usage();
1167 }
1168
1169 std::list<std::string> lines;
1170 for (;;)
1171 {
1172 std::string line;
1173 if (!getline(wnmpfile, line))
402 { 1174 {
403 query = "INSERT INTO adverbs (form) VALUES (?)";
404
405 break; 1175 break;
406 } 1176 }
1177
1178 if (line.back() == '\r')
1179 {
1180 line.pop_back();
1181 }
1182
1183 lines.push_back(line);
407 } 1184 }
408 1185
409 sqlite3_stmt* ppstmt; 1186 progress ppgs("Writing part meronyms...", lines.size());
410 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) 1187 for (auto line : lines)
1188 {
1189 ppgs.update();
1190
1191 std::regex relation("^mp\\((1\\d{8}),(1\\d{8})\\)\\.");
1192 std::smatch relation_data;
1193 if (!std::regex_search(line, relation_data, relation))
1194 {
1195 continue;
1196 }
1197
1198 int synset_id_1 = stoi(relation_data[1]);
1199 int synset_id_2 = stoi(relation_data[2]);
1200 std::string query("INSERT INTO part_meronymy (holonym_id, meronym_id) VALUES (?, ?)");
1201
1202 for (auto mapping1 : wn[synset_id_1])
1203 {
1204 for (auto mapping2 : wn[synset_id_2])
1205 {
1206 sqlite3_stmt* ppstmt;
1207 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.size(), &ppstmt, NULL) != SQLITE_OK)
1208 {
1209 db_error(ppdb, query);
1210 }
1211
1212 sqlite3_bind_int(ppstmt, 1, mapping1.second);
1213 sqlite3_bind_int(ppstmt, 2, mapping2.second);
1214
1215 if (sqlite3_step(ppstmt) != SQLITE_DONE)
1216 {
1217 db_error(ppdb, query);
1218 }
1219
1220 sqlite3_finalize(ppstmt);
1221 }
1222 }
1223 }
1224 }
1225
1226 // per table
1227 {
1228 std::ifstream wnperfile(wnpref + "wn_per.pl");
1229 if (!wnperfile.is_open())
411 { 1230 {
412 std::cout << "Error writing to output database: " << sqlite3_errmsg(ppdb) << std::endl; 1231 std::cout << "Invalid WordNet data directory." << std::endl;
413 sqlite3_close_v2(ppdb);
414 print_usage(); 1232 print_usage();
415 } 1233 }
1234
1235 std::list<std::string> lines;
1236 for (;;)
1237 {
1238 std::string line;
1239 if (!getline(wnperfile, line))
1240 {
1241 break;
1242 }
1243
1244 if (line.back() == '\r')
1245 {
1246 line.pop_back();
1247 }
1248
1249 lines.push_back(line);
1250 }
1251
1252 progress ppgs("Writing pertainyms and mannernyms...", lines.size());
1253 for (auto line : lines)
1254 {
1255 ppgs.update();
1256
1257 std::regex relation("^per\\(([34]\\d{8}),(\\d+),([13]\\d{8}),(\\d+)\\)\\.");
1258 std::smatch relation_data;
1259 if (!std::regex_search(line, relation_data, relation))
1260 {
1261 continue;
1262 }
1263
1264 int synset_id_1 = stoi(relation_data[1]);
1265 int wnum_1 = stoi(relation_data[2]);
1266 int synset_id_2 = stoi(relation_data[3]);
1267 int wnum_2 = stoi(relation_data[4]);
1268 std::string query;
1269 switch (synset_id_1 / 100000000)
1270 {
1271 case 3: // Adjective
1272 {
1273 // This is a pertainym, the second word should be a noun
1274 // Technically it can be an adjective but we're ignoring that
1275 if (synset_id_2 / 100000000 != 1)
1276 {
1277 continue;
1278 }
1279
1280 query = "INSERT INTO pertainymy (pertainym_id, noun_id) VALUES (?, ?)";
1281
1282 break;
1283 }
1284
1285 case 4: // Adverb
1286 {
1287 // This is a mannernym, the second word should be an adjective
1288 if (synset_id_2 / 100000000 != 3)
1289 {
1290 continue;
1291 }
1292
1293 query = "INSERT INTO mannernymy (mannernym_id, adjective_id) VALUES (?, ?)";
1294
1295 break;
1296 }
1297 }
1298
1299 sqlite3_stmt* ppstmt;
1300 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
1301 {
1302 db_error(ppdb, query);
1303 }
416 1304
417 sqlite3_bind_text(ppstmt, 1, word.c_str(), word.length(), SQLITE_STATIC); 1305 sqlite3_bind_int(ppstmt, 1, wn[synset_id_1][wnum_1]);
1306 sqlite3_bind_int(ppstmt, 2, wn[synset_id_2][wnum_2]);
418 1307
419 if (sqlite3_step(ppstmt) != SQLITE_DONE) 1308 if (sqlite3_step(ppstmt) != SQLITE_DONE)
1309 {
1310 db_error(ppdb, query);
1311 }
1312
1313 sqlite3_finalize(ppstmt);
1314 }
1315 }
1316
1317 // sa table
1318 {
1319 std::ifstream wnsafile(wnpref + "wn_sa.pl");
1320 if (!wnsafile.is_open())
420 { 1321 {
421 std::cout << "Error writing to output database: " << sqlite3_errmsg(ppdb) << std::endl; 1322 std::cout << "Invalid WordNet data directory." << std::endl;
422 sqlite3_close_v2(ppdb);
423 print_usage(); 1323 print_usage();
424 } 1324 }
1325
1326 std::list<std::string> lines;
1327 for (;;)
1328 {
1329 std::string line;
1330 if (!getline(wnsafile, line))
1331 {
1332 break;
1333 }
1334
1335 if (line.back() == '\r')
1336 {
1337 line.pop_back();
1338 }
1339
1340 lines.push_back(line);
1341 }
425 1342
426 sqlite3_finalize(ppstmt); 1343 progress ppgs("Writing specifications...", lines.size());
1344 for (auto line : lines)
1345 {
1346 ppgs.update();
1347
1348 std::regex relation("^per\\((3\\d{8}),(\\d+),(3\\d{8}),(\\d+)\\)\\.");
1349 std::smatch relation_data;
1350 if (!std::regex_search(line, relation_data, relation))
1351 {
1352 continue;
1353 }
1354
1355 int synset_id_1 = stoi(relation_data[1]);
1356 int wnum_1 = stoi(relation_data[2]);
1357 int synset_id_2 = stoi(relation_data[3]);
1358 int wnum_2 = stoi(relation_data[4]);
1359 std::string query("INSERT INTO specification (general_id, specific_id) VALUES (?, ?)");
1360
1361 sqlite3_stmt* ppstmt;
1362 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
1363 {
1364 db_error(ppdb, query);
1365 }
1366
1367 sqlite3_bind_int(ppstmt, 1, wn[synset_id_1][wnum_1]);
1368 sqlite3_bind_int(ppstmt, 2, wn[synset_id_2][wnum_2]);
427 1369
428 query = "SELECT last_insert_rowid()"; 1370 if (sqlite3_step(ppstmt) != SQLITE_DONE)
429 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) 1371 {
1372 db_error(ppdb, query);
1373 }
1374
1375 sqlite3_finalize(ppstmt);
1376 }
1377 }
1378 /*
1379 // sim table
1380 {
1381 std::ifstream wnsimfile(wnpref + "wn_sim.pl");
1382 if (!wnsimfile.is_open())
430 { 1383 {
431 std::cout << "Error writing to output database: " << sqlite3_errmsg(ppdb) << std::endl; 1384 std::cout << "Invalid WordNet data directory." << std::endl;
432 sqlite3_close_v2(ppdb);
433 print_usage(); 1385 print_usage();
434 } 1386 }
1387
1388 std::list<std::string> lines;
1389 for (;;)
1390 {
1391 std::string line;
1392 if (!getline(wnsimfile, line))
1393 {
1394 break;
1395 }
1396
1397 if (line.back() == '\r')
1398 {
1399 line.pop_back();
1400 }
1401
1402 lines.push_back(line);
1403 }
435 1404
436 if (sqlite3_step(ppstmt) != SQLITE_ROW) 1405 progress ppgs("Writing sense synonyms...", lines.size());
1406 for (auto line : lines)
1407 {
1408 ppgs.update();
1409
1410 std::regex relation("^sim\\((3\\d{8}),(3\\d{8})\\)\\.");
1411 std::smatch relation_data;
1412 if (!std::regex_search(line, relation_data, relation))
1413 {
1414 continue;
1415 }
1416
1417 int synset_id_1 = stoi(relation_data[1]);
1418 int synset_id_2 = stoi(relation_data[2]);
1419 std::string query("INSERT INTO adjective_synonymy (adjective_1_id, adjective_2_id) VALUES (?, ?)");
1420
1421 for (auto mapping1 : wn[synset_id_1])
1422 {
1423 for (auto mapping2 : wn[synset_id_2])
1424 {
1425 sqlite3_stmt* ppstmt;
1426 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.size(), &ppstmt, NULL) != SQLITE_OK)
1427 {
1428 db_error(ppdb, query);
1429 }
1430
1431 sqlite3_bind_int(ppstmt, 1, mapping1.second);
1432 sqlite3_bind_int(ppstmt, 2, mapping2.second);
1433
1434 if (sqlite3_step(ppstmt) != SQLITE_DONE)
1435 {
1436 db_error(ppdb, query);
1437 }
1438
1439 sqlite3_reset(ppstmt);
1440 sqlite3_clear_bindings(ppstmt);
1441
1442 sqlite3_bind_int(ppstmt, 1, mapping2.second);
1443 sqlite3_bind_int(ppstmt, 2, mapping1.second);
1444
1445 if (sqlite3_step(ppstmt) != SQLITE_DONE)
1446 {
1447 db_error(ppdb, query);
1448 }
1449
1450 sqlite3_finalize(ppstmt);
1451 }
1452 }
1453 }
1454 }
1455 */
1456 // syntax table
1457 {
1458 std::ifstream wnsyntaxfile(wnpref + "wn_syntax.pl");
1459 if (!wnsyntaxfile.is_open())
437 { 1460 {
438 std::cout << "Error writing to output database: " << sqlite3_errmsg(ppdb) << std::endl; 1461 std::cout << "Invalid WordNet data directory." << std::endl;
439 sqlite3_close_v2(ppdb);
440 print_usage(); 1462 print_usage();
441 } 1463 }
1464
1465 std::list<std::string> lines;
1466 for (;;)
1467 {
1468 std::string line;
1469 if (!getline(wnsyntaxfile, line))
1470 {
1471 break;
1472 }
442 1473
443 wn[synset_id][wnum] = sqlite3_column_int(ppstmt, 0); 1474 if (line.back() == '\r')
1475 {
1476 line.pop_back();
1477 }
1478
1479 lines.push_back(line);
1480 }
444 1481
445 sqlite3_finalize(ppstmt); 1482 progress ppgs("Writing adjective syntax markers...", lines.size());
1483 for (auto line : lines)
1484 {
1485 ppgs.update();
1486
1487 std::regex relation("^syntax\\((3\\d{8}),(\\d+),([ipa])p?\\)\\.");
1488 std::smatch relation_data;
1489 if (!std::regex_search(line, relation_data, relation))
1490 {
1491 continue;
1492 }
1493
1494 int synset_id = stoi(relation_data[1]);
1495 int wnum = stoi(relation_data[2]);
1496 std::string syn = relation_data[3];
1497 std::string query("UPDATE adjectives SET position = ? WHERE adjective_id = ?");
1498
1499 sqlite3_stmt* ppstmt;
1500 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.size(), &ppstmt, NULL) != SQLITE_OK)
1501 {
1502 db_error(ppdb, query);
1503 }
1504
1505 sqlite3_bind_text(ppstmt, 1, syn.c_str(), 1, SQLITE_STATIC);
1506 sqlite3_bind_int(ppstmt, 2, wn[synset_id][wnum]);
1507
1508 if (sqlite3_step(ppstmt) != SQLITE_DONE)
1509 {
1510 db_error(ppdb, query);
1511 }
1512
1513 sqlite3_finalize(ppstmt);
1514 }
446 } 1515 }
447 1516
448 sqlite3_close_v2(ppdb); 1517 sqlite3_close_v2(ppdb);
449 1518
450 std::cout << "Done." << std::endl; 1519 std::cout << "Done." << std::endl;
451} \ No newline at end of file 1520}
diff --git a/progress.h b/progress.h new file mode 100644 index 0000000..81f07a3 --- /dev/null +++ b/progress.h
@@ -0,0 +1,50 @@
1#ifndef PROGRESS_H_A34EF856
2#define PROGRESS_H_A34EF856
3
4#include <string>
5
6class progress {
7 private:
8 std::string message;
9 int total;
10 int cur = 0;
11 int lprint = 0;
12
13 public:
14 progress(std::string message, int total) : message(message), total(total)
15 {
16 std::cout << message << " 0%" << std::flush;
17 }
18
19 void update(int val)
20 {
21 if (val <= total)
22 {
23 cur = val;
24 } else {
25 cur = total;
26 }
27
28 int pp = cur * 100 / total;
29 if (pp != lprint)
30 {
31 lprint = pp;
32
33 std::cout << "\b\b\b\b" << std::right;
34 std::cout.width(3);
35 std::cout << pp << "%" << std::flush;
36 }
37 }
38
39 void update()
40 {
41 update(cur+1);
42 }
43
44 ~progress()
45 {
46 std::cout << "\b\b\b\b100%" << std::endl;
47 }
48};
49
50#endif /* end of include guard: PROGRESS_H_A34EF856 */
diff --git a/schema.sql b/schema.sql index 62dd780..fd55734 100644 --- a/schema.sql +++ b/schema.sql
@@ -34,20 +34,25 @@ CREATE TABLE `verb_groups` (
34DROP TABLE IF EXISTS `adjectives`; 34DROP TABLE IF EXISTS `adjectives`;
35CREATE TABLE `adjectives` ( 35CREATE TABLE `adjectives` (
36 `adjective_id` INTEGER PRIMARY KEY, 36 `adjective_id` INTEGER PRIMARY KEY,
37 `form` VARCHAR(32) NOT NULL, 37 `base_form` VARCHAR(32) NOT NULL,
38 `comparative` VARCHAR(32),
39 `superlative` VARCHAR(32),
38 `position` CHAR(1) 40 `position` CHAR(1)
39); 41);
40 42
41DROP TABLE IF EXISTS `adverbs`; 43DROP TABLE IF EXISTS `adverbs`;
42CREATE TABLE `adverbs` ( 44CREATE TABLE `adverbs` (
43 `adverb_id` INTEGER PRIMARY KEY, 45 `adverb_id` INTEGER PRIMARY KEY,
44 `form` VARCHAR(32) NOT NULL 46 `base_form` VARCHAR(32) NOT NULL,
47 `comparative` VARCHAR(32),
48 `superlative` VARCHAR(32)
45); 49);
46 50
47DROP TABLE IF EXISTS `nouns`; 51DROP TABLE IF EXISTS `nouns`;
48CREATE TABLE `nouns` ( 52CREATE TABLE `nouns` (
49 `noun_id` INTEGER PRIMARY KEY, 53 `noun_id` INTEGER PRIMARY KEY,
50 `form` VARCHAR(32) NOT NULL 54 `singular` VARCHAR(32) NOT NULL,
55 `plural` VARCHAR(32)
51); 56);
52 57
53DROP TABLE IF EXISTS `hypernymy`; 58DROP TABLE IF EXISTS `hypernymy`;
@@ -146,10 +151,54 @@ CREATE TABLE `mannernymy` (
146 FOREIGN KEY (`mannernym_id`) REFERENCES `adverbs`(`adverb_id`) 151 FOREIGN KEY (`mannernym_id`) REFERENCES `adverbs`(`adverb_id`)
147); 152);
148 153
149DROP TABLE IF EXISTS `synonymy`; 154DROP TABLE IF EXISTS `noun_synonymy`;
150CREATE TABLE `synonymy` ( 155CREATE TABLE `noun_synonymy` (
156 `noun_1_id` INTEGER NOT NULL,
157 `noun_2_id` INTEGER NOT NULL,
158 FOREIGN KEY (`noun_1_id`) REFERENCES `nouns`(`nouns_id`),
159 FOREIGN KEY (`noun_2_id`) REFERENCES `nouns`(`nouns_id`)
160);
161
162DROP TABLE IF EXISTS `adjective_synonymy`;
163CREATE TABLE `adjective_synonymy` (
151 `adjective_1_id` INTEGER NOT NULL, 164 `adjective_1_id` INTEGER NOT NULL,
152 `adjective_2_id` INTEGER NOT NULL, 165 `adjective_2_id` INTEGER NOT NULL,
153 FOREIGN KEY (`adjective_1_id`) REFERENCES `adjectives`(`adjective_id`), 166 FOREIGN KEY (`adjective_1_id`) REFERENCES `adjectives`(`adjective_id`),
154 FOREIGN KEY (`adjective_2_id`) REFERENCES `adjectives`(`adjective_id`) 167 FOREIGN KEY (`adjective_2_id`) REFERENCES `adjectives`(`adjective_id`)
155); 168);
169
170DROP TABLE IF EXISTS `adverb_synonymy`;
171CREATE TABLE `adverb_synonymy` (
172 `adverb_1_id` INTEGER NOT NULL,
173 `adverb_2_id` INTEGER NOT NULL,
174 FOREIGN KEY (`adverb_1_id`) REFERENCES `adverbs`(`adverb_id`),
175 FOREIGN KEY (`adverb_2_id`) REFERENCES `adverbs`(`adverb_id`)
176);
177
178DROP TABLE IF EXISTS `noun_pronunciations`;
179CREATE TABLE `noun_pronunciations` (
180 `noun_id` INTEGER NOT NULL,
181 `pronunciation` VARCHAR(64) NOT NULL,
182 FOREIGN KEY (`noun_id`) REFERENCES `nouns`(`noun_id`)
183);
184
185DROP TABLE IF EXISTS `verb_pronunciations`;
186CREATE TABLE `verb_pronunciations` (
187 `verb_id` INTEGER NOT NULL,
188 `pronunciation` VARCHAR(64) NOT NULL,
189 FOREIGN KEY (`verb_id`) REFERENCES `verbs`(`verb_id`)
190);
191
192DROP TABLE IF EXISTS `adjective_pronunciations`;
193CREATE TABLE `adjective_pronunciations` (
194 `adjective_id` INTEGER NOT NULL,
195 `pronunciation` VARCHAR(64) NOT NULL,
196 FOREIGN KEY (`adjective_id`) REFERENCES `adjectives`(`adjective_id`)
197);
198
199DROP TABLE IF EXISTS `adverb_pronunciations`;
200CREATE TABLE `adverb_pronunciations` (
201 `adverb_id` INTEGER NOT NULL,
202 `pronunciation` VARCHAR(64) NOT NULL,
203 FOREIGN KEY (`adverb_id`) REFERENCES `adverbs`(`adverb_id`)
204);
diff --git a/verbly/adjective.cpp b/verbly/adjective.cpp new file mode 100644 index 0000000..0f4087f --- /dev/null +++ b/verbly/adjective.cpp
@@ -0,0 +1,586 @@
1#include "verbly.h"
2
3namespace verbly {
4
5 adjective::adjective(const data& _data, int _id) : word(_data, _id)
6 {
7
8 }
9
10 std::string adjective::base_form() const
11 {
12 return _base_form;
13 }
14
15 std::string adjective::comparative_form() const
16 {
17 return _comparative_form;
18 }
19
20 std::string adjective::superlative_form() const
21 {
22 return _superlative_form;
23 }
24
25 adjective::positioning adjective::position() const
26 {
27 return _position;
28 }
29
30 bool adjective::has_comparative_form() const
31 {
32 return !_comparative_form.empty();
33 }
34
35 bool adjective::has_superlative_form() const
36 {
37 return !_superlative_form.empty();
38 }
39
40 bool adjective::has_position() const
41 {
42 return _position != adjective::positioning::undefined;
43 }
44
45 adjective_query adjective::antonyms() const
46 {
47 return _data.adjectives().antonym_of(*this);
48 }
49
50 adjective_query adjective::synonyms() const
51 {
52 return _data.adjectives().synonym_of(*this);
53 }
54
55 adjective_query adjective::generalizations() const
56 {
57 return _data.adjectives().generalization_of(*this);
58 }
59
60 adjective_query adjective::specifications() const
61 {
62 return _data.adjectives().specification_of(*this);
63 }
64
65 noun_query adjective::anti_pertainyms() const
66 {
67 return _data.nouns().anti_pertainym_of(*this);
68 }
69
70 adverb_query adjective::mannernyms() const
71 {
72 return _data.adverbs().mannernym_of(*this);
73 }
74
75 noun_query adjective::attributes() const
76 {
77 return _data.nouns().attribute_of(*this);
78 }
79
80 adjective_query::adjective_query(const data& _data) : _data(_data)
81 {
82
83 }
84
85 adjective_query& adjective_query::limit(int _limit)
86 {
87 if ((_limit > 0) || (_limit == unlimited))
88 {
89 this->_limit = _limit;
90 }
91
92 return *this;
93 }
94
95 adjective_query& adjective_query::random(bool _random)
96 {
97 this->_random = _random;
98
99 return *this;
100 }
101
102 adjective_query& adjective_query::except(const adjective& _word)
103 {
104 _except.push_back(_word);
105
106 return *this;
107 }
108
109 adjective_query& adjective_query::rhymes_with(const word& _word)
110 {
111 for (auto rhyme : _word.rhyme_phonemes())
112 {
113 _rhymes.push_back(rhyme);
114 }
115
116 if (dynamic_cast<const adjective*>(&_word) != nullptr)
117 {
118 _except.push_back(dynamic_cast<const adjective&>(_word));
119 }
120
121 return *this;
122 }
123
124 adjective_query& adjective_query::has_pronunciation(bool _has_prn)
125 {
126 this->_has_prn = _has_prn;
127
128 return *this;
129 }
130
131 adjective_query& adjective_query::is_variant(bool _is_variant)
132 {
133 this->_is_variant = _is_variant;
134
135 return *this;
136 }
137
138 adjective_query& adjective_query::variant_of(const noun& _noun)
139 {
140 _variant_of.push_back(_noun);
141
142 return *this;
143 }
144
145 adjective_query& adjective_query::not_variant_of(const noun& _noun)
146 {
147 _not_variant_of.push_back(_noun);
148
149 return *this;
150 }
151
152 adjective_query& adjective_query::has_antonyms(bool _is_antonymic)
153 {
154 this->_is_antonymic = _is_antonymic;
155
156 return *this;
157 }
158
159 adjective_query& adjective_query::antonym_of(const adjective& _adj)
160 {
161 _antonym_of.push_back(_adj);
162
163 return *this;
164 }
165
166 adjective_query& adjective_query::not_antonym_of(const adjective& _adj)
167 {
168 _not_antonym_of.push_back(_adj);
169
170 return *this;
171 }
172
173 adjective_query& adjective_query::has_synonyms(bool _is_synonymic)
174 {
175 this->_is_synonymic = _is_synonymic;
176
177 return *this;
178 }
179
180 adjective_query& adjective_query::synonym_of(const adjective& _adj)
181 {
182 _synonym_of.push_back(_adj);
183
184 return *this;
185 }
186
187 adjective_query& adjective_query::not_synonym_of(const adjective& _adj)
188 {
189 _not_synonym_of.push_back(_adj);
190
191 return *this;
192 }
193
194 adjective_query& adjective_query::is_generalization(bool _is_generalization)
195 {
196 this->_is_generalization = _is_generalization;
197
198 return *this;
199 }
200
201 adjective_query& adjective_query::generalization_of(const adjective& _adj)
202 {
203 _generalization_of.push_back(_adj);
204
205 return *this;
206 }
207
208 adjective_query& adjective_query::not_generalization_of(const adjective& _adj)
209 {
210 _not_generalization_of.push_back(_adj);
211
212 return *this;
213 }
214
215 adjective_query& adjective_query::is_specification(bool _is_specification)
216 {
217 this->_is_specification = _is_specification;
218
219 return *this;
220 }
221
222 adjective_query& adjective_query::specification_of(const adjective& _adj)
223 {
224 _specification_of.push_back(_adj);
225
226 return *this;
227 }
228
229 adjective_query& adjective_query::not_specification_of(const adjective& _adj)
230 {
231 _not_specification_of.push_back(_adj);
232
233 return *this;
234 }
235
236 adjective_query& adjective_query::is_pertainymic(bool _is_pertainymic)
237 {
238 this->_is_pertainymic = _is_pertainymic;
239
240 return *this;
241 }
242
243 adjective_query& adjective_query::pertainym_of(const noun& _noun)
244 {
245 _pertainym_of.push_back(_noun);
246
247 return *this;
248 }
249
250 adjective_query& adjective_query::is_mannernymic(bool _is_mannernymic)
251 {
252 this->_is_mannernymic = _is_mannernymic;
253
254 return *this;
255 }
256
257 adjective_query& adjective_query::anti_mannernym_of(const adverb& _adv)
258 {
259 _anti_mannernym_of.push_back(_adv);
260
261 return *this;
262 }
263
264 std::list<adjective> adjective_query::run() const
265 {
266 std::stringstream construct;
267 construct << "SELECT adjective_id, base_form, comparative, superlative, position FROM adjectives";
268 std::list<std::string> conditions;
269
270 if (_has_prn)
271 {
272 conditions.push_back("adjective_id IN (SELECT adjective_id FROM adjective_pronunciations)");
273 }
274
275 if (!_rhymes.empty())
276 {
277 std::list<std::string> clauses(_rhymes.size(), "pronunciation LIKE @RHMPRN");
278 std::string cond = "adjective_id IN (SELECT adjective_id FROM adjective_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
279 conditions.push_back(cond);
280 }
281
282 for (auto except : _except)
283 {
284 conditions.push_back("adjective_id != @EXCID");
285 }
286
287 if (_requires_comparative_form)
288 {
289 conditions.push_back("comparative IS NOT NULL");
290 }
291
292 if (_requires_superlative_form)
293 {
294 conditions.push_back("superlative IS NOT NULL");
295 }
296
297 if (_position != adjective::positioning::undefined)
298 {
299 switch (_position)
300 {
301 case adjective::positioning::predicate: conditions.push_back("position = 'p'"); break;
302 case adjective::positioning::attributive: conditions.push_back("position = 'a'"); break;
303 case adjective::positioning::postnominal: conditions.push_back("position = 'i'"); break;
304 }
305 }
306
307 if (_is_variant)
308 {
309 conditions.push_back("adjective_id IN (SELECT adjective_id FROM variation)");
310 }
311
312 if (!_variant_of.empty())
313 {
314 std::list<std::string> clauses(_variant_of.size(), "noun_id = @ATTRID");
315 std::string cond = "adjective_id IN (SELECT adjective_id FROM variation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
316 conditions.push_back(cond);
317 }
318
319 if (!_not_variant_of.empty())
320 {
321 std::list<std::string> clauses(_not_variant_of.size(), "noun_id = @NATTRID");
322 std::string cond = "adjective_id NOT IN (SELECT adjective_id FROM variation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
323 conditions.push_back(cond);
324 }
325
326 if (_is_antonymic)
327 {
328 conditions.push_back("adjective_id IN (SELECT adjective_2_id FROM adjective_antonymy)");
329 }
330
331 if (!_antonym_of.empty())
332 {
333 std::list<std::string> clauses(_antonym_of.size(), "adjective_1_id = @ANTID");
334 std::string cond = "adjective_id IN (SELECT adjective_2_id FROM adjective_antonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
335 conditions.push_back(cond);
336 }
337
338 if (!_not_antonym_of.empty())
339 {
340 std::list<std::string> clauses(_not_antonym_of.size(), "adjective_1_id = @NANTID");
341 std::string cond = "adjective_id NOT IN (SELECT adjective_2_id FROM adjective_antonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
342 conditions.push_back(cond);
343 }
344
345 if (_is_synonymic)
346 {
347 conditions.push_back("adjective_id IN (SELECT adjective_2_id FROM adjective_synonymy)");
348 }
349
350 if (!_synonym_of.empty())
351 {
352 std::list<std::string> clauses(_synonym_of.size(), "adjective_1_id = @SYNID");
353 std::string cond = "adjective_id IN (SELECT adjective_2_id FROM adjective_synonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
354 conditions.push_back(cond);
355 }
356
357 if (!_not_synonym_of.empty())
358 {
359 std::list<std::string> clauses(_not_synonym_of.size(), "adjective_1_id = @NSYNID");
360 std::string cond = "adjective_id NOT IN (SELECT adjective_2_id FROM adjective_synonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
361 conditions.push_back(cond);
362 }
363
364 if (_is_generalization)
365 {
366 conditions.push_back("adjective_id IN (SELECT general_id FROM specification)");
367 }
368
369 if (!_generalization_of.empty())
370 {
371 std::list<std::string> clauses(_generalization_of.size(), "specific_id = @SPECID");
372 std::string cond = "adjective_id IN (SELECT general_id FROM specification WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
373 conditions.push_back(cond);
374 }
375
376 if (!_not_generalization_of.empty())
377 {
378 std::list<std::string> clauses(_not_generalization_of.size(), "specific_id = @NSPECID");
379 std::string cond = "adjective_id NOT IN (SELECT general_id FROM specification WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
380 conditions.push_back(cond);
381 }
382
383 if (_is_specification)
384 {
385 conditions.push_back("adjective_id IN (SELECT specific_id FROM specification)");
386 }
387
388 if (!_specification_of.empty())
389 {
390 std::list<std::string> clauses(_specification_of.size(), "general_id = @GENID");
391 std::string cond = "adjective_id IN (SELECT specific_id FROM specification WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
392 conditions.push_back(cond);
393 }
394
395 if (!_not_specification_of.empty())
396 {
397 std::list<std::string> clauses(_not_specification_of.size(), "general_id = @NGENID");
398 std::string cond = "adjective_id NOT IN (SELECT specific_id FROM specification WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
399 conditions.push_back(cond);
400 }
401
402 if (_is_pertainymic)
403 {
404 conditions.push_back("adjective_id IN (SELECT pertainym_id FROM pertainymy)");
405 }
406
407 if (!_pertainym_of.empty())
408 {
409 std::list<std::string> clauses(_pertainym_of.size(), "noun_id = @APERID");
410 std::string cond = "adjective_id IN (SELECT pertainym_id FROM pertainymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
411 conditions.push_back(cond);
412 }
413
414 if (_is_mannernymic)
415 {
416 conditions.push_back("adjective_id IN (SELECT adjective_id FROM mannernymy)");
417 }
418
419 if (!_anti_mannernym_of.empty())
420 {
421 std::list<std::string> clauses(_anti_mannernym_of.size(), "mannernym_id = @MANID");
422 std::string cond = "adjective_id IN (SELECT adjective_id FROM mannernymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
423 conditions.push_back(cond);
424 }
425
426 if (!conditions.empty())
427 {
428 construct << " WHERE ";
429 construct << verbly::implode(std::begin(conditions), std::end(conditions), " AND ");
430 }
431
432 if (_random)
433 {
434 construct << " ORDER BY RANDOM()";
435 }
436
437 if (_limit != unlimited)
438 {
439 construct << " LIMIT " << _limit;
440 }
441
442 sqlite3_stmt* ppstmt;
443 std::string query = construct.str();
444 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
445 {
446 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
447 }
448
449 if (!_rhymes.empty())
450 {
451 int i = 0;
452 for (auto rhyme : _rhymes)
453 {
454 std::string rhymer = "%" + rhyme;
455 sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@RHMPRN"), rhymer.c_str(), rhymer.length(), SQLITE_STATIC);
456
457 i++;
458 }
459 }
460
461 for (auto except : _except)
462 {
463 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@EXCID"), except._id);
464 }
465
466 for (auto attribute : _variant_of)
467 {
468 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@ATTRID"), attribute._id);
469 }
470
471 for (auto attribute : _not_variant_of)
472 {
473 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NATTRID"), attribute._id);
474 }
475
476 for (auto antonym : _antonym_of)
477 {
478 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@ANTID"), antonym._id);
479 }
480
481 for (auto antonym : _not_antonym_of)
482 {
483 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NANTID"), antonym._id);
484 }
485
486 for (auto synonym : _synonym_of)
487 {
488 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SYNID"), synonym._id);
489 }
490
491 for (auto synonym : _not_synonym_of)
492 {
493 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NSYNID"), synonym._id);
494 }
495
496 for (auto specific : _generalization_of)
497 {
498 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SPECID"), specific._id);
499 }
500
501 for (auto specific : _not_generalization_of)
502 {
503 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NSPECID"), specific._id);
504 }
505
506 for (auto general : _specification_of)
507 {
508 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@GENID"), general._id);
509 }
510
511 for (auto general : _not_specification_of)
512 {
513 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NGENID"), general._id);
514 }
515
516 for (auto n : _pertainym_of)
517 {
518 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@APERID"), n._id);
519 }
520
521 for (auto mannernym : _anti_mannernym_of)
522 {
523 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@MANID"), mannernym._id);
524 }
525
526 std::list<adjective> output;
527 while (sqlite3_step(ppstmt) == SQLITE_ROW)
528 {
529 adjective tnc {_data, sqlite3_column_int(ppstmt, 0)};
530 tnc._base_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
531
532 if (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL)
533 {
534 tnc._comparative_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
535 }
536
537 if (sqlite3_column_type(ppstmt, 3) != SQLITE_NULL)
538 {
539 tnc._superlative_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 3)));
540 }
541
542 if (sqlite3_column_type(ppstmt, 4) != SQLITE_NULL)
543 {
544 std::string adjpos(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 4)));
545 if (adjpos == "p")
546 {
547 tnc._position = adjective::positioning::predicate;
548 } else if (adjpos == "a")
549 {
550 tnc._position = adjective::positioning::attributive;
551 } else if (adjpos == "i")
552 {
553 tnc._position = adjective::positioning::postnominal;
554 }
555 }
556
557 output.push_back(tnc);
558 }
559
560 sqlite3_finalize(ppstmt);
561
562 for (auto& adjective : output)
563 {
564 query = "SELECT pronunciation FROM adjective_pronunciations WHERE adjective_id = ?";
565 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
566 {
567 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
568 }
569
570 sqlite3_bind_int(ppstmt, 1, adjective._id);
571
572 while (sqlite3_step(ppstmt) == SQLITE_ROW)
573 {
574 std::string pronunciation(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 0)));
575 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " ");
576
577 adjective.pronunciations.push_back(phonemes);
578 }
579
580 sqlite3_finalize(ppstmt);
581 }
582
583 return output;
584 }
585
586};
diff --git a/verbly/adjective.h b/verbly/adjective.h index 9d7883f..4927d59 100644 --- a/verbly/adjective.h +++ b/verbly/adjective.h
@@ -3,17 +3,129 @@
3 3
4namespace verbly { 4namespace verbly {
5 5
6 class adjective { 6 class adjective_query;
7 class adverb_query;
8 class noun_query;
9
10 class adjective : public word {
11 public:
12 enum class positioning {
13 undefined,
14 predicate,
15 attributive,
16 postnominal
17 };
18
7 private: 19 private:
8 int id; 20 std::string _base_form;
21 std::string _comparative_form;
22 std::string _superlative_form;
23 positioning _position = positioning::undefined;
24
25 friend class adjective_query;
26
27 public:
28 adjective(const data& _data, int _id);
29
30 std::string base_form() const;
31 std::string comparative_form() const;
32 std::string superlative_form() const;
33 positioning position() const;
34
35 bool has_comparative_form() const;
36 bool has_superlative_form() const;
37 bool has_position() const;
9 38
39 adjective_query antonyms() const;
40 adjective_query synonyms() const;
41 adjective_query generalizations() const;
42 adjective_query specifications() const;
43 noun_query anti_pertainyms() const;
44 adverb_query mannernyms() const;
45 noun_query attributes() const;
46 };
47
48 class adjective_query {
10 public: 49 public:
11 std::string form; 50 adjective_query(const data& _data);
51
52 adjective_query& limit(int _limit);
53 adjective_query& random(bool _random);
54 adjective_query& except(const adjective& _word);
55 adjective_query& rhymes_with(const word& _word);
56 adjective_query& has_pronunciation(bool _has_prn);
57
58 adjective_query& requires_comparative_form(bool req);
59 adjective_query& requires_superlative_form(bool req);
60 adjective_query& position(adjective::positioning pos);
61
62 adjective_query& is_variant(bool _is_variant);
63 adjective_query& variant_of(const noun& _noun);
64 adjective_query& not_variant_of(const noun& _noun);
65
66 adjective_query& has_antonyms(bool _is_antonymic);
67 adjective_query& antonym_of(const adjective& _adj);
68 adjective_query& not_antonym_of(const adjective& _adj);
69
70 adjective_query& has_synonyms(bool _is_synonymic);
71 adjective_query& synonym_of(const adjective& _adj);
72 adjective_query& not_synonym_of(const adjective& _adj);
73
74 adjective_query& is_generalization(bool _is_generalization);
75 adjective_query& generalization_of(const adjective& _adj);
76 adjective_query& not_generalization_of(const adjective& _adj);
77
78 adjective_query& is_specification(bool _is_specification);
79 adjective_query& specification_of(const adjective& _adj);
80 adjective_query& not_specification_of(const adjective& _adj);
81
82 adjective_query& is_pertainymic(bool _is_pertainymic);
83 adjective_query& pertainym_of(const noun& _noun);
84
85 adjective_query& is_mannernymic(bool _is_mannernymic);
86 adjective_query& anti_mannernym_of(const adverb& _adv);
87
88 std::list<adjective> run() const;
89
90 const static int unlimited = -1;
91
92 protected:
93 const data& _data;
94 int _limit = unlimited;
95 bool _random = false;
96 std::list<std::string> _rhymes;
97 std::list<adjective> _except;
98 bool _has_prn = false;
99
100 bool _requires_comparative_form = false;
101 bool _requires_superlative_form = false;
102 adjective::positioning _position = adjective::positioning::undefined;
103
104 bool _is_variant = false;
105 std::list<noun> _variant_of;
106 std::list<noun> _not_variant_of;
107
108 bool _is_antonymic = false;
109 std::list<adjective> _antonym_of;
110 std::list<adjective> _not_antonym_of;
111
112 bool _is_synonymic = false;
113 std::list<adjective> _synonym_of;
114 std::list<adjective> _not_synonym_of;
115
116 bool _is_generalization = false;
117 std::list<adjective> _generalization_of;
118 std::list<adjective> _not_generalization_of;
119
120 bool _is_specification = false;
121 std::list<adjective> _specification_of;
122 std::list<adjective> _not_specification_of;
123
124 bool _is_pertainymic = false;
125 std::list<noun> _pertainym_of;
12 126
13 adjective(int id) : id(id) 127 bool _is_mannernymic = false;
14 { 128 std::list<adverb> _anti_mannernym_of;
15
16 }
17 }; 129 };
18 130
19}; 131};
diff --git a/verbly/adverb.cpp b/verbly/adverb.cpp new file mode 100644 index 0000000..9bb5a0d --- /dev/null +++ b/verbly/adverb.cpp
@@ -0,0 +1,364 @@
1#include "verbly.h"
2
3namespace verbly {
4
5 adverb::adverb(const data& _data, int _id) : word(_data, _id)
6 {
7
8 }
9
10 std::string adverb::base_form() const
11 {
12 return _base_form;
13 }
14
15 std::string adverb::comparative_form() const
16 {
17 return _comparative_form;
18 }
19
20 std::string adverb::superlative_form() const
21 {
22 return _superlative_form;
23 }
24
25 bool adverb::has_comparative_form() const
26 {
27 return !_comparative_form.empty();
28 }
29
30 bool adverb::has_superlative_form() const
31 {
32 return !_superlative_form.empty();
33 }
34
35 adverb_query adverb::antonyms() const
36 {
37 return _data.adverbs().antonym_of(*this);
38 }
39
40 adverb_query adverb::synonyms() const
41 {
42 return _data.adverbs().synonym_of(*this);
43 }
44
45 adjective_query adverb::anti_mannernyms() const
46 {
47 return _data.adjectives().anti_mannernym_of(*this);
48 }
49
50 adverb_query::adverb_query(const data& _data) : _data(_data)
51 {
52
53 }
54
55 adverb_query& adverb_query::limit(int _limit)
56 {
57 if ((_limit > 0) || (_limit == unlimited))
58 {
59 this->_limit = _limit;
60 }
61
62 return *this;
63 }
64
65 adverb_query& adverb_query::random(bool _random)
66 {
67 this->_random = _random;
68
69 return *this;
70 }
71
72 adverb_query& adverb_query::except(const adverb& _word)
73 {
74 _except.push_back(_word);
75
76 return *this;
77 }
78
79 adverb_query& adverb_query::rhymes_with(const word& _word)
80 {
81 for (auto rhyme : _word.rhyme_phonemes())
82 {
83 _rhymes.push_back(rhyme);
84 }
85
86 if (dynamic_cast<const adverb*>(&_word) != nullptr)
87 {
88 _except.push_back(dynamic_cast<const adverb&>(_word));
89 }
90
91 return *this;
92 }
93
94 adverb_query& adverb_query::has_pronunciation(bool _has_prn)
95 {
96 this->_has_prn = _has_prn;
97
98 return *this;
99 }
100
101 adverb_query& adverb_query::requires_comparative_form(bool _arg)
102 {
103 _requires_comparative_form = _arg;
104
105 return *this;
106 }
107
108 adverb_query& adverb_query::requires_superlative_form(bool _arg)
109 {
110 _requires_superlative_form = _arg;
111
112 return *this;
113 }
114
115 adverb_query& adverb_query::has_antonyms(bool _arg)
116 {
117 _has_antonyms = _arg;
118
119 return *this;
120 }
121
122 adverb_query& adverb_query::antonym_of(const adverb& _adv)
123 {
124 _antonym_of.push_back(_adv);
125
126 return *this;
127 }
128
129 adverb_query& adverb_query::not_antonym_of(const adverb& _adv)
130 {
131 _not_antonym_of.push_back(_adv);
132
133 return *this;
134 }
135
136 adverb_query& adverb_query::has_synonyms(bool _arg)
137 {
138 _has_synonyms = _arg;
139
140 return *this;
141 }
142
143 adverb_query& adverb_query::synonym_of(const adverb& _adv)
144 {
145 _synonym_of.push_back(_adv);
146
147 return *this;
148 }
149
150 adverb_query& adverb_query::not_synonym_of(const adverb& _adv)
151 {
152 _not_synonym_of.push_back(_adv);
153
154 return *this;
155 }
156
157 adverb_query& adverb_query::is_mannernymic(bool _arg)
158 {
159 _is_mannernymic = _arg;
160
161 return *this;
162 }
163
164 adverb_query& adverb_query::mannernym_of(const adjective& _adj)
165 {
166 _mannernym_of.push_back(_adj);
167
168 return *this;
169 }
170
171 std::list<adverb> adverb_query::run() const
172 {
173 std::stringstream construct;
174 construct << "SELECT adverb_id, base_form, comparative, superlative FROM adverbs";
175 std::list<std::string> conditions;
176
177 if (_has_prn)
178 {
179 conditions.push_back("adverb_id IN (SELECT adverb_id FROM adverb_pronunciations)");
180 }
181
182 if (!_rhymes.empty())
183 {
184 std::list<std::string> clauses(_rhymes.size(), "pronunciation LIKE @RHMPRN");
185 std::string cond = "adverb_id IN (SELECT adverb_id FROM adverb_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
186 conditions.push_back(cond);
187 }
188
189 for (auto except : _except)
190 {
191 conditions.push_back("adverb_id != @EXCID");
192 }
193
194 if (_requires_comparative_form)
195 {
196 conditions.push_back("comparative IS NOT NULL");
197 }
198
199 if (_requires_superlative_form)
200 {
201 conditions.push_back("superlative IS NOT NULL");
202 }
203
204 if (_has_antonyms)
205 {
206 conditions.push_back("adverb_id IN (SELECT adverb_2_id FROM adverb_antonymy)");
207 }
208
209 if (!_antonym_of.empty())
210 {
211 std::list<std::string> clauses(_antonym_of.size(), "adverb_1_id = @ANTID");
212 std::string cond = "adverb_id IN (SELECT adverb_2_id FROM adverb_antonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
213 conditions.push_back(cond);
214 }
215
216 if (!_not_antonym_of.empty())
217 {
218 std::list<std::string> clauses(_not_antonym_of.size(), "adverb_1_id = @NANTID");
219 std::string cond = "adverb_id NOT IN (SELECT adverb_2_id FROM adverb_antonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
220 conditions.push_back(cond);
221 }
222
223 if (_has_synonyms)
224 {
225 conditions.push_back("adverb_id IN (SELECT adverb_2_id FROM adverb_synonymy)");
226 }
227
228 if (!_synonym_of.empty())
229 {
230 std::list<std::string> clauses(_synonym_of.size(), "adverb_1_id = @SYNID");
231 std::string cond = "adverb_id IN (SELECT adverb_2_id FROM adverb_synonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
232 conditions.push_back(cond);
233 }
234
235 if (!_not_synonym_of.empty())
236 {
237 std::list<std::string> clauses(_not_synonym_of.size(), "adverb_1_id = @NSYNID");
238 std::string cond = "adverb_id NOT IN (SELECT adverb_2_id FROM adverb_synonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
239 conditions.push_back(cond);
240 }
241
242 if (_is_mannernymic)
243 {
244 conditions.push_back("adverb_id IN (SELECT mannernym_id FROM mannernymy)");
245 }
246
247 if (!_mannernym_of.empty())
248 {
249 std::list<std::string> clauses(_mannernym_of.size(), "adjective_id = @AMANID");
250 std::string cond = "adverb_id IN (SELECT mannernym_id FROM mannernymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
251 conditions.push_back(cond);
252 }
253
254 if (!conditions.empty())
255 {
256 construct << " WHERE ";
257 construct << verbly::implode(std::begin(conditions), std::end(conditions), " AND ");
258 }
259
260 if (_random)
261 {
262 construct << " ORDER BY RANDOM()";
263 }
264
265 if (_limit != unlimited)
266 {
267 construct << " LIMIT " << _limit;
268 }
269
270 sqlite3_stmt* ppstmt;
271 std::string query = construct.str();
272 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
273 {
274 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
275 }
276
277 if (!_rhymes.empty())
278 {
279 int i = 0;
280 for (auto rhyme : _rhymes)
281 {
282 std::string rhymer = "%" + rhyme;
283 sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@RHMPRN"), rhymer.c_str(), rhymer.length(), SQLITE_STATIC);
284
285 i++;
286 }
287 }
288
289 for (auto except : _except)
290 {
291 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@EXCID"), except._id);
292 }
293
294 for (auto antonym : _antonym_of)
295 {
296 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@ANTID"), antonym._id);
297 }
298
299 for (auto antonym : _not_antonym_of)
300 {
301 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NANTID"), antonym._id);
302 }
303
304 for (auto synonym : _synonym_of)
305 {
306 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SYNID"), synonym._id);
307 }
308
309 for (auto synonym : _not_synonym_of)
310 {
311 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NSYNID"), synonym._id);
312 }
313
314 for (auto adj : _mannernym_of)
315 {
316 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@AMANID"), adj._id);
317 }
318
319 std::list<adverb> output;
320 while (sqlite3_step(ppstmt) == SQLITE_ROW)
321 {
322 adverb tnc {_data, sqlite3_column_int(ppstmt, 0)};
323 tnc._base_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
324
325 if (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL)
326 {
327 tnc._comparative_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
328 }
329
330 if (sqlite3_column_type(ppstmt, 3) != SQLITE_NULL)
331 {
332 tnc._superlative_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 3)));
333 }
334
335 output.push_back(tnc);
336 }
337
338 sqlite3_finalize(ppstmt);
339
340 for (auto& adverb : output)
341 {
342 query = "SELECT pronunciation FROM adverb_pronunciations WHERE adverb_id = ?";
343 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
344 {
345 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
346 }
347
348 sqlite3_bind_int(ppstmt, 1, adverb._id);
349
350 while (sqlite3_step(ppstmt) == SQLITE_ROW)
351 {
352 std::string pronunciation(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 0)));
353 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " ");
354
355 adverb.pronunciations.push_back(phonemes);
356 }
357
358 sqlite3_finalize(ppstmt);
359 }
360
361 return output;
362 }
363
364};
diff --git a/verbly/adverb.h b/verbly/adverb.h index 6d2466e..42c3492 100644 --- a/verbly/adverb.h +++ b/verbly/adverb.h
@@ -3,17 +3,78 @@
3 3
4namespace verbly { 4namespace verbly {
5 5
6 class adverb { 6 class adverb : public word {
7 private: 7 private:
8 int id; 8 std::string _base_form;
9 std::string _comparative_form;
10 std::string _superlative_form;
9 11
12 friend class adverb_query;
13
14 public:
15 adverb(const data& _data, int _id);
16
17 std::string base_form() const;
18 std::string comparative_form() const;
19 std::string superlative_form() const;
20
21 bool has_comparative_form() const;
22 bool has_superlative_form() const;
23
24 adverb_query antonyms() const;
25 adverb_query synonyms() const;
26 adjective_query anti_mannernyms() const;
27 };
28
29 class adverb_query {
10 public: 30 public:
11 std::string form; 31 adverb_query(const data& _data);
32
33 adverb_query& limit(int _limit);
34 adverb_query& random(bool _random);
35 adverb_query& except(const adverb& _word);
36 adverb_query& rhymes_with(const word& _word);
37 adverb_query& has_pronunciation(bool _has_prn);
38
39 adverb_query& requires_comparative_form(bool _arg);
40 adverb_query& requires_superlative_form(bool _arg);
41
42 adverb_query& has_antonyms(bool _arg);
43 adverb_query& antonym_of(const adverb& _adv);
44 adverb_query& not_antonym_of(const adverb& _adv);
45
46 adverb_query& has_synonyms(bool _arg);
47 adverb_query& synonym_of(const adverb& _adv);
48 adverb_query& not_synonym_of(const adverb& _adv);
49
50 adverb_query& is_mannernymic(bool _arg);
51 adverb_query& mannernym_of(const adjective& _adj);
52
53 std::list<adverb> run() const;
54
55 const static int unlimited = -1;
56
57 private:
58 const data& _data;
59 int _limit = unlimited;
60 bool _random = false;
61 std::list<std::string> _rhymes;
62 std::list<adverb> _except;
63 bool _has_prn = false;
64
65 bool _requires_comparative_form = false;
66 bool _requires_superlative_form = false;
67
68 bool _has_antonyms = false;
69 std::list<adverb> _antonym_of;
70 std::list<adverb> _not_antonym_of;
71
72 bool _has_synonyms = false;
73 std::list<adverb> _synonym_of;
74 std::list<adverb> _not_synonym_of;
12 75
13 adverb(int id) : id(id) 76 bool _is_mannernymic = false;
14 { 77 std::list<adjective> _mannernym_of;
15
16 }
17 }; 78 };
18 79
19}; 80};
diff --git a/verbly/data.cpp b/verbly/data.cpp new file mode 100644 index 0000000..57a8850 --- /dev/null +++ b/verbly/data.cpp
@@ -0,0 +1,50 @@
1#include "verbly.h"
2
3namespace verbly {
4
5 data::data(std::string datafile)
6 {
7 if (sqlite3_open_v2(datafile.c_str(), &ppdb, SQLITE_OPEN_READONLY, NULL) != SQLITE_OK)
8 {
9 throw std::invalid_argument(sqlite3_errmsg(ppdb));
10 }
11 }
12
13 data::data(data&& other)
14 {
15 ppdb = other.ppdb;
16 }
17
18 data& data::operator=(data&& other)
19 {
20 ppdb = other.ppdb;
21
22 return *this;
23 }
24
25 data::~data()
26 {
27 sqlite3_close_v2(ppdb);
28 }
29
30 verb_query data::verbs() const
31 {
32 return verb_query(*this);
33 }
34
35 adjective_query data::adjectives() const
36 {
37 return adjective_query(*this);
38 }
39
40 adverb_query data::adverbs() const
41 {
42 return adverb_query(*this);
43 }
44
45 noun_query data::nouns() const
46 {
47 return noun_query(*this);
48 }
49
50};
diff --git a/verbly/data.h b/verbly/data.h index e901cba..37092d7 100644 --- a/verbly/data.h +++ b/verbly/data.h
@@ -1,273 +1,46 @@
1#ifndef DATA_H_C4AEC3DD 1#ifndef DATA_H_C4AEC3DD
2#define DATA_H_C4AEC3DD 2#define DATA_H_C4AEC3DD
3 3
4#include "verb.h"
5#include <sqlite3.h> 4#include <sqlite3.h>
6#include <stdexcept> 5#include <stdexcept>
7 6
8namespace verbly { 7namespace verbly {
9 8
9 class data;
10 class word;
11 class adjective;
12 class noun;
13 class verb;
14 class adverb;
15 class adjective_query;
16 class adverb_query;
17 class noun_query;
18 class verb_query;
19
10 class data { 20 class data {
11 private: 21 private:
12 sqlite3* ppdb; 22 sqlite3* ppdb;
13 23
14 public: 24 friend class adjective_query;
15 class verb_query { 25 friend class noun_query;
16 public: 26 friend class verb_query;
17 const static int unlimited = -1; 27 friend class adverb_query;
18
19 private:
20 const data& database;
21 int m_limit = unlimited;
22 bool m_random = false;
23
24 public:
25 verb_query(const data& database) : database(database)
26 {
27
28 }
29
30 verb_query& limit(int m_limit)
31 {
32 if ((m_limit > 0) || (m_limit == unlimited))
33 {
34 this->m_limit = m_limit;
35 }
36
37 return *this;
38 }
39
40 verb_query& random(bool m_random)
41 {
42 this->m_random = m_random;
43
44 return *this;
45 }
46
47 std::list<verb> run() const
48 {
49 std::stringstream construct;
50 construct << "SELECT verb_id, infinitive, past_tense, past_participle, ing_form, s_form FROM verbs";
51
52 if (m_random)
53 {
54 construct << " ORDER BY RANDOM()";
55 }
56
57 if (m_limit != unlimited)
58 {
59 construct << " LIMIT " << m_limit;
60 }
61
62 sqlite3_stmt* ppstmt;
63 std::string query = construct.str();
64 if (sqlite3_prepare_v2(database.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
65 {
66 throw std::runtime_error(sqlite3_errmsg(database.ppdb));
67 }
68
69 std::list<verb> output;
70 while (sqlite3_step(ppstmt) == SQLITE_ROW)
71 {
72 verb tnc {sqlite3_column_int(ppstmt, 0)};
73 tnc.infinitive = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
74 tnc.past_tense = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
75 tnc.past_participle = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 3)));
76 tnc.ing_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 4)));
77 tnc.s_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 5)));
78
79 output.push_back(tnc);
80 }
81
82 sqlite3_finalize(ppstmt);
83
84 return output;
85 }
86
87 };
88
89 class adjective_query {
90 public:
91 const static int unlimited = -1;
92
93 private:
94 const data& database;
95 int m_limit = unlimited;
96 bool m_random = false;
97
98 public:
99 adjective_query(const data& database) : database(database)
100 {
101
102 }
103
104 adjective_query& limit(int m_limit)
105 {
106 if ((m_limit > 0) || (m_limit == unlimited))
107 {
108 this->m_limit = m_limit;
109 }
110
111 return *this;
112 }
113
114 adjective_query& random(bool m_random)
115 {
116 this->m_random = m_random;
117
118 return *this;
119 }
120
121 std::list<adjective> run() const
122 {
123 std::stringstream construct;
124 construct << "SELECT adjective_id, form FROM adjectives";
125
126 if (m_random)
127 {
128 construct << " ORDER BY RANDOM()";
129 }
130
131 if (m_limit != unlimited)
132 {
133 construct << " LIMIT " << m_limit;
134 }
135
136 sqlite3_stmt* ppstmt;
137 std::string query = construct.str();
138 if (sqlite3_prepare_v2(database.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
139 {
140 throw std::runtime_error(sqlite3_errmsg(database.ppdb));
141 }
142
143 std::list<adjective> output;
144 while (sqlite3_step(ppstmt) == SQLITE_ROW)
145 {
146 adjective tnc {sqlite3_column_int(ppstmt, 0)};
147 tnc.form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
148
149 output.push_back(tnc);
150 }
151
152 sqlite3_finalize(ppstmt);
153
154 return output;
155 }
156
157 };
158
159 class adverb_query {
160 public:
161 const static int unlimited = -1;
162
163 private:
164 const data& database;
165 int m_limit = unlimited;
166 bool m_random = false;
167
168 public:
169 adverb_query(const data& database) : database(database)
170 {
171
172 }
173
174 adverb_query& limit(int m_limit)
175 {
176 if ((m_limit > 0) || (m_limit == unlimited))
177 {
178 this->m_limit = m_limit;
179 }
180
181 return *this;
182 }
183
184 adverb_query& random(bool m_random)
185 {
186 this->m_random = m_random;
187
188 return *this;
189 }
190
191 std::list<adverb> run() const
192 {
193 std::stringstream construct;
194 construct << "SELECT adverb_id, form FROM adverbs";
195
196 if (m_random)
197 {
198 construct << " ORDER BY RANDOM()";
199 }
200
201 if (m_limit != unlimited)
202 {
203 construct << " LIMIT " << m_limit;
204 }
205
206 sqlite3_stmt* ppstmt;
207 std::string query = construct.str();
208 if (sqlite3_prepare_v2(database.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
209 {
210 throw std::runtime_error(sqlite3_errmsg(database.ppdb));
211 }
212
213 std::list<adverb> output;
214 while (sqlite3_step(ppstmt) == SQLITE_ROW)
215 {
216 adverb tnc {sqlite3_column_int(ppstmt, 0)};
217 tnc.form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
218
219 output.push_back(tnc);
220 }
221
222 sqlite3_finalize(ppstmt);
223
224 return output;
225 }
226
227 };
228 28
229 data(std::string datafile) 29 public:
230 { 30 data(std::string datafile);
231 if (sqlite3_open_v2(datafile.c_str(), &ppdb, SQLITE_OPEN_READONLY, NULL) != SQLITE_OK)
232 {
233 throw std::invalid_argument(sqlite3_errmsg(ppdb));
234 }
235 }
236 31
237 data(const data& other) = delete; 32 data(const data& other) = delete;
238 data& operator=(const data& other) = delete; 33 data& operator=(const data& other) = delete;
239 34
240 data(data&& other) 35 data(data&& other);
241 { 36 data& operator=(data&& other);
242 ppdb = other.ppdb;
243 }
244
245 data& operator=(data&& other)
246 {
247 ppdb = other.ppdb;
248
249 return *this;
250 }
251
252 ~data()
253 {
254 sqlite3_close_v2(ppdb);
255 }
256
257 verb_query verbs() const
258 {
259 return verb_query(*this);
260 }
261 37
262 adjective_query adjectives() const 38 ~data();
263 {
264 return adjective_query(*this);
265 }
266 39
267 adverb_query adverbs() const 40 verb_query verbs() const;
268 { 41 adjective_query adjectives() const;
269 return adverb_query(*this); 42 adverb_query adverbs() const;
270 } 43 noun_query nouns() const;
271 44
272 }; 45 };
273 46
diff --git a/verbly/noun.cpp b/verbly/noun.cpp new file mode 100644 index 0000000..9336a1c --- /dev/null +++ b/verbly/noun.cpp
@@ -0,0 +1,916 @@
1#include "verbly.h"
2
3namespace verbly {
4
5 noun::noun(const data& _data, int _id) : word(_data, _id)
6 {
7
8 }
9
10 std::string noun::base_form() const
11 {
12 return _singular;
13 }
14
15 std::string noun::singular_form() const
16 {
17 return _singular;
18 }
19
20 std::string noun::plural_form() const
21 {
22 return _plural;
23 }
24
25 bool noun::has_plural_form() const
26 {
27 return !_plural.empty();
28 }
29
30 noun_query noun::hypernyms() const
31 {
32 return _data.nouns().hypernym_of(*this);
33 }
34
35 noun_query noun::hyponyms() const
36 {
37 return _data.nouns().hyponym_of(*this);
38 }
39
40 noun_query noun::part_meronyms() const
41 {
42 return _data.nouns().part_meronym_of(*this);
43 }
44
45 noun_query noun::part_holonyms() const
46 {
47 return _data.nouns().part_holonym_of(*this);
48 }
49
50 noun_query noun::substance_meronyms() const
51 {
52 return _data.nouns().substance_meronym_of(*this);
53 }
54
55 noun_query noun::substance_holonyms() const
56 {
57 return _data.nouns().substance_holonym_of(*this);
58 }
59
60 noun_query noun::member_meronyms() const
61 {
62 return _data.nouns().member_meronym_of(*this);
63 }
64
65 noun_query noun::member_holonyms() const
66 {
67 return _data.nouns().member_holonym_of(*this);
68 }
69
70 noun_query noun::classes() const
71 {
72 return _data.nouns().class_of(*this);
73 }
74
75 noun_query noun::instances() const
76 {
77 return _data.nouns().instance_of(*this);
78 }
79
80 noun_query noun::synonyms() const
81 {
82 return _data.nouns().synonym_of(*this);
83 }
84
85 noun_query noun::antonyms() const
86 {
87 return _data.nouns().antonym_of(*this);
88 }
89
90 adjective_query noun::pertainyms() const
91 {
92 return _data.adjectives().pertainym_of(*this);
93 }
94
95 adjective_query noun::variations() const
96 {
97 return _data.adjectives().variant_of(*this);
98 }
99
100 noun_query::noun_query(const data& _data) : _data(_data)
101 {
102
103 }
104
105 noun_query& noun_query::limit(int _limit)
106 {
107 if ((_limit > 0) || (_limit == unlimited))
108 {
109 this->_limit = _limit;
110 }
111
112 return *this;
113 }
114
115 noun_query& noun_query::random(bool _random)
116 {
117 this->_random = _random;
118
119 return *this;
120 }
121
122 noun_query& noun_query::except(const noun& _word)
123 {
124 _except.push_back(_word);
125
126 return *this;
127 }
128
129 noun_query& noun_query::rhymes_with(const word& _word)
130 {
131 for (auto rhyme : _word.rhyme_phonemes())
132 {
133 _rhymes.push_back(rhyme);
134 }
135
136 if (dynamic_cast<const noun*>(&_word) != nullptr)
137 {
138 _except.push_back(dynamic_cast<const noun&>(_word));
139 }
140
141 return *this;
142 }
143
144 noun_query& noun_query::has_pronunciation(bool _has_prn)
145 {
146 this->_has_prn = _has_prn;
147
148 return *this;
149 }
150
151 noun_query& noun_query::is_hypernym(bool _arg)
152 {
153 _is_hypernym = _arg;
154
155 return *this;
156 }
157
158 noun_query& noun_query::hypernym_of(const noun& _noun)
159 {
160 _hypernym_of.push_back(_noun);
161
162 return *this;
163 }
164
165 noun_query& noun_query::not_hypernym_of(const noun& _noun)
166 {
167 _not_hypernym_of.push_back(_noun);
168
169 return *this;
170 }
171
172 noun_query& noun_query::is_hyponym(bool _arg)
173 {
174 _is_hyponym = _arg;
175
176 return *this;
177 }
178
179 noun_query& noun_query::hyponym_of(const noun& _noun)
180 {
181 _hyponym_of.push_back(_noun);
182
183 return *this;
184 }
185
186 noun_query& noun_query::not_hyponym_of(const noun& _noun)
187 {
188 _not_hyponym_of.push_back(_noun);
189
190 return *this;
191 }
192
193 noun_query& noun_query::is_part_meronym(bool _arg)
194 {
195 _is_part_meronym = _arg;
196
197 return *this;
198 }
199
200 noun_query& noun_query::part_meronym_of(const noun& _noun)
201 {
202 _part_meronym_of.push_back(_noun);
203
204 return *this;
205 }
206
207 noun_query& noun_query::not_part_meronym_of(const noun& _noun)
208 {
209 _not_part_meronym_of.push_back(_noun);
210
211 return *this;
212 }
213
214 noun_query& noun_query::is_part_holonym(bool _arg)
215 {
216 _is_part_holonym = _arg;
217
218 return *this;
219 }
220
221 noun_query& noun_query::part_holonym_of(const noun& _noun)
222 {
223 _part_holonym_of.push_back(_noun);
224
225 return *this;
226 }
227
228 noun_query& noun_query::not_part_holonym_of(const noun& _noun)
229 {
230 _not_part_holonym_of.push_back(_noun);
231
232 return *this;
233 }
234
235 noun_query& noun_query::is_substance_meronym(bool _arg)
236 {
237 _is_substance_meronym = _arg;
238
239 return *this;
240 }
241
242 noun_query& noun_query::substance_meronym_of(const noun& _noun)
243 {
244 _substance_meronym_of.push_back(_noun);
245
246 return *this;
247 }
248
249 noun_query& noun_query::not_substance_meronym_of(const noun& _noun)
250 {
251 _not_substance_meronym_of.push_back(_noun);
252
253 return *this;
254 }
255
256 noun_query& noun_query::is_substance_holonym(bool _arg)
257 {
258 _is_substance_holonym = _arg;
259
260 return *this;
261 }
262
263 noun_query& noun_query::substance_holonym_of(const noun& _noun)
264 {
265 _substance_holonym_of.push_back(_noun);
266
267 return *this;
268 }
269
270 noun_query& noun_query::not_substance_holonym_of(const noun& _noun)
271 {
272 _not_substance_holonym_of.push_back(_noun);
273
274 return *this;
275 }
276
277 noun_query& noun_query::is_member_meronym(bool _arg)
278 {
279 _is_member_meronym = _arg;
280
281 return *this;
282 }
283
284 noun_query& noun_query::member_meronym_of(const noun& _noun)
285 {
286 _member_meronym_of.push_back(_noun);
287
288 return *this;
289 }
290
291 noun_query& noun_query::not_member_meronym_of(const noun& _noun)
292 {
293 _not_member_meronym_of.push_back(_noun);
294
295 return *this;
296 }
297
298 noun_query& noun_query::is_member_holonym(bool _arg)
299 {
300 _is_member_holonym = _arg;
301
302 return *this;
303 }
304
305 noun_query& noun_query::member_holonym_of(const noun& _noun)
306 {
307 _member_holonym_of.push_back(_noun);
308
309 return *this;
310 }
311
312 noun_query& noun_query::not_member_holonym_of(const noun& _noun)
313 {
314 _not_member_holonym_of.push_back(_noun);
315
316 return *this;
317 }
318
319 noun_query& noun_query::is_proper(bool _arg)
320 {
321 _is_proper = _arg;
322
323 return *this;
324 }
325
326 noun_query& noun_query::instance_of(const noun& _noun)
327 {
328 _instance_of.push_back(_noun);
329
330 return *this;
331 }
332
333 noun_query& noun_query::not_instance_of(const noun& _noun)
334 {
335 _not_instance_of.push_back(_noun);
336
337 return *this;
338 }
339
340 noun_query& noun_query::is_class(bool _arg)
341 {
342 _is_class = _arg;
343
344 return *this;
345 }
346
347 noun_query& noun_query::class_of(const noun& _noun)
348 {
349 _class_of.push_back(_noun);
350
351 return *this;
352 }
353
354 noun_query& noun_query::not_class_of(const noun& _noun)
355 {
356 _not_class_of.push_back(_noun);
357
358 return *this;
359 }
360
361 noun_query& noun_query::has_synonyms(bool _arg)
362 {
363 _has_synonyms = _arg;
364
365 return *this;
366 }
367
368 noun_query& noun_query::synonym_of(const noun& _noun)
369 {
370 _synonym_of.push_back(_noun);
371
372 return *this;
373 }
374
375 noun_query& noun_query::not_synonym_of(const noun& _noun)
376 {
377 _not_synonym_of.push_back(_noun);
378
379 return *this;
380 }
381
382 noun_query& noun_query::has_antonyms(bool _arg)
383 {
384 _has_antonyms = _arg;
385
386 return *this;
387 }
388
389 noun_query& noun_query::antonym_of(const noun& _noun)
390 {
391 _antonym_of.push_back(_noun);
392
393 return *this;
394 }
395
396 noun_query& noun_query::not_antonym_of(const noun& _noun)
397 {
398 _not_antonym_of.push_back(_noun);
399
400 return *this;
401 }
402
403 noun_query& noun_query::has_pertainym(bool _arg)
404 {
405 _has_pertainym = _arg;
406
407 return *this;
408 }
409
410 noun_query& noun_query::anti_pertainym_of(const adjective& _adj)
411 {
412 _anti_pertainym_of.push_back(_adj);
413
414 return *this;
415 }
416
417 noun_query& noun_query::is_attribute(bool _arg)
418 {
419 _is_attribute = _arg;
420
421 return *this;
422 }
423
424 noun_query& noun_query::attribute_of(const adjective& _adj)
425 {
426 _attribute_of.push_back(_adj);
427
428 return *this;
429 }
430
431 std::list<noun> noun_query::run() const
432 {
433 std::stringstream construct;
434 construct << "SELECT noun_id, singular, plural FROM nouns";
435 std::list<std::string> conditions;
436
437 if (_has_prn)
438 {
439 conditions.push_back("noun_id IN (SELECT noun_id FROM noun_pronunciations)");
440 }
441
442 if (!_rhymes.empty())
443 {
444 std::list<std::string> clauses(_rhymes.size(), "pronunciation LIKE @RHMPRN");
445 std::string cond = "noun_id IN (SELECT noun_id FROM noun_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
446 conditions.push_back(cond);
447 }
448
449 for (auto except : _except)
450 {
451 conditions.push_back("noun_id != @EXCID");
452 }
453
454 if (_is_hypernym)
455 {
456 conditions.push_back("noun_id IN (SELECT hypernym_id FROM hypernymy)");
457 }
458
459 if (!_hypernym_of.empty())
460 {
461 std::list<std::string> clauses(_hypernym_of.size(), "hyponym_id = @HYPO");
462 std::string cond = "noun_id IN (SELECT hypernym_id FROM hypernymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
463 conditions.push_back(cond);
464 }
465
466 if (!_not_hypernym_of.empty())
467 {
468 std::list<std::string> clauses(_not_hypernym_of.size(), "hyponym_id = @NHYPO");
469 std::string cond = "noun_id NOT IN (SELECT hypernym_id FROM hypernymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
470 conditions.push_back(cond);
471 }
472
473 if (_is_hyponym)
474 {
475 conditions.push_back("noun_id IN (SELECT hyponym_id FROM hypernymy)");
476 }
477
478 if (!_hyponym_of.empty())
479 {
480 std::list<std::string> clauses(_hyponym_of.size(), "hypernym_id = @HYPER");
481 std::string cond = "noun_id IN (SELECT hyponym_id FROM hypernymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
482 conditions.push_back(cond);
483 }
484
485 if (!_not_hyponym_of.empty())
486 {
487 std::list<std::string> clauses(_not_hyponym_of.size(), "hypernym_id = @NHYPER");
488 std::string cond = "noun_id NOT IN (SELECT hyponym_id FROM hypernymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
489 conditions.push_back(cond);
490 }
491
492 if (_is_part_meronym)
493 {
494 conditions.push_back("noun_id IN (SELECT meronym_id FROM part_meronymy)");
495 }
496
497 if (!_part_meronym_of.empty())
498 {
499 std::list<std::string> clauses(_part_meronym_of.size(), "holonym_id = @PHOLO");
500 std::string cond = "noun_id IN (SELECT meronym_id FROM part_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
501 conditions.push_back(cond);
502 }
503
504 if (!_not_part_meronym_of.empty())
505 {
506 std::list<std::string> clauses(_not_part_meronym_of.size(), "holonym_id = @NPHOLO");
507 std::string cond = "noun_id NOT IN (SELECT meronym_id FROM part_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
508 conditions.push_back(cond);
509 }
510
511 if (_is_part_holonym)
512 {
513 conditions.push_back("noun_id IN (SELECT holonym_id FROM part_meronymy)");
514 }
515
516 if (!_part_holonym_of.empty())
517 {
518 std::list<std::string> clauses(_part_holonym_of.size(), "meronym_id = @PMERO");
519 std::string cond = "noun_id IN (SELECT holonym_id FROM part_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
520 conditions.push_back(cond);
521 }
522
523 if (!_not_part_holonym_of.empty())
524 {
525 std::list<std::string> clauses(_not_part_holonym_of.size(), "meronym_id = @NPMERO");
526 std::string cond = "noun_id NOT IN (SELECT holonym_id FROM part_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
527 conditions.push_back(cond);
528 }
529
530 if (_is_substance_meronym)
531 {
532 conditions.push_back("noun_id IN (SELECT meronym_id FROM substance_meronymy)");
533 }
534
535 if (!_substance_meronym_of.empty())
536 {
537 std::list<std::string> clauses(_substance_meronym_of.size(), "holonym_id = @SHOLO");
538 std::string cond = "noun_id IN (SELECT meronym_id FROM substance_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
539 conditions.push_back(cond);
540 }
541
542 if (!_not_substance_meronym_of.empty())
543 {
544 std::list<std::string> clauses(_not_substance_meronym_of.size(), "holonym_id = @NSHOLO");
545 std::string cond = "noun_id NOT IN (SELECT meronym_id FROM substance_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
546 conditions.push_back(cond);
547 }
548
549 if (_is_substance_holonym)
550 {
551 conditions.push_back("noun_id IN (SELECT holonym_id FROM substance_meronymy)");
552 }
553
554 if (!_substance_holonym_of.empty())
555 {
556 std::list<std::string> clauses(_substance_holonym_of.size(), "meronym_id = @SMERO");
557 std::string cond = "noun_id IN (SELECT holonym_id FROM substance_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
558 conditions.push_back(cond);
559 }
560
561 if (!_not_substance_holonym_of.empty())
562 {
563 std::list<std::string> clauses(_not_substance_holonym_of.size(), "meronym_id = @NSMERO");
564 std::string cond = "noun_id NOT IN (SELECT holonym_id FROM substance_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
565 conditions.push_back(cond);
566 }
567
568 if (_is_member_meronym)
569 {
570 conditions.push_back("noun_id IN (SELECT meronym_id FROM member_meronymy)");
571 }
572
573 if (!_member_meronym_of.empty())
574 {
575 std::list<std::string> clauses(_member_meronym_of.size(), "holonym_id = @MHOLO");
576 std::string cond = "noun_id IN (SELECT meronym_id FROM member_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
577 conditions.push_back(cond);
578 }
579
580 if (!_not_member_meronym_of.empty())
581 {
582 std::list<std::string> clauses(_not_member_meronym_of.size(), "holonym_id = @NMHOLO");
583 std::string cond = "noun_id NOT IN (SELECT meronym_id FROM member_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
584 conditions.push_back(cond);
585 }
586
587 if (_is_member_holonym)
588 {
589 conditions.push_back("noun_id IN (SELECT holonym_id FROM member_meronym)");
590 }
591
592 if (!_member_holonym_of.empty())
593 {
594 std::list<std::string> clauses(_member_holonym_of.size(), "meronym_id = @MMERO");
595 std::string cond = "noun_id IN (SELECT holonym_id FROM member_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
596 conditions.push_back(cond);
597 }
598
599 if (!_not_member_holonym_of.empty())
600 {
601 std::list<std::string> clauses(_not_member_holonym_of.size(), "meronym_id = @NMMERO");
602 std::string cond = "noun_id NOT IN (SELECT holonym_id FROM member_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
603 conditions.push_back(cond);
604 }
605
606 if (_is_proper)
607 {
608 conditions.push_back("noun_id IN (SELECT instance_id FROM instantiation)");
609 }
610
611 if (!_instance_of.empty())
612 {
613 std::list<std::string> clauses(_instance_of.size(), "class_id = @CLSID");
614 std::string cond = "noun_id IN (SELECT instance_id FROM instantiation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
615 conditions.push_back(cond);
616 }
617
618 if (!_not_instance_of.empty())
619 {
620 std::list<std::string> clauses(_not_instance_of.size(), "class_id = @NCLSID");
621 std::string cond = "noun_id NOT IN (SELECT instance_id FROM instantiation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
622 conditions.push_back(cond);
623 }
624
625 if (_is_class)
626 {
627 conditions.push_back("noun_id IN (SELECT class_id FROM instantiation)");
628 }
629
630 if (!_class_of.empty())
631 {
632 std::list<std::string> clauses(_class_of.size(), "instance_id = @INSID");
633 std::string cond = "noun_id IN (SELECT class_id FROM instantiation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
634 conditions.push_back(cond);
635 }
636
637 if (!_not_class_of.empty())
638 {
639 std::list<std::string> clauses(_not_class_of.size(), "instance_id = @NINSID");
640 std::string cond = "noun_id NOT IN (SELECT class_id FROM instantiation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
641 conditions.push_back(cond);
642 }
643
644 if (_has_synonyms)
645 {
646 conditions.push_back("noun_id IN (SELECT adjective_2_id FROM adjective_synonymy)");
647 }
648
649 if (!_synonym_of.empty())
650 {
651 std::list<std::string> clauses(_synonym_of.size(), "adjective_1_id = @SYNID");
652 std::string cond = "noun_id IN (SELECT adjective_2_id FROM adjective_synonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
653 conditions.push_back(cond);
654 }
655
656 if (!_not_synonym_of.empty())
657 {
658 std::list<std::string> clauses(_not_synonym_of.size(), "adjective_1_id = @NSYNID");
659 std::string cond = "noun_id NOT IN (SELECT adjective_2_id FROM adjective_synonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
660 conditions.push_back(cond);
661 }
662
663 if (_has_antonyms)
664 {
665 conditions.push_back("noun_id IN (SELECT adjective_2_id FROM adjective_antonymy)");
666 }
667
668 if (!_antonym_of.empty())
669 {
670 std::list<std::string> clauses(_antonym_of.size(), "adjective_1_id = @ANTID");
671 std::string cond = "noun_id IN (SELECT adjective_2_id FROM adjective_antonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
672 conditions.push_back(cond);
673 }
674
675 if (!_not_antonym_of.empty())
676 {
677 std::list<std::string> clauses(_not_antonym_of.size(), "adjective_1_id = @NANTID");
678 std::string cond = "noun_id NOT IN (SELECT adjective_2_id FROM adjective_antonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
679 conditions.push_back(cond);
680 }
681
682 if (_has_pertainym)
683 {
684 conditions.push_back("noun_id IN (SELECT noun_id FROM pertainymy)");
685 }
686
687 if (!_anti_pertainym_of.empty())
688 {
689 std::list<std::string> clauses(_anti_pertainym_of.size(), "pertainym_id = @PERID");
690 std::string cond = "noun_id IN (SELECT noun_id FROM pertainymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
691 conditions.push_back(cond);
692 }
693
694 if (_is_attribute)
695 {
696 conditions.push_back("noun_id IN (SELECT noun_id FROM variation)");
697 }
698
699 if (!_attribute_of.empty())
700 {
701 std::list<std::string> clauses(_attribute_of.size(), "adjective_id = @VALID");
702 std::string cond = "noun_id IN (SELECT noun_id FROM variation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
703 conditions.push_back(cond);
704 }
705
706 if (!conditions.empty())
707 {
708 construct << " WHERE ";
709 construct << verbly::implode(std::begin(conditions), std::end(conditions), " AND ");
710 }
711
712 if (_random)
713 {
714 construct << " ORDER BY RANDOM()";
715 }
716
717 if (_limit != unlimited)
718 {
719 construct << " LIMIT " << _limit;
720 }
721
722 sqlite3_stmt* ppstmt;
723 std::string query = construct.str();
724 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
725 {
726 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
727 }
728
729 if (!_rhymes.empty())
730 {
731 int i = 0;
732 for (auto rhyme : _rhymes)
733 {
734 std::string rhymer = "%" + rhyme;
735 sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@RHMPRN"), rhymer.c_str(), rhymer.length(), SQLITE_STATIC);
736
737 i++;
738 }
739 }
740
741 for (auto except : _except)
742 {
743 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@EXCID"), except._id);
744 }
745
746 for (auto hyponym : _hypernym_of)
747 {
748 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@HYPO"), hyponym._id);
749 }
750
751 for (auto hyponym : _not_hypernym_of)
752 {
753 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NHYPO"), hyponym._id);
754 }
755
756 for (auto hypernym : _hyponym_of)
757 {
758 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@HYPER"), hypernym._id);
759 }
760
761 for (auto hypernym : _not_hyponym_of)
762 {
763 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NHYPER"), hypernym._id);
764 }
765
766 for (auto holonym : _part_meronym_of)
767 {
768 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@PHOLO"), holonym._id);
769 }
770
771 for (auto holonym : _not_part_meronym_of)
772 {
773 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NPHOLO"), holonym._id);
774 }
775
776 for (auto meronym : _part_holonym_of)
777 {
778 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@PMERO"), meronym._id);
779 }
780
781 for (auto meronym : _not_part_holonym_of)
782 {
783 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NPMERO"), meronym._id);
784 }
785
786 for (auto holonym : _substance_meronym_of)
787 {
788 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SHOLO"), holonym._id);
789 }
790
791 for (auto holonym : _not_substance_meronym_of)
792 {
793 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NSHOLO"), holonym._id);
794 }
795
796 for (auto meronym : _substance_holonym_of)
797 {
798 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SMERO"), meronym._id);
799 }
800
801 for (auto meronym : _not_substance_holonym_of)
802 {
803 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NSMERO"), meronym._id);
804 }
805
806 for (auto holonym : _member_meronym_of)
807 {
808 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@MHOLO"), holonym._id);
809 }
810
811 for (auto holonym : _not_member_meronym_of)
812 {
813 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NMHOLO"), holonym._id);
814 }
815
816 for (auto meronym : _member_holonym_of)
817 {
818 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@MMERO"), meronym._id);
819 }
820
821 for (auto meronym : _not_member_holonym_of)
822 {
823 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NMMERO"), meronym._id);
824 }
825
826 for (auto cls : _instance_of)
827 {
828 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@CLSID"), cls._id);
829 }
830
831 for (auto cls : _not_instance_of)
832 {
833 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NCLSID"), cls._id);
834 }
835
836 for (auto inst : _class_of)
837 {
838 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@INSID"), inst._id);
839 }
840
841 for (auto inst : _not_class_of)
842 {
843 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NINSID"), inst._id);
844 }
845
846 for (auto synonym : _synonym_of)
847 {
848 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SYNID"), synonym._id);
849 }
850
851 for (auto synonym : _not_synonym_of)
852 {
853 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NSYNID"), synonym._id);
854 }
855
856 for (auto antonym : _antonym_of)
857 {
858 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@ANTID"), antonym._id);
859 }
860
861 for (auto antonym : _not_antonym_of)
862 {
863 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NANTID"), antonym._id);
864 }
865
866 for (auto pertainym : _anti_pertainym_of)
867 {
868 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@PERID"), pertainym._id);
869 }
870
871 for (auto value : _attribute_of)
872 {
873 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@VALID"), value._id);
874 }
875
876 std::list<noun> output;
877 while (sqlite3_step(ppstmt) == SQLITE_ROW)
878 {
879 noun tnc {_data, sqlite3_column_int(ppstmt, 0)};
880 tnc._singular = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
881
882 if (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL)
883 {
884 tnc._plural = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
885 }
886
887 output.push_back(tnc);
888 }
889
890 sqlite3_finalize(ppstmt);
891
892 for (auto& noun : output)
893 {
894 query = "SELECT pronunciation FROM noun_pronunciations WHERE noun_id = ?";
895 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
896 {
897 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
898 }
899
900 sqlite3_bind_int(ppstmt, 1, noun._id);
901
902 while (sqlite3_step(ppstmt) == SQLITE_ROW)
903 {
904 std::string pronunciation(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 0)));
905 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " ");
906
907 noun.pronunciations.push_back(phonemes);
908 }
909
910 sqlite3_finalize(ppstmt);
911 }
912
913 return output;
914 }
915
916};
diff --git a/verbly/noun.h b/verbly/noun.h new file mode 100644 index 0000000..f5ba256 --- /dev/null +++ b/verbly/noun.h
@@ -0,0 +1,171 @@
1#ifndef NOUN_H_24A03C83
2#define NOUN_H_24A03C83
3
4namespace verbly {
5
6 class noun : public word {
7 private:
8 std::string _singular;
9 std::string _plural;
10
11 friend class noun_query;
12
13 public:
14 noun(const data& _data, int _id);
15
16 std::string base_form() const;
17 std::string singular_form() const;
18 std::string plural_form() const;
19
20 bool has_plural_form() const;
21
22 noun_query hypernyms() const;
23 noun_query hyponyms() const;
24 noun_query part_meronyms() const;
25 noun_query part_holonyms() const;
26 noun_query substance_meronyms() const;
27 noun_query substance_holonyms() const;
28 noun_query member_meronyms() const;
29 noun_query member_holonyms() const;
30 noun_query classes() const;
31 noun_query instances() const;
32 noun_query synonyms() const;
33 noun_query antonyms() const;
34 adjective_query pertainyms() const;
35 adjective_query variations() const;
36 };
37
38 class noun_query {
39 public:
40 noun_query(const data& _data);
41
42 noun_query& limit(int _limit);
43 noun_query& random(bool _random);
44 noun_query& except(const noun& _word);
45 noun_query& rhymes_with(const word& _word);
46 noun_query& has_pronunciation(bool _has_prn);
47
48 noun_query& is_hypernym(bool _arg);
49 noun_query& hypernym_of(const noun& _noun);
50 noun_query& not_hypernym_of(const noun& _noun);
51
52 noun_query& is_hyponym(bool _arg);
53 noun_query& hyponym_of(const noun& _noun);
54 noun_query& not_hyponym_of(const noun& _noun);
55
56 noun_query& is_part_meronym(bool _arg);
57 noun_query& part_meronym_of(const noun& _noun);
58 noun_query& not_part_meronym_of(const noun& _noun);
59
60 noun_query& is_part_holonym(bool _arg);
61 noun_query& part_holonym_of(const noun& _noun);
62 noun_query& not_part_holonym_of(const noun& _noun);
63
64 noun_query& is_substance_meronym(bool _arg);
65 noun_query& substance_meronym_of(const noun& _noun);
66 noun_query& not_substance_meronym_of(const noun& _noun);
67
68 noun_query& is_substance_holonym(bool _arg);
69 noun_query& substance_holonym_of(const noun& _noun);
70 noun_query& not_substance_holonym_of(const noun& _noun);
71
72 noun_query& is_member_meronym(bool _arg);
73 noun_query& member_meronym_of(const noun& _noun);
74 noun_query& not_member_meronym_of(const noun& _noun);
75
76 noun_query& is_member_holonym(bool _arg);
77 noun_query& member_holonym_of(const noun& _noun);
78 noun_query& not_member_holonym_of(const noun& _noun);
79
80 noun_query& is_proper(bool _arg);
81 noun_query& instance_of(const noun& _noun);
82 noun_query& not_instance_of(const noun& _noun);
83
84 noun_query& is_class(bool _arg);
85 noun_query& class_of(const noun& _noun);
86 noun_query& not_class_of(const noun& _noun);
87
88 noun_query& has_synonyms(bool _arg);
89 noun_query& synonym_of(const noun& _noun);
90 noun_query& not_synonym_of(const noun& _noun);
91
92 noun_query& has_antonyms(bool _arg);
93 noun_query& antonym_of(const noun& _noun);
94 noun_query& not_antonym_of(const noun& _noun);
95
96 noun_query& has_pertainym(bool _arg);
97 noun_query& anti_pertainym_of(const adjective& _adj);
98
99 noun_query& is_attribute(bool _arg);
100 noun_query& attribute_of(const adjective& _adj);
101
102 std::list<noun> run() const;
103
104 const static int unlimited = -1;
105
106 private:
107 const data& _data;
108 int _limit = unlimited;
109 bool _random = false;
110 std::list<std::string> _rhymes;
111 std::list<noun> _except;
112 bool _has_prn = false;
113
114 bool _is_hypernym = false;
115 std::list<noun> _hypernym_of;
116 std::list<noun> _not_hypernym_of;
117
118 bool _is_hyponym = false;
119 std::list<noun> _hyponym_of;
120 std::list<noun> _not_hyponym_of;
121
122 bool _is_part_meronym = false;
123 std::list<noun> _part_meronym_of;
124 std::list<noun> _not_part_meronym_of;
125
126 bool _is_substance_meronym = false;
127 std::list<noun> _substance_meronym_of;
128 std::list<noun> _not_substance_meronym_of;
129
130 bool _is_member_meronym = false;
131 std::list<noun> _member_meronym_of;
132 std::list<noun> _not_member_meronym_of;
133
134 bool _is_part_holonym = false;
135 std::list<noun> _part_holonym_of;
136 std::list<noun> _not_part_holonym_of;
137
138 bool _is_substance_holonym = false;
139 std::list<noun> _substance_holonym_of;
140 std::list<noun> _not_substance_holonym_of;
141
142 bool _is_member_holonym = false;
143 std::list<noun> _member_holonym_of;
144 std::list<noun> _not_member_holonym_of;
145
146 bool _is_proper = false;
147 std::list<noun> _instance_of;
148 std::list<noun> _not_instance_of;
149
150 bool _is_class = false;
151 std::list<noun> _class_of;
152 std::list<noun> _not_class_of;
153
154 bool _has_synonyms = false;
155 std::list<noun> _synonym_of;
156 std::list<noun> _not_synonym_of;
157
158 bool _has_antonyms = false;
159 std::list<noun> _antonym_of;
160 std::list<noun> _not_antonym_of;
161
162 bool _has_pertainym = false;
163 std::list<adjective> _anti_pertainym_of;
164
165 bool _is_attribute = false;
166 std::list<adjective> _attribute_of;
167 };
168
169};
170
171#endif /* end of include guard: NOUN_H_24A03C83 */
diff --git a/verbly/token.cpp b/verbly/token.cpp new file mode 100644 index 0000000..aa8f50e --- /dev/null +++ b/verbly/token.cpp
@@ -0,0 +1,53 @@
1#include "verbly.h"
2
3namespace verbly {
4
5 token::token(token::type _type) : _type(_type)
6 {
7
8 }
9
10 token::type token::token_type() const
11 {
12 return _type;
13 }
14
15 verb_token::verb_token(const class verb& _verb) : token(token::type::verb), _verb(&_verb)
16 {
17
18 }
19
20 const class verb& verb_token::verb() const
21 {
22 return *_verb;
23 }
24
25 verb_token& verb_token::inflect(verb_token::inflection infl)
26 {
27 _inflection = infl;
28 return *this;
29 }
30
31 bool verb_token::complete() const
32 {
33 return true;
34 }
35
36 std::string verb_token::compile() const
37 {
38 switch (_inflection)
39 {
40 case inflection::infinitive: return _verb->infinitive_form();
41 case inflection::past_tense: return _verb->past_tense_form();
42 case inflection::past_participle: return _verb->past_participle_form();
43 case inflection::ing_form: return _verb->ing_form();
44 case inflection::s_form: return _verb->s_form();
45 }
46 }
47
48 token* verb_token::copy() const
49 {
50 return new verb_token(*this);
51 }
52
53};
diff --git a/verbly/token.h b/verbly/token.h index 2848fd0..44d99cb 100644 --- a/verbly/token.h +++ b/verbly/token.h
@@ -4,16 +4,10 @@
4#include <string> 4#include <string>
5#include <list> 5#include <list>
6#include <sstream> 6#include <sstream>
7#include "verb.h"
8 7
9namespace verbly { 8namespace verbly {
10 9
11 enum class type { 10 class verb;
12 verb,
13 fillin,
14 string,
15 utterance
16 };
17 11
18 class selrestr { 12 class selrestr {
19 }; 13 };
@@ -29,20 +23,22 @@ namespace verbly {
29 }; 23 };
30 24
31 class token { 25 class token {
26 public:
27 enum class type {
28 verb,
29 fillin,
30 string,
31 utterance
32 };
33
32 protected: 34 protected:
33 // General 35 // General
34 type type; 36 type _type;
35 37
36 token(enum type type) : type(type) 38 token(type _type);
37 {
38
39 }
40 39
41 public: 40 public:
42 enum type token_type() const 41 enum type token_type() const;
43 {
44 return type;
45 }
46 42
47 virtual bool complete() const = 0; 43 virtual bool complete() const = 0;
48 virtual std::string compile() const = 0; 44 virtual std::string compile() const = 0;
@@ -50,42 +46,32 @@ namespace verbly {
50 }; 46 };
51 47
52 class verb_token : public token { 48 class verb_token : public token {
49 public:
50 enum class inflection {
51 infinitive,
52 past_tense,
53 past_participle,
54 ing_form,
55 s_form
56 };
57
53 private: 58 private:
54 // Verb 59 // Verb
55 const verb* m_verb; 60 const verb* _verb;
56 conjugation verb_infl = conjugation::infinitive; 61 inflection _inflection = inflection::infinitive;
57 62
58 public: 63 public:
59 verb_token(const class verb& verb) : token(type::verb), m_verb(&verb) 64 verb_token(const class verb& _verb);
60 {
61
62 }
63 65
64 const class verb& verb() const 66 const class verb& verb() const;
65 {
66 return *m_verb;
67 }
68 67
69 verb_token& conjugate(conjugation infl) 68 verb_token& inflect(inflection infl);
70 {
71 verb_infl = infl;
72 return *this;
73 }
74 69
75 bool complete() const 70 bool complete() const;
76 {
77 return true;
78 }
79 71
80 std::string compile() const 72 std::string compile() const;
81 {
82 return m_verb->conjugate(verb_infl);
83 }
84 73
85 token* copy() const 74 token* copy() const;
86 {
87 return new verb_token(*this);
88 }
89 }; 75 };
90 76
91 class utterance_token : public token { 77 class utterance_token : public token {
@@ -140,7 +126,7 @@ namespace verbly {
140 } 126 }
141 };*/ 127 };*/
142 128
143 utterance_token(std::initializer_list<token*> tkns) : token(type::utterance) 129 utterance_token(std::initializer_list<token*> tkns) : token(token::type::utterance)
144 { 130 {
145 for (auto tkn : tkns) 131 for (auto tkn : tkns)
146 { 132 {
@@ -148,7 +134,7 @@ namespace verbly {
148 } 134 }
149 } 135 }
150 136
151 utterance_token(const utterance_token& other) : token(type::utterance) 137 utterance_token(const utterance_token& other) : token(token::type::utterance)
152 { 138 {
153 for (auto& tkn : other.utterance) 139 for (auto& tkn : other.utterance)
154 { 140 {
@@ -156,7 +142,7 @@ namespace verbly {
156 } 142 }
157 } 143 }
158 144
159 utterance_token(utterance_token&& other) : token(type::utterance), utterance(std::move(other.utterance)) 145 utterance_token(utterance_token&& other) : token(token::type::utterance), utterance(std::move(other.utterance))
160 { 146 {
161 147
162 } 148 }
@@ -237,7 +223,7 @@ namespace verbly {
237 fillin_type m_fillin_type; 223 fillin_type m_fillin_type;
238 224
239 public: 225 public:
240 fillin_token(fillin_type ft) : token(type::fillin), m_fillin_type(ft) 226 fillin_token(fillin_type ft) : token(token::type::fillin), m_fillin_type(ft)
241 { 227 {
242 228
243 } 229 }
@@ -301,7 +287,7 @@ namespace verbly {
301 std::string str; 287 std::string str;
302 288
303 public: 289 public:
304 string_token(std::string str) : token(type::string), str(str) 290 string_token(std::string str) : token(token::type::string), str(str)
305 { 291 {
306 292
307 } 293 }
diff --git a/verbly/util.h b/verbly/util.h new file mode 100644 index 0000000..815b47c --- /dev/null +++ b/verbly/util.h
@@ -0,0 +1,53 @@
1#ifndef UTIL_H_15DDCA2D
2#define UTIL_H_15DDCA2D
3
4#include <string>
5#include <iterator>
6#include <sstream>
7
8namespace verbly {
9
10 template <class InputIterator>
11 std::string implode(InputIterator first, InputIterator last, std::string delimiter)
12 {
13 std::stringstream result;
14
15 for (InputIterator it = first; it != last; it++)
16 {
17 if (it != first)
18 {
19 result << delimiter;
20 }
21
22 result << *it;
23 }
24
25 return result.str();
26 }
27
28 template <class Container>
29 Container split(std::string input, std::string delimiter)
30 {
31 Container result;
32
33 while (!input.empty())
34 {
35 int divider = input.find(" ");
36 if (divider == std::string::npos)
37 {
38 result.push_back(input);
39
40 input = "";
41 } else {
42 result.push_back(input.substr(0, divider));
43
44 input = input.substr(divider+1);
45 }
46 }
47
48 return result;
49 }
50
51};
52
53#endif /* end of include guard: UTIL_H_15DDCA2D */
diff --git a/verbly/verb.cpp b/verbly/verb.cpp new file mode 100644 index 0000000..23f7c92 --- /dev/null +++ b/verbly/verb.cpp
@@ -0,0 +1,193 @@
1#include "verbly.h"
2
3namespace verbly {
4
5 verb::verb(const data& _data, int _id) : word(_data, _id)
6 {
7
8 }
9
10 std::string verb::base_form() const
11 {
12 return _infinitive;
13 }
14
15 std::string verb::infinitive_form() const
16 {
17 return _infinitive;
18 }
19
20 std::string verb::past_tense_form() const
21 {
22 return _past_tense;
23 }
24
25 std::string verb::past_participle_form() const
26 {
27 return _past_participle;
28 }
29
30 std::string verb::ing_form() const
31 {
32 return _ing_form;
33 }
34
35 std::string verb::s_form() const
36 {
37 return _s_form;
38 }
39
40 verb_query::verb_query(const data& _data) : _data(_data)
41 {
42
43 }
44
45 verb_query& verb_query::limit(int _limit)
46 {
47 if ((_limit > 0) || (_limit == unlimited))
48 {
49 this->_limit = _limit;
50 }
51
52 return *this;
53 }
54
55 verb_query& verb_query::random(bool _random)
56 {
57 this->_random = _random;
58
59 return *this;
60 }
61
62 verb_query& verb_query::except(const verb& _word)
63 {
64 _except.push_back(_word);
65
66 return *this;
67 }
68
69 verb_query& verb_query::rhymes_with(const word& _word)
70 {
71 for (auto rhyme : _word.rhyme_phonemes())
72 {
73 _rhymes.push_back(rhyme);
74 }
75
76 if (dynamic_cast<const verb*>(&_word) != nullptr)
77 {
78 _except.push_back(dynamic_cast<const verb&>(_word));
79 }
80
81 return *this;
82 }
83
84 verb_query& verb_query::has_pronunciation(bool _has_prn)
85 {
86 this->_has_prn = _has_prn;
87
88 return *this;
89 }
90
91 std::list<verb> verb_query::run() const
92 {
93 std::stringstream construct;
94 construct << "SELECT verb_id, infinitive, past_tense, past_participle, ing_form, s_form FROM verbs";
95 std::list<std::string> conditions;
96
97 if (_has_prn)
98 {
99 conditions.push_back("verb_id IN (SELECT verb_id FROM verb_pronunciations)");
100 }
101
102 if (!_rhymes.empty())
103 {
104 std::list<std::string> clauses(_rhymes.size(), "pronunciation LIKE @RHMPRN");
105 std::string cond = "verb_id IN (SELECT verb_id FROM verb_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
106 conditions.push_back(cond);
107 }
108
109 for (auto except : _except)
110 {
111 conditions.push_back("verb_id != @EXCID");
112 }
113
114 if (!conditions.empty())
115 {
116 construct << " WHERE ";
117 construct << verbly::implode(std::begin(conditions), std::end(conditions), " AND ");
118 }
119
120 if (_random)
121 {
122 construct << " ORDER BY RANDOM()";
123 }
124
125 if (_limit != unlimited)
126 {
127 construct << " LIMIT " << _limit;
128 }
129
130 sqlite3_stmt* ppstmt;
131 std::string query = construct.str();
132 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
133 {
134 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
135 }
136
137 if (!_rhymes.empty())
138 {
139 int i = 0;
140 for (auto rhyme : _rhymes)
141 {
142 std::string rhymer = "%" + rhyme;
143 sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@RHMPRN"), rhymer.c_str(), rhymer.length(), SQLITE_STATIC);
144
145 i++;
146 }
147 }
148
149 for (auto except : _except)
150 {
151 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@EXCID"), except._id);
152 }
153
154 std::list<verb> output;
155 while (sqlite3_step(ppstmt) == SQLITE_ROW)
156 {
157 verb tnc {_data, sqlite3_column_int(ppstmt, 0)};
158 tnc._infinitive = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
159 tnc._past_tense = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
160 tnc._past_participle = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 3)));
161 tnc._ing_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 4)));
162 tnc._s_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 5)));
163
164 output.push_back(tnc);
165 }
166
167 sqlite3_finalize(ppstmt);
168
169 for (auto& verb : output)
170 {
171 query = "SELECT pronunciation FROM verb_pronunciations WHERE verb_id = ?";
172 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
173 {
174 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
175 }
176
177 sqlite3_bind_int(ppstmt, 1, verb._id);
178
179 while (sqlite3_step(ppstmt) == SQLITE_ROW)
180 {
181 std::string pronunciation(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 0)));
182 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " ");
183
184 verb.pronunciations.push_back(phonemes);
185 }
186
187 sqlite3_finalize(ppstmt);
188 }
189
190 return output;
191 }
192
193};
diff --git a/verbly/verb.h b/verbly/verb.h index 42c8dc2..7cc87e2 100644 --- a/verbly/verb.h +++ b/verbly/verb.h
@@ -1,8 +1,6 @@
1#ifndef VERB_H_BCC929AD 1#ifndef VERB_H_BCC929AD
2#define VERB_H_BCC929AD 2#define VERB_H_BCC929AD
3 3
4#include <vector>
5
6namespace verbly { 4namespace verbly {
7 5
8 /*class frame_part { 6 /*class frame_part {
@@ -26,42 +24,50 @@ namespace verbly {
26 } 24 }
27 };*/ 25 };*/
28 26
29 enum class conjugation { 27 class verb : public word {
30 present_participle,
31 past_participle,
32 infinitive
33 };
34
35 class verb {
36 private: 28 private:
37 int id; 29 std::string _infinitive;
30 std::string _past_tense;
31 std::string _past_participle;
32 std::string _ing_form;
33 std::string _s_form;
34
35 friend class verb_query;
38 36
39 public: 37 public:
40 verb(int id) : id(id) 38 verb(const data& _data, int _id);
41 {
42
43 }
44 39
45 std::string infinitive; 40 std::string base_form() const;
46 std::string past_tense; 41 std::string infinitive_form() const;
47 std::string past_participle; 42 std::string past_tense_form() const;
48 std::string ing_form; 43 std::string past_participle_form() const;
49 std::string s_form; 44 std::string ing_form() const;
50 //std::vector<frame> frames; 45 std::string s_form() const;
46 };
47
48 class verb_query {
49 public:
50 verb_query(const data& _data);
51 51
52 std::string conjugate(conjugation infl) const 52 verb_query& limit(int _limit);
53 { 53 verb_query& random(bool _random);
54 switch (infl) 54 verb_query& except(const verb& _word);
55 { 55 verb_query& rhymes_with(const word& _word);
56 case conjugation::infinitive: return infinitive; 56 verb_query& has_pronunciation(bool _has_prn);
57 case conjugation::past_participle: return past_participle; 57
58 case conjugation::present_participle: return ing_form; 58 std::list<verb> run() const;
59 } 59
60 } 60 const static int unlimited = -1;
61
62 private:
63 const data& _data;
64 int _limit = unlimited;
65 bool _random = false;
66 std::list<std::string> _rhymes;
67 std::list<verb> _except;
68 bool _has_prn = false;
61 }; 69 };
62 70
63}; 71};
64 72
65#include "token.h"
66
67#endif /* end of include guard: VERB_H_BCC929AD */ 73#endif /* end of include guard: VERB_H_BCC929AD */
diff --git a/verbly/verbly.h b/verbly/verbly.h index 44fd3a8..b9f5367 100644 --- a/verbly/verbly.h +++ b/verbly/verbly.h
@@ -2,10 +2,13 @@
2#define VERBLY_H_5B39CE50 2#define VERBLY_H_5B39CE50
3 3
4#include "c++14.h" 4#include "c++14.h"
5#include "util.h"
5#include "token.h" 6#include "token.h"
7#include "data.h"
8#include "word.h"
6#include "verb.h" 9#include "verb.h"
7#include "adjective.h"
8#include "adverb.h" 10#include "adverb.h"
9#include "data.h" 11#include "adjective.h"
12#include "noun.h"
10 13
11#endif /* end of include guard: VERBLY_H_5B39CE50 */ 14#endif /* end of include guard: VERBLY_H_5B39CE50 */
diff --git a/verbly/word.cpp b/verbly/word.cpp new file mode 100644 index 0000000..c50e7d3 --- /dev/null +++ b/verbly/word.cpp
@@ -0,0 +1,32 @@
1#include "verbly.h"
2
3namespace verbly {
4
5 word::word(const data& _data, int _id) : _data(_data), _id(_id)
6 {
7
8 }
9
10 std::list<std::string> word::rhyme_phonemes() const
11 {
12 std::list<std::string> result;
13
14 for (auto pronunciation : pronunciations)
15 {
16 auto phemstrt = std::find_if(std::begin(pronunciation), std::end(pronunciation), [] (std::string phoneme) {
17 return phoneme.find("1") != std::string::npos;
18 });
19
20 std::stringstream rhymer;
21 for (auto it = phemstrt; it != std::end(pronunciation); it++)
22 {
23 rhymer << " " << *it;
24 }
25
26 result.push_back(rhymer.str());
27 }
28
29 return result;
30 }
31
32};
diff --git a/verbly/word.h b/verbly/word.h new file mode 100644 index 0000000..23ddb2b --- /dev/null +++ b/verbly/word.h
@@ -0,0 +1,35 @@
1#ifndef WORD_H_8FC89498
2#define WORD_H_8FC89498
3
4namespace verbly {
5
6 class adjective_query;
7 class verb_query;
8 class adverb_query;
9
10 template <class T>
11 class query;
12
13 class word {
14 protected:
15 const data& _data;
16 int _id;
17
18 std::list<std::list<std::string>> pronunciations;
19
20 word(const data& _data, int _id);
21
22 friend class adjective_query;
23 friend class verb_query;
24 friend class noun_query;
25 friend class adverb_query;
26
27 public:
28 virtual std::string base_form() const = 0;
29
30 std::list<std::string> rhyme_phonemes() const;
31 };
32
33};
34
35#endif /* end of include guard: WORD_H_8FC89498 */