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