[Scummvm-cvs-logs] SF.net SVN: scummvm:[54777] scummvm/trunk/engines/mohawk

fuzzie at users.sourceforge.net fuzzie at users.sourceforge.net
Sun Dec 5 17:19:36 CET 2010


Revision: 54777
          http://scummvm.svn.sourceforge.net/scummvm/?rev=54777&view=rev
Author:   fuzzie
Date:     2010-12-05 16:19:35 +0000 (Sun, 05 Dec 2010)

Log Message:
-----------
MOHAWK: add runCommand/checkCondition routines for LB 2/3

Modified Paths:
--------------
    scummvm/trunk/engines/mohawk/livingbooks.cpp
    scummvm/trunk/engines/mohawk/livingbooks.h

Modified: scummvm/trunk/engines/mohawk/livingbooks.cpp
===================================================================
--- scummvm/trunk/engines/mohawk/livingbooks.cpp	2010-12-05 08:36:41 UTC (rev 54776)
+++ scummvm/trunk/engines/mohawk/livingbooks.cpp	2010-12-05 16:19:35 UTC (rev 54777)
@@ -2061,6 +2061,278 @@
 	debug(9, "nextTime is now %d frames away", _nextTime - (uint)(_vm->_system->getMillis() / 16));
 }
 
+bool LBValue::operator==(const LBValue &x) const {
+	if (type != x.type) return false;
+
+	switch (type) {
+	case kLBValueString:
+		return string == x.string;
+
+	case kLBValueInteger:
+		return integer == x.integer;
+	}
+
+	error("internal error in LBValue");
+}
+
+bool LBValue::operator!=(const LBValue &x) const {
+	return !(*this == x);
+}
+
+enum LBTokenType {
+	kLBNoToken,
+	kLBNameToken,
+	kLBStringToken,
+	kLBOperatorToken,
+	kLBIntegerToken,
+	kLBEndToken
+};
+
+static Common::String readToken(const Common::String &source, uint &pos, LBTokenType &type) {
+	Common::String token;
+	type = kLBNoToken;
+
+	bool done = false;
+	while (pos < source.size() && !done) {
+		if (type == kLBStringToken) {
+			if (source[pos] == '"') {
+				pos++;
+				return token;
+			}
+
+			token += source[pos];
+			pos++;
+			continue;
+		}
+
+		switch (source[pos]) {
+		case ' ':
+			pos++;
+			done = true;
+			break;
+
+		case ')':
+			if (type == kLBNoToken) {
+				type = kLBEndToken;
+				return Common::String();
+			}
+			done = true;
+			break;
+
+		case ';':
+			if (type == kLBNoToken) {
+				pos++;
+				type = kLBEndToken;
+				return Common::String();
+			}
+			done = true;
+			break;
+
+		case '@':
+			// FIXME
+			error("found @ in string '%s', not supported yet", source.c_str());
+
+		case '+':
+		case '-':
+		case '!':
+		case '=':
+		case '>':
+		case '<':
+			if (type == kLBNoToken)
+				type = kLBOperatorToken;
+			if (type == kLBOperatorToken)
+				token += source[pos];
+			else
+				done = true;
+			break;
+
+		case '"':
+			if (type == kLBNoToken)
+				type = kLBStringToken;
+			else
+				done = true;
+			break;
+
+		case '0':
+		case '1':
+		case '2':
+		case '3':
+		case '4':
+		case '5':
+		case '6':
+		case '7':
+		case '8':
+		case '9':
+			if (type == kLBNoToken)
+				type = kLBIntegerToken;
+			if (type == kLBNameToken || type == kLBIntegerToken)
+				token += source[pos];
+			else
+				done = true;
+			break;
+
+		default:
+			if (type == kLBNoToken)
+				type = kLBNameToken;
+			if (type == kLBNameToken)
+				token += source[pos];
+			else
+				done = true;
+			break;
+		}
+
+		if (!done)
+			pos++;
+	}
+
+	if (type == kLBStringToken)
+		error("readToken: ran out of input while parsing string from '%s'", source.c_str());
+
+	if (!token.size()) {
+		assert(type == kLBNoToken);
+		type = kLBEndToken;
+	}
+
+	return token;
+}
+
+LBValue LBItem::parseValue(const Common::String &source, uint &pos) {
+	LBTokenType type, postOpType;
+	Common::String preOp, postOp;
+
+	Common::String str = readToken(source, pos, type);
+	if (type == kLBOperatorToken) {
+		preOp = str;
+		str = readToken(source, pos, type);
+	}
+
+	LBValue value;
+	if (type == kLBStringToken) {
+		value.type = kLBValueString;
+		value.string = str;
+	} else if (type == kLBIntegerToken) {
+		value.type = kLBValueInteger;
+		value.integer = atoi(str.c_str());
+	} else if (type == kLBNameToken) {
+		value = _vm->_variables[str];
+	} else {
+		error("expected string/integer as value in '%s', got '%s'", source.c_str(), str.c_str());
+	}
+
+	uint readAheadPos = pos;
+	postOp = readToken(source, readAheadPos, postOpType);
+	if (postOpType != kLBEndToken) {
+		if (postOpType != kLBOperatorToken)
+			error("expected operator after '%s' in '%s', got '%s'", str.c_str(), source.c_str(), postOp.c_str());
+		// might be a comparison operator, caller will handle other cases if valid
+		if (postOp == "-" || postOp == "+") {
+			pos = readAheadPos;
+			LBValue nextValue = parseValue(source, pos);
+			if (value.type != kLBValueInteger || nextValue.type != kLBValueInteger)
+				error("expected integer for arthmetic operator in '%s'", source.c_str());
+			if (postOp == "+")
+				value.integer += nextValue.integer;
+			else if (postOp == "-")
+				value.integer -= nextValue.integer;
+			else
+				error("internal error in parseValue");
+		}
+	}
+
+	if (preOp.size()) {
+		if (preOp == "!") {
+			if (value.type == kLBValueInteger)
+				value.integer = !value.integer;
+			else
+				error("expected integer after ! operator in '%s'", source.c_str());
+		} else {
+			error("expected valid operator before '%s' in '%s', got '%s'", str.c_str(), source.c_str(), preOp.c_str());
+		}
+	}
+
+	return value;
+}
+
+void LBItem::runCommand(const Common::String &command) {
+	uint pos = 0;
+	LBTokenType type;
+
+	debug(2, "running command '%s'", command.c_str());
+
+	while (pos < command.size()) {
+		Common::String varname = readToken(command, pos, type);
+		if (type != kLBNameToken)
+			error("expected name as lvalue of command '%s', got '%s'", command.c_str(), varname.c_str());
+		Common::String op = readToken(command, pos, type);
+		if (type != kLBOperatorToken || (op != "=" && op != "++" && op != "--"))
+			error("expected assignment/postincrement/postdecrement operator for command '%s', got '%s'", command.c_str(), op.c_str());
+
+		if (op == "=") {
+			LBValue value = parseValue(command, pos);
+			_vm->_variables[varname] = value;
+		} else {
+			if (_vm->_variables[varname].type != kLBValueInteger)
+				error("expected integer after postincrement/postdecrement operator in '%s'", command.c_str());
+			if (op == "++")
+				_vm->_variables[varname].integer++;
+			else if (op == "--")
+				_vm->_variables[varname].integer--;
+			else
+				error("internal error in runCommand");
+		}
+	}
+}
+
+bool LBItem::checkCondition(const Common::String &condition) {
+	uint pos = 0;
+	LBTokenType type;
+
+	debug(3, "checking condition '%s'", condition.c_str());
+
+	if (condition.size() <= pos || condition[pos] != '(')
+		error("bad condition '%s' (started wrong)", condition.c_str());
+	pos++;
+
+	LBValue value1 = parseValue(condition, pos);
+
+	Common::String op = readToken(condition, pos, type);
+	if (type == kLBEndToken) {
+		if (condition.size() != pos + 1 || condition[pos] != ')')
+			error("bad condition '%s' (ended wrong)", condition.c_str());
+
+		if (value1.type == kLBValueInteger)
+			return value1.integer;
+		else
+			error("expected comparison operator for condition '%s'", condition.c_str());
+	}
+	if (type != kLBOperatorToken || (op != "!=" && op != "==" && op != ">" && op != "<" && op != ">=" && op != "<="))
+		error("expected comparison operator for condition '%s', got '%s'", condition.c_str(), op.c_str());
+
+	LBValue value2 = parseValue(condition, pos);
+
+	if (condition.size() != pos + 1 || condition[pos] != ')')
+		error("bad condition '%s' (ended wrong)", condition.c_str());
+
+	if (op == "!=")
+		return (value1 != value2);
+	else if (op == "==")
+		return (value1 == value2);
+
+	if (value1.type != kLBValueInteger || value2.type != kLBValueInteger)
+		error("evaluation operator %s in condition '%s' expected two integer operands!", op.c_str(), condition.c_str());
+
+	if (op == ">")
+		return (value1.integer > value2.integer);
+	else if (op == ">=")
+		return (value1.integer >= value2.integer);
+	else if (op == "<")
+		return (value1.integer < value2.integer);
+	else if (op == "<=")
+		return (value1.integer <= value2.integer);
+
+	error("internal error in checkCondition");
+}
+
 LBSoundItem::LBSoundItem(MohawkEngine_LivingBooks *vm, Common::Rect rect) : LBItem(vm, rect) {
 	debug(3, "new LBSoundItem");
 	_running = false;

Modified: scummvm/trunk/engines/mohawk/livingbooks.h
===================================================================
--- scummvm/trunk/engines/mohawk/livingbooks.h	2010-12-05 08:36:41 UTC (rev 54776)
+++ scummvm/trunk/engines/mohawk/livingbooks.h	2010-12-05 16:19:35 UTC (rev 54777)
@@ -224,6 +224,22 @@
 	Common::Array<Common::Point> _shapeOffsets;
 };
 
+enum LBValueType {
+	kLBValueString,
+	kLBValueInteger
+};
+
+struct LBValue {
+	LBValue() { type = kLBValueInteger; integer = 0; }
+
+	LBValueType type;
+	Common::String string;
+	int integer;
+
+	bool operator==(const LBValue &x) const;
+	bool operator!=(const LBValue &x) const;
+};
+
 class LBItem {
 public:
 	LBItem(MohawkEngine_LivingBooks *vm, Common::Rect rect);
@@ -280,6 +296,10 @@
 
 	Common::Array<LBScriptEntry *> _scriptEntries;
 	void runScript(uint id);
+
+	LBValue parseValue(const Common::String &command, uint &pos);
+	void runCommand(const Common::String &command);
+	bool checkCondition(const Common::String &condition);
 };
 
 class LBSoundItem : public LBItem {
@@ -460,6 +480,9 @@
 	void prevPage();
 	void nextPage();
 
+	// TODO: make private
+	Common::HashMap<Common::String, LBValue> _variables;
+
 private:
 	LivingBooksConsole *_console;
 	Common::ConfigFile _bookInfoFile;


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list