⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 kernel.cpp

📁 J-Alice是一个用C++实现的Ailcebot的克隆。它可以做为一个mini-http服务器在控制台或irc聊天。目前
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//	And I think that concludes loading the AIML :-)
}

Nodemaster *Kernel::add(const string &pattern, const string &that, const string &topic) {
	string path = pattern + " <that> " + that + " <topic> " + topic;
//	cout << "ADD PATH: " << path << endl;
	return add(path, root);
}

Nodemaster *Kernel::add(const string &sentence, Nodemaster *parent) {
	StringTokenizer st(sentence, " ");
	int count = st.countTokens();
	return add(st, parent, count, sentence);
}

Nodemaster * Kernel::add(StringTokenizer &st, Nodemaster *parent, int count, const string &sentence) {
	if (count == 0) {
		return parent;
	} else {
		string word = st.nextToken();
		Nodemaster *n = parent->getChild(word);
		if (n == NULL) {
//	new Nodemapper()? It's an ABC...
			n = new Nodemaster();
			parent->addChild(word, n);
		}
		return add(st, n, count - 1, sentence);
	}
}

Match *Kernel::match(const string &input, const string &that, const string &topic) {
	Match *m = NULL;
	string path = input + " <that> " + that + " <topic> " + topic;
//	cout << "MATCH PATH: " << path << endl;
	m = match(root, root, INPUT, path, "", "");
	if (m != NULL) {
		m->setPath(m->getInputPattern() + " : " + m->getThatPattern() + " : " + m->getTopicPattern());
		return m;
	}
	throw(int(MATCH_EXCEPTION));
}

/**
 * Needs optimizing .. perhaps changes to the Nodemaster/Nodemapper
 * will have to be included.
 * For example: input of say 5 words, and 24 wildcard pattern is
 * extremely slow, and will dramatically increase in time to
 * complete as graphmaster size increases.
 *
 * If (max_tokens(pattern) > max_tokens(remaining input))
 * then stop searching this branch.
 *
 * Still, this is not fail proof, but it will lead to faster
 * running times in the average case :-)
 */
/*
Match *Kernel::match(Nodemaster *node, Nodemaster *parent, const string &input, const string &star, const string &path) {
	StringTokenizer st(input, " ");
	int count = st.countTokens();
	Match *m = NULL;
	if (count == 0) {
		if (node->hasTemplate()) {
			m = new Match();
			m->setNode(node);
			//	Is this correct?
			m->addTopicStar(trim(star));
			m->setTopicPattern("*");
			return m;
		} else {
			return NULL;
		}
	}
	string word = st.nextToken();
	string tail = "";
	if (st.hasMoreTokens()) {
		tail = input.substr(word.length() + 1, input.length());
	}
	if (node->getChild("_") != NULL) {
		m = match(node->getChild("_"), node, tail, word, path + " _");
		if (m != NULL) {
			if (!trim(star).empty()) {
				m->addInputStar(trim(star));
			}
			return m;
		}
//		cout << "No _ (" << path << ")" << endl;
	}
	if (node->getChild(word) != NULL) {
		if (word[0] == '<') {
			m = match(node->getChild(word), node, tail, star, "");
		} else {
			m = match(node->getChild(word), node, tail, star, path + " " + word);
		}
		if (m != NULL) {
			if (word == "<that>") {
				m->addInputStar(trim(star));
				m->setInputPattern(trim(path));
			} else
			if (word == "<topic>") {
				m->addThatStar(trim(star));
				m->setThatPattern(trim(path));
			}
			return m;
		}
//		cout << "No " << word << " (" << path << ")" << endl;
	}
	if (node->getChild("*") != NULL) {
		m = match(node->getChild("*"), node, tail, word, path + " *");
		if (m != NULL) {
			if (!trim(star).empty()) {
				m->addInputStar(trim(star));
			}
			return m;
		}
//		cout << "No * (" << path << ")" << endl;
	}
	if (node == parent->getChild("*") || node == parent->getChild("_")) {
//		cout << "Adding word to <star/>" << endl;
		return match(node, parent, tail, star + " " + word, path);
	}
	return NULL;
}*/

