From 8cc88b6fcad2195883f058a2cd0cb3f7c2414acd Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Fri, 1 Jul 2016 10:56:02 +0200 Subject: [PATCH] DIRECTOR: Lingo: Initial code for built-in functions --- engines/director/lingo/lingo-builtins.cpp | 53 +++++++++++++++ engines/director/lingo/lingo-codegen.cpp | 37 +++++++++++ engines/director/lingo/lingo-gr.cpp | 79 +++++++++++------------ engines/director/lingo/lingo-gr.y | 7 +- engines/director/lingo/lingo.cpp | 19 +----- engines/director/lingo/lingo.h | 29 +++++++-- engines/director/module.mk | 1 + 7 files changed, 155 insertions(+), 70 deletions(-) create mode 100644 engines/director/lingo/lingo-builtins.cpp diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp new file mode 100644 index 000000000000..2286bb7ed2c4 --- /dev/null +++ b/engines/director/lingo/lingo-builtins.cpp @@ -0,0 +1,53 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "engines/director/lingo/lingo.h" + +namespace Director { + +static struct BuiltinProto { + const char *name; + void (*func)(void); + int nparams; +} builtins[] = { + { "random", Lingo::b_random, 1}, + { 0, 0, 0 } +}; + +void Lingo::initBuiltIns() { + for (BuiltinProto *blt = builtins; blt->name; blt++) { + _builtins[blt->name] = new Builtin(blt->func, blt->nparams); + } +} + +void Lingo::b_random() { + Datum max = g_lingo->pop(); + Datum res; + + res.u.i = 5; + res.type = INT; + + warning("b_random"); + g_lingo->push(res); +} + +} diff --git a/engines/director/lingo/lingo-codegen.cpp b/engines/director/lingo/lingo-codegen.cpp index 89d30bec4765..6e388ddbabb3 100644 --- a/engines/director/lingo/lingo-codegen.cpp +++ b/engines/director/lingo/lingo-codegen.cpp @@ -126,6 +126,23 @@ void Lingo::define(Common::String &name, int start, int nargs) { sym->nargs = nargs; } +int Lingo::codeString(const char *str) { + int numInsts = calcStringAlignment(str); + + // Where we copy the string over + int pos = _currentScript->size(); + + // Allocate needed space in script + for (int i = 0; i < numInsts; i++) + _currentScript->push_back(0); + + byte *dst = (byte *)&_currentScript->front() + pos * sizeof(inst); + + memcpy(dst, str, strlen(str) + 1); + + return _currentScript->size(); +} + void Lingo::codeArg(Common::String *s) { _argstack.push_back(s); } @@ -164,4 +181,24 @@ int Lingo::codeId_(Common::String &name) { return ret; } +int Lingo::codeFunc(Common::String *name, int nargs) { + int ret; + + if (!g_lingo->_builtins.contains(*name)) { + ret = g_lingo->code1(g_lingo->c_call); + g_lingo->codeString(name->c_str()); + + inst numpar = 0; + WRITE_UINT32(&numpar, nargs); + g_lingo->code1(numpar); + } else { + if (nargs != g_lingo->_builtins[*name]->nargs) + error("Built-in function %s expects %d arguments but got %d", name->c_str(), g_lingo->_builtins[*name]->nargs, nargs); + + ret = g_lingo->code1(g_lingo->_builtins[*name]->func); + } + + return ret; +} + } diff --git a/engines/director/lingo/lingo-gr.cpp b/engines/director/lingo/lingo-gr.cpp index 13630f54269b..01329d468b3a 100644 --- a/engines/director/lingo/lingo-gr.cpp +++ b/engines/director/lingo/lingo-gr.cpp @@ -532,10 +532,10 @@ static const yytype_uint16 yyrline[] = 102, 105, 111, 117, 125, 126, 127, 133, 145, 156, 172, 186, 187, 188, 190, 192, 198, 200, 202, 204, 205, 206, 209, 214, 217, 218, 219, 220, 221, 222, - 223, 224, 225, 226, 227, 228, 229, 232, 238, 239, - 240, 241, 242, 243, 246, 247, 258, 259, 260, 261, - 266, 272, 279, 280, 281, 282, 285, 286, 287, 315, - 315, 321, 322, 323, 324, 326, 329, 337, 338, 339 + 223, 224, 225, 226, 227, 228, 229, 232, 235, 236, + 237, 238, 239, 240, 243, 244, 255, 256, 257, 258, + 263, 269, 276, 277, 278, 279, 282, 283, 284, 312, + 312, 318, 319, 320, 321, 323, 326, 334, 335, 336 }; #endif @@ -1794,60 +1794,57 @@ yyparse () case 47: #line 232 "engines/director/lingo/lingo-gr.y" { - g_lingo->code1(g_lingo->c_call); - g_lingo->codeString((yyvsp[(1) - (4)].s)->c_str()); - inst numpar = 0; - WRITE_UINT32(&numpar, (yyvsp[(3) - (4)].narg)); - g_lingo->code1(numpar); ;} + g_lingo->codeFunc((yyvsp[(1) - (4)].s), (yyvsp[(3) - (4)].narg)); + delete (yyvsp[(1) - (4)].s); ;} break; case 48: -#line 238 "engines/director/lingo/lingo-gr.y" +#line 235 "engines/director/lingo/lingo-gr.y" { g_lingo->code1(g_lingo->c_mci); g_lingo->codeString((yyvsp[(2) - (2)].s)->c_str()); delete (yyvsp[(2) - (2)].s); ;} break; case 49: -#line 239 "engines/director/lingo/lingo-gr.y" +#line 236 "engines/director/lingo/lingo-gr.y" { g_lingo->code1(g_lingo->c_mciwait); g_lingo->codeString((yyvsp[(2) - (2)].s)->c_str()); delete (yyvsp[(2) - (2)].s); ;} break; case 50: -#line 240 "engines/director/lingo/lingo-gr.y" +#line 237 "engines/director/lingo/lingo-gr.y" { g_lingo->code1(g_lingo->c_printtop); ;} break; case 52: -#line 242 "engines/director/lingo/lingo-gr.y" +#line 239 "engines/director/lingo/lingo-gr.y" { g_lingo->code1(g_lingo->c_exit); ;} break; case 54: -#line 246 "engines/director/lingo/lingo-gr.y" +#line 243 "engines/director/lingo/lingo-gr.y" { g_lingo->code1(g_lingo->c_global); g_lingo->codeString((yyvsp[(1) - (1)].s)->c_str()); delete (yyvsp[(1) - (1)].s); ;} break; case 55: -#line 247 "engines/director/lingo/lingo-gr.y" +#line 244 "engines/director/lingo/lingo-gr.y" { g_lingo->code1(g_lingo->c_global); g_lingo->codeString((yyvsp[(3) - (3)].s)->c_str()); delete (yyvsp[(3) - (3)].s); ;} break; case 56: -#line 258 "engines/director/lingo/lingo-gr.y" +#line 255 "engines/director/lingo/lingo-gr.y" { g_lingo->code1(g_lingo->c_gotoloop); ;} break; case 57: -#line 259 "engines/director/lingo/lingo-gr.y" +#line 256 "engines/director/lingo/lingo-gr.y" { g_lingo->code1(g_lingo->c_gotonext); ;} break; case 58: -#line 260 "engines/director/lingo/lingo-gr.y" +#line 257 "engines/director/lingo/lingo-gr.y" { g_lingo->code1(g_lingo->c_gotoprevious); ;} break; case 59: -#line 261 "engines/director/lingo/lingo-gr.y" +#line 258 "engines/director/lingo/lingo-gr.y" { g_lingo->code1(g_lingo->c_goto); g_lingo->codeString((yyvsp[(2) - (2)].s)->c_str()); @@ -1856,7 +1853,7 @@ yyparse () break; case 60: -#line 266 "engines/director/lingo/lingo-gr.y" +#line 263 "engines/director/lingo/lingo-gr.y" { g_lingo->code1(g_lingo->c_goto); g_lingo->codeString((yyvsp[(2) - (3)].s)->c_str()); @@ -1866,7 +1863,7 @@ yyparse () break; case 61: -#line 272 "engines/director/lingo/lingo-gr.y" +#line 269 "engines/director/lingo/lingo-gr.y" { g_lingo->code1(g_lingo->c_goto); g_lingo->codeString(""); @@ -1875,47 +1872,47 @@ yyparse () break; case 62: -#line 279 "engines/director/lingo/lingo-gr.y" +#line 276 "engines/director/lingo/lingo-gr.y" { (yyval.s) = (yyvsp[(3) - (3)].s); ;} break; case 63: -#line 280 "engines/director/lingo/lingo-gr.y" +#line 277 "engines/director/lingo/lingo-gr.y" { (yyval.s) = (yyvsp[(2) - (2)].s); ;} break; case 64: -#line 281 "engines/director/lingo/lingo-gr.y" +#line 278 "engines/director/lingo/lingo-gr.y" { (yyval.s) = (yyvsp[(2) - (2)].s); ;} break; case 65: -#line 282 "engines/director/lingo/lingo-gr.y" +#line 279 "engines/director/lingo/lingo-gr.y" { (yyval.s) = (yyvsp[(1) - (1)].s); ;} break; case 66: -#line 285 "engines/director/lingo/lingo-gr.y" +#line 282 "engines/director/lingo/lingo-gr.y" { (yyval.s) = (yyvsp[(3) - (3)].s); ;} break; case 67: -#line 286 "engines/director/lingo/lingo-gr.y" +#line 283 "engines/director/lingo/lingo-gr.y" { (yyval.s) = (yyvsp[(2) - (2)].s); ;} break; case 68: -#line 287 "engines/director/lingo/lingo-gr.y" +#line 284 "engines/director/lingo/lingo-gr.y" { (yyval.s) = (yyvsp[(3) - (3)].s); ;} break; case 69: -#line 315 "engines/director/lingo/lingo-gr.y" +#line 312 "engines/director/lingo/lingo-gr.y" { g_lingo->_indef = true; ;} break; case 70: -#line 316 "engines/director/lingo/lingo-gr.y" +#line 313 "engines/director/lingo/lingo-gr.y" { g_lingo->code1(g_lingo->c_procret); g_lingo->define(*(yyvsp[(2) - (8)].s), (yyvsp[(4) - (8)].code), (yyvsp[(5) - (8)].narg)); @@ -1923,32 +1920,32 @@ yyparse () break; case 71: -#line 321 "engines/director/lingo/lingo-gr.y" +#line 318 "engines/director/lingo/lingo-gr.y" { (yyval.narg) = 0; ;} break; case 72: -#line 322 "engines/director/lingo/lingo-gr.y" +#line 319 "engines/director/lingo/lingo-gr.y" { g_lingo->codeArg((yyvsp[(1) - (1)].s)); (yyval.narg) = 1; ;} break; case 73: -#line 323 "engines/director/lingo/lingo-gr.y" +#line 320 "engines/director/lingo/lingo-gr.y" { g_lingo->codeArg((yyvsp[(3) - (3)].s)); (yyval.narg) = (yyvsp[(1) - (3)].narg) + 1; ;} break; case 74: -#line 324 "engines/director/lingo/lingo-gr.y" +#line 321 "engines/director/lingo/lingo-gr.y" { g_lingo->codeArg((yyvsp[(4) - (4)].s)); (yyval.narg) = (yyvsp[(1) - (4)].narg) + 1; ;} break; case 75: -#line 326 "engines/director/lingo/lingo-gr.y" +#line 323 "engines/director/lingo/lingo-gr.y" { g_lingo->codeArgStore(); ;} break; case 76: -#line 329 "engines/director/lingo/lingo-gr.y" +#line 326 "engines/director/lingo/lingo-gr.y" { g_lingo->code1(g_lingo->c_call); g_lingo->codeString((yyvsp[(1) - (3)].s)->c_str()); @@ -1958,23 +1955,23 @@ yyparse () break; case 77: -#line 337 "engines/director/lingo/lingo-gr.y" +#line 334 "engines/director/lingo/lingo-gr.y" { (yyval.narg) = 0; ;} break; case 78: -#line 338 "engines/director/lingo/lingo-gr.y" +#line 335 "engines/director/lingo/lingo-gr.y" { (yyval.narg) = 1; ;} break; case 79: -#line 339 "engines/director/lingo/lingo-gr.y" +#line 336 "engines/director/lingo/lingo-gr.y" { (yyval.narg) = (yyvsp[(1) - (3)].narg) + 1; ;} break; /* Line 1267 of yacc.c. */ -#line 1978 "engines/director/lingo/lingo-gr.cpp" +#line 1975 "engines/director/lingo/lingo-gr.cpp" default: break; } YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); @@ -2188,6 +2185,6 @@ yyparse () } -#line 342 "engines/director/lingo/lingo-gr.y" +#line 339 "engines/director/lingo/lingo-gr.y" diff --git a/engines/director/lingo/lingo-gr.y b/engines/director/lingo/lingo-gr.y index 73dc4f0e08d3..aac0f03582c9 100644 --- a/engines/director/lingo/lingo-gr.y +++ b/engines/director/lingo/lingo-gr.y @@ -230,11 +230,8 @@ expr: INT { ; func: ID '(' arglist ')' { - g_lingo->code1(g_lingo->c_call); - g_lingo->codeString($1->c_str()); - inst numpar = 0; - WRITE_UINT32(&numpar, $3); - g_lingo->code1(numpar); }; + g_lingo->codeFunc($1, $3); + delete $1; } | tMCI STRING { g_lingo->code1(g_lingo->c_mci); g_lingo->codeString($2->c_str()); delete $2; } | tMCIWAIT ID { g_lingo->code1(g_lingo->c_mciwait); g_lingo->codeString($2->c_str()); delete $2; } | tPUT expr { g_lingo->code1(g_lingo->c_printtop); } diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp index e584ac02b909..d8c3bdfad172 100644 --- a/engines/director/lingo/lingo.cpp +++ b/engines/director/lingo/lingo.cpp @@ -81,6 +81,8 @@ Lingo::Lingo(DirectorEngine *vm) : _vm(vm) { for (const EventHandlerType *t = &eventHanlerDescs[0]; t->handler != kEventNone; ++t) _eventHandlerTypes[t->handler] = t->name; + initBuiltIns(); + _currentScript = 0; _currentScriptType = kMovieScript; _pc = 0; @@ -93,23 +95,6 @@ Lingo::Lingo(DirectorEngine *vm) : _vm(vm) { Lingo::~Lingo() { } -int Lingo::codeString(const char *str) { - int numInsts = calcStringAlignment(str); - - // Where we copy the string over - int pos = _currentScript->size(); - - // Allocate needed space in script - for (int i = 0; i < numInsts; i++) - _currentScript->push_back(0); - - byte *dst = (byte *)&_currentScript->front() + pos * sizeof(inst); - - memcpy(dst, str, strlen(str) + 1); - - return _currentScript->size(); -} - void Lingo::addCode(Common::String code, ScriptType type, uint16 id) { code += '\n'; diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h index f9c58f0fa453..d1969c231708 100644 --- a/engines/director/lingo/lingo.h +++ b/engines/director/lingo/lingo.h @@ -103,9 +103,17 @@ struct Datum { /* interpreter stack type */ Datum() { u.sym = NULL; type = VOID; } }; +struct Builtin { + void (*func)(void); + int nargs; + + Builtin(void (*func1)(void), int nargs1) : func(func1), nargs(nargs1) {} +}; + typedef Common::HashMap ScriptHash; typedef Common::Array StackData; typedef Common::HashMap SymbolHash; +typedef Common::HashMap BuiltinHash; struct CFrame { /* proc/func call stack frame */ Symbol *sp; /* symbol table entry */ @@ -124,6 +132,16 @@ class Lingo { void processEvent(LEvent event, int entityId); + void initBuiltIns(); + +public: + void execute(int pc); + void pushContext(); + void popContext(); + Symbol *lookupVar(const char *name, bool create = true, bool putInGlobalList = false); + void cleanLocalVars(); + void define(Common::String &s, int start, int nargs); + int code1(inst code) { _currentScript->push_back(code); return _currentScript->size() - 1; } int code2(inst code_1, inst code_2) { int o = code1(code_1); code1(code_2); return o; } int code3(inst code_1, inst code_2, inst code_3) { int o = code1(code_1); code1(code_2); code1(code_3); return o; } @@ -134,13 +152,7 @@ class Lingo { int l = strlen(s); return (l + 1 + instLen - 1) / instLen; } -public: - void execute(int pc); - void pushContext(); - void popContext(); - Symbol *lookupVar(const char *name, bool create = true, bool putInGlobalList = false); - void cleanLocalVars(); - void define(Common::String &s, int start, int nargs); + int codeFunc(Common::String *name, int nargs); void codeArg(Common::String *s); void codeArgStore(); int codeId(Common::String &s); @@ -179,6 +191,8 @@ class Lingo { static void c_gotoprevious(); static void c_global(); + static void b_random(); + void func_mci(Common::String &s); void func_mciwait(Common::String &s); void func_goto(Common::String &frame, Common::String &movie); @@ -194,6 +208,7 @@ class Lingo { Common::Array _callstack; Common::Array _argstack; + BuiltinHash _builtins; private: int parse(const char *code); diff --git a/engines/director/module.mk b/engines/director/module.mk index b39c75c9ac9a..273a133cfb56 100644 --- a/engines/director/module.mk +++ b/engines/director/module.mk @@ -10,6 +10,7 @@ MODULE_OBJS = \ sound.o \ lingo/lingo-gr.o \ lingo/lingo.o \ + lingo/lingo-builtins.o \ lingo/lingo-code.o \ lingo/lingo-codegen.o \ lingo/lingo-funcs.o \