|     24 	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
    24 	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
|     25 	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 
    25 	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 
|     26 	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
    26 	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|     27 */ | 
    27 */ | 
|     28  | 
    28  | 
|         | 
    29 #include <cstring> | 
|     29 #include "parser.h" | 
    30 #include "parser.h" | 
|     30 #include "events.h" | 
    31 #include "events.h" | 
|     31 #include "commands.h" | 
    32 #include "commands.h" | 
|     32 #include "stringTable.h" | 
    33 #include "stringTable.h" | 
|     33 #include "list.h" | 
    34 #include "list.h" | 
|     47 	m_onenterBuffer (new DataBuffer), | 
    48 	m_onenterBuffer (new DataBuffer), | 
|     48 	m_mainLoopBuffer (new DataBuffer), | 
    49 	m_mainLoopBuffer (new DataBuffer), | 
|     49 	m_lexer (new Lexer), | 
    50 	m_lexer (new Lexer), | 
|     50 	m_numStates (0), | 
    51 	m_numStates (0), | 
|     51 	m_numEvents (0), | 
    52 	m_numEvents (0), | 
|     52 	m_currentMode (PARSERMODE_TopLevel), | 
    53 	m_currentMode (ParserMode::TopLevel), | 
|     53 	m_isStateSpawnDefined (false), | 
    54 	m_isStateSpawnDefined (false), | 
|     54 	m_gotMainLoop (false), | 
    55 	m_gotMainLoop (false), | 
|     55 	m_scopeCursor (-1), | 
    56 	m_scopeCursor (-1), | 
|     56 	m_isElseAllowed (false), | 
    57 	m_isElseAllowed (false), | 
|     57 	m_highestGlobalVarIndex (0), | 
    58 	m_highestGlobalVarIndex (0), | 
|     68  | 
    69  | 
|     69 // ============================================================================ | 
    70 // ============================================================================ | 
|     70 // | 
    71 // | 
|     71 void BotscriptParser::checkToplevel() | 
    72 void BotscriptParser::checkToplevel() | 
|     72 { | 
    73 { | 
|     73 	if (m_currentMode != PARSERMODE_TopLevel) | 
    74 	if (m_currentMode != ParserMode::TopLevel) | 
|     74 		error ("%1-statements may only be defined at top level!", getTokenString()); | 
    75 		error ("%1-statements may only be defined at top level!", getTokenString()); | 
|     75 } | 
    76 } | 
|     76  | 
    77  | 
|     77 // ============================================================================ | 
    78 // ============================================================================ | 
|     78 // | 
    79 // | 
|     79 void BotscriptParser::checkNotToplevel() | 
    80 void BotscriptParser::checkNotToplevel() | 
|     80 { | 
    81 { | 
|     81 	if (m_currentMode == PARSERMODE_TopLevel) | 
    82 	if (m_currentMode == ParserMode::TopLevel) | 
|     82 		error ("%1-statements must not be defined at top level!", getTokenString()); | 
    83 		error ("%1-statements must not be defined at top level!", getTokenString()); | 
|     83 } | 
    84 } | 
|     84  | 
    85  | 
|     85 // ============================================================================ | 
    86 // ============================================================================ | 
|     86 // | 
    87 // | 
|    213 			} | 
   214 			} | 
|    214 		} | 
   215 		} | 
|    215 	} | 
   216 	} | 
|    216  | 
   217  | 
|    217 	// Script file ended. Do some last checks and write the last things to main buffer | 
   218 	// Script file ended. Do some last checks and write the last things to main buffer | 
|    218 	if (m_currentMode != PARSERMODE_TopLevel) | 
   219 	if (m_currentMode != ParserMode::TopLevel) | 
|    219 		error ("script did not end at top level; a `}` is missing somewhere"); | 
   220 		error ("script did not end at top level; a `}` is missing somewhere"); | 
|    220  | 
   221  | 
|    221 	if (isReadOnly() == false) | 
   222 	if (isReadOnly() == false) | 
