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 ;
int ScriptCompiler : : current_label ;
ScriptCompiler : : ScriptCompiler ( )
{
Reset ( ) ;
}
void ScriptCompiler : : Reset ( )
{
code_pos = NULL ;
code_ptr = NULL ;
prog_ptr = NULL ;
prog_end_ptr = NULL ;
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 ;
}
iBreakJumpLocCount = 0 ;
iContinueJumpLocCount = 0 ;
m_iHasExternal = 0 ;
m_iInternalMaxVarStackOffset = 0 ;
m_iMaxCallStackOffset = 0 ;
m_iMaxExternalVarStackOffset = 0 ;
m_iVarStackOffset = 0 ;
bCanBreak = false ;
bCanContinue = false ;
prev_opcode_pos = 0 ;
}
unsigned char ScriptCompiler : : PrevOpcode ( )
{
return prev_opcodes [ prev_opcode_pos ] . opcode ;
}
char ScriptCompiler : : PrevVarStackOffset ( )
{
return prev_opcodes [ prev_opcode_pos ] . VarStackOffset ;
}
void ScriptCompiler : : AbsorbPrevOpcode ( )
{
m_iVarStackOffset - = PrevVarStackOffset ( ) ;
code_pos - = OpcodeLength ( PrevOpcode ( ) ) ;
if ( ! prev_opcode_pos ) {
prev_opcode_pos = 100 ;
}
prev_opcode_pos - - ;
}
void ScriptCompiler : : ClearPrevOpcode ( )
{
prev_opcodes [ prev_opcode_pos ] . opcode = OP_PREVIOUS ;
}
void ScriptCompiler : : AddBreakJumpLocation ( unsigned char * pos )
{
if ( iBreakJumpLocCount < BREAK_JUMP_LOCATION_COUNT )
{
apucBreakJumpLocations [ iBreakJumpLocCount + + ] = pos ;
}
else
{
iBreakJumpLocCount = 0 ;
CompileError ( - 1 , " Increase BREAK_JUMP_LOCATION_COUNT and recompile. \n " ) ;
}
}
void ScriptCompiler : : AddContinueJumpLocation ( unsigned char * pos )
{
if ( iContinueJumpLocCount < CONTINUE_JUMP_LOCATION_COUNT )
{
apucContinueJumpLocations [ iContinueJumpLocCount + + ] = pos ;
}
else
{
iContinueJumpLocCount = 0 ;
CompileError ( - 1 , " Increase CONTINUE_JUMP_LOCATION_COUNT and recompile. \n " ) ;
}
}
void ScriptCompiler : : AddJumpLocation ( unsigned char * pos )
{
unsigned int offset = code_pos - sizeof ( unsigned int ) - pos ;
2023-02-02 23:48:51 +01:00
SetOpcodeValue ( offset ) ;
2016-03-27 11:49:47 +02:00
ClearPrevOpcode ( ) ;
}
void ScriptCompiler : : AddJumpBackLocation ( unsigned char * pos )
{
int offset = ( code_pos - pos ) ;
2023-02-02 23:48:51 +01:00
EmitOpcodeValue ( offset , sizeof ( unsigned int ) ) ;
2016-03-27 11:49:47 +02:00
ClearPrevOpcode ( ) ;
}
void ScriptCompiler : : AddJumpToLocation ( unsigned char * pos )
{
int offset = ( pos - code_pos - 1 ) ;
2023-02-02 23:48:51 +01:00
EmitOpcodeValue ( offset , sizeof ( unsigned int ) ) ;
2016-03-27 11:49:47 +02:00
ClearPrevOpcode ( ) ;
}
bool ScriptCompiler : : BuiltinReadVariable ( unsigned int sourcePos , int type , int eventnum )
{
ClassDef * c ;
EventDef * def ;
switch ( type )
{
case method_game :
2023-02-05 21:12:51 +01:00
c = Game : : classinfostatic ( ) ;
2016-03-27 11:49:47 +02:00
break ;
case method_level :
2023-02-05 21:12:51 +01:00
c = Level : : classinfostatic ( ) ;
2016-03-27 11:49:47 +02:00
break ;
case method_local :
2023-02-05 21:12:51 +01:00
c = ScriptThread : : classinfostatic ( ) ;
2016-03-27 11:49:47 +02:00
break ;
case method_parm :
2023-02-05 21:12:51 +01:00
c = Parm : : classinfostatic ( ) ;
2016-03-27 11:49:47 +02:00
break ;
case method_group :
2023-02-05 21:12:51 +01:00
c = ScriptClass : : classinfostatic ( ) ;
2016-03-27 11:49:47 +02:00
break ;
default :
return true ;
}
def = c - > GetDef ( eventnum ) ;
if ( def )
{
if ( def - > type = = EV_GETTER )
{
return true ;
}
else
{
CompileError ( sourcePos , " Cannot get a write-only variable " ) ;
return false ;
}
}
else
{
return false ;
}
}
bool ScriptCompiler : : BuiltinWriteVariable ( unsigned int sourcePos , int type , int eventnum )
{
ClassDef * c ;
EventDef * def ;
switch ( type )
{
case method_game :
2023-02-05 21:12:51 +01:00
c = Game : : classinfostatic ( ) ;
2016-03-27 11:49:47 +02:00
break ;
case method_level :
2023-02-05 21:12:51 +01:00
c = Level : : classinfostatic ( ) ;
2016-03-27 11:49:47 +02:00
break ;
case method_local :
2023-02-05 21:12:51 +01:00
c = ScriptThread : : classinfostatic ( ) ;
2016-03-27 11:49:47 +02:00
break ;
case method_parm :
2023-02-05 21:12:51 +01:00
c = Parm : : classinfostatic ( ) ;
2016-03-27 11:49:47 +02:00
break ;
case method_group :
2023-02-05 21:12:51 +01:00
c = ScriptClass : : classinfostatic ( ) ;
2016-03-27 11:49:47 +02:00
break ;
default :
return true ;
}
def = c - > GetDef ( eventnum ) ;
if ( def )
{
if ( def - > type = = EV_SETTER )
{
return true ;
}
else
{
CompileError ( sourcePos , " Cannot get a read-only variable " ) ;
return false ;
}
}
else
{
return false ;
}
}
void ScriptCompiler : : EmitAssignmentStatement ( sval_t lhs , unsigned int sourcePos )
{
int eventnum ;
sval_t listener_val ;
char * name = lhs . node [ 2 ] . stringValue ;
str name2 = name ;
name2 . tolower ( ) ;
if ( lhs . node [ 0 ] . type ! = sval_field )
{
if ( lhs . node [ 0 ] . type = = sval_array )
{
EmitRef ( lhs . node [ 1 ] , sourcePos ) ;
EmitValue ( lhs . node [ 2 ] ) ;
EmitOpcode ( OP_LOAD_ARRAY_VAR , lhs . node [ 3 ] . sourcePosValue ) ;
return ;
}
else
{
CompileError ( sourcePos , " bad lvalue: %d (expecting field or array) " , lhs . node [ 0 ] . type ) ;
}
}
unsigned int index = Director . AddString ( name ) ;
eventnum = Event : : FindSetterEventNum ( name2 ) ;
if ( eventnum )
{
index = Director . GetString ( name2 ) ;
}
listener_val = lhs . node [ 1 ] ;
if ( listener_val . node [ 0 ] . type ! = sval_store_method | | ( 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 ) ;
}
2023-02-02 23:48:51 +01:00
EmitOpcodeValue ( index , sizeof ( unsigned int ) ) ;
2016-03-27 11:49:47 +02:00
}
void ScriptCompiler : : EmitBoolJumpFalse ( unsigned int sourcePos )
{
if ( PrevOpcode ( ) = = OP_UN_CAST_BOOLEAN )
{
AbsorbPrevOpcode ( ) ;
EmitOpcode ( OP_VAR_JUMP_FALSE4 , sourcePos ) ;
}
else
{
EmitOpcode ( OP_BOOL_JUMP_FALSE4 , sourcePos ) ;
}
}
void ScriptCompiler : : EmitBoolJumpTrue ( unsigned int sourcePos )
{
if ( PrevOpcode ( ) = = OP_UN_CAST_BOOLEAN )
{
AbsorbPrevOpcode ( ) ;
EmitOpcode ( OP_VAR_JUMP_TRUE4 , sourcePos ) ;
}
else
{
EmitOpcode ( OP_BOOL_JUMP_TRUE4 , sourcePos ) ;
}
}
void ScriptCompiler : : EmitBoolNot ( unsigned int sourcePos )
{
int prev = PrevOpcode ( ) ;
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 ) ;
}
return EmitOpcode ( OP_BOOL_UN_NOT , sourcePos ) ;
}
void ScriptCompiler : : EmitBoolToVar ( unsigned int sourcePos )
{
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 ) ;
}
int pos = ( prev_opcode_pos + 1 ) % 100 ;
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 ;
}
}
void ScriptCompiler : : EmitBreak ( unsigned int sourcePos )
{
if ( bCanBreak )
{
EmitOpcode ( OP_JUMP4 , sourcePos ) ;
unsigned char * pos = code_pos ;
code_pos + = 4 ;
ClearPrevOpcode ( ) ;
AddBreakJumpLocation ( pos ) ;
}
else
{
CompileError ( sourcePos , " illegal break \n " ) ;
}
}
void ScriptCompiler : : EmitCatch ( sval_t val , unsigned char * try_begin_code_pos , unsigned int sourcePos )
{
unsigned char * old_code_pos ;
StateScript * m_oldStateScript ;
EmitOpcode ( OP_JUMP4 , sourcePos ) ;
old_code_pos = code_pos ;
code_pos + = sizeof ( unsigned int ) ;
ClearPrevOpcode ( ) ;
m_oldStateScript = stateScript ;
stateScript = script - > CreateCatchStateScript ( try_begin_code_pos , code_pos ) ;
EmitValue ( val ) ;
stateScript = m_oldStateScript ;
AddJumpLocation ( old_code_pos ) ;
}
void ScriptCompiler : : EmitConstArray ( sval_t lhs , sval_t rhs , unsigned int sourcePos )
{
int iCount = 1 ;
2023-02-02 23:48:51 +01:00
while ( 1 )
2016-03-27 11:49:47 +02:00
{
iCount + + ;
2023-02-02 23:48:51 +01:00
EmitValue ( lhs ) ;
2016-03-27 11:49:47 +02:00
2023-02-02 23:48:51 +01:00
if ( rhs . node [ 0 ] . type ! = sval_constarray ) {
2016-03-27 11:49:47 +02:00
break ;
}
2023-02-02 23:48:51 +01:00
lhs = rhs . node [ 1 ] ;
rhs = rhs . node [ 2 ] ;
2016-03-27 11:49:47 +02:00
}
2023-02-02 23:48:51 +01:00
EmitValue ( rhs ) ;
EmitConstArrayOpcode ( iCount ) ;
2016-03-27 11:49:47 +02:00
}
void ScriptCompiler : : EmitConstArrayOpcode ( int iCount )
{
SetOpcodeVarStackOffset ( OP_LOAD_CONST_ARRAY1 , 1 - iCount ) ;
EmitOpcode ( OP_LOAD_CONST_ARRAY1 , - 1 ) ;
2023-02-02 23:48:51 +01:00
EmitOpcodeValue ( iCount , sizeof ( short ) ) ;
2016-03-27 11:49:47 +02:00
}
void ScriptCompiler : : EmitContinue ( unsigned int sourcePos )
{
if ( bCanContinue )
{
EmitOpcode ( OP_JUMP4 , sourcePos ) ;
2023-02-02 23:48:51 +01:00
unsigned char * pos = code_pos ;
code_pos + = sizeof ( unsigned int ) ;
2016-03-27 11:49:47 +02:00
ClearPrevOpcode ( ) ;
AddContinueJumpLocation ( pos ) ;
}
else
{
CompileError ( sourcePos , " illegal continue \n " ) ;
}
}
void ScriptCompiler : : EmitDoWhileJump ( sval_t while_stmt , sval_t while_expr , unsigned int sourcePos )
{
unsigned char * pos = code_pos ;
int label1 , label2 ;
if ( showopcodes - > integer )
{
label1 = current_label + + ;
glbs . DPrintf ( " <LABEL%d>: \n " , label1 ) ;
}
ClearPrevOpcode ( ) ;
bool old_bCanBreak = bCanBreak ;
bool old_bCanContinue = bCanContinue ;
int breakCount = iBreakJumpLocCount ;
int continueCount = iContinueJumpLocCount ;
bCanBreak = true ;
bCanContinue = true ;
EmitValue ( while_stmt ) ;
ProcessContinueJumpLocations ( continueCount ) ;
bCanContinue = old_bCanContinue ;
EmitValue ( while_expr ) ;
EmitVarToBool ( sourcePos ) ;
label2 = EmitNot ( sourcePos ) ;
unsigned char * jmp = code_pos ;
code_pos + = sizeof ( unsigned int ) ;
if ( showopcodes - > integer )
{
glbs . DPrintf ( " JUMP_BACK4 <LABEL%d> \n " , label1 ) ;
}
EmitJumpBack ( pos , sourcePos ) ;
ClearPrevOpcode ( ) ;
if ( showopcodes - > integer )
{
glbs . DPrintf ( " <LABEL%d>: \n " , label2 ) ;
}
AddJumpLocation ( jmp ) ;
ProcessBreakJumpLocations ( breakCount ) ;
bCanBreak = old_bCanBreak ;
}
void ScriptCompiler : : EmitEof ( unsigned int sourcePos )
{
if ( PrevOpcode ( ) ) {
EmitOpcode ( OP_DONE , - 1 ) ;
}
}
void ScriptCompiler : : EmitField ( sval_t listener_val , sval_t field_val , unsigned int sourcePos )
{
unsigned int eventnum = 0 ;
unsigned int index = - 1 ;
unsigned int prev_index ;
if ( field_val . node [ 0 ] . stringValue )
{
str name = field_val . stringValue ;
str name2 = field_val . stringValue ;
name2 . tolower ( ) ;
index = Director . AddString ( name ) ;
eventnum = Event : : FindGetterEventNum ( name2 ) ;
if ( eventnum )
{
index = Director . GetString ( name2 ) ;
}
}
2023-02-02 23:48:51 +01:00
prev_index = GetOpcodeValue < unsigned int > ( sizeof ( unsigned int ) , sizeof ( unsigned int ) ) ;
2016-03-27 11:49:47 +02:00
if ( listener_val . node [ 0 ] . type ! = sval_store_method | | ( eventnum & & BuiltinReadVariable ( sourcePos , listener_val . node [ 1 ] . byteValue , eventnum ) ) )
{
EmitValue ( listener_val ) ;
EmitOpcode ( OP_STORE_FIELD , sourcePos ) ;
2023-02-02 23:48:51 +01:00
EmitOpcodeValue ( index , sizeof ( unsigned int ) ) ;
2016-03-27 11:49:47 +02:00
}
else if ( PrevOpcode ( ) ! = ( OP_LOAD_GAME_VAR + listener_val . node [ 1 ] . byteValue ) | | prev_index ! = index )
{
2023-02-02 23:48:51 +01:00
EmitOpcode ( OP_STORE_GAME_VAR + listener_val . node [ 1 ] . byteValue , sourcePos ) ;
EmitOpcodeValue ( index , sizeof ( unsigned int ) ) ;
2016-03-27 11:49:47 +02:00
}
else
{
AbsorbPrevOpcode ( ) ;
EmitOpcode ( OP_LOAD_STORE_GAME_VAR + listener_val . node [ 1 ] . byteValue , sourcePos ) ;
2023-07-04 23:15:45 +02:00
code_pos + = sizeof ( unsigned int ) ;
2016-03-27 11:49:47 +02:00
}
}
void ScriptCompiler : : EmitFloat ( float value , unsigned int sourcePos )
{
// ley0k: optimization
if ( value = = ( float ) ( int ) value )
{
return EmitInteger ( ( unsigned int ) value , sourcePos ) ;
}
EmitOpcode ( OP_STORE_FLOAT , sourcePos ) ;
2023-02-02 23:48:51 +01:00
EmitOpcodeValue ( value , sizeof ( float ) ) ;
2016-03-27 11:49:47 +02:00
}
void ScriptCompiler : : EmitFunc1 ( int opcode , unsigned int sourcePos )
{
if ( opcode = = OP_UN_MINUS )
{
ScriptVariable var ;
if ( EvalPrevValue ( var ) )
{
AbsorbPrevOpcode ( ) ;
var . minus ( ) ;
return EmitValue ( var , sourcePos ) ;
}
}
EmitOpcode ( opcode , sourcePos ) ;
}
void ScriptCompiler : : EmitFunction ( int iParamCount , sval_t val , unsigned int sourcePos )
{
char * p = val . stringValue ;
str filename ;
str label ;
bool found = false ;
while ( * p )
{
if ( p [ 0 ] = = ' : ' & & p [ 1 ] = = ' : ' )
{
p [ 0 ] = 0 ;
filename = val . stringValue ;
label = p + 2 ;
found = true ;
break ;
}
p + + ;
}
SetOpcodeVarStackOffset ( OP_FUNC , - iParamCount ) ;
EmitOpcode ( OP_FUNC , sourcePos ) ;
if ( ! found )
{
label = val . stringValue ;
2023-02-02 23:48:51 +01:00
EmitOpcodeValue ( false , sizeof ( bool ) ) ;
EmitOpcodeValue ( Director . AddString ( label ) , sizeof ( unsigned int ) ) ;
2016-03-27 11:49:47 +02:00
}
else
{
2023-02-02 23:48:51 +01:00
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-02-02 23:48:51 +01:00
EmitOpcodeValue ( iParamCount , sizeof ( uint8_t ) ) ;
2016-03-27 11:49:47 +02:00
}
void ScriptCompiler : : EmitIfElseJump ( sval_t if_stmt , sval_t else_stmt , unsigned int sourcePos )
{
unsigned char * jmp1 , * jmp2 ;
int label1 , label2 ;
label1 = EmitNot ( sourcePos ) ;
jmp1 = code_pos ;
code_pos + = sizeof ( unsigned int ) ;
ClearPrevOpcode ( ) ;
EmitValue ( if_stmt ) ;
if ( showopcodes - > integer )
{
label2 = current_label + + ;
glbs . DPrintf ( " JUMP <LABEL%d> \n " , label2 ) ;
}
EmitOpcode ( OP_JUMP4 , sourcePos ) ;
jmp2 = code_pos ;
code_pos + = sizeof ( unsigned int ) ;
ClearPrevOpcode ( ) ;
if ( showopcodes - > integer )
{
glbs . DPrintf ( " <LABEL%d>: \n " , label1 ) ;
}
AddJumpLocation ( jmp1 ) ;
EmitValue ( else_stmt ) ;
if ( showopcodes - > integer )
{
glbs . DPrintf ( " <LABEL%d>: \n " , label1 ) ;
}
AddJumpLocation ( jmp2 ) ;
}
void ScriptCompiler : : EmitIfJump ( sval_t if_stmt , unsigned int sourcePos )
{
unsigned char * jmp ;
int label = EmitNot ( sourcePos ) ;
jmp = code_pos ;
code_pos + = sizeof ( unsigned int ) ;
ClearPrevOpcode ( ) ;
EmitValue ( if_stmt ) ;
if ( showopcodes - > integer )
{
glbs . DPrintf ( " <LABEL%d>: \n " , label ) ;
}
AddJumpLocation ( jmp ) ;
}
void ScriptCompiler : : EmitInteger ( unsigned int value , unsigned int sourcePos )
{
if ( value = = 0 )
{
EmitOpcode ( OP_STORE_INT0 , sourcePos ) ;
}
else if ( value < 127 )
{
EmitOpcode ( OP_STORE_INT1 , sourcePos ) ;
2023-02-02 23:48:51 +01:00
EmitOpcodeValue ( value , sizeof ( byte ) ) ;
2016-03-27 11:49:47 +02:00
}
else if ( value < 32767 )
{
2023-02-02 23:48:51 +01:00
EmitOpcode ( OP_STORE_INT2 , sourcePos ) ;
EmitOpcodeValue ( value , sizeof ( short ) ) ;
2016-03-27 11:49:47 +02:00
}
else if ( value < 8388607 )
{
2023-02-02 23:48:51 +01:00
EmitOpcode ( OP_STORE_INT3 , sourcePos ) ;
EmitOpcodeValue ( value , sizeof ( short3 ) ) ;
2016-03-27 11:49:47 +02:00
}
else
{
2023-02-02 23:48:51 +01:00
EmitOpcode ( OP_STORE_INT4 , sourcePos ) ;
EmitOpcodeValue ( value , sizeof ( int ) ) ;
2016-03-27 11:49:47 +02:00
}
}
void ScriptCompiler : : EmitJump ( unsigned char * pos , unsigned int sourcePos )
{
EmitOpcode ( OP_JUMP4 , sourcePos ) ;
AddJumpToLocation ( pos ) ;
}
void ScriptCompiler : : EmitJumpBack ( unsigned char * pos , unsigned int sourcePos )
{
EmitOpcode ( OP_JUMP_BACK4 , sourcePos ) ;
AddJumpBackLocation ( pos ) ;
}
void ScriptCompiler : : EmitLabel ( str name , unsigned int sourcePos )
{
if ( showopcodes - > integer )
{
glbs . DPrintf ( " <%s>: \n " , name . c_str ( ) ) ;
}
if ( stateScript - > AddLabel ( name , code_pos ) )
{
CompileError ( sourcePos , " Duplicate label '%s' " , name . c_str ( ) ) ;
}
}
void ScriptCompiler : : EmitLabelParameterList ( sval_t parameter_list , unsigned int sourcePos )
{
sval_u param ;
ClearPrevOpcode ( ) ;
param = parameter_list . node [ 0 ] ;
if ( param . node & & param . node [ 0 ] . node [ 0 ] . type ! = sval_none )
{
EmitOpcode ( OP_MARK_STACK_POS , sourcePos ) ;
while ( param . node )
{
EmitParameter ( param . node [ 0 ] , param . node [ 2 ] . sourcePosValue ) ;
param = param . node [ 1 ] ;
}
EmitOpcode ( OP_RESTORE_STACK_POS , sourcePos ) ;
}
}
void ScriptCompiler : : EmitLabelPrivate ( str name , unsigned int sourcePos )
{
if ( showopcodes - > integer )
{
glbs . DPrintf ( " <%s>: \n " , name . c_str ( ) ) ;
}
if ( stateScript - > AddLabel ( name , code_pos , true ) )
{
CompileError ( sourcePos , " Duplicate label '%s' " , name . c_str ( ) ) ;
}
}
void ScriptCompiler : : EmitLogicJump ( sval_t logic_stmt , bool isOr , unsigned int sourcePos )
{
unsigned char * jmp ;
int label ;
if ( showopcodes - > integer )
{
label = current_label + + ;
if ( isOr )
{
glbs . DPrintf ( " BOOL_LOGICAL_OR <LABEL%d> \n " , label ) ;
}
else
{
glbs . DPrintf ( " BOOL_LOGICAL_AND <LABEL%d> \n " , label ) ;
}
}
EmitOpcode ( OP_BOOL_LOGICAL_AND + isOr , sourcePos ) ;
jmp = code_pos ;
code_pos + = sizeof ( unsigned int ) ;
ClearPrevOpcode ( ) ;
EmitValue ( logic_stmt ) ;
EmitVarToBool ( sourcePos ) ;
if ( showopcodes - > integer )
{
glbs . DPrintf ( " <LABEL%d>: \n " , label ) ;
}
AddJumpLocation ( jmp ) ;
EmitBoolToVar ( sourcePos ) ;
}
void ScriptCompiler : : EmitMakeArray ( sval_t val )
{
int iCount = 0 ;
sval_t * node ;
for ( node = val . node [ 0 ] . node ; node ! = NULL ; iCount + + , node = node [ 1 ] . node )
{
EmitValue ( node [ 0 ] ) ;
}
EmitConstArrayOpcode ( iCount ) ;
}
void ScriptCompiler : : EmitMethodExpression ( int iParamCount , int eventnum , unsigned int sourcePos )
{
if ( iParamCount > 5 )
{
SetOpcodeVarStackOffset ( OP_EXEC_METHOD_COUNT1 , - iParamCount ) ;
EmitOpcode ( OP_EXEC_METHOD_COUNT1 , sourcePos ) ;
2023-02-02 23:48:51 +01:00
EmitOpcodeValue ( iParamCount , sizeof ( byte ) ) ;
2016-03-27 11:49:47 +02:00
}
else
{
EmitOpcode ( OP_EXEC_METHOD0 + iParamCount , sourcePos ) ;
}
2023-02-02 23:48:51 +01:00
EmitOpcodeValue ( eventnum , sizeof ( unsigned int ) ) ;
2016-03-27 11:49:47 +02:00
}
void ScriptCompiler : : EmitNil ( unsigned int sourcePos )
{
if ( showopcodes - > integer )
{
glbs . DPrintf ( " \t \t %08d: \n " , code_pos - code_ptr ) ;
}
}
void ScriptCompiler : : EmitNop ( )
{
EmitOpcode ( OP_NOP , - 1 ) ;
}
int ScriptCompiler : : EmitNot ( unsigned int sourcePos )
{
int label = 0 ;
if ( PrevOpcode ( ) = = OP_BOOL_UN_NOT )
{
AbsorbPrevOpcode ( ) ;
if ( showopcodes - > integer )
{
label = current_label + + ;
glbs . DPrintf ( " BOOL_JUMP_TRUE <LABEL%d> \n " , label ) ;
}
EmitBoolJumpTrue ( sourcePos ) ;
}
else
{
if ( showopcodes - > integer )
{
label = current_label + + ;
glbs . DPrintf ( " BOOL_JUMP_FALSE <LABEL%d> \n " , label ) ;
}
EmitBoolJumpFalse ( sourcePos ) ;
}
return label ;
}
void ScriptCompiler : : EmitOpcode ( int opcode , unsigned int sourcePos )
{
int IsExternal ;
int iVarStackOffset ;
if ( code_pos = = NULL )
{
Com_Printf ( " Compiler not initialized ! \n " ) ;
return ;
}
if ( script - > m_ProgToSource )
{
str sourceLine ;
sourceinfo_t info ;
info . sourcePos = sourcePos ;
script - > GetSourceAt ( sourcePos , sourceLine , info . column , info . line ) ;
script - > m_ProgToSource - > addKeyValue ( code_pos ) = info ;
}
IsExternal = IsExternalOpcode ( opcode ) ;
iVarStackOffset = OpcodeVarStackOffset ( opcode ) ;
if ( IsExternal )
{
if ( m_iVarStackOffset > m_iMaxExternalVarStackOffset ) {
m_iMaxExternalVarStackOffset = m_iVarStackOffset ;
}
m_iHasExternal = 1 ;
}
m_iVarStackOffset + = iVarStackOffset ;
if ( ! IsExternal )
{
if ( m_iVarStackOffset > m_iInternalMaxVarStackOffset ) {
m_iInternalMaxVarStackOffset = m_iVarStackOffset ;
}
}
/*if( m_iInternalMaxVarStackOffset + 9 * m_iMaxExternalVarStackOffset + 1 > 255 )
{
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
) ;
} */
if ( showopcodes - > integer )
{
glbs . DPrintf ( " \t \t %08d: %s (%d) %s \n " , code_pos - code_ptr , OpcodeName ( opcode ) , m_iVarStackOffset , IsExternal ? " [external] " : " " ) ;
}
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 ;
2023-02-02 23:48:51 +01:00
EmitOpcodeValue ( opcode , sizeof ( byte ) ) ;
2016-03-27 11:49:47 +02:00
}
void ScriptCompiler : : EmitParameter ( sval_t lhs , unsigned int sourcePos )
{
if ( lhs . node [ 0 ] . type ! = sval_field )
{
CompileError ( sourcePos , " bad parameter lvalue: %d (expecting field) " , lhs . node [ 0 ] . type ) ;
}
sval_u listener_val = lhs . node [ 1 ] ;
const char * name = lhs . node [ 2 ] . stringValue ;
unsigned int index = Director . AddString ( name ) ;
int eventnum = Event : : FindSetterEventNum ( name ) ;
if ( listener_val . node [ 0 ] . type ! = sval_store_method | | ( 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 ) ;
2023-02-02 23:48:51 +01:00
EmitOpcodeValue ( index , sizeof ( unsigned int ) ) ;
2016-03-27 11:49:47 +02:00
}
}
int ScriptCompiler : : EmitParameterList ( sval_t event_parameter_list )
{
sval_t * node ;
int iParamCount = 0 ;
for ( node = event_parameter_list . node [ 1 ] . node [ 0 ] . node ; node ! = NULL ; node = node [ 1 ] . node )
{
if ( node [ 0 ] . node [ 0 ] . type = = sval_none )
{
continue ;
}
EmitValue ( * node ) ;
iParamCount + + ;
}
return iParamCount ;
}
void ScriptCompiler : : EmitRef ( sval_t val , unsigned int sourcePos )
{
unsigned int index ;
if ( val . node [ 0 ] . type ! = sval_field )
{
if ( val . node [ 0 ] . type = = sval_array )
{
EmitRef ( val . node [ 1 ] , sourcePos ) ;
EmitValue ( val . node [ 2 ] ) ;
EmitOpcode ( OP_STORE_ARRAY_REF , val . node [ 3 ] . sourcePosValue ) ;
return ;
}
else
{
CompileError ( sourcePos , " bad lvalue: %d (expecting field or array) " , val . node [ 0 ] . type ) ;
return ;
}
}
index = Director . AddString ( val . node [ 2 ] . stringValue ) ;
EmitValue ( val . node [ 1 ] ) ;
2023-02-02 23:48:51 +01:00
EmitOpcode ( OP_STORE_FIELD_REF , sourcePos ) ;
EmitOpcodeValue ( index , sizeof ( unsigned int ) ) ;
2016-03-27 11:49:47 +02:00
}
void ScriptCompiler : : EmitStatementList ( sval_t val )
{
sval_t * node ;
for ( node = val . node [ 0 ] . node ; node ! = NULL ; node = node [ 1 ] . node )
{
EmitValue ( * node ) ;
}
}
void ScriptCompiler : : EmitString ( str value , unsigned int sourcePos )
{
unsigned int index = Director . AddString ( value ) ;
if ( showopcodes - > integer ) {
glbs . DPrintf ( " \t \t STRING \" %s \" \n " , value . c_str ( ) ) ;
}
EmitOpcode ( OP_STORE_STRING , sourcePos ) ;
2023-02-02 23:48:51 +01:00
EmitOpcodeValue ( index , sizeof ( unsigned int ) ) ;
2016-03-27 11:49:47 +02:00
}
void ScriptCompiler : : EmitSwitch ( sval_t val , unsigned int sourcePos )
{
bool bStartCanBreak ;
int iStartBreakJumpLocCount ;
StateScript * m_oldStateScript ;
m_oldStateScript = stateScript ;
stateScript = script - > CreateSwitchStateScript ( ) ;
EmitOpcode ( OP_SWITCH , sourcePos ) ;
2023-02-02 23:48:51 +01:00
EmitOpcodeValue ( stateScript , sizeof ( StateScript * ) ) ;
2016-03-27 11:49:47 +02:00
bStartCanBreak = bCanBreak ;
iStartBreakJumpLocCount = iBreakJumpLocCount ;
bCanBreak = true ;
EmitBreak ( sourcePos ) ;
EmitValue ( val ) ;
ProcessBreakJumpLocations ( iStartBreakJumpLocCount ) ;
bCanBreak = bStartCanBreak ;
stateScript = m_oldStateScript ;
}
void ScriptCompiler : : EmitValue ( ScriptVariable & var , unsigned int sourcePos )
{
if ( var . GetType ( ) = = VARIABLE_INTEGER )
{
EmitInteger ( var . intValue ( ) , sourcePos ) ;
}
else if ( var . GetType ( ) = = VARIABLE_FLOAT )
{
EmitFloat ( var . floatValue ( ) , sourcePos ) ;
}
}
void ScriptCompiler : : EmitValue ( sval_t val )
{
__emit :
switch ( val . node [ 0 ] . type )
{
case sval_none :
break ;
case sval_and :
case sval_or :
EmitValue ( val . node [ 1 ] ) ;
EmitVarToBool ( val . node [ 3 ] . sourcePosValue ) ;
EmitLogicJump ( val . node [ 2 ] , val . node [ 0 ] . type = = sval_or , val . node [ 3 ] . sourcePosValue ) ;
break ;
case sval_array :
EmitValue ( val . node [ 1 ] ) ;
EmitValue ( val . node [ 2 ] ) ;
EmitOpcode ( OP_STORE_ARRAY , val . node [ 3 ] . sourcePosValue ) ;
break ;
case sval_assignment :
EmitValue ( val . node [ 2 ] ) ;
EmitAssignmentStatement ( val . node [ 1 ] , val . node [ 3 ] . sourcePosValue ) ;
break ;
case sval_break :
return EmitBreak ( val . node [ 1 ] . sourcePosValue ) ;
case sval_calc_vector :
EmitValue ( val . node [ 1 ] ) ;
EmitValue ( val . node [ 2 ] ) ;
EmitValue ( val . node [ 3 ] ) ;
EmitOpcode ( OP_CALC_VECTOR , val . node [ 4 ] . sourcePosValue ) ;
break ;
case sval_negative :
val . node [ 1 ] . intValue = - val . node [ 1 ] . intValue ;
case sval_case :
{
sval_u case_parm = val . node [ 1 ] ;
if ( case_parm . node [ 0 ] . type = = sval_store_integer )
{
EmitLabel ( case_parm . node [ 1 ] . intValue , val . node [ 3 ] . sourcePosValue ) ;
}
else if ( case_parm . node [ 0 ] . type = = sval_store_string )
{
EmitLabel ( case_parm . node [ 1 ] . stringValue , val . node [ 3 ] . sourcePosValue ) ;
}
else if ( case_parm . node [ 0 ] . type = = sval_func1 & & case_parm . node [ 1 ] . byteValue = = OP_UN_MINUS )
{
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 ;
}
case sval_catch :
{
unsigned char * old_code_pos = code_pos ;
ClearPrevOpcode ( ) ;
EmitValue ( val . node [ 1 ] ) ;
EmitCatch ( val . node [ 2 ] , old_code_pos , val . node [ 3 ] . sourcePosValue ) ;
break ;
}
case sval_cmd :
{
str cmd = val . node [ 1 ] . stringValue ;
cmd . tolower ( ) ;
int eventnum = Event : : FindNormalEventNum ( cmd ) ;
int iParamCount = EmitParameterList ( val . node [ 2 ] ) ;
if ( ! eventnum )
{
CompileError ( val . node [ 3 ] . sourcePosValue , " unknown command: %s " , val . node [ 1 ] . stringValue ) ;
/*EmitOpcode( OP_STORE_LOCAL, val.node[ 3 ].sourcePosValue );
EmitFunction ( iParamCount , val . node [ 1 ] , val . node [ 3 ] . sourcePosValue ) ;
EmitOpcode ( OP_LOAD_LOCAL_VAR , val . node [ 3 ] . sourcePosValue ) ;
* reinterpret_cast < unsigned int * > ( code_pos ) = Director . AddString ( " " ) ;
code_pos + = sizeof ( unsigned int ) ; */
}
else
{
if ( iParamCount > 5 )
{
SetOpcodeVarStackOffset ( OP_EXEC_CMD_COUNT1 , - iParamCount ) ;
EmitOpcode ( OP_EXEC_CMD_COUNT1 , val . node [ 3 ] . sourcePosValue ) ;
2023-02-02 23:48:51 +01:00
EmitOpcodeValue ( iParamCount , sizeof ( byte ) ) ;
2016-03-27 11:49:47 +02:00
}
else
{
EmitOpcode ( OP_EXEC_CMD0 + iParamCount , val . node [ 3 ] . sourcePosValue ) ;
}
2023-02-02 23:48:51 +01:00
EmitOpcodeValue ( eventnum , sizeof ( unsigned int ) ) ;
2016-03-27 11:49:47 +02:00
}
break ;
}
case sval_cmd_default_ret :
{
str cmd = val . node [ 1 ] . stringValue ;
cmd . tolower ( ) ;
int eventnum = Event : : FindReturnEventNum ( cmd ) ;
int iParamCount = EmitParameterList ( val . node [ 2 ] ) ;
EmitOpcode ( OP_STORE_LOCAL , val . node [ 3 ] . sourcePosValue ) ;
if ( ! eventnum )
{
CompileError ( val . node [ 3 ] . sourcePosValue , " unknown return command: %s " , val . node [ 1 ] . stringValue ) ;
//EmitFunction( iParamCount, val.node[ 1 ], val.node[ 3 ].sourcePosValue );
}
else
{
EmitMethodExpression ( iParamCount , eventnum , val . node [ 3 ] . sourcePosValue ) ;
}
break ;
}
case sval_cmd_method :
{
str cmd = val . node [ 2 ] . stringValue ;
cmd . tolower ( ) ;
int eventnum = Event : : FindNormalEventNum ( cmd ) ;
int iParamCount = EmitParameterList ( val . node [ 3 ] ) ;
EmitValue ( val . node [ 1 ] ) ;
if ( ! eventnum )
{
CompileError ( val . node [ 4 ] . sourcePosValue , " unknown command: %s " , val . node [ 2 ] . stringValue ) ;
/*EmitFunction( iParamCount, val.node[ 2 ], val.node[ 4 ].sourcePosValue );
EmitOpcode ( OP_LOAD_LOCAL_VAR , val . node [ 3 ] . sourcePosValue ) ;
* reinterpret_cast < unsigned int * > ( code_pos ) = Director . AddString ( " " ) ;
code_pos + = sizeof ( unsigned int ) ; */
}
else
{
if ( iParamCount > 5 )
{
SetOpcodeVarStackOffset ( OP_EXEC_CMD_METHOD_COUNT1 , - iParamCount - 1 ) ;
EmitOpcode ( OP_EXEC_CMD_METHOD_COUNT1 , val . node [ 4 ] . sourcePosValue ) ;
2023-02-02 23:48:51 +01:00
EmitOpcodeValue ( iParamCount , sizeof ( byte ) ) ;
2016-03-27 11:49:47 +02:00
}
else
{
EmitOpcode ( OP_EXEC_CMD_METHOD0 + iParamCount , val . node [ 4 ] . sourcePosValue ) ;
}
2023-02-02 23:48:51 +01:00
EmitOpcodeValue ( eventnum , sizeof ( unsigned int ) ) ;
2016-03-27 11:49:47 +02:00
}
break ;
}
case sval_cmd_method_ret :
{
str cmd = val . node [ 2 ] . stringValue ;
cmd . tolower ( ) ;
int eventnum = Event : : FindReturnEventNum ( cmd ) ;
int iParamCount = EmitParameterList ( val . node [ 3 ] ) ;
EmitValue ( val . node [ 1 ] ) ;
if ( ! eventnum )
{
CompileError ( val . node [ 4 ] . sourcePosValue , " unknown return command: %s " , val . node [ 2 ] . stringValue ) ;
//EmitFunction( iParamCount ,val.node[ 2 ], val.node[ 4 ].sourcePosValue );
}
else
{
EmitMethodExpression ( iParamCount , eventnum , val . node [ 4 ] . sourcePosValue ) ;
}
break ;
}
case sval_constarray :
return EmitConstArray ( val . node [ 1 ] , val . node [ 2 ] , val . node [ 3 ] . sourcePosValue ) ;
case sval_continue :
return EmitContinue ( val . node [ 1 ] . sourcePosValue ) ;
case sval_do :
return EmitDoWhileJump ( val . node [ 1 ] , val . node [ 2 ] , val . node [ 3 ] . sourcePosValue ) ;
case sval_field :
return EmitField ( val . node [ 1 ] , val . node [ 2 ] , val . node [ 3 ] . sourcePosValue ) ;
case sval_func1 :
EmitValue ( val . node [ 2 ] ) ;
EmitFunc1 ( val . node [ 1 ] . byteValue , val . node [ 3 ] . sourcePosValue ) ;
break ;
case sval_if :
EmitValue ( val . node [ 1 ] ) ;
EmitVarToBool ( val . node [ 4 ] . sourcePosValue ) ;
EmitIfJump ( val . node [ 2 ] , val . node [ 3 ] . sourcePosValue ) ;
break ;
case sval_ifelse :
EmitValue ( val . node [ 1 ] ) ;
EmitVarToBool ( val . node [ 4 ] . sourcePosValue ) ;
EmitIfElseJump ( val . node [ 2 ] , val . node [ 3 ] , val . node [ 4 ] . sourcePosValue ) ;
break ;
case sval_label :
EmitLabel ( val . node [ 1 ] . stringValue , val . node [ 3 ] . sourcePosValue ) ;
EmitLabelParameterList ( val . node [ 2 ] , val . node [ 3 ] . sourcePosValue ) ;
break ;
case sval_privatelabel :
EmitLabelPrivate ( val . node [ 1 ] . stringValue , val . node [ 3 ] . sourcePosValue ) ;
EmitLabelParameterList ( val . node [ 2 ] , val . node [ 3 ] . sourcePosValue ) ;
break ;
case sval_makearray :
return EmitMakeArray ( val . node [ 1 ] ) ;
case sval_not :
EmitValue ( val . node [ 1 ] ) ;
EmitVarToBool ( val . node [ 2 ] . sourcePosValue ) ;
EmitBoolNot ( val . node [ 2 ] . sourcePosValue ) ;
EmitBoolToVar ( val . node [ 2 ] . sourcePosValue ) ;
break ;
case sval_operation :
EmitValue ( val . node [ 2 ] ) ;
EmitValue ( val . node [ 3 ] ) ;
EmitOpcode ( val . node [ 1 ] . byteValue , val . node [ 4 ] . sourcePosValue ) ;
break ;
case sval_statement_list :
return EmitStatementList ( val . node [ 1 ] ) ;
case sval_store_float :
EmitFloat ( val . node [ 1 ] . floatValue , val . node [ 2 ] . sourcePosValue ) ;
break ;
case sval_store_integer :
EmitInteger ( val . node [ 1 ] . intValue , val . node [ 2 ] . sourcePosValue ) ;
break ;
case sval_store_method :
EmitOpcode ( OP_STORE_GAME + val . node [ 1 ] . byteValue , val . node [ 2 ] . sourcePosValue ) ;
break ;
case sval_store_nil :
EmitOpcode ( OP_STORE_NIL , val . node [ 1 ] . sourcePosValue ) ;
break ;
case sval_store_null :
EmitOpcode ( OP_STORE_NULL , val . node [ 1 ] . sourcePosValue ) ;
break ;
case sval_store_string :
EmitString ( val . node [ 1 ] . stringValue , val . node [ 2 ] . sourcePosValue ) ;
break ;
case sval_switch :
EmitValue ( val . node [ 1 ] ) ;
EmitSwitch ( val . node [ 2 ] , val . node [ 3 ] . sourcePosValue ) ;
break ;
case sval_next :
val = val . node [ 1 ] ;
goto __emit ; // prevent stack overflow
case sval_while :
return EmitWhileJump ( val . node [ 1 ] , val . node [ 2 ] , val . node [ 3 ] , val . node [ 4 ] . sourcePosValue ) ;
default :
CompileError ( - 1 , " unknown type %d \n " , val . node [ 0 ] . type ) ;
break ;
}
}
void ScriptCompiler : : EmitVarToBool ( unsigned int sourcePos )
{
int prev = PrevOpcode ( ) ;
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 ) ;
}
return EmitOpcode ( OP_UN_CAST_BOOLEAN , sourcePos ) ;
}
void ScriptCompiler : : EmitWhileJump ( sval_t while_expr , sval_t while_stmt , sval_t inc_stmt , unsigned int sourcePos )
{
unsigned char * pos = code_pos ;
int label1 , label2 ;
if ( showopcodes - > integer )
{
label1 = current_label + + ;
glbs . DPrintf ( " <LABEL%d>: \n " , label1 ) ;
}
ClearPrevOpcode ( ) ;
EmitValue ( while_expr ) ;
EmitVarToBool ( sourcePos ) ;
label2 = EmitNot ( sourcePos ) ;
unsigned char * jmp = code_pos ;
code_pos + = sizeof ( unsigned int ) ;
ClearPrevOpcode ( ) ;
bool old_bCanBreak = bCanBreak ;
bool old_bCanContinue = bCanContinue ;
int breakCount = iBreakJumpLocCount ;
int continueCount = iContinueJumpLocCount ;
bCanBreak = true ;
bCanContinue = true ;
EmitValue ( while_stmt ) ;
ProcessContinueJumpLocations ( continueCount ) ;
bCanContinue = old_bCanContinue ;
EmitValue ( inc_stmt ) ;
if ( showopcodes - > integer )
{
glbs . DPrintf ( " JUMP_BACK4 <LABEL%d> \n " , label1 ) ;
}
EmitJumpBack ( pos , sourcePos ) ;
ClearPrevOpcode ( ) ;
if ( showopcodes - > integer )
{
glbs . DPrintf ( " <LABEL%d>: \n " , label2 ) ;
}
AddJumpLocation ( jmp ) ;
ProcessBreakJumpLocations ( breakCount ) ;
bCanBreak = old_bCanBreak ;
}
bool ScriptCompiler : : EvalPrevValue ( ScriptVariable & var )
{
int intValue = 0 ;
float floatValue = 0.0f ;
switch ( PrevOpcode ( ) )
{
case OP_STORE_INT0 :
intValue = 0 ;
break ;
case OP_STORE_INT1 :
2023-02-05 22:17:54 +01:00
intValue = GetOpcodeValue < byte > ( sizeof ( byte ) , sizeof ( byte ) ) ;
2016-03-27 11:49:47 +02:00
break ;
case OP_STORE_INT2 :
2023-02-02 23:48:51 +01:00
intValue = GetOpcodeValue < short > ( sizeof ( short ) , sizeof ( short ) ) ;
2016-03-27 11:49:47 +02:00
break ;
case OP_STORE_INT3 :
2023-02-02 23:48:51 +01:00
intValue = GetOpcodeValue < short3 > ( sizeof ( short3 ) , sizeof ( short3 ) ) ;
2016-03-27 11:49:47 +02:00
break ;
case OP_STORE_INT4 :
2023-02-02 23:48:51 +01:00
intValue = GetOpcodeValue < int > ( sizeof ( int ) , sizeof ( int ) ) ;
2016-03-27 11:49:47 +02:00
break ;
case OP_STORE_FLOAT :
2023-02-02 23:48:51 +01:00
intValue = GetOpcodeValue < float > ( sizeof ( float ) , sizeof ( float ) ) ;
2016-03-27 11:49:47 +02:00
var . setFloatValue ( floatValue ) ;
return true ;
default :
return false ;
}
var . setIntValue ( intValue ) ;
return true ;
}
void ScriptCompiler : : ProcessBreakJumpLocations ( int iStartBreakJumpLocCount )
{
if ( iBreakJumpLocCount > iStartBreakJumpLocCount )
{
do
{
iBreakJumpLocCount - - ;
unsigned int offset = code_pos - sizeof ( unsigned int ) - apucBreakJumpLocations [ iBreakJumpLocCount ] ;
2023-02-02 23:48:51 +01:00
EmitAt ( apucBreakJumpLocations [ iBreakJumpLocCount ] , offset , sizeof ( unsigned int ) ) ;
2016-03-27 11:49:47 +02:00
} while ( iBreakJumpLocCount > iStartBreakJumpLocCount ) ;
ClearPrevOpcode ( ) ;
}
}
void ScriptCompiler : : ProcessContinueJumpLocations ( int iStartContinueJumpLocCount )
{
if ( iContinueJumpLocCount > iStartContinueJumpLocCount )
{
do
{
iContinueJumpLocCount - - ;
unsigned int offset = code_pos - sizeof ( unsigned int ) - apucContinueJumpLocations [ iContinueJumpLocCount ] ;
2023-02-02 23:48:51 +01:00
EmitAt ( apucContinueJumpLocations [ iContinueJumpLocCount ] , offset , sizeof ( unsigned int ) ) ;
2016-03-27 11:49:47 +02:00
} while ( iContinueJumpLocCount > iStartContinueJumpLocCount ) ;
ClearPrevOpcode ( ) ;
}
}
unsigned char * ScriptCompiler : : GetPosition ( )
{
return code_pos ;
}
void ScriptCompiler : : CompileError ( unsigned int sourcePos , const char * format , . . . )
{
char buffer [ 4000 ] ;
va_list va ;
va_start ( va , format ) ;
vsprintf ( buffer , format , va ) ;
va_end ( va ) ;
compileSuccess = false ;
glbs . DPrintf ( " %s \n " , buffer ) ;
script - > PrintSourcePos ( sourcePos , false ) ;
throw ScriptException ( buffer ) ;
}
int yyparse ( ) ;
char * ScriptCompiler : : Preprocess ( char * sourceBuffer )
{
// FIXME (ley0k): Preprocessor (#defines and #includes)
return sourceBuffer ;
}
void ScriptCompiler : : Preclean ( char * processedBuffer )
{
}
extern int prev_yylex ;
int yyerror ( const char * msg )
{
//parsedata.pos -= yyleng;
parsedata . exc . yylineno = prev_yylex ! = TOKEN_EOL ? yylineno : yylineno - 1 ;
parsedata . exc . yytext = yytext ;
parsedata . exc . yytoken = msg ;
//str line = ScriptCompiler::GetLine( parsedata.sourceBuffer, parsedata.exc.yylineno );
glbs . Printf ( " parse error: \n %s: \n " , parsedata . exc . yytoken . c_str ( ) ) ;
parsedata . gameScript - > PrintSourcePos ( parsedata . pos - yyleng , false ) ;
parsedata . pos + + ;
return 1 ;
}
2017-02-19 21:14:27 +01:00
size_t ScriptCompiler : : Parse ( GameScript * gameScript , char * sourceBuffer )
2016-03-27 11:49:47 +02:00
{
parsedata = yyparsedata ( ) ;
parsedata . sourceBuffer = sourceBuffer ;
parsedata . gameScript = gameScript ;
parsedata . braces_count = 0 ;
prev_yylex = 0 ;
script = gameScript ;
stateScript = & gameScript - > m_State ;
yy_scan_string ( sourceBuffer ) ;
parsetree_init ( ) ;
try
{
if ( yyparse ( ) ! = 0 | | parsedata . exc . yytoken ! = " " )
{
// an error occured
yylex_destroy ( ) ;
if ( ! parsedata . exc . yytext )
{
if ( parsedata . braces_count ) {
glbs . DPrintf ( " unmatching {} pair \n " ) ;
}
else {
glbs . DPrintf ( " unexpected end of file found \n " ) ;
}
}
return 0 ;
}
}
catch ( ScriptException & exc )
{
exc ;
return 0 ;
}
yylex_destroy ( ) ;
return parsedata . total_length ;
}
2017-02-19 21:14:27 +01:00
size_t ScriptCompiler : : Compile ( GameScript * gameScript , unsigned char * progBuffer )
2016-03-27 11:49:47 +02:00
{
2017-02-19 21:14:27 +01:00
size_t length ;
2016-03-27 11:49:47 +02:00
if ( progBuffer = = NULL )
{
glbs . DPrintf ( " Invalid program buffer \n " ) ;
return 0 ;
}
code_pos = progBuffer ;
code_ptr = progBuffer ;
prog_ptr = progBuffer ;
gameScript - > m_ProgToSource = new con_set < unsigned char * , sourceinfo_t > ;
compileSuccess = true ;
prev_opcodes [ prev_opcode_pos ] . opcode = OP_PREVIOUS ;
try
{
EmitValue ( parsedata . val ) ;
EmitEof ( - 1 ) ;
if ( compileSuccess )
{
stateScript - > AddLabel ( " " , code_ptr ) ;
length = code_pos - code_ptr ;
}
else
{
length = 0 ;
}
prog_end_ptr = code_pos ;
}
catch ( ScriptException & exc )
{
exc ;
length = 0 ;
prog_end_ptr = code_pos ;
}
parsetree_freeall ( ) ;
return length ;
}
str ScriptCompiler : : GetLine ( str content , int line )
{
char * p ;
str found ;
int i = 1 ;
p = ( char * ) content . c_str ( ) ;
while ( * p )
{
if ( * p = = ' \n ' )
{
i + + ;
}
if ( i > = line )
{
found = strtok ( p , " \n " ) ;
break ;
}
p + + ;
}
return found ;
}
2023-02-02 23:48:51 +01:00
template < typename Value >
void ScriptCompiler : : EmitOpcodeValue ( const Value & value , size_t size )
{
Com_Memcpy ( code_pos , & value , size ) ;
code_pos + = size ;
}
template < typename Value >
void ScriptCompiler : : EmitAt ( unsigned char * location , const Value & value , size_t size )
{
Com_Memcpy ( location , & value , size ) ;
}
template < typename Value >
void ScriptCompiler : : SetOpcodeValue ( const Value & value )
{
Com_Memcpy ( code_pos , & value , sizeof ( value ) ) ;
}
template < typename Value >
Value ScriptCompiler : : GetOpcodeValue ( size_t size ) const
{
Value val { 0 } ;
Com_Memcpy ( & val , code_pos , size ) ;
return val ;
}
template < typename Value >
Value ScriptCompiler : : GetOpcodeValue ( size_t offset , size_t size ) const
{
Value val { 0 } ;
Com_Memcpy ( & val , code_pos - offset , size ) ;
return val ;
}
2016-03-27 11:49:47 +02:00
void CompileAssemble ( const char * filename , const char * outputfile )
{
GameScript * gameScript = Director . GetGameScript ( filename ) ;
Archiver arc ;
if ( ! gameScript - > m_ProgBuffer | | ! gameScript - > m_ProgLength ) {
return ;
}
arc . Create ( outputfile ) ;
if ( ! arc . NoErrors ( ) )
{
glbs . DPrintf ( " Error saving to file '%s' \n " , filename ) ;
return ;
}
gameScript - > m_bPrecompiled = true ;
gameScript - > Archive ( arc ) ;
// dump the compiled script to file
arc . Close ( ) ;
}
bool GetCompiledScript ( GameScript * scr )
{
Archiver arc ;
arc . SetSilent ( true ) ;
arc . Read ( scr - > Filename ( ) , false ) ;
if ( ! arc . NoErrors ( ) )
{
return false ;
}
arc . SetSilent ( false ) ;
scr - > Archive ( arc ) ;
arc . Close ( ) ;
return true ;
}