GLK: ADVSYS: In progress implementing input line parser

This commit is contained in:
Paul Gilbert 2019-06-11 20:12:28 -07:00
parent 4e74751e7e
commit 9efb6d71e2
4 changed files with 106 additions and 13 deletions

View file

@ -202,7 +202,7 @@ bool Game::match(int obj, int noun, int *adjectives) {
return true;
}
int Game::checkVerb(int *verbs) {
int Game::checkVerb(const Common::Array<int> &verbs) {
// Iterate through the actions
for (int idx = 1; idx <= _actionCount; ++idx) {
if (hasVerb(idx, verbs))
@ -212,7 +212,7 @@ int Game::checkVerb(int *verbs) {
return NIL;
}
int Game::findAction(int *verbs, int preposition, int flag) {
int Game::findAction(const Common::Array<int> &verbs, int preposition, int flag) {
// Iterate through the actions
for (int idx = 1; idx <= _actionCount; ++idx) {
if ((preposition && !hasPreposition(idx, preposition)) || !hasVerb(idx, verbs))
@ -301,23 +301,23 @@ bool Game::hasAdjective(int obj, int adjective) const {
return false;
}
bool Game::hasVerb(int act, int *verbs) const {
bool Game::hasVerb(int act, const Common::Array<int> &verbs) const {
// Get the list of verbs
int link = getActionField(act, A_VERBS);
// Look for the verb
for (; link; link = readWord(link + L_NEXT)) {
int *verb = verbs;
Common::Array<int>::const_iterator verb = verbs.begin();
int word = readWord(link + L_DATA);
for (; *verb && word; link = readWord(link + L_NEXT)) {
for (; verb < verbs.end() && word; link = readWord(link + L_NEXT)) {
if (*verb != readWord(word + L_DATA))
break;
++verb;
}
if (!*verb && !word)
if (verb == verbs.end() && !word)
return true;
}

View file

@ -45,6 +45,19 @@ enum Action {
A_SIZE = 8
};
/**
* Word types
*/
enum WordType {
WT_UNKNOWN = 0,
WT_VERB = 1,
WT_NOUN = 2,
WT_ADJECTIVE = 3,
WT_PREPOSITION = 4,
WT_CONJUNCTION = 5,
WT_ARTICLE = 6
};
/**
* Object fields
*/
@ -169,7 +182,7 @@ private:
/**
* Returns true if an action has a given verb
*/
bool hasVerb(int act, int *verbs) const;
bool hasVerb(int act, const Common::Array<int> &verbs) const;
/**
* Returns true if an action is in a given list
@ -253,8 +266,8 @@ public:
/**
* Return a word's type
*/
int getWordType(int word) const {
return _wordTypeTable[word];
WordType getWordType(int word) const {
return (WordType)_wordTypeTable[word];
}
/**
@ -265,12 +278,12 @@ public:
/**
* Check to see if this is a valid verb
*/
int checkVerb(int *verbs);
int checkVerb(const Common::Array<int> &verbs);
/**
* Find an action matching a given description
*/
int findAction(int *verbs, int preposition, int flag);
int findAction(const Common::Array<int> &verbs, int preposition, int flag);
/**
* Get an object property

View file

@ -85,7 +85,7 @@ OpcodeMethod VM::_METHODS[0x34] = {
VM::VM(OSystem *syst, const GlkGameDescription &gameDesc) : GlkInterface(syst, gameDesc), Game(),
_fp(_stack), _pc(0), _status(IN_PROGRESS), _actor(-1), _action(-1), _dObject(-1),
_ndObjects(-1), _iObject(-1) {
_ndObjects(-1), _iObject(-1), _wordPtr(nullptr) {
Common::fill(&_nouns[0], &_nouns[20], 0);
Common::fill(&_nounWords[0], &_nounWords[20], -1);
Common::fill(&_adjectives[0], &_adjectives[20], (int *)nullptr);
@ -452,6 +452,14 @@ bool VM::parseInput() {
if (!getLine())
return false;
// Check for actor
WordType wordType = getWordType(_words.front());
if (wordType == WT_ADJECTIVE || wordType == WT_NOUN) {
if (!(_actor = getNoun()))
return false;
flag |= A_ACTOR;
}
// TODO: stub
return false;
}
@ -475,6 +483,7 @@ bool VM::getLine() {
return false;
}
_wordPtr = _words.begin();
return true;
}
@ -505,6 +514,50 @@ bool VM::getWord(Common::String &line) {
}
}
bool VM::getNoun() {
// TODO: Stub
return false;
}
bool VM::getVerb() {
_verbs.clear();
if (_words.front() == NIL || getWordType(_words.front()) != WT_VERB) {
parseError();
return false;
}
_verbs.push_back(*_wordPtr++);
// Check for a word following the verb
if (!_words.empty()) {
_verbs.push_back(_words.front());
if (checkVerb(_verbs)) {
++_wordPtr;
} else {
_verbs.push_back(_words.back());
if (checkVerb(_verbs)) {
_words.pop_back();
} else {
_verbs.pop_back();
if (!checkVerb(_verbs)) {
parseError();
return false;
}
}
}
}
return true;
}
void VM::parseError() {
// TODO
}
bool VM::isWhitespace(char c) {
return c == ' ' || c == ',' || c == '.';
}

View file

@ -113,6 +113,16 @@ enum FPOffset {
FP_ARGS = 3
};
/**
* Action flags
*/
enum ActionFlag {
A_ACTOR = 1, ///< Actor
A_DOBJECT = 2, ///< Direct object
A_IOBJECT = 4 ///< Indirect object
};
class VM;
typedef void (VM::*OpcodeMethod)();
@ -192,6 +202,7 @@ class VM : public GlkInterface, public Game {
int _number;
InputWord() : _number(0) {}
operator int() const { return _number; }
};
private:
// Execution fields
@ -213,7 +224,8 @@ private:
int _ndObjects;
int _iObject;
Common::Array<InputWord> _words;
InputWord *_wordPtr;
Common::Array<InputWord>::iterator _wordPtr;
Common::Array<int> _verbs;
private:
/**
* Execute a single opcode within the script
@ -251,6 +263,21 @@ private:
*/
bool getWord(Common::String &line);
/**
* Get a noun phrase and return the object it refers to
*/
bool getNoun();
/**
* Get a verb phrase and return the action it refers to
*/
bool getVerb();
/**
* Called when a parsing error occurs
*/
void parseError();
/**
* Returns true if a passed character is a skippable whitespace
*/