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
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (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, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 // Heavily inspired by hoc
24 // Copyright (C) AT&T 1995
25 // All Rights Reserved
26 //
27 // Permission to use, copy, modify, and distribute this software and
28 // its documentation for any purpose and without fee is hereby
29 // granted, provided that the above copyright notice appear in all
30 // copies and that both that the copyright notice and this
31 // permission notice and warranty disclaimer appear in supporting
32 // documentation, and that the name of AT&T or any of its entities
33 // not be used in advertising or publicity pertaining to
34 // distribution of the software without specific, written prior
35 // permission.
36 //
37 // AT&T DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
38 // INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
39 // IN NO EVENT SHALL AT&T OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
40 // SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
41 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
42 // IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43 // ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
44 // THIS SOFTWARE.
45
46
47 %debug
48
49 %{
50 #define FORBIDDEN_SYMBOL_ALLOW_ALL
51
52 #include "common/hash-str.h"
53
54 #include "director/lingo/lingo.h"
55 #include "director/lingo/lingo-gr.h"
56
57 extern int yylex();
58 extern int yyparse();
59
60 using namespace Director;
yyerror(const char * s)61 void yyerror(const char *s) {
62 g_lingo->_hadError = true;
63 warning("%s at line %d col %d", s, g_lingo->_linenumber, g_lingo->_colnumber);
64 }
65
checkEnd(Common::String * token,const char * expect,bool required)66 void checkEnd(Common::String *token, const char *expect, bool required) {
67 if (required) {
68 if (token->compareToIgnoreCase(expect)) {
69 Common::String err = Common::String::format("end mismatch. Expected %s but got %s", expect, token->c_str());
70 yyerror(err.c_str());
71 }
72 }
73
74 delete token;
75 }
76
77 %}
78
79 %union {
80 Common::String *s;
81 int i;
82 double f;
83 int e[2]; // Entity + field
84 int code;
85 int narg; /* number of arguments */
86 Common::Array<double> *arr;
87 }
88
89 %token UNARY
90 %token CASTREF VOID VAR POINT RECT ARRAY OBJECT REFERENCE
91 %token<i> INT
92 %token<e> THEENTITY THEENTITYWITHID
93 %token<f> FLOAT
94 %token<s> BLTIN BLTINNOARGS BLTINNOARGSORONE BLTINONEARG BLTINARGLIST TWOWORDBUILTIN
95 %token<s> FBLTIN FBLTINNOARGS FBLTINONEARG FBLTINARGLIST RBLTIN RBLTINONEARG
96 %token<s> ID STRING HANDLER SYMBOL
97 %token<s> ENDCLAUSE tPLAYACCEL
98 %token tDOWN tELSE tNLELSIF tEXIT tFRAME tGLOBAL tGO tIF tINTO tLOOP tMACRO
99 %token tMOVIE tNEXT tOF tPREVIOUS tPUT tREPEAT tSET tTHEN tTHENNL tTO tWHEN
100 %token tWITH tWHILE tNLELSE tFACTORY tMETHOD tOPEN tPLAY tDONE tINSTANCE
101 %token tGE tLE tGT tLT tEQ tNEQ tAND tOR tNOT tMOD
102 %token tAFTER tBEFORE tCONCAT tCONTAINS tSTARTS tCHAR tITEM tLINE tWORD
103 %token tSPRITE tINTERSECTS tWITHIN tTELL tPROPERTY
104 %token tON tME
105
106 %type<code> asgn begin elseif elsestmtoneliner end expr if when repeatwhile repeatwith stmtlist tell
107 %type<narg> argdef arglist nonemptyarglist
108 %type<s> on
109
110 %right '='
111 %left tLT tLE tGT tGE tNEQ tCONTAINS tSTARTS
112 %left '&'
113 %left '+' '-'
114 %left '*' '/' '%' tAND tOR tMOD
115 %right UNARY
116
117 %%
118
119 program: program nl programline
120 | programline
121 | error nl { yyerrok; }
122 ;
123
124 nl: '\n' {
125 g_lingo->_linenumber++;
126 g_lingo->_colnumber = 1;
127 }
128
129 programline: /* empty */
130 | defn
131 | macro
132 | stmt
133 ;
134
135 asgn: tPUT expr tINTO ID {
136 g_lingo->code1(g_lingo->c_varpush);
137 g_lingo->codeString($4->c_str());
138 g_lingo->code1(g_lingo->c_assign);
139 $$ = $2;
140 delete $4; }
141 | tPUT expr tINTO reference {
142 g_lingo->code1(g_lingo->c_assign);
143 $$ = $2; }
144 | tPUT expr tAFTER expr { $$ = g_lingo->code1(g_lingo->c_after); } // D3
145 | tPUT expr tBEFORE expr { $$ = g_lingo->code1(g_lingo->c_before); } // D3
146 | tSET ID '=' expr {
147 g_lingo->code1(g_lingo->c_varpush);
148 g_lingo->codeString($2->c_str());
149 g_lingo->code1(g_lingo->c_assign);
150 $$ = $4;
151 delete $2; }
152 | tSET THEENTITY '=' expr {
153 g_lingo->codeConst(0); // Put dummy id
154 g_lingo->code1(g_lingo->c_theentityassign);
155 inst e = 0, f = 0;
156 WRITE_UINT32(&e, $2[0]);
157 WRITE_UINT32(&f, $2[1]);
158 g_lingo->code2(e, f);
159 $$ = $4; }
160 | tSET THEENTITYWITHID expr '=' expr {
161 g_lingo->code1(g_lingo->c_swap);
162 g_lingo->code1(g_lingo->c_theentityassign);
163 inst e = 0, f = 0;
164 WRITE_UINT32(&e, $2[0]);
165 WRITE_UINT32(&f, $2[1]);
166 g_lingo->code2(e, f);
167 $$ = $5; }
168 | tSET ID tTO expr {
169 g_lingo->code1(g_lingo->c_varpush);
170 g_lingo->codeString($2->c_str());
171 g_lingo->code1(g_lingo->c_assign);
172 $$ = $4;
173 delete $2; }
174 | tSET THEENTITY tTO expr {
175 g_lingo->codeConst(0); // Put dummy id
176 g_lingo->code1(g_lingo->c_theentityassign);
177 inst e = 0, f = 0;
178 WRITE_UINT32(&e, $2[0]);
179 WRITE_UINT32(&f, $2[1]);
180 g_lingo->code2(e, f);
181 $$ = $4; }
182 | tSET THEENTITYWITHID expr tTO expr {
183 g_lingo->code1(g_lingo->c_swap);
184 g_lingo->code1(g_lingo->c_theentityassign);
185 inst e = 0, f = 0;
186 WRITE_UINT32(&e, $2[0]);
187 WRITE_UINT32(&f, $2[1]);
188 g_lingo->code2(e, f);
189 $$ = $5; }
190 ;
191
192 stmtoneliner: expr
193 | proc
194 ;
195
196 stmt: stmtoneliner
197 | ifstmt
198 // repeat while (expression = TRUE)
199 // statements
200 // end repeat
201 //
202 | repeatwhile '(' cond ')' stmtlist end ENDCLAUSE {
203 inst body = 0, end = 0;
204 WRITE_UINT32(&body, $5 - $1);
205 WRITE_UINT32(&end, $6 - $1);
206 (*g_lingo->_currentScript)[$1 + 1] = body; /* body of loop */
207 (*g_lingo->_currentScript)[$1 + 2] = end; /* end, if cond fails */
208
209 checkEnd($7, "repeat", true); }
210 ;
211 // repeat with index = start to end
212 // statements
213 // end repeat
214 //
215 | repeatwith '=' expr end tTO expr end stmtlist end ENDCLAUSE {
216 inst init = 0, finish = 0, body = 0, end = 0, inc = 0;
217 WRITE_UINT32(&init, $3 - $1);
218 WRITE_UINT32(&finish, $6 - $1);
219 WRITE_UINT32(&body, $8 - $1);
220 WRITE_UINT32(&end, $9 - $1);
221 WRITE_UINT32(&inc, 1);
222 (*g_lingo->_currentScript)[$1 + 1] = init; /* initial count value */
223 (*g_lingo->_currentScript)[$1 + 2] = finish;/* final count value */
224 (*g_lingo->_currentScript)[$1 + 3] = body; /* body of loop */
225 (*g_lingo->_currentScript)[$1 + 4] = inc; /* increment */
226 (*g_lingo->_currentScript)[$1 + 5] = end; /* end, if cond fails */
227
228 checkEnd($10, "repeat", true); }
229 // repeat with index = high down to low
230 // statements
231 // end repeat
232 //
233 | repeatwith '=' expr end tDOWN tTO expr end stmtlist end ENDCLAUSE {
234 inst init = 0, finish = 0, body = 0, end = 0, inc = 0;
235 WRITE_UINT32(&init, $3 - $1);
236 WRITE_UINT32(&finish, $7 - $1);
237 WRITE_UINT32(&body, $9 - $1);
238 WRITE_UINT32(&end, $10 - $1);
239 WRITE_UINT32(&inc, -1);
240 (*g_lingo->_currentScript)[$1 + 1] = init; /* initial count value */
241 (*g_lingo->_currentScript)[$1 + 2] = finish;/* final count value */
242 (*g_lingo->_currentScript)[$1 + 3] = body; /* body of loop */
243 (*g_lingo->_currentScript)[$1 + 4] = inc; /* increment */
244 (*g_lingo->_currentScript)[$1 + 5] = end; /* end, if cond fails */
245
246 checkEnd($11, "repeat", true); }
247 | when stmtoneliner end {
248 inst end = 0;
249 WRITE_UINT32(&end, $3 - $1);
250 g_lingo->code1(STOP);
251 (*g_lingo->_currentScript)[$1 + 1] = end;
252 }
253 | tell expr nl stmtlist end ENDCLAUSE {
254 warning("STUB: TELL is not implemented");
255 checkEnd($6, "tell", true); }
256 | tell expr tTO expr {
257 warning("STUB: TELL is not implemented");
258 }
259 ;
260
261 ifstmt: if cond tTHENNL stmtlist end ENDCLAUSE {
262 inst then = 0, end = 0;
263 WRITE_UINT32(&then, $4 - $1);
264 WRITE_UINT32(&end, $5 - $1);
265 (*g_lingo->_currentScript)[$1 + 1] = then; /* thenpart */
266 (*g_lingo->_currentScript)[$1 + 3] = end; /* end, if cond fails */
267
268 checkEnd($6, "if", true);
269
270 g_lingo->processIf(0, 0); }
271 | if cond tTHENNL stmtlist end tNLELSE stmtlist end ENDCLAUSE {
272 inst then = 0, else1 = 0, end = 0;
273 WRITE_UINT32(&then, $4 - $1);
274 WRITE_UINT32(&else1, $7 - $1);
275 WRITE_UINT32(&end, $8 - $1);
276 (*g_lingo->_currentScript)[$1 + 1] = then; /* thenpart */
277 (*g_lingo->_currentScript)[$1 + 2] = else1; /* elsepart */
278 (*g_lingo->_currentScript)[$1 + 3] = end; /* end, if cond fails */
279
280 checkEnd($9, "if", true);
281
282 g_lingo->processIf(0, 0); }
283 | if cond tTHENNL stmtlist end begin elseifstmt end ENDCLAUSE {
284 inst then = 0, else1 = 0, end = 0;
285 WRITE_UINT32(&then, $4 - $1);
286 WRITE_UINT32(&else1, $6 - $1);
287 WRITE_UINT32(&end, $8 - $1);
288 (*g_lingo->_currentScript)[$1 + 1] = then; /* thenpart */
289 (*g_lingo->_currentScript)[$1 + 2] = else1; /* elsepart */
290 (*g_lingo->_currentScript)[$1 + 3] = end; /* end, if cond fails */
291
292 checkEnd($9, "if", true);
293
294 g_lingo->processIf(0, $8 - $1); }
295 | if cond tTHENNL stmtlist end tNLELSE begin stmtoneliner end {
296 inst then = 0, else1 = 0, end = 0;
297 WRITE_UINT32(&then, $4 - $1);
298 WRITE_UINT32(&else1, $7 - $1);
299 WRITE_UINT32(&end, $9 - $1);
300 (*g_lingo->_currentScript)[$1 + 1] = then; /* thenpart */
301 (*g_lingo->_currentScript)[$1 + 2] = else1; /* elsepart */
302 (*g_lingo->_currentScript)[$1 + 3] = end; /* end, if cond fails */
303
304 g_lingo->processIf(0, $9 - $1); }
305 | if cond tTHEN begin stmtoneliner end {
306 inst then = 0, else1 = 0, end = 0;
307 WRITE_UINT32(&then, $4 - $1);
308 WRITE_UINT32(&else1, 0);
309 WRITE_UINT32(&end, $6 - $1);
310 (*g_lingo->_currentScript)[$1 + 1] = then; /* thenpart */
311 (*g_lingo->_currentScript)[$1 + 2] = else1; /* elsepart */
312 (*g_lingo->_currentScript)[$1 + 3] = end; /* end, if cond fails */
313
314 g_lingo->processIf(0, 0); }
315 | if cond tTHEN begin stmtoneliner end tNLELSE begin stmtoneliner end {
316 inst then = 0, else1 = 0, end = 0;
317 WRITE_UINT32(&then, $4 - $1);
318 WRITE_UINT32(&else1, $8 - $1);
319 WRITE_UINT32(&end, $10 - $1);
320 (*g_lingo->_currentScript)[$1 + 1] = then; /* thenpart */
321 (*g_lingo->_currentScript)[$1 + 2] = else1; /* elsepart */
322 (*g_lingo->_currentScript)[$1 + 3] = end; /* end, if cond fails */
323
324 g_lingo->processIf(0, 0); }
325 | if cond tTHEN begin stmtoneliner end elseifstmtoneliner end elsestmtoneliner end {
326 inst then = 0, else1 = 0, end = 0;
327 WRITE_UINT32(&then, $4 - $1);
328 WRITE_UINT32(&else1, $6 - $1);
329 WRITE_UINT32(&end, $10 - $1);
330 (*g_lingo->_currentScript)[$1 + 1] = then; /* thenpart */
331 (*g_lingo->_currentScript)[$1 + 2] = else1; /* elsepart */
332 (*g_lingo->_currentScript)[$1 + 3] = end; /* end, if cond fails */
333
334 g_lingo->processIf(0, $10 - $1); }
335 ;
336
337 elsestmtoneliner: /* nothing */ { $$ = 0; }
338 | tNLELSE begin stmtoneliner { $$ = $2; }
339 ;
340
341 elseifstmt: elseifstmt elseifstmt1
342 | elseifstmt1
343 ;
344
345 elseifstmtoneliner: elseifstmtoneliner elseifstmtoneliner1
346 | elseifstmtoneliner1
347 ;
348
349 elseifstmtoneliner1: elseif cond tTHEN begin stmt end {
350 inst then = 0;
351 WRITE_UINT32(&then, $4 - $1);
352 (*g_lingo->_currentScript)[$1 + 1] = then; /* thenpart */
353
354 g_lingo->codeLabel($1); }
355 ;
356
357 elseifstmt1: elseifstmtoneliner
358 | elseif cond tTHEN begin stmtlist end {
359 inst then = 0;
360 WRITE_UINT32(&then, $5 - $1);
361 (*g_lingo->_currentScript)[$1 + 1] = then; /* thenpart */
362
363 g_lingo->codeLabel($1); }
364 ;
365
366 cond: expr { g_lingo->code1(STOP); }
367 | expr '=' expr { g_lingo->code2(g_lingo->c_eq, STOP); }
368 | '(' cond ')'
369 ;
370
371 repeatwhile: tREPEAT tWHILE { $$ = g_lingo->code3(g_lingo->c_repeatwhilecode, STOP, STOP); }
372 ;
373
374 repeatwith: tREPEAT tWITH ID {
375 $$ = g_lingo->code3(g_lingo->c_repeatwithcode, STOP, STOP);
376 g_lingo->code3(STOP, STOP, STOP);
377 g_lingo->codeString($3->c_str());
378 delete $3; }
379 ;
380
381 if: tIF {
382 $$ = g_lingo->code1(g_lingo->c_ifcode);
383 g_lingo->code3(STOP, STOP, STOP);
384 g_lingo->code1(0); // Do not skip end
385 g_lingo->codeLabel(0); } // Mark beginning of the if() statement
386 ;
387
388 elseif: tNLELSIF {
389 inst skipEnd;
390 WRITE_UINT32(&skipEnd, 1); // We have to skip end to avoid multiple executions
391 $$ = g_lingo->code1(g_lingo->c_ifcode);
392 g_lingo->code3(STOP, STOP, STOP);
393 g_lingo->code1(skipEnd); }
394 ;
395
396 begin: /* nothing */ { $$ = g_lingo->_currentScript->size(); }
397 ;
398
399 end: /* nothing */ { g_lingo->code1(STOP); $$ = g_lingo->_currentScript->size(); }
400 ;
401
402 stmtlist: /* nothing */ { $$ = g_lingo->_currentScript->size(); }
403 | stmtlist nl
404 | stmtlist stmt
405 ;
406
407 when: tWHEN ID tTHEN {
408 $$ = g_lingo->code1(g_lingo->c_whencode);
409 g_lingo->code1(STOP);
410 g_lingo->codeString($2->c_str());
411 delete $2; }
412
413 tell: tTELL {
414 $$ = g_lingo->code1(g_lingo->c_tellcode);
415 g_lingo->code1(STOP); }
416
417 expr: INT { $$ = g_lingo->codeConst($1); }
418 | FLOAT {
419 $$ = g_lingo->code1(g_lingo->c_fconstpush);
420 g_lingo->codeFloat($1); }
421 | SYMBOL { // D3
422 $$ = g_lingo->code1(g_lingo->c_symbolpush);
423 g_lingo->codeString($1->c_str()); }
424 | STRING {
425 $$ = g_lingo->code1(g_lingo->c_stringpush);
426 g_lingo->codeString($1->c_str()); }
427 | FBLTINNOARGS {
428 g_lingo->codeFunc($1, 0);
429 delete $1; }
430 | FBLTINONEARG expr {
431 g_lingo->codeFunc($1, 1);
432 delete $1; }
433 | FBLTINARGLIST nonemptyarglist { g_lingo->codeFunc($1, $2); }
434 | FBLTINARGLIST '(' nonemptyarglist ')' { g_lingo->codeFunc($1, $3); }
435 | ID '(' arglist ')' {
436 $$ = g_lingo->codeFunc($1, $3);
437 delete $1; }
438 | ID {
439 $$ = g_lingo->code1(g_lingo->c_eval);
440 g_lingo->codeString($1->c_str());
441 delete $1; }
442 | THEENTITY {
443 $$ = g_lingo->codeConst(0); // Put dummy id
444 g_lingo->code1(g_lingo->c_theentitypush);
445 inst e = 0, f = 0;
446 WRITE_UINT32(&e, $1[0]);
447 WRITE_UINT32(&f, $1[1]);
448 g_lingo->code2(e, f); }
449 | THEENTITYWITHID expr {
450 $$ = g_lingo->code1(g_lingo->c_theentitypush);
451 inst e = 0, f = 0;
452 WRITE_UINT32(&e, $1[0]);
453 WRITE_UINT32(&f, $1[1]);
454 g_lingo->code2(e, f); }
455 | asgn
456 | expr '+' expr { g_lingo->code1(g_lingo->c_add); }
457 | expr '-' expr { g_lingo->code1(g_lingo->c_sub); }
458 | expr '*' expr { g_lingo->code1(g_lingo->c_mul); }
459 | expr '/' expr { g_lingo->code1(g_lingo->c_div); }
460 | expr tMOD expr { g_lingo->code1(g_lingo->c_mod); }
461 | expr '>' expr { g_lingo->code1(g_lingo->c_gt); }
462 | expr '<' expr { g_lingo->code1(g_lingo->c_lt); }
463 | expr tNEQ expr { g_lingo->code1(g_lingo->c_neq); }
464 | expr tGE expr { g_lingo->code1(g_lingo->c_ge); }
465 | expr tLE expr { g_lingo->code1(g_lingo->c_le); }
466 | expr tAND expr { g_lingo->code1(g_lingo->c_and); }
467 | expr tOR expr { g_lingo->code1(g_lingo->c_or); }
468 | tNOT expr %prec UNARY { g_lingo->code1(g_lingo->c_not); }
469 | expr '&' expr { g_lingo->code1(g_lingo->c_ampersand); }
470 | expr tCONCAT expr { g_lingo->code1(g_lingo->c_concat); }
471 | expr tCONTAINS expr { g_lingo->code1(g_lingo->c_contains); }
472 | expr tSTARTS expr { g_lingo->code1(g_lingo->c_starts); }
473 | '+' expr %prec UNARY { $$ = $2; }
474 | '-' expr %prec UNARY { $$ = $2; g_lingo->code1(g_lingo->c_negate); }
475 | '(' expr ')' { $$ = $2; }
476 | '[' arglist ']' { $$ = g_lingo->codeArray($2); }
477 | tSPRITE expr tINTERSECTS expr { g_lingo->code1(g_lingo->c_intersects); }
478 | tSPRITE expr tWITHIN expr { g_lingo->code1(g_lingo->c_within); }
479 | tCHAR expr tOF expr { g_lingo->code1(g_lingo->c_charOf); }
480 | tCHAR expr tTO expr tOF expr { g_lingo->code1(g_lingo->c_charToOf); }
481 | tITEM expr tOF expr { g_lingo->code1(g_lingo->c_itemOf); }
482 | tITEM expr tTO expr tOF expr { g_lingo->code1(g_lingo->c_itemToOf); }
483 | tLINE expr tOF expr { g_lingo->code1(g_lingo->c_lineOf); }
484 | tLINE expr tTO expr tOF expr { g_lingo->code1(g_lingo->c_lineToOf); }
485 | tWORD expr tOF expr { g_lingo->code1(g_lingo->c_wordOf); }
486 | tWORD expr tTO expr tOF expr { g_lingo->code1(g_lingo->c_wordToOf); }
487 ;
488
489 reference: RBLTINONEARG expr {
490 g_lingo->codeFunc($1, 1);
491 delete $1; }
492 ;
493
494 proc: tPUT expr { g_lingo->code1(g_lingo->c_printtop); }
495 | gotofunc
496 | playfunc
497 | tEXIT tREPEAT { g_lingo->code1(g_lingo->c_exitRepeat); }
498 | tEXIT { g_lingo->code1(g_lingo->c_procret); }
499 | tGLOBAL globallist
500 | tPROPERTY propertylist
501 | tINSTANCE instancelist
502 | BLTINNOARGS {
503 g_lingo->codeFunc($1, 0);
504 delete $1; }
505 | BLTINONEARG expr {
506 g_lingo->codeFunc($1, 1);
507 delete $1; }
508 | BLTINNOARGSORONE expr {
509 g_lingo->codeFunc($1, 1);
510 delete $1; }
511 | BLTINNOARGSORONE {
512 g_lingo->code1(g_lingo->c_voidpush);
513 g_lingo->codeFunc($1, 1);
514 delete $1; }
515 | BLTINARGLIST nonemptyarglist { g_lingo->codeFunc($1, $2); }
516 | BLTINARGLIST '(' nonemptyarglist ')' { g_lingo->codeFunc($1, $3); }
517 | tME '(' ID ')' { g_lingo->codeMe($3, 0); }
518 | tME '(' ID ',' arglist ')' { g_lingo->codeMe($3, $5); }
519 | tOPEN expr tWITH expr { g_lingo->code1(g_lingo->c_open); }
520 | tOPEN expr { g_lingo->code2(g_lingo->c_voidpush, g_lingo->c_open); }
521 | TWOWORDBUILTIN ID arglist { Common::String s(*$1); s += '-'; s += *$2; g_lingo->codeFunc(&s, $3); }
522 ;
523
524 globallist: ID { g_lingo->code1(g_lingo->c_global); g_lingo->codeString($1->c_str()); delete $1; }
525 | globallist ',' ID { g_lingo->code1(g_lingo->c_global); g_lingo->codeString($3->c_str()); delete $3; }
526 ;
527
528 propertylist: ID { g_lingo->code1(g_lingo->c_property); g_lingo->codeString($1->c_str()); delete $1; }
529 | propertylist ',' ID { g_lingo->code1(g_lingo->c_property); g_lingo->codeString($3->c_str()); delete $3; }
530 ;
531
532 instancelist: ID { g_lingo->code1(g_lingo->c_instance); g_lingo->codeString($1->c_str()); delete $1; }
533 | instancelist ',' ID { g_lingo->code1(g_lingo->c_instance); g_lingo->codeString($3->c_str()); delete $3; }
534 ;
535
536 // go {to} {frame} whichFrame {of movie whichMovie}
537 // go {to} {frame "Open23" of} movie whichMovie
538 // go loop
539 // go next
540 // go previous
541 // go to {frame} whichFrame {of movie whichMovie}
542 // go to {frame whichFrame of} movie whichMovie
543
544 gotofunc: tGO tLOOP { g_lingo->code1(g_lingo->c_gotoloop); }
545 | tGO tNEXT { g_lingo->code1(g_lingo->c_gotonext); }
546 | tGO tPREVIOUS { g_lingo->code1(g_lingo->c_gotoprevious); }
547 | tGO gotoframe {
548 g_lingo->codeConst(1);
549 g_lingo->code1(g_lingo->c_goto); }
550 | tGO gotoframe gotomovie {
551 g_lingo->codeConst(3);
552 g_lingo->code1(g_lingo->c_goto); }
553 | tGO gotomovie {
554 g_lingo->codeConst(2);
555 g_lingo->code1(g_lingo->c_goto); }
556 ;
557
558 gotoframe: tFRAME expr
559 | expr
560 ;
561
562 gotomovie: tOF tMOVIE expr
563 | tMOVIE expr
564 ;
565
566 playfunc: tPLAY tDONE { g_lingo->code1(g_lingo->c_playdone); }
567 | tPLAY gotoframe {
568 g_lingo->codeConst(1);
569 g_lingo->code1(g_lingo->c_play); }
570 | tPLAY gotoframe gotomovie {
571 g_lingo->codeConst(3);
572 g_lingo->code1(g_lingo->c_play); }
573 | tPLAY gotomovie {
574 g_lingo->codeConst(2);
575 g_lingo->code1(g_lingo->c_play); }
576 | tPLAYACCEL { g_lingo->codeSetImmediate(true); } arglist {
577 g_lingo->codeSetImmediate(false);
578 g_lingo->codeFunc($1, $3); }
579 ;
580
581 // macro
582 //
583 // Special Note The macro keyword is retained in Director 3.0 to maintain compatibility
584 // with scripts developed under Version 2.0. When writing new scripts, or editing old
585 // scripts, you should use handlers instead of macros. (Handlers are defined with the on keyword.)
586 //
587 // Syntax:
588 //
589 // -- [comment]
590 // macro macroName [argument1] [, argument2]
591 // [, argument3]
592 // [statement1]
593 // [statement2]
594 //
595 // Keyword. Defines a macro. A macro is a multiple-line script defined
596 // in the Text window. Macros can accept arguments (inputs) and
597 // optionally return a result. Macros can call other macros and can be
598 // called from any other script or factory.
599 //
600 // The first line of a castmember in the Text window that contains a macro must be
601 // a comment (--). You can define more than one macro in a given text castmember.
602 // The macro definition ends where the next macro (or factory) begins.
603 //
604 // See also:
605 // on keyword
606 defn: tMACRO ID { g_lingo->_indef = true; g_lingo->_currentFactory.clear(); }
607 begin argdef nl argstore stmtlist {
608 g_lingo->code1(g_lingo->c_procret);
609 g_lingo->define(*$2, $4, $5);
610 g_lingo->_indef = false; }
611 | tFACTORY ID {
612 g_lingo->codeFactory(*$2);
613 }
614 | tMETHOD ID { g_lingo->_indef = true; }
615 begin argdef nl argstore stmtlist {
616 g_lingo->code1(g_lingo->c_procret);
617 g_lingo->define(*$2, $4, $5 + 1, &g_lingo->_currentFactory);
618 g_lingo->_indef = false; } ;
619 | on begin argdef nl argstore stmtlist ENDCLAUSE { // D3
620 g_lingo->code1(g_lingo->c_procret);
621 g_lingo->define(*$1, $2, $3);
622 g_lingo->_indef = false;
623 g_lingo->_ignoreMe = false;
624
625 checkEnd($7, $1->c_str(), false);
626 }
627 | on begin argdef nl argstore stmtlist { // D4. No 'end' clause
628 g_lingo->code1(g_lingo->c_procret);
629 g_lingo->define(*$1, $2, $3);
630 g_lingo->_indef = false;
631 g_lingo->_ignoreMe = false;
632 }
633
634 on: tON ID { $$ = $2; g_lingo->_indef = true; g_lingo->_currentFactory.clear(); g_lingo->_ignoreMe = true; }
635
636 argdef: /* nothing */ { $$ = 0; }
637 | ID { g_lingo->codeArg($1); $$ = 1; }
638 | argdef ',' ID { g_lingo->codeArg($3); $$ = $1 + 1; }
639 | argdef nl ',' ID { g_lingo->codeArg($4); $$ = $1 + 1; }
640 ;
641
642 argstore: /* nothing */ { g_lingo->codeArgStore(); }
643 ;
644
645
646 macro: ID nonemptyarglist {
647 g_lingo->code1(g_lingo->c_call);
648 g_lingo->codeString($1->c_str());
649 inst numpar = 0;
650 WRITE_UINT32(&numpar, $2);
651 g_lingo->code1(numpar); }
652 ;
653
654 arglist: /* nothing */ { $$ = 0; }
655 | expr { $$ = 1; }
656 | arglist ',' expr { $$ = $1 + 1; }
657 ;
658
659 nonemptyarglist: expr { $$ = 1; }
660 | nonemptyarglist ',' expr { $$ = $1 + 1; }
661 ;
662
663 %%
664