2016-03-27 11:49:47 +02:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Copyright ( C ) 2015 the OpenMoHAA team
This file is part of OpenMoHAA source code .
OpenMoHAA source code is free software ; you can redistribute it
and / or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation ; either version 2 of the License ,
or ( at your option ) any later version .
OpenMoHAA source code is distributed in the hope that it will be
useful , but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with OpenMoHAA source code ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
// compiler.cpp : Parse, then compile to op-codes.
2023-01-30 18:20:50 +01:00
# include "scriptcompiler.h"
2016-03-27 11:49:47 +02:00
# include "scriptvm.h"
2023-06-17 01:24:20 +02:00
# include "../fgame/level.h"
# include "../fgame/parm.h"
# include "../fgame/game.h"
# include "../fgame/scriptmaster.h"
# include "../fgame/scriptthread.h"
2023-01-30 18:20:50 +01:00
# include "scriptclass.h"
2023-04-29 21:56:38 +02:00
# include "scriptexception.h"
2023-06-17 01:24:20 +02:00
# include "../parser/parsetree.h"
2023-06-17 16:54:12 +02:00
# include "../parser/generated/yyParser.hpp"
# include "../parser/generated/yyLexer.h"
2016-03-27 11:49:47 +02:00
ScriptCompiler Compiler ;
2023-07-05 21:23:39 +02:00
int ScriptCompiler : : current_label ;
2016-03-27 11:49:47 +02:00
ScriptCompiler : : ScriptCompiler ( )
{
2023-07-05 21:23:39 +02:00
Reset ( ) ;
2016-03-27 11:49:47 +02:00
}
void ScriptCompiler : : Reset ( )
{
2023-07-05 21:23:39 +02:00
code_pos = NULL ;
code_ptr = NULL ;
prog_ptr = NULL ;
prog_end_ptr = NULL ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
for ( int i = 0 ; i < BREAK_JUMP_LOCATION_COUNT ; i + + ) {
apucBreakJumpLocations [ i ] = 0 ;
apucContinueJumpLocations [ i ] = 0 ;
prev_opcodes [ i ] . opcode = 0 ;
prev_opcodes [ i ] . VarStackOffset = 0 ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
iBreakJumpLocCount = 0 ;
iContinueJumpLocCount = 0 ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
m_iHasExternal = 0 ;
m_iInternalMaxVarStackOffset = 0 ;
m_iMaxCallStackOffset = 0 ;
m_iMaxExternalVarStackOffset = 0 ;
m_iVarStackOffset = 0 ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
bCanBreak = false ;
bCanContinue = false ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
prev_opcode_pos = 0 ;
2016-03-27 11:49:47 +02:00
}
unsigned char ScriptCompiler : : PrevOpcode ( )
{
2023-07-05 21:23:39 +02:00
return prev_opcodes [ prev_opcode_pos ] . opcode ;
2016-03-27 11:49:47 +02:00
}
char ScriptCompiler : : PrevVarStackOffset ( )
{
2023-07-05 21:23:39 +02:00
return prev_opcodes [ prev_opcode_pos ] . VarStackOffset ;
2016-03-27 11:49:47 +02:00
}
void ScriptCompiler : : AbsorbPrevOpcode ( )
{
2023-07-05 21:23:39 +02:00
m_iVarStackOffset - = PrevVarStackOffset ( ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
code_pos - = OpcodeLength ( PrevOpcode ( ) ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( ! prev_opcode_pos ) {
prev_opcode_pos = 100 ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
prev_opcode_pos - - ;
2016-03-27 11:49:47 +02:00
}
void ScriptCompiler : : ClearPrevOpcode ( )
{
2023-07-05 21:23:39 +02:00
prev_opcodes [ prev_opcode_pos ] . opcode = OP_PREVIOUS ;
2016-03-27 11:49:47 +02:00
}
2023-08-13 17:59:49 +02:00
void ScriptCompiler : : AccumulatePrevOpcode ( int opcode , int iVarStackOffset )
{
2023-10-01 22:47:25 +02:00
if ( showopcodes - > integer ) {
glbs . DPrintf ( " \t \t %08d: %s (%d) \n " , code_pos - code_ptr , OpcodeName ( OP_BOOL_TO_VAR ) , m_iVarStackOffset ) ;
}
2023-08-13 17:59:49 +02:00
2023-10-01 22:47:25 +02:00
int pos = ( prev_opcode_pos + 1 ) % 100 ;
2023-08-13 17:59:49 +02:00
2023-10-01 22:47:25 +02:00
prev_opcode_pos = pos ;
prev_opcodes [ pos ] . opcode = OP_BOOL_TO_VAR ;
prev_opcodes [ pos ] . VarStackOffset = 0 ;
prev_opcodes [ ( pos + 1 ) % 100 ] . opcode = OP_PREVIOUS ;
2023-08-13 17:59:49 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : AddBreakJumpLocation ( unsigned char * pos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
if ( iBreakJumpLocCount < BREAK_JUMP_LOCATION_COUNT ) {
apucBreakJumpLocations [ iBreakJumpLocCount + + ] = pos ;
} else {
iBreakJumpLocCount = 0 ;
CompileError ( - 1 , " Increase BREAK_JUMP_LOCATION_COUNT and recompile. \n " ) ;
}
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : AddContinueJumpLocation ( unsigned char * pos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
if ( iContinueJumpLocCount < CONTINUE_JUMP_LOCATION_COUNT ) {
apucContinueJumpLocations [ iContinueJumpLocCount + + ] = pos ;
} else {
iContinueJumpLocCount = 0 ;
CompileError ( - 1 , " Increase CONTINUE_JUMP_LOCATION_COUNT and recompile. \n " ) ;
}
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : AddJumpLocation ( unsigned char * pos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
unsigned int offset = code_pos - sizeof ( unsigned int ) - pos ;
2016-03-27 11:49:47 +02:00
2023-08-13 17:59:49 +02:00
EmitAt ( pos , offset , sizeof ( offset ) ) ;
2023-07-05 21:23:39 +02:00
ClearPrevOpcode ( ) ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : AddJumpBackLocation ( unsigned char * pos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
int offset = ( code_pos - pos ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitOpcodeValue ( offset , sizeof ( unsigned int ) ) ;
ClearPrevOpcode ( ) ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : AddJumpToLocation ( unsigned char * pos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
int offset = ( pos - code_pos - 1 ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitOpcodeValue ( offset , sizeof ( unsigned int ) ) ;
ClearPrevOpcode ( ) ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
bool ScriptCompiler : : BuiltinReadVariable ( unsigned int sourcePos , int type , int eventnum )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
ClassDef * c ;
EventDef * def ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
switch ( type ) {
case method_game :
c = Game : : classinfostatic ( ) ;
break ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
case method_level :
c = Level : : classinfostatic ( ) ;
break ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
case method_local :
c = ScriptThread : : classinfostatic ( ) ;
break ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
case method_parm :
c = Parm : : classinfostatic ( ) ;
break ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
case method_group :
c = ScriptClass : : classinfostatic ( ) ;
break ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
default :
return true ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
def = c - > GetDef ( eventnum ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( def ) {
if ( def - > type = = EV_GETTER ) {
return true ;
} else {
CompileError ( sourcePos , " Cannot get a write-only variable " ) ;
return false ;
}
} else {
return false ;
}
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
bool ScriptCompiler : : BuiltinWriteVariable ( unsigned int sourcePos , int type , int eventnum )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
ClassDef * c ;
EventDef * def ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
switch ( type ) {
case method_game :
c = Game : : classinfostatic ( ) ;
break ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
case method_level :
c = Level : : classinfostatic ( ) ;
break ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
case method_local :
c = ScriptThread : : classinfostatic ( ) ;
break ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
case method_parm :
c = Parm : : classinfostatic ( ) ;
break ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
case method_group :
c = ScriptClass : : classinfostatic ( ) ;
break ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
default :
return true ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
def = c - > GetDef ( eventnum ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( def ) {
if ( def - > type = = EV_SETTER ) {
return true ;
} else {
CompileError ( sourcePos , " Cannot get a read-only variable " ) ;
return false ;
}
} else {
return false ;
}
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitAssignmentStatement ( sval_t lhs , unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-08-19 00:57:19 +02:00
int eventnum ;
unsigned int index ;
sval_t listener_val ;
2023-10-01 22:47:25 +02:00
const char * name = lhs . node [ 2 ] . stringValue ;
2023-11-01 19:16:01 +01:00
str name_lowered ;
2016-03-27 11:49:47 +02:00
2023-08-12 19:59:40 +02:00
if ( lhs . node [ 0 ] . type ! = ENUM_field ) {
if ( lhs . node [ 0 ] . type = = ENUM_array_expr ) {
2023-07-05 21:23:39 +02:00
EmitRef ( lhs . node [ 1 ] , sourcePos ) ;
EmitValue ( lhs . node [ 2 ] ) ;
EmitOpcode ( OP_LOAD_ARRAY_VAR , lhs . node [ 3 ] . sourcePosValue ) ;
} else {
CompileError ( sourcePos , " bad lvalue: %d (expecting field or array) " , lhs . node [ 0 ] . type ) ;
2023-08-13 03:33:50 +02:00
}
return ;
2023-07-05 21:23:39 +02:00
}
2016-03-27 11:49:47 +02:00
2023-11-01 19:16:01 +01:00
name_lowered = name ;
name_lowered . tolower ( ) ;
index = Director . AddString ( name_lowered ) ;
eventnum = Event : : FindSetterEventNum ( name_lowered ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
listener_val = lhs . node [ 1 ] ;
2016-03-27 11:49:47 +02:00
2023-08-12 19:59:40 +02:00
if ( listener_val . node [ 0 ] . type ! = ENUM_listener
2023-07-05 21:23:39 +02:00
| | ( eventnum & & BuiltinWriteVariable ( sourcePos , listener_val . node [ 1 ] . byteValue , eventnum ) ) ) {
EmitValue ( listener_val ) ;
EmitOpcode ( OP_LOAD_FIELD_VAR , sourcePos ) ;
} else {
EmitOpcode ( OP_LOAD_GAME_VAR + listener_val . node [ 1 ] . byteValue , sourcePos ) ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitOpcodeValue ( index , sizeof ( unsigned int ) ) ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitBoolJumpFalse ( unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
if ( PrevOpcode ( ) = = OP_UN_CAST_BOOLEAN ) {
AbsorbPrevOpcode ( ) ;
EmitOpcode ( OP_VAR_JUMP_FALSE4 , sourcePos ) ;
} else {
EmitOpcode ( OP_BOOL_JUMP_FALSE4 , sourcePos ) ;
}
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitBoolJumpTrue ( unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
if ( PrevOpcode ( ) = = OP_UN_CAST_BOOLEAN ) {
AbsorbPrevOpcode ( ) ;
EmitOpcode ( OP_VAR_JUMP_TRUE4 , sourcePos ) ;
} else {
EmitOpcode ( OP_BOOL_JUMP_TRUE4 , sourcePos ) ;
}
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitBoolNot ( unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
int prev = PrevOpcode ( ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( prev = = OP_BOOL_STORE_TRUE ) {
AbsorbPrevOpcode ( ) ;
return EmitOpcode ( OP_BOOL_STORE_FALSE , sourcePos ) ;
} else if ( prev > OP_BOOL_STORE_TRUE & & prev = = OP_BOOL_UN_NOT ) {
AbsorbPrevOpcode ( ) ;
return EmitNil ( sourcePos ) ;
} else if ( prev = = OP_BOOL_STORE_FALSE ) {
AbsorbPrevOpcode ( ) ;
return EmitOpcode ( OP_BOOL_STORE_TRUE , sourcePos ) ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
return EmitOpcode ( OP_BOOL_UN_NOT , sourcePos ) ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitBoolToVar ( unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
if ( PrevOpcode ( ) = = OP_UN_CAST_BOOLEAN ) {
AbsorbPrevOpcode ( ) ;
EmitOpcode ( OP_UN_CAST_BOOLEAN , sourcePos ) ;
} else {
if ( showopcodes - > integer ) {
glbs . DPrintf ( " \t \t %08d: %s (%d) \n " , code_pos - code_ptr , OpcodeName ( OP_BOOL_TO_VAR ) , m_iVarStackOffset ) ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
int pos = ( prev_opcode_pos + 1 ) % 100 ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
prev_opcode_pos = pos ;
prev_opcodes [ pos ] . opcode = OP_BOOL_TO_VAR ;
prev_opcodes [ pos ] . VarStackOffset = 0 ;
prev_opcodes [ ( pos + 1 ) % 100 ] . opcode = OP_PREVIOUS ;
}
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitBreak ( unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
if ( bCanBreak ) {
EmitOpcode ( OP_JUMP4 , sourcePos ) ;
unsigned char * pos = code_pos ;
code_pos + = 4 ;
ClearPrevOpcode ( ) ;
AddBreakJumpLocation ( pos ) ;
} else {
CompileError ( sourcePos , " illegal break \n " ) ;
}
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitCatch ( sval_t val , unsigned char * try_begin_code_pos , unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
unsigned char * old_code_pos ;
StateScript * m_oldStateScript ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitOpcode ( OP_JUMP4 , sourcePos ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
old_code_pos = code_pos ;
code_pos + = sizeof ( unsigned int ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
ClearPrevOpcode ( ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
m_oldStateScript = stateScript ;
stateScript = script - > CreateCatchStateScript ( try_begin_code_pos , code_pos ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitValue ( val ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
stateScript = m_oldStateScript ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
AddJumpLocation ( old_code_pos ) ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitConstArray ( sval_t lhs , sval_t rhs , unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-08-13 03:33:50 +02:00
uint32_t iCount = 1 ;
2016-03-27 11:49:47 +02:00
2023-08-13 03:33:50 +02:00
EmitValue ( lhs ) ;
2016-03-27 11:49:47 +02:00
2023-08-13 03:33:50 +02:00
for ( const sval_t * node = rhs . node [ 0 ] . node ; node ; node = node [ 1 ] . node , iCount + + ) {
EmitValue ( * node ) ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitConstArrayOpcode ( iCount ) ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitConstArrayOpcode ( int iCount )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
SetOpcodeVarStackOffset ( OP_LOAD_CONST_ARRAY1 , 1 - iCount ) ;
EmitOpcode ( OP_LOAD_CONST_ARRAY1 , - 1 ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitOpcodeValue ( iCount , sizeof ( short ) ) ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitContinue ( unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
if ( bCanContinue ) {
EmitOpcode ( OP_JUMP4 , sourcePos ) ;
unsigned char * pos = code_pos ;
code_pos + = sizeof ( unsigned int ) ;
ClearPrevOpcode ( ) ;
AddContinueJumpLocation ( pos ) ;
} else {
CompileError ( sourcePos , " illegal continue \n " ) ;
}
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitDoWhileJump ( sval_t while_stmt , sval_t while_expr , unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
unsigned char * pos = code_pos ;
int label1 , label2 ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( showopcodes - > integer ) {
label1 = current_label + + ;
glbs . DPrintf ( " <LABEL%d>: \n " , label1 ) ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
ClearPrevOpcode ( ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
bool old_bCanBreak = bCanBreak ;
bool old_bCanContinue = bCanContinue ;
int breakCount = iBreakJumpLocCount ;
int continueCount = iContinueJumpLocCount ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
bCanBreak = true ;
bCanContinue = true ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitValue ( while_stmt ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
ProcessContinueJumpLocations ( continueCount ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
bCanContinue = old_bCanContinue ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitValue ( while_expr ) ;
EmitVarToBool ( sourcePos ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
label2 = EmitNot ( sourcePos ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
unsigned char * jmp = code_pos ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
code_pos + = sizeof ( unsigned int ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( showopcodes - > integer ) {
glbs . DPrintf ( " JUMP_BACK4 <LABEL%d> \n " , label1 ) ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitJumpBack ( pos , sourcePos ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
ClearPrevOpcode ( ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( showopcodes - > integer ) {
glbs . DPrintf ( " <LABEL%d>: \n " , label2 ) ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
AddJumpLocation ( jmp ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
ProcessBreakJumpLocations ( breakCount ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
bCanBreak = old_bCanBreak ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitEof ( unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
if ( PrevOpcode ( ) ) {
EmitOpcode ( OP_DONE , - 1 ) ;
}
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitField ( sval_t listener_val , sval_t field_val , unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
unsigned int eventnum = 0 ;
unsigned int index = - 1 ;
unsigned int prev_index ;
2023-11-01 19:16:01 +01:00
str name_lowered ;
2016-03-27 11:49:47 +02:00
2023-08-13 21:55:22 +02:00
/*
2023-07-05 21:23:39 +02:00
if ( field_val . node [ 0 ] . stringValue ) {
str name = field_val . stringValue ;
str name2 = field_val . stringValue ;
name2 . tolower ( ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
index = Director . AddString ( name ) ;
eventnum = Event : : FindGetterEventNum ( name2 ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( eventnum ) {
index = Director . GetString ( name2 ) ;
}
}
2023-08-13 21:55:22 +02:00
*/
2023-11-01 19:16:01 +01:00
name_lowered = field_val . stringValue ;
name_lowered . tolower ( ) ;
index = Director . AddString ( name_lowered ) ;
eventnum = Event : : FindGetterEventNum ( name_lowered ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
prev_index = GetOpcodeValue < unsigned int > ( sizeof ( unsigned int ) , sizeof ( unsigned int ) ) ;
2016-03-27 11:49:47 +02:00
2023-08-12 19:59:40 +02:00
if ( listener_val . node [ 0 ] . type ! = ENUM_listener
2023-07-05 21:23:39 +02:00
| | ( eventnum & & BuiltinReadVariable ( sourcePos , listener_val . node [ 1 ] . byteValue , eventnum ) ) ) {
EmitValue ( listener_val ) ;
EmitOpcode ( OP_STORE_FIELD , sourcePos ) ;
EmitOpcodeValue ( index , sizeof ( unsigned int ) ) ;
} else if ( PrevOpcode ( ) ! = ( OP_LOAD_GAME_VAR + listener_val . node [ 1 ] . byteValue ) | | prev_index ! = index ) {
EmitOpcode ( OP_STORE_GAME_VAR + listener_val . node [ 1 ] . byteValue , sourcePos ) ;
EmitOpcodeValue ( index , sizeof ( unsigned int ) ) ;
} else {
AbsorbPrevOpcode ( ) ;
EmitOpcode ( OP_LOAD_STORE_GAME_VAR + listener_val . node [ 1 ] . byteValue , sourcePos ) ;
code_pos + = sizeof ( unsigned int ) ;
}
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitFloat ( float value , unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
EmitOpcode ( OP_STORE_FLOAT , sourcePos ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitOpcodeValue ( value , sizeof ( float ) ) ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitFunc1 ( int opcode , unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
if ( opcode = = OP_UN_MINUS ) {
ScriptVariable var ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( EvalPrevValue ( var ) ) {
AbsorbPrevOpcode ( ) ;
var . minus ( ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
return EmitValue ( var , sourcePos ) ;
}
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitOpcode ( opcode , sourcePos ) ;
2016-03-27 11:49:47 +02:00
}
2023-08-12 19:59:40 +02:00
/*
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitFunction ( int iParamCount , sval_t val , unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-08-12 19:59:40 +02:00
const char * p = val . stringValue ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
str filename ;
str label ;
bool found = false ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
while ( * p ) {
if ( p [ 0 ] = = ' : ' & & p [ 1 ] = = ' : ' ) {
p [ 0 ] = 0 ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
filename = val . stringValue ;
label = p + 2 ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
found = true ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
break ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
p + + ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
SetOpcodeVarStackOffset ( OP_FUNC , - iParamCount ) ;
EmitOpcode ( OP_FUNC , sourcePos ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( ! found ) {
label = val . stringValue ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitOpcodeValue ( false , sizeof ( bool ) ) ;
EmitOpcodeValue ( Director . AddString ( label ) , sizeof ( unsigned int ) ) ;
} else {
EmitOpcodeValue ( true , sizeof ( bool ) ) ;
EmitOpcodeValue ( Director . AddString ( filename ) , sizeof ( unsigned int ) ) ;
EmitOpcodeValue ( Director . AddString ( label ) , sizeof ( unsigned int ) ) ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitOpcodeValue ( iParamCount , sizeof ( uint8_t ) ) ;
2016-03-27 11:49:47 +02:00
}
2023-08-12 19:59:40 +02:00
*/
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitIfElseJump ( sval_t if_stmt , sval_t else_stmt , unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
unsigned char * jmp1 , * jmp2 ;
int label1 , label2 ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
label1 = EmitNot ( sourcePos ) ;
jmp1 = code_pos ;
code_pos + = sizeof ( unsigned int ) ;
ClearPrevOpcode ( ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitValue ( if_stmt ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( showopcodes - > integer ) {
label2 = current_label + + ;
glbs . DPrintf ( " JUMP <LABEL%d> \n " , label2 ) ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitOpcode ( OP_JUMP4 , sourcePos ) ;
jmp2 = code_pos ;
code_pos + = sizeof ( unsigned int ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
ClearPrevOpcode ( ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( showopcodes - > integer ) {
glbs . DPrintf ( " <LABEL%d>: \n " , label1 ) ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
AddJumpLocation ( jmp1 ) ;
EmitValue ( else_stmt ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( showopcodes - > integer ) {
glbs . DPrintf ( " <LABEL%d>: \n " , label1 ) ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
AddJumpLocation ( jmp2 ) ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitIfJump ( sval_t if_stmt , unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
unsigned char * jmp ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
int label = EmitNot ( sourcePos ) ;
jmp = code_pos ;
code_pos + = sizeof ( unsigned int ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
ClearPrevOpcode ( ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitValue ( if_stmt ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( showopcodes - > integer ) {
glbs . DPrintf ( " <LABEL%d>: \n " , label ) ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
AddJumpLocation ( jmp ) ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitInteger ( unsigned int value , unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
if ( value = = 0 ) {
EmitOpcode ( OP_STORE_INT0 , sourcePos ) ;
} else if ( value < 127 ) {
EmitOpcode ( OP_STORE_INT1 , sourcePos ) ;
EmitOpcodeValue ( value , sizeof ( byte ) ) ;
} else if ( value < 32767 ) {
EmitOpcode ( OP_STORE_INT2 , sourcePos ) ;
EmitOpcodeValue ( value , sizeof ( short ) ) ;
} else if ( value < 8388607 ) {
EmitOpcode ( OP_STORE_INT3 , sourcePos ) ;
EmitOpcodeValue ( value , sizeof ( short3 ) ) ;
} else {
EmitOpcode ( OP_STORE_INT4 , sourcePos ) ;
EmitOpcodeValue ( value , sizeof ( int ) ) ;
}
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitJump ( unsigned char * pos , unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
EmitOpcode ( OP_JUMP4 , sourcePos ) ;
AddJumpToLocation ( pos ) ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitJumpBack ( unsigned char * pos , unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
EmitOpcode ( OP_JUMP_BACK4 , sourcePos ) ;
AddJumpBackLocation ( pos ) ;
2016-03-27 11:49:47 +02:00
}
2023-10-01 22:47:25 +02:00
void ScriptCompiler : : EmitLabel ( const char * name , unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
if ( showopcodes - > integer ) {
2023-08-13 21:55:22 +02:00
glbs . DPrintf ( " <%s>: \n " , name ) ;
2023-07-05 21:23:39 +02:00
}
2016-03-27 11:49:47 +02:00
2023-08-13 03:33:50 +02:00
if ( ! stateScript - > AddLabel ( name , code_pos ) ) {
2023-08-13 21:55:22 +02:00
CompileError ( sourcePos , " Duplicate label '%s' " , name ) ;
2023-07-05 21:23:39 +02:00
}
2023-08-13 21:55:22 +02:00
// Make sure to clear the previous opcode since it's a new context
ClearPrevOpcode ( ) ;
}
void ScriptCompiler : : EmitLabel ( int name , unsigned int sourcePos )
{
2023-10-01 22:47:25 +02:00
if ( showopcodes - > integer ) {
glbs . DPrintf ( " <%d>: \n " , name ) ;
}
2023-08-13 21:55:22 +02:00
2023-10-01 22:47:25 +02:00
if ( ! stateScript - > AddLabel ( str ( name ) , code_pos ) ) {
CompileError ( sourcePos , " Duplicate label '%d' " , name ) ;
}
2023-08-13 21:55:22 +02:00
2023-10-01 22:47:25 +02:00
// Make sure to clear the previous opcode since it's a new context
ClearPrevOpcode ( ) ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitLabelParameterList ( sval_t parameter_list , unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-08-13 03:33:50 +02:00
if ( parameter_list . node ) {
EmitOpcode ( OP_MARK_STACK_POS , sourcePos ) ;
2016-03-27 11:49:47 +02:00
2023-08-13 03:33:50 +02:00
for ( const sval_t * param = parameter_list . node - > node ; param ; param = param [ 1 ] . node ) {
EmitParameter ( * param , sourcePos ) ;
} ;
2016-03-27 11:49:47 +02:00
2023-08-13 03:33:50 +02:00
EmitOpcode ( OP_RESTORE_STACK_POS , sourcePos ) ;
}
2016-03-27 11:49:47 +02:00
}
2023-10-01 22:47:25 +02:00
void ScriptCompiler : : EmitLabelPrivate ( const char * name , unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
if ( showopcodes - > integer ) {
2023-08-13 21:55:22 +02:00
glbs . DPrintf ( " <%s>: \n " , name ) ;
2023-07-05 21:23:39 +02:00
}
2016-03-27 11:49:47 +02:00
2023-08-13 03:33:50 +02:00
if ( ! stateScript - > AddLabel ( name , code_pos , true ) ) {
2023-08-13 21:55:22 +02:00
CompileError ( sourcePos , " Duplicate label '%s' " , name ) ;
2023-10-01 22:47:25 +02:00
}
2023-08-13 21:55:22 +02:00
2023-10-01 22:47:25 +02:00
// Make sure to clear the previous opcode since it's a new context
ClearPrevOpcode ( ) ;
2016-03-27 11:49:47 +02:00
}
2023-08-13 17:59:49 +02:00
void ScriptCompiler : : EmitAndJump ( sval_t logic_stmt , unsigned int sourcePos )
{
2023-10-01 22:47:25 +02:00
unsigned char * jmp ;
2023-08-13 17:59:49 +02:00
int label ;
if ( showopcodes - > integer ) {
label = current_label + + ;
glbs . DPrintf ( " BOOL_LOGICAL_AND <LABEL%d> \n " , label ) ;
}
EmitOpcode ( OP_BOOL_LOGICAL_AND , sourcePos ) ;
jmp = code_pos ;
code_pos + = sizeof ( unsigned int ) ;
ClearPrevOpcode ( ) ;
EmitValue ( logic_stmt ) ;
EmitVarToBool ( sourcePos ) ;
if ( showopcodes - > integer ) {
glbs . DPrintf ( " <LABEL%d>: \n " , label ) ;
}
2023-10-01 22:47:25 +02:00
AddJumpLocation ( jmp ) ;
AccumulatePrevOpcode ( OP_BOOL_LOGICAL_AND , 0 ) ;
2023-08-13 17:59:49 +02:00
}
void ScriptCompiler : : EmitOrJump ( sval_t logic_stmt , unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
unsigned char * jmp ;
int label ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( showopcodes - > integer ) {
label = current_label + + ;
2016-03-27 11:49:47 +02:00
2023-10-01 22:47:25 +02:00
glbs . DPrintf ( " BOOL_LOGICAL_OR <LABEL%d> \n " , label ) ;
2023-07-05 21:23:39 +02:00
}
2016-03-27 11:49:47 +02:00
2023-08-13 17:59:49 +02:00
EmitOpcode ( OP_BOOL_LOGICAL_OR , sourcePos ) ;
2023-07-05 21:23:39 +02:00
jmp = code_pos ;
code_pos + = sizeof ( unsigned int ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
ClearPrevOpcode ( ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitValue ( logic_stmt ) ;
EmitVarToBool ( sourcePos ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( showopcodes - > integer ) {
glbs . DPrintf ( " <LABEL%d>: \n " , label ) ;
}
2016-03-27 11:49:47 +02:00
2023-10-01 22:47:25 +02:00
AddJumpLocation ( jmp ) ;
AccumulatePrevOpcode ( OP_BOOL_LOGICAL_OR , 0 ) ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitMakeArray ( sval_t val )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
int iCount = 0 ;
sval_t * node ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
for ( node = val . node [ 0 ] . node ; node ! = NULL ; iCount + + , node = node [ 1 ] . node ) {
EmitValue ( node [ 0 ] ) ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitConstArrayOpcode ( iCount ) ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitMethodExpression ( int iParamCount , int eventnum , unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
if ( iParamCount > 5 ) {
SetOpcodeVarStackOffset ( OP_EXEC_METHOD_COUNT1 , - iParamCount ) ;
EmitOpcode ( OP_EXEC_METHOD_COUNT1 , sourcePos ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitOpcodeValue ( iParamCount , sizeof ( byte ) ) ;
} else {
EmitOpcode ( OP_EXEC_METHOD0 + iParamCount , sourcePos ) ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitOpcodeValue ( eventnum , sizeof ( unsigned int ) ) ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitNil ( unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
if ( showopcodes - > integer ) {
glbs . DPrintf ( " \t \t %08d: \n " , code_pos - code_ptr ) ;
}
2016-03-27 11:49:47 +02:00
}
void ScriptCompiler : : EmitNop ( )
{
2023-07-05 21:23:39 +02:00
EmitOpcode ( OP_NOP , - 1 ) ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
int ScriptCompiler : : EmitNot ( unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
int label = 0 ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( PrevOpcode ( ) = = OP_BOOL_UN_NOT ) {
AbsorbPrevOpcode ( ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( showopcodes - > integer ) {
label = current_label + + ;
glbs . DPrintf ( " BOOL_JUMP_TRUE <LABEL%d> \n " , label ) ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitBoolJumpTrue ( sourcePos ) ;
} else {
if ( showopcodes - > integer ) {
label = current_label + + ;
glbs . DPrintf ( " BOOL_JUMP_FALSE <LABEL%d> \n " , label ) ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitBoolJumpFalse ( sourcePos ) ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
return label ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitOpcode ( int opcode , unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
int IsExternal ;
int iVarStackOffset ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( code_pos = = NULL ) {
Com_Printf ( " Compiler not initialized ! \n " ) ;
return ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( script - > m_ProgToSource ) {
sourceinfo_t info ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
info . sourcePos = sourcePos ;
2016-03-27 11:49:47 +02:00
2023-08-19 21:12:03 +02:00
script - > GetSourceAt ( sourcePos , NULL , info . column , info . line ) ;
2023-07-05 21:23:39 +02:00
script - > m_ProgToSource - > addKeyValue ( code_pos ) = info ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
IsExternal = IsExternalOpcode ( opcode ) ;
iVarStackOffset = OpcodeVarStackOffset ( opcode ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( IsExternal ) {
if ( m_iVarStackOffset > m_iMaxExternalVarStackOffset ) {
m_iMaxExternalVarStackOffset = m_iVarStackOffset ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
m_iHasExternal = 1 ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
m_iVarStackOffset + = iVarStackOffset ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( ! IsExternal ) {
if ( m_iVarStackOffset > m_iInternalMaxVarStackOffset ) {
m_iInternalMaxVarStackOffset = m_iVarStackOffset ;
}
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
/*if( m_iInternalMaxVarStackOffset + 9 * m_iMaxExternalVarStackOffset + 1 > 255 )
2016-03-27 11:49:47 +02:00
{
CompileError ( sourcePos ,
" The required variable stack size of %d exceeds the statically allocated variable stack of size %d. \n Increase SCRIPTTHREAD_VARSTACK_SIZE to at least %d and recompile. \n " ,
m_iInternalMaxVarStackOffset + 9 * m_iMaxExternalVarStackOffset + 1 ,
255 ,
m_iInternalMaxVarStackOffset + 9 * m_iMaxExternalVarStackOffset + 1
) ;
} */
2023-07-05 21:23:39 +02:00
if ( showopcodes - > integer ) {
glbs . DPrintf (
" \t \t %08d: %s (%d) %s \n " ,
code_pos - code_ptr ,
OpcodeName ( opcode ) ,
m_iVarStackOffset ,
IsExternal ? " [external] " : " "
) ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
prev_opcode_pos = ( prev_opcode_pos + 1 ) % 100 ;
prev_opcodes [ prev_opcode_pos ] . opcode = opcode ;
prev_opcodes [ prev_opcode_pos ] . VarStackOffset = iVarStackOffset ;
prev_opcodes [ ( prev_opcode_pos + 1 ) % 100 ] . opcode = OP_PREVIOUS ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitOpcodeValue ( opcode , sizeof ( byte ) ) ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitParameter ( sval_t lhs , unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2024-01-28 23:17:00 +01:00
str name_lowered ;
2023-08-12 19:59:40 +02:00
if ( lhs . node [ 0 ] . type ! = ENUM_field ) {
2023-07-05 21:23:39 +02:00
CompileError ( sourcePos , " bad parameter lvalue: %d (expecting field) " , lhs . node [ 0 ] . type ) ;
}
2016-03-27 11:49:47 +02:00
2023-08-13 03:33:50 +02:00
sval_u listener_val = lhs . node [ 1 ] ;
const char * name = lhs . node [ 2 ] . stringValue ;
2024-01-28 23:17:00 +01:00
name_lowered = name ;
name_lowered . tolower ( ) ;
2016-03-27 11:49:47 +02:00
2024-01-28 23:17:00 +01:00
int eventnum = Event : : FindSetterEventNum ( name_lowered ) ;
2016-03-27 11:49:47 +02:00
2023-08-12 19:59:40 +02:00
if ( listener_val . node [ 0 ] . type ! = ENUM_listener
2023-07-05 21:23:39 +02:00
| | ( eventnum & & BuiltinWriteVariable ( sourcePos , listener_val . node [ 1 ] . byteValue , eventnum ) ) ) {
CompileError ( sourcePos , " built-in field '%s' not allowed " , name ) ;
} else {
EmitOpcode ( OP_STORE_PARAM , sourcePos ) ;
EmitOpcode ( OP_LOAD_GAME_VAR + listener_val . node [ 1 ] . byteValue , sourcePos ) ;
2016-03-27 11:49:47 +02:00
2024-01-28 23:17:00 +01:00
unsigned int index = Director . AddString ( name_lowered ) ;
2023-07-05 21:23:39 +02:00
EmitOpcodeValue ( index , sizeof ( unsigned int ) ) ;
}
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
int ScriptCompiler : : EmitParameterList ( sval_t event_parameter_list )
2016-03-27 11:49:47 +02:00
{
2023-08-13 03:33:50 +02:00
sval_t * node ;
uint32_t iParamCount = 0 ;
2016-03-27 11:49:47 +02:00
2023-08-13 03:33:50 +02:00
if ( ! event_parameter_list . node ) {
return 0 ;
}
2016-03-27 11:49:47 +02:00
2023-08-13 03:33:50 +02:00
for ( node = event_parameter_list . node - > node ; node ; node = node [ 1 ] . node ) {
EmitValue ( * node ) ;
2016-03-27 11:49:47 +02:00
2023-08-13 03:33:50 +02:00
iParamCount + + ;
}
2016-03-27 11:49:47 +02:00
2023-08-13 03:33:50 +02:00
return iParamCount ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitRef ( sval_t val , unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
unsigned int index ;
2024-01-28 23:53:02 +01:00
str name_lowered ;
2016-03-27 11:49:47 +02:00
2023-08-12 19:59:40 +02:00
if ( val . node [ 0 ] . type ! = ENUM_field ) {
if ( val . node [ 0 ] . type = = ENUM_array_expr ) {
2023-07-05 21:23:39 +02:00
EmitRef ( val . node [ 1 ] , sourcePos ) ;
EmitValue ( val . node [ 2 ] ) ;
EmitOpcode ( OP_STORE_ARRAY_REF , val . node [ 3 ] . sourcePosValue ) ;
} else {
CompileError ( sourcePos , " bad lvalue: %d (expecting field or array) " , val . node [ 0 ] . type ) ;
2023-08-13 03:33:50 +02:00
}
return ;
2023-07-05 21:23:39 +02:00
}
2016-03-27 11:49:47 +02:00
2024-01-28 23:53:02 +01:00
name_lowered = val . node [ 2 ] . stringValue ;
name_lowered . tolower ( ) ;
index = Director . AddString ( name_lowered ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitValue ( val . node [ 1 ] ) ;
EmitOpcode ( OP_STORE_FIELD_REF , sourcePos ) ;
EmitOpcodeValue ( index , sizeof ( unsigned int ) ) ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitStatementList ( sval_t val )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
sval_t * node ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
for ( node = val . node [ 0 ] . node ; node ! = NULL ; node = node [ 1 ] . node ) {
EmitValue ( * node ) ;
}
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitString ( str value , unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
unsigned int index = Director . AddString ( value ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( showopcodes - > integer ) {
glbs . DPrintf ( " \t \t STRING \" %s \" \n " , value . c_str ( ) ) ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitOpcode ( OP_STORE_STRING , sourcePos ) ;
EmitOpcodeValue ( index , sizeof ( unsigned int ) ) ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitSwitch ( sval_t val , unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
bool bStartCanBreak ;
int iStartBreakJumpLocCount ;
StateScript * m_oldStateScript ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
m_oldStateScript = stateScript ;
stateScript = script - > CreateSwitchStateScript ( ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitOpcode ( OP_SWITCH , sourcePos ) ;
EmitOpcodeValue ( stateScript , sizeof ( StateScript * ) ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
bStartCanBreak = bCanBreak ;
iStartBreakJumpLocCount = iBreakJumpLocCount ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
bCanBreak = true ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitBreak ( sourcePos ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitValue ( val ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
ProcessBreakJumpLocations ( iStartBreakJumpLocCount ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
bCanBreak = bStartCanBreak ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
stateScript = m_oldStateScript ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitValue ( ScriptVariable & var , unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
if ( var . GetType ( ) = = VARIABLE_INTEGER ) {
EmitInteger ( var . intValue ( ) , sourcePos ) ;
} else if ( var . GetType ( ) = = VARIABLE_FLOAT ) {
EmitFloat ( var . floatValue ( ) , sourcePos ) ;
}
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitValue ( sval_t val )
2016-03-27 11:49:47 +02:00
{
__emit :
2023-07-05 21:23:39 +02:00
switch ( val . node [ 0 ] . type ) {
2023-08-12 19:59:40 +02:00
case ENUM_NOP :
2023-07-05 21:23:39 +02:00
break ;
2023-10-01 22:47:25 +02:00
case ENUM_logical_and :
EmitValue ( val . node [ 1 ] ) ;
EmitVarToBool ( val . node [ 3 ] . sourcePosValue ) ;
EmitAndJump ( val . node [ 2 ] , val . node [ 3 ] . sourcePosValue ) ;
break ;
2023-08-13 17:59:49 +02:00
2023-08-12 19:59:40 +02:00
case ENUM_logical_or :
2023-07-05 21:23:39 +02:00
EmitValue ( val . node [ 1 ] ) ;
EmitVarToBool ( val . node [ 3 ] . sourcePosValue ) ;
2023-08-13 17:59:49 +02:00
EmitOrJump ( val . node [ 2 ] , val . node [ 3 ] . sourcePosValue ) ;
2023-07-05 21:23:39 +02:00
break ;
2023-08-12 19:59:40 +02:00
case ENUM_array_expr :
2023-07-05 21:23:39 +02:00
EmitValue ( val . node [ 1 ] ) ;
EmitValue ( val . node [ 2 ] ) ;
EmitOpcode ( OP_STORE_ARRAY , val . node [ 3 ] . sourcePosValue ) ;
break ;
2023-08-12 19:59:40 +02:00
case ENUM_assignment_statement :
2023-07-05 21:23:39 +02:00
EmitValue ( val . node [ 2 ] ) ;
EmitAssignmentStatement ( val . node [ 1 ] , val . node [ 3 ] . sourcePosValue ) ;
break ;
2023-08-12 19:59:40 +02:00
case ENUM_break :
2023-07-05 21:23:39 +02:00
return EmitBreak ( val . node [ 1 ] . sourcePosValue ) ;
2023-08-12 19:59:40 +02:00
case ENUM_vector :
2023-07-05 21:23:39 +02:00
EmitValue ( val . node [ 1 ] ) ;
EmitValue ( val . node [ 2 ] ) ;
EmitValue ( val . node [ 3 ] ) ;
EmitOpcode ( OP_CALC_VECTOR , val . node [ 4 ] . sourcePosValue ) ;
break ;
2023-08-12 19:59:40 +02:00
case ENUM_neg_int_labeled_statement :
2023-07-05 21:23:39 +02:00
val . node [ 1 ] . intValue = - val . node [ 1 ] . intValue ;
2023-08-12 19:59:40 +02:00
case ENUM_int_labeled_statement :
2023-07-05 21:23:39 +02:00
{
sval_u case_parm = val . node [ 1 ] ;
2023-08-12 19:59:40 +02:00
if ( case_parm . node [ 0 ] . type = = ENUM_integer ) {
2023-07-05 21:23:39 +02:00
EmitLabel ( case_parm . node [ 1 ] . intValue , val . node [ 3 ] . sourcePosValue ) ;
2023-08-12 19:59:40 +02:00
} else if ( case_parm . node [ 0 ] . type = = ENUM_string ) {
2023-07-05 21:23:39 +02:00
EmitLabel ( case_parm . node [ 1 ] . stringValue , val . node [ 3 ] . sourcePosValue ) ;
2023-08-12 19:59:40 +02:00
} else if ( case_parm . node [ 0 ] . type = = ENUM_func1_expr & & case_parm . node [ 1 ] . byteValue = = OP_UN_MINUS ) {
2023-07-05 21:23:39 +02:00
EmitLabel ( - case_parm . node [ 2 ] . node [ 1 ] . intValue , val . node [ 3 ] . sourcePosValue ) ;
} else {
CompileError (
val . node [ 3 ] . sourcePosValue ,
" bad case value: %d (expected integer or string) " ,
case_parm . node [ 0 ] . type
) ;
}
EmitLabelParameterList ( val . node [ 2 ] , val . node [ 3 ] . sourcePosValue ) ;
break ;
}
2023-08-12 19:59:40 +02:00
case ENUM_try :
2023-07-05 21:23:39 +02:00
{
unsigned char * old_code_pos = code_pos ;
ClearPrevOpcode ( ) ;
EmitValue ( val . node [ 1 ] ) ;
EmitCatch ( val . node [ 2 ] , old_code_pos , val . node [ 3 ] . sourcePosValue ) ;
break ;
}
2023-08-12 19:59:40 +02:00
case ENUM_cmd_event_statement :
2023-08-13 03:33:50 +02:00
{
const int eventnum = Event : : FindNormalEventNum ( val . node [ 1 ] . stringValue ) ;
sval_t parameter_list = val . node [ 2 ] ;
const uint32_t iParamCount = EmitParameterList ( parameter_list ) ;
if ( ! eventnum ) {
CompileError ( val . node [ 3 ] . sourcePosValue , " unknown command: %s " , val . node [ 1 ] . stringValue ) ;
}
if ( iParamCount > 5 ) {
SetOpcodeVarStackOffset ( OP_EXEC_CMD_COUNT1 , - ( int32_t ) iParamCount ) ;
EmitOpcode ( OP_EXEC_CMD_COUNT1 , val . node [ 3 ] . sourcePosValue ) ;
EmitOpcodeValue ( iParamCount , sizeof ( byte ) ) ;
} else {
EmitOpcode ( OP_EXEC_CMD0 + iParamCount , val . node [ 3 ] . sourcePosValue ) ;
}
EmitOpcodeValue ( ( op_ev_t ) eventnum , sizeof ( unsigned int ) ) ;
break ;
}
2023-08-12 19:59:40 +02:00
case ENUM_cmd_event_expr :
2023-07-05 21:23:39 +02:00
{
2023-08-13 03:33:50 +02:00
const int eventnum = Event : : FindReturnEventNum ( val . node [ 1 ] . stringValue ) ;
sval_t parameter_list = val . node [ 2 ] ;
const uint32_t iParamCount = EmitParameterList ( parameter_list ) ;
2023-07-05 21:23:39 +02:00
2023-08-13 03:33:50 +02:00
if ( ! eventnum ) {
CompileError ( val . node [ 3 ] . sourcePosValue , " unknown command: %s " , val . node [ 1 ] . stringValue ) ;
}
2016-03-27 11:49:47 +02:00
2023-10-01 22:47:25 +02:00
EmitOpcode ( OP_STORE_LOCAL , val . node [ 3 ] . sourcePosValue ) ;
2023-08-13 03:33:50 +02:00
EmitMethodExpression ( iParamCount , eventnum , val . node [ 3 ] . sourcePosValue ) ;
break ;
2023-07-05 21:23:39 +02:00
}
2023-08-12 19:59:40 +02:00
case ENUM_method_event_statement :
2023-07-05 21:23:39 +02:00
{
2023-08-13 03:33:50 +02:00
const int eventnum = Event : : FindNormalEventNum ( val . node [ 2 ] . stringValue ) ;
sval_t parameter_list = val . node [ 3 ] ;
const uint32_t iParamCount = EmitParameterList ( parameter_list ) ;
2023-07-05 21:23:39 +02:00
2023-08-13 03:33:50 +02:00
if ( ! eventnum ) {
CompileError ( val . node [ 4 ] . sourcePosValue , " unknown command: %s " , val . node [ 2 ] . stringValue ) ;
}
2023-07-05 21:23:39 +02:00
2023-08-13 03:33:50 +02:00
EmitValue ( val . node [ 1 ] ) ;
2023-07-05 21:23:39 +02:00
2023-08-13 03:33:50 +02:00
if ( iParamCount > 5 ) {
SetOpcodeVarStackOffset ( OP_EXEC_CMD_COUNT1 , - ( int32_t ) iParamCount ) ;
2023-08-17 21:29:55 +02:00
EmitOpcode ( OP_EXEC_CMD_METHOD_COUNT1 , val . node [ 4 ] . sourcePosValue ) ;
2016-03-27 11:49:47 +02:00
2023-08-13 03:33:50 +02:00
EmitOpcodeValue ( iParamCount , sizeof ( byte ) ) ;
} else {
EmitOpcode ( OP_EXEC_CMD_METHOD0 + iParamCount , val . node [ 4 ] . sourcePosValue ) ;
}
2023-07-05 21:23:39 +02:00
2023-08-13 03:33:50 +02:00
EmitOpcodeValue ( eventnum , sizeof ( unsigned int ) ) ;
break ;
2023-07-05 21:23:39 +02:00
}
2023-08-12 19:59:40 +02:00
case ENUM_method_event_expr :
2023-08-13 03:33:50 +02:00
{
const int eventnum = Event : : FindReturnEventNum ( val . node [ 2 ] . stringValue ) ;
sval_t parameter_list = val . node [ 3 ] ;
const uint32_t iParamCount = EmitParameterList ( parameter_list ) ;
2023-07-05 21:23:39 +02:00
2023-08-13 03:33:50 +02:00
if ( ! eventnum ) {
CompileError ( val . node [ 4 ] . sourcePosValue , " unknown command: %s " , val . node [ 2 ] . stringValue ) ;
}
2023-07-05 21:23:39 +02:00
2023-08-13 03:33:50 +02:00
EmitValue ( val . node [ 1 ] ) ;
EmitMethodExpression ( iParamCount , eventnum , val . node [ 4 ] . sourcePosValue ) ;
break ;
}
2023-07-05 21:23:39 +02:00
2023-08-12 19:59:40 +02:00
case ENUM_const_array_expr :
2023-10-01 22:47:25 +02:00
EmitConstArray ( val . node [ 1 ] , val . node [ 2 ] , val . node [ 3 ] . sourcePosValue ) ;
break ;
2023-07-05 21:23:39 +02:00
2023-08-12 19:59:40 +02:00
case ENUM_continue :
2023-10-01 22:47:25 +02:00
EmitContinue ( val . node [ 1 ] . sourcePosValue ) ;
break ;
2023-07-05 21:23:39 +02:00
2023-08-12 19:59:40 +02:00
case ENUM_do :
2023-10-01 22:47:25 +02:00
EmitDoWhileJump ( val . node [ 1 ] , val . node [ 2 ] , val . node [ 3 ] . sourcePosValue ) ;
break ;
2023-07-05 21:23:39 +02:00
2023-08-12 19:59:40 +02:00
case ENUM_field :
2023-10-01 22:47:25 +02:00
EmitField ( val . node [ 1 ] , val . node [ 2 ] , val . node [ 3 ] . sourcePosValue ) ;
break ;
2023-07-05 21:23:39 +02:00
2023-08-12 19:59:40 +02:00
case ENUM_func1_expr :
2023-07-05 21:23:39 +02:00
EmitValue ( val . node [ 2 ] ) ;
EmitFunc1 ( val . node [ 1 ] . byteValue , val . node [ 3 ] . sourcePosValue ) ;
break ;
2023-08-12 19:59:40 +02:00
case ENUM_if_statement :
2023-07-05 21:23:39 +02:00
EmitValue ( val . node [ 1 ] ) ;
EmitVarToBool ( val . node [ 4 ] . sourcePosValue ) ;
EmitIfJump ( val . node [ 2 ] , val . node [ 3 ] . sourcePosValue ) ;
break ;
2023-08-12 19:59:40 +02:00
case ENUM_if_else_statement :
2023-07-05 21:23:39 +02:00
EmitValue ( val . node [ 1 ] ) ;
EmitVarToBool ( val . node [ 4 ] . sourcePosValue ) ;
EmitIfElseJump ( val . node [ 2 ] , val . node [ 3 ] , val . node [ 4 ] . sourcePosValue ) ;
break ;
2023-08-12 19:59:40 +02:00
case ENUM_labeled_statement :
2023-07-05 21:23:39 +02:00
EmitLabel ( val . node [ 1 ] . stringValue , val . node [ 3 ] . sourcePosValue ) ;
EmitLabelParameterList ( val . node [ 2 ] , val . node [ 3 ] . sourcePosValue ) ;
break ;
2023-08-12 19:59:40 +02:00
case ENUM_privatelabel :
2023-07-05 21:23:39 +02:00
EmitLabelPrivate ( val . node [ 1 ] . stringValue , val . node [ 3 ] . sourcePosValue ) ;
EmitLabelParameterList ( val . node [ 2 ] , val . node [ 3 ] . sourcePosValue ) ;
break ;
2023-08-12 19:59:40 +02:00
case ENUM_makearray :
2023-07-05 21:23:39 +02:00
return EmitMakeArray ( val . node [ 1 ] ) ;
2023-08-12 19:59:40 +02:00
case ENUM_bool_not :
2023-07-05 21:23:39 +02:00
EmitValue ( val . node [ 1 ] ) ;
EmitVarToBool ( val . node [ 2 ] . sourcePosValue ) ;
EmitBoolNot ( val . node [ 2 ] . sourcePosValue ) ;
EmitBoolToVar ( val . node [ 2 ] . sourcePosValue ) ;
break ;
2023-08-12 19:59:40 +02:00
case ENUM_func2_expr :
2023-07-05 21:23:39 +02:00
EmitValue ( val . node [ 2 ] ) ;
EmitValue ( val . node [ 3 ] ) ;
EmitOpcode ( val . node [ 1 ] . byteValue , val . node [ 4 ] . sourcePosValue ) ;
break ;
2023-08-12 19:59:40 +02:00
case ENUM_statement_list :
2023-08-13 17:59:49 +02:00
EmitStatementList ( val . node [ 1 ] ) ;
break ;
2023-07-05 21:23:39 +02:00
2023-08-12 19:59:40 +02:00
case ENUM_float :
2023-07-05 21:23:39 +02:00
EmitFloat ( val . node [ 1 ] . floatValue , val . node [ 2 ] . sourcePosValue ) ;
break ;
2023-08-12 19:59:40 +02:00
case ENUM_integer :
2023-07-05 21:23:39 +02:00
EmitInteger ( val . node [ 1 ] . intValue , val . node [ 2 ] . sourcePosValue ) ;
break ;
2023-08-12 19:59:40 +02:00
case ENUM_listener :
2023-07-05 21:23:39 +02:00
EmitOpcode ( OP_STORE_GAME + val . node [ 1 ] . byteValue , val . node [ 2 ] . sourcePosValue ) ;
break ;
2023-08-12 19:59:40 +02:00
case ENUM_NIL :
2023-07-05 21:23:39 +02:00
EmitOpcode ( OP_STORE_NIL , val . node [ 1 ] . sourcePosValue ) ;
break ;
2023-08-12 19:59:40 +02:00
case ENUM_NULL :
2023-07-05 21:23:39 +02:00
EmitOpcode ( OP_STORE_NULL , val . node [ 1 ] . sourcePosValue ) ;
break ;
2023-08-12 19:59:40 +02:00
case ENUM_string :
2023-07-05 21:23:39 +02:00
EmitString ( val . node [ 1 ] . stringValue , val . node [ 2 ] . sourcePosValue ) ;
break ;
2023-08-12 19:59:40 +02:00
case ENUM_switch :
2023-07-05 21:23:39 +02:00
EmitValue ( val . node [ 1 ] ) ;
EmitSwitch ( val . node [ 2 ] , val . node [ 3 ] . sourcePosValue ) ;
break ;
2023-08-12 19:59:40 +02:00
case ENUM_ptr :
2023-07-05 21:23:39 +02:00
val = val . node [ 1 ] ;
goto __emit ; // prevent stack overflow
2023-08-12 19:59:40 +02:00
case ENUM_while_statement :
2023-08-13 17:59:49 +02:00
EmitWhileJump ( val . node [ 1 ] , val . node [ 2 ] , val . node [ 3 ] , val . node [ 4 ] . sourcePosValue ) ;
break ;
2023-07-05 21:23:39 +02:00
default :
CompileError ( - 1 , " unknown type %d \n " , val . node [ 0 ] . type ) ;
break ;
}
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitVarToBool ( unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
int prev = PrevOpcode ( ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( prev = = OP_STORE_INT0 ) {
AbsorbPrevOpcode ( ) ;
return EmitOpcode ( OP_BOOL_STORE_FALSE , sourcePos ) ;
} else if ( prev > OP_STORE_INT0 ) {
if ( prev < = OP_STORE_INT4 ) {
AbsorbPrevOpcode ( ) ;
return EmitOpcode ( OP_BOOL_STORE_TRUE , sourcePos ) ;
}
} else if ( prev = = OP_BOOL_TO_VAR ) {
AbsorbPrevOpcode ( ) ;
return EmitNil ( sourcePos ) ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
return EmitOpcode ( OP_UN_CAST_BOOLEAN , sourcePos ) ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitWhileJump ( sval_t while_expr , sval_t while_stmt , sval_t inc_stmt , unsigned int sourcePos )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
unsigned char * pos = code_pos ;
int label1 , label2 ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( showopcodes - > integer ) {
label1 = current_label + + ;
glbs . DPrintf ( " <LABEL%d>: \n " , label1 ) ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
ClearPrevOpcode ( ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitValue ( while_expr ) ;
EmitVarToBool ( sourcePos ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
label2 = EmitNot ( sourcePos ) ;
unsigned char * jmp = code_pos ;
code_pos + = sizeof ( unsigned int ) ;
ClearPrevOpcode ( ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
bool old_bCanBreak = bCanBreak ;
bool old_bCanContinue = bCanContinue ;
int breakCount = iBreakJumpLocCount ;
int continueCount = iContinueJumpLocCount ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
bCanBreak = true ;
bCanContinue = true ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitValue ( while_stmt ) ;
ProcessContinueJumpLocations ( continueCount ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
bCanContinue = old_bCanContinue ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitValue ( inc_stmt ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( showopcodes - > integer ) {
glbs . DPrintf ( " JUMP_BACK4 <LABEL%d> \n " , label1 ) ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitJumpBack ( pos , sourcePos ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
ClearPrevOpcode ( ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( showopcodes - > integer ) {
glbs . DPrintf ( " <LABEL%d>: \n " , label2 ) ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
AddJumpLocation ( jmp ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
ProcessBreakJumpLocations ( breakCount ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
bCanBreak = old_bCanBreak ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
bool ScriptCompiler : : EvalPrevValue ( ScriptVariable & var )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
int intValue = 0 ;
float floatValue = 0.0f ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
switch ( PrevOpcode ( ) ) {
case OP_STORE_INT0 :
intValue = 0 ;
break ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
case OP_STORE_INT1 :
intValue = GetOpcodeValue < byte > ( sizeof ( byte ) , sizeof ( byte ) ) ;
break ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
case OP_STORE_INT2 :
intValue = GetOpcodeValue < short > ( sizeof ( short ) , sizeof ( short ) ) ;
break ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
case OP_STORE_INT3 :
intValue = GetOpcodeValue < short3 > ( sizeof ( short3 ) , sizeof ( short3 ) ) ;
break ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
case OP_STORE_INT4 :
intValue = GetOpcodeValue < int > ( sizeof ( int ) , sizeof ( int ) ) ;
break ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
case OP_STORE_FLOAT :
2023-08-17 19:17:16 +02:00
floatValue = GetOpcodeValue < float > ( sizeof ( float ) , sizeof ( float ) ) ;
2023-07-05 21:23:39 +02:00
var . setFloatValue ( floatValue ) ;
return true ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
default :
return false ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
var . setIntValue ( intValue ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
return true ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : ProcessBreakJumpLocations ( int iStartBreakJumpLocCount )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
if ( iBreakJumpLocCount > iStartBreakJumpLocCount ) {
do {
iBreakJumpLocCount - - ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
unsigned int offset = code_pos - sizeof ( unsigned int ) - apucBreakJumpLocations [ iBreakJumpLocCount ] ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitAt ( apucBreakJumpLocations [ iBreakJumpLocCount ] , offset , sizeof ( unsigned int ) ) ;
} while ( iBreakJumpLocCount > iStartBreakJumpLocCount ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
ClearPrevOpcode ( ) ;
}
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : ProcessContinueJumpLocations ( int iStartContinueJumpLocCount )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
if ( iContinueJumpLocCount > iStartContinueJumpLocCount ) {
do {
iContinueJumpLocCount - - ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
unsigned int offset = code_pos - sizeof ( unsigned int ) - apucContinueJumpLocations [ iContinueJumpLocCount ] ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
EmitAt ( apucContinueJumpLocations [ iContinueJumpLocCount ] , offset , sizeof ( unsigned int ) ) ;
} while ( iContinueJumpLocCount > iStartContinueJumpLocCount ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
ClearPrevOpcode ( ) ;
}
2016-03-27 11:49:47 +02:00
}
unsigned char * ScriptCompiler : : GetPosition ( )
{
2023-07-05 21:23:39 +02:00
return code_pos ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : CompileError ( unsigned int sourcePos , const char * format , . . . )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
char buffer [ 4000 ] ;
va_list va ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
va_start ( va , format ) ;
vsprintf ( buffer , format , va ) ;
va_end ( va ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
compileSuccess = false ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
glbs . DPrintf ( " %s \n " , buffer ) ;
script - > PrintSourcePos ( sourcePos , false ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
throw ScriptException ( buffer ) ;
2016-03-27 11:49:47 +02:00
}
int yyparse ( ) ;
2023-07-05 21:23:39 +02:00
char * ScriptCompiler : : Preprocess ( char * sourceBuffer )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
return sourceBuffer ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : Preclean ( char * processedBuffer ) { }
2016-03-27 11:49:47 +02:00
2023-08-13 03:33:50 +02:00
extern int prev_yylex ;
extern int out_pos ;
extern int success_pos ;
extern const char * start_ptr ;
extern const char * in_ptr ;
2023-08-12 19:59:40 +02:00
extern parseStage_e parseStage ;
2016-03-27 11:49:47 +02:00
2023-08-13 03:33:50 +02:00
void yy_init_script ( ) ;
2023-07-05 21:23:39 +02:00
int yyerror ( const char * msg )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
//parsedata.pos -= yyleng;
parsedata . exc . yylineno = prev_yylex ! = TOKEN_EOL ? yylineno : yylineno - 1 ;
parsedata . exc . yytext = yytext ;
parsedata . exc . yytoken = msg ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
//str line = ScriptCompiler::GetLine( parsedata.sourceBuffer, parsedata.exc.yylineno );
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
glbs . Printf ( " parse error: \n %s: \n " , parsedata . exc . yytoken . c_str ( ) ) ;
2016-03-27 11:49:47 +02:00
2023-08-13 03:33:50 +02:00
parsedata . gameScript - > PrintSourcePos ( success_pos , false ) ;
2023-07-05 21:23:39 +02:00
parsedata . pos + + ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
return 1 ;
2016-03-27 11:49:47 +02:00
}
2024-04-08 21:00:48 +02:00
bool ScriptCompiler : : Parse ( GameScript * gameScript , char * sourceBuffer , const char * type , size_t & outLength )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
parsedata = yyparsedata ( ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
parsedata . sourceBuffer = sourceBuffer ;
parsedata . gameScript = gameScript ;
parsedata . braces_count = 0 ;
2016-03-27 11:49:47 +02:00
2023-08-13 03:33:50 +02:00
start_ptr = sourceBuffer ;
2023-07-05 21:23:39 +02:00
prev_yylex = 0 ;
2023-08-13 03:33:50 +02:00
out_pos = 0 ;
2023-08-12 19:59:40 +02:00
success_pos = 0 ;
2023-08-13 03:33:50 +02:00
parseStage = PS_TYPE ;
in_ptr = type ;
2023-08-12 19:59:40 +02:00
2023-07-05 21:23:39 +02:00
script = gameScript ;
stateScript = & gameScript - > m_State ;
2016-03-27 11:49:47 +02:00
2024-04-08 21:00:48 +02:00
outLength = 0 ;
2023-08-13 03:33:50 +02:00
yy_init_script ( ) ;
2023-07-05 21:23:39 +02:00
parsetree_init ( ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
try {
if ( yyparse ( ) ! = 0 | | parsedata . exc . yytoken ! = " " ) {
// an error occured
if ( ! parsedata . exc . yytext ) {
if ( parsedata . braces_count ) {
glbs . DPrintf ( " unmatching {} pair \n " ) ;
} else {
glbs . DPrintf ( " unexpected end of file found \n " ) ;
}
}
2023-08-13 03:33:50 +02:00
yylex_destroy ( ) ;
2024-04-08 21:00:48 +02:00
return false ;
2023-07-05 21:23:39 +02:00
}
} catch ( ScriptException & exc ) {
2023-08-13 03:33:50 +02:00
yylex_destroy ( ) ;
2023-07-05 21:23:39 +02:00
exc ;
2024-04-08 21:00:48 +02:00
return false ;
2023-07-05 21:23:39 +02:00
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
yylex_destroy ( ) ;
2016-03-27 11:49:47 +02:00
2024-04-08 21:00:48 +02:00
outLength = parsedata . total_length ;
return true ;
2016-03-27 11:49:47 +02:00
}
2024-04-08 21:00:48 +02:00
bool ScriptCompiler : : Compile ( GameScript * gameScript , unsigned char * progBuffer , size_t & outLength )
2016-03-27 11:49:47 +02:00
{
2024-04-08 21:00:48 +02:00
bool success = false ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( progBuffer = = NULL ) {
glbs . DPrintf ( " Invalid program buffer \n " ) ;
return 0 ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
code_pos = progBuffer ;
code_ptr = progBuffer ;
prog_ptr = progBuffer ;
2016-03-27 11:49:47 +02:00
2023-10-27 19:59:29 +02:00
gameScript - > m_ProgToSource = new con_set < const unsigned char * , sourceinfo_t > ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
compileSuccess = true ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
prev_opcodes [ prev_opcode_pos ] . opcode = OP_PREVIOUS ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
try {
EmitValue ( parsedata . val ) ;
EmitEof ( - 1 ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( compileSuccess ) {
stateScript - > AddLabel ( " " , code_ptr ) ;
2016-03-27 11:49:47 +02:00
2024-04-08 21:00:48 +02:00
outLength = code_pos - code_ptr ;
success = true ;
2023-07-05 21:23:39 +02:00
} else {
2024-04-08 21:00:48 +02:00
outLength = 0 ;
2023-07-05 21:23:39 +02:00
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
prog_end_ptr = code_pos ;
} catch ( ScriptException & exc ) {
exc ;
2024-04-08 21:00:48 +02:00
outLength = 0 ;
2023-07-05 21:23:39 +02:00
prog_end_ptr = code_pos ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
parsetree_freeall ( ) ;
2016-03-27 11:49:47 +02:00
2024-04-08 21:00:48 +02:00
return success ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
str ScriptCompiler : : GetLine ( str content , int line )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
char * p ;
str found ;
int i = 1 ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
p = ( char * ) content . c_str ( ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
while ( * p ) {
if ( * p = = ' \n ' ) {
i + + ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( i > = line ) {
found = strtok ( p , " \n " ) ;
break ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
p + + ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
return found ;
2016-03-27 11:49:47 +02:00
}
2023-02-02 23:48:51 +01:00
template < typename Value >
void ScriptCompiler : : EmitOpcodeValue ( const Value & value , size_t size )
{
2023-07-05 21:23:39 +02:00
Com_Memcpy ( code_pos , & value , size ) ;
code_pos + = size ;
2023-02-02 23:48:51 +01:00
}
template < typename Value >
2023-07-05 21:23:39 +02:00
void ScriptCompiler : : EmitAt ( unsigned char * location , const Value & value , size_t size )
2023-02-02 23:48:51 +01:00
{
2023-07-05 21:23:39 +02:00
Com_Memcpy ( location , & value , size ) ;
2023-02-02 23:48:51 +01:00
}
template < typename Value >
void ScriptCompiler : : SetOpcodeValue ( const Value & value )
{
2023-07-05 21:23:39 +02:00
Com_Memcpy ( code_pos , & value , sizeof ( value ) ) ;
2023-02-02 23:48:51 +01:00
}
template < typename Value >
Value ScriptCompiler : : GetOpcodeValue ( size_t size ) const
{
2023-07-05 21:23:39 +02:00
Value val { 0 } ;
Com_Memcpy ( & val , code_pos , size ) ;
return val ;
2023-02-02 23:48:51 +01:00
}
template < typename Value >
Value ScriptCompiler : : GetOpcodeValue ( size_t offset , size_t size ) const
{
2023-07-05 21:23:39 +02:00
Value val { 0 } ;
Com_Memcpy ( & val , code_pos - offset , size ) ;
return val ;
2023-02-02 23:48:51 +01:00
}
2023-07-05 21:23:39 +02:00
void CompileAssemble ( const char * filename , const char * outputfile )
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
GameScript * gameScript = Director . GetGameScript ( filename ) ;
Archiver arc ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( ! gameScript - > m_ProgBuffer | | ! gameScript - > m_ProgLength ) {
return ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
arc . Create ( outputfile ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( ! arc . NoErrors ( ) ) {
glbs . DPrintf ( " Error saving to file '%s' \n " , filename ) ;
return ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
gameScript - > m_bPrecompiled = true ;
gameScript - > Archive ( arc ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
// dump the compiled script to file
arc . Close ( ) ;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
bool GetCompiledScript ( GameScript * scr )
2016-03-27 11:49:47 +02:00
{
2023-09-13 21:32:58 +02:00
/*
2023-07-05 21:23:39 +02:00
Archiver arc ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
arc . SetSilent ( true ) ;
arc . Read ( scr - > Filename ( ) , false ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
if ( ! arc . NoErrors ( ) ) {
return false ;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
arc . SetSilent ( false ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
scr - > Archive ( arc ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
arc . Close ( ) ;
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
return true ;
2023-09-13 21:32:58 +02:00
*/
// FIXME: not used?
return false ;
2016-03-27 11:49:47 +02:00
}