aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Sandulenko2019-12-23 22:36:21 +0100
committerEugene Sandulenko2019-12-24 00:19:26 +0100
commit15c5d33b8878b119395f165bf534b0f3d578d278 (patch)
treeb1f8855c4e8995ae58c0cf66a56602c89129f1eb
parentca781b7389a52ea6515aa459d308044cfa151701 (diff)
downloadscummvm-rg350-15c5d33b8878b119395f165bf534b0f3d578d278.tar.gz
scummvm-rg350-15c5d33b8878b119395f165bf534b0f3d578d278.tar.bz2
scummvm-rg350-15c5d33b8878b119395f165bf534b0f3d578d278.zip
DIRECTOR: LINGO: Preprocess 'return' constant so it compiles
-rw-r--r--engines/director/lingo/lingo-builtins.cpp2
-rw-r--r--engines/director/lingo/lingo.cpp76
-rw-r--r--engines/director/lingo/lingo.h1
3 files changed, 71 insertions, 8 deletions
diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index d1056fe397..cab0a58a8e 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -208,7 +208,7 @@ static struct BuiltinProto {
{ "enter", Lingo::b_enter, 0, 0, false, 2, FBLTIN }, // D2
{ "false", Lingo::b_false, 0, 0, false, 2, FBLTIN }, // D2
{ "quote", Lingo::b_quote, 0, 0, false, 2, FBLTIN }, // D2
-// { "return", Lingo::b_returnconst, 0, 0, false, 2, FBLTIN }, // D2 // FIXME
+ { "scummvm_return", Lingo::b_returnconst, 0, 0, false, 2, FBLTIN }, // D2
{ "tab", Lingo::b_tab, 0, 0, false, 2, FBLTIN }, // D2
{ "true", Lingo::b_true, 0, 0, false, 2, FBLTIN }, // D2
{ "version", Lingo::b_version, 0, 0, false, 3, FBLTIN }, // D3
diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index d4529d17ca..347b97a42e 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -217,6 +217,10 @@ void Lingo::addCode(const char *code, ScriptType type, uint16 id) {
}
}
+bool isspecial(char c) {
+ return strchr("-+*/%%^:,()><&[]", c) != NULL;
+}
+
static Common::String nexttok(const char *s, const char **newP = nullptr) {
Common::String res;
@@ -224,9 +228,14 @@ static Common::String nexttok(const char *s, const char **newP = nullptr) {
while (*s && (*s == ' ' || *s == '\t')) // If we see a whitespace
s++;
- // Now copy everything till whitespace
- while (*s && *s != ' ' && *s != '\t' && *s != '\n')
- res += *s++;
+ if (Common::isAlnum(*s)) {
+ // Now copy everything till whitespace
+ while (*s && (Common::isAlnum(*s) || *s == '.'))
+ res += *s++;
+ } else {
+ while (*s && isspecial(*s))
+ res += *s++;
+ }
if (newP)
*newP = s;
@@ -309,28 +318,33 @@ Common::String Lingo::codePreprocessor(const char *s, bool simple) {
// Preprocess if statements
// Here we add ' end if' at end of each statement, which lets us
// make the grammar very straightforward
- Common::String line, tok;
+ Common::String line, tok, res1;
const char *lineStart, *prevEnd;
int iflevel = 0;
while (*s) {
line.clear();
+ res1.clear();
// Get next line
while (*s && *s != '\n') { // If we see a whitespace
if (*s == '\xc2') {
- res += *s++;
+ res1 += *s++;
if (*s == '\n') {
line += ' ';
- res += *s++;
+ res1 += *s++;
}
} else {
- res += *s;
+ res1 += *s;
line += tolower(*s++);
}
}
debugC(2, kDebugLingoParse, "line: %d '%s'", iflevel, line.c_str());
+ res1 = preprocessReturn(res1);
+
+ res += res1;
+
if (line.size() < 4) { // If line is too small, then skip it
if (*s) // copy newline symbol
res += *s++;
@@ -457,6 +471,54 @@ Common::String Lingo::codePreprocessor(const char *s, bool simple) {
return res;
}
+#ifndef strcasestr
+const char *strcasestr(const char *s, const char *find) {
+ char c, sc;
+ size_t len;
+
+ if ((c = *find++) != 0) {
+ c = (char)tolower((unsigned char)c);
+ len = strlen(find);
+ do {
+ do {
+ if ((sc = *s++) == 0)
+ return (NULL);
+ } while ((char)tolower((unsigned char)sc) != c);
+ } while (scumm_strnicmp(s, find, len) != 0);
+ s--;
+ }
+ return s;
+}
+#endif
+
+Common::String Lingo::preprocessReturn(Common::String in) {
+ Common::String res, prev, next;
+ const char *ptr = in.c_str();
+ const char *beg = ptr;
+
+ while ((ptr = strcasestr(beg, "return")) != NULL) {
+ res += Common::String(beg, ptr);
+
+ if (ptr == beg)
+ prev = "";
+ else
+ prev = prevtok(ptr - 1, beg);
+
+ next = nexttok(ptr + 6); // end of 'return'
+
+ if (prev.equals("&") || prev.equals("&&") || next.equals("&") || next.equals("&&")) {
+ res += "scummvm_"; // Turn it into scummvm_return
+ }
+
+ res += *ptr++; // We advance one character, so 'eturn' is left
+ beg = ptr;
+ }
+
+ res += Common::String(beg);
+
+ return res;
+}
+
void Lingo::executeScript(ScriptType type, uint16 id, uint16 function) {
if (!_scriptContexts[type].contains(id)) {
debugC(3, kDebugLingoExec, "Request to execute non-existant script type %d id %d", type, id);
diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h
index 26d49176e3..b8a9702d52 100644
--- a/engines/director/lingo/lingo.h
+++ b/engines/director/lingo/lingo.h
@@ -190,6 +190,7 @@ public:
private:
Common::String codePreprocessor(const char *s, bool simple = false);
+ Common::String preprocessReturn(Common::String in);
const char *findNextDefinition(const char *s);
// lingo-events.cpp