//	Begin hopefully more efficient match engine, with @ support :)

Match *Kernel::match(Nodemaster *node, Nodemaster *parent, int state, const string &input, const string &star, const string &path) {
	StringTokenizer st(input);
	
	if (st.countTokens() == 0) {
		if (node->hasTemplate()) {
			Match *m = new Match();	//	How come need to wrap it?
			m->setNode(node);
			m->addTopicStar(trim(star));
			m->setTopicPattern(trim(path));
			return m;
		}
		return NULL;
	}
	
	string word = st.nextToken();
	string tail = "";
	Match *m = NULL;
	
	if (st.hasMoreTokens()) {
		tail = trim(input.substr(word.length()));
	}
	
	int index = constants.find(" " + word + " ");
	
	if (index != string::npos) {
		if (node->getChild(word) != NULL) {
			m = match(node->getChild(word), node, state + 1, tail, "", "");
			if (m != NULL) {
				addStar(m, trim(star), state);
				addPath(m, trim(path), state);
			}
		}
		return m;
	}
	if (node->getChild("_") != NULL) {
		m = match(node->getChild("_"), node, state, tail, word, path + " _");
		if (m != NULL) {
			addStar(m, trim(star), state);
			return m;
		}
	}
	if (node->getChild(word) != NULL) {
		m = match(node->getChild(word), node, state, tail, star, path + " " + word);
		if (m != NULL) {
	//		if (!trim(star).empty()) {
	//			addStar(m, trim(star), state);
	//		}
			return m;
		}
	}
	if (node->getChild("@") != NULL) {
	//	This one is a bit of a mystery to get figured out
		//Vector queries = node.getQueries();
		//for (int ix = 0; ix < queries.size(); ++ix) {
			//String type = (String)queries.elementAt(ix);
			//if (lookup(type, star.trim()) == true) {
				//m = match(node.getChild("@" + type), node, state, tail, word, path + " @" + type);
				//if (m != null) {
					//addStar(m, star.trim(), state);
					//return m;
				//}
			//}
		//}
	}
	if (node->getChild("*") != NULL) {
		m = match(node->getChild("*"), node, state, tail, word, path + " *");
		if (m != NULL) {
			addStar(m, trim(star), state);
			return m;
		}
	}
	if (node == parent->getChild("*") ||
			node == parent->getChild("_") ||
			node == parent->getChild("@")) {
		return match(node, parent, state, tail, star + " " + word, path);
	}
	return NULL;
}

void Kernel::addStar(Match *m, const string &value, int state) {
	if (value.empty()) {
		return;
	}
	switch (state) {
		case INPUT:
			m->addInputStar(value);
			return;
		case THAT:
			m->addThatStar(value);
			return;
		case TOPIC:
			m->addTopicStar(value);
			return;
	}
}

void Kernel::addPath(Match *m, const string &value, int state) {
	if (value.empty()) {
		return;
	}
	switch (state) {
		case INPUT:
			m->setInputPattern(value);
			return;
		case THAT:
			m->setThatPattern(value);
			return;
		case TOPIC:
			m->setTopicPattern(value);
			return;
	}
}

bool Kernel::lookup(const string &, const string &) {
	//Object o = querySets.get(type);
	//if (o == null) {
		//return false;
	//}
	
	//Enumeration items = ((Vector)o).elements();
	//while (items.hasMoreElements()) {
		//String item = (String)items.nextElement();
		//if (item.startsWith("@")) {
			//String subset = item.substring(1);
			//if (lookup(subset, input) == true) {
				//return true;
			//} else {
				//item = subset;
			//}
		//}
		//--	REGEX HERE WOULD ROCK
		//bool result = Pattern.matches(item, input.toUpperCase());
		//if (result == true) {
			//return true;
		//}
	//}
	
	return false;
}

