#include <kernel/kernel.h> #include <phantasmal/parser.h> #include <phantasmal/lpc_names.h> private mapping article_map; private mapping adverb_map; private mapping iverb_map; private mapping tverb_map; private mapping noun_map; private mapping adj_map; int wordmap_init; private mapping word_type_map; int regenerate_grammar; /* * We need to create a token-grammar which lists all appropriate words * by what parts of speech they are. Specifically, it should have a * number of categories like 'words that are intransitive verbs, * nouns, and verbs taking an object, but nothing else'. To do that * we'll need a list of all parts of speech in the listing, and to * know whether any given word is one or another part of speech. */ string* parts_of_speech; /* This stuff should correspond nicely to the parts_of_speech array. If not, you'll see some weird autogenerated grammars coming from the ParseD... */ #define ARTICLE_BIT 1 #define ADVERB_BIT 2 #define IVERB_BIT 4 #define TVERB_BIT 8 #define NOUN_BIT 16 #define ADJ_BIT 32 static void create(varargs int clone) { } void upgraded(varargs int clone) { mapping fake_bothverb_map; /* Add parts of speech carefully -- each one increases the amount of time you spend building the list. To add one, you'll need to update this array. You'll also need to add an XXX_BIT constant for it and add entries to several functions further down in this file. Search for things like noun_map and NOUN_BIT to find them. */ parts_of_speech = ({ "article", "adverb", "iverb", "tverb", "noun", "adjective" }); /* * Articles will probably merge with determiners later... * Possessive nouns, numbers, things like that. That assumes * there's no overlap, but possessive nouns should all have an * apostrophe, and numbers and possessive pronouns should be a * known, fixed set. * * We could give them their own part of speech, but remember that * there's one step of making the grammar that takes time * exponential in the number of parts of speech. Best not to be too * liberal in adding them. Having, say, twelve or fourteen * different parts of speech could become too slow and violate the * rlimits() for the upgrade routine. */ article_map = ([ "a" : 1, "the" : 1, ]); adverb_map = ([ "slowly" : 1, "quickly" : 1, "fast" : 1, "really" : 1, ]); fake_bothverb_map = ([ "glance" : 1, "look" : 1, "exa" : 1, "examine" : 1, ]); iverb_map = ([ "users" : 1, "who" : 1, "whoami" : 1, "typo" : 1, "bug" : 1, "idea" : 1, "inv" : 1, "inventory" : 1, ]) + fake_bothverb_map + ([ "north" : 1, "south" : 1, "east" : 1, "west" : 1, ]); tverb_map = ([ "get" : 1, "grab" : 1, "take" : 1, "drop" : 1, "put" : 1, "place" : 1, "remove" : 1, ]) + fake_bothverb_map; if(!noun_map) noun_map = ([ ]); if(!adj_map) adj_map = ([ ]); regenerate_grammar = 1; } int registered_as_word(string word) { if(!SYSTEM() && !COMMON() && !GAME()) return 0; return !!word_type_map[word]; } private void add_pos_to_wordmap(mapping wordmap, mapping posmap, int bits) { string* ind; int ctr; ind = map_indices(posmap); for(ctr = 0; ctr < sizeof(ind); ctr++) { if(wordmap[ind[ctr]]) { wordmap[ind[ctr]] |= bits; } else { wordmap[ind[ctr]] = bits; } } } static mapping pvt_get_wordmap(void) { return word_type_map; } static void init_wordmap(void) { if(wordmap_init) return; word_type_map = ([ ]); add_pos_to_wordmap(word_type_map, article_map, ARTICLE_BIT); add_pos_to_wordmap(word_type_map, adverb_map, ADVERB_BIT); add_pos_to_wordmap(word_type_map, iverb_map, IVERB_BIT); add_pos_to_wordmap(word_type_map, tverb_map, TVERB_BIT); add_pos_to_wordmap(word_type_map, noun_map, NOUN_BIT); add_pos_to_wordmap(word_type_map, adj_map, ADJ_BIT); wordmap_init = 1; } static string make_string_from_pos_bits(int bits) { string *roots; if(!bits) return ""; roots = ({ }); if(bits & ARTICLE_BIT) roots += ({ "ar" }); if(bits & ADVERB_BIT) roots += ({ "av" }); if(bits & IVERB_BIT) roots += ({ "iv" }); if(bits & TVERB_BIT) roots += ({ "tv" }); if(bits & NOUN_BIT) roots += ({ "n" }); if(bits & ADJ_BIT) roots += ({ "ad" }); return implode(roots, "_"); } /**** Functions to support word registration ****/ private void update_wordmap(string word, int bits, int do_add) { if(word_type_map[word]) { if(do_add) { word_type_map[word] |= bits; } else { word_type_map[word] &= ~bits; if(word_type_map[word] == 0) word_type_map[word] = nil; } } else { if(do_add) { word_type_map[word] = bits; } else { error("Can't remove a nonexistent word from word_type_map!"); } } } /* TODO: some security for these functions */ void ref_noun(string noun) { if(noun_map[noun]) { noun_map[noun]++; return; } if(wordmap_init) { regenerate_grammar = 1; update_wordmap(noun, NOUN_BIT, 1); } noun_map[noun] = 1; } void unref_noun(string noun) { int val; if(!noun_map[noun] || (val = noun_map[noun]) < 1) { error("Unreferencing nonexistent noun '" + (noun ? "(nil)" : noun) + "'!"); } if(val == 1) { /* Remove entry */ noun_map[noun] = nil; if(wordmap_init) { regenerate_grammar = 1; update_wordmap(noun, NOUN_BIT, 0); } } else { noun_map[noun]--; } } void ref_adj(string adj) { if(adj_map[adj]) { adj_map[adj]++; return; } if(wordmap_init) { regenerate_grammar = 1; update_wordmap(adj, ADJ_BIT, 1); } adj_map[adj] = 1; } void unref_adj(string adj) { int val; if(!adj_map[adj] || (val = adj_map[adj]) < 1) { error("Unreferencing nonexistent adjective '" + (adj ? "(nil)" : adj) + "'!"); } if(val == 1) { /* Remove entry */ adj_map[adj] = nil; if(wordmap_init) { regenerate_grammar = 1; update_wordmap(adj, ADJ_BIT, 0); } } else { adj_map[adj]--; } } void register_verb(string verb, int transitive) { if(!SYSTEM() && !COMMON() && !GAME()) error("Only privileged code can register new verbs!"); if(transitive & VERB_TRANSITIVE) { tverb_map[verb] = 1; update_wordmap(verb, TVERB_BIT, 1); } if(transitive & VERB_INTRANSITIVE) { iverb_map[verb] = 1; update_wordmap(verb, IVERB_BIT, 1); } regenerate_grammar = 1; } void unregister_verb(string verb) { if(!SYSTEM() && !COMMON() && !GAME()) error("Only privileged code can unregister verbs!"); iverb_map[verb] = nil; tverb_map[verb] = nil; update_wordmap(verb, IVERB_BIT | TVERB_BIT, 0); regenerate_grammar = 1; }