ScummVM API documentation
lingo.h
1/* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#ifndef DIRECTOR_LINGO_LINGO_H
23#define DIRECTOR_LINGO_LINGO_H
24
25namespace Audio {
26class AudioStream;
27}
28namespace Common {
29class SeekableReadStreamEndian;
30}
31
32namespace Director {
33
34struct ChunkReference;
35struct MenuReference;
36struct PictureReference;
37struct TheEntity;
38struct TheEntityField;
39struct LingoArchive;
40struct LingoV4Bytecode;
41struct LingoV4TheEntity;
42struct Node;
43struct Picture;
44class AbstractObject;
45class Cast;
46class ScriptContext;
47class DirectorEngine;
48class Frame;
49class Window;
50class LingoCompiler;
51struct Breakpoint;
52
53typedef void (*inst)(void);
54#define STOP (inst)0
55#define ENTITY_INDEX(t,id) ((t) * 100000 + (id))
56
57int calcStringAlignment(const char *s);
58int calcCodeAlignment(int l);
59
60typedef Common::Array<inst> ScriptData;
61
62struct FuncDesc {
63 Common::String name;
64 const char *proto;
65
66 FuncDesc(Common::String n, const char *p) { name = n; proto = p; }
67};
68
70
72
74 const char *name;
75 void (*func)(int);
76 int minArgs; // -1 -- arglist
77 int maxArgs;
78 int version;
79 SymbolType type;
80};
81
82struct Symbol { /* symbol table entry */
83 Common::String *name;
84 SymbolType type;
85 union {
86 ScriptData *defn; /* HANDLER */
87 void (*func)(); /* OPCODE */
88 void (*bltin)(int); /* BUILTIN */
89 Common::String *s; /* STRING */
90 } u;
91
92 int *refCount;
93
94 int nargs; /* number of arguments */
95 int maxArgs; /* maximal number of arguments, for builtins */
96 int targetType; /* valid target objects, for method builtins */
97
100 ScriptContext *ctx; /* optional script context to execute with */
101 AbstractObject *target; /* optional method target */
102 bool anonymous;
103
104 Symbol();
105 Symbol(const Symbol &s);
106 Symbol& operator=(const Symbol &s);
107 bool operator==(Symbol &s) const;
108 void reset();
109 ~Symbol();
110};
111
112struct PArray {
113 bool _sorted;
114 PropertyArray arr;
115
116 PArray() : _sorted(false) {}
117
118 PArray(int size) : _sorted(false), arr(size) {}
119};
120
121struct FArray {
122 bool _sorted;
123 DatumArray arr;
124
125 FArray() : _sorted(false) {}
126
127 FArray(int size) : _sorted(false), arr(size) {}
128};
129
130
131struct Datum { /* interpreter stack type */
132 DatumType type;
133
134 union {
135 int i; /* INT, ARGC, ARGCNORET */
136 double f; /* FLOAT */
137 Common::String *s; /* STRING, VARREF, OBJECT */
138 FArray *farr; /* ARRAY, POINT, RECT */
139 PArray *parr; /* PARRAY */
140 AbstractObject *obj; /* OBJECT */
141 ChunkReference *cref; /* CHUNKREF */
142 CastMemberID *cast; /* CASTREF, FIELDREF */
143 MenuReference *menu; /* MENUREF */
144 PictureReference *picture; /* PICTUREREF */
145 } u;
146
147 int *refCount;
148
149 bool ignoreGlobal; // True if this Datum should be ignored by showGlobals and clearGlobals
150
151 Datum();
152 Datum(const Datum &d);
153 Datum& operator=(const Datum &d);
154 Datum(int val);
155 Datum(double val);
156 Datum(const Common::String &val);
157 Datum(AbstractObject *val);
158 Datum(CastMember *val);
159 Datum(const CastMemberID &val);
160 Datum(const Common::Point &point);
161 Datum(const Common::Rect &rect);
162 void reset();
163
164 ~Datum() {
165 reset();
166 }
167
168 Datum eval() const;
169 double asFloat() const;
170 int asInt() const;
171 Common::String asString(bool printonly = false) const;
172 CastMemberID asMemberID(CastType castType = kCastTypeAny, int castLib = 0) const;
173 Common::Point asPoint() const;
174 Datum clone() const;
175
176 bool isRef() const;
177 bool isVarRef() const;
178 bool isCastRef() const;
179 bool isArray() const;
180 bool isNumeric() const;
181 bool isVoid() const { return type == VOID; }
182
183 const char *type2str(bool ilk = false) const;
184
185 int equalTo(const Datum &d, bool ignoreCase = false) const;
186 uint32 compareTo(const Datum &d) const;
187
188 bool operator==(const Datum &d) const;
189 bool operator>(const Datum &d) const;
190 bool operator<(const Datum &d) const;
191 bool operator>=(const Datum &d) const;
192 bool operator<=(const Datum &d) const;
193};
194
196 Datum source;
197 ChunkType type;
198 int startChunk;
199 int endChunk;
200 int start;
201 int end;
202
203 ChunkReference(const Datum &src, ChunkType t, int sc, int ec, int s, int e)
204 : source(src), type(t), startChunk(sc), endChunk(ec), start(s), end(e) {}
205};
206
208 int menuIdNum;
209 Common::String *menuIdStr;
210 int menuItemIdNum;
211 Common::String *menuItemIdStr;
212
214};
215
217 Picture *_picture = nullptr;
219};
220
221struct PCell {
222 Datum p;
223 Datum v;
224
225 PCell();
226 PCell(const Datum &prop, const Datum &val);
227};
228
229struct Builtin {
230 void (*func)(void);
231 int nargs;
232
233 Builtin(void (*func1)(void), int nargs1) : func(func1), nargs(nargs1) {}
234};
235
243typedef void (*XLibOpenerFunc)(ObjectType, const Common::Path &);
244typedef void (*XLibCloserFunc)(ObjectType);
250
253
254struct CFrame { /* proc/func call stack frame */
255 Symbol sp; /* symbol table entry */
256 int retPC; /* where to resume after return */
257 ScriptData *retScript; /* which script to resume after return */
258 ScriptContext *retContext; /* which script context to use after return */
259 DatumHash *retLocalVars;
260 Datum retMe; /* which me obj to use after return */
261 uint stackSizeBefore;
262 bool allowRetVal; /* whether to allow a return value */
263 Datum defaultRetVal; /* default return value */
264 int paramCount; /* original number of arguments submitted */
265 Common::Array<Datum> paramList; /* original argument list */
266 Window *retWindow = nullptr; /* window to restore on return */
267};
268
270 LEvent event;
271 int eventId;
272 EventHandlerSourceType eventHandlerSourceType;
273 ScriptType scriptType;
274 bool passByDefault;
275 uint16 channelId;
276 CastMemberID scriptId;
277 Common::Point mousePos;
278 int behaviorIndex;
279 AbstractObject *scriptInstance;
280
281 LingoEvent(LEvent e, int ei, ScriptType st, bool pass, CastMemberID si = CastMemberID(), Common::Point mp = Common::Point(-1, -1), int bi = -1) {
282 event = e;
283 eventId = ei;
284 eventHandlerSourceType = kNoneHandler;
285 scriptType = st;
286 passByDefault = pass;
287 channelId = 0;
288 scriptId = si;
289 mousePos = mp;
290 behaviorIndex = bi;
291 scriptInstance = nullptr;
292
293 debugC(7, kDebugEvents, "LingoEvent: event=%s, eventId=%d, scriptType=%d, passByDefault=%d, scriptId=(%d,%d), mousePos=(%d,%d), behaviorIndex=%d",
294 leventType2str(event), eventId, scriptType, passByDefault, scriptId.member, scriptId.castLib, mousePos.x, mousePos.y, behaviorIndex);
295 }
296
297 LingoEvent(LEvent e, int ei, EventHandlerSourceType ehst, bool pass, Common::Point mp = Common::Point(-1, -1), uint16 ci = 0, int bi = -1) {
298 event = e;
299 eventId = ei;
300 eventHandlerSourceType = ehst;
301 scriptType = kNoneScript;
302 passByDefault = pass;
303 channelId = ci;
304 scriptId = CastMemberID();
305 mousePos = mp;
306 behaviorIndex = bi;
307 scriptInstance = nullptr;
308
309 debugC(7, kDebugEvents, "LingoEvent: event=%s, eventId=%d, eventHandlerSourceType=%s, passByDefault=%d, channelId=%d, mousePos=(%d,%d), behaviorIndex=%d",
310 leventType2str(event), eventId, eventHandlerSourceType2str(eventHandlerSourceType), passByDefault, channelId, mousePos.x, mousePos.y, behaviorIndex);
311 }
312};
313
314
316 LingoArchive(Cast *c) : cast(c) {};
318
319 Cast *cast;
320 ScriptContextHash lctxContexts;
321 ScriptContextHash scriptContexts[kMaxScriptType + 1];
322 FactoryContextHash factoryContexts;
324 Common::HashMap<uint32, Common::String> primaryEventHandlers;
325 SymbolHash functionHandlers;
326
327 ScriptContext *getScriptContext(ScriptType type, uint16 id);
328 ScriptContext *findScriptContext(uint16 id);
329 Common::String getName(uint16 id);
330 Common::String formatFunctionList(const char *prefix);
331
332 void addCode(const Common::U32String &code, ScriptType type, uint16 id, const char *scriptName = nullptr, uint32 preprocFlags = kLPPNone);
333 void patchCode(const Common::U32String &code, ScriptType type, uint16 id, const char *scriptName = nullptr, uint32 preprocFlags = kLPPNone);
334 void removeCode(ScriptType type, uint16 id);
335 void replaceCode(const Common::U32String &code, ScriptType type, uint16 id, const char *scriptName = nullptr);
336 void addCodeV4(Common::SeekableReadStreamEndian &stream, uint16 lctxIndex, const Common::String &archName, uint16 version);
337 void addNamesV4(Common::SeekableReadStreamEndian &stream);
338
339 // lingo-patcher.cpp
340 void patchScriptHandler(ScriptType type, CastMemberID id);
341};
342
344 // Execution state for a Lingo process, created every time
345 // a top-level handler is called (e.g. on mouseDown).
346 // Can be swapped out when another script gets called with priority.
347 // Call frames are pushed and popped from the callstack with
348 // pushContext and popContext.
349 Common::Array<CFrame *> callstack; // call stack
350 uint pc = 0; // current program counter
351 ScriptData *script = nullptr; // current Lingo script
352 ScriptContext *context = nullptr; // current Lingo script context
353 DatumHash *localVars = nullptr; // current local variables
354 Datum me; // current me object
355 StackData stack;
356 int currentChannelId = 0;
357
358 ~LingoState();
359};
360
361enum LingoExecState {
362 kRunning,
363 kPause,
364};
365
366class Lingo {
367
368public:
370 ~Lingo();
371
372 void resetLingo();
373 void cleanupLingo();
374 void resetLingoGo();
375
376 int getMenuNum();
377 int getMenuItemsNum(Datum &d);
378 int getXtrasNum();
379 int getCastLibsNum();
380 int getMembersNum(uint16 castLibID);
381
382 void executeHandler(const Common::String &name, int numargs = 0);
383 void executeScript(ScriptType type, CastMemberID id);
384 Common::String formatStack();
385 void printStack(const char *s, uint pc);
386 Common::String formatCallStack(uint pc);
387 void printCallStack(uint pc);
388 Common::String formatFrame();
389 Common::String formatCurrentInstruction();
390 Common::String decodeInstruction(ScriptData *sd, uint pc, uint *newPC = NULL);
391 Common::String decodeScript(ScriptData *sd);
392 Common::String formatFunctionName(Symbol &sym);
393 Common::String formatFunctionBody(Symbol &sym);
394
395 void reloadBuiltIns();
396 void initBuiltIns();
397 void initBuiltIns(const BuiltinProto protos[]);
398 void cleanupBuiltIns();
399 void cleanupBuiltIns(const BuiltinProto protos[]);
400 void initFuncs();
401 void cleanupFuncs();
402 void initBytecode();
403 void initMethods();
404 void cleanupMethods();
405 void initXLibs();
406 void cleanupXLibs();
407
408 Common::String normalizeXLibName(Common::String name);
409 void openXLib(Common::String name, ObjectType type, const Common::Path &path);
410 void closeXLib(Common::String name);
411 void closeOpenXLibs();
412 void reloadOpenXLibs();
413
414 void runTests();
415
416 // lingo-events.cpp
417private:
418 void initEventHandlerTypes();
419 bool processEvent(LEvent event, ScriptType st, CastMemberID scriptId, int channelId = -1, AbstractObject *obj = nullptr);
420
421public:
422 ScriptType event2script(LEvent ev);
423 Symbol getHandler(const Common::String &name);
424
425 void processEvents(Common::Queue<LingoEvent> &queue, bool isInputEvent);
426
427public:
428 bool execute(int targetFrame = -1);
429 void switchStateFromWindow();
430 void freezeState();
431 void freezePlayState();
432 void requeuePlayState();
433 void pushContext(const Symbol funcSym, bool allowRetVal, Datum defaultRetVal, int paramCount, int nargs);
434 void popContext(bool aborting = false);
435 void cleanLocalVars();
436 void varAssign(const Datum &var, const Datum &value);
437 Datum varFetch(const Datum &var, bool silent = false);
438 Common::U32String evalChunkRef(const Datum &var);
439 Datum findVarV4(int varType, const Datum &id);
440 CastMemberID resolveCastMember(const Datum &memberID, const Datum &castLib, CastType type);
441 CastMemberID toCastMemberID(const Datum &member, const Datum &castLib);
442 void exposeXObject(const char *name, Datum obj);
443
444 int getAlignedType(const Datum &d1, const Datum &d2, bool equality);
445
446 Common::String formatAllVars();
447 void printAllVars();
448
449 inst readInst() { return getInst(_state->pc++); }
450 inst getInst(uint pc) { return (*_state->script)[pc]; }
451 int readInt() { return getInt(_state->pc++); }
452 int getInt(uint pc);
453 double readFloat() { double d = getFloat(_state->pc); _state->pc += calcCodeAlignment(sizeof(double)); return d; }
454 double getFloat(uint pc) { return *(double *)(&((*_state->script)[_state->pc])); }
455 char *readString() { char *s = getString(_state->pc); _state->pc += calcStringAlignment(s); return s; }
456 char *getString(uint pc) { return (char *)(&((*_state->script)[_state->pc])); }
457
458 Datum getVoid();
459 void pushVoid();
460
461 void printArgs(const char *funcname, int nargs, const char *prefix = nullptr);
462 inline void printSTUBWithArglist(const char *funcname, int nargs) { printArgs(funcname, nargs, "STUB: "); }
463 void convertVOIDtoString(int arg, int nargs);
464 void dropStack(int nargs);
465 void drop(uint num);
466
467 void lingoError(const char *s, ...);
468
469 void func_mci(const Common::String &name);
470 void func_mciwait(const Common::String &name);
471 void func_beep(int repeats);
472 void func_goto(Datum &frame, Datum &movie, bool commandgo = false );
473 void func_gotoloop();
474 void func_gotonext();
475 void func_gotoprevious();
476 void func_play(Datum &frame, Datum &movie);
477 void func_playdone();
478 void func_cursor(Datum cursorDatum);
479 int func_marker(int m);
480 uint16 func_label(Datum &label);
481
482 // lingo-the.cpp
483public:
484 void initTheEntities();
485 void cleanUpTheEntities();
486 const char *entity2str(int id);
487 const char *field2str(int id);
488
489 // global kTheEntity
490 Datum _actorList;
491 Common::u32char_type_t _itemDelimiter;
492 bool _exitLock;
493 bool _preLoadEventAbort; // no-op, everything is always preloaded
494 Datum _searchPath;
495 bool _trace; // state of movie's trace function
496 int _traceLoad; // internal Director verbosity level
497 bool _updateMovieEnabled;
498 bool _romanLingo;
499 Common::String _soundDevice;
500
501 Datum getTheEntity(int entity, Datum &id, int field);
502 void setTheEntity(int entity, Datum &id, int field, Datum &d);
503 Datum getTheSprite(Datum &id, int field);
504 void setTheSprite(Datum &id, int field, Datum &d);
505 Datum getTheCast(Datum &id, int field);
506 void setTheCast(Datum &id, int field, Datum &d);
507 Datum getTheCastLib(Datum &id, int field);
508 void setTheCastLib(Datum &id, int field, Datum &d);
509 Datum getTheField(Datum &id1, int field);
510 void setTheField(Datum &id1, int field, Datum &d);
511 Datum getTheChunk(Datum &chunk, int field);
512 void setTheChunk(Datum &chunk, int field, Datum &d);
513 void getObjectProp(Datum &obj, Common::String &propName);
514 void setObjectProp(Datum &obj, Common::String &propName, Datum &d);
515 Datum getTheDate(int field);
516 Datum getTheTime(int field);
517 Datum getTheDeskTopRectList();
518
519private:
520 Common::StringArray _entityNames;
521 Common::StringArray _fieldNames;
522
523public:
524 LingoCompiler *_compiler;
525 LingoState *_state;
526
527 bool _freezeState;
528 bool _freezePlay;
529 bool _playDone;
530 bool _abort;
531 bool _expectError;
532 bool _caughtError;
533
534 TheEntityHash _theEntities;
535 TheEntityFieldHash _theEntityFields;
536
537 int _objectEntityId;
538
539 SymbolHash _builtinCmds;
540 SymbolHash _builtinFuncs;
541 SymbolHash _builtinConsts;
542 SymbolHash _builtinListHandlers;
543 SymbolHash _methods;
544 XLibOpenerFuncHash _xlibOpeners;
545 XLibCloserFuncHash _xlibClosers;
546 XLibTypeHash _xlibTypes;
547
548 OpenXLibsHash _openXLibs;
549 OpenXLibsStateHash _openXLibsState;
550 Common::StringArray _openXtras;
551 Common::Array<Datum> _openXtraObjects;
552 OpenXLibsStateHash _openXtrasState;
553
554 Common::String _floatPrecisionFormat;
555
556public:
557 void push(Datum d);
558 Datum pop();
559 Datum peek(uint offset);
560
561public:
562 Common::HashMap<uint32, const char *> _eventHandlerTypes;
565
566 DatumHash _globalvars;
567
568 FuncHash _functions;
569
572
573 uint _globalCounter;
574
575 DirectorEngine *_vm;
576
577 int _floatPrecision;
578
579 Datum _theResult;
580
581 // events
582 bool _passEvent;
583 Datum _perFrameHook;
584
585 Datum _windowList;
586 Symbol _currentInputEvent;
587
588 struct {
589 LingoExecState _state = kRunning;
590 bool (*_shouldPause)() = nullptr;
591 } _exec;
592
593public:
594 void executeImmediateScripts(Frame *frame);
595 void executePerFrameHook(int frame, int subframe, bool stepFrame = true);
596
597 // lingo-utils.cpp
598private:
600 void initCharNormalizations();
601
602public:
603 Common::String normalizeString(const Common::String &str);
604
605public:
606 void addBreakpoint(Breakpoint &bp);
607 bool delBreakpoint(int id);
608 Breakpoint *getBreakpoint(int id);
609
610 const Common::Array<Breakpoint> &getBreakpoints() const { return _breakpoints; }
611 Common::Array<Breakpoint> &getBreakpoints() { return _breakpoints; }
612
613private:
614 int _bpNextId = 1;
615 Common::Array<Breakpoint> _breakpoints;
616};
617
618extern Lingo *g_lingo;
619
620} // End of namespace Director
621
622#endif
Definition: array.h:52
Definition: path.h:52
Definition: queue.h:42
Definition: stream.h:944
Definition: str.h:59
Definition: ustr.h:57
Definition: lingo-object.h:42
Definition: cast.h:88
Definition: castmember.h:48
Definition: director.h:158
Definition: frame.h:180
Definition: lingo-codegen.h:30
Definition: lingo.h:366
Definition: lingo-object.h:213
Definition: window.h:106
void void void void void debugC(int level, uint32 debugChannel, MSVC_PRINTF const char *s,...) GCC_PRINTF(3
char32_t u32char_type_t
Definition: ustr.h:55
Definition: system.h:39
Definition: algorithm.h:29
T y
Definition: rect.h:49
T x
Definition: rect.h:48
Definition: rect.h:144
Definition: rect.h:536
Definition: debugger.h:45
Definition: lingo.h:229
Definition: lingo.h:73
Definition: lingo.h:254
Definition: types.h:424
Definition: lingo.h:195
Definition: lingo.h:131
Definition: lingo.h:121
Definition: lingo.h:62
Definition: lingo.h:315
Definition: lingo.h:269
Definition: lingo.h:343
Definition: lingo.h:207
Definition: lingo.h:112
Definition: lingo.h:221
Definition: picture.h:33
Definition: lingo.h:216
Definition: lingo.h:82
Definition: lobject.h:332