string Kernel::process(Match *m, PElement e, Responder *r, const string &id) {
	return TemplateProcessor::processTemplate(m, e, r, id);
}

string Kernel::respond(const string &input, const string &id) {
	return respond(input, id, 1, false);
}

string Kernel::respond(const string &input, const string &id, bool srai) {
	return respond(input, id, 1, srai);
}

string Kernel::respond(const string &input, const string &id, Responder *r) {
	return respond(input, id, r, 1, false);
}

string Kernel::respond(const string &input, const string &id, int depth, bool srai) {
	/**
	 * Instead of NULL, should be: new TextResponder() or something.
	 * NULL isn't going to work later on
	 */
	return respond(input, id, NULL, depth, srai);
}

static int recursionDepth = 0;

string Kernel::respond(const string &input, const string &id, Responder *r, int, bool srai) {
//	cout << "KERNEL: " << input << ":" << id << endl;
	if (!srai) {
		recursionDepth = 0;
	}
	//	I want this to be configurable...
	if (++recursionDepth > 32) {
		Memory::push("that", "", id);
		cerr << "AIML contains an infinite loop" << endl;
		cerr << "Input involved in loop: " << input << endl;
		throw(int(LOOP_EXCEPTION));
	//	Can't seem to forward exceptions proper .. or even catch it
	//	But no reply will do...
	}
	string currentResponse = "", buffer = "";
	Match *m = NULL;
	if (!srai) {
		Memory::push("input", input, id);
	}
	StringTokenizer st(input, ".?!");
	while (st.hasMoreTokens()) {
		string sentence = trim(st.nextToken());
		if (sentence.length() < 1) {
			continue;
		}
		sentence = Substituter::normalize(sentence);
		string that = Memory::getValue("that", id);
		if (!srai) {
			StringTokenizer stThat(that, ".?!");
			while (stThat.hasMoreTokens()) {
				that = stThat.nextToken();
				that = trim(that);
				Memory::push("that", that, id);
			}
		}
		that = Substituter::normalize(that);
		string topic = Memory::getValue("topic", id);
		topic = Substituter::normalize(topic);
		if (that.empty()) {
			that = "*";
		}
		if (topic.empty()) {
			topic = "*";
		}
		try {
			//	Do timing...
			m = match(sentence, that, topic);
			//	For getting the match...
			string tmpl = "<template>" + m->getTemplate() + "</template>";
			Parser *p = new Parser();
			strstream ss;
			ss << tmpl << endl;
			currentResponse = Kernel::process(m, p->parse(ss, "xxx"), r, id);
			Memory::setValue("beforethat", id, that);
			Memory::setValue("that", id, currentResponse);
			delete p;
		} catch (int &ex) {
			//	CodeWarrior turns MATCH_EXCEPTION into 0
			//	I guess because we get here through stack unwinding,
			//	whereas LOOP_EXCEPTION isn't
			//	Oh, and CW using zero overhead exception handling...
			if (ex == LOOP_EXCEPTION) {
			//	cerr << "Loop exception occured" << endl;
				return "I'm lost for words";
			}
			if (ex == MATCH_EXCEPTION) {
				cerr << "There is no match for input: " << sentence << endl;
				//	Was crashing without this in some cases
				m = NULL;
			}
		}
		if (m != NULL) {
		//	cout << "PATH: " << m->getPath() << endl;
			delete m;
			if (srai) {
				--recursionDepth;
				return currentResponse;
			} else {
				buffer += currentResponse + " ";
			}
		}
	}
	string result = buffer;//Substituter::output(buffer);
	//	Aha! Here it is...
	--recursionDepth;
	if (trimming) {
		return trim(result, " \t\r\n");
	}
	return result;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -