| 257 // encountered it, then mark down that we have it. |
256 // encountered it, then mark down that we have it. |
| 258 if (statename.toLowercase() == "statespawn") |
257 if (statename.toLowercase() == "statespawn") |
| 259 m_isStateSpawnDefined = true; |
258 m_isStateSpawnDefined = true; |
| 260 |
259 |
| 261 // Must end in a colon |
260 // Must end in a colon |
| 262 m_lexer->mustGetNext (TK_Colon); |
261 m_lexer->mustGetNext (Token::Colon); |
| 263 |
262 |
| 264 // write the previous state's onenter and |
263 // write the previous state's onenter and |
| 265 // mainloop buffers to file now |
264 // mainloop buffers to file now |
| 266 if (m_currentState.isEmpty() == false) |
265 if (m_currentState.isEmpty() == false) |
| 267 writeMemberBuffers(); |
266 writeMemberBuffers(); |
| 268 |
267 |
| 269 currentBuffer()->writeDWord (DH_StateName); |
268 currentBuffer()->writeDWord (DataHeader::StateName); |
| 270 currentBuffer()->writeString (statename); |
269 currentBuffer()->writeString (statename); |
| 271 currentBuffer()->writeDWord (DH_StateIndex); |
270 currentBuffer()->writeDWord (DataHeader::StateIndex); |
| 272 currentBuffer()->writeDWord (m_numStates); |
271 currentBuffer()->writeDWord (m_numStates); |
| 273 |
272 |
| 274 m_numStates++; |
273 m_numStates++; |
| 275 m_currentState = statename; |
274 m_currentState = statename; |
| 276 m_gotMainLoop = false; |
275 m_gotMainLoop = false; |
| 279 // ============================================================================ |
278 // ============================================================================ |
| 280 // |
279 // |
| 281 void BotscriptParser::parseEventBlock() |
280 void BotscriptParser::parseEventBlock() |
| 282 { |
281 { |
| 283 checkToplevel(); |
282 checkToplevel(); |
| 284 m_lexer->mustGetNext (TK_String); |
283 m_lexer->mustGetNext (Token::String); |
| 285 |
284 |
| 286 EventDefinition* e = findEventByName (getTokenString()); |
285 EventDefinition* e = findEventByName (getTokenString()); |
| 287 |
286 |
| 288 if (e == null) |
287 if (e == null) |
| 289 error ("bad event, got `%1`\n", getTokenString()); |
288 error ("bad event, got `%1`\n", getTokenString()); |
| 290 |
289 |
| 291 m_lexer->mustGetNext (TK_BraceStart); |
290 m_lexer->mustGetNext (Token::BraceStart); |
| 292 m_currentMode = PARSERMODE_Event; |
291 m_currentMode = PARSERMODE_Event; |
| 293 currentBuffer()->writeDWord (DH_Event); |
292 currentBuffer()->writeDWord (DataHeader::Event); |
| 294 currentBuffer()->writeDWord (e->number); |
293 currentBuffer()->writeDWord (e->number); |
| 295 m_numEvents++; |
294 m_numEvents++; |
| 296 } |
295 } |
| 297 |
296 |
| 298 // ============================================================================ |
297 // ============================================================================ |
| 299 // |
298 // |
| 300 void BotscriptParser::parseMainloop() |
299 void BotscriptParser::parseMainloop() |
| 301 { |
300 { |
| 302 checkToplevel(); |
301 checkToplevel(); |
| 303 m_lexer->mustGetNext (TK_BraceStart); |
302 m_lexer->mustGetNext (Token::BraceStart); |
| 304 |
303 |
| 305 m_currentMode = PARSERMODE_MainLoop; |
304 m_currentMode = PARSERMODE_MainLoop; |
| 306 m_mainLoopBuffer->writeDWord (DH_MainLoop); |
305 m_mainLoopBuffer->writeDWord (DataHeader::MainLoop); |
| 307 } |
306 } |
| 308 |
307 |
| 309 // ============================================================================ |
308 // ============================================================================ |
| 310 // |
309 // |
| 311 void BotscriptParser::parseOnEnterExit() |
310 void BotscriptParser::parseOnEnterExit() |
| 312 { |
311 { |
| 313 checkToplevel(); |
312 checkToplevel(); |
| 314 bool onenter = (tokenIs (TK_Onenter)); |
313 bool onenter = (tokenIs (Token::Onenter)); |
| 315 m_lexer->mustGetNext (TK_BraceStart); |
314 m_lexer->mustGetNext (Token::BraceStart); |
| 316 |
315 |
| 317 m_currentMode = onenter ? PARSERMODE_Onenter : PARSERMODE_Onexit; |
316 m_currentMode = onenter ? PARSERMODE_Onenter : PARSERMODE_Onexit; |
| 318 currentBuffer()->writeDWord (onenter ? DH_OnEnter : DH_OnExit); |
317 currentBuffer()->writeDWord (onenter ? DataHeader::OnEnter : DataHeader::OnExit); |
| 319 } |
318 } |
| 320 |
319 |
| 321 // ============================================================================ |
320 // ============================================================================ |
| 322 // |
321 // |
| 323 void BotscriptParser::parseVar() |
322 void BotscriptParser::parseVar() |
| 324 { |
323 { |
| 325 Variable* var = new Variable; |
324 Variable* var = new Variable; |
| 326 var->origin = m_lexer->describeCurrentPosition(); |
325 var->origin = m_lexer->describeCurrentPosition(); |
| 327 var->isarray = false; |
326 var->isarray = false; |
| 328 const bool isconst = m_lexer->next (TK_Const); |
327 bool isconst = m_lexer->next (Token::Const); |
| 329 m_lexer->mustGetAnyOf ({TK_Int,TK_Str,TK_Void}); |
328 m_lexer->mustGetAnyOf ({Token::Int,Token::Str,Token::Void}); |
| 330 |
329 |
| 331 DataType vartype = (tokenIs (TK_Int)) ? TYPE_Int : |
330 DataType vartype = (tokenIs (Token::Int)) ? TYPE_Int |
| 332 (tokenIs (TK_Str)) ? TYPE_String : |
331 : (tokenIs (Token::Str)) ? TYPE_String |
| 333 TYPE_Bool; |
332 : TYPE_Bool; |
| 334 |
333 |
| 335 m_lexer->mustGetNext (TK_DollarSign); |
334 if (m_lexer->next (Token::Const)) |
| 336 m_lexer->mustGetNext (TK_Symbol); |
335 { |
| |
336 if (isconst) |
| |
337 error ("duplicate const in variable declaration"); |
| |
338 |
| |
339 isconst = true; |
| |
340 } |
| |
341 |
| |
342 m_lexer->mustGetNext (Token::DollarSign); |
| |
343 m_lexer->mustGetNext (Token::Symbol); |
| 337 String name = getTokenString(); |
344 String name = getTokenString(); |
| 338 |
345 |
| 339 if (m_lexer->next (TK_BracketStart)) |
346 if (m_lexer->next (Token::BracketStart)) |
| 340 { |
347 { |
| 341 m_lexer->mustGetNext (TK_BracketEnd); |
348 m_lexer->mustGetNext (Token::BracketEnd); |
| 342 var->isarray = true; |
349 var->isarray = true; |
| 343 |
350 |
| 344 if (isconst) |
351 if (isconst) |
| 345 error ("arrays cannot be const"); |
352 error ("arrays cannot be const"); |
| 346 } |
353 } |
| 347 |
354 |
| 348 for (Variable* var : SCOPE(0).globalVariables + SCOPE(0).localVariables) |
355 for (Variable* var : SCOPE(0).globalVariables + SCOPE(0).localVariables) |
| 349 { |
356 { |
| 350 if (var->name == name) |
357 if (var->name == name) |
| |
358 { |
| 351 error ("Variable $%1 is already declared on this scope; declared at %2", |
359 error ("Variable $%1 is already declared on this scope; declared at %2", |
| 352 var->name, var->origin); |
360 var->name, var->origin); |
| |
361 } |
| 353 } |
362 } |
| 354 |
363 |
| 355 var->name = name; |
364 var->name = name; |
| 356 var->statename = ""; |
365 var->statename = ""; |
| 357 var->type = vartype; |
366 var->type = vartype; |
| 410 { |
419 { |
| 411 checkNotToplevel(); |
420 checkNotToplevel(); |
| 412 pushScope(); |
421 pushScope(); |
| 413 |
422 |
| 414 // Condition |
423 // Condition |
| 415 m_lexer->mustGetNext (TK_ParenStart); |
424 m_lexer->mustGetNext (Token::ParenStart); |
| 416 |
425 |
| 417 // Read the expression and write it. |
426 // Read the expression and write it. |
| 418 DataBuffer* c = parseExpression (TYPE_Int); |
427 DataBuffer* c = parseExpression (TYPE_Int); |
| 419 currentBuffer()->mergeAndDestroy (c); |
428 currentBuffer()->mergeAndDestroy (c); |
| 420 |
429 |
| 421 m_lexer->mustGetNext (TK_ParenEnd); |
430 m_lexer->mustGetNext (Token::ParenEnd); |
| 422 m_lexer->mustGetNext (TK_BraceStart); |
431 m_lexer->mustGetNext (Token::BraceStart); |
| 423 |
432 |
| 424 // Add a mark - to here temporarily - and add a reference to it. |
433 // Add a mark - to here temporarily - and add a reference to it. |
| 425 // Upon a closing brace, the mark will be adjusted. |
434 // Upon a closing brace, the mark will be adjusted. |
| 426 ByteMark* mark = currentBuffer()->addMark (""); |
435 ByteMark* mark = currentBuffer()->addMark (""); |
| 427 |
436 |
| 428 // Use DH_IfNotGoto - if the expression is not true, we goto the mark |
437 // Use DataHeader::IfNotGoto - if the expression is not true, we goto the mark |
| 429 // we just defined - and this mark will be at the end of the scope block. |
438 // we just defined - and this mark will be at the end of the scope block. |
| 430 currentBuffer()->writeDWord (DH_IfNotGoto); |
439 currentBuffer()->writeDWord (DataHeader::IfNotGoto); |
| 431 currentBuffer()->addReference (mark); |
440 currentBuffer()->addReference (mark); |
| 432 |
441 |
| 433 // Store it |
442 // Store it |
| 434 SCOPE (0).mark1 = mark; |
443 SCOPE (0).mark1 = mark; |
| 435 SCOPE (0).type = SCOPE_If; |
444 SCOPE (0).type = SCOPE_If; |
| 438 // ============================================================================ |
447 // ============================================================================ |
| 439 // |
448 // |
| 440 void BotscriptParser::parseElse() |
449 void BotscriptParser::parseElse() |
| 441 { |
450 { |
| 442 checkNotToplevel(); |
451 checkNotToplevel(); |
| 443 m_lexer->mustGetNext (TK_BraceStart); |
452 m_lexer->mustGetNext (Token::BraceStart); |
| 444 pushScope (eNoReset); |
453 pushScope (true); |
| 445 |
454 |
| 446 if (SCOPE (0).type != SCOPE_If) |
455 if (SCOPE (0).type != SCOPE_If) |
| 447 error ("else without preceding if"); |
456 error ("else without preceding if"); |
| 448 |
457 |
| 449 // write down to jump to the end of the else statement |
458 // write down to jump to the end of the else statement |
| 450 // Otherwise we have fall-throughs |
459 // Otherwise we have fall-throughs |
| 451 SCOPE (0).mark2 = currentBuffer()->addMark (""); |
460 SCOPE (0).mark2 = currentBuffer()->addMark (""); |
| 452 |
461 |
| 453 // Instruction to jump to the end after if block is complete |
462 // Instruction to jump to the end after if block is complete |
| 454 currentBuffer()->writeDWord (DH_Goto); |
463 currentBuffer()->writeDWord (DataHeader::Goto); |
| 455 currentBuffer()->addReference (SCOPE (0).mark2); |
464 currentBuffer()->addReference (SCOPE (0).mark2); |
| 456 |
465 |
| 457 // Move the ifnot mark here and set type to else |
466 // Move the ifnot mark here and set type to else |
| 458 currentBuffer()->adjustMark (SCOPE (0).mark1); |
467 currentBuffer()->adjustMark (SCOPE (0).mark1); |
| 459 SCOPE (0).type = SCOPE_Else; |
468 SCOPE (0).type = SCOPE_Else; |
| 472 // the beginning with a go-to statement. |
481 // the beginning with a go-to statement. |
| 473 ByteMark* mark1 = currentBuffer()->addMark (""); // start |
482 ByteMark* mark1 = currentBuffer()->addMark (""); // start |
| 474 ByteMark* mark2 = currentBuffer()->addMark (""); // end |
483 ByteMark* mark2 = currentBuffer()->addMark (""); // end |
| 475 |
484 |
| 476 // Condition |
485 // Condition |
| 477 m_lexer->mustGetNext (TK_ParenStart); |
486 m_lexer->mustGetNext (Token::ParenStart); |
| 478 DataBuffer* expr = parseExpression (TYPE_Int); |
487 DataBuffer* expr = parseExpression (TYPE_Int); |
| 479 m_lexer->mustGetNext (TK_ParenEnd); |
488 m_lexer->mustGetNext (Token::ParenEnd); |
| 480 m_lexer->mustGetNext (TK_BraceStart); |
489 m_lexer->mustGetNext (Token::BraceStart); |
| 481 |
490 |
| 482 // write condition |
491 // write condition |
| 483 currentBuffer()->mergeAndDestroy (expr); |
492 currentBuffer()->mergeAndDestroy (expr); |
| 484 |
493 |
| 485 // Instruction to go to the end if it fails |
494 // Instruction to go to the end if it fails |
| 486 currentBuffer()->writeDWord (DH_IfNotGoto); |
495 currentBuffer()->writeDWord (DataHeader::IfNotGoto); |
| 487 currentBuffer()->addReference (mark2); |
496 currentBuffer()->addReference (mark2); |
| 488 |
497 |
| 489 // Store the needed stuff |
498 // Store the needed stuff |
| 490 SCOPE (0).mark1 = mark1; |
499 SCOPE (0).mark1 = mark1; |
| 491 SCOPE (0).mark2 = mark2; |
500 SCOPE (0).mark2 = mark2; |
| 498 { |
507 { |
| 499 checkNotToplevel(); |
508 checkNotToplevel(); |
| 500 pushScope(); |
509 pushScope(); |
| 501 |
510 |
| 502 // Initializer |
511 // Initializer |
| 503 m_lexer->mustGetNext (TK_ParenStart); |
512 m_lexer->mustGetNext (Token::ParenStart); |
| 504 DataBuffer* init = parseStatement(); |
513 DataBuffer* init = parseStatement(); |
| 505 |
514 |
| 506 if (init == null) |
515 if (init == null) |
| 507 error ("bad statement for initializer of for"); |
516 error ("bad statement for initializer of for"); |
| 508 |
517 |
| 509 m_lexer->mustGetNext (TK_Semicolon); |
518 m_lexer->mustGetNext (Token::Semicolon); |
| 510 |
519 |
| 511 // Condition |
520 // Condition |
| 512 DataBuffer* cond = parseExpression (TYPE_Int); |
521 DataBuffer* cond = parseExpression (TYPE_Int); |
| 513 |
522 |
| 514 if (cond == null) |
523 if (cond == null) |
| 515 error ("bad statement for condition of for"); |
524 error ("bad statement for condition of for"); |
| 516 |
525 |
| 517 m_lexer->mustGetNext (TK_Semicolon); |
526 m_lexer->mustGetNext (Token::Semicolon); |
| 518 |
527 |
| 519 // Incrementor |
528 // Incrementor |
| 520 DataBuffer* incr = parseStatement(); |
529 DataBuffer* incr = parseStatement(); |
| 521 |
530 |
| 522 if (incr == null) |
531 if (incr == null) |
| 523 error ("bad statement for incrementor of for"); |
532 error ("bad statement for incrementor of for"); |
| 524 |
533 |
| 525 m_lexer->mustGetNext (TK_ParenEnd); |
534 m_lexer->mustGetNext (Token::ParenEnd); |
| 526 m_lexer->mustGetNext (TK_BraceStart); |
535 m_lexer->mustGetNext (Token::BraceStart); |
| 527 |
536 |
| 528 // First, write out the initializer |
537 // First, write out the initializer |
| 529 currentBuffer()->mergeAndDestroy (init); |
538 currentBuffer()->mergeAndDestroy (init); |
| 530 |
539 |
| 531 // Init two marks |
540 // Init two marks |
| 532 ByteMark* mark1 = currentBuffer()->addMark (""); |
541 ByteMark* mark1 = currentBuffer()->addMark (""); |
| 533 ByteMark* mark2 = currentBuffer()->addMark (""); |
542 ByteMark* mark2 = currentBuffer()->addMark (""); |
| 534 |
543 |
| 535 // Add the condition |
544 // Add the condition |
| 536 currentBuffer()->mergeAndDestroy (cond); |
545 currentBuffer()->mergeAndDestroy (cond); |
| 537 currentBuffer()->writeDWord (DH_IfNotGoto); |
546 currentBuffer()->writeDWord (DataHeader::IfNotGoto); |
| 538 currentBuffer()->addReference (mark2); |
547 currentBuffer()->addReference (mark2); |
| 539 |
548 |
| 540 // Store the marks and incrementor |
549 // Store the marks and incrementor |
| 541 SCOPE (0).mark1 = mark1; |
550 SCOPE (0).mark1 = mark1; |
| 542 SCOPE (0).mark2 = mark2; |
551 SCOPE (0).mark2 = mark2; |
| 591 if (SCOPE (0).type != SCOPE_Switch) |
600 if (SCOPE (0).type != SCOPE_Switch) |
| 592 error ("case label outside switch"); |
601 error ("case label outside switch"); |
| 593 |
602 |
| 594 // Get a literal value for the case block. Zandronum does not support |
603 // Get a literal value for the case block. Zandronum does not support |
| 595 // expressions here. |
604 // expressions here. |
| 596 m_lexer->mustGetNext (TK_Number); |
605 m_lexer->mustGetNext (Token::Number); |
| 597 int num = m_lexer->token()->text.toLong(); |
606 int num = m_lexer->token()->text.toLong(); |
| 598 m_lexer->mustGetNext (TK_Colon); |
607 m_lexer->mustGetNext (Token::Colon); |
| 599 |
608 |
| 600 for (const CaseInfo& info : SCOPE(0).cases) |
609 for (const CaseInfo& info : SCOPE(0).cases) |
| |
610 { |
| 601 if (info.number == num) |
611 if (info.number == num) |
| 602 error ("multiple case %1 labels in one switch", num); |
612 error ("multiple case %1 labels in one switch", num); |
| |
613 } |
| 603 |
614 |
| 604 // Write down the expression and case-go-to. This builds |
615 // Write down the expression and case-go-to. This builds |
| 605 // the case tree. The closing event will write the actual |
616 // the case tree. The closing event will write the actual |
| 606 // blocks and move the marks appropriately. |
617 // blocks and move the marks appropriately. |
| 607 // |
618 // |
| 626 error ("default label outside switch"); |
637 error ("default label outside switch"); |
| 627 |
638 |
| 628 if (SCOPE (0).buffer1 != null) |
639 if (SCOPE (0).buffer1 != null) |
| 629 error ("multiple default labels in one switch"); |
640 error ("multiple default labels in one switch"); |
| 630 |
641 |
| 631 m_lexer->mustGetNext (TK_Colon); |
642 m_lexer->mustGetNext (Token::Colon); |
| 632 |
643 |
| 633 // The default header is buffered into buffer1, since |
644 // The default header is buffered into buffer1, since |
| 634 // it has to be the last of the case headers |
645 // it has to be the last of the case headers |
| 635 // |
646 // |
| 636 // Since the expression is pushed into the switch |
647 // Since the expression is pushed into the switch |
| 637 // and is only popped when case succeeds, we have |
648 // and is only popped when case succeeds, we have |
| 638 // to pop it with DH_Drop manually if we end up in |
649 // to pop it with DataHeader::Drop manually if we end up in |
| 639 // a default. |
650 // a default. |
| 640 DataBuffer* buf = new DataBuffer; |
651 DataBuffer* buf = new DataBuffer; |
| 641 SCOPE (0).buffer1 = buf; |
652 SCOPE (0).buffer1 = buf; |
| 642 buf->writeDWord (DH_Drop); |
653 buf->writeDWord (DataHeader::Drop); |
| 643 buf->writeDWord (DH_Goto); |
654 buf->writeDWord (DataHeader::Goto); |
| 644 addSwitchCase (buf); |
655 addSwitchCase (buf); |
| 645 } |
656 } |
| 646 |
657 |
| 647 // ============================================================================ |
658 // ============================================================================ |
| 648 // |
659 // |
| 649 void BotscriptParser::parseBreak() |
660 void BotscriptParser::parseBreak() |
| 650 { |
661 { |
| 651 if (m_scopeCursor == 0) |
662 if (m_scopeCursor == 0) |
| 652 error ("unexpected `break`"); |
663 error ("unexpected `break`"); |
| 653 |
664 |
| 654 currentBuffer()->writeDWord (DH_Goto); |
665 currentBuffer()->writeDWord (DataHeader::Goto); |
| 655 |
666 |
| 656 // switch and if use mark1 for the closing point, |
667 // switch and if use mark1 for the closing point, |
| 657 // for and while use mark2. |
668 // for and while use mark2. |
| 658 switch (SCOPE (0).type) |
669 switch (SCOPE (0).type) |
| 659 { |
670 { |
| 660 case SCOPE_If: |
671 case SCOPE_If: |
| 661 case SCOPE_Switch: |
672 case SCOPE_Switch: |
| 662 { |
|
| 663 currentBuffer()->addReference (SCOPE (0).mark1); |
673 currentBuffer()->addReference (SCOPE (0).mark1); |
| 664 } break; |
674 break; |
| 665 |
675 |
| 666 case SCOPE_For: |
676 case SCOPE_For: |
| 667 case SCOPE_While: |
677 case SCOPE_While: |
| 668 { |
|
| 669 currentBuffer()->addReference (SCOPE (0).mark2); |
678 currentBuffer()->addReference (SCOPE (0).mark2); |
| 670 } break; |
679 break; |
| 671 |
680 |
| 672 default: |
681 default: |
| 673 { |
|
| 674 error ("unexpected `break`"); |
682 error ("unexpected `break`"); |
| 675 } break; |
683 break; |
| 676 } |
684 } |
| 677 |
685 |
| 678 m_lexer->mustGetNext (TK_Semicolon); |
686 m_lexer->mustGetNext (Token::Semicolon); |
| 679 } |
687 } |
| 680 |
688 |
| 681 // ============================================================================ |
689 // ============================================================================ |
| 682 // |
690 // |
| 683 void BotscriptParser::parseContinue() |
691 void BotscriptParser::parseContinue() |
| 684 { |
692 { |
| 685 m_lexer->mustGetNext (TK_Semicolon); |
693 m_lexer->mustGetNext (Token::Semicolon); |
| 686 |
694 |
| 687 int curs; |
695 int curs; |
| 688 bool found = false; |
696 bool found = false; |
| 689 |
697 |
| 690 // Fall through the scope until we find a loop block |
698 // Fall through the scope until we find a loop block |
| 691 for (curs = m_scopeCursor; curs > 0 && !found; curs--) |
699 for (curs = m_scopeCursor; curs > 0 and !found; curs--) |
| 692 { |
700 { |
| 693 switch (m_scopeStack[curs].type) |
701 switch (m_scopeStack[curs].type) |
| 694 { |
702 { |
| 695 case SCOPE_For: |
703 case SCOPE_For: |
| 696 case SCOPE_While: |
704 case SCOPE_While: |
| 697 case SCOPE_Do: |
705 case SCOPE_Do: |
| 698 { |
706 currentBuffer()->writeDWord (DataHeader::Goto); |
| 699 currentBuffer()->writeDWord (DH_Goto); |
|
| 700 currentBuffer()->addReference (m_scopeStack[curs].mark1); |
707 currentBuffer()->addReference (m_scopeStack[curs].mark1); |
| 701 found = true; |
708 found = true; |
| 702 } break; |
709 break; |
| 703 |
710 |
| 704 default: |
711 default: |
| 705 break; |
712 break; |
| 706 } |
713 } |
| 707 } |
714 } |
| 743 { // write the incrementor at the end of the loop block |
750 { // write the incrementor at the end of the loop block |
| 744 currentBuffer()->mergeAndDestroy (SCOPE (0).buffer1); |
751 currentBuffer()->mergeAndDestroy (SCOPE (0).buffer1); |
| 745 } |
752 } |
| 746 case SCOPE_While: |
753 case SCOPE_While: |
| 747 { // write down the instruction to go back to the start of the loop |
754 { // write down the instruction to go back to the start of the loop |
| 748 currentBuffer()->writeDWord (DH_Goto); |
755 currentBuffer()->writeDWord (DataHeader::Goto); |
| 749 currentBuffer()->addReference (SCOPE (0).mark1); |
756 currentBuffer()->addReference (SCOPE (0).mark1); |
| 750 |
757 |
| 751 // Move the closing mark here since we're at the end of the while loop |
758 // Move the closing mark here since we're at the end of the while loop |
| 752 currentBuffer()->adjustMark (SCOPE (0).mark2); |
759 currentBuffer()->adjustMark (SCOPE (0).mark2); |
| 753 break; |
760 break; |
| 754 } |
761 } |
| 755 |
762 |
| 756 case SCOPE_Do: |
763 case SCOPE_Do: |
| 757 { |
764 { |
| 758 m_lexer->mustGetNext (TK_While); |
765 m_lexer->mustGetNext (Token::While); |
| 759 m_lexer->mustGetNext (TK_ParenStart); |
766 m_lexer->mustGetNext (Token::ParenStart); |
| 760 DataBuffer* expr = parseExpression (TYPE_Int); |
767 DataBuffer* expr = parseExpression (TYPE_Int); |
| 761 m_lexer->mustGetNext (TK_ParenEnd); |
768 m_lexer->mustGetNext (Token::ParenEnd); |
| 762 m_lexer->mustGetNext (TK_Semicolon); |
769 m_lexer->mustGetNext (Token::Semicolon); |
| 763 |
770 |
| 764 // If the condition runs true, go back to the start. |
771 // If the condition runs true, go back to the start. |
| 765 currentBuffer()->mergeAndDestroy (expr); |
772 currentBuffer()->mergeAndDestroy (expr); |
| 766 currentBuffer()->writeDWord (DH_IfGoto); |
773 currentBuffer()->writeDWord (DataHeader::IfGoto); |
| 767 currentBuffer()->addReference (SCOPE (0).mark1); |
774 currentBuffer()->addReference (SCOPE (0).mark1); |
| 768 break; |
775 break; |
| 769 } |
776 } |
| 770 |
777 |
| 771 case SCOPE_Switch: |
778 case SCOPE_Switch: |
| 809 // Descend down the stack |
816 // Descend down the stack |
| 810 m_scopeCursor--; |
817 m_scopeCursor--; |
| 811 return; |
818 return; |
| 812 } |
819 } |
| 813 |
820 |
| 814 int dataheader = (m_currentMode == PARSERMODE_Event) ? DH_EndEvent : |
821 int dataheader = (m_currentMode == PARSERMODE_Event) ? DataHeader::EndEvent |
| 815 (m_currentMode == PARSERMODE_MainLoop) ? DH_EndMainLoop : |
822 : (m_currentMode == PARSERMODE_MainLoop) ? DataHeader::EndMainLoop |
| 816 (m_currentMode == PARSERMODE_Onenter) ? DH_EndOnEnter : |
823 : (m_currentMode == PARSERMODE_Onenter) ? DataHeader::EndOnEnter |
| 817 (m_currentMode == PARSERMODE_Onexit) ? DH_EndOnExit : -1; |
824 : (m_currentMode == PARSERMODE_Onexit) ? DataHeader::EndOnExit |
| |
825 : -1; |
| 818 |
826 |
| 819 if (dataheader == -1) |
827 if (dataheader == -1) |
| 820 error ("unexpected `}`"); |
828 error ("unexpected `}`"); |
| 821 |
829 |
| 822 // Data header must be written before mode is changed because |
830 // Data header must be written before mode is changed because |
| 823 // onenter and mainloop go into special buffers, and we want |
831 // onenter and mainloop go into special buffers, and we want |
| 824 // the closing data headers into said buffers too. |
832 // the closing data headers into said buffers too. |
| 825 currentBuffer()->writeDWord (dataheader); |
833 currentBuffer()->writeDWord (dataheader); |
| 826 m_currentMode = PARSERMODE_TopLevel; |
834 m_currentMode = PARSERMODE_TopLevel; |
| 827 m_lexer->next (TK_Semicolon); |
835 m_lexer->next (Token::Semicolon); |
| 828 } |
836 } |
| 829 |
837 |
| 830 // ============================================================================= |
838 // ============================================================================= |
| 831 // |
839 // |
| 832 void BotscriptParser::parseEventdef() |
840 void BotscriptParser::parseEventdef() |
| 833 { |
841 { |
| 834 EventDefinition* e = new EventDefinition; |
842 EventDefinition* e = new EventDefinition; |
| 835 |
843 |
| 836 m_lexer->mustGetNext (TK_Number); |
844 m_lexer->mustGetNext (Token::Number); |
| 837 e->number = getTokenString().toLong(); |
845 e->number = getTokenString().toLong(); |
| 838 m_lexer->mustGetNext (TK_Colon); |
846 m_lexer->mustGetNext (Token::Colon); |
| 839 m_lexer->mustGetNext (TK_Symbol); |
847 m_lexer->mustGetNext (Token::Symbol); |
| 840 e->name = m_lexer->token()->text; |
848 e->name = m_lexer->token()->text; |
| 841 m_lexer->mustGetNext (TK_ParenStart); |
849 m_lexer->mustGetNext (Token::ParenStart); |
| 842 m_lexer->mustGetNext (TK_ParenEnd); |
850 m_lexer->mustGetNext (Token::ParenEnd); |
| 843 m_lexer->mustGetNext (TK_Semicolon); |
851 m_lexer->mustGetNext (Token::Semicolon); |
| 844 addEvent (e); |
852 addEvent (e); |
| 845 } |
853 } |
| 846 |
854 |
| 847 // ============================================================================= |
855 // ============================================================================= |
| 848 // |
856 // |
| 850 { |
858 { |
| 851 CommandInfo* comm = new CommandInfo; |
859 CommandInfo* comm = new CommandInfo; |
| 852 comm->origin = m_lexer->describeCurrentPosition(); |
860 comm->origin = m_lexer->describeCurrentPosition(); |
| 853 |
861 |
| 854 // Return value |
862 // Return value |
| 855 m_lexer->mustGetAnyOf ({TK_Int,TK_Void,TK_Bool,TK_Str}); |
863 m_lexer->mustGetAnyOf ({Token::Int,Token::Void,Token::Bool,Token::Str}); |
| 856 comm->returnvalue = getTypeByName (m_lexer->token()->text); // TODO |
864 comm->returnvalue = getTypeByName (m_lexer->token()->text); // TODO |
| 857 ASSERT_NE (comm->returnvalue, -1); |
865 ASSERT_NE (comm->returnvalue, -1); |
| 858 |
866 |
| 859 // Number |
867 // Number |
| 860 m_lexer->mustGetNext (TK_Number); |
868 m_lexer->mustGetNext (Token::Number); |
| 861 comm->number = m_lexer->token()->text.toLong(); |
869 comm->number = m_lexer->token()->text.toLong(); |
| 862 m_lexer->mustGetNext (TK_Colon); |
870 m_lexer->mustGetNext (Token::Colon); |
| 863 |
871 |
| 864 // Name |
872 // Name |
| 865 m_lexer->mustGetNext (TK_Symbol); |
873 m_lexer->mustGetNext (Token::Symbol); |
| 866 comm->name = m_lexer->token()->text; |
874 comm->name = m_lexer->token()->text; |
| 867 |
875 |
| 868 // Arguments |
876 // Arguments |
| 869 m_lexer->mustGetNext (TK_ParenStart); |
877 m_lexer->mustGetNext (Token::ParenStart); |
| 870 comm->minargs = 0; |
878 comm->minargs = 0; |
| 871 |
879 |
| 872 while (m_lexer->peekNextType (TK_ParenEnd) == false) |
880 while (m_lexer->peekNextType (Token::ParenEnd) == false) |
| 873 { |
881 { |
| 874 if (comm->args.isEmpty() == false) |
882 if (comm->args.isEmpty() == false) |
| 875 m_lexer->mustGetNext (TK_Comma); |
883 m_lexer->mustGetNext (Token::Comma); |
| 876 |
884 |
| 877 CommandArgument arg; |
885 CommandArgument arg; |
| 878 m_lexer->mustGetAnyOf ({TK_Int,TK_Bool,TK_Str}); |
886 m_lexer->mustGetAnyOf ({Token::Int,Token::Bool,Token::Str}); |
| 879 DataType type = getTypeByName (m_lexer->token()->text); // TODO |
887 DataType type = getTypeByName (m_lexer->token()->text); // TODO |
| 880 ASSERT_NE (type, -1) |
888 ASSERT_NE (type, -1) |
| 881 ASSERT_NE (type, TYPE_Void) |
889 ASSERT_NE (type, TYPE_Void) |
| 882 arg.type = type; |
890 arg.type = type; |
| 883 |
891 |
| 884 m_lexer->mustGetNext (TK_Symbol); |
892 m_lexer->mustGetNext (Token::Symbol); |
| 885 arg.name = m_lexer->token()->text; |
893 arg.name = m_lexer->token()->text; |
| 886 |
894 |
| 887 // If this is an optional parameter, we need the default value. |
895 // If this is an optional parameter, we need the default value. |
| 888 if (comm->minargs < comm->args.size() || m_lexer->peekNextType (TK_Assign)) |
896 if (comm->minargs < comm->args.size() or m_lexer->peekNextType (Token::Assign)) |
| 889 { |
897 { |
| 890 m_lexer->mustGetNext (TK_Assign); |
898 m_lexer->mustGetNext (Token::Assign); |
| 891 |
899 |
| 892 switch (type) |
900 switch (type) |
| 893 { |
901 { |
| 894 case TYPE_Int: |
902 case TYPE_Int: |
| 895 case TYPE_Bool: |
903 case TYPE_Bool: |
| 896 m_lexer->mustGetNext (TK_Number); |
904 m_lexer->mustGetNext (Token::Number); |
| 897 break; |
905 break; |
| 898 |
906 |
| 899 case TYPE_String: |
907 case TYPE_String: |
| 900 error ("string arguments cannot have default values"); |
908 error ("string arguments cannot have default values"); |
| 901 |
909 |
| 925 { |
933 { |
| 926 checkToplevel(); |
934 checkToplevel(); |
| 927 m_lexer->mustGetSymbol ("zandronum"); |
935 m_lexer->mustGetSymbol ("zandronum"); |
| 928 String versionText; |
936 String versionText; |
| 929 |
937 |
| 930 while (m_lexer->next() && (m_lexer->tokenType() == TK_Number || m_lexer->tokenType() == TK_Dot)) |
938 while (m_lexer->next() and (m_lexer->tokenType() == Token::Number or m_lexer->tokenType() == Token::Dot)) |
| 931 versionText += getTokenString(); |
939 versionText += getTokenString(); |
| 932 |
940 |
| 933 // Note: at this point the lexer's pointing at the token after the version. |
941 // Note: at this point the lexer's pointing at the token after the version. |
| 934 if (versionText.isEmpty()) |
942 if (versionText.isEmpty()) |
| 935 error ("expected version string, got `%1`", getTokenString()); |
943 error ("expected version string, got `%1`", getTokenString()); |
| |
944 |
| 936 if (g_validZandronumVersions.contains (versionText) == false) |
945 if (g_validZandronumVersions.contains (versionText) == false) |
| 937 error ("unknown version string `%2`: valid versions: `%1`\n", g_validZandronumVersions, versionText); |
946 error ("unknown version string `%2`: valid versions: `%1`\n", g_validZandronumVersions, versionText); |
| 938 |
947 |
| 939 StringList versionTokens = versionText.split ("."); |
948 StringList versionTokens = versionText.split ("."); |
| 940 m_zandronumVersion = versionTokens[0].toLong() * 10000 + versionTokens[1].toLong() * 100; |
949 m_zandronumVersion = versionTokens[0].toLong() * 10000 + versionTokens[1].toLong() * 100; |
| 941 m_defaultZandronumVersion = false; |
950 m_defaultZandronumVersion = false; |
| 942 m_lexer->tokenMustBe (TK_Semicolon); |
951 m_lexer->tokenMustBe (Token::Semicolon); |
| 943 } |
952 } |
| 944 |
953 |
| 945 // ============================================================================/ |
954 // ============================================================================/ |
| 946 // |
955 // |
| 947 // Parses a command call |
956 // Parses a command call |
| 948 // |
957 // |
| 949 DataBuffer* BotscriptParser::parseCommand (CommandInfo* comm) |
958 DataBuffer* BotscriptParser::parseCommand (CommandInfo* comm) |
| 950 { |
959 { |
| 951 DataBuffer* r = new DataBuffer (64); |
960 DataBuffer* r = new DataBuffer (64); |
| 952 |
961 |
| 953 if (m_currentMode == PARSERMODE_TopLevel && comm->returnvalue == TYPE_Void) |
962 if (m_currentMode == PARSERMODE_TopLevel and comm->returnvalue == TYPE_Void) |
| 954 error ("command call at top level"); |
963 error ("command call at top level"); |
| 955 |
964 |
| 956 m_lexer->mustGetNext (TK_ParenStart); |
965 m_lexer->mustGetNext (Token::ParenStart); |
| 957 m_lexer->mustGetNext (TK_Any); |
966 m_lexer->mustGetNext (Token::Any); |
| 958 |
967 |
| 959 int curarg = 0; |
968 int curarg = 0; |
| 960 |
969 |
| 961 for (;;) |
970 for (;;) |
| 962 { |
971 { |
| 963 if (tokenIs (TK_ParenEnd)) |
972 if (tokenIs (Token::ParenEnd)) |
| 964 { |
973 { |
| 965 if (curarg < comm->minargs) |
974 if (curarg < comm->minargs) |
| |
975 { |
| 966 error ("too few arguments passed to %1\n\tusage is: %2", |
976 error ("too few arguments passed to %1\n\tusage is: %2", |
| 967 comm->name, comm->signature()); |
977 comm->name, comm->signature()); |
| |
978 } |
| 968 |
979 |
| 969 break; |
980 break; |
| 970 } |
981 } |
| 971 |
982 |
| 972 if (curarg >= comm->args.size()) |
983 if (curarg >= comm->args.size()) |
| 973 error ("too many arguments (%3) passed to %1\n\tusage is: %2", |
984 error ("too many arguments (%3) passed to %1\n\tusage is: %2", |
| 974 comm->name, comm->signature()); |
985 comm->name, comm->signature()); |
| 975 |
986 |
| 976 r->mergeAndDestroy (parseExpression (comm->args[curarg].type, true)); |
987 r->mergeAndDestroy (parseExpression (comm->args[curarg].type, true)); |
| 977 m_lexer->mustGetNext (TK_Any); |
988 m_lexer->mustGetNext (Token::Any); |
| 978 |
989 |
| 979 if (curarg < comm->minargs - 1) |
990 if (curarg < comm->minargs - 1) |
| 980 { |
991 { |
| 981 m_lexer->tokenMustBe (TK_Comma); |
992 m_lexer->tokenMustBe (Token::Comma); |
| 982 m_lexer->mustGetNext (TK_Any); |
993 m_lexer->mustGetNext (Token::Any); |
| 983 } |
994 } |
| 984 else if (curarg < comm->args.size() - 1) |
995 else if (curarg < comm->args.size() - 1) |
| 985 { |
996 { |
| 986 // Can continue, but can terminate as well. |
997 // Can continue, but can terminate as well. |
| 987 if (tokenIs (TK_ParenEnd)) |
998 if (tokenIs (Token::ParenEnd)) |
| 988 { |
999 { |
| 989 curarg++; |
1000 curarg++; |
| 990 break; |
1001 break; |
| 991 } |
1002 } |
| 992 else |
1003 else |
| 993 { |
1004 { |
| 994 m_lexer->tokenMustBe (TK_Comma); |
1005 m_lexer->tokenMustBe (Token::Comma); |
| 995 m_lexer->mustGetNext (TK_Any); |
1006 m_lexer->mustGetNext (Token::Any); |
| 996 } |
1007 } |
| 997 } |
1008 } |
| 998 |
1009 |
| 999 curarg++; |
1010 curarg++; |
| 1000 } |
1011 } |
| 1001 |
1012 |
| 1002 // If the script skipped any optional arguments, fill in defaults. |
1013 // If the script skipped any optional arguments, fill in defaults. |
| 1003 while (curarg < comm->args.size()) |
1014 while (curarg < comm->args.size()) |
| 1004 { |
1015 { |
| 1005 r->writeDWord (DH_PushNumber); |
1016 r->writeDWord (DataHeader::PushNumber); |
| 1006 r->writeDWord (comm->args[curarg].defvalue); |
1017 r->writeDWord (comm->args[curarg].defvalue); |
| 1007 curarg++; |
1018 curarg++; |
| 1008 } |
1019 } |
| 1009 |
1020 |
| 1010 r->writeDWord (DH_Command); |
1021 r->writeDWord (DataHeader::Command); |
| 1011 r->writeDWord (comm->number); |
1022 r->writeDWord (comm->number); |
| 1012 r->writeDWord (comm->args.size()); |
1023 r->writeDWord (comm->args.size()); |
| 1013 |
1024 |
| 1014 return r; |
1025 return r; |
| 1015 } |
1026 } |
| 1016 |
1027 |
| 1017 // ============================================================================ |
1028 // ============================================================================ |
| 1018 // |
1029 // |
| 1019 String BotscriptParser::parseFloat() |
1030 String BotscriptParser::parseFloat() |
| 1020 { |
1031 { |
| 1021 m_lexer->tokenMustBe (TK_Number); |
1032 m_lexer->tokenMustBe (Token::Number); |
| 1022 String floatstring = getTokenString(); |
1033 String floatstring = getTokenString(); |
| 1023 Lexer::TokenInfo tok; |
1034 Lexer::TokenInfo tok; |
| 1024 |
1035 |
| 1025 // Go after the decimal point |
1036 // Go after the decimal point |
| 1026 if (m_lexer->peekNext (&tok) && tok.type ==TK_Dot) |
1037 if (m_lexer->peekNext (&tok) and tok.type ==Token::Dot) |
| 1027 { |
1038 { |
| 1028 m_lexer->skip(); |
1039 m_lexer->skip(); |
| 1029 m_lexer->mustGetNext (TK_Number); |
1040 m_lexer->mustGetNext (Token::Number); |
| 1030 floatstring += "."; |
1041 floatstring += "."; |
| 1031 floatstring += getTokenString(); |
1042 floatstring += getTokenString(); |
| 1032 } |
1043 } |
| 1033 |
1044 |
| 1034 return floatstring; |
1045 return floatstring; |
| 1038 // |
1049 // |
| 1039 // Parses an assignment operator. |
1050 // Parses an assignment operator. |
| 1040 // |
1051 // |
| 1041 AssignmentOperator BotscriptParser::parseAssignmentOperator() |
1052 AssignmentOperator BotscriptParser::parseAssignmentOperator() |
| 1042 { |
1053 { |
| 1043 const List<ETokenType> tokens = |
1054 const List<Token> tokens = |
| 1044 { |
1055 { |
| 1045 TK_Assign, |
1056 Token::Assign, |
| 1046 TK_AddAssign, |
1057 Token::AddAssign, |
| 1047 TK_SubAssign, |
1058 Token::SubAssign, |
| 1048 TK_MultiplyAssign, |
1059 Token::MultiplyAssign, |
| 1049 TK_DivideAssign, |
1060 Token::DivideAssign, |
| 1050 TK_ModulusAssign, |
1061 Token::ModulusAssign, |
| 1051 TK_DoublePlus, |
1062 Token::DoublePlus, |
| 1052 TK_DoubleMinus, |
1063 Token::DoubleMinus, |
| 1053 }; |
1064 }; |
| 1054 |
1065 |
| 1055 m_lexer->mustGetAnyOf (tokens); |
1066 m_lexer->mustGetAnyOf (tokens); |
| 1056 |
1067 |
| 1057 switch (m_lexer->tokenType()) |
1068 switch (m_lexer->tokenType()) |
| 1058 { |
1069 { |
| 1059 case TK_Assign: return ASSIGNOP_Assign; |
1070 case Token::Assign: return ASSIGNOP_Assign; |
| 1060 case TK_AddAssign: return ASSIGNOP_Add; |
1071 case Token::AddAssign: return ASSIGNOP_Add; |
| 1061 case TK_SubAssign: return ASSIGNOP_Subtract; |
1072 case Token::SubAssign: return ASSIGNOP_Subtract; |
| 1062 case TK_MultiplyAssign: return ASSIGNOP_Multiply; |
1073 case Token::MultiplyAssign: return ASSIGNOP_Multiply; |
| 1063 case TK_DivideAssign: return ASSIGNOP_Divide; |
1074 case Token::DivideAssign: return ASSIGNOP_Divide; |
| 1064 case TK_ModulusAssign: return ASSIGNOP_Modulus; |
1075 case Token::ModulusAssign: return ASSIGNOP_Modulus; |
| 1065 case TK_DoublePlus: return ASSIGNOP_Increase; |
1076 case Token::DoublePlus: return ASSIGNOP_Increase; |
| 1066 case TK_DoubleMinus: return ASSIGNOP_Decrease; |
1077 case Token::DoubleMinus: return ASSIGNOP_Decrease; |
| 1067 default: break; |
1078 default: break; |
| 1068 } |
1079 } |
| 1069 |
1080 |
| 1070 error ("WTF bad operator token %1", m_lexer->describeToken (m_lexer->token())); |
1081 error ("WTF bad operator token %1", m_lexer->describeToken (m_lexer->token())); |
| 1071 return (AssignmentOperator) 0; |
1082 return (AssignmentOperator) 0; |
| 1081 DataHeader array; |
1092 DataHeader array; |
| 1082 }; |
1093 }; |
| 1083 |
1094 |
| 1084 const AssignmentDataHeaderInfo gAssignmentDataHeaders[] = |
1095 const AssignmentDataHeaderInfo gAssignmentDataHeaders[] = |
| 1085 { |
1096 { |
| 1086 { ASSIGNOP_Assign, DH_AssignLocalVar, DH_AssignGlobalVar, DH_AssignGlobalArray }, |
1097 { ASSIGNOP_Assign, DataHeader::AssignLocalVar, DataHeader::AssignGlobalVar, |
| 1087 { ASSIGNOP_Add, DH_AddLocalVar, DH_AddGlobalVar, DH_AddGlobalArray }, |
1098 DataHeader::AssignGlobalArray }, |
| 1088 { ASSIGNOP_Subtract, DH_SubtractLocalVar, DH_SubtractGlobalVar, DH_SubtractGlobalArray }, |
1099 { ASSIGNOP_Add, DataHeader::AddLocalVar, DataHeader::AddGlobalVar, |
| 1089 { ASSIGNOP_Multiply, DH_MultiplyLocalVar, DH_MultiplyGlobalVar, DH_MultiplyGlobalArray }, |
1100 DataHeader::AddGlobalArray }, |
| 1090 { ASSIGNOP_Divide, DH_DivideLocalVar, DH_DivideGlobalVar, DH_DivideGlobalArray }, |
1101 { ASSIGNOP_Subtract, DataHeader::SubtractLocalVar, DataHeader::SubtractGlobalVar, |
| 1091 { ASSIGNOP_Modulus, DH_ModLocalVar, DH_ModGlobalVar, DH_ModGlobalArray }, |
1102 DataHeader::SubtractGlobalArray }, |
| 1092 { ASSIGNOP_Increase, DH_IncreaseLocalVar, DH_IncreaseGlobalVar, DH_IncreaseGlobalArray }, |
1103 { ASSIGNOP_Multiply, DataHeader::MultiplyLocalVar, DataHeader::MultiplyGlobalVar, |
| 1093 { ASSIGNOP_Decrease, DH_DecreaseLocalVar, DH_DecreaseGlobalVar, DH_DecreaseGlobalArray }, |
1104 DataHeader::MultiplyGlobalArray }, |
| |
1105 { ASSIGNOP_Divide, DataHeader::DivideLocalVar, DataHeader::DivideGlobalVar, |
| |
1106 DataHeader::DivideGlobalArray }, |
| |
1107 { ASSIGNOP_Modulus, DataHeader::ModLocalVar, DataHeader::ModGlobalVar, |
| |
1108 DataHeader::ModGlobalArray }, |
| |
1109 { ASSIGNOP_Increase, DataHeader::IncreaseLocalVar, DataHeader::IncreaseGlobalVar, |
| |
1110 DataHeader::IncreaseGlobalArray }, |
| |
1111 { ASSIGNOP_Decrease, DataHeader::DecreaseLocalVar, DataHeader::DecreaseGlobalVar, |
| |
1112 DataHeader::DecreaseGlobalArray }, |
| 1094 }; |
1113 }; |
| 1095 |
1114 |
| 1096 DataHeader BotscriptParser::getAssigmentDataHeader (AssignmentOperator op, Variable* var) |
1115 DataHeader BotscriptParser::getAssigmentDataHeader (AssignmentOperator op, Variable* var) |
| 1097 { |
1116 { |
| 1098 for (const auto& a : gAssignmentDataHeaders) |
1117 for (const auto& a : gAssignmentDataHeaders) |
| 1144 |
1163 |
| 1145 if (var->isarray) |
1164 if (var->isarray) |
| 1146 retbuf->mergeAndDestroy (arrayindex); |
1165 retbuf->mergeAndDestroy (arrayindex); |
| 1147 |
1166 |
| 1148 // Parse the right operand |
1167 // Parse the right operand |
| 1149 if (oper != ASSIGNOP_Increase && oper != ASSIGNOP_Decrease) |
1168 if (oper != ASSIGNOP_Increase and oper != ASSIGNOP_Decrease) |
| 1150 { |
1169 { |
| 1151 DataBuffer* expr = parseExpression (var->type); |
1170 DataBuffer* expr = parseExpression (var->type); |
| 1152 retbuf->mergeAndDestroy (expr); |
1171 retbuf->mergeAndDestroy (expr); |
| 1153 } |
1172 } |
| 1154 |
1173 |
| 1155 #if 0 |
1174 #if 0 |
| 1156 // <<= and >>= do not have data headers. Solution: expand them. |
1175 // <<= and >>= do not have data headers. Solution: expand them. |
| 1157 // a <<= b -> a = a << b |
1176 // a <<= b -> a = a << b |
| 1158 // a >>= b -> a = a >> b |
1177 // a >>= b -> a = a >> b |
| 1159 retbuf->WriteDWord (var->IsGlobal() ? DH_PushGlobalVar : DH_PushLocalVar); |
1178 retbuf->WriteDWord (var->IsGlobal() ? DataHeader::PushGlobalVar : DataHeader::PushLocalVar); |
| 1160 retbuf->WriteDWord (var->index); |
1179 retbuf->WriteDWord (var->index); |
| 1161 retbuf->MergeAndDestroy (expr); |
1180 retbuf->MergeAndDestroy (expr); |
| 1162 retbuf->WriteDWord ((oper == OPER_ASSIGNLEFTSHIFT) ? DH_LeftShift : DH_RightShift); |
1181 retbuf->WriteDWord ((oper == OPER_ASSIGNLEFTSHIFT) ? DataHeader::LeftShift : |
| 1163 retbuf->WriteDWord (var->IsGlobal() ? DH_AssignGlobalVar : DH_AssignLocalVar); |
1182 DataHeader::RightShift); |
| |
1183 retbuf->WriteDWord (var->IsGlobal() ? DataHeader::AssignGlobalVar : DataHeader::AssignLocalVar); |
| 1164 retbuf->WriteDWord (var->index); |
1184 retbuf->WriteDWord (var->index); |
| 1165 #endif |
1185 #endif |
| 1166 |
1186 |
| 1167 DataHeader dh = getAssigmentDataHeader (oper, var); |
1187 DataHeader dh = getAssigmentDataHeader (oper, var); |
| 1168 retbuf->writeDWord (dh); |
1188 retbuf->writeDWord (dh); |
| 1358 if (fp == null) |
1378 if (fp == null) |
| 1359 error ("couldn't open %1 for writing: %2", outfile, strerror (errno)); |
1379 error ("couldn't open %1 for writing: %2", outfile, strerror (errno)); |
| 1360 |
1380 |
| 1361 // First, resolve references |
1381 // First, resolve references |
| 1362 for (MarkReference* ref : m_mainBuffer->references()) |
1382 for (MarkReference* ref : m_mainBuffer->references()) |
| |
1383 { |
| 1363 for (int i = 0; i < 4; ++i) |
1384 for (int i = 0; i < 4; ++i) |
| 1364 m_mainBuffer->buffer()[ref->pos + i] = (ref->target->pos >> (8 * i)) & 0xFF; |
1385 m_mainBuffer->buffer()[ref->pos + i] = (ref->target->pos >> (8 * i)) & 0xFF; |
| |
1386 } |
| 1365 |
1387 |
| 1366 // Then, dump the main buffer to the file |
1388 // Then, dump the main buffer to the file |
| 1367 fwrite (m_mainBuffer->buffer(), 1, m_mainBuffer->writtenSize(), fp); |
1389 fwrite (m_mainBuffer->buffer(), 1, m_mainBuffer->writtenSize(), fp); |
| 1368 print ("-- %1 byte%s1 written to %2\n", m_mainBuffer->writtenSize(), outfile); |
1390 print ("-- %1 byte%s1 written to %2\n", m_mainBuffer->writtenSize(), outfile); |
| 1369 fclose (fp); |
1391 fclose (fp); |