199 |
199 |
200 // Get the name of the label |
200 // Get the name of the label |
201 MustNext (); |
201 MustNext (); |
202 |
202 |
203 // Find the mark this goto statement points to |
203 // Find the mark this goto statement points to |
|
204 // TODO: This should define the mark instead of bombing |
|
205 // out if the mark isn't found! |
204 unsigned int m = w->FindMark (token); |
206 unsigned int m = w->FindMark (token); |
205 if (m == MAX_MARKS) |
207 if (m == MAX_MARKS) |
206 ParserError ("unknown label `%s`!", token.chars()); |
208 ParserError ("unknown label `%s`!", token.chars()); |
207 |
209 |
208 // Add a reference to the mark. |
210 // Add a reference to the mark. |
328 MUST_NOT_TOPLEVEL |
332 MUST_NOT_TOPLEVEL |
329 PushBlockStack (); |
333 PushBlockStack (); |
330 MustNext ("{"); |
334 MustNext ("{"); |
331 blockstack[g_BlockStackCursor].mark1 = w->AddMark (""); |
335 blockstack[g_BlockStackCursor].mark1 = w->AddMark (""); |
332 blockstack[g_BlockStackCursor].type = BLOCKTYPE_DO; |
336 blockstack[g_BlockStackCursor].type = BLOCKTYPE_DO; |
|
337 continue; |
|
338 } |
|
339 |
|
340 // ============================================================ |
|
341 // Switch |
|
342 if (!token.icompare ("switch")) { |
|
343 /* This goes a bit tricky. switch is structured in the |
|
344 * bytecode followingly: |
|
345 * (expression) |
|
346 * case a: goto casemark1 |
|
347 * case b: goto casemark2 |
|
348 * case c: goto casemark3 |
|
349 * goto mark1 // jump to end if no matches |
|
350 * casemark1: ... |
|
351 * casemark2: ... |
|
352 * casemark3: ... |
|
353 * mark1: // end mark |
|
354 */ |
|
355 |
|
356 MUST_NOT_TOPLEVEL |
|
357 PushBlockStack (); |
|
358 MustNext ("("); |
|
359 MustNext (); |
|
360 w->WriteBuffer (ParseExpression (TYPE_INT)); |
|
361 MustNext (")"); |
|
362 MustNext ("{"); |
|
363 blockstack[g_BlockStackCursor].type = BLOCKTYPE_SWITCH; |
|
364 blockstack[g_BlockStackCursor].mark1 = w->AddMark (""); // end mark |
|
365 continue; |
|
366 } |
|
367 |
|
368 // ============================================================ |
|
369 if (!token.icompare ("case")) { |
|
370 // case is only allowed inside switch |
|
371 if (g_BlockStackCursor <= 0 || blockstack[g_BlockStackCursor].type != BLOCKTYPE_SWITCH) |
|
372 ParserError ("`case` outside switch"); |
|
373 |
|
374 BlockInformation* info = &blockstack[g_BlockStackCursor]; |
|
375 info->casecursor++; |
|
376 if (info->casecursor >= MAX_CASE) |
|
377 ParserError ("too many `case` statements in one switch"); |
|
378 |
|
379 // Get the literal (Zandronum does not support expressions here) |
|
380 MustNumber (); |
|
381 int num = atoi (token.chars ()); |
|
382 |
|
383 MustNext (":"); |
|
384 |
|
385 // Init a mark for the case buffer |
|
386 int m = w->AddMark (""); |
|
387 info->casemarks[info->casecursor] = m; |
|
388 |
|
389 // Write down the expression and case-go-to. This builds |
|
390 // the case tree. The closing event will write the actual |
|
391 // blocks and move the marks appropriately. |
|
392 info->casebuffers[info->casecursor] = w->RecordBuffer = NULL; |
|
393 w->Write<word> (DH_CASEGOTO); |
|
394 w->Write<word> (num); |
|
395 w->AddReference (m); |
|
396 |
|
397 // Init a buffer for the case block, tell the object |
|
398 // writer to record all written data to it. |
|
399 info->casebuffers[info->casecursor] = w->RecordBuffer = new DataBuffer; |
|
400 continue; |
|
401 } |
|
402 |
|
403 // ============================================================ |
|
404 // Break statement. |
|
405 if (!token.icompare ("break")) { |
|
406 if (!g_BlockStackCursor) |
|
407 ParserError ("unexpected `break`"); |
|
408 |
|
409 BlockInformation* info = &blockstack[g_BlockStackCursor]; |
|
410 |
|
411 w->Write<word> (DH_GOTO); |
|
412 |
|
413 // switch and if use mark1 for the closing point, |
|
414 // for and while use mark2. |
|
415 switch (info->type) { |
|
416 case BLOCKTYPE_IF: |
|
417 case BLOCKTYPE_SWITCH: |
|
418 w->AddReference (info->mark1); |
|
419 break; |
|
420 case BLOCKTYPE_FOR: |
|
421 case BLOCKTYPE_WHILE: |
|
422 w->AddReference (info->mark2); |
|
423 break; |
|
424 default: |
|
425 ParserError ("unexpected `break`"); |
|
426 break; |
|
427 } |
|
428 |
|
429 MustNext (";"); |
333 continue; |
430 continue; |
334 } |
431 } |
335 |
432 |
336 // ============================================================ |
433 // ============================================================ |
337 if (!token.compare ("}")) { |
434 if (!token.compare ("}")) { |
368 // If the condition runs true, go back to the start. |
465 // If the condition runs true, go back to the start. |
369 w->WriteBuffer (expr); |
466 w->WriteBuffer (expr); |
370 w->Write<long> (DH_IFGOTO); |
467 w->Write<long> (DH_IFGOTO); |
371 w->AddReference (info->mark1); |
468 w->AddReference (info->mark1); |
372 break; |
469 break; |
|
470 } |
|
471 |
|
472 case BLOCKTYPE_SWITCH: { |
|
473 // Switch closes. Move down to the record buffer of |
|
474 // the lower block. |
|
475 BlockInformation* previnfo = &blockstack[g_BlockStackCursor - 1]; |
|
476 if (previnfo->casecursor != -1) |
|
477 w->RecordBuffer = previnfo->casebuffers[previnfo->casecursor]; |
|
478 else |
|
479 w->RecordBuffer = NULL; |
|
480 |
|
481 // Go through all of the buffers we |
|
482 // recorded down and write them. |
|
483 for (unsigned int u = 0; u < MAX_CASE; u++) { |
|
484 if (!info->casebuffers[u]) |
|
485 continue; |
|
486 |
|
487 w->MoveMark (info->casemarks[u]); |
|
488 w->WriteBuffer (info->casebuffers[u]); |
|
489 } |
|
490 |
|
491 // Move the closing mark here |
|
492 w->MoveMark (info->mark1); |
|
493 } |
373 } |
494 } |
374 |
495 |
375 // Descend down the stack |
496 // Descend down the stack |
376 g_BlockStackCursor--; |
497 g_BlockStackCursor--; |
377 continue; |
498 continue; |
691 BlockInformation* info = &blockstack[g_BlockStackCursor]; |
812 BlockInformation* info = &blockstack[g_BlockStackCursor]; |
692 info->type = 0; |
813 info->type = 0; |
693 info->mark1 = 0; |
814 info->mark1 = 0; |
694 info->mark2 = 0; |
815 info->mark2 = 0; |
695 info->buffer1 = NULL; |
816 info->buffer1 = NULL; |
|
817 info->casecursor = -1; |
|
818 for (int i = 0; i < MAX_CASE; i++) { |
|
819 info->casemarks[i] = MAX_MARKS; |
|
820 info->casebuffers[i] = NULL; |
|
821 } |
696 } |
822 } |
697 |
823 |
698 DataBuffer* ScriptReader::ParseStatement (ObjWriter* w) { |
824 DataBuffer* ScriptReader::ParseStatement (ObjWriter* w) { |
699 // If it's a variable, expect assignment. |
825 // If it's a variable, expect assignment. |
700 if (ScriptVar* var = FindGlobalVariable (token)) { |
826 if (ScriptVar* var = FindGlobalVariable (token)) { |