|    222 	{ | 
   223 	{ | 
|    223 		// stateSpawn must be defined! | 
   224 		// stateSpawn must be defined! | 
|    263 	// write the previous state's onenter and | 
   264 	// write the previous state's onenter and | 
|    264 	// mainloop buffers to file now | 
   265 	// mainloop buffers to file now | 
|    265 	if (m_currentState.isEmpty() == false) | 
   266 	if (m_currentState.isEmpty() == false) | 
|    266 		writeMemberBuffers(); | 
   267 		writeMemberBuffers(); | 
|    267  | 
   268  | 
|    268 	currentBuffer()->writeDWord (DataHeader::StateName); | 
   269 	currentBuffer()->writeHeader (DataHeader::StateName); | 
|    269 	currentBuffer()->writeString (statename); | 
   270 	currentBuffer()->writeString (statename); | 
|    270 	currentBuffer()->writeDWord (DataHeader::StateIndex); | 
   271 	currentBuffer()->writeHeader (DataHeader::StateIndex); | 
|    271 	currentBuffer()->writeDWord (m_numStates); | 
   272 	currentBuffer()->writeDWord (m_numStates); | 
|    272  | 
   273  | 
|    273 	m_numStates++; | 
   274 	m_numStates++; | 
|    274 	m_currentState = statename; | 
   275 	m_currentState = statename; | 
|    275 	m_gotMainLoop = false; | 
   276 	m_gotMainLoop = false; | 
|    286  | 
   287  | 
|    287 	if (e == null) | 
   288 	if (e == null) | 
|    288 		error ("bad event, got `%1`\n", getTokenString()); | 
   289 		error ("bad event, got `%1`\n", getTokenString()); | 
|    289  | 
   290  | 
|    290 	m_lexer->mustGetNext (Token::BraceStart); | 
   291 	m_lexer->mustGetNext (Token::BraceStart); | 
|    291 	m_currentMode = PARSERMODE_Event; | 
   292 	m_currentMode = ParserMode::Event; | 
|    292 	currentBuffer()->writeDWord (DataHeader::Event); | 
   293 	currentBuffer()->writeHeader (DataHeader::Event); | 
|    293 	currentBuffer()->writeDWord (e->number); | 
   294 	currentBuffer()->writeDWord (e->number); | 
|    294 	m_numEvents++; | 
   295 	m_numEvents++; | 
|    295 } | 
   296 } | 
|    296  | 
   297  | 
|    297 // ============================================================================ | 
   298 // ============================================================================ | 
|    299 void BotscriptParser::parseMainloop() | 
   300 void BotscriptParser::parseMainloop() | 
|    300 { | 
   301 { | 
|    301 	checkToplevel(); | 
   302 	checkToplevel(); | 
|    302 	m_lexer->mustGetNext (Token::BraceStart); | 
   303 	m_lexer->mustGetNext (Token::BraceStart); | 
|    303  | 
   304  | 
|    304 	m_currentMode = PARSERMODE_MainLoop; | 
   305 	m_currentMode = ParserMode::MainLoop; | 
|    305 	m_mainLoopBuffer->writeDWord (DataHeader::MainLoop); | 
   306 	m_mainLoopBuffer->writeHeader (DataHeader::MainLoop); | 
|    306 } | 
   307 } | 
|    307  | 
   308  | 
|    308 // ============================================================================ | 
   309 // ============================================================================ | 
|    309 // | 
   310 // | 
|    310 void BotscriptParser::parseOnEnterExit() | 
   311 void BotscriptParser::parseOnEnterExit() | 
|    311 { | 
   312 { | 
|    312 	checkToplevel(); | 
   313 	checkToplevel(); | 
|    313 	bool onenter = (tokenIs (Token::Onenter)); | 
   314 	bool onenter = (tokenIs (Token::Onenter)); | 
|    314 	m_lexer->mustGetNext (Token::BraceStart); | 
   315 	m_lexer->mustGetNext (Token::BraceStart); | 
|    315  | 
   316 	m_currentMode = onenter ? ParserMode::Onenter : ParserMode::Onexit; | 
|    316 	m_currentMode = onenter ? PARSERMODE_Onenter : PARSERMODE_Onexit; | 
   317 	currentBuffer()->writeHeader (onenter ? DataHeader::OnEnter : DataHeader::OnExit); | 
|    317 	currentBuffer()->writeDWord (onenter ? DataHeader::OnEnter : DataHeader::OnExit); | 
        | 
|    318 } | 
   318 } | 
|    319  | 
   319  | 
|    320 // ============================================================================ | 
   320 // ============================================================================ | 
|    321 // | 
   321 // | 
|    322 void BotscriptParser::parseVar() | 
   322 void BotscriptParser::parseVar() | 
