From 15c5d33b8878b119395f165bf534b0f3d578d278 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Mon, 23 Dec 2019 22:36:21 +0100 Subject: DIRECTOR: LINGO: Preprocess 'return' constant so it compiles --- engines/director/lingo/lingo-builtins.cpp | 2 +- engines/director/lingo/lingo.cpp | 76 ++++++++++++++++++++++++++++--- engines/director/lingo/lingo.h | 1 + 3 files changed, 71 insertions(+), 8 deletions(-) (limited to 'engines/director') 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 -- cgit v1.2.3