55 ParserError ("%s-statements may only be defined at top level!", token.chars()); |
55 ParserError ("%s-statements may only be defined at top level!", token.chars()); |
56 |
56 |
57 #define MUST_NOT_TOPLEVEL if (g_CurMode == MODE_TOPLEVEL) \ |
57 #define MUST_NOT_TOPLEVEL if (g_CurMode == MODE_TOPLEVEL) \ |
58 ParserError ("%s-statements may not be defined at top level!", token.chars()); |
58 ParserError ("%s-statements may not be defined at top level!", token.chars()); |
59 |
59 |
60 #define SCOPE(n) blockstack[g_BlockStackCursor - n] |
60 #define SCOPE(n) scopestack[g_ScopeCursor - n] |
61 |
61 |
62 int g_NumStates = 0; |
62 int g_NumStates = 0; |
63 int g_NumEvents = 0; |
63 int g_NumEvents = 0; |
64 int g_CurMode = MODE_TOPLEVEL; |
64 int g_CurMode = MODE_TOPLEVEL; |
65 str g_CurState = ""; |
65 str g_CurState = ""; |
66 bool g_stateSpawnDefined = false; |
66 bool g_stateSpawnDefined = false; |
67 bool g_GotMainLoop = false; |
67 bool g_GotMainLoop = false; |
68 unsigned int g_BlockStackCursor = 0; |
68 unsigned int g_ScopeCursor = 0; |
69 DataBuffer* g_IfExpression = NULL; |
69 DataBuffer* g_IfExpression = NULL; |
70 bool g_CanElse = false; |
70 bool g_CanElse = false; |
71 |
71 |
72 // ============================================================================ |
72 // ============================================================================ |
73 // Main parser code. Begins read of the script file, checks the syntax of it |
73 // Main parser code. Begins read of the script file, checks the syntax of it |
74 // and writes the data to the object file via ObjWriter - which also takes care |
74 // and writes the data to the object file via ObjWriter - which also takes care |
75 // of necessary buffering so stuff is written in the correct order. |
75 // of necessary buffering so stuff is written in the correct order. |
76 void ScriptReader::ParseBotScript (ObjWriter* w) { |
76 void ScriptReader::ParseBotScript (ObjWriter* w) { |
77 // Zero the entire block stack first |
77 // Zero the entire block stack first |
78 for (int i = 0; i < MAX_STRUCTSTACK; i++) |
78 for (int i = 0; i < MAX_STRUCTSTACK; i++) |
79 memset (&blockstack[i], 0, sizeof (BlockInformation)); |
79 memset (&scopestack[i], 0, sizeof (BlockInformation)); |
80 |
80 |
81 while (Next()) { |
81 while (Next()) { |
82 // Check if else is potentically valid |
82 // Check if else is potentically valid |
83 if (!token.compare ("else") && !g_CanElse) |
83 if (!token.compare ("else") && !g_CanElse) |
84 ParserError ("else without preceding if"); |
84 ParserError ("else without preceding if"); |
230 // Add a mark - to here temporarily - and add a reference to it. |
230 // Add a mark - to here temporarily - and add a reference to it. |
231 // Upon a closing brace, the mark will be adjusted. |
231 // Upon a closing brace, the mark will be adjusted. |
232 unsigned int marknum = w->AddMark (""); |
232 unsigned int marknum = w->AddMark (""); |
233 |
233 |
234 // Use DH_IFNOTGOTO - if the expression is not true, we goto the mark |
234 // Use DH_IFNOTGOTO - if the expression is not true, we goto the mark |
235 // we just defined - and this mark will be at the end of the block. |
235 // we just defined - and this mark will be at the end of the scope block. |
236 w->Write<word> (DH_IFNOTGOTO); |
236 w->Write<word> (DH_IFNOTGOTO); |
237 w->AddReference (marknum); |
237 w->AddReference (marknum); |
238 |
238 |
239 // Store it in the block stack |
239 // Store it |
240 SCOPE(0).mark1 = marknum; |
240 SCOPE(0).mark1 = marknum; |
241 SCOPE(0).type = BLOCKTYPE_IF; |
241 SCOPE(0).type = SCOPETYPE_IF; |
242 continue; |
242 continue; |
243 } |
243 } |
244 |
244 |
245 if (!token.compare ("else")) { |
245 if (!token.compare ("else")) { |
246 MUST_NOT_TOPLEVEL |
246 MUST_NOT_TOPLEVEL |
247 MustNext ("{"); |
247 MustNext ("{"); |
248 |
248 |
249 // Don't use PushBlockStack as that will reset the scope. |
249 // Don't use PushScope that will reset the scope. |
250 g_BlockStackCursor++; |
250 g_ScopeCursor++; |
251 if (g_BlockStackCursor >= MAX_STRUCTSTACK) |
251 if (g_ScopeCursor >= MAX_STRUCTSTACK) |
252 ParserError ("too deep scope"); |
252 ParserError ("too deep scope"); |
253 |
253 |
254 if (SCOPE(0).type != BLOCKTYPE_IF) |
254 if (SCOPE(0).type != SCOPETYPE_IF) |
255 ParserError ("else without preceding if"); |
255 ParserError ("else without preceding if"); |
256 |
256 |
257 // Write down to jump to the end of the else statement |
257 // Write down to jump to the end of the else statement |
258 // Otherwise we have fall-throughs |
258 // Otherwise we have fall-throughs |
259 SCOPE(0).mark2 = w->AddMark (""); |
259 SCOPE(0).mark2 = w->AddMark (""); |
262 w->Write (DH_GOTO); |
262 w->Write (DH_GOTO); |
263 w->AddReference (SCOPE(0).mark2); |
263 w->AddReference (SCOPE(0).mark2); |
264 |
264 |
265 // Move the ifnot mark here and set type to else |
265 // Move the ifnot mark here and set type to else |
266 w->MoveMark (SCOPE(0).mark1); |
266 w->MoveMark (SCOPE(0).mark1); |
267 SCOPE(0).type = BLOCKTYPE_ELSE; |
267 SCOPE(0).type = SCOPETYPE_ELSE; |
268 continue; |
268 continue; |
269 } |
269 } |
270 |
270 |
271 // ============================================================ |
271 // ============================================================ |
272 // While |
272 // While |
273 if (!token.compare ("while")) { |
273 if (!token.compare ("while")) { |
274 MUST_NOT_TOPLEVEL |
274 MUST_NOT_TOPLEVEL |
275 PushBlockStack (); |
275 PushScope (); |
276 |
276 |
277 // While loops need two marks - one at the start of the loop and one at the |
277 // While loops need two marks - one at the start of the loop and one at the |
278 // end. The condition is checked at the very start of the loop, if it fails, |
278 // end. The condition is checked at the very start of the loop, if it fails, |
279 // we use goto to skip to the end of the loop. At the end, we loop back to |
279 // we use goto to skip to the end of the loop. At the end, we loop back to |
280 // the beginning with a go-to statement. |
280 // the beginning with a go-to statement. |
296 w->AddReference (mark2); |
296 w->AddReference (mark2); |
297 |
297 |
298 // Store the needed stuff |
298 // Store the needed stuff |
299 SCOPE(0).mark1 = mark1; |
299 SCOPE(0).mark1 = mark1; |
300 SCOPE(0).mark2 = mark2; |
300 SCOPE(0).mark2 = mark2; |
301 SCOPE(0).type = BLOCKTYPE_WHILE; |
301 SCOPE(0).type = SCOPETYPE_WHILE; |
302 continue; |
302 continue; |
303 } |
303 } |
304 |
304 |
305 // ============================================================ |
305 // ============================================================ |
306 // For loop |
306 // For loop |
307 if (!token.compare ("for")) { |
307 if (!token.compare ("for")) { |
308 MUST_NOT_TOPLEVEL |
308 MUST_NOT_TOPLEVEL |
309 PushBlockStack (); |
309 PushScope (); |
310 |
310 |
311 // Initializer |
311 // Initializer |
312 MustNext ("("); |
312 MustNext ("("); |
313 MustNext (); |
313 MustNext (); |
314 DataBuffer* init = ParseStatement (w); |
314 DataBuffer* init = ParseStatement (w); |
339 |
339 |
340 // Store the marks and incrementor |
340 // Store the marks and incrementor |
341 SCOPE(0).mark1 = mark1; |
341 SCOPE(0).mark1 = mark1; |
342 SCOPE(0).mark2 = mark2; |
342 SCOPE(0).mark2 = mark2; |
343 SCOPE(0).buffer1 = incr; |
343 SCOPE(0).buffer1 = incr; |
344 SCOPE(0).type = BLOCKTYPE_FOR; |
344 SCOPE(0).type = SCOPETYPE_FOR; |
345 continue; |
345 continue; |
346 } |
346 } |
347 |
347 |
348 // ============================================================ |
348 // ============================================================ |
349 // Do/while loop |
349 // Do/while loop |
350 if (!token.compare ("do")) { |
350 if (!token.compare ("do")) { |
351 MUST_NOT_TOPLEVEL |
351 MUST_NOT_TOPLEVEL |
352 PushBlockStack (); |
352 PushScope (); |
353 MustNext ("{"); |
353 MustNext ("{"); |
354 SCOPE(0).mark1 = w->AddMark (""); |
354 SCOPE(0).mark1 = w->AddMark (""); |
355 SCOPE(0).type = BLOCKTYPE_DO; |
355 SCOPE(0).type = SCOPETYPE_DO; |
356 continue; |
356 continue; |
357 } |
357 } |
358 |
358 |
359 // ============================================================ |
359 // ============================================================ |
360 // Switch |
360 // Switch |
371 * casemark3: ... |
371 * casemark3: ... |
372 * mark1: // end mark |
372 * mark1: // end mark |
373 */ |
373 */ |
374 |
374 |
375 MUST_NOT_TOPLEVEL |
375 MUST_NOT_TOPLEVEL |
376 PushBlockStack (); |
376 PushScope (); |
377 MustNext ("("); |
377 MustNext ("("); |
378 MustNext (); |
378 MustNext (); |
379 w->WriteBuffer (ParseExpression (TYPE_INT)); |
379 w->WriteBuffer (ParseExpression (TYPE_INT)); |
380 MustNext (")"); |
380 MustNext (")"); |
381 MustNext ("{"); |
381 MustNext ("{"); |
382 SCOPE(0).type = BLOCKTYPE_SWITCH; |
382 SCOPE(0).type = SCOPETYPE_SWITCH; |
383 SCOPE(0).mark1 = w->AddMark (""); // end mark |
383 SCOPE(0).mark1 = w->AddMark (""); // end mark |
384 SCOPE(0).buffer1 = NULL; // default header |
384 SCOPE(0).buffer1 = NULL; // default header |
385 continue; |
385 continue; |
386 } |
386 } |
387 |
387 |
388 // ============================================================ |
388 // ============================================================ |
389 if (!token.compare ("case")) { |
389 if (!token.compare ("case")) { |
390 // case is only allowed inside switch |
390 // case is only allowed inside switch |
391 if (SCOPE(0).type != BLOCKTYPE_SWITCH) |
391 if (SCOPE(0).type != SCOPETYPE_SWITCH) |
392 ParserError ("case label outside switch"); |
392 ParserError ("case label outside switch"); |
393 |
393 |
394 // Get the literal (Zandronum does not support expressions here) |
394 // Get the literal (Zandronum does not support expressions here) |
395 MustNumber (); |
395 MustNumber (); |
396 int num = atoi (token.chars ()); |
396 int num = atoi (token.chars ()); |
415 SCOPE(0).casenumbers[SCOPE(0).casecursor] = num; |
415 SCOPE(0).casenumbers[SCOPE(0).casecursor] = num; |
416 continue; |
416 continue; |
417 } |
417 } |
418 |
418 |
419 if (!token.compare ("default")) { |
419 if (!token.compare ("default")) { |
420 if (SCOPE(0).type != BLOCKTYPE_SWITCH) |
420 if (SCOPE(0).type != SCOPETYPE_SWITCH) |
421 ParserError ("default label outside switch"); |
421 ParserError ("default label outside switch"); |
422 |
422 |
423 if (SCOPE(0).buffer1) |
423 if (SCOPE(0).buffer1) |
424 ParserError ("multiple default labels in one switch"); |
424 ParserError ("multiple default labels in one switch"); |
425 |
425 |
441 } |
441 } |
442 |
442 |
443 // ============================================================ |
443 // ============================================================ |
444 // Break statement. |
444 // Break statement. |
445 if (!token.compare ("break")) { |
445 if (!token.compare ("break")) { |
446 if (!g_BlockStackCursor) |
446 if (!g_ScopeCursor) |
447 ParserError ("unexpected `break`"); |
447 ParserError ("unexpected `break`"); |
448 |
448 |
449 w->Write<word> (DH_GOTO); |
449 w->Write<word> (DH_GOTO); |
450 |
450 |
451 // switch and if use mark1 for the closing point, |
451 // switch and if use mark1 for the closing point, |
452 // for and while use mark2. |
452 // for and while use mark2. |
453 switch (SCOPE(0).type) { |
453 switch (SCOPE(0).type) { |
454 case BLOCKTYPE_IF: |
454 case SCOPETYPE_IF: |
455 case BLOCKTYPE_SWITCH: |
455 case SCOPETYPE_SWITCH: |
456 w->AddReference (SCOPE(0).mark1); |
456 w->AddReference (SCOPE(0).mark1); |
457 break; |
457 break; |
458 case BLOCKTYPE_FOR: |
458 case SCOPETYPE_FOR: |
459 case BLOCKTYPE_WHILE: |
459 case SCOPETYPE_WHILE: |
460 w->AddReference (SCOPE(0).mark2); |
460 w->AddReference (SCOPE(0).mark2); |
461 break; |
461 break; |
462 default: |
462 default: |
463 ParserError ("unexpected `break`"); |
463 ParserError ("unexpected `break`"); |
464 break; |
464 break; |
488 // ============================================================ |
488 // ============================================================ |
489 if (!token.compare ("}")) { |
489 if (!token.compare ("}")) { |
490 // Closing brace |
490 // Closing brace |
491 |
491 |
492 // If we're in the block stack, we're descending down from it now |
492 // If we're in the block stack, we're descending down from it now |
493 if (g_BlockStackCursor > 0) { |
493 if (g_ScopeCursor > 0) { |
494 switch (SCOPE(0).type) { |
494 switch (SCOPE(0).type) { |
495 case BLOCKTYPE_IF: |
495 case SCOPETYPE_IF: |
496 // Adjust the closing mark. |
496 // Adjust the closing mark. |
497 w->MoveMark (SCOPE(0).mark1); |
497 w->MoveMark (SCOPE(0).mark1); |
498 |
498 |
499 // We're returning from if, thus else can be next |
499 // We're returning from if, thus else can be next |
500 g_CanElse = true; |
500 g_CanElse = true; |
501 break; |
501 break; |
502 case BLOCKTYPE_ELSE: |
502 case SCOPETYPE_ELSE: |
503 // else instead uses mark1 for itself (so if expression |
503 // else instead uses mark1 for itself (so if expression |
504 // fails, jump to else), mark2 means end of else |
504 // fails, jump to else), mark2 means end of else |
505 w->MoveMark (SCOPE(0).mark2); |
505 w->MoveMark (SCOPE(0).mark2); |
506 break; |
506 break; |
507 case BLOCKTYPE_FOR: |
507 case SCOPETYPE_FOR: |
508 // Write the incrementor at the end of the loop block |
508 // Write the incrementor at the end of the loop block |
509 w->WriteBuffer (SCOPE(0).buffer1); |
509 w->WriteBuffer (SCOPE(0).buffer1); |
510 // fall-thru |
510 // fall-thru |
511 case BLOCKTYPE_WHILE: |
511 case SCOPETYPE_WHILE: |
512 // Write down the instruction to go back to the start of the loop |
512 // Write down the instruction to go back to the start of the loop |
513 w->Write (DH_GOTO); |
513 w->Write (DH_GOTO); |
514 w->AddReference (SCOPE(0).mark1); |
514 w->AddReference (SCOPE(0).mark1); |
515 |
515 |
516 // Move the closing mark here since we're at the end of the while loop |
516 // Move the closing mark here since we're at the end of the while loop |
517 w->MoveMark (SCOPE(0).mark2); |
517 w->MoveMark (SCOPE(0).mark2); |
518 break; |
518 break; |
519 case BLOCKTYPE_DO: { |
519 case SCOPETYPE_DO: { |
520 MustNext ("while"); |
520 MustNext ("while"); |
521 MustNext ("("); |
521 MustNext ("("); |
522 MustNext (); |
522 MustNext (); |
523 DataBuffer* expr = ParseExpression (TYPE_INT); |
523 DataBuffer* expr = ParseExpression (TYPE_INT); |
524 MustNext (")"); |
524 MustNext (")"); |
528 w->WriteBuffer (expr); |
528 w->WriteBuffer (expr); |
529 w->Write<long> (DH_IFGOTO); |
529 w->Write<long> (DH_IFGOTO); |
530 w->AddReference (SCOPE(0).mark1); |
530 w->AddReference (SCOPE(0).mark1); |
531 break; |
531 break; |
532 } |
532 } |
533 case BLOCKTYPE_SWITCH: { |
533 case SCOPETYPE_SWITCH: { |
534 // Switch closes. Move down to the record buffer of |
534 // Switch closes. Move down to the record buffer of |
535 // the lower block. |
535 // the lower block. |
536 if (SCOPE(1).casecursor != -1) |
536 if (SCOPE(1).casecursor != -1) |
537 w->SwitchBuffer = SCOPE(1).casebuffers[SCOPE(1).casecursor]; |
537 w->SwitchBuffer = SCOPE(1).casebuffers[SCOPE(1).casecursor]; |
538 else |
538 else |