|    408 	else | 
   408 	else | 
|    409 		SCOPE(0).localVariables << var; | 
   409 		SCOPE(0).localVariables << var; | 
|    410  | 
   410  | 
|    411 	suggestHighestVarIndex (isInGlobalState(), var->index); | 
   411 	suggestHighestVarIndex (isInGlobalState(), var->index); | 
|    412 	m_lexer->mustGetNext (Token::Semicolon); | 
   412 	m_lexer->mustGetNext (Token::Semicolon); | 
|    413 	print ("Declared %3 variable #%1 $%2\n", var->index, var->name, isInGlobalState() ? "global" : "state-local"); | 
   413 	print ("Declared %3 variable #%1 $%2\n", var->index, var->name, isInGlobalState() ? "global" :  | 
|         | 
   414 "state-local"); | 
|    414 } | 
   415 } | 
|    415  | 
   416  | 
|    416 // ============================================================================ | 
   417 // ============================================================================ | 
|    417 // | 
   418 // | 
|    418 void BotscriptParser::parseIf() | 
   419 void BotscriptParser::parseIf() | 
|    434 	// Upon a closing brace, the mark will be adjusted. | 
   435 	// Upon a closing brace, the mark will be adjusted. | 
|    435 	ByteMark* mark = currentBuffer()->addMark (""); | 
   436 	ByteMark* mark = currentBuffer()->addMark (""); | 
|    436  | 
   437  | 
|    437 	// Use DataHeader::IfNotGoto - if the expression is not true, we goto the mark | 
   438 	// Use DataHeader::IfNotGoto - if the expression is not true, we goto the mark | 
|    438 	// we just defined - and this mark will be at the end of the scope block. | 
   439 	// we just defined - and this mark will be at the end of the scope block. | 
|    439 	currentBuffer()->writeDWord (DataHeader::IfNotGoto); | 
   440 	currentBuffer()->writeHeader (DataHeader::IfNotGoto); | 
|    440 	currentBuffer()->addReference (mark); | 
   441 	currentBuffer()->addReference (mark); | 
|    441  | 
   442  | 
|    442 	// Store it | 
   443 	// Store it | 
|    443 	SCOPE (0).mark1 = mark; | 
   444 	SCOPE (0).mark1 = mark; | 
|    444 	SCOPE (0).type = SCOPE_If; | 
   445 	SCOPE (0).type = SCOPE_If; | 
|    458 	// write down to jump to the end of the else statement | 
   459 	// write down to jump to the end of the else statement | 
|    459 	// Otherwise we have fall-throughs | 
   460 	// Otherwise we have fall-throughs | 
|    460 	SCOPE (0).mark2 = currentBuffer()->addMark (""); | 
   461 	SCOPE (0).mark2 = currentBuffer()->addMark (""); | 
|    461  | 
   462  | 
|    462 	// Instruction to jump to the end after if block is complete | 
   463 	// Instruction to jump to the end after if block is complete | 
|    463 	currentBuffer()->writeDWord (DataHeader::Goto); | 
   464 	currentBuffer()->writeHeader (DataHeader::Goto); | 
|    464 	currentBuffer()->addReference (SCOPE (0).mark2); | 
   465 	currentBuffer()->addReference (SCOPE (0).mark2); | 
|    465  | 
   466  | 
|    466 	// Move the ifnot mark here and set type to else | 
   467 	// Move the ifnot mark here and set type to else | 
|    467 	currentBuffer()->adjustMark (SCOPE (0).mark1); | 
   468 	currentBuffer()->adjustMark (SCOPE (0).mark1); | 
|    468 	SCOPE (0).type = SCOPE_Else; | 
   469 	SCOPE (0).type = SCOPE_Else; | 
|    490  | 
   491  | 
|    491 	// write condition | 
   492 	// write condition | 
|    492 	currentBuffer()->mergeAndDestroy (expr); | 
   493 	currentBuffer()->mergeAndDestroy (expr); | 
|    493  | 
   494  | 
|    494 	// Instruction to go to the end if it fails | 
   495 	// Instruction to go to the end if it fails | 
|    495 	currentBuffer()->writeDWord (DataHeader::IfNotGoto); | 
   496 	currentBuffer()->writeHeader (DataHeader::IfNotGoto); | 
|    496 	currentBuffer()->addReference (mark2); | 
   497 	currentBuffer()->addReference (mark2); | 
|    497  | 
   498  | 
|    498 	// Store the needed stuff | 
   499 	// Store the needed stuff | 
|    499 	SCOPE (0).mark1 = mark1; | 
   500 	SCOPE (0).mark1 = mark1; | 
|    500 	SCOPE (0).mark2 = mark2; | 
   501 	SCOPE (0).mark2 = mark2; | 
|    541 	ByteMark* mark1 = currentBuffer()->addMark (""); | 
   542 	ByteMark* mark1 = currentBuffer()->addMark (""); | 
|    542 	ByteMark* mark2 = currentBuffer()->addMark (""); | 
   543 	ByteMark* mark2 = currentBuffer()->addMark (""); | 
|    543  | 
   544  | 
|    544 	// Add the condition | 
   545 	// Add the condition | 
|    545 	currentBuffer()->mergeAndDestroy (cond); | 
   546 	currentBuffer()->mergeAndDestroy (cond); | 
|    546 	currentBuffer()->writeDWord (DataHeader::IfNotGoto); | 
   547 	currentBuffer()->writeHeader (DataHeader::IfNotGoto); | 
|    547 	currentBuffer()->addReference (mark2); | 
   548 	currentBuffer()->addReference (mark2); | 
|    548  | 
   549  | 
|    549 	// Store the marks and incrementor | 
   550 	// Store the marks and incrementor | 
|    550 	SCOPE (0).mark1 = mark1; | 
   551 	SCOPE (0).mark1 = mark1; | 
|    551 	SCOPE (0).mark2 = mark2; | 
   552 	SCOPE (0).mark2 = mark2; | 
|    621 	// of buffering setup and stuff like that. | 
   622 	// of buffering setup and stuff like that. | 
|    622 	// | 
   623 	// | 
|    623 	// We null the switch buffer for the case-go-to statement as | 
   624 	// We null the switch buffer for the case-go-to statement as | 
|    624 	// we want it all under the switch, not into the case-buffers. | 
   625 	// we want it all under the switch, not into the case-buffers. | 
|    625 	m_switchBuffer = null; | 
   626 	m_switchBuffer = null; | 
|    626 	currentBuffer()->writeDWord (DataHeader::CaseGoto); | 
   627 	currentBuffer()->writeHeader (DataHeader::CaseGoto); | 
|    627 	currentBuffer()->writeDWord (num); | 
   628 	currentBuffer()->writeDWord (num); | 
|    628 	addSwitchCase (null); | 
   629 	addSwitchCase (null); | 
|    629 	SCOPE (0).casecursor->number = num; | 
   630 	SCOPE (0).casecursor->number = num; | 
|    630 } | 
   631 } | 
|    631  | 
   632  | 
|    648 	// and is only popped when case succeeds, we have | 
   649 	// and is only popped when case succeeds, we have | 
|    649 	// to pop it with DataHeader::Drop manually if we end up in | 
   650 	// to pop it with DataHeader::Drop manually if we end up in | 
|    650 	// a default. | 
   651 	// a default. | 
|    651 	DataBuffer* buf = new DataBuffer; | 
   652 	DataBuffer* buf = new DataBuffer; | 
|    652 	SCOPE (0).buffer1 = buf; | 
   653 	SCOPE (0).buffer1 = buf; | 
|    653 	buf->writeDWord (DataHeader::Drop); | 
   654 	buf->writeHeader (DataHeader::Drop); | 
|    654 	buf->writeDWord (DataHeader::Goto); | 
   655 	buf->writeHeader (DataHeader::Goto); | 
|    655 	addSwitchCase (buf); | 
   656 	addSwitchCase (buf); | 
|    656 } | 
   657 } | 
|    657  | 
   658  | 
|    658 // ============================================================================ | 
   659 // ============================================================================ | 
|    659 // | 
   660 // | 
|    660 void BotscriptParser::parseBreak() | 
   661 void BotscriptParser::parseBreak() | 
|    661 { | 
   662 { | 
|    662 	if (m_scopeCursor == 0) | 
   663 	if (m_scopeCursor == 0) | 
|    663 		error ("unexpected `break`"); | 
   664 		error ("unexpected `break`"); | 
|    664  | 
   665  | 
|    665 	currentBuffer()->writeDWord (DataHeader::Goto); | 
   666 	currentBuffer()->writeHeader (DataHeader::Goto); | 
|    666  | 
   667  | 
|    667 	// switch and if use mark1 for the closing point, | 
   668 	// switch and if use mark1 for the closing point, | 
|    668 	// for and while use mark2. | 
   669 	// for and while use mark2. | 
|    669 	switch (SCOPE (0).type) | 
   670 	switch (SCOPE (0).type) | 
|    670 	{ | 
   671 	{ | 
|    750 			{	// write the incrementor at the end of the loop block | 
   751 			{	// write the incrementor at the end of the loop block | 
|    751 				currentBuffer()->mergeAndDestroy (SCOPE (0).buffer1); | 
   752 				currentBuffer()->mergeAndDestroy (SCOPE (0).buffer1); | 
|    752 			} | 
   753 			} | 
|    753 			case SCOPE_While: | 
   754 			case SCOPE_While: | 
|    754 			{	// write down the instruction to go back to the start of the loop | 
   755 			{	// write down the instruction to go back to the start of the loop | 
|    755 				currentBuffer()->writeDWord (DataHeader::Goto); | 
   756 				currentBuffer()->writeHeader (DataHeader::Goto); | 
|    756 				currentBuffer()->addReference (SCOPE (0).mark1); | 
   757 				currentBuffer()->addReference (SCOPE (0).mark1); | 
|    757  | 
   758  | 
|    758 				// Move the closing mark here since we're at the end of the while loop | 
   759 				// Move the closing mark here since we're at the end of the while loop | 
|    759 				currentBuffer()->adjustMark (SCOPE (0).mark2); | 
   760 				currentBuffer()->adjustMark (SCOPE (0).mark2); | 
|    760 				break; | 
   761 				break; | 
|    768 				m_lexer->mustGetNext (Token::ParenEnd); | 
   769 				m_lexer->mustGetNext (Token::ParenEnd); | 
|    769 				m_lexer->mustGetNext (Token::Semicolon); | 
   770 				m_lexer->mustGetNext (Token::Semicolon); | 
|    770  | 
   771  | 
|    771 				// If the condition runs true, go back to the start. | 
   772 				// If the condition runs true, go back to the start. | 
|    772 				currentBuffer()->mergeAndDestroy (expr); | 
   773 				currentBuffer()->mergeAndDestroy (expr); | 
|    773 				currentBuffer()->writeDWord (DataHeader::IfGoto); | 
   774 				currentBuffer()->writeHeader (DataHeader::IfGoto); | 
|    774 				currentBuffer()->addReference (SCOPE (0).mark1); | 
   775 				currentBuffer()->addReference (SCOPE (0).mark1); | 
|    775 				break; | 
   776 				break; | 
|    776 			} | 
   777 			} | 
|    777  | 
   778  | 
|    778 			case SCOPE_Switch: | 
   779 			case SCOPE_Switch: | 
|    789 				// the headers (thus won't fall-through if no case matched) | 
   790 				// the headers (thus won't fall-through if no case matched) | 
|    790 				if (SCOPE (0).buffer1) | 
   791 				if (SCOPE (0).buffer1) | 
|    791 					currentBuffer()->mergeAndDestroy (SCOPE (0).buffer1); | 
   792 					currentBuffer()->mergeAndDestroy (SCOPE (0).buffer1); | 
|    792 				else | 
   793 				else | 
|    793 				{ | 
   794 				{ | 
|    794 					currentBuffer()->writeDWord (DataHeader::Drop); | 
   795 					currentBuffer()->writeHeader (DataHeader::Drop); | 
|    795 					currentBuffer()->writeDWord (DataHeader::Goto); | 
   796 					currentBuffer()->writeHeader (DataHeader::Goto); | 
|    796 					currentBuffer()->addReference (SCOPE (0).mark1); | 
   797 					currentBuffer()->addReference (SCOPE (0).mark1); | 
|    797 				} | 
   798 				} | 
|    798  | 
   799  | 
|    799 				// Go through all of the buffers we | 
   800 				// Go through all of the buffers we | 
|    800 				// recorded down and write them. | 
   801 				// recorded down and write them. | 
|    816 		// Descend down the stack | 
   817 		// Descend down the stack | 
|    817 		m_scopeCursor--; | 
   818 		m_scopeCursor--; | 
|    818 		return; | 
   819 		return; | 
|    819 	} | 
   820 	} | 
|    820  | 
   821  | 
|    821 	int dataheader = (m_currentMode == PARSERMODE_Event) ? DataHeader::EndEvent | 
   822 	DataHeader dataheader = | 
|    822 				   : (m_currentMode == PARSERMODE_MainLoop) ? DataHeader::EndMainLoop | 
   823 		  (m_currentMode == ParserMode::Event) ? DataHeader::EndEvent | 
|    823 				   : (m_currentMode == PARSERMODE_Onenter) ? DataHeader::EndOnEnter | 
   824 		: (m_currentMode == ParserMode::MainLoop) ? DataHeader::EndMainLoop | 
|    824 				   : (m_currentMode == PARSERMODE_Onexit) ? DataHeader::EndOnExit | 
   825 		: (m_currentMode == ParserMode::Onenter) ? DataHeader::EndOnEnter | 
|    825 				   : -1; | 
   826 		: (m_currentMode == ParserMode::Onexit) ? DataHeader::EndOnExit | 
|    826  | 
   827 		: DataHeader::NumDataHeaders; | 
|    827 	if (dataheader == -1) | 
   828  | 
|         | 
   829 	if (dataheader == DataHeader::NumDataHeaders) | 
|    828 		error ("unexpected `}`"); | 
   830 		error ("unexpected `}`"); | 
|    829  | 
   831  | 
|    830 	// Data header must be written before mode is changed because | 
   832 	// Data header must be written before mode is changed because | 
|    831 	// onenter and mainloop go into special buffers, and we want | 
   833 	// onenter and mainloop go into special buffers, and we want | 
|    832 	// the closing data headers into said buffers too. | 
   834 	// the closing data headers into said buffers too. | 
|    833 	currentBuffer()->writeDWord (dataheader); | 
   835 	currentBuffer()->writeHeader (dataheader); | 
|    834 	m_currentMode = PARSERMODE_TopLevel; | 
   836 	m_currentMode = ParserMode::TopLevel; | 
|    835 	m_lexer->next (Token::Semicolon); | 
   837 	m_lexer->next (Token::Semicolon); | 
|    836 } | 
   838 } | 
|    837  | 
   839  | 
|    838 // ============================================================================= | 
   840 // ============================================================================= | 
|    839 // | 
   841 // | 
|    933 { | 
   935 { | 
|    934 	checkToplevel(); | 
   936 	checkToplevel(); | 
|    935 	m_lexer->mustGetSymbol ("zandronum"); | 
   937 	m_lexer->mustGetSymbol ("zandronum"); | 
|    936 	String versionText; | 
   938 	String versionText; | 
|    937  | 
   939  | 
|    938 	while (m_lexer->next() and (m_lexer->tokenType() == Token::Number or m_lexer->tokenType() == Token::Dot)) | 
   940 	while (m_lexer->next() and (m_lexer->tokenType() == Token::Number or m_lexer->tokenType() ==  | 
|         | 
   941 Token::Dot)) | 
|    939 		versionText += getTokenString(); | 
   942 		versionText += getTokenString(); | 
|    940  | 
   943  | 
|    941 	// Note: at this point the lexer's pointing at the token after the version. | 
   944 	// Note: at this point the lexer's pointing at the token after the version. | 
|    942 	if (versionText.isEmpty()) | 
   945 	if (versionText.isEmpty()) | 
|    943 		error ("expected version string, got `%1`", getTokenString()); | 
   946 		error ("expected version string, got `%1`", getTokenString()); | 
|    944  | 
   947  | 
|    945 	if (g_validZandronumVersions.contains (versionText) == false) | 
   948 	if (g_validZandronumVersions.contains (versionText) == false) | 
|    946 		error ("unknown version string `%2`: valid versions: `%1`\n", g_validZandronumVersions, versionText); | 
   949 		error ("unknown version string `%2`: valid versions: `%1`\n", g_validZandronumVersions,  | 
|         | 
   950 versionText); | 
|    947  | 
   951  | 
|    948 	StringList versionTokens = versionText.split ("."); | 
   952 	StringList versionTokens = versionText.split ("."); | 
|    949 	m_zandronumVersion = versionTokens[0].toLong() * 10000 + versionTokens[1].toLong() * 100; | 
   953 	m_zandronumVersion = versionTokens[0].toLong() * 10000 + versionTokens[1].toLong() * 100; | 
|    950 	m_defaultZandronumVersion = false; | 
   954 	m_defaultZandronumVersion = false; | 
|    951 	m_lexer->tokenMustBe (Token::Semicolon); | 
   955 	m_lexer->tokenMustBe (Token::Semicolon); | 
|    957 // | 
   961 // | 
|    958 DataBuffer* BotscriptParser::parseCommand (CommandInfo* comm) | 
   962 DataBuffer* BotscriptParser::parseCommand (CommandInfo* comm) | 
|    959 { | 
   963 { | 
|    960 	DataBuffer* r = new DataBuffer (64); | 
   964 	DataBuffer* r = new DataBuffer (64); | 
|    961  | 
   965  | 
|    962 	if (m_currentMode == PARSERMODE_TopLevel and comm->returnvalue == TYPE_Void) | 
   966 	if (m_currentMode == ParserMode::TopLevel and comm->returnvalue == TYPE_Void) | 
|    963 		error ("command call at top level"); | 
   967 		error ("command call at top level"); | 
|    964  | 
   968  | 
|    965 	m_lexer->mustGetNext (Token::ParenStart); | 
   969 	m_lexer->mustGetNext (Token::ParenStart); | 
|    966 	m_lexer->mustGetNext (Token::Any); | 
   970 	m_lexer->mustGetNext (Token::Any); | 
|    967  | 
   971  | 
|   1011 	} | 
  1015 	} | 
|   1012  | 
  1016  | 
|   1013 	// If the script skipped any optional arguments, fill in defaults. | 
  1017 	// If the script skipped any optional arguments, fill in defaults. | 
|   1014 	while (curarg < comm->args.size()) | 
  1018 	while (curarg < comm->args.size()) | 
|   1015 	{ | 
  1019 	{ | 
|   1016 		r->writeDWord (DataHeader::PushNumber); | 
  1020 		r->writeHeader (DataHeader::PushNumber); | 
|   1017 		r->writeDWord (comm->args[curarg].defvalue); | 
  1021 		r->writeDWord (comm->args[curarg].defvalue); | 
|   1018 		curarg++; | 
  1022 		curarg++; | 
|   1019 	} | 
  1023 	} | 
|   1020  | 
  1024  | 
|   1021 	r->writeDWord (DataHeader::Command); | 
  1025 	r->writeHeader (DataHeader::Command); | 
|   1022 	r->writeDWord (comm->number); | 
  1026 	r->writeDWord (comm->number); | 
|   1023 	r->writeDWord (comm->args.size()); | 
  1027 	r->writeDWord (comm->args.size()); | 
|   1024  | 
  1028  | 
|   1025 	return r; | 
  1029 	return r; | 
|   1026 } | 
  1030 } | 
|   1182 DataHeader::RightShift); | 
  1186 DataHeader::RightShift); | 
|   1183 	retbuf->WriteDWord (var->IsGlobal() ? DataHeader::AssignGlobalVar : DataHeader::AssignLocalVar); | 
  1187 	retbuf->WriteDWord (var->IsGlobal() ? DataHeader::AssignGlobalVar : DataHeader::AssignLocalVar); | 
|   1184 	retbuf->WriteDWord (var->index); | 
  1188 	retbuf->WriteDWord (var->index); | 
|   1185 #endif | 
  1189 #endif | 
|   1186  | 
  1190  | 
|   1187 	DataHeader dh = getAssigmentDataHeader (oper, var); | 
  1191 	retbuf->writeHeader (getAssigmentDataHeader (oper, var)); | 
|   1188 	retbuf->writeDWord (dh); | 
        | 
|   1189 	retbuf->writeDWord (var->index); | 
  1192 	retbuf->writeDWord (var->index); | 
|   1190 	return retbuf; | 
  1193 	return retbuf; | 
|   1191 } | 
  1194 } | 
|   1192  | 
  1195  | 
|   1193 // ============================================================================ | 
  1196 // ============================================================================ | 
|   1312 DataBuffer* BotscriptParser::currentBuffer() | 
  1315 DataBuffer* BotscriptParser::currentBuffer() | 
|   1313 { | 
  1316 { | 
|   1314 	if (m_switchBuffer != null) | 
  1317 	if (m_switchBuffer != null) | 
|   1315 		return m_switchBuffer; | 
  1318 		return m_switchBuffer; | 
|   1316  | 
  1319  | 
|   1317 	if (m_currentMode == PARSERMODE_MainLoop) | 
  1320 	if (m_currentMode == ParserMode::MainLoop) | 
|   1318 		return m_mainLoopBuffer; | 
  1321 		return m_mainLoopBuffer; | 
|   1319  | 
  1322  | 
|   1320 	if (m_currentMode == PARSERMODE_Onenter) | 
  1323 	if (m_currentMode == ParserMode::Onenter) | 
|   1321 		return m_onenterBuffer; | 
  1324 		return m_onenterBuffer; | 
|   1322  | 
  1325  | 
|   1323 	return m_mainBuffer; | 
  1326 	return m_mainBuffer; | 
|   1324 } | 
  1327 } | 
|   1325  | 
  1328  | 
|   1328 void BotscriptParser::writeMemberBuffers() | 
  1331 void BotscriptParser::writeMemberBuffers() | 
|   1329 { | 
  1332 { | 
|   1330 	// If there was no mainloop defined, write a dummy one now. | 
  1333 	// If there was no mainloop defined, write a dummy one now. | 
|   1331 	if (m_gotMainLoop == false) | 
  1334 	if (m_gotMainLoop == false) | 
|   1332 	{ | 
  1335 	{ | 
|   1333 		m_mainLoopBuffer->writeDWord (DataHeader::MainLoop); | 
  1336 		m_mainLoopBuffer->writeHeader (DataHeader::MainLoop); | 
|   1334 		m_mainLoopBuffer->writeDWord (DataHeader::EndMainLoop); | 
  1337 		m_mainLoopBuffer->writeHeader (DataHeader::EndMainLoop); | 
|   1335 	} | 
  1338 	} | 
|   1336  | 
  1339  | 
|   1337 	// Write the onenter and mainloop buffers, in that order in particular. | 
  1340 	// Write the onenter and mainloop buffers, in that order in particular. | 
|   1338 	for (DataBuffer** bufp : List<DataBuffer**> ({&m_onenterBuffer, &m_mainLoopBuffer})) | 
  1341 	for (DataBuffer** bufp : List<DataBuffer**> ({&m_onenterBuffer, &m_mainLoopBuffer})) | 
|   1339 	{ | 
  1342 	{ | 
|   1357  | 
  1360  | 
|   1358 	if (stringcount == 0) | 
  1361 	if (stringcount == 0) | 
|   1359 		return; | 
  1362 		return; | 
|   1360  | 
  1363  | 
|   1361 	// Write header | 
  1364 	// Write header | 
|   1362 	m_mainBuffer->writeDWord (DataHeader::StringList); | 
  1365 	m_mainBuffer->writeHeader (DataHeader::StringList); | 
|   1363 	m_mainBuffer->writeDWord (stringcount); | 
  1366 	m_mainBuffer->writeDWord (stringcount); | 
|   1364  | 
  1367  | 
|   1365 	// Write all strings | 
  1368 	// Write all strings | 
|   1366 	for (int i = 0; i < stringcount; i++) | 
  1369 	for (int i = 0; i < stringcount; i++) | 
|   1367 		m_mainBuffer->writeString (getStringTable()[i]); | 
  1370 		m_mainBuffer->writeString (getStringTable()[i]); | 
|   1374 void BotscriptParser::writeToFile (String outfile) | 
  1377 void BotscriptParser::writeToFile (String outfile) | 
|   1375 { | 
  1378 { | 
|   1376 	FILE* fp = fopen (outfile, "wb"); | 
  1379 	FILE* fp = fopen (outfile, "wb"); | 
|   1377  | 
  1380  | 
|   1378 	if (fp == null) | 
  1381 	if (fp == null) | 
|   1379 		error ("couldn't open %1 for writing: %2", outfile, strerror (errno)); | 
  1382 		error ("couldn't open %1 for writing: %2", outfile, std::strerror (errno)); | 
|   1380  | 
  1383  | 
|   1381 	// First, resolve references | 
  1384 	// First, resolve references | 
|   1382 	for (MarkReference* ref : m_mainBuffer->references()) | 
  1385 	for (MarkReference* ref : m_mainBuffer->references()) | 
|   1383 	{ | 
  1386 	{ | 
|   1384 		for (int i = 0; i < 4; ++i) | 
  1387 		for (int i = 0; i < 4; ++i) |