64 |
64 |
65 // ============================================================================ |
65 // ============================================================================ |
66 // |
66 // |
67 void BotscriptParser::CheckToplevel() |
67 void BotscriptParser::CheckToplevel() |
68 { |
68 { |
69 if (mCurrentMode != ETopLevelMode) |
69 if (mCurrentMode != PARSERMODE_TopLevel) |
70 Error ("%1-statements may only be defined at top level!", GetTokenString()); |
70 Error ("%1-statements may only be defined at top level!", GetTokenString()); |
71 } |
71 } |
72 |
72 |
73 // ============================================================================ |
73 // ============================================================================ |
74 // |
74 // |
75 void BotscriptParser::CheckNotToplevel() |
75 void BotscriptParser::CheckNotToplevel() |
76 { |
76 { |
77 if (mCurrentMode == ETopLevelMode) |
77 if (mCurrentMode == PARSERMODE_TopLevel) |
78 Error ("%1-statements must not be defined at top level!", GetTokenString()); |
78 Error ("%1-statements must not be defined at top level!", GetTokenString()); |
79 } |
79 } |
80 |
80 |
81 // ============================================================================ |
81 // ============================================================================ |
82 // |
82 // |
274 // write the previous state's onenter and |
274 // write the previous state's onenter and |
275 // mainloop buffers to file now |
275 // mainloop buffers to file now |
276 if (mCurrentState.IsEmpty() == false) |
276 if (mCurrentState.IsEmpty() == false) |
277 writeMemberBuffers(); |
277 writeMemberBuffers(); |
278 |
278 |
279 buffer()->WriteDWord (dhStateName); |
279 buffer()->WriteDWord (DH_StateName); |
280 buffer()->WriteString (statename); |
280 buffer()->WriteString (statename); |
281 buffer()->WriteDWord (dhStateIndex); |
281 buffer()->WriteDWord (DH_StateIndex); |
282 buffer()->WriteDWord (mNumStates); |
282 buffer()->WriteDWord (mNumStates); |
283 |
283 |
284 mNumStates++; |
284 mNumStates++; |
285 mCurrentState = statename; |
285 mCurrentState = statename; |
286 mGotMainLoop = false; |
286 mGotMainLoop = false; |
310 void BotscriptParser::ParseMainloop() |
310 void BotscriptParser::ParseMainloop() |
311 { |
311 { |
312 CheckToplevel(); |
312 CheckToplevel(); |
313 mLexer->MustGetNext (tkBraceStart); |
313 mLexer->MustGetNext (tkBraceStart); |
314 |
314 |
315 mCurrentMode = EMainLoopMode; |
315 mCurrentMode = PARSERMODE_MainLoop; |
316 mMainLoopBuffer->WriteDWord (dhMainLoop); |
316 mMainLoopBuffer->WriteDWord (DH_MainLoop); |
317 } |
317 } |
318 |
318 |
319 // ============================================================================ |
319 // ============================================================================ |
320 // |
320 // |
321 void BotscriptParser::ParseOnEnterExit() |
321 void BotscriptParser::ParseOnEnterExit() |
322 { |
322 { |
323 CheckToplevel(); |
323 CheckToplevel(); |
324 bool onenter = (TokenIs (tkOnenter)); |
324 bool onenter = (TokenIs (tkOnenter)); |
325 mLexer->MustGetNext (tkBraceStart); |
325 mLexer->MustGetNext (tkBraceStart); |
326 |
326 |
327 mCurrentMode = onenter ? EOnenterMode : EOnexitMode; |
327 mCurrentMode = onenter ? PARSERMODE_Onenter : PARSERMODE_Onexit; |
328 buffer()->WriteDWord (onenter ? dhOnEnter : dhOnExit); |
328 buffer()->WriteDWord (onenter ? DH_OnEnter : DH_OnExit); |
329 } |
329 } |
330 |
330 |
331 // ============================================================================ |
331 // ============================================================================ |
332 // |
332 // |
333 void BotscriptParser::ParseVar() |
333 void BotscriptParser::ParseVar() |
336 var->origin = mLexer->DescribeCurrentPosition(); |
336 var->origin = mLexer->DescribeCurrentPosition(); |
337 var->isarray = false; |
337 var->isarray = false; |
338 const bool isconst = mLexer->GetNext (tkConst); |
338 const bool isconst = mLexer->GetNext (tkConst); |
339 mLexer->MustGetAnyOf ({tkInt, tkStr, tkVoid}); |
339 mLexer->MustGetAnyOf ({tkInt, tkStr, tkVoid}); |
340 |
340 |
341 EType vartype = (TokenIs (tkInt)) ? EIntType : |
341 DataType vartype = (TokenIs (tkInt)) ? TYPE_Int : |
342 (TokenIs (tkStr)) ? EStringType : |
342 (TokenIs (tkStr)) ? TYPE_String : |
343 EBoolType; |
343 TYPE_Bool; |
344 |
344 |
345 mLexer->MustGetNext (tkSymbol); |
345 mLexer->MustGetNext (tkSymbol); |
346 String name = GetTokenString(); |
346 String name = GetTokenString(); |
347 |
347 |
348 if (mLexer->GetNext (tkBracketStart)) |
348 if (mLexer->GetNext (tkBracketStart)) |
365 var->statename = ""; |
365 var->statename = ""; |
366 var->type = vartype; |
366 var->type = vartype; |
367 |
367 |
368 if (isconst == false) |
368 if (isconst == false) |
369 { |
369 { |
370 var->writelevel = Variable::WRITE_Mutable; |
370 var->writelevel = WRITE_Mutable; |
371 } |
371 } |
372 else |
372 else |
373 { |
373 { |
374 mLexer->MustGetNext (tkAssign); |
374 mLexer->MustGetNext (tkAssign); |
375 Expression expr (this, mLexer, vartype); |
375 Expression expr (this, mLexer, vartype); |
376 |
376 |
377 // If the expression was constexpr, we know its value and thus |
377 // If the expression was constexpr, we know its value and thus |
378 // can store it in the variable. |
378 // can store it in the variable. |
379 if (expr.GetResult()->IsConstexpr()) |
379 if (expr.GetResult()->IsConstexpr()) |
380 { |
380 { |
381 var->writelevel = Variable::WRITE_Constexpr; |
381 var->writelevel = WRITE_Constexpr; |
382 var->value = expr.GetResult()->GetValue(); |
382 var->value = expr.GetResult()->GetValue(); |
383 } |
383 } |
384 else |
384 else |
385 { |
385 { |
386 // TODO: might need a VM-wise oninit for this... |
386 // TODO: might need a VM-wise oninit for this... |
450 |
450 |
451 // Condition |
451 // Condition |
452 mLexer->MustGetNext (tkParenStart); |
452 mLexer->MustGetNext (tkParenStart); |
453 |
453 |
454 // Read the expression and write it. |
454 // Read the expression and write it. |
455 DataBuffer* c = ParseExpression (EIntType); |
455 DataBuffer* c = ParseExpression (TYPE_Int); |
456 buffer()->MergeAndDestroy (c); |
456 buffer()->MergeAndDestroy (c); |
457 |
457 |
458 mLexer->MustGetNext (tkParenEnd); |
458 mLexer->MustGetNext (tkParenEnd); |
459 mLexer->MustGetNext (tkBraceStart); |
459 mLexer->MustGetNext (tkBraceStart); |
460 |
460 |
461 // Add a mark - to here temporarily - and add a reference to it. |
461 // Add a mark - to here temporarily - and add a reference to it. |
462 // Upon a closing brace, the mark will be adjusted. |
462 // Upon a closing brace, the mark will be adjusted. |
463 ByteMark* mark = buffer()->AddMark (""); |
463 ByteMark* mark = buffer()->AddMark (""); |
464 |
464 |
465 // Use dhIfNotGoto - if the expression is not true, we goto the mark |
465 // Use DH_IfNotGoto - if the expression is not true, we goto the mark |
466 // we just defined - and this mark will be at the end of the scope block. |
466 // we just defined - and this mark will be at the end of the scope block. |
467 buffer()->WriteDWord (dhIfNotGoto); |
467 buffer()->WriteDWord (DH_IfNotGoto); |
468 buffer()->AddReference (mark); |
468 buffer()->AddReference (mark); |
469 |
469 |
470 // Store it |
470 // Store it |
471 SCOPE (0).mark1 = mark; |
471 SCOPE (0).mark1 = mark; |
472 SCOPE (0).type = eIfScope; |
472 SCOPE (0).type = SCOPE_If; |
473 } |
473 } |
474 |
474 |
475 // ============================================================================ |
475 // ============================================================================ |
476 // |
476 // |
477 void BotscriptParser::ParseElse() |
477 void BotscriptParser::ParseElse() |
478 { |
478 { |
479 CheckNotToplevel(); |
479 CheckNotToplevel(); |
480 mLexer->MustGetNext (tkBraceStart); |
480 mLexer->MustGetNext (tkBraceStart); |
481 PushScope (eNoReset); |
481 PushScope (eNoReset); |
482 |
482 |
483 if (SCOPE (0).type != eIfScope) |
483 if (SCOPE (0).type != SCOPE_If) |
484 Error ("else without preceding if"); |
484 Error ("else without preceding if"); |
485 |
485 |
486 // write down to jump to the end of the else statement |
486 // write down to jump to the end of the else statement |
487 // Otherwise we have fall-throughs |
487 // Otherwise we have fall-throughs |
488 SCOPE (0).mark2 = buffer()->AddMark (""); |
488 SCOPE (0).mark2 = buffer()->AddMark (""); |
489 |
489 |
490 // Instruction to jump to the end after if block is complete |
490 // Instruction to jump to the end after if block is complete |
491 buffer()->WriteDWord (dhGoto); |
491 buffer()->WriteDWord (DH_Goto); |
492 buffer()->AddReference (SCOPE (0).mark2); |
492 buffer()->AddReference (SCOPE (0).mark2); |
493 |
493 |
494 // Move the ifnot mark here and set type to else |
494 // Move the ifnot mark here and set type to else |
495 buffer()->AdjustMark (SCOPE (0).mark1); |
495 buffer()->AdjustMark (SCOPE (0).mark1); |
496 SCOPE (0).type = eElseScope; |
496 SCOPE (0).type = SCOPE_Else; |
497 } |
497 } |
498 |
498 |
499 // ============================================================================ |
499 // ============================================================================ |
500 // |
500 // |
501 void BotscriptParser::ParseWhileBlock() |
501 void BotscriptParser::ParseWhileBlock() |
510 ByteMark* mark1 = buffer()->AddMark (""); // start |
510 ByteMark* mark1 = buffer()->AddMark (""); // start |
511 ByteMark* mark2 = buffer()->AddMark (""); // end |
511 ByteMark* mark2 = buffer()->AddMark (""); // end |
512 |
512 |
513 // Condition |
513 // Condition |
514 mLexer->MustGetNext (tkParenStart); |
514 mLexer->MustGetNext (tkParenStart); |
515 DataBuffer* expr = ParseExpression (EIntType); |
515 DataBuffer* expr = ParseExpression (TYPE_Int); |
516 mLexer->MustGetNext (tkParenEnd); |
516 mLexer->MustGetNext (tkParenEnd); |
517 mLexer->MustGetNext (tkBraceStart); |
517 mLexer->MustGetNext (tkBraceStart); |
518 |
518 |
519 // write condition |
519 // write condition |
520 buffer()->MergeAndDestroy (expr); |
520 buffer()->MergeAndDestroy (expr); |
521 |
521 |
522 // Instruction to go to the end if it fails |
522 // Instruction to go to the end if it fails |
523 buffer()->WriteDWord (dhIfNotGoto); |
523 buffer()->WriteDWord (DH_IfNotGoto); |
524 buffer()->AddReference (mark2); |
524 buffer()->AddReference (mark2); |
525 |
525 |
526 // Store the needed stuff |
526 // Store the needed stuff |
527 SCOPE (0).mark1 = mark1; |
527 SCOPE (0).mark1 = mark1; |
528 SCOPE (0).mark2 = mark2; |
528 SCOPE (0).mark2 = mark2; |
529 SCOPE (0).type = eWhileScope; |
529 SCOPE (0).type = SCOPE_While; |
530 } |
530 } |
531 |
531 |
532 // ============================================================================ |
532 // ============================================================================ |
533 // |
533 // |
534 void BotscriptParser::ParseForBlock() |
534 void BotscriptParser::ParseForBlock() |
569 ByteMark* mark1 = buffer()->AddMark (""); |
569 ByteMark* mark1 = buffer()->AddMark (""); |
570 ByteMark* mark2 = buffer()->AddMark (""); |
570 ByteMark* mark2 = buffer()->AddMark (""); |
571 |
571 |
572 // Add the condition |
572 // Add the condition |
573 buffer()->MergeAndDestroy (cond); |
573 buffer()->MergeAndDestroy (cond); |
574 buffer()->WriteDWord (dhIfNotGoto); |
574 buffer()->WriteDWord (DH_IfNotGoto); |
575 buffer()->AddReference (mark2); |
575 buffer()->AddReference (mark2); |
576 |
576 |
577 // Store the marks and incrementor |
577 // Store the marks and incrementor |
578 SCOPE (0).mark1 = mark1; |
578 SCOPE (0).mark1 = mark1; |
579 SCOPE (0).mark2 = mark2; |
579 SCOPE (0).mark2 = mark2; |
580 SCOPE (0).buffer1 = incr; |
580 SCOPE (0).buffer1 = incr; |
581 SCOPE (0).type = eForScope; |
581 SCOPE (0).type = SCOPE_For; |
582 } |
582 } |
583 |
583 |
584 // ============================================================================ |
584 // ============================================================================ |
585 // |
585 // |
586 void BotscriptParser::ParseDoBlock() |
586 void BotscriptParser::ParseDoBlock() |
587 { |
587 { |
588 CheckNotToplevel(); |
588 CheckNotToplevel(); |
589 PushScope(); |
589 PushScope(); |
590 mLexer->MustGetNext (tkBraceStart); |
590 mLexer->MustGetNext (tkBraceStart); |
591 SCOPE (0).mark1 = buffer()->AddMark (""); |
591 SCOPE (0).mark1 = buffer()->AddMark (""); |
592 SCOPE (0).type = eDoScope; |
592 SCOPE (0).type = SCOPE_Do; |
593 } |
593 } |
594 |
594 |
595 // ============================================================================ |
595 // ============================================================================ |
596 // |
596 // |
597 void BotscriptParser::ParseSwitchBlock() |
597 void BotscriptParser::ParseSwitchBlock() |
610 // mark1: // end mark |
610 // mark1: // end mark |
611 |
611 |
612 CheckNotToplevel(); |
612 CheckNotToplevel(); |
613 PushScope(); |
613 PushScope(); |
614 mLexer->MustGetNext (tkParenStart); |
614 mLexer->MustGetNext (tkParenStart); |
615 buffer()->MergeAndDestroy (ParseExpression (EIntType)); |
615 buffer()->MergeAndDestroy (ParseExpression (TYPE_Int)); |
616 mLexer->MustGetNext (tkParenEnd); |
616 mLexer->MustGetNext (tkParenEnd); |
617 mLexer->MustGetNext (tkBraceStart); |
617 mLexer->MustGetNext (tkBraceStart); |
618 SCOPE (0).type = eSwitchScope; |
618 SCOPE (0).type = SCOPE_Switch; |
619 SCOPE (0).mark1 = buffer()->AddMark (""); // end mark |
619 SCOPE (0).mark1 = buffer()->AddMark (""); // end mark |
620 SCOPE (0).buffer1 = null; // default header |
620 SCOPE (0).buffer1 = null; // default header |
621 } |
621 } |
622 |
622 |
623 // ============================================================================ |
623 // ============================================================================ |
624 // |
624 // |
625 void BotscriptParser::ParseSwitchCase() |
625 void BotscriptParser::ParseSwitchCase() |
626 { |
626 { |
627 // case is only allowed inside switch |
627 // case is only allowed inside switch |
628 if (SCOPE (0).type != eSwitchScope) |
628 if (SCOPE (0).type != SCOPE_Switch) |
629 Error ("case label outside switch"); |
629 Error ("case label outside switch"); |
630 |
630 |
631 // Get a literal value for the case block. Zandronum does not support |
631 // Get a literal value for the case block. Zandronum does not support |
632 // expressions here. |
632 // expressions here. |
633 mLexer->MustGetNext (tkNumber); |
633 mLexer->MustGetNext (tkNumber); |
647 // of buffering setup and stuff like that. |
647 // of buffering setup and stuff like that. |
648 // |
648 // |
649 // We null the switch buffer for the case-go-to statement as |
649 // We null the switch buffer for the case-go-to statement as |
650 // we want it all under the switch, not into the case-buffers. |
650 // we want it all under the switch, not into the case-buffers. |
651 mSwitchBuffer = null; |
651 mSwitchBuffer = null; |
652 buffer()->WriteDWord (dhCaseGoto); |
652 buffer()->WriteDWord (DH_CaseGoto); |
653 buffer()->WriteDWord (num); |
653 buffer()->WriteDWord (num); |
654 AddSwitchCase (null); |
654 AddSwitchCase (null); |
655 SCOPE (0).casecursor->number = num; |
655 SCOPE (0).casecursor->number = num; |
656 } |
656 } |
657 |
657 |
658 // ============================================================================ |
658 // ============================================================================ |
659 // |
659 // |
660 void BotscriptParser::ParseSwitchDefault() |
660 void BotscriptParser::ParseSwitchDefault() |
661 { |
661 { |
662 if (SCOPE (0).type != eSwitchScope) |
662 if (SCOPE (0).type != SCOPE_Switch) |
663 Error ("default label outside switch"); |
663 Error ("default label outside switch"); |
664 |
664 |
665 if (SCOPE (0).buffer1 != null) |
665 if (SCOPE (0).buffer1 != null) |
666 Error ("multiple default labels in one switch"); |
666 Error ("multiple default labels in one switch"); |
667 |
667 |
670 // The default header is buffered into buffer1, since |
670 // The default header is buffered into buffer1, since |
671 // it has to be the last of the case headers |
671 // it has to be the last of the case headers |
672 // |
672 // |
673 // Since the expression is pushed into the switch |
673 // Since the expression is pushed into the switch |
674 // and is only popped when case succeeds, we have |
674 // and is only popped when case succeeds, we have |
675 // to pop it with dhDrop manually if we end up in |
675 // to pop it with DH_Drop manually if we end up in |
676 // a default. |
676 // a default. |
677 DataBuffer* buf = new DataBuffer; |
677 DataBuffer* buf = new DataBuffer; |
678 SCOPE (0).buffer1 = buf; |
678 SCOPE (0).buffer1 = buf; |
679 buf->WriteDWord (dhDrop); |
679 buf->WriteDWord (DH_Drop); |
680 buf->WriteDWord (dhGoto); |
680 buf->WriteDWord (DH_Goto); |
681 AddSwitchCase (buf); |
681 AddSwitchCase (buf); |
682 } |
682 } |
683 |
683 |
684 // ============================================================================ |
684 // ============================================================================ |
685 // |
685 // |
686 void BotscriptParser::ParseBreak() |
686 void BotscriptParser::ParseBreak() |
687 { |
687 { |
688 if (mScopeCursor == 0) |
688 if (mScopeCursor == 0) |
689 Error ("unexpected `break`"); |
689 Error ("unexpected `break`"); |
690 |
690 |
691 buffer()->WriteDWord (dhGoto); |
691 buffer()->WriteDWord (DH_Goto); |
692 |
692 |
693 // switch and if use mark1 for the closing point, |
693 // switch and if use mark1 for the closing point, |
694 // for and while use mark2. |
694 // for and while use mark2. |
695 switch (SCOPE (0).type) |
695 switch (SCOPE (0).type) |
696 { |
696 { |
697 case eIfScope: |
697 case SCOPE_If: |
698 case eSwitchScope: |
698 case SCOPE_Switch: |
699 { |
699 { |
700 buffer()->AddReference (SCOPE (0).mark1); |
700 buffer()->AddReference (SCOPE (0).mark1); |
701 } break; |
701 } break; |
702 |
702 |
703 case eForScope: |
703 case SCOPE_For: |
704 case eWhileScope: |
704 case SCOPE_While: |
705 { |
705 { |
706 buffer()->AddReference (SCOPE (0).mark2); |
706 buffer()->AddReference (SCOPE (0).mark2); |
707 } break; |
707 } break; |
708 |
708 |
709 default: |
709 default: |
756 // If we're in the block stack, we're descending down from it now |
756 // If we're in the block stack, we're descending down from it now |
757 if (mScopeCursor > 0) |
757 if (mScopeCursor > 0) |
758 { |
758 { |
759 switch (SCOPE (0).type) |
759 switch (SCOPE (0).type) |
760 { |
760 { |
761 case eIfScope: |
761 case SCOPE_If: |
762 { |
762 { |
763 // Adjust the closing mark. |
763 // Adjust the closing mark. |
764 buffer()->AdjustMark (SCOPE (0).mark1); |
764 buffer()->AdjustMark (SCOPE (0).mark1); |
765 |
765 |
766 // We're returning from `if`, thus `else` follow |
766 // We're returning from `if`, thus `else` follow |
767 mCanElse = true; |
767 mCanElse = true; |
768 break; |
768 break; |
769 } |
769 } |
770 |
770 |
771 case eElseScope: |
771 case SCOPE_Else: |
772 { |
772 { |
773 // else instead uses mark1 for itself (so if expression |
773 // else instead uses mark1 for itself (so if expression |
774 // fails, jump to else), mark2 means end of else |
774 // fails, jump to else), mark2 means end of else |
775 buffer()->AdjustMark (SCOPE (0).mark2); |
775 buffer()->AdjustMark (SCOPE (0).mark2); |
776 break; |
776 break; |
777 } |
777 } |
778 |
778 |
779 case eForScope: |
779 case SCOPE_For: |
780 { // write the incrementor at the end of the loop block |
780 { // write the incrementor at the end of the loop block |
781 buffer()->MergeAndDestroy (SCOPE (0).buffer1); |
781 buffer()->MergeAndDestroy (SCOPE (0).buffer1); |
782 } |
782 } |
783 case eWhileScope: |
783 case SCOPE_While: |
784 { // write down the instruction to go back to the start of the loop |
784 { // write down the instruction to go back to the start of the loop |
785 buffer()->WriteDWord (dhGoto); |
785 buffer()->WriteDWord (DH_Goto); |
786 buffer()->AddReference (SCOPE (0).mark1); |
786 buffer()->AddReference (SCOPE (0).mark1); |
787 |
787 |
788 // Move the closing mark here since we're at the end of the while loop |
788 // Move the closing mark here since we're at the end of the while loop |
789 buffer()->AdjustMark (SCOPE (0).mark2); |
789 buffer()->AdjustMark (SCOPE (0).mark2); |
790 break; |
790 break; |
791 } |
791 } |
792 |
792 |
793 case eDoScope: |
793 case SCOPE_Do: |
794 { |
794 { |
795 mLexer->MustGetNext (tkWhile); |
795 mLexer->MustGetNext (tkWhile); |
796 mLexer->MustGetNext (tkParenStart); |
796 mLexer->MustGetNext (tkParenStart); |
797 DataBuffer* expr = ParseExpression (EIntType); |
797 DataBuffer* expr = ParseExpression (TYPE_Int); |
798 mLexer->MustGetNext (tkParenEnd); |
798 mLexer->MustGetNext (tkParenEnd); |
799 mLexer->MustGetNext (tkSemicolon); |
799 mLexer->MustGetNext (tkSemicolon); |
800 |
800 |
801 // If the condition runs true, go back to the start. |
801 // If the condition runs true, go back to the start. |
802 buffer()->MergeAndDestroy (expr); |
802 buffer()->MergeAndDestroy (expr); |
803 buffer()->WriteDWord (dhIfGoto); |
803 buffer()->WriteDWord (DH_IfGoto); |
804 buffer()->AddReference (SCOPE (0).mark1); |
804 buffer()->AddReference (SCOPE (0).mark1); |
805 break; |
805 break; |
806 } |
806 } |
807 |
807 |
808 case eSwitchScope: |
808 case SCOPE_Switch: |
809 { |
809 { |
810 // Switch closes. Move down to the record buffer of |
810 // Switch closes. Move down to the record buffer of |
811 // the lower block. |
811 // the lower block. |
812 if (SCOPE (1).casecursor != SCOPE (1).cases.begin() - 1) |
812 if (SCOPE (1).casecursor != SCOPE (1).cases.begin() - 1) |
813 mSwitchBuffer = SCOPE (1).casecursor->data; |
813 mSwitchBuffer = SCOPE (1).casecursor->data; |
837 // Move the closing mark here |
837 // Move the closing mark here |
838 buffer()->AdjustMark (SCOPE (0).mark1); |
838 buffer()->AdjustMark (SCOPE (0).mark1); |
839 break; |
839 break; |
840 } |
840 } |
841 |
841 |
842 case eUnknownScope: |
842 case SCOPE_Unknown: |
843 break; |
843 break; |
844 } |
844 } |
845 |
845 |
846 // Descend down the stack |
846 // Descend down the stack |
847 mScopeCursor--; |
847 mScopeCursor--; |
848 return; |
848 return; |
849 } |
849 } |
850 |
850 |
851 int dataheader = (mCurrentMode == EEventMode) ? dhEndEvent : |
851 int dataheader = (mCurrentMode == PARSERMODE_Event) ? DH_EndEvent : |
852 (mCurrentMode == EMainLoopMode) ? dhEndMainLoop : |
852 (mCurrentMode == PARSERMODE_MainLoop) ? DH_EndMainLoop : |
853 (mCurrentMode == EOnenterMode) ? dhEndOnEnter : |
853 (mCurrentMode == PARSERMODE_Onenter) ? DH_EndOnEnter : |
854 (mCurrentMode == EOnexitMode) ? dhEndOnExit : -1; |
854 (mCurrentMode == PARSERMODE_Onexit) ? DH_EndOnExit : -1; |
855 |
855 |
856 if (dataheader == -1) |
856 if (dataheader == -1) |
857 Error ("unexpected `}`"); |
857 Error ("unexpected `}`"); |
858 |
858 |
859 // Data header must be written before mode is changed because |
859 // Data header must be written before mode is changed because |
860 // onenter and mainloop go into special buffers, and we want |
860 // onenter and mainloop go into special buffers, and we want |
861 // the closing data headers into said buffers too. |
861 // the closing data headers into said buffers too. |
862 buffer()->WriteDWord (dataheader); |
862 buffer()->WriteDWord (dataheader); |
863 mCurrentMode = ETopLevelMode; |
863 mCurrentMode = PARSERMODE_TopLevel; |
864 mLexer->GetNext (tkSemicolon); |
864 mLexer->GetNext (tkSemicolon); |
865 } |
865 } |
866 |
866 |
867 // ============================================================================ |
867 // ============================================================================ |
868 // |
868 // |
1092 |
1092 |
1093 mLexer->MustGetAnyOf (tokens); |
1093 mLexer->MustGetAnyOf (tokens); |
1094 |
1094 |
1095 switch (mLexer->GetTokenType()) |
1095 switch (mLexer->GetTokenType()) |
1096 { |
1096 { |
1097 case tkAssign: return EAssign; |
1097 case tkAssign: return ASSIGNOP_Assign; |
1098 case tkAddAssign: return EAssignAdd; |
1098 case tkAddAssign: return ASSIGNOP_Add; |
1099 case tkSubAssign: return EAssignSub; |
1099 case tkSubAssign: return ASSIGNOP_Subtract; |
1100 case tkMultiplyAssign: return EAssignMul; |
1100 case tkMultiplyAssign: return ASSIGNOP_Multiply; |
1101 case tkDivideAssign: return EAssignDiv; |
1101 case tkDivideAssign: return ASSIGNOP_Divide; |
1102 case tkModulusAssign: return EAssignMod; |
1102 case tkModulusAssign: return ASSIGNOP_Modulus; |
1103 case tkDoublePlus: return EAssignIncrement; |
1103 case tkDoublePlus: return ASSIGNOP_Increase; |
1104 case tkDoubleMinus: return EAssignDecrement; |
1104 case tkDoubleMinus: return ASSIGNOP_Decrease; |
1105 default: break; |
1105 default: break; |
1106 } |
1106 } |
1107 |
1107 |
1108 assert (false); |
1108 assert (false); |
1109 return (EAssignmentOperator) 0; |
1109 return (AssignmentOperator) 0; |
1110 } |
1110 } |
1111 |
1111 |
1112 // ============================================================================ |
1112 // ============================================================================ |
1113 // |
1113 // |
1114 struct AssignmentDataHeaderInfo |
1114 struct AssignmentDataHeaderInfo |
1115 { |
1115 { |
1116 EAssignmentOperator op; |
1116 AssignmentOperator op; |
1117 EDataHeader local; |
1117 DataHeader local; |
1118 EDataHeader global; |
1118 DataHeader global; |
1119 EDataHeader array; |
1119 DataHeader array; |
1120 }; |
1120 }; |
1121 |
1121 |
1122 const AssignmentDataHeaderInfo gAssignmentDataHeaders[] = |
1122 const AssignmentDataHeaderInfo gAssignmentDataHeaders[] = |
1123 { |
1123 { |
1124 { EAssign, dhAssignLocalVar, dhAssignGlobalVar, dhAssignGlobalArray }, |
1124 { ASSIGNOP_Assign, DH_AssignLocalVar, DH_AssignGlobalVar, DH_AssignGlobalArray }, |
1125 { EAssignAdd, dhAddLocalVar, dhAddGlobalVar, dhAddGlobalArray }, |
1125 { ASSIGNOP_Add, DH_AddLocalVar, DH_AddGlobalVar, DH_AddGlobalArray }, |
1126 { EAssignSub, dhSubtractLocalVar, dhSubtractGlobalVar, dhSubtractGlobalArray }, |
1126 { ASSIGNOP_Subtract, DH_SubtractLocalVar, DH_SubtractGlobalVar, DH_SubtractGlobalArray }, |
1127 { EAssignMul, dhMultiplyLocalVar, dhMultiplyGlobalVar, dhMultiplyGlobalArray }, |
1127 { ASSIGNOP_Multiply, DH_MultiplyLocalVar, DH_MultiplyGlobalVar, DH_MultiplyGlobalArray }, |
1128 { EAssignDiv, dhDivideLocalVar, dhDivideGlobalVar, dhDivideGlobalArray }, |
1128 { ASSIGNOP_Divide, DH_DivideLocalVar, DH_DivideGlobalVar, DH_DivideGlobalArray }, |
1129 { EAssignMod, dhModLocalVar, dhModGlobalVar, dhModGlobalArray }, |
1129 { ASSIGNOP_Modulus, DH_ModLocalVar, DH_ModGlobalVar, DH_ModGlobalArray }, |
1130 { EAssignIncrement, dhIncreaseLocalVar, dhIncreaseGlobalVar, dhIncreaseGlobalArray }, |
1130 { ASSIGNOP_Increase, DH_IncreaseLocalVar, DH_IncreaseGlobalVar, DH_IncreaseGlobalArray }, |
1131 { EAssignDecrement, dhDecreaseLocalVar, dhDecreaseGlobalVar, dhDecreaseGlobalArray }, |
1131 { ASSIGNOP_Decrease, DH_DecreaseLocalVar, DH_DecreaseGlobalVar, DH_DecreaseGlobalArray }, |
1132 }; |
1132 }; |
1133 |
1133 |
1134 EDataHeader BotscriptParser::GetAssigmentDataHeader (EAssignmentOperator op, Variable* var) |
1134 DataHeader BotscriptParser::GetAssigmentDataHeader (AssignmentOperator op, Variable* var) |
1135 { |
1135 { |
1136 for (const auto& a : gAssignmentDataHeaders) |
1136 for (const auto& a : gAssignmentDataHeaders) |
1137 { |
1137 { |
1138 if (a.op != op) |
1138 if (a.op != op) |
1139 continue; |
1139 continue; |
1160 DataBuffer* BotscriptParser::ParseAssignment (Variable* var) |
1160 DataBuffer* BotscriptParser::ParseAssignment (Variable* var) |
1161 { |
1161 { |
1162 DataBuffer* retbuf = new DataBuffer; |
1162 DataBuffer* retbuf = new DataBuffer; |
1163 DataBuffer* arrayindex = null; |
1163 DataBuffer* arrayindex = null; |
1164 |
1164 |
1165 if (var->writelevel != Variable::WRITE_Mutable) |
1165 if (var->writelevel != WRITE_Mutable) |
1166 Error ("cannot alter read-only variable $%1", var->name); |
1166 Error ("cannot alter read-only variable $%1", var->name); |
1167 |
1167 |
1168 if (var->isarray) |
1168 if (var->isarray) |
1169 { |
1169 { |
1170 mLexer->MustGetNext (tkBracketStart); |
1170 mLexer->MustGetNext (tkBracketStart); |
1171 Expression expr (this, mLexer, EIntType); |
1171 Expression expr (this, mLexer, TYPE_Int); |
1172 expr.GetResult()->ConvertToBuffer(); |
1172 expr.GetResult()->ConvertToBuffer(); |
1173 arrayindex = expr.GetResult()->GetBuffer()->Clone(); |
1173 arrayindex = expr.GetResult()->GetBuffer()->Clone(); |
1174 mLexer->MustGetNext (tkBracketEnd); |
1174 mLexer->MustGetNext (tkBracketEnd); |
1175 } |
1175 } |
1176 |
1176 |
1177 // Get an operator |
1177 // Get an operator |
1178 EAssignmentOperator oper = ParseAssignmentOperator(); |
1178 AssignmentOperator oper = ParseAssignmentOperator(); |
1179 |
1179 |
1180 if (mCurrentMode == ETopLevelMode) |
1180 if (mCurrentMode == PARSERMODE_TopLevel) |
1181 Error ("can't alter variables at top level"); |
1181 Error ("can't alter variables at top level"); |
1182 |
1182 |
1183 // Parse the right operand |
1183 // Parse the right operand |
1184 if (oper != EAssignIncrement && oper != EAssignDecrement) |
1184 if (oper != ASSIGNOP_Increase && oper != ASSIGNOP_Decrease) |
1185 { |
1185 { |
1186 DataBuffer* expr = ParseExpression (var->type); |
1186 DataBuffer* expr = ParseExpression (var->type); |
1187 retbuf->MergeAndDestroy (expr); |
1187 retbuf->MergeAndDestroy (expr); |
1188 } |
1188 } |
1189 |
1189 |
1192 |
1192 |
1193 #if 0 |
1193 #if 0 |
1194 // <<= and >>= do not have data headers. Solution: expand them. |
1194 // <<= and >>= do not have data headers. Solution: expand them. |
1195 // a <<= b -> a = a << b |
1195 // a <<= b -> a = a << b |
1196 // a >>= b -> a = a >> b |
1196 // a >>= b -> a = a >> b |
1197 retbuf->WriteDWord (var->IsGlobal() ? dhPushGlobalVar : dhPushLocalVar); |
1197 retbuf->WriteDWord (var->IsGlobal() ? DH_PushGlobalVar : DH_PushLocalVar); |
1198 retbuf->WriteDWord (var->index); |
1198 retbuf->WriteDWord (var->index); |
1199 retbuf->MergeAndDestroy (expr); |
1199 retbuf->MergeAndDestroy (expr); |
1200 retbuf->WriteDWord ((oper == OPER_ASSIGNLEFTSHIFT) ? dhLeftShift : dhRightShift); |
1200 retbuf->WriteDWord ((oper == OPER_ASSIGNLEFTSHIFT) ? DH_LeftShift : DH_RightShift); |
1201 retbuf->WriteDWord (var->IsGlobal() ? dhAssignGlobalVar : dhAssignLocalVar); |
1201 retbuf->WriteDWord (var->IsGlobal() ? DH_AssignGlobalVar : DH_AssignLocalVar); |
1202 retbuf->WriteDWord (var->index); |
1202 retbuf->WriteDWord (var->index); |
1203 #endif |
1203 #endif |
1204 |
1204 |
1205 EDataHeader dh = GetAssigmentDataHeader (oper, var); |
1205 DataHeader dh = GetAssigmentDataHeader (oper, var); |
1206 retbuf->WriteDWord (dh); |
1206 retbuf->WriteDWord (dh); |
1207 retbuf->WriteDWord (var->index); |
1207 retbuf->WriteDWord (var->index); |
1208 return retbuf; |
1208 return retbuf; |
1209 } |
1209 } |
1210 |
1210 |
1216 |
1216 |
1217 if (mScopeStack.Size() < mScopeCursor + 1) |
1217 if (mScopeStack.Size() < mScopeCursor + 1) |
1218 { |
1218 { |
1219 ScopeInfo newscope; |
1219 ScopeInfo newscope; |
1220 mScopeStack << newscope; |
1220 mScopeStack << newscope; |
1221 reset = eResetScope; |
1221 reset = SCOPE_Reset; |
1222 } |
1222 } |
1223 |
1223 |
1224 if (reset == eResetScope) |
1224 if (reset == SCOPE_Reset) |
1225 { |
1225 { |
1226 ScopeInfo* info = &SCOPE (0); |
1226 ScopeInfo* info = &SCOPE (0); |
1227 info->type = eUnknownScope; |
1227 info->type = SCOPE_Unknown; |
1228 info->mark1 = null; |
1228 info->mark1 = null; |
1229 info->mark2 = null; |
1229 info->mark2 = null; |
1230 info->buffer1 = null; |
1230 info->buffer1 = null; |
1231 info->cases.Clear(); |
1231 info->cases.Clear(); |
1232 info->casecursor = info->cases.begin() - 1; |
1232 info->casecursor = info->cases.begin() - 1; |
1346 void BotscriptParser::writeMemberBuffers() |
1346 void BotscriptParser::writeMemberBuffers() |
1347 { |
1347 { |
1348 // If there was no mainloop defined, write a dummy one now. |
1348 // If there was no mainloop defined, write a dummy one now. |
1349 if (mGotMainLoop == false) |
1349 if (mGotMainLoop == false) |
1350 { |
1350 { |
1351 mMainLoopBuffer->WriteDWord (dhMainLoop); |
1351 mMainLoopBuffer->WriteDWord (DH_MainLoop); |
1352 mMainLoopBuffer->WriteDWord (dhEndMainLoop); |
1352 mMainLoopBuffer->WriteDWord (DH_EndMainLoop); |
1353 } |
1353 } |
1354 |
1354 |
1355 // Write the onenter and mainloop buffers, in that order in particular. |
1355 // Write the onenter and mainloop buffers, in that order in particular. |
1356 for (DataBuffer** bufp : List<DataBuffer**> ({&mOnEnterBuffer, &mMainLoopBuffer})) |
1356 for (DataBuffer** bufp : List<DataBuffer**> ({&mOnEnterBuffer, &mMainLoopBuffer})) |
1357 { |
1357 { |