mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-03-28 00:29:34 +00:00
Merge branch 'development' into weirdtsbug
This commit is contained in:
commit
a746957cd9
89 changed files with 1943 additions and 1733 deletions
618
Engine/source/console/torquescript/CMDgram.y
Normal file
618
Engine/source/console/torquescript/CMDgram.y
Normal file
|
|
@ -0,0 +1,618 @@
|
|||
%{
|
||||
|
||||
// bison --defines=cmdgram.h --verbose -o cmdgram.cpp -p CMD CMDgram.y
|
||||
|
||||
// Make sure we don't get gram.h twice.
|
||||
#define _CMDGRAM_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "console/console.h"
|
||||
#include "console/compiler.h"
|
||||
#include "console/consoleInternal.h"
|
||||
#include "core/strings/stringFunctions.h"
|
||||
|
||||
#ifndef YYDEBUG
|
||||
#define YYDEBUG 0
|
||||
#endif
|
||||
|
||||
#define YYSSIZE 350
|
||||
|
||||
int outtext(char *fmt, ...);
|
||||
extern int serrors;
|
||||
|
||||
#define nil 0
|
||||
#undef YY_ARGS
|
||||
#define YY_ARGS(x) x
|
||||
|
||||
int CMDlex();
|
||||
void CMDerror(const char *, ...);
|
||||
|
||||
#ifdef alloca
|
||||
#undef alloca
|
||||
#endif
|
||||
#define alloca dMalloc
|
||||
|
||||
template< typename T >
|
||||
struct Token
|
||||
{
|
||||
T value;
|
||||
U32 lineNumber;
|
||||
};
|
||||
|
||||
%}
|
||||
%{
|
||||
/* Reserved Word Definitions */
|
||||
%}
|
||||
%token <i> rwDEFINE rwENDDEF rwDECLARE rwDECLARESINGLETON
|
||||
%token <i> rwBREAK rwELSE rwCONTINUE rwGLOBAL
|
||||
%token <i> rwIF rwNIL rwRETURN rwWHILE rwDO
|
||||
%token <i> rwENDIF rwENDWHILE rwENDFOR rwDEFAULT
|
||||
%token <i> rwFOR rwFOREACH rwFOREACHSTR rwIN rwDATABLOCK rwSWITCH rwCASE rwSWITCHSTR
|
||||
%token <i> rwCASEOR rwPACKAGE rwNAMESPACE rwCLASS
|
||||
%token <i> rwASSERT
|
||||
%token ILLEGAL_TOKEN
|
||||
%{
|
||||
/* Constants and Identifier Definitions */
|
||||
%}
|
||||
%token <c> CHRCONST
|
||||
%token <i> INTCONST
|
||||
%token <s> TTAG
|
||||
%token <s> VAR
|
||||
%token <s> IDENT
|
||||
%token <i> TYPEIDENT
|
||||
%token <str> DOCBLOCK
|
||||
%token <str> STRATOM
|
||||
%token <str> TAGATOM
|
||||
%token <f> FLTCONST
|
||||
|
||||
%{
|
||||
/* Operator Definitions */
|
||||
%}
|
||||
%token <i> '+' '-' '*' '/' '<' '>' '=' '.' '|' '&' '%'
|
||||
%token <i> '(' ')' ',' ':' ';' '{' '}' '^' '~' '!' '@'
|
||||
%token <i> opINTNAME opINTNAMER
|
||||
%token <i> opMINUSMINUS opPLUSPLUS
|
||||
%token <i> STMT_SEP
|
||||
%token <i> opSHL opSHR opPLASN opMIASN opMLASN opDVASN opMODASN opANDASN
|
||||
%token <i> opXORASN opORASN opSLASN opSRASN opCAT
|
||||
%token <i> opEQ opNE opGE opLE opAND opOR opSTREQ
|
||||
%token <i> opCOLONCOLON
|
||||
|
||||
%union {
|
||||
Token< char > c;
|
||||
Token< int > i;
|
||||
Token< const char* > s;
|
||||
Token< char* > str;
|
||||
Token< double > f;
|
||||
StmtNode* stmt;
|
||||
ExprNode* expr;
|
||||
SlotAssignNode* slist;
|
||||
VarNode* var;
|
||||
SlotDecl slot;
|
||||
InternalSlotDecl intslot;
|
||||
ObjectBlockDecl odcl;
|
||||
ObjectDeclNode* od;
|
||||
AssignDecl asn;
|
||||
IfStmtNode* ifnode;
|
||||
}
|
||||
|
||||
%type <s> parent_block
|
||||
%type <ifnode> case_block
|
||||
%type <stmt> switch_stmt
|
||||
%type <stmt> decl
|
||||
%type <stmt> decl_list
|
||||
%type <stmt> package_decl
|
||||
%type <stmt> fn_decl_stmt
|
||||
%type <stmt> fn_decl_list
|
||||
%type <stmt> statement_list
|
||||
%type <stmt> stmt
|
||||
%type <expr> expr_list
|
||||
%type <expr> expr_list_decl
|
||||
%type <expr> aidx_expr
|
||||
%type <expr> funcall_expr
|
||||
%type <expr> assert_expr
|
||||
%type <expr> object_name
|
||||
%type <expr> object_args
|
||||
%type <expr> stmt_expr
|
||||
%type <expr> case_expr
|
||||
%type <expr> class_name_expr
|
||||
%type <stmt> if_stmt
|
||||
%type <stmt> while_stmt
|
||||
%type <stmt> for_stmt
|
||||
%type <stmt> foreach_stmt
|
||||
%type <stmt> stmt_block
|
||||
%type <stmt> datablock_decl
|
||||
%type <od> object_decl
|
||||
%type <od> object_decl_list
|
||||
%type <odcl> object_declare_block
|
||||
%type <expr> expr
|
||||
%type <slist> slot_assign_list_opt
|
||||
%type <slist> slot_assign_list
|
||||
%type <slist> slot_assign
|
||||
%type <slot> slot_acc
|
||||
%type <intslot> intslot_acc
|
||||
%type <stmt> expression_stmt
|
||||
%type <var> var_list
|
||||
%type <var> var_list_decl
|
||||
%type <asn> assign_op_struct
|
||||
|
||||
%left '['
|
||||
%right opMODASN opANDASN opXORASN opPLASN opMIASN opMLASN opDVASN opMDASN opNDASN opNTASN opORASN opSLASN opSRASN '='
|
||||
%left '?' ':'
|
||||
%left opOR
|
||||
%left opAND
|
||||
%left '|'
|
||||
%left '^'
|
||||
%left '&'
|
||||
%left opEQ opNE
|
||||
%left '<' opLE '>' opGE
|
||||
%left '@' opCAT opSTREQ opSTRNE
|
||||
%left opSHL opSHR
|
||||
%left '+' '-'
|
||||
%left '*' '/' '%'
|
||||
%right '!' '~' opPLUSPLUS opMINUSMINUS UNARY
|
||||
%left '.'
|
||||
%left opINTNAME opINTNAMER
|
||||
|
||||
%%
|
||||
|
||||
start
|
||||
: decl_list
|
||||
{ }
|
||||
;
|
||||
|
||||
decl_list
|
||||
:
|
||||
{ $$ = nil; }
|
||||
| decl_list decl
|
||||
{ if(!gStatementList) { gStatementList = $2; } else { gStatementList->append($2); } }
|
||||
;
|
||||
|
||||
decl
|
||||
: stmt
|
||||
{ $$ = $1; }
|
||||
| fn_decl_stmt
|
||||
{ $$ = $1; }
|
||||
| package_decl
|
||||
{ $$ = $1; }
|
||||
;
|
||||
|
||||
package_decl
|
||||
: rwPACKAGE IDENT '{' fn_decl_list '}' ';'
|
||||
{ $$ = $4; for(StmtNode *walk = ($4);walk;walk = walk->getNext() ) walk->setPackage($2.value); }
|
||||
;
|
||||
|
||||
fn_decl_list
|
||||
: fn_decl_stmt
|
||||
{ $$ = $1; }
|
||||
| fn_decl_list fn_decl_stmt
|
||||
{ $$ = $1; ($1)->append($2); }
|
||||
;
|
||||
|
||||
statement_list
|
||||
:
|
||||
{ $$ = nil; }
|
||||
| statement_list stmt
|
||||
{ if(!$1) { $$ = $2; } else { ($1)->append($2); $$ = $1; } }
|
||||
;
|
||||
|
||||
stmt
|
||||
: if_stmt
|
||||
| while_stmt
|
||||
| for_stmt
|
||||
| foreach_stmt
|
||||
| datablock_decl
|
||||
| switch_stmt
|
||||
| rwBREAK ';'
|
||||
{ $$ = BreakStmtNode::alloc( $1.lineNumber ); }
|
||||
| rwCONTINUE ';'
|
||||
{ $$ = ContinueStmtNode::alloc( $1.lineNumber ); }
|
||||
| rwRETURN ';'
|
||||
{ $$ = ReturnStmtNode::alloc( $1.lineNumber, NULL ); }
|
||||
| rwRETURN expr ';'
|
||||
{ $$ = ReturnStmtNode::alloc( $1.lineNumber, $2 ); }
|
||||
| expression_stmt ';'
|
||||
{ $$ = $1; }
|
||||
| TTAG '=' expr ';'
|
||||
{ $$ = TTagSetStmtNode::alloc( $1.lineNumber, $1.value, $3, NULL ); }
|
||||
| TTAG '=' expr ',' expr ';'
|
||||
{ $$ = TTagSetStmtNode::alloc( $1.lineNumber, $1.value, $3, $5 ); }
|
||||
| DOCBLOCK
|
||||
{ $$ = StrConstNode::alloc( $1.lineNumber, $1.value, false, true ); }
|
||||
;
|
||||
|
||||
fn_decl_stmt
|
||||
: rwDEFINE IDENT '(' var_list_decl ')' '{' statement_list '}'
|
||||
{ $$ = FunctionDeclStmtNode::alloc( $1.lineNumber, $2.value, NULL, $4, $7 ); }
|
||||
| rwDEFINE IDENT opCOLONCOLON IDENT '(' var_list_decl ')' '{' statement_list '}'
|
||||
{ $$ = FunctionDeclStmtNode::alloc( $1.lineNumber, $4.value, $2.value, $6, $9 ); }
|
||||
;
|
||||
|
||||
var_list_decl
|
||||
:
|
||||
{ $$ = NULL; }
|
||||
| var_list
|
||||
{ $$ = $1; }
|
||||
;
|
||||
|
||||
var_list
|
||||
: VAR
|
||||
{ $$ = VarNode::alloc( $1.lineNumber, $1.value, NULL ); }
|
||||
| var_list ',' VAR
|
||||
{ $$ = $1; ((StmtNode*)($1))->append((StmtNode*)VarNode::alloc( $3.lineNumber, $3.value, NULL ) ); }
|
||||
;
|
||||
|
||||
datablock_decl
|
||||
: rwDATABLOCK class_name_expr '(' expr parent_block ')' '{' slot_assign_list_opt '}' ';'
|
||||
{ $$ = ObjectDeclNode::alloc( $1.lineNumber, $2, $4, NULL, $5.value, $8, NULL, true, false, false); }
|
||||
;
|
||||
|
||||
object_decl
|
||||
: rwDECLARE class_name_expr '(' object_name parent_block object_args ')' '{' object_declare_block '}'
|
||||
{ $$ = ObjectDeclNode::alloc( $1.lineNumber, $2, $4, $6, $5.value, $9.slots, $9.decls, false, false, false); }
|
||||
| rwDECLARE class_name_expr '(' object_name parent_block object_args ')'
|
||||
{ $$ = ObjectDeclNode::alloc( $1.lineNumber, $2, $4, $6, $5.value, NULL, NULL, false, false, false); }
|
||||
| rwDECLARE class_name_expr '(' '[' object_name ']' parent_block object_args ')' '{' object_declare_block '}'
|
||||
{ $$ = ObjectDeclNode::alloc( $1.lineNumber, $2, $5, $8, $7.value, $11.slots, $11.decls, false, true, false); }
|
||||
| rwDECLARE class_name_expr '(' '[' object_name ']' parent_block object_args ')'
|
||||
{ $$ = ObjectDeclNode::alloc( $1.lineNumber, $2, $5, $8, $7.value, NULL, NULL, false, true, false); }
|
||||
| rwDECLARESINGLETON class_name_expr '(' object_name parent_block object_args ')' '{' object_declare_block '}'
|
||||
{ $$ = ObjectDeclNode::alloc( $1.lineNumber, $2, $4, $6, $5.value, $9.slots, $9.decls, false, false, true); }
|
||||
| rwDECLARESINGLETON class_name_expr '(' object_name parent_block object_args ')'
|
||||
{ $$ = ObjectDeclNode::alloc( $1.lineNumber, $2, $4, $6, $5.value, NULL, NULL, false, false, true); }
|
||||
;
|
||||
|
||||
parent_block
|
||||
:
|
||||
{ $$.value = NULL; }
|
||||
| ':' IDENT
|
||||
{ $$ = $2; }
|
||||
;
|
||||
|
||||
object_name
|
||||
:
|
||||
{ $$ = StrConstNode::alloc( CodeBlock::smCurrentParser->getCurrentLine(), "", false); }
|
||||
| expr
|
||||
{ $$ = $1; }
|
||||
;
|
||||
|
||||
object_args
|
||||
:
|
||||
{ $$ = NULL; }
|
||||
| ',' expr_list
|
||||
{ $$ = $2; }
|
||||
;
|
||||
|
||||
object_declare_block
|
||||
:
|
||||
{ $$.slots = NULL; $$.decls = NULL; }
|
||||
| slot_assign_list
|
||||
{ $$.slots = $1; $$.decls = NULL; }
|
||||
| object_decl_list
|
||||
{ $$.slots = NULL; $$.decls = $1; }
|
||||
| slot_assign_list object_decl_list
|
||||
{ $$.slots = $1; $$.decls = $2; }
|
||||
;
|
||||
|
||||
object_decl_list
|
||||
: object_decl ';'
|
||||
{ $$ = $1; }
|
||||
| object_decl_list object_decl ';'
|
||||
{ $1->append($2); $$ = $1; }
|
||||
;
|
||||
|
||||
stmt_block
|
||||
: '{' statement_list '}'
|
||||
{ $$ = $2; }
|
||||
| stmt
|
||||
{ $$ = $1; }
|
||||
;
|
||||
|
||||
switch_stmt
|
||||
: rwSWITCH '(' expr ')' '{' case_block '}'
|
||||
{ $$ = $6; $6->propagateSwitchExpr($3, false); }
|
||||
| rwSWITCHSTR '(' expr ')' '{' case_block '}'
|
||||
{ $$ = $6; $6->propagateSwitchExpr($3, true); }
|
||||
;
|
||||
|
||||
case_block
|
||||
: rwCASE case_expr ':' statement_list
|
||||
{ $$ = IfStmtNode::alloc( $1.lineNumber, $2, $4, NULL, false); }
|
||||
| rwCASE case_expr ':' statement_list rwDEFAULT ':' statement_list
|
||||
{ $$ = IfStmtNode::alloc( $1.lineNumber, $2, $4, $7, false); }
|
||||
| rwCASE case_expr ':' statement_list case_block
|
||||
{ $$ = IfStmtNode::alloc( $1.lineNumber, $2, $4, $5, true); }
|
||||
;
|
||||
|
||||
case_expr
|
||||
: expr
|
||||
{ $$ = $1;}
|
||||
| case_expr rwCASEOR expr
|
||||
{ ($1)->append($3); $$=$1; }
|
||||
;
|
||||
|
||||
if_stmt
|
||||
: rwIF '(' expr ')' stmt_block
|
||||
{ $$ = IfStmtNode::alloc($1.lineNumber, $3, $5, NULL, false); }
|
||||
| rwIF '(' expr ')' stmt_block rwELSE stmt_block
|
||||
{ $$ = IfStmtNode::alloc($1.lineNumber, $3, $5, $7, false); }
|
||||
;
|
||||
|
||||
while_stmt
|
||||
: rwWHILE '(' expr ')' stmt_block
|
||||
{ $$ = LoopStmtNode::alloc($1.lineNumber, nil, $3, nil, $5, false); }
|
||||
| rwDO stmt_block rwWHILE '(' expr ')'
|
||||
{ $$ = LoopStmtNode::alloc($3.lineNumber, nil, $5, nil, $2, true); }
|
||||
;
|
||||
|
||||
for_stmt
|
||||
: rwFOR '(' expr ';' expr ';' expr ')' stmt_block
|
||||
{ $$ = LoopStmtNode::alloc($1.lineNumber, $3, $5, $7, $9, false); }
|
||||
| rwFOR '(' expr ';' expr ';' ')' stmt_block
|
||||
{ $$ = LoopStmtNode::alloc($1.lineNumber, $3, $5, NULL, $8, false); }
|
||||
| rwFOR '(' expr ';' ';' expr ')' stmt_block
|
||||
{ $$ = LoopStmtNode::alloc($1.lineNumber, $3, NULL, $6, $8, false); }
|
||||
| rwFOR '(' expr ';' ';' ')' stmt_block
|
||||
{ $$ = LoopStmtNode::alloc($1.lineNumber, $3, NULL, NULL, $7, false); }
|
||||
| rwFOR '(' ';' expr ';' expr ')' stmt_block
|
||||
{ $$ = LoopStmtNode::alloc($1.lineNumber, NULL, $4, $6, $8, false); }
|
||||
| rwFOR '(' ';' expr ';' ')' stmt_block
|
||||
{ $$ = LoopStmtNode::alloc($1.lineNumber, NULL, $4, NULL, $7, false); }
|
||||
| rwFOR '(' ';' ';' expr ')' stmt_block
|
||||
{ $$ = LoopStmtNode::alloc($1.lineNumber, NULL, NULL, $5, $7, false); }
|
||||
| rwFOR '(' ';' ';' ')' stmt_block
|
||||
{ $$ = LoopStmtNode::alloc($1.lineNumber, NULL, NULL, NULL, $6, false); }
|
||||
;
|
||||
|
||||
foreach_stmt
|
||||
: rwFOREACH '(' VAR rwIN expr ')' stmt_block
|
||||
{ $$ = IterStmtNode::alloc( $1.lineNumber, $3.value, $5, $7, false ); }
|
||||
| rwFOREACHSTR '(' VAR rwIN expr ')' stmt_block
|
||||
{ $$ = IterStmtNode::alloc( $1.lineNumber, $3.value, $5, $7, true ); }
|
||||
;
|
||||
|
||||
expression_stmt
|
||||
: stmt_expr
|
||||
{ $$ = $1; }
|
||||
;
|
||||
|
||||
expr
|
||||
: stmt_expr
|
||||
{ $$ = $1; }
|
||||
| '(' expr ')'
|
||||
{ $$ = $2; }
|
||||
| expr '^' expr
|
||||
{ $$ = IntBinaryExprNode::alloc( $1->dbgLineNumber, $2.value, $1, $3); }
|
||||
| expr '%' expr
|
||||
{ $$ = IntBinaryExprNode::alloc( $1->dbgLineNumber, $2.value, $1, $3); }
|
||||
| expr '&' expr
|
||||
{ $$ = IntBinaryExprNode::alloc( $1->dbgLineNumber, $2.value, $1, $3); }
|
||||
| expr '|' expr
|
||||
{ $$ = IntBinaryExprNode::alloc( $1->dbgLineNumber, $2.value, $1, $3); }
|
||||
| expr '+' expr
|
||||
{ $$ = FloatBinaryExprNode::alloc( $1->dbgLineNumber, $2.value, $1, $3); }
|
||||
| expr '-' expr
|
||||
{ $$ = FloatBinaryExprNode::alloc( $1->dbgLineNumber, $2.value, $1, $3); }
|
||||
| expr '*' expr
|
||||
{ $$ = FloatBinaryExprNode::alloc( $1->dbgLineNumber, $2.value, $1, $3); }
|
||||
| expr '/' expr
|
||||
{ $$ = FloatBinaryExprNode::alloc( $1->dbgLineNumber, $2.value, $1, $3); }
|
||||
| '-' expr %prec UNARY
|
||||
{ $$ = FloatUnaryExprNode::alloc( $1.lineNumber, $1.value, $2); }
|
||||
| '*' expr %prec UNARY
|
||||
{ $$ = TTagDerefNode::alloc( $1.lineNumber, $2 ); }
|
||||
| TTAG
|
||||
{ $$ = TTagExprNode::alloc( $1.lineNumber, $1.value ); }
|
||||
| expr '?' expr ':' expr
|
||||
{ $$ = ConditionalExprNode::alloc( $1->dbgLineNumber, $1, $3, $5); }
|
||||
| expr '<' expr
|
||||
{ $$ = IntBinaryExprNode::alloc( $1->dbgLineNumber, $2.value, $1, $3); }
|
||||
| expr '>' expr
|
||||
{ $$ = IntBinaryExprNode::alloc( $1->dbgLineNumber, $2.value, $1, $3); }
|
||||
| expr opGE expr
|
||||
{ $$ = IntBinaryExprNode::alloc( $1->dbgLineNumber, $2.value, $1, $3); }
|
||||
| expr opLE expr
|
||||
{ $$ = IntBinaryExprNode::alloc( $1->dbgLineNumber, $2.value, $1, $3); }
|
||||
| expr opEQ expr
|
||||
{ $$ = IntBinaryExprNode::alloc( $1->dbgLineNumber, $2.value, $1, $3); }
|
||||
| expr opNE expr
|
||||
{ $$ = IntBinaryExprNode::alloc( $1->dbgLineNumber, $2.value, $1, $3); }
|
||||
| expr opOR expr
|
||||
{ $$ = IntBinaryExprNode::alloc( $1->dbgLineNumber, $2.value, $1, $3); }
|
||||
| expr opSHL expr
|
||||
{ $$ = IntBinaryExprNode::alloc( $1->dbgLineNumber, $2.value, $1, $3); }
|
||||
| expr opSHR expr
|
||||
{ $$ = IntBinaryExprNode::alloc( $1->dbgLineNumber, $2.value, $1, $3); }
|
||||
| expr opAND expr
|
||||
{ $$ = IntBinaryExprNode::alloc( $1->dbgLineNumber, $2.value, $1, $3); }
|
||||
| expr opSTREQ expr
|
||||
{ $$ = StreqExprNode::alloc( $1->dbgLineNumber, $1, $3, true); }
|
||||
| expr opSTRNE expr
|
||||
{ $$ = StreqExprNode::alloc( $1->dbgLineNumber, $1, $3, false); }
|
||||
| expr '@' expr
|
||||
{ $$ = StrcatExprNode::alloc( $1->dbgLineNumber, $1, $3, $2.value); }
|
||||
| '!' expr
|
||||
{ $$ = IntUnaryExprNode::alloc($1.lineNumber, $1.value, $2); }
|
||||
| '~' expr
|
||||
{ $$ = IntUnaryExprNode::alloc($1.lineNumber, $1.value, $2); }
|
||||
| TAGATOM
|
||||
{ $$ = StrConstNode::alloc( $1.lineNumber, $1.value, true); }
|
||||
| FLTCONST
|
||||
{ $$ = FloatNode::alloc( $1.lineNumber, $1.value ); }
|
||||
| INTCONST
|
||||
{ $$ = IntNode::alloc( $1.lineNumber, $1.value ); }
|
||||
| rwBREAK
|
||||
{ $$ = ConstantNode::alloc( $1.lineNumber, StringTable->insert("break")); }
|
||||
| slot_acc
|
||||
{ $$ = SlotAccessNode::alloc( $1.lineNumber, $1.object, $1.array, $1.slotName ); }
|
||||
| intslot_acc
|
||||
{ $$ = InternalSlotAccessNode::alloc( $1.lineNumber, $1.object, $1.slotExpr, $1.recurse); }
|
||||
| IDENT
|
||||
{ $$ = ConstantNode::alloc( $1.lineNumber, $1.value ); }
|
||||
| STRATOM
|
||||
{ $$ = StrConstNode::alloc( $1.lineNumber, $1.value, false); }
|
||||
| VAR
|
||||
{ $$ = (ExprNode*)VarNode::alloc( $1.lineNumber, $1.value, NULL); }
|
||||
| VAR '[' aidx_expr ']'
|
||||
{ $$ = (ExprNode*)VarNode::alloc( $1.lineNumber, $1.value, $3 ); }
|
||||
;
|
||||
/*
|
||||
| rwDEFINE '(' var_list_decl ')' '{' statement_list '}'
|
||||
{
|
||||
const U32 bufLen = 64;
|
||||
UTF8 buffer[bufLen];
|
||||
dSprintf(buffer, bufLen, "__anonymous_function%d", gAnonFunctionID++);
|
||||
StringTableEntry fName = StringTable->insert(buffer);
|
||||
StmtNode *fndef = FunctionDeclStmtNode::alloc($1.lineNumber, fName, NULL, $3, $6);
|
||||
|
||||
if(!gAnonFunctionList)
|
||||
gAnonFunctionList = fndef;
|
||||
else
|
||||
gAnonFunctionList->append(fndef);
|
||||
|
||||
$$ = StrConstNode::alloc( $1.lineNumber, (UTF8*)fName, false );
|
||||
}
|
||||
*/
|
||||
|
||||
slot_acc
|
||||
: expr '.' IDENT
|
||||
{ $$.lineNumber = $1->dbgLineNumber; $$.object = $1; $$.slotName = $3.value; $$.array = NULL; }
|
||||
| expr '.' IDENT '[' aidx_expr ']'
|
||||
{ $$.lineNumber = $1->dbgLineNumber; $$.object = $1; $$.slotName = $3.value; $$.array = $5; }
|
||||
;
|
||||
|
||||
intslot_acc
|
||||
: expr opINTNAME class_name_expr
|
||||
{ $$.lineNumber = $1->dbgLineNumber; $$.object = $1; $$.slotExpr = $3; $$.recurse = false; }
|
||||
| expr opINTNAMER class_name_expr
|
||||
{ $$.lineNumber = $1->dbgLineNumber; $$.object = $1; $$.slotExpr = $3; $$.recurse = true; }
|
||||
;
|
||||
|
||||
class_name_expr
|
||||
: IDENT
|
||||
{ $$ = ConstantNode::alloc( $1.lineNumber, $1.value ); }
|
||||
| '(' expr ')'
|
||||
{ $$ = $2; }
|
||||
;
|
||||
|
||||
assign_op_struct
|
||||
: opPLUSPLUS
|
||||
{ $$.lineNumber = $1.lineNumber; $$.token = opPLUSPLUS; $$.expr = FloatNode::alloc( $1.lineNumber, 1 ); }
|
||||
| opMINUSMINUS
|
||||
{ $$.lineNumber = $1.lineNumber; $$.token = opMINUSMINUS; $$.expr = FloatNode::alloc( $1.lineNumber, 1 ); }
|
||||
| opPLASN expr
|
||||
{ $$.lineNumber = $1.lineNumber; $$.token = '+'; $$.expr = $2; }
|
||||
| opMIASN expr
|
||||
{ $$.lineNumber = $1.lineNumber; $$.token = '-'; $$.expr = $2; }
|
||||
| opMLASN expr
|
||||
{ $$.lineNumber = $1.lineNumber; $$.token = '*'; $$.expr = $2; }
|
||||
| opDVASN expr
|
||||
{ $$.lineNumber = $1.lineNumber; $$.token = '/'; $$.expr = $2; }
|
||||
| opMODASN expr
|
||||
{ $$.lineNumber = $1.lineNumber; $$.token = '%'; $$.expr = $2; }
|
||||
| opANDASN expr
|
||||
{ $$.lineNumber = $1.lineNumber; $$.token = '&'; $$.expr = $2; }
|
||||
| opXORASN expr
|
||||
{ $$.lineNumber = $1.lineNumber; $$.token = '^'; $$.expr = $2; }
|
||||
| opORASN expr
|
||||
{ $$.lineNumber = $1.lineNumber; $$.token = '|'; $$.expr = $2; }
|
||||
| opSLASN expr
|
||||
{ $$.lineNumber = $1.lineNumber; $$.token = opSHL; $$.expr = $2; }
|
||||
| opSRASN expr
|
||||
{ $$.lineNumber = $1.lineNumber; $$.token = opSHR; $$.expr = $2; }
|
||||
;
|
||||
|
||||
stmt_expr
|
||||
: funcall_expr
|
||||
{ $$ = $1; }
|
||||
| assert_expr
|
||||
{ $$ = $1; }
|
||||
| object_decl
|
||||
{ $$ = $1; }
|
||||
| VAR '=' expr
|
||||
{ $$ = AssignExprNode::alloc( $1.lineNumber, $1.value, NULL, $3); }
|
||||
| VAR '[' aidx_expr ']' '=' expr
|
||||
{ $$ = AssignExprNode::alloc( $1.lineNumber, $1.value, $3, $6); }
|
||||
| VAR assign_op_struct
|
||||
{ $$ = AssignOpExprNode::alloc( $1.lineNumber, $1.value, NULL, $2.expr, $2.token); }
|
||||
| VAR '[' aidx_expr ']' assign_op_struct
|
||||
{ $$ = AssignOpExprNode::alloc( $1.lineNumber, $1.value, $3, $5.expr, $5.token); }
|
||||
| slot_acc assign_op_struct
|
||||
{ $$ = SlotAssignOpNode::alloc( $1.lineNumber, $1.object, $1.slotName, $1.array, $2.token, $2.expr); }
|
||||
| slot_acc '=' expr
|
||||
{ $$ = SlotAssignNode::alloc( $1.lineNumber, $1.object, $1.array, $1.slotName, $3); }
|
||||
| slot_acc '=' '{' expr_list '}'
|
||||
{ $$ = SlotAssignNode::alloc( $1.lineNumber, $1.object, $1.array, $1.slotName, $4); }
|
||||
;
|
||||
|
||||
funcall_expr
|
||||
: IDENT '(' expr_list_decl ')'
|
||||
{ $$ = FuncCallExprNode::alloc( $1.lineNumber, $1.value, NULL, $3, false); }
|
||||
| IDENT opCOLONCOLON IDENT '(' expr_list_decl ')'
|
||||
{ $$ = FuncCallExprNode::alloc( $1.lineNumber, $3.value, $1.value, $5, false); }
|
||||
| expr '.' IDENT '(' expr_list_decl ')'
|
||||
{ $1->append($5); $$ = FuncCallExprNode::alloc( $1->dbgLineNumber, $3.value, NULL, $1, true); }
|
||||
;
|
||||
/*
|
||||
| expr '(' expr_list_decl ')'
|
||||
{ $$ = FuncPointerCallExprNode::alloc( $1->dbgLineNumber, $1, $3); }
|
||||
;
|
||||
*/
|
||||
|
||||
assert_expr
|
||||
: rwASSERT '(' expr ')'
|
||||
{ $$ = AssertCallExprNode::alloc( $1.lineNumber, $3, NULL ); }
|
||||
| rwASSERT '(' expr ',' STRATOM ')'
|
||||
{ $$ = AssertCallExprNode::alloc( $1.lineNumber, $3, $5.value ); }
|
||||
;
|
||||
|
||||
expr_list_decl
|
||||
:
|
||||
{ $$ = NULL; }
|
||||
| expr_list
|
||||
{ $$ = $1; }
|
||||
;
|
||||
|
||||
expr_list
|
||||
: expr
|
||||
{ $$ = $1; }
|
||||
| expr_list ',' expr
|
||||
{ ($1)->append($3); $$ = $1; }
|
||||
;
|
||||
|
||||
slot_assign_list_opt
|
||||
:
|
||||
{ $$ = NULL; }
|
||||
| slot_assign_list
|
||||
{ $$ = $1; }
|
||||
;
|
||||
|
||||
slot_assign_list
|
||||
: slot_assign
|
||||
{ $$ = $1; }
|
||||
| slot_assign_list slot_assign
|
||||
{ $1->append($2); $$ = $1; }
|
||||
;
|
||||
|
||||
slot_assign
|
||||
: IDENT '=' expr ';'
|
||||
{ $$ = SlotAssignNode::alloc( $1.lineNumber, NULL, NULL, $1.value, $3); }
|
||||
| TYPEIDENT IDENT '=' expr ';'
|
||||
{ $$ = SlotAssignNode::alloc( $1.lineNumber, NULL, NULL, $2.value, $4, $1.value); }
|
||||
| rwDATABLOCK '=' expr ';'
|
||||
{ $$ = SlotAssignNode::alloc( $1.lineNumber, NULL, NULL, StringTable->insert("datablock"), $3); }
|
||||
| IDENT '[' aidx_expr ']' '=' expr ';'
|
||||
{ $$ = SlotAssignNode::alloc( $1.lineNumber, NULL, $3, $1.value, $6); }
|
||||
| TYPEIDENT IDENT '[' aidx_expr ']' '=' expr ';'
|
||||
{ $$ = SlotAssignNode::alloc( $1.lineNumber, NULL, $4, $2.value, $7, $1.value); }
|
||||
;
|
||||
|
||||
aidx_expr
|
||||
: expr
|
||||
{ $$ = $1; }
|
||||
| aidx_expr ',' expr
|
||||
{ $$ = CommaCatExprNode::alloc( $1->dbgLineNumber, $1, $3); }
|
||||
;
|
||||
%%
|
||||
|
||||
2557
Engine/source/console/torquescript/CMDscan.cpp
Normal file
2557
Engine/source/console/torquescript/CMDscan.cpp
Normal file
File diff suppressed because it is too large
Load diff
630
Engine/source/console/torquescript/CMDscan.l
Normal file
630
Engine/source/console/torquescript/CMDscan.l
Normal file
|
|
@ -0,0 +1,630 @@
|
|||
%{
|
||||
|
||||
// flex --nounput -o CMDscan.cpp -P CMD CMDscan.l
|
||||
|
||||
#define YYLMAX 4096
|
||||
#define YY_NO_UNISTD_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include "platform/platform.h"
|
||||
#include "core/stringTable.h"
|
||||
#include "console/console.h"
|
||||
#include "console/compiler.h"
|
||||
#include "console/dynamicTypes.h"
|
||||
#include "core/strings/stringFunctions.h"
|
||||
|
||||
template< typename T >
|
||||
struct Token
|
||||
{
|
||||
T value;
|
||||
S32 lineNumber;
|
||||
};
|
||||
|
||||
// Can't have ctors in structs used in unions, so we have this.
|
||||
template< typename T >
|
||||
inline Token< T > MakeToken( T value, U32 lineNumber )
|
||||
{
|
||||
Token< T > result;
|
||||
result.value = value;
|
||||
result.lineNumber = lineNumber;
|
||||
return result;
|
||||
}
|
||||
|
||||
#include "console/cmdgram.h"
|
||||
|
||||
// HACK: C++17 and beyond can't use register keyword
|
||||
#define register
|
||||
|
||||
using namespace Compiler;
|
||||
|
||||
#define YY_NEVER_INTERACTIVE 1
|
||||
|
||||
// Some basic parsing primitives...
|
||||
static int Sc_ScanDocBlock();
|
||||
static int Sc_ScanString(int ret);
|
||||
static int Sc_ScanNum();
|
||||
static int Sc_ScanVar();
|
||||
static int Sc_ScanHex();
|
||||
static int Sc_ScanIdent();
|
||||
|
||||
// Deal with debuggability of FLEX.
|
||||
#ifdef TORQUE_DEBUG
|
||||
#define FLEX_DEBUG 1
|
||||
#else
|
||||
#define FLEX_DEBUG 0
|
||||
#endif
|
||||
|
||||
// Install our own input code...
|
||||
#undef CMDgetc
|
||||
int CMDgetc();
|
||||
|
||||
// Hack to make windows lex happy.
|
||||
#ifndef isatty
|
||||
inline int isatty(int) { return 0; }
|
||||
#endif
|
||||
|
||||
// Wrap our getc, so that lex doesn't try to do its own buffering/file IO.
|
||||
#define YY_INPUT(buf,result,max_size) \
|
||||
{ \
|
||||
int c = '*', n; \
|
||||
for ( n = 0; n < max_size && \
|
||||
(c = CMDgetc()) != EOF && c != '\n'; ++n ) \
|
||||
buf[n] = (char) c; \
|
||||
if ( c == '\n' ) \
|
||||
buf[n++] = (char) c; \
|
||||
result = n; \
|
||||
}
|
||||
|
||||
// General helper stuff.
|
||||
static int lineIndex;
|
||||
|
||||
// File state
|
||||
void CMDSetScanBuffer(const char *sb, const char *fn);
|
||||
const char * CMDgetFileLine(int &lineNumber);
|
||||
|
||||
// Error reporting
|
||||
void CMDerror(const char * s, ...);
|
||||
|
||||
// Reset the parser.
|
||||
void CMDrestart(FILE *in);
|
||||
|
||||
%}
|
||||
|
||||
DIGIT [0-9]
|
||||
INTEGER {DIGIT}+
|
||||
FLOAT ({INTEGER}?\.{INTEGER})|({INTEGER}(\.{INTEGER})?[eE][+-]?{INTEGER})
|
||||
LETTER [A-Za-z_]
|
||||
FILECHAR [A-Za-z_\.]
|
||||
VARMID [:A-Za-z0-9_]
|
||||
IDTAIL [A-Za-z0-9_]
|
||||
VARTAIL {VARMID}*{IDTAIL}
|
||||
VAR [$%]{LETTER}{VARTAIL}*
|
||||
ID {LETTER}{IDTAIL}*
|
||||
ILID [$%]{DIGIT}+{LETTER}{VARTAIL}*
|
||||
FILENAME {FILECHAR}+
|
||||
SPACE [ \t\v\f]
|
||||
HEXDIGIT [a-fA-F0-9]
|
||||
|
||||
%%
|
||||
;
|
||||
{SPACE}+ { }
|
||||
("///"([^/\n\r][^\n\r]*)?[\n\r]+)+ { return(Sc_ScanDocBlock()); }
|
||||
"//"[^\n\r]* ;
|
||||
[\r] ;
|
||||
[\n] {lineIndex++;}
|
||||
\"(\\.|[^\\"\n\r])*\" { return(Sc_ScanString(STRATOM)); }
|
||||
\'(\\.|[^\\'\n\r])*\' { return(Sc_ScanString(TAGATOM)); }
|
||||
"==" { CMDlval.i = MakeToken< int >( opEQ, lineIndex ); return opEQ; }
|
||||
"!=" { CMDlval.i = MakeToken< int >( opNE, lineIndex ); return opNE; }
|
||||
">=" { CMDlval.i = MakeToken< int >( opGE, lineIndex ); return opGE; }
|
||||
"<=" { CMDlval.i = MakeToken< int >( opLE, lineIndex ); return opLE; }
|
||||
"&&" { CMDlval.i = MakeToken< int >( opAND, lineIndex ); return opAND; }
|
||||
"||" { CMDlval.i = MakeToken< int >( opOR, lineIndex ); return opOR; }
|
||||
"::" { CMDlval.i = MakeToken< int >( opCOLONCOLON, lineIndex ); return opCOLONCOLON; }
|
||||
"--" { CMDlval.i = MakeToken< int >( opMINUSMINUS, lineIndex ); return opMINUSMINUS; }
|
||||
"++" { CMDlval.i = MakeToken< int >( opPLUSPLUS, lineIndex ); return opPLUSPLUS; }
|
||||
"$=" { CMDlval.i = MakeToken< int >( opSTREQ, lineIndex ); return opSTREQ; }
|
||||
"!$=" { CMDlval.i = MakeToken< int >( opSTRNE, lineIndex ); return opSTRNE; }
|
||||
"<<" { CMDlval.i = MakeToken< int >( opSHL, lineIndex ); return opSHL; }
|
||||
">>" { CMDlval.i = MakeToken< int >( opSHR, lineIndex ); return opSHR; }
|
||||
"+=" { CMDlval.i = MakeToken< int >( opPLASN, lineIndex ); return opPLASN; }
|
||||
"-=" { CMDlval.i = MakeToken< int >( opMIASN, lineIndex ); return opMIASN; }
|
||||
"*=" { CMDlval.i = MakeToken< int >( opMLASN, lineIndex ); return opMLASN; }
|
||||
"/=" { CMDlval.i = MakeToken< int >( opDVASN, lineIndex ); return opDVASN; }
|
||||
"%=" { CMDlval.i = MakeToken< int >( opMODASN, lineIndex ); return opMODASN; }
|
||||
"&=" { CMDlval.i = MakeToken< int >( opANDASN, lineIndex ); return opANDASN; }
|
||||
"^=" { CMDlval.i = MakeToken< int >( opXORASN, lineIndex ); return opXORASN; }
|
||||
"|=" { CMDlval.i = MakeToken< int >( opORASN, lineIndex ); return opORASN; }
|
||||
"<<=" { CMDlval.i = MakeToken< int >( opSLASN, lineIndex ); return opSLASN; }
|
||||
">>=" { CMDlval.i = MakeToken< int >( opSRASN, lineIndex ); return opSRASN; }
|
||||
"->" { CMDlval.i = MakeToken< int >( opINTNAME, lineIndex ); return opINTNAME; }
|
||||
"-->" { CMDlval.i = MakeToken< int >( opINTNAMER, lineIndex ); return opINTNAMER; }
|
||||
"NL" { CMDlval.i = MakeToken< int >( '\n', lineIndex ); return '@'; }
|
||||
"TAB" { CMDlval.i = MakeToken< int >( '\t', lineIndex ); return '@'; }
|
||||
"SPC" { CMDlval.i = MakeToken< int >( ' ', lineIndex ); return '@'; }
|
||||
"@" { CMDlval.i = MakeToken< int >( 0, lineIndex ); return '@'; }
|
||||
"/*" { /* this comment stops syntax highlighting from getting messed up when editing the lexer in TextPad */
|
||||
int c = 0, l;
|
||||
for ( ; ; )
|
||||
{
|
||||
l = c;
|
||||
c = yyinput();
|
||||
|
||||
// Is this an open comment?
|
||||
if ( c == EOF )
|
||||
{
|
||||
CMDerror( "unexpected end of file found in comment" );
|
||||
break;
|
||||
}
|
||||
|
||||
// Increment line numbers.
|
||||
else if ( c == '\n' )
|
||||
lineIndex++;
|
||||
|
||||
// Did we find the end of the comment?
|
||||
else if ( l == '*' && c == '/' )
|
||||
break;
|
||||
}
|
||||
}
|
||||
"?" |
|
||||
"[" |
|
||||
"]" |
|
||||
"(" |
|
||||
")" |
|
||||
"+" |
|
||||
"-" |
|
||||
"*" |
|
||||
"/" |
|
||||
"<" |
|
||||
">" |
|
||||
"|" |
|
||||
"." |
|
||||
"!" |
|
||||
":" |
|
||||
";" |
|
||||
"{" |
|
||||
"}" |
|
||||
"," |
|
||||
"&" |
|
||||
"%" |
|
||||
"^" |
|
||||
"~" |
|
||||
"=" { CMDlval.i = MakeToken< int >( CMDtext[ 0 ], lineIndex ); return CMDtext[ 0 ]; }
|
||||
"in" { CMDlval.i = MakeToken< int >( rwIN, lineIndex ); return(rwIN); }
|
||||
"or" { CMDlval.i = MakeToken< int >( rwCASEOR, lineIndex ); return(rwCASEOR); }
|
||||
"break" { CMDlval.i = MakeToken< int >( rwBREAK, lineIndex ); return(rwBREAK); }
|
||||
"return" { CMDlval.i = MakeToken< int >( rwRETURN, lineIndex ); return(rwRETURN); }
|
||||
"else" { CMDlval.i = MakeToken< int >( rwELSE, lineIndex ); return(rwELSE); }
|
||||
"assert" { CMDlval.i = MakeToken< int >( rwASSERT, lineIndex ); return(rwASSERT); }
|
||||
"while" { CMDlval.i = MakeToken< int >( rwWHILE, lineIndex ); return(rwWHILE); }
|
||||
"do" { CMDlval.i = MakeToken< int >( rwDO, lineIndex ); return(rwDO); }
|
||||
"if" { CMDlval.i = MakeToken< int >( rwIF, lineIndex ); return(rwIF); }
|
||||
"foreach$" { CMDlval.i = MakeToken< int >( rwFOREACHSTR, lineIndex ); return(rwFOREACHSTR); }
|
||||
"foreach" { CMDlval.i = MakeToken< int >( rwFOREACH, lineIndex ); return(rwFOREACH); }
|
||||
"for" { CMDlval.i = MakeToken< int >( rwFOR, lineIndex ); return(rwFOR); }
|
||||
"continue" { CMDlval.i = MakeToken< int >( rwCONTINUE, lineIndex ); return(rwCONTINUE); }
|
||||
"function" { CMDlval.i = MakeToken< int >( rwDEFINE, lineIndex ); return(rwDEFINE); }
|
||||
"new" { CMDlval.i = MakeToken< int >( rwDECLARE, lineIndex ); return(rwDECLARE); }
|
||||
"singleton" { CMDlval.i = MakeToken< int >( rwDECLARESINGLETON, lineIndex ); return(rwDECLARESINGLETON); }
|
||||
"datablock" { CMDlval.i = MakeToken< int >( rwDATABLOCK, lineIndex ); return(rwDATABLOCK); }
|
||||
"case" { CMDlval.i = MakeToken< int >( rwCASE, lineIndex ); return(rwCASE); }
|
||||
"switch$" { CMDlval.i = MakeToken< int >( rwSWITCHSTR, lineIndex ); return(rwSWITCHSTR); }
|
||||
"switch" { CMDlval.i = MakeToken< int >( rwSWITCH, lineIndex ); return(rwSWITCH); }
|
||||
"default" { CMDlval.i = MakeToken< int >( rwDEFAULT, lineIndex ); return(rwDEFAULT); }
|
||||
"package" { CMDlval.i = MakeToken< int >( rwPACKAGE, lineIndex ); return(rwPACKAGE); }
|
||||
"namespace" { CMDlval.i = MakeToken< int >( rwNAMESPACE, lineIndex ); return(rwNAMESPACE); }
|
||||
"true" { CMDlval.i = MakeToken< int >( 1, lineIndex ); return INTCONST; }
|
||||
"false" { CMDlval.i = MakeToken< int >( 0, lineIndex ); return INTCONST; }
|
||||
{VAR} { return(Sc_ScanVar()); }
|
||||
|
||||
{ID} { return Sc_ScanIdent(); }
|
||||
0[xX]{HEXDIGIT}+ return(Sc_ScanHex());
|
||||
{INTEGER} { CMDtext[CMDleng] = 0; CMDlval.i = MakeToken< int >( dAtoi(CMDtext), lineIndex ); return INTCONST; }
|
||||
{FLOAT} return Sc_ScanNum();
|
||||
{ILID} return(ILLEGAL_TOKEN);
|
||||
. return(ILLEGAL_TOKEN);
|
||||
%%
|
||||
|
||||
static const char *scanBuffer;
|
||||
static const char *fileName;
|
||||
static int scanIndex;
|
||||
|
||||
const char * CMDGetCurrentFile()
|
||||
{
|
||||
return fileName;
|
||||
}
|
||||
|
||||
int CMDGetCurrentLine()
|
||||
{
|
||||
return lineIndex;
|
||||
}
|
||||
|
||||
extern bool gConsoleSyntaxError;
|
||||
|
||||
void CMDerror(const char *format, ...)
|
||||
{
|
||||
Compiler::gSyntaxError = true;
|
||||
|
||||
const int BUFMAX = 1024;
|
||||
char tempBuf[BUFMAX];
|
||||
va_list args;
|
||||
va_start( args, format );
|
||||
#ifdef TORQUE_OS_WIN
|
||||
_vsnprintf( tempBuf, BUFMAX, format, args );
|
||||
#else
|
||||
vsnprintf( tempBuf, BUFMAX, format, args );
|
||||
#endif
|
||||
va_end(args);
|
||||
|
||||
if(fileName)
|
||||
{
|
||||
Con::errorf(ConsoleLogEntry::Script, "%s Line: %d - %s", fileName, lineIndex, tempBuf);
|
||||
|
||||
#ifndef NO_ADVANCED_ERROR_REPORT
|
||||
// dhc - lineIndex is bogus. let's try to add some sanity back in.
|
||||
int i,j,n;
|
||||
char c;
|
||||
int linediv = 1;
|
||||
// first, walk the buffer, trying to detect line ending type.
|
||||
// this is imperfect, if inconsistant line endings exist...
|
||||
for (i=0; i<scanIndex; i++)
|
||||
{
|
||||
c = scanBuffer[i];
|
||||
if (c=='\r' && scanBuffer[i+1]=='\n') linediv = 2; // crlf detected
|
||||
if (c=='\r' || c=='\n' || c==0) break; // enough for us to stop.
|
||||
}
|
||||
// grab some of the chars starting at the error location - lineending.
|
||||
i = 1; j = 0; n = 1;
|
||||
// find prev lineending
|
||||
while (n<BUFMAX-8 && i<scanIndex) // cap at file start
|
||||
{
|
||||
c = scanBuffer[scanIndex-i];
|
||||
if ((c=='\r' || c=='\n') && i>BUFMAX>>2) break; // at least get a little data
|
||||
n++; i++;
|
||||
}
|
||||
// find next lineending
|
||||
while (n<BUFMAX-8 && j<BUFMAX>>1) // cap at half-buf-size forward
|
||||
{
|
||||
c = scanBuffer[scanIndex+j];
|
||||
if (c==0) break;
|
||||
if ((c=='\r' || c=='\n') && j>BUFMAX>>2) break; // at least get a little data
|
||||
n++; j++;
|
||||
}
|
||||
if (i) i--; // chop off extra linefeed.
|
||||
if (j) j--; // chop off extra linefeed.
|
||||
// build our little text block
|
||||
if (i) dStrncpy(tempBuf,scanBuffer+scanIndex-i,i);
|
||||
dStrncpy(tempBuf+i,"##", 2); // bracketing.
|
||||
tempBuf[i+2] = scanBuffer[scanIndex]; // copy the halt character.
|
||||
dStrncpy(tempBuf+i+3,"##", 2); // bracketing.
|
||||
if (j) dStrncpy(tempBuf+i+5,scanBuffer+scanIndex+1,j); // +1 to go past current char.
|
||||
tempBuf[i+j+5] = 0; // null terminate
|
||||
for(n=0; n<i+j+5; n++) // convert CR to LF if alone...
|
||||
if (tempBuf[n]=='\r' && tempBuf[n+1]!='\n') tempBuf[n] = '\n';
|
||||
// write out to console the advanced error report
|
||||
Con::warnf(ConsoleLogEntry::Script, ">>> Advanced script error report. Line %d.", lineIndex);
|
||||
Con::warnf(ConsoleLogEntry::Script, ">>> Some error context, with ## on sides of error halt:");
|
||||
Con::errorf(ConsoleLogEntry::Script, "%s", tempBuf);
|
||||
Con::warnf(ConsoleLogEntry::Script, ">>> Error report complete.\n");
|
||||
#endif
|
||||
|
||||
// Update the script-visible error buffer.
|
||||
const char *prevStr = Con::getVariable("$ScriptError");
|
||||
if (prevStr[0])
|
||||
dSprintf(tempBuf, sizeof(tempBuf), "%s\n%s Line: %d - Syntax error.", prevStr, fileName, lineIndex);
|
||||
else
|
||||
dSprintf(tempBuf, sizeof(tempBuf), "%s Line: %d - Syntax error.", fileName, lineIndex);
|
||||
Con::setVariable("$ScriptError", tempBuf);
|
||||
|
||||
// We also need to mark that we came up with a new error.
|
||||
static S32 sScriptErrorHash=1000;
|
||||
Con::setIntVariable("$ScriptErrorHash", sScriptErrorHash++);
|
||||
}
|
||||
else
|
||||
Con::errorf(ConsoleLogEntry::Script, tempBuf);
|
||||
}
|
||||
|
||||
void CMDSetScanBuffer(const char *sb, const char *fn)
|
||||
{
|
||||
scanBuffer = sb;
|
||||
fileName = fn;
|
||||
scanIndex = 0;
|
||||
lineIndex = 1;
|
||||
}
|
||||
|
||||
int CMDgetc()
|
||||
{
|
||||
int ret = scanBuffer[scanIndex];
|
||||
if(ret)
|
||||
scanIndex++;
|
||||
else
|
||||
ret = -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int CMDwrap()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int Sc_ScanVar()
|
||||
{
|
||||
// Truncate the temp buffer...
|
||||
CMDtext[CMDleng] = 0;
|
||||
|
||||
// Make it a stringtable string!
|
||||
CMDlval.s = MakeToken< StringTableEntry >( StringTable->insert(CMDtext), lineIndex );
|
||||
return(VAR);
|
||||
}
|
||||
|
||||
static int charConv(int in)
|
||||
{
|
||||
switch(in)
|
||||
{
|
||||
case 'r':
|
||||
return '\r';
|
||||
case 'n':
|
||||
return '\n';
|
||||
case 't':
|
||||
return '\t';
|
||||
default:
|
||||
return in;
|
||||
}
|
||||
}
|
||||
|
||||
static int getHexDigit(char c)
|
||||
{
|
||||
if(c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
if(c >= 'A' && c <= 'F')
|
||||
return c - 'A' + 10;
|
||||
if(c >= 'a' && c <= 'f')
|
||||
return c - 'a' + 10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int Sc_ScanDocBlock()
|
||||
{
|
||||
S32 len = dStrlen(CMDtext);
|
||||
char* text = (char *) consoleAlloc(len + 1);
|
||||
S32 line = lineIndex;
|
||||
|
||||
for( S32 i = 0, j = 0; j <= len; j++ )
|
||||
{
|
||||
if( ( j <= (len - 2) ) && ( CMDtext[j] == '/' ) && ( CMDtext[j + 1] == '/' ) && ( CMDtext[j + 2] == '/' ) )
|
||||
{
|
||||
j += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( CMDtext[j] == '\r' )
|
||||
continue;
|
||||
|
||||
if( CMDtext[j] == '\n' )
|
||||
lineIndex++;
|
||||
|
||||
text[i++] = CMDtext[j];
|
||||
}
|
||||
|
||||
CMDlval.str = MakeToken< char* >( text, line );
|
||||
return(DOCBLOCK);
|
||||
}
|
||||
|
||||
static int Sc_ScanString(int ret)
|
||||
{
|
||||
CMDtext[CMDleng - 1] = 0;
|
||||
if(!collapseEscape(CMDtext+1))
|
||||
return -1;
|
||||
|
||||
dsize_t bufferLen = dStrlen( CMDtext );
|
||||
char* buffer = ( char* ) consoleAlloc( bufferLen );
|
||||
dStrcpy( buffer, CMDtext + 1, bufferLen );
|
||||
|
||||
CMDlval.str = MakeToken< char* >( buffer, lineIndex );
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int Sc_ScanIdent()
|
||||
{
|
||||
ConsoleBaseType *type;
|
||||
|
||||
CMDtext[CMDleng] = 0;
|
||||
|
||||
if((type = ConsoleBaseType::getTypeByName(CMDtext)) != NULL)
|
||||
{
|
||||
/* It's a type */
|
||||
CMDlval.i = MakeToken< int >( type->getTypeID(), lineIndex );
|
||||
return TYPEIDENT;
|
||||
}
|
||||
|
||||
/* It's an identifier */
|
||||
CMDlval.s = MakeToken< StringTableEntry >( StringTable->insert(CMDtext), lineIndex );
|
||||
return IDENT;
|
||||
}
|
||||
|
||||
void expandEscape(char *dest, const char *src)
|
||||
{
|
||||
U8 c;
|
||||
while((c = (U8) *src++) != 0)
|
||||
{
|
||||
if(c == '\"')
|
||||
{
|
||||
*dest++ = '\\';
|
||||
*dest++ = '\"';
|
||||
}
|
||||
else if(c == '\\')
|
||||
{
|
||||
*dest++ = '\\';
|
||||
*dest++ = '\\';
|
||||
}
|
||||
else if(c == '\r')
|
||||
{
|
||||
*dest++ = '\\';
|
||||
*dest++ = 'r';
|
||||
}
|
||||
else if(c == '\n')
|
||||
{
|
||||
*dest++ = '\\';
|
||||
*dest++ = 'n';
|
||||
}
|
||||
else if(c == '\t')
|
||||
{
|
||||
*dest++ = '\\';
|
||||
*dest++ = 't';
|
||||
}
|
||||
else if(c == '\'')
|
||||
{
|
||||
*dest++ = '\\';
|
||||
*dest++ = '\'';
|
||||
}
|
||||
else if((c >= 1 && c <= 7) ||
|
||||
(c >= 11 && c <= 12) ||
|
||||
(c >= 14 && c <= 15))
|
||||
{
|
||||
/* Remap around: \b = 0x8, \t = 0x9, \n = 0xa, \r = 0xd */
|
||||
static U8 expandRemap[15] = { 0x0,
|
||||
0x0,
|
||||
0x1,
|
||||
0x2,
|
||||
0x3,
|
||||
0x4,
|
||||
0x5,
|
||||
0x6,
|
||||
0x0,
|
||||
0x0,
|
||||
0x0,
|
||||
0x7,
|
||||
0x8,
|
||||
0x0,
|
||||
0x9 };
|
||||
|
||||
*dest++ = '\\';
|
||||
*dest++ = 'c';
|
||||
if(c == 15)
|
||||
*dest++ = 'r';
|
||||
else if(c == 16)
|
||||
*dest++ = 'p';
|
||||
else if(c == 17)
|
||||
*dest++ = 'o';
|
||||
else
|
||||
*dest++ = expandRemap[c] + '0';
|
||||
}
|
||||
else if(c < 32)
|
||||
{
|
||||
*dest++ = '\\';
|
||||
*dest++ = 'x';
|
||||
S32 dig1 = c >> 4;
|
||||
S32 dig2 = c & 0xf;
|
||||
if(dig1 < 10)
|
||||
dig1 += '0';
|
||||
else
|
||||
dig1 += 'A' - 10;
|
||||
if(dig2 < 10)
|
||||
dig2 += '0';
|
||||
else
|
||||
dig2 += 'A' - 10;
|
||||
*dest++ = dig1;
|
||||
*dest++ = dig2;
|
||||
}
|
||||
else
|
||||
*dest++ = c;
|
||||
}
|
||||
*dest = '\0';
|
||||
}
|
||||
|
||||
bool collapseEscape(char *buf)
|
||||
{
|
||||
S32 len = dStrlen(buf) + 1;
|
||||
for(S32 i = 0; i < len;)
|
||||
{
|
||||
if(buf[i] == '\\')
|
||||
{
|
||||
if(buf[i+1] == 'x')
|
||||
{
|
||||
S32 dig1 = getHexDigit(buf[i+2]);
|
||||
if(dig1 == -1)
|
||||
return false;
|
||||
|
||||
S32 dig2 = getHexDigit(buf[i+3]);
|
||||
if(dig2 == -1)
|
||||
return false;
|
||||
buf[i] = dig1 * 16 + dig2;
|
||||
dMemmove(buf + i + 1, buf + i + 4, len - i - 3);
|
||||
len -= 3;
|
||||
i++;
|
||||
}
|
||||
else if(buf[i+1] == 'c')
|
||||
{
|
||||
/* Remap around: \b = 0x8, \t = 0x9, \n = 0xa, \r = 0xd */
|
||||
static U8 collapseRemap[10] = { 0x1,
|
||||
0x2,
|
||||
0x3,
|
||||
0x4,
|
||||
0x5,
|
||||
0x6,
|
||||
0x7,
|
||||
0xb,
|
||||
0xc,
|
||||
0xe };
|
||||
|
||||
if(buf[i+2] == 'r')
|
||||
buf[i] = 15;
|
||||
else if(buf[i+2] == 'p')
|
||||
buf[i] = 16;
|
||||
else if(buf[i+2] == 'o')
|
||||
buf[i] = 17;
|
||||
else
|
||||
{
|
||||
int dig1 = buf[i+2] - '0';
|
||||
if(dig1 < 0 || dig1 > 9)
|
||||
return false;
|
||||
buf[i] = collapseRemap[dig1];
|
||||
}
|
||||
// Make sure we don't put 0x1 at the beginning of the string.
|
||||
if ((buf[i] == 0x1) && (i == 0))
|
||||
{
|
||||
buf[i] = 0x2;
|
||||
buf[i+1] = 0x1;
|
||||
dMemmove(buf + i + 2, buf + i + 3, len - i - 1);
|
||||
len -= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
dMemmove(buf + i + 1, buf + i + 3, len - i - 2);
|
||||
len -= 2;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
buf[i] = charConv(buf[i+1]);
|
||||
dMemmove(buf + i + 1, buf + i + 2, len - i - 1);
|
||||
len--;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int Sc_ScanNum()
|
||||
{
|
||||
CMDtext[CMDleng] = 0;
|
||||
CMDlval.f = MakeToken< double >( dAtof(CMDtext), lineIndex );
|
||||
return(FLTCONST);
|
||||
}
|
||||
|
||||
static int Sc_ScanHex()
|
||||
{
|
||||
S32 val = 0;
|
||||
dSscanf(CMDtext, "%x", &val);
|
||||
CMDlval.i = MakeToken< int >( val, lineIndex );
|
||||
return INTCONST;
|
||||
}
|
||||
|
||||
void CMD_reset()
|
||||
{
|
||||
CMDrestart(NULL);
|
||||
}
|
||||
606
Engine/source/console/torquescript/ast.h
Normal file
606
Engine/source/console/torquescript/ast.h
Normal file
|
|
@ -0,0 +1,606 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _AST_H_
|
||||
#define _AST_H_
|
||||
|
||||
#include "evalState.h"
|
||||
#include "platform/types.h"
|
||||
|
||||
class SimObject;
|
||||
class SimGroup;
|
||||
class CodeStream;
|
||||
|
||||
/// Enable this #define if you are seeing the message "precompile size mismatch" in the console.
|
||||
/// This will help track down which node type is causing the error. It could be
|
||||
/// due to incorrect compiler optimization.
|
||||
//#define DEBUG_AST_NODES
|
||||
|
||||
enum TypeReq
|
||||
{
|
||||
TypeReqNone,
|
||||
TypeReqUInt,
|
||||
TypeReqFloat,
|
||||
TypeReqString
|
||||
};
|
||||
|
||||
enum ExprNodeName
|
||||
{
|
||||
NameExprNode,
|
||||
NameFloatNode,
|
||||
NameIntNode,
|
||||
NameVarNode
|
||||
};
|
||||
|
||||
/// Representation of a node for the scripting language parser.
|
||||
///
|
||||
/// When the scripting language is evaluated, it is turned from a string representation,
|
||||
/// into a parse tree, thence into byte code, which is ultimately interpreted by the VM.
|
||||
///
|
||||
/// This is the base class for the nodes in the parse tree. There are a great many subclasses,
|
||||
/// each representing a different language construct.
|
||||
struct StmtNode
|
||||
{
|
||||
StmtNode* next; ///< Next entry in parse tree.
|
||||
|
||||
StmtNode();
|
||||
virtual ~StmtNode() {}
|
||||
|
||||
/// @name next Accessors
|
||||
/// @{
|
||||
|
||||
///
|
||||
void append(StmtNode* next);
|
||||
StmtNode* getNext() const { return next; }
|
||||
|
||||
/// @}
|
||||
|
||||
/// @name Debug Info
|
||||
/// @{
|
||||
|
||||
StringTableEntry dbgFileName; ///< Name of file this node is associated with.
|
||||
S32 dbgLineNumber; ///< Line number this node is associated with.
|
||||
#ifdef DEBUG_AST_NODES
|
||||
virtual String dbgStmtType() const = 0;
|
||||
#endif
|
||||
/// @}
|
||||
|
||||
/// @name Breaking
|
||||
/// @{
|
||||
|
||||
void addBreakLine(CodeStream& codeStream);
|
||||
/// @}
|
||||
|
||||
/// @name Compilation
|
||||
/// @{
|
||||
|
||||
virtual U32 compileStmt(CodeStream& codeStream, U32 ip) = 0;
|
||||
virtual void setPackage(StringTableEntry packageName);
|
||||
/// @}
|
||||
};
|
||||
|
||||
/// Helper macro
|
||||
#ifndef DEBUG_AST_NODES
|
||||
# define DBG_STMT_TYPE(s) virtual const char* dbgStmtType() const { return "#s"; }
|
||||
#else
|
||||
# define DBG_STMT_TYPE(s)
|
||||
#endif
|
||||
|
||||
struct BreakStmtNode : StmtNode
|
||||
{
|
||||
static BreakStmtNode* alloc(S32 lineNumber);
|
||||
|
||||
|
||||
U32 compileStmt(CodeStream& codeStream, U32 ip);
|
||||
DBG_STMT_TYPE(BreakStmtNode);
|
||||
};
|
||||
|
||||
struct ContinueStmtNode : StmtNode
|
||||
{
|
||||
static ContinueStmtNode* alloc(S32 lineNumber);
|
||||
|
||||
U32 compileStmt(CodeStream& codeStream, U32 ip);
|
||||
DBG_STMT_TYPE(ContinueStmtNode);
|
||||
};
|
||||
|
||||
/// A mathematical expression.
|
||||
struct ExprNode : StmtNode
|
||||
{
|
||||
ExprNode* optimizedNode;
|
||||
|
||||
U32 compileStmt(CodeStream& codeStream, U32 ip);
|
||||
|
||||
virtual U32 compile(CodeStream& codeStream, U32 ip, TypeReq type) = 0;
|
||||
virtual TypeReq getPreferredType() = 0;
|
||||
virtual ExprNodeName getExprNodeNameEnum() const { return NameExprNode; }
|
||||
};
|
||||
|
||||
struct ReturnStmtNode : StmtNode
|
||||
{
|
||||
ExprNode* expr;
|
||||
|
||||
static ReturnStmtNode* alloc(S32 lineNumber, ExprNode* expr);
|
||||
|
||||
U32 compileStmt(CodeStream& codeStream, U32 ip);
|
||||
DBG_STMT_TYPE(ReturnStmtNode);
|
||||
};
|
||||
|
||||
struct IfStmtNode : StmtNode
|
||||
{
|
||||
ExprNode* testExpr;
|
||||
StmtNode* ifBlock, * elseBlock;
|
||||
U32 endifOffset;
|
||||
U32 elseOffset;
|
||||
bool integer;
|
||||
bool propagate;
|
||||
|
||||
static IfStmtNode* alloc(S32 lineNumber, ExprNode* testExpr, StmtNode* ifBlock, StmtNode* elseBlock, bool propagateThrough);
|
||||
void propagateSwitchExpr(ExprNode* left, bool string);
|
||||
ExprNode* getSwitchOR(ExprNode* left, ExprNode* list, bool string);
|
||||
|
||||
U32 compileStmt(CodeStream& codeStream, U32 ip);
|
||||
DBG_STMT_TYPE(IfStmtNode);
|
||||
};
|
||||
|
||||
struct LoopStmtNode : StmtNode
|
||||
{
|
||||
ExprNode* testExpr;
|
||||
ExprNode* initExpr;
|
||||
ExprNode* endLoopExpr;
|
||||
StmtNode* loopBlock;
|
||||
bool isDoLoop;
|
||||
U32 breakOffset;
|
||||
U32 continueOffset;
|
||||
U32 loopBlockStartOffset;
|
||||
bool integer;
|
||||
|
||||
static LoopStmtNode* alloc(S32 lineNumber, ExprNode* testExpr, ExprNode* initExpr, ExprNode* endLoopExpr, StmtNode* loopBlock, bool isDoLoop);
|
||||
|
||||
U32 compileStmt(CodeStream& codeStream, U32 ip);
|
||||
DBG_STMT_TYPE(LoopStmtNode);
|
||||
};
|
||||
|
||||
/// A "foreach" statement.
|
||||
struct IterStmtNode : StmtNode
|
||||
{
|
||||
/// Local variable name to use for the container element.
|
||||
StringTableEntry varName;
|
||||
|
||||
/// Expression evaluating to a SimSet object.
|
||||
ExprNode* containerExpr;
|
||||
|
||||
/// The statement body.
|
||||
StmtNode* body;
|
||||
|
||||
/// If true, this is a 'foreach$'.
|
||||
bool isStringIter;
|
||||
|
||||
/// Bytecode size of body statement. Set by precompileStmt.
|
||||
U32 bodySize;
|
||||
|
||||
static IterStmtNode* alloc(S32 lineNumber, StringTableEntry varName, ExprNode* containerExpr, StmtNode* body, bool isStringIter);
|
||||
|
||||
U32 compileStmt(CodeStream& codeStream, U32 ip);
|
||||
};
|
||||
|
||||
/// A binary mathematical expression (ie, left op right).
|
||||
struct BinaryExprNode : ExprNode
|
||||
{
|
||||
S32 op;
|
||||
ExprNode* left;
|
||||
ExprNode* right;
|
||||
};
|
||||
|
||||
struct FloatBinaryExprNode : BinaryExprNode
|
||||
{
|
||||
static FloatBinaryExprNode* alloc(S32 lineNumber, S32 op, ExprNode* left, ExprNode* right);
|
||||
|
||||
U32 compile(CodeStream& codeStream, U32 ip, TypeReq type);
|
||||
|
||||
bool optimize();
|
||||
|
||||
TypeReq getPreferredType();
|
||||
DBG_STMT_TYPE(FloatBinaryExprNode);
|
||||
};
|
||||
|
||||
struct ConditionalExprNode : ExprNode
|
||||
{
|
||||
ExprNode* testExpr;
|
||||
ExprNode* trueExpr;
|
||||
ExprNode* falseExpr;
|
||||
bool integer;
|
||||
static ConditionalExprNode* alloc(S32 lineNumber, ExprNode* testExpr, ExprNode* trueExpr, ExprNode* falseExpr);
|
||||
|
||||
virtual U32 compile(CodeStream& codeStream, U32 ip, TypeReq type);
|
||||
virtual TypeReq getPreferredType();
|
||||
DBG_STMT_TYPE(ConditionalExprNode);
|
||||
};
|
||||
|
||||
struct IntBinaryExprNode : BinaryExprNode
|
||||
{
|
||||
TypeReq subType;
|
||||
U32 operand;
|
||||
|
||||
static IntBinaryExprNode* alloc(S32 lineNumber, S32 op, ExprNode* left, ExprNode* right);
|
||||
|
||||
void getSubTypeOperand();
|
||||
|
||||
bool optimize();
|
||||
|
||||
U32 compile(CodeStream& codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
DBG_STMT_TYPE(IntBinaryExprNode);
|
||||
};
|
||||
|
||||
struct StreqExprNode : BinaryExprNode
|
||||
{
|
||||
bool eq;
|
||||
static StreqExprNode* alloc(S32 lineNumber, ExprNode* left, ExprNode* right, bool eq);
|
||||
|
||||
U32 compile(CodeStream& codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
DBG_STMT_TYPE(StreqExprNode);
|
||||
};
|
||||
|
||||
struct StrcatExprNode : BinaryExprNode
|
||||
{
|
||||
S32 appendChar;
|
||||
static StrcatExprNode* alloc(S32 lineNumber, ExprNode* left, ExprNode* right, S32 appendChar);
|
||||
|
||||
U32 compile(CodeStream& codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
DBG_STMT_TYPE(StrcatExprNode);
|
||||
};
|
||||
|
||||
struct CommaCatExprNode : BinaryExprNode
|
||||
{
|
||||
static CommaCatExprNode* alloc(S32 lineNumber, ExprNode* left, ExprNode* right);
|
||||
|
||||
|
||||
U32 compile(CodeStream& codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
DBG_STMT_TYPE(CommaCatExprNode);
|
||||
};
|
||||
|
||||
struct IntUnaryExprNode : ExprNode
|
||||
{
|
||||
S32 op;
|
||||
ExprNode* expr;
|
||||
bool integer;
|
||||
|
||||
static IntUnaryExprNode* alloc(S32 lineNumber, S32 op, ExprNode* expr);
|
||||
|
||||
U32 compile(CodeStream& codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
DBG_STMT_TYPE(IntUnaryExprNode);
|
||||
};
|
||||
|
||||
struct FloatUnaryExprNode : ExprNode
|
||||
{
|
||||
S32 op;
|
||||
ExprNode* expr;
|
||||
|
||||
static FloatUnaryExprNode* alloc(S32 lineNumber, S32 op, ExprNode* expr);
|
||||
|
||||
U32 compile(CodeStream& codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
DBG_STMT_TYPE(FloatUnaryExprNode);
|
||||
};
|
||||
|
||||
struct VarNode : ExprNode
|
||||
{
|
||||
StringTableEntry varName;
|
||||
ExprNode* arrayIndex;
|
||||
|
||||
static VarNode* alloc(S32 lineNumber, StringTableEntry varName, ExprNode* arrayIndex);
|
||||
|
||||
U32 compile(CodeStream& codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
virtual ExprNodeName getExprNodeNameEnum() const { return NameVarNode; }
|
||||
DBG_STMT_TYPE(VarNode);
|
||||
};
|
||||
|
||||
struct IntNode : ExprNode
|
||||
{
|
||||
S32 value;
|
||||
U32 index; // if it's converted to float/string
|
||||
|
||||
static IntNode* alloc(S32 lineNumber, S32 value);
|
||||
|
||||
U32 compile(CodeStream& codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
virtual ExprNodeName getExprNodeNameEnum() const { return NameIntNode; }
|
||||
DBG_STMT_TYPE(IntNode);
|
||||
};
|
||||
|
||||
struct FloatNode : ExprNode
|
||||
{
|
||||
F64 value;
|
||||
U32 index;
|
||||
|
||||
static FloatNode* alloc(S32 lineNumber, F64 value);
|
||||
|
||||
U32 compile(CodeStream& codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
virtual ExprNodeName getExprNodeNameEnum() const { return NameFloatNode; }
|
||||
DBG_STMT_TYPE(FloatNode);
|
||||
};
|
||||
|
||||
struct StrConstNode : ExprNode
|
||||
{
|
||||
char* str;
|
||||
F64 fVal;
|
||||
U32 index;
|
||||
bool tag;
|
||||
bool doc; // Specifies that this string is a documentation block.
|
||||
|
||||
static StrConstNode* alloc(S32 lineNumber, const char* str, bool tag, bool doc = false);
|
||||
|
||||
U32 compile(CodeStream& codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
DBG_STMT_TYPE(StrConstNode);
|
||||
};
|
||||
|
||||
struct ConstantNode : ExprNode
|
||||
{
|
||||
StringTableEntry value;
|
||||
F64 fVal;
|
||||
U32 index;
|
||||
|
||||
static ConstantNode* alloc(S32 lineNumber, StringTableEntry value);
|
||||
|
||||
U32 compile(CodeStream& codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
DBG_STMT_TYPE(ConstantNode);
|
||||
};
|
||||
|
||||
struct AssignExprNode : ExprNode
|
||||
{
|
||||
StringTableEntry varName;
|
||||
ExprNode* expr;
|
||||
ExprNode* arrayIndex;
|
||||
TypeReq subType;
|
||||
|
||||
static AssignExprNode* alloc(S32 lineNumber, StringTableEntry varName, ExprNode* arrayIndex, ExprNode* expr);
|
||||
|
||||
U32 compile(CodeStream& codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
DBG_STMT_TYPE(AssignExprNode);
|
||||
};
|
||||
|
||||
struct AssignDecl
|
||||
{
|
||||
S32 lineNumber;
|
||||
S32 token;
|
||||
ExprNode* expr;
|
||||
bool integer;
|
||||
};
|
||||
|
||||
struct AssignOpExprNode : ExprNode
|
||||
{
|
||||
StringTableEntry varName;
|
||||
ExprNode* expr;
|
||||
ExprNode* arrayIndex;
|
||||
S32 op;
|
||||
U32 operand;
|
||||
TypeReq subType;
|
||||
|
||||
static AssignOpExprNode* alloc(S32 lineNumber, StringTableEntry varName, ExprNode* arrayIndex, ExprNode* expr, S32 op);
|
||||
|
||||
U32 compile(CodeStream& codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
DBG_STMT_TYPE(AssignOpExprNode);
|
||||
};
|
||||
|
||||
struct TTagSetStmtNode : StmtNode
|
||||
{
|
||||
StringTableEntry tag;
|
||||
ExprNode* valueExpr;
|
||||
ExprNode* stringExpr;
|
||||
|
||||
static TTagSetStmtNode* alloc(S32 lineNumber, StringTableEntry tag, ExprNode* valueExpr, ExprNode* stringExpr);
|
||||
|
||||
U32 compileStmt(CodeStream& codeStream, U32 ip);
|
||||
DBG_STMT_TYPE(TTagSetStmtNode);
|
||||
};
|
||||
|
||||
struct TTagDerefNode : ExprNode
|
||||
{
|
||||
ExprNode* expr;
|
||||
|
||||
static TTagDerefNode* alloc(S32 lineNumber, ExprNode* expr);
|
||||
|
||||
U32 compile(CodeStream& codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
DBG_STMT_TYPE(TTagDerefNode);
|
||||
};
|
||||
|
||||
struct TTagExprNode : ExprNode
|
||||
{
|
||||
StringTableEntry tag;
|
||||
|
||||
static TTagExprNode* alloc(S32 lineNumber, StringTableEntry tag);
|
||||
|
||||
U32 compile(CodeStream& codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
DBG_STMT_TYPE(TTagExprNode);
|
||||
};
|
||||
|
||||
struct FuncCallExprNode : ExprNode
|
||||
{
|
||||
StringTableEntry funcName;
|
||||
StringTableEntry nameSpace;
|
||||
ExprNode* args;
|
||||
U32 callType;
|
||||
enum {
|
||||
FunctionCall,
|
||||
StaticCall,
|
||||
MethodCall,
|
||||
ParentCall
|
||||
};
|
||||
|
||||
static FuncCallExprNode* alloc(S32 lineNumber, StringTableEntry funcName, StringTableEntry nameSpace, ExprNode* args, bool dot);
|
||||
|
||||
U32 compile(CodeStream& codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
DBG_STMT_TYPE(FuncCallExprNode);
|
||||
};
|
||||
|
||||
struct AssertCallExprNode : ExprNode
|
||||
{
|
||||
ExprNode* testExpr;
|
||||
const char* message;
|
||||
U32 messageIndex;
|
||||
|
||||
static AssertCallExprNode* alloc(S32 lineNumber, ExprNode* testExpr, const char* message);
|
||||
|
||||
U32 compile(CodeStream& codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
DBG_STMT_TYPE(AssertCallExprNode);
|
||||
};
|
||||
|
||||
struct SlotDecl
|
||||
{
|
||||
S32 lineNumber;
|
||||
ExprNode* object;
|
||||
StringTableEntry slotName;
|
||||
ExprNode* array;
|
||||
};
|
||||
|
||||
struct SlotAccessNode : ExprNode
|
||||
{
|
||||
ExprNode* objectExpr, * arrayExpr;
|
||||
StringTableEntry slotName;
|
||||
|
||||
static SlotAccessNode* alloc(S32 lineNumber, ExprNode* objectExpr, ExprNode* arrayExpr, StringTableEntry slotName);
|
||||
|
||||
U32 compile(CodeStream& codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
DBG_STMT_TYPE(SlotAccessNode);
|
||||
};
|
||||
|
||||
struct InternalSlotDecl
|
||||
{
|
||||
S32 lineNumber;
|
||||
ExprNode* object;
|
||||
ExprNode* slotExpr;
|
||||
bool recurse;
|
||||
};
|
||||
|
||||
struct InternalSlotAccessNode : ExprNode
|
||||
{
|
||||
ExprNode* objectExpr, * slotExpr;
|
||||
bool recurse;
|
||||
|
||||
static InternalSlotAccessNode* alloc(S32 lineNumber, ExprNode* objectExpr, ExprNode* slotExpr, bool recurse);
|
||||
|
||||
U32 compile(CodeStream& codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
DBG_STMT_TYPE(InternalSlotAccessNode);
|
||||
};
|
||||
|
||||
struct SlotAssignNode : ExprNode
|
||||
{
|
||||
ExprNode* objectExpr, * arrayExpr;
|
||||
StringTableEntry slotName;
|
||||
ExprNode* valueExpr;
|
||||
U32 typeID;
|
||||
|
||||
static SlotAssignNode* alloc(S32 lineNumber, ExprNode* objectExpr, ExprNode* arrayExpr, StringTableEntry slotName, ExprNode* valueExpr, U32 typeID = -1);
|
||||
|
||||
U32 compile(CodeStream& codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
DBG_STMT_TYPE(SlotAssignNode);
|
||||
};
|
||||
|
||||
struct SlotAssignOpNode : ExprNode
|
||||
{
|
||||
ExprNode* objectExpr, * arrayExpr;
|
||||
StringTableEntry slotName;
|
||||
S32 op;
|
||||
ExprNode* valueExpr;
|
||||
U32 operand;
|
||||
TypeReq subType;
|
||||
|
||||
static SlotAssignOpNode* alloc(S32 lineNumber, ExprNode* objectExpr, StringTableEntry slotName, ExprNode* arrayExpr, S32 op, ExprNode* valueExpr);
|
||||
|
||||
U32 compile(CodeStream& codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
DBG_STMT_TYPE(SlotAssignOpNode);
|
||||
};
|
||||
|
||||
struct ObjectDeclNode : ExprNode
|
||||
{
|
||||
ExprNode* classNameExpr;
|
||||
StringTableEntry parentObject;
|
||||
ExprNode* objectNameExpr;
|
||||
ExprNode* argList;
|
||||
SlotAssignNode* slotDecls;
|
||||
ObjectDeclNode* subObjects;
|
||||
bool isDatablock;
|
||||
U32 failOffset;
|
||||
bool isClassNameInternal;
|
||||
bool isSingleton;
|
||||
|
||||
static ObjectDeclNode* alloc(S32 lineNumber, ExprNode* classNameExpr, ExprNode* objectNameExpr, ExprNode* argList, StringTableEntry parentObject, SlotAssignNode* slotDecls, ObjectDeclNode* subObjects, bool isDatablock, bool classNameInternal, bool isSingleton);
|
||||
|
||||
U32 precompileSubObject(bool);
|
||||
U32 compile(CodeStream& codeStream, U32 ip, TypeReq type);
|
||||
U32 compileSubObject(CodeStream& codeStream, U32 ip, bool);
|
||||
TypeReq getPreferredType();
|
||||
DBG_STMT_TYPE(ObjectDeclNode);
|
||||
};
|
||||
|
||||
struct ObjectBlockDecl
|
||||
{
|
||||
SlotAssignNode* slots;
|
||||
ObjectDeclNode* decls;
|
||||
};
|
||||
|
||||
struct FunctionDeclStmtNode : StmtNode
|
||||
{
|
||||
StringTableEntry fnName;
|
||||
VarNode* args;
|
||||
StmtNode* stmts;
|
||||
StringTableEntry nameSpace;
|
||||
StringTableEntry package;
|
||||
U32 endOffset;
|
||||
U32 argc;
|
||||
|
||||
static FunctionDeclStmtNode* alloc(S32 lineNumber, StringTableEntry fnName, StringTableEntry nameSpace, VarNode* args, StmtNode* stmts);
|
||||
|
||||
U32 compileStmt(CodeStream& codeStream, U32 ip);
|
||||
void setPackage(StringTableEntry packageName);
|
||||
DBG_STMT_TYPE(FunctionDeclStmtNode);
|
||||
};
|
||||
|
||||
namespace Script
|
||||
{
|
||||
inline ExprEvalState gEvalState;
|
||||
|
||||
inline StmtNode *gStatementList;
|
||||
inline StmtNode *gAnonFunctionList;
|
||||
inline U32 gAnonFunctionID = 0;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
456
Engine/source/console/torquescript/astAlloc.cpp
Normal file
456
Engine/source/console/torquescript/astAlloc.cpp
Normal file
|
|
@ -0,0 +1,456 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2013 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/console.h"
|
||||
#include "compiler.h"
|
||||
#include "console/consoleInternal.h"
|
||||
|
||||
using namespace Compiler;
|
||||
|
||||
/// @file
|
||||
///
|
||||
/// TorqueScript AST node allocators.
|
||||
///
|
||||
/// These static methods exist to allocate new AST node for the compiler. They
|
||||
/// all allocate memory from the consoleAllocator for efficiency, and often take
|
||||
/// arguments relating to the state of the nodes. They are called from gram.y
|
||||
/// (really gram.c) as the lexer analyzes the script code.
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
BreakStmtNode* BreakStmtNode::alloc(S32 lineNumber)
|
||||
{
|
||||
BreakStmtNode* ret = (BreakStmtNode*)consoleAlloc(sizeof(BreakStmtNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ContinueStmtNode* ContinueStmtNode::alloc(S32 lineNumber)
|
||||
{
|
||||
ContinueStmtNode* ret = (ContinueStmtNode*)consoleAlloc(sizeof(ContinueStmtNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ReturnStmtNode* ReturnStmtNode::alloc(S32 lineNumber, ExprNode* expr)
|
||||
{
|
||||
ReturnStmtNode* ret = (ReturnStmtNode*)consoleAlloc(sizeof(ReturnStmtNode));
|
||||
constructInPlace(ret);
|
||||
ret->expr = expr;
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
IfStmtNode* IfStmtNode::alloc(S32 lineNumber, ExprNode* testExpr, StmtNode* ifBlock, StmtNode* elseBlock, bool propagate)
|
||||
{
|
||||
IfStmtNode* ret = (IfStmtNode*)consoleAlloc(sizeof(IfStmtNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
|
||||
ret->testExpr = testExpr;
|
||||
ret->ifBlock = ifBlock;
|
||||
ret->elseBlock = elseBlock;
|
||||
ret->propagate = propagate;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
LoopStmtNode* LoopStmtNode::alloc(S32 lineNumber, ExprNode* initExpr, ExprNode* testExpr, ExprNode* endLoopExpr, StmtNode* loopBlock, bool isDoLoop)
|
||||
{
|
||||
LoopStmtNode* ret = (LoopStmtNode*)consoleAlloc(sizeof(LoopStmtNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->testExpr = testExpr;
|
||||
ret->initExpr = initExpr;
|
||||
ret->endLoopExpr = endLoopExpr;
|
||||
ret->loopBlock = loopBlock;
|
||||
ret->isDoLoop = isDoLoop;
|
||||
|
||||
// Deal with setting some dummy constant nodes if we weren't provided with
|
||||
// info... This allows us to play nice with missing parts of for(;;) for
|
||||
// instance.
|
||||
if (!ret->testExpr) ret->testExpr = IntNode::alloc(lineNumber, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
IterStmtNode* IterStmtNode::alloc(S32 lineNumber, StringTableEntry varName, ExprNode* containerExpr, StmtNode* body, bool isStringIter)
|
||||
{
|
||||
IterStmtNode* ret = (IterStmtNode*)consoleAlloc(sizeof(IterStmtNode));
|
||||
constructInPlace(ret);
|
||||
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->varName = varName;
|
||||
ret->containerExpr = containerExpr;
|
||||
ret->body = body;
|
||||
ret->isStringIter = isStringIter;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
FloatBinaryExprNode* FloatBinaryExprNode::alloc(S32 lineNumber, S32 op, ExprNode* left, ExprNode* right)
|
||||
{
|
||||
FloatBinaryExprNode* ret = (FloatBinaryExprNode*)consoleAlloc(sizeof(FloatBinaryExprNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->optimizedNode = NULL;
|
||||
|
||||
ret->op = op;
|
||||
ret->left = left;
|
||||
ret->right = right;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
IntBinaryExprNode* IntBinaryExprNode::alloc(S32 lineNumber, S32 op, ExprNode* left, ExprNode* right)
|
||||
{
|
||||
IntBinaryExprNode* ret = (IntBinaryExprNode*)consoleAlloc(sizeof(IntBinaryExprNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->optimizedNode = NULL;
|
||||
|
||||
ret->op = op;
|
||||
ret->left = left;
|
||||
ret->right = right;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
StreqExprNode* StreqExprNode::alloc(S32 lineNumber, ExprNode* left, ExprNode* right, bool eq)
|
||||
{
|
||||
StreqExprNode* ret = (StreqExprNode*)consoleAlloc(sizeof(StreqExprNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->optimizedNode = NULL;
|
||||
ret->left = left;
|
||||
ret->right = right;
|
||||
ret->eq = eq;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
StrcatExprNode* StrcatExprNode::alloc(S32 lineNumber, ExprNode* left, ExprNode* right, int appendChar)
|
||||
{
|
||||
StrcatExprNode* ret = (StrcatExprNode*)consoleAlloc(sizeof(StrcatExprNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->optimizedNode = NULL;
|
||||
ret->left = left;
|
||||
ret->right = right;
|
||||
ret->appendChar = appendChar;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
CommaCatExprNode* CommaCatExprNode::alloc(S32 lineNumber, ExprNode* left, ExprNode* right)
|
||||
{
|
||||
CommaCatExprNode* ret = (CommaCatExprNode*)consoleAlloc(sizeof(CommaCatExprNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->optimizedNode = NULL;
|
||||
ret->left = left;
|
||||
ret->right = right;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
IntUnaryExprNode* IntUnaryExprNode::alloc(S32 lineNumber, S32 op, ExprNode* expr)
|
||||
{
|
||||
IntUnaryExprNode* ret = (IntUnaryExprNode*)consoleAlloc(sizeof(IntUnaryExprNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->optimizedNode = NULL;
|
||||
ret->op = op;
|
||||
ret->expr = expr;
|
||||
return ret;
|
||||
}
|
||||
|
||||
FloatUnaryExprNode* FloatUnaryExprNode::alloc(S32 lineNumber, S32 op, ExprNode* expr)
|
||||
{
|
||||
FloatUnaryExprNode* ret = (FloatUnaryExprNode*)consoleAlloc(sizeof(FloatUnaryExprNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->optimizedNode = NULL;
|
||||
ret->op = op;
|
||||
ret->expr = expr;
|
||||
return ret;
|
||||
}
|
||||
|
||||
VarNode* VarNode::alloc(S32 lineNumber, StringTableEntry varName, ExprNode* arrayIndex)
|
||||
{
|
||||
VarNode* ret = (VarNode*)consoleAlloc(sizeof(VarNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->optimizedNode = NULL;
|
||||
ret->varName = varName;
|
||||
ret->arrayIndex = arrayIndex;
|
||||
return ret;
|
||||
}
|
||||
|
||||
IntNode* IntNode::alloc(S32 lineNumber, S32 value)
|
||||
{
|
||||
IntNode* ret = (IntNode*)consoleAlloc(sizeof(IntNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->optimizedNode = NULL;
|
||||
ret->value = value;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ConditionalExprNode* ConditionalExprNode::alloc(S32 lineNumber, ExprNode* testExpr, ExprNode* trueExpr, ExprNode* falseExpr)
|
||||
{
|
||||
ConditionalExprNode* ret = (ConditionalExprNode*)consoleAlloc(sizeof(ConditionalExprNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->optimizedNode = NULL;
|
||||
ret->testExpr = testExpr;
|
||||
ret->trueExpr = trueExpr;
|
||||
ret->falseExpr = falseExpr;
|
||||
ret->integer = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
FloatNode* FloatNode::alloc(S32 lineNumber, F64 value)
|
||||
{
|
||||
FloatNode* ret = (FloatNode*)consoleAlloc(sizeof(FloatNode));
|
||||
constructInPlace(ret);
|
||||
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->optimizedNode = NULL;
|
||||
ret->value = value;
|
||||
return ret;
|
||||
}
|
||||
|
||||
StrConstNode* StrConstNode::alloc(S32 lineNumber, const char* str, bool tag, bool doc)
|
||||
{
|
||||
StrConstNode* ret = (StrConstNode*)consoleAlloc(sizeof(StrConstNode));
|
||||
constructInPlace(ret);
|
||||
S32 len = dStrlen(str);
|
||||
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->optimizedNode = NULL;
|
||||
ret->str = (char*)consoleAlloc(len + 1);
|
||||
ret->tag = tag;
|
||||
ret->doc = doc;
|
||||
dStrcpy(ret->str, str, len + 1);
|
||||
ret->str[len] = '\0';
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ConstantNode* ConstantNode::alloc(S32 lineNumber, StringTableEntry value)
|
||||
{
|
||||
ConstantNode* ret = (ConstantNode*)consoleAlloc(sizeof(ConstantNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->optimizedNode = NULL;
|
||||
ret->value = value;
|
||||
return ret;
|
||||
}
|
||||
|
||||
AssignExprNode* AssignExprNode::alloc(S32 lineNumber, StringTableEntry varName, ExprNode* arrayIndex, ExprNode* expr)
|
||||
{
|
||||
AssignExprNode* ret = (AssignExprNode*)consoleAlloc(sizeof(AssignExprNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->optimizedNode = NULL;
|
||||
ret->varName = varName;
|
||||
ret->expr = expr;
|
||||
ret->arrayIndex = arrayIndex;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
AssignOpExprNode* AssignOpExprNode::alloc(S32 lineNumber, StringTableEntry varName, ExprNode* arrayIndex, ExprNode* expr, S32 op)
|
||||
{
|
||||
AssignOpExprNode* ret = (AssignOpExprNode*)consoleAlloc(sizeof(AssignOpExprNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->optimizedNode = NULL;
|
||||
ret->varName = varName;
|
||||
ret->expr = expr;
|
||||
ret->arrayIndex = arrayIndex;
|
||||
ret->op = op;
|
||||
return ret;
|
||||
}
|
||||
|
||||
TTagSetStmtNode* TTagSetStmtNode::alloc(S32 lineNumber, StringTableEntry tag, ExprNode* valueExpr, ExprNode* stringExpr)
|
||||
{
|
||||
TTagSetStmtNode* ret = (TTagSetStmtNode*)consoleAlloc(sizeof(TTagSetStmtNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->tag = tag;
|
||||
ret->valueExpr = valueExpr;
|
||||
ret->stringExpr = stringExpr;
|
||||
return ret;
|
||||
}
|
||||
|
||||
TTagDerefNode* TTagDerefNode::alloc(S32 lineNumber, ExprNode* expr)
|
||||
{
|
||||
TTagDerefNode* ret = (TTagDerefNode*)consoleAlloc(sizeof(TTagDerefNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->optimizedNode = NULL;
|
||||
ret->expr = expr;
|
||||
return ret;
|
||||
}
|
||||
|
||||
TTagExprNode* TTagExprNode::alloc(S32 lineNumber, StringTableEntry tag)
|
||||
{
|
||||
TTagExprNode* ret = (TTagExprNode*)consoleAlloc(sizeof(TTagExprNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->optimizedNode = NULL;
|
||||
ret->tag = tag;
|
||||
return ret;
|
||||
}
|
||||
|
||||
FuncCallExprNode* FuncCallExprNode::alloc(S32 lineNumber, StringTableEntry funcName, StringTableEntry nameSpace, ExprNode* args, bool dot)
|
||||
{
|
||||
FuncCallExprNode* ret = (FuncCallExprNode*)consoleAlloc(sizeof(FuncCallExprNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->optimizedNode = NULL;
|
||||
ret->funcName = funcName;
|
||||
ret->nameSpace = nameSpace;
|
||||
ret->args = args;
|
||||
if (dot)
|
||||
ret->callType = MethodCall;
|
||||
else if (nameSpace != NULL)
|
||||
{
|
||||
if (dStricmp(nameSpace, "Parent") == 0)
|
||||
ret->callType = ParentCall;
|
||||
else
|
||||
ret->callType = StaticCall;
|
||||
}
|
||||
else
|
||||
ret->callType = FunctionCall;
|
||||
return ret;
|
||||
}
|
||||
|
||||
AssertCallExprNode* AssertCallExprNode::alloc(S32 lineNumber, ExprNode* testExpr, const char* message)
|
||||
{
|
||||
#ifdef TORQUE_ENABLE_SCRIPTASSERTS
|
||||
|
||||
AssertCallExprNode* ret = (AssertCallExprNode*)consoleAlloc(sizeof(FuncCallExprNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->testExpr = testExpr;
|
||||
ret->message = message ? message : "TorqueScript assert!";
|
||||
return ret;
|
||||
|
||||
#else
|
||||
|
||||
return NULL;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
SlotAccessNode* SlotAccessNode::alloc(S32 lineNumber, ExprNode* objectExpr, ExprNode* arrayExpr, StringTableEntry slotName)
|
||||
{
|
||||
SlotAccessNode* ret = (SlotAccessNode*)consoleAlloc(sizeof(SlotAccessNode));
|
||||
constructInPlace(ret);
|
||||
ret->optimizedNode = NULL;
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->objectExpr = objectExpr;
|
||||
ret->arrayExpr = arrayExpr;
|
||||
ret->slotName = slotName;
|
||||
return ret;
|
||||
}
|
||||
|
||||
InternalSlotAccessNode* InternalSlotAccessNode::alloc(S32 lineNumber, ExprNode* objectExpr, ExprNode* slotExpr, bool recurse)
|
||||
{
|
||||
InternalSlotAccessNode* ret = (InternalSlotAccessNode*)consoleAlloc(sizeof(InternalSlotAccessNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->optimizedNode = NULL;
|
||||
ret->objectExpr = objectExpr;
|
||||
ret->slotExpr = slotExpr;
|
||||
ret->recurse = recurse;
|
||||
return ret;
|
||||
}
|
||||
|
||||
SlotAssignNode* SlotAssignNode::alloc(S32 lineNumber, ExprNode* objectExpr, ExprNode* arrayExpr, StringTableEntry slotName, ExprNode* valueExpr, U32 typeID /* = -1 */)
|
||||
{
|
||||
SlotAssignNode* ret = (SlotAssignNode*)consoleAlloc(sizeof(SlotAssignNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->optimizedNode = NULL;
|
||||
ret->objectExpr = objectExpr;
|
||||
ret->arrayExpr = arrayExpr;
|
||||
ret->slotName = slotName;
|
||||
ret->valueExpr = valueExpr;
|
||||
ret->typeID = typeID;
|
||||
return ret;
|
||||
}
|
||||
|
||||
SlotAssignOpNode* SlotAssignOpNode::alloc(S32 lineNumber, ExprNode* objectExpr, StringTableEntry slotName, ExprNode* arrayExpr, S32 op, ExprNode* valueExpr)
|
||||
{
|
||||
SlotAssignOpNode* ret = (SlotAssignOpNode*)consoleAlloc(sizeof(SlotAssignOpNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->optimizedNode = NULL;
|
||||
ret->objectExpr = objectExpr;
|
||||
ret->arrayExpr = arrayExpr;
|
||||
ret->slotName = slotName;
|
||||
ret->op = op;
|
||||
ret->valueExpr = valueExpr;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ObjectDeclNode* ObjectDeclNode::alloc(S32 lineNumber, ExprNode* classNameExpr, ExprNode* objectNameExpr, ExprNode* argList, StringTableEntry parentObject, SlotAssignNode* slotDecls, ObjectDeclNode* subObjects, bool isDatablock, bool classNameInternal, bool isSingleton)
|
||||
{
|
||||
ObjectDeclNode* ret = (ObjectDeclNode*)consoleAlloc(sizeof(ObjectDeclNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->optimizedNode = NULL;
|
||||
ret->classNameExpr = classNameExpr;
|
||||
ret->objectNameExpr = objectNameExpr;
|
||||
ret->argList = argList;
|
||||
ret->slotDecls = slotDecls;
|
||||
ret->subObjects = subObjects;
|
||||
ret->isDatablock = isDatablock;
|
||||
ret->isClassNameInternal = classNameInternal;
|
||||
ret->isSingleton = isSingleton;
|
||||
ret->failOffset = 0;
|
||||
if (parentObject)
|
||||
ret->parentObject = parentObject;
|
||||
else
|
||||
ret->parentObject = StringTable->insert("");
|
||||
return ret;
|
||||
}
|
||||
|
||||
FunctionDeclStmtNode* FunctionDeclStmtNode::alloc(S32 lineNumber, StringTableEntry fnName, StringTableEntry nameSpace, VarNode* args, StmtNode* stmts)
|
||||
{
|
||||
FunctionDeclStmtNode* ret = (FunctionDeclStmtNode*)consoleAlloc(sizeof(FunctionDeclStmtNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->fnName = fnName;
|
||||
ret->args = args;
|
||||
ret->stmts = stmts;
|
||||
ret->nameSpace = nameSpace;
|
||||
ret->package = NULL;
|
||||
return ret;
|
||||
}
|
||||
1563
Engine/source/console/torquescript/astNodes.cpp
Normal file
1563
Engine/source/console/torquescript/astNodes.cpp
Normal file
File diff suppressed because it is too large
Load diff
6
Engine/source/console/torquescript/bison.bat
Normal file
6
Engine/source/console/torquescript/bison.bat
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
echo Changing to %4 ...
|
||||
cd %4
|
||||
echo Generating %2 and %3 with prefix %1.
|
||||
..\..\bin\bison\bison.exe -o %2 %3 --defines -p %1
|
||||
echo Renaming %2 to %5 .
|
||||
move /Y %2 %5
|
||||
686
Engine/source/console/torquescript/bison.simple
Normal file
686
Engine/source/console/torquescript/bison.simple
Normal file
|
|
@ -0,0 +1,686 @@
|
|||
/* -*-C-*- Note some compilers choke on comments on `#line' lines. */
|
||||
#line 3 "bison.simple"
|
||||
|
||||
/* Skeleton output parser for bison,
|
||||
Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc.
|
||||
|
||||
This program 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, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* As a special exception, when this file is copied by Bison into a
|
||||
Bison output file, you may use that output file without restriction.
|
||||
This special exception was added by the Free Software Foundation
|
||||
in version 1.24 of Bison. */
|
||||
|
||||
#ifndef alloca
|
||||
#ifdef __GNUC__
|
||||
#define alloca __builtin_alloca
|
||||
#else /* not GNU C. */
|
||||
#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi)
|
||||
#include <alloca.h>
|
||||
#else /* not sparc */
|
||||
#if defined (MSDOS) && !defined (__TURBOC__)
|
||||
#include <malloc.h>
|
||||
#else /* not MSDOS, or __TURBOC__ */
|
||||
#if defined(_AIX)
|
||||
#include <malloc.h>
|
||||
#pragma alloca
|
||||
#else /* not MSDOS, __TURBOC__, or _AIX */
|
||||
#ifdef __hpux
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
void *alloca (unsigned int);
|
||||
};
|
||||
#else /* not __cplusplus */
|
||||
void *alloca ();
|
||||
#endif /* not __cplusplus */
|
||||
#endif /* __hpux */
|
||||
#endif /* not _AIX */
|
||||
#endif /* not MSDOS, or __TURBOC__ */
|
||||
#endif /* not sparc. */
|
||||
#endif /* not GNU C. */
|
||||
#endif /* alloca not defined. */
|
||||
|
||||
/* This is the parser code that is written into each bison parser
|
||||
when the %semantic_parser declaration is not specified in the grammar.
|
||||
It was written by Richard Stallman by simplifying the hairy parser
|
||||
used when %semantic_parser is specified. */
|
||||
|
||||
/* Note: there must be only one dollar sign in this file.
|
||||
It is replaced by the list of actions, each action
|
||||
as one case of the switch. */
|
||||
|
||||
#define yyerrok (yyerrstatus = 0)
|
||||
#define yyclearin (yychar = YYEMPTY)
|
||||
#define YYEMPTY -2
|
||||
#define YYEOF 0
|
||||
#define YYACCEPT return(0)
|
||||
#define YYABORT return(1)
|
||||
#define YYERROR goto yyerrlab1
|
||||
/* Like YYERROR except do call yyerror.
|
||||
This remains here temporarily to ease the
|
||||
transition to the new meaning of YYERROR, for GCC.
|
||||
Once GCC version 2 has supplanted version 1, this can go. */
|
||||
#define YYFAIL goto yyerrlab
|
||||
#define YYRECOVERING() (!!yyerrstatus)
|
||||
#define YYBACKUP(token, value) \
|
||||
do \
|
||||
if (yychar == YYEMPTY && yylen == 1) \
|
||||
{ yychar = (token), yylval = (value); \
|
||||
yychar1 = YYTRANSLATE (yychar); \
|
||||
YYPOPSTACK; \
|
||||
goto yybackup; \
|
||||
} \
|
||||
else \
|
||||
{ yyerror ("syntax error: cannot back up"); YYERROR; } \
|
||||
while (0)
|
||||
|
||||
#define YYTERROR 1
|
||||
#define YYERRCODE 256
|
||||
|
||||
#ifndef YYPURE
|
||||
#define YYLEX yylex()
|
||||
#endif
|
||||
|
||||
#ifdef YYPURE
|
||||
#ifdef YYLSP_NEEDED
|
||||
#ifdef YYLEX_PARAM
|
||||
#define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM)
|
||||
#else
|
||||
#define YYLEX yylex(&yylval, &yylloc)
|
||||
#endif
|
||||
#else /* not YYLSP_NEEDED */
|
||||
#ifdef YYLEX_PARAM
|
||||
#define YYLEX yylex(&yylval, YYLEX_PARAM)
|
||||
#else
|
||||
#define YYLEX yylex(&yylval)
|
||||
#endif
|
||||
#endif /* not YYLSP_NEEDED */
|
||||
#endif
|
||||
|
||||
/* If nonreentrant, generate the variables here */
|
||||
|
||||
#ifndef YYPURE
|
||||
|
||||
int yychar; /* the lookahead symbol */
|
||||
YYSTYPE yylval; /* the semantic value of the */
|
||||
/* lookahead symbol */
|
||||
|
||||
#ifdef YYLSP_NEEDED
|
||||
YYLTYPE yylloc; /* location data for the lookahead */
|
||||
/* symbol */
|
||||
#endif
|
||||
|
||||
int yynerrs; /* number of parse errors so far */
|
||||
#endif /* not YYPURE */
|
||||
|
||||
#if YYDEBUG != 0
|
||||
int yydebug; /* nonzero means print parse trace */
|
||||
/* Since this is uninitialized, it does not stop multiple parsers
|
||||
from coexisting. */
|
||||
#endif
|
||||
|
||||
/* YYINITDEPTH indicates the initial size of the parser's stacks */
|
||||
|
||||
#ifndef YYINITDEPTH
|
||||
#define YYINITDEPTH 200
|
||||
#endif
|
||||
|
||||
/* YYMAXDEPTH is the maximum size the stacks can grow to
|
||||
(effective only if the built-in stack extension method is used). */
|
||||
|
||||
#if YYMAXDEPTH == 0
|
||||
#undef YYMAXDEPTH
|
||||
#endif
|
||||
|
||||
#ifndef YYMAXDEPTH
|
||||
#define YYMAXDEPTH 10000
|
||||
#endif
|
||||
|
||||
/* Prevent warning if -Wstrict-prototypes. */
|
||||
#ifdef __GNUC__
|
||||
int yyparse (void);
|
||||
#endif
|
||||
|
||||
#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */
|
||||
#define __yy_memcpy(FROM,TO,COUNT) __builtin_memcpy(TO,FROM,COUNT)
|
||||
#else /* not GNU C or C++ */
|
||||
#ifndef __cplusplus
|
||||
|
||||
/* This is the most reliable way to avoid incompatibilities
|
||||
in available built-in functions on various systems. */
|
||||
static void
|
||||
__yy_memcpy (from, to, count)
|
||||
char *from;
|
||||
char *to;
|
||||
int count;
|
||||
{
|
||||
char *f = from;
|
||||
char *t = to;
|
||||
int i = count;
|
||||
|
||||
while (i-- > 0)
|
||||
*t++ = *f++;
|
||||
}
|
||||
|
||||
#else /* __cplusplus */
|
||||
|
||||
/* This is the most reliable way to avoid incompatibilities
|
||||
in available built-in functions on various systems. */
|
||||
static void
|
||||
__yy_memcpy (char *from, char *to, int count)
|
||||
{
|
||||
char *f = from;
|
||||
char *t = to;
|
||||
int i = count;
|
||||
|
||||
while (i-- > 0)
|
||||
*t++ = *f++;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#line 192 "bison.simple"
|
||||
|
||||
/* The user can define YYPARSE_PARAM as the name of an argument to be passed
|
||||
into yyparse. The argument should have type void *.
|
||||
It should actually point to an object.
|
||||
Grammar actions can access the variable by casting it
|
||||
to the proper pointer type. */
|
||||
|
||||
#ifdef YYPARSE_PARAM
|
||||
#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
|
||||
#else
|
||||
#define YYPARSE_PARAM
|
||||
#define YYPARSE_PARAM_DECL
|
||||
#endif
|
||||
|
||||
int
|
||||
yyparse(YYPARSE_PARAM)
|
||||
YYPARSE_PARAM_DECL
|
||||
{
|
||||
int yystate;
|
||||
int yyn;
|
||||
short *yyssp;
|
||||
YYSTYPE *yyvsp;
|
||||
int yyerrstatus; /* number of tokens to shift before error messages enabled */
|
||||
int yychar1 = 0; /* lookahead token as an internal (translated) token number */
|
||||
|
||||
short yyssa[YYINITDEPTH]; /* the state stack */
|
||||
YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */
|
||||
|
||||
short *yyss = yyssa; /* refer to the stacks thru separate pointers */
|
||||
YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */
|
||||
|
||||
#ifdef YYLSP_NEEDED
|
||||
YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */
|
||||
YYLTYPE *yyls = yylsa;
|
||||
YYLTYPE *yylsp;
|
||||
|
||||
#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--)
|
||||
#else
|
||||
#define YYPOPSTACK (yyvsp--, yyssp--)
|
||||
#endif
|
||||
|
||||
int yystacksize = YYINITDEPTH;
|
||||
|
||||
#ifdef YYPURE
|
||||
int yychar;
|
||||
YYSTYPE yylval;
|
||||
int yynerrs;
|
||||
#ifdef YYLSP_NEEDED
|
||||
YYLTYPE yylloc;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
YYSTYPE yyval; /* the variable used to return */
|
||||
/* semantic values from the action */
|
||||
/* routines */
|
||||
|
||||
int yylen;
|
||||
|
||||
#if YYDEBUG != 0
|
||||
if (yydebug)
|
||||
fprintf(stderr, "Starting parse\n");
|
||||
#endif
|
||||
|
||||
yystate = 0;
|
||||
yyerrstatus = 0;
|
||||
yynerrs = 0;
|
||||
yychar = YYEMPTY; /* Cause a token to be read. */
|
||||
|
||||
/* Initialize stack pointers.
|
||||
Waste one element of value and location stack
|
||||
so that they stay on the same level as the state stack.
|
||||
The wasted elements are never initialized. */
|
||||
|
||||
yyssp = yyss - 1;
|
||||
yyvsp = yyvs;
|
||||
#ifdef YYLSP_NEEDED
|
||||
yylsp = yyls;
|
||||
#endif
|
||||
|
||||
/* Push a new state, which is found in yystate . */
|
||||
/* In all cases, when you get here, the value and location stacks
|
||||
have just been pushed. so pushing a state here evens the stacks. */
|
||||
yynewstate:
|
||||
|
||||
*++yyssp = yystate;
|
||||
|
||||
if (yyssp >= yyss + yystacksize - 1)
|
||||
{
|
||||
/* Give user a chance to reallocate the stack */
|
||||
/* Use copies of these so that the &'s don't force the real ones into memory. */
|
||||
YYSTYPE *yyvs1 = yyvs;
|
||||
short *yyss1 = yyss;
|
||||
#ifdef YYLSP_NEEDED
|
||||
YYLTYPE *yyls1 = yyls;
|
||||
#endif
|
||||
|
||||
/* Get the current used size of the three stacks, in elements. */
|
||||
int size = yyssp - yyss + 1;
|
||||
|
||||
#ifdef yyoverflow
|
||||
/* Each stack pointer address is followed by the size of
|
||||
the data in use in that stack, in bytes. */
|
||||
#ifdef YYLSP_NEEDED
|
||||
/* This used to be a conditional around just the two extra args,
|
||||
but that might be undefined if yyoverflow is a macro. */
|
||||
yyoverflow("parser stack overflow",
|
||||
&yyss1, size * sizeof (*yyssp),
|
||||
&yyvs1, size * sizeof (*yyvsp),
|
||||
&yyls1, size * sizeof (*yylsp),
|
||||
&yystacksize);
|
||||
#else
|
||||
yyoverflow("parser stack overflow",
|
||||
&yyss1, size * sizeof (*yyssp),
|
||||
&yyvs1, size * sizeof (*yyvsp),
|
||||
&yystacksize);
|
||||
#endif
|
||||
|
||||
yyss = yyss1; yyvs = yyvs1;
|
||||
#ifdef YYLSP_NEEDED
|
||||
yyls = yyls1;
|
||||
#endif
|
||||
#else /* no yyoverflow */
|
||||
/* Extend the stack our own way. */
|
||||
if (yystacksize >= YYMAXDEPTH)
|
||||
{
|
||||
yyerror("parser stack overflow");
|
||||
return 2;
|
||||
}
|
||||
yystacksize *= 2;
|
||||
if (yystacksize > YYMAXDEPTH)
|
||||
yystacksize = YYMAXDEPTH;
|
||||
yyss = (short *) alloca (yystacksize * sizeof (*yyssp));
|
||||
__yy_memcpy ((char *)yyss1, (char *)yyss, size * sizeof (*yyssp));
|
||||
yyvs = (YYSTYPE *) alloca (yystacksize * sizeof (*yyvsp));
|
||||
__yy_memcpy ((char *)yyvs1, (char *)yyvs, size * sizeof (*yyvsp));
|
||||
#ifdef YYLSP_NEEDED
|
||||
yyls = (YYLTYPE *) alloca (yystacksize * sizeof (*yylsp));
|
||||
__yy_memcpy ((char *)yyls1, (char *)yyls, size * sizeof (*yylsp));
|
||||
#endif
|
||||
#endif /* no yyoverflow */
|
||||
|
||||
yyssp = yyss + size - 1;
|
||||
yyvsp = yyvs + size - 1;
|
||||
#ifdef YYLSP_NEEDED
|
||||
yylsp = yyls + size - 1;
|
||||
#endif
|
||||
|
||||
#if YYDEBUG != 0
|
||||
if (yydebug)
|
||||
fprintf(stderr, "Stack size increased to %d\n", yystacksize);
|
||||
#endif
|
||||
|
||||
if (yyssp >= yyss + yystacksize - 1)
|
||||
YYABORT;
|
||||
}
|
||||
|
||||
#if YYDEBUG != 0
|
||||
if (yydebug)
|
||||
fprintf(stderr, "Entering state %d\n", yystate);
|
||||
#endif
|
||||
|
||||
goto yybackup;
|
||||
yybackup:
|
||||
|
||||
/* Do appropriate processing given the current state. */
|
||||
/* Read a lookahead token if we need one and don't already have one. */
|
||||
/* yyresume: */
|
||||
|
||||
/* First try to decide what to do without reference to lookahead token. */
|
||||
|
||||
yyn = yypact[yystate];
|
||||
if (yyn == YYFLAG)
|
||||
goto yydefault;
|
||||
|
||||
/* Not known => get a lookahead token if don't already have one. */
|
||||
|
||||
/* yychar is either YYEMPTY or YYEOF
|
||||
or a valid token in external form. */
|
||||
|
||||
if (yychar == YYEMPTY)
|
||||
{
|
||||
#if YYDEBUG != 0
|
||||
if (yydebug)
|
||||
fprintf(stderr, "Reading a token: ");
|
||||
#endif
|
||||
yychar = YYLEX;
|
||||
}
|
||||
|
||||
/* Convert token to internal form (in yychar1) for indexing tables with */
|
||||
|
||||
if (yychar <= 0) /* This means end of input. */
|
||||
{
|
||||
yychar1 = 0;
|
||||
yychar = YYEOF; /* Don't call YYLEX any more */
|
||||
|
||||
#if YYDEBUG != 0
|
||||
if (yydebug)
|
||||
fprintf(stderr, "Now at end of input.\n");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
yychar1 = YYTRANSLATE(yychar);
|
||||
|
||||
#if YYDEBUG != 0
|
||||
if (yydebug)
|
||||
{
|
||||
fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]);
|
||||
/* Give the individual parser a way to print the precise meaning
|
||||
of a token, for further debugging info. */
|
||||
#ifdef YYPRINT
|
||||
YYPRINT (stderr, yychar, yylval);
|
||||
#endif
|
||||
fprintf (stderr, ")\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
yyn += yychar1;
|
||||
if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
|
||||
goto yydefault;
|
||||
|
||||
yyn = yytable[yyn];
|
||||
|
||||
/* yyn is what to do for this token type in this state.
|
||||
Negative => reduce, -yyn is rule number.
|
||||
Positive => shift, yyn is new state.
|
||||
New state is final state => don't bother to shift,
|
||||
just return success.
|
||||
0, or most negative number => error. */
|
||||
|
||||
if (yyn < 0)
|
||||
{
|
||||
if (yyn == YYFLAG)
|
||||
goto yyerrlab;
|
||||
yyn = -yyn;
|
||||
goto yyreduce;
|
||||
}
|
||||
else if (yyn == 0)
|
||||
goto yyerrlab;
|
||||
|
||||
if (yyn == YYFINAL)
|
||||
YYACCEPT;
|
||||
|
||||
/* Shift the lookahead token. */
|
||||
|
||||
#if YYDEBUG != 0
|
||||
if (yydebug)
|
||||
fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]);
|
||||
#endif
|
||||
|
||||
/* Discard the token being shifted unless it is eof. */
|
||||
if (yychar != YYEOF)
|
||||
yychar = YYEMPTY;
|
||||
|
||||
*++yyvsp = yylval;
|
||||
#ifdef YYLSP_NEEDED
|
||||
*++yylsp = yylloc;
|
||||
#endif
|
||||
|
||||
/* count tokens shifted since error; after three, turn off error status. */
|
||||
if (yyerrstatus) yyerrstatus--;
|
||||
|
||||
yystate = yyn;
|
||||
goto yynewstate;
|
||||
|
||||
/* Do the default action for the current state. */
|
||||
yydefault:
|
||||
|
||||
yyn = yydefact[yystate];
|
||||
if (yyn == 0)
|
||||
goto yyerrlab;
|
||||
|
||||
/* Do a reduction. yyn is the number of a rule to reduce with. */
|
||||
yyreduce:
|
||||
yylen = yyr2[yyn];
|
||||
if (yylen > 0)
|
||||
yyval = yyvsp[1-yylen]; /* implement default value of the action */
|
||||
|
||||
#if YYDEBUG != 0
|
||||
if (yydebug)
|
||||
{
|
||||
int i;
|
||||
|
||||
fprintf (stderr, "Reducing via rule %d (line %d), ",
|
||||
yyn, yyrline[yyn]);
|
||||
|
||||
/* Print the symbols being reduced, and their result. */
|
||||
for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)
|
||||
fprintf (stderr, "%s ", yytname[yyrhs[i]]);
|
||||
fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]);
|
||||
}
|
||||
#endif
|
||||
|
||||
$ /* the action file gets copied in in place of this dollarsign */
|
||||
#line 487 "bison.simple"
|
||||
|
||||
yyvsp -= yylen;
|
||||
yyssp -= yylen;
|
||||
#ifdef YYLSP_NEEDED
|
||||
yylsp -= yylen;
|
||||
#endif
|
||||
|
||||
#if YYDEBUG != 0
|
||||
if (yydebug)
|
||||
{
|
||||
short *ssp1 = yyss - 1;
|
||||
fprintf (stderr, "state stack now");
|
||||
while (ssp1 != yyssp)
|
||||
fprintf (stderr, " %d", *++ssp1);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
*++yyvsp = yyval;
|
||||
|
||||
#ifdef YYLSP_NEEDED
|
||||
yylsp++;
|
||||
if (yylen == 0)
|
||||
{
|
||||
yylsp->first_line = yylloc.first_line;
|
||||
yylsp->first_column = yylloc.first_column;
|
||||
yylsp->last_line = (yylsp-1)->last_line;
|
||||
yylsp->last_column = (yylsp-1)->last_column;
|
||||
yylsp->text = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
yylsp->last_line = (yylsp+yylen-1)->last_line;
|
||||
yylsp->last_column = (yylsp+yylen-1)->last_column;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Now "shift" the result of the reduction.
|
||||
Determine what state that goes to,
|
||||
based on the state we popped back to
|
||||
and the rule number reduced by. */
|
||||
|
||||
yyn = yyr1[yyn];
|
||||
|
||||
yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
|
||||
if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
|
||||
yystate = yytable[yystate];
|
||||
else
|
||||
yystate = yydefgoto[yyn - YYNTBASE];
|
||||
|
||||
goto yynewstate;
|
||||
|
||||
yyerrlab: /* here on detecting error */
|
||||
|
||||
if (! yyerrstatus)
|
||||
/* If not already recovering from an error, report this error. */
|
||||
{
|
||||
++yynerrs;
|
||||
|
||||
#ifdef YYERROR_VERBOSE
|
||||
yyn = yypact[yystate];
|
||||
|
||||
if (yyn > YYFLAG && yyn < YYLAST)
|
||||
{
|
||||
int size = 0;
|
||||
char *msg;
|
||||
int x, count;
|
||||
|
||||
count = 0;
|
||||
/* Start X at -yyn if nec to avoid negative indexes in yycheck. */
|
||||
for (x = (yyn < 0 ? -yyn : 0);
|
||||
x < (sizeof(yytname) / sizeof(char *)); x++)
|
||||
if (yycheck[x + yyn] == x)
|
||||
size += strlen(yytname[x]) + 15, count++;
|
||||
msg = (char *) malloc(size + 15);
|
||||
if (msg != 0)
|
||||
{
|
||||
strcpy(msg, "parse error");
|
||||
|
||||
if (count < 5)
|
||||
{
|
||||
count = 0;
|
||||
for (x = (yyn < 0 ? -yyn : 0);
|
||||
x < (sizeof(yytname) / sizeof(char *)); x++)
|
||||
if (yycheck[x + yyn] == x)
|
||||
{
|
||||
strcat(msg, count == 0 ? ", expecting `" : " or `");
|
||||
strcat(msg, yytname[x]);
|
||||
strcat(msg, "'");
|
||||
count++;
|
||||
}
|
||||
}
|
||||
yyerror(msg);
|
||||
free(msg);
|
||||
}
|
||||
else
|
||||
yyerror ("parse error; also virtual memory exceeded");
|
||||
}
|
||||
else
|
||||
#endif /* YYERROR_VERBOSE */
|
||||
yyerror("parse error");
|
||||
}
|
||||
|
||||
goto yyerrlab1;
|
||||
yyerrlab1: /* here on error raised explicitly by an action */
|
||||
|
||||
if (yyerrstatus == 3)
|
||||
{
|
||||
/* if just tried and failed to reuse lookahead token after an error, discard it. */
|
||||
|
||||
/* return failure if at end of input */
|
||||
if (yychar == YYEOF)
|
||||
YYABORT;
|
||||
|
||||
#if YYDEBUG != 0
|
||||
if (yydebug)
|
||||
fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]);
|
||||
#endif
|
||||
|
||||
yychar = YYEMPTY;
|
||||
}
|
||||
|
||||
/* Else will try to reuse lookahead token
|
||||
after shifting the error token. */
|
||||
|
||||
yyerrstatus = 3; /* Each real token shifted decrements this */
|
||||
|
||||
goto yyerrhandle;
|
||||
|
||||
yyerrdefault: /* current state does not do anything special for the error token. */
|
||||
|
||||
#if 0
|
||||
/* This is wrong; only states that explicitly want error tokens
|
||||
should shift them. */
|
||||
yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/
|
||||
if (yyn) goto yydefault;
|
||||
#endif
|
||||
|
||||
yyerrpop: /* pop the current state because it cannot handle the error token */
|
||||
|
||||
if (yyssp == yyss) YYABORT;
|
||||
yyvsp--;
|
||||
yystate = *--yyssp;
|
||||
#ifdef YYLSP_NEEDED
|
||||
yylsp--;
|
||||
#endif
|
||||
|
||||
#if YYDEBUG != 0
|
||||
if (yydebug)
|
||||
{
|
||||
short *ssp1 = yyss - 1;
|
||||
fprintf (stderr, "Error: state stack now");
|
||||
while (ssp1 != yyssp)
|
||||
fprintf (stderr, " %d", *++ssp1);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
yyerrhandle:
|
||||
|
||||
yyn = yypact[yystate];
|
||||
if (yyn == YYFLAG)
|
||||
goto yyerrdefault;
|
||||
|
||||
yyn += YYTERROR;
|
||||
if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
|
||||
goto yyerrdefault;
|
||||
|
||||
yyn = yytable[yyn];
|
||||
if (yyn < 0)
|
||||
{
|
||||
if (yyn == YYFLAG)
|
||||
goto yyerrpop;
|
||||
yyn = -yyn;
|
||||
goto yyreduce;
|
||||
}
|
||||
else if (yyn == 0)
|
||||
goto yyerrpop;
|
||||
|
||||
if (yyn == YYFINAL)
|
||||
YYACCEPT;
|
||||
|
||||
#if YYDEBUG != 0
|
||||
if (yydebug)
|
||||
fprintf(stderr, "Shifting error token, ");
|
||||
#endif
|
||||
|
||||
*++yyvsp = yylval;
|
||||
#ifdef YYLSP_NEEDED
|
||||
*++yylsp = yylloc;
|
||||
#endif
|
||||
|
||||
yystate = yyn;
|
||||
goto yynewstate;
|
||||
}
|
||||
2392
Engine/source/console/torquescript/cmdgram.cpp
Normal file
2392
Engine/source/console/torquescript/cmdgram.cpp
Normal file
File diff suppressed because it is too large
Load diff
97
Engine/source/console/torquescript/cmdgram.h
Normal file
97
Engine/source/console/torquescript/cmdgram.h
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
#ifndef _CMDGRAM_H_
|
||||
#define _CMDGRAM_H_
|
||||
|
||||
typedef union {
|
||||
Token< char > c;
|
||||
Token< int > i;
|
||||
Token< const char* > s;
|
||||
Token< char* > str;
|
||||
Token< double > f;
|
||||
StmtNode* stmt;
|
||||
ExprNode* expr;
|
||||
SlotAssignNode* slist;
|
||||
VarNode* var;
|
||||
SlotDecl slot;
|
||||
InternalSlotDecl intslot;
|
||||
ObjectBlockDecl odcl;
|
||||
ObjectDeclNode* od;
|
||||
AssignDecl asn;
|
||||
IfStmtNode* ifnode;
|
||||
} YYSTYPE;
|
||||
#define rwDEFINE 258
|
||||
#define rwENDDEF 259
|
||||
#define rwDECLARE 260
|
||||
#define rwDECLARESINGLETON 261
|
||||
#define rwBREAK 262
|
||||
#define rwELSE 263
|
||||
#define rwCONTINUE 264
|
||||
#define rwGLOBAL 265
|
||||
#define rwIF 266
|
||||
#define rwNIL 267
|
||||
#define rwRETURN 268
|
||||
#define rwWHILE 269
|
||||
#define rwDO 270
|
||||
#define rwENDIF 271
|
||||
#define rwENDWHILE 272
|
||||
#define rwENDFOR 273
|
||||
#define rwDEFAULT 274
|
||||
#define rwFOR 275
|
||||
#define rwFOREACH 276
|
||||
#define rwFOREACHSTR 277
|
||||
#define rwIN 278
|
||||
#define rwDATABLOCK 279
|
||||
#define rwSWITCH 280
|
||||
#define rwCASE 281
|
||||
#define rwSWITCHSTR 282
|
||||
#define rwCASEOR 283
|
||||
#define rwPACKAGE 284
|
||||
#define rwNAMESPACE 285
|
||||
#define rwCLASS 286
|
||||
#define rwASSERT 287
|
||||
#define ILLEGAL_TOKEN 288
|
||||
#define CHRCONST 289
|
||||
#define INTCONST 290
|
||||
#define TTAG 291
|
||||
#define VAR 292
|
||||
#define IDENT 293
|
||||
#define TYPEIDENT 294
|
||||
#define DOCBLOCK 295
|
||||
#define STRATOM 296
|
||||
#define TAGATOM 297
|
||||
#define FLTCONST 298
|
||||
#define opINTNAME 299
|
||||
#define opINTNAMER 300
|
||||
#define opMINUSMINUS 301
|
||||
#define opPLUSPLUS 302
|
||||
#define STMT_SEP 303
|
||||
#define opSHL 304
|
||||
#define opSHR 305
|
||||
#define opPLASN 306
|
||||
#define opMIASN 307
|
||||
#define opMLASN 308
|
||||
#define opDVASN 309
|
||||
#define opMODASN 310
|
||||
#define opANDASN 311
|
||||
#define opXORASN 312
|
||||
#define opORASN 313
|
||||
#define opSLASN 314
|
||||
#define opSRASN 315
|
||||
#define opCAT 316
|
||||
#define opEQ 317
|
||||
#define opNE 318
|
||||
#define opGE 319
|
||||
#define opLE 320
|
||||
#define opAND 321
|
||||
#define opOR 322
|
||||
#define opSTREQ 323
|
||||
#define opCOLONCOLON 324
|
||||
#define opMDASN 325
|
||||
#define opNDASN 326
|
||||
#define opNTASN 327
|
||||
#define opSTRNE 328
|
||||
#define UNARY 329
|
||||
|
||||
|
||||
extern YYSTYPE CMDlval;
|
||||
|
||||
#endif
|
||||
1399
Engine/source/console/torquescript/codeBlock.cpp
Normal file
1399
Engine/source/console/torquescript/codeBlock.cpp
Normal file
File diff suppressed because it is too large
Load diff
170
Engine/source/console/torquescript/codeBlock.h
Normal file
170
Engine/source/console/torquescript/codeBlock.h
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _CODEBLOCK_H_
|
||||
#define _CODEBLOCK_H_
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "parser.h"
|
||||
#include "console/runtime.h"
|
||||
|
||||
struct CompilerLocalVariableToRegisterMappingTable
|
||||
{
|
||||
struct RemappingTable
|
||||
{
|
||||
std::vector<StringTableEntry> varList;
|
||||
};
|
||||
|
||||
std::unordered_map<StringTableEntry, RemappingTable> localVarToRegister;
|
||||
|
||||
void add(StringTableEntry functionName, StringTableEntry namespaceName, StringTableEntry varName);
|
||||
S32 lookup(StringTableEntry namespaceName, StringTableEntry functionName, StringTableEntry varName);
|
||||
CompilerLocalVariableToRegisterMappingTable copy();
|
||||
void reset();
|
||||
void write(Stream& stream);
|
||||
};
|
||||
|
||||
#include "compiler.h"
|
||||
|
||||
class Stream;
|
||||
class ConsoleValue;
|
||||
|
||||
/// Core TorqueScript code management class.
|
||||
///
|
||||
/// This class represents a block of code, usually mapped directly to a file.
|
||||
class CodeBlock : Con::Module
|
||||
{
|
||||
private:
|
||||
static CodeBlock* smCodeBlockList;
|
||||
|
||||
public:
|
||||
static bool smInFunction;
|
||||
static TorqueScriptParser * smCurrentParser;
|
||||
|
||||
static CodeBlock *getCodeBlockList()
|
||||
{
|
||||
return smCodeBlockList;
|
||||
}
|
||||
|
||||
static CodeBlock *find(StringTableEntry);
|
||||
|
||||
CodeBlock();
|
||||
~CodeBlock() override;
|
||||
|
||||
StringTableEntry name;
|
||||
StringTableEntry fullPath;
|
||||
StringTableEntry modPath;
|
||||
|
||||
char *globalStrings;
|
||||
char *functionStrings;
|
||||
|
||||
U32 functionStringsMaxLen;
|
||||
U32 globalStringsMaxLen;
|
||||
|
||||
F64 *globalFloats;
|
||||
F64 *functionFloats;
|
||||
|
||||
U32 codeSize;
|
||||
U32 *code;
|
||||
|
||||
CompilerLocalVariableToRegisterMappingTable variableRegisterTable;
|
||||
|
||||
U32 refCount;
|
||||
U32 lineBreakPairCount;
|
||||
U32 *lineBreakPairs;
|
||||
Vector<U32> breakList;
|
||||
CodeBlock *nextFile;
|
||||
|
||||
void addToCodeList();
|
||||
void removeFromCodeList();
|
||||
void calcBreakList();
|
||||
void clearAllBreaks() override;
|
||||
void setAllBreaks() override;
|
||||
void dumpInstructions(U32 startIp = 0, bool upToReturn = false);
|
||||
|
||||
/// Returns the first breakable line or 0 if none was found.
|
||||
/// @param lineNumber The one based line number.
|
||||
U32 findFirstBreakLine(U32 lineNumber) override;
|
||||
|
||||
void clearBreakpoint(U32 lineNumber) override;
|
||||
|
||||
/// Set a OP_BREAK instruction on a line. If a break
|
||||
/// is not possible on that line it returns false.
|
||||
/// @param lineNumber The one based line number.
|
||||
bool setBreakpoint(U32 lineNumber) override;
|
||||
|
||||
void findBreakLine(U32 ip, U32 &line, U32 &instruction) override;
|
||||
const char *getFileLine(U32 ip) override;
|
||||
|
||||
///
|
||||
String getFunctionArgs(U32 offset);
|
||||
|
||||
bool read(StringTableEntry fileName, Stream &st);
|
||||
bool compile(const char *dsoName, StringTableEntry fileName, const char *script, bool overrideNoDso = false);
|
||||
|
||||
/// Compiles and executes a block of script storing the compiled code in this
|
||||
/// CodeBlock. If there is no filename breakpoints will not be generated and
|
||||
/// the CodeBlock will not be added to the linked list of loaded CodeBlocks.
|
||||
/// Note that if the script contains no executable statements the CodeBlock
|
||||
/// will delete itself on return an empty string. The return string is any
|
||||
/// result of the code executed, if any, or an empty string.
|
||||
///
|
||||
/// @param fileName The file name, including path and extension, for the
|
||||
/// block of code or an empty string.
|
||||
/// @param script The script code to compile and execute.
|
||||
/// @param noCalls Skips calling functions from the script.
|
||||
/// @param setFrame A zero based index of the stack frame to execute the code
|
||||
/// with, zero being the top of the stack. If the the index is
|
||||
/// -1 a new frame is created. If the index is out of range the
|
||||
/// top stack frame is used.
|
||||
Con::EvalResult compileExec(StringTableEntry fileName, const char *script,
|
||||
bool noCalls, S32 setFrame = -1);
|
||||
|
||||
/// Executes the existing code in the CodeBlock. The return string is any
|
||||
/// result of the code executed, if any, or an empty string.
|
||||
///
|
||||
/// @param offset The instruction offset to start executing from.
|
||||
/// @param fnName The name of the function to execute or null.
|
||||
/// @param ns The namespace of the function to execute or null.
|
||||
/// @param argc The number of parameters passed to the function or
|
||||
/// zero to execute code outside of a function.
|
||||
/// @param argv The function parameter list.
|
||||
/// @param noCalls Skips calling functions from the script.
|
||||
/// @param setFrame A zero based index of the stack frame to execute the code
|
||||
/// with, zero being the top of the stack. If the the index is
|
||||
/// -1 a new frame is created. If the index is out of range the
|
||||
/// top stack frame is used.
|
||||
/// @param packageName The code package name or null.
|
||||
Con::EvalResult exec(U32 offset, const char* fnName, Namespace* ns, U32 argc,
|
||||
ConsoleValue* argv, bool noCalls, StringTableEntry packageName,
|
||||
S32 setFrame = -1) override;
|
||||
|
||||
const char* getFunctionArgs(StringTableEntry functionName, U32 functionOffset) override { return getFunctionArgs(functionOffset); }
|
||||
const char* getPath() override { return fullPath; }
|
||||
const char* getName() override { return name; }
|
||||
Vector<U32> getBreakableLines() override { return breakList; }
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
2298
Engine/source/console/torquescript/compiledEval.cpp
Normal file
2298
Engine/source/console/torquescript/compiledEval.cpp
Normal file
File diff suppressed because it is too large
Load diff
561
Engine/source/console/torquescript/compiler.cpp
Normal file
561
Engine/source/console/torquescript/compiler.cpp
Normal file
|
|
@ -0,0 +1,561 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "console/console.h"
|
||||
|
||||
#include "compiler.h"
|
||||
#include "console/simBase.h"
|
||||
|
||||
extern FuncVars gEvalFuncVars;
|
||||
extern FuncVars gGlobalScopeFuncVars;
|
||||
extern FuncVars *gFuncVars;
|
||||
|
||||
namespace Con
|
||||
{
|
||||
extern bool scriptWarningsAsAsserts;
|
||||
};
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
|
||||
F64 consoleStringToNumber(const char *str, StringTableEntry file, U32 line)
|
||||
{
|
||||
F64 val = dAtof(str);
|
||||
if (val != 0)
|
||||
return val;
|
||||
else if (!dStricmp(str, "true"))
|
||||
return 1;
|
||||
else if (!dStricmp(str, "false"))
|
||||
return 0;
|
||||
else if (file)
|
||||
{
|
||||
Con::warnf(ConsoleLogEntry::General, "%s (%d): string always evaluates to 0.", file, line);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
CompilerStringTable *gCurrentStringTable, gGlobalStringTable, gFunctionStringTable;
|
||||
CompilerFloatTable *gCurrentFloatTable, gGlobalFloatTable, gFunctionFloatTable;
|
||||
DataChunker gConsoleAllocator;
|
||||
CompilerIdentTable gIdentTable;
|
||||
CompilerLocalVariableToRegisterMappingTable gFunctionVariableMappingTable;
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
void evalSTEtoCode(StringTableEntry ste, U32 ip, U32 *ptr)
|
||||
{
|
||||
#if defined(TORQUE_CPU_X64) || defined(TORQUE_CPU_ARM64)
|
||||
*(U64*)(ptr) = (U64)ste;
|
||||
#else
|
||||
*ptr = (U32)ste;
|
||||
#endif
|
||||
}
|
||||
|
||||
void compileSTEtoCode(StringTableEntry ste, U32 ip, U32 *ptr)
|
||||
{
|
||||
if (ste)
|
||||
getIdentTable().add(ste, ip);
|
||||
*ptr = 0;
|
||||
*(ptr + 1) = 0;
|
||||
}
|
||||
|
||||
void(*STEtoCode)(StringTableEntry ste, U32 ip, U32 *ptr) = evalSTEtoCode;
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
bool gSyntaxError = false;
|
||||
bool gIsEvalCompile = false;
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
CompilerStringTable *getCurrentStringTable() { return gCurrentStringTable; }
|
||||
CompilerStringTable &getGlobalStringTable() { return gGlobalStringTable; }
|
||||
CompilerStringTable &getFunctionStringTable() { return gFunctionStringTable; }
|
||||
|
||||
CompilerLocalVariableToRegisterMappingTable& getFunctionVariableMappingTable() { return gFunctionVariableMappingTable; }
|
||||
|
||||
void setCurrentStringTable(CompilerStringTable* cst) { gCurrentStringTable = cst; }
|
||||
|
||||
CompilerFloatTable *getCurrentFloatTable() { return gCurrentFloatTable; }
|
||||
CompilerFloatTable &getGlobalFloatTable() { return gGlobalFloatTable; }
|
||||
CompilerFloatTable &getFunctionFloatTable() { return gFunctionFloatTable; }
|
||||
|
||||
void setCurrentFloatTable(CompilerFloatTable* cst) { gCurrentFloatTable = cst; }
|
||||
|
||||
CompilerIdentTable &getIdentTable() { return gIdentTable; }
|
||||
|
||||
void precompileIdent(StringTableEntry ident)
|
||||
{
|
||||
if (ident)
|
||||
gGlobalStringTable.add(ident);
|
||||
}
|
||||
|
||||
void resetTables()
|
||||
{
|
||||
setCurrentStringTable(&gGlobalStringTable);
|
||||
setCurrentFloatTable(&gGlobalFloatTable);
|
||||
getGlobalFloatTable().reset();
|
||||
getGlobalStringTable().reset();
|
||||
getFunctionFloatTable().reset();
|
||||
getFunctionStringTable().reset();
|
||||
getIdentTable().reset();
|
||||
getFunctionVariableMappingTable().reset();
|
||||
gGlobalScopeFuncVars.clear();
|
||||
gFuncVars = gIsEvalCompile ? &gEvalFuncVars : &gGlobalScopeFuncVars;
|
||||
}
|
||||
|
||||
void *consoleAlloc(U32 size) { return gConsoleAllocator.alloc(size); }
|
||||
void consoleAllocReset() { gConsoleAllocator.freeBlocks(); }
|
||||
|
||||
void scriptErrorHandler(const char* str)
|
||||
{
|
||||
if (Con::scriptWarningsAsAsserts)
|
||||
{
|
||||
AssertISV(false, str);
|
||||
}
|
||||
else
|
||||
{
|
||||
Con::warnf(ConsoleLogEntry::Type::Script, "%s", str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
using namespace Compiler;
|
||||
|
||||
S32 FuncVars::assign(StringTableEntry var, TypeReq currentType, S32 lineNumber, bool isConstant)
|
||||
{
|
||||
std::unordered_map<StringTableEntry, Var>::iterator found = vars.find(var);
|
||||
if (found != vars.end())
|
||||
{
|
||||
// if we are calling assign more than once AND it changes type, we don't know what the variable type is as this is a
|
||||
// dynamically typed language. So we will assign to None and bail. None will be taken care of by the code to always
|
||||
// load what the default type is (What Globals and arrays use, type None).
|
||||
if (currentType != found->second.currentType && found->second.currentType != TypeReqNone)
|
||||
found->second.currentType = TypeReqNone;
|
||||
|
||||
if (found->second.isConstant)
|
||||
{
|
||||
const char* str = avar("Script Warning: Reassigning variable %s when it is a constant. File: %s Line : %d", var, CodeBlock::smCurrentParser->getCurrentFile(), lineNumber);
|
||||
scriptErrorHandler(str);
|
||||
}
|
||||
return found->second.reg;
|
||||
}
|
||||
|
||||
S32 id = counter++;
|
||||
vars[var] = { id, currentType, var, isConstant };
|
||||
variableNameMap[id] = var;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
S32 FuncVars::lookup(StringTableEntry var, S32 lineNumber)
|
||||
{
|
||||
std::unordered_map<StringTableEntry, Var>::iterator found = vars.find(var);
|
||||
|
||||
if (found == vars.end())
|
||||
{
|
||||
const char* str = avar("Script Warning: Variable %s referenced before used when compiling script. File: %s Line: %d", var, CodeBlock::smCurrentParser->getCurrentFile(), lineNumber);
|
||||
scriptErrorHandler(str);
|
||||
|
||||
return assign(var, TypeReqString, lineNumber, false);
|
||||
}
|
||||
|
||||
return found->second.reg;
|
||||
}
|
||||
|
||||
TypeReq FuncVars::lookupType(StringTableEntry var, S32 lineNumber)
|
||||
{
|
||||
std::unordered_map<StringTableEntry, Var>::iterator found = vars.find(var);
|
||||
|
||||
if (found == vars.end())
|
||||
{
|
||||
const char* str = avar("Script Warning: Variable %s referenced before used when compiling script. File: %s Line: %d", var, CodeBlock::smCurrentParser->getCurrentFile(), lineNumber);
|
||||
scriptErrorHandler(str);
|
||||
|
||||
assign(var, TypeReqString, lineNumber, false);
|
||||
return vars.find(var)->second.currentType;
|
||||
}
|
||||
|
||||
return found->second.currentType;
|
||||
}
|
||||
|
||||
void FuncVars::clear()
|
||||
{
|
||||
vars.clear();
|
||||
variableNameMap.clear();
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
|
||||
U32 CompilerStringTable::add(const char *str, bool caseSens, bool tag)
|
||||
{
|
||||
// Is it already in?
|
||||
Entry **walk;
|
||||
for (walk = &list; *walk; walk = &((*walk)->next))
|
||||
{
|
||||
if ((*walk)->tag != tag)
|
||||
continue;
|
||||
|
||||
if (caseSens)
|
||||
{
|
||||
if (!String::compare((*walk)->string, str))
|
||||
return (*walk)->start;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!dStricmp((*walk)->string, str))
|
||||
return (*walk)->start;
|
||||
}
|
||||
}
|
||||
|
||||
// Write it out.
|
||||
Entry *newStr = (Entry *)consoleAlloc(sizeof(Entry));
|
||||
*walk = newStr;
|
||||
newStr->next = NULL;
|
||||
newStr->start = totalLen;
|
||||
U32 len = dStrlen(str) + 1;
|
||||
if (tag && len < 7) // alloc space for the numeric tag 1 for tag, 5 for # and 1 for nul
|
||||
len = 7;
|
||||
totalLen += len;
|
||||
newStr->string = (char *)consoleAlloc(len);
|
||||
newStr->len = len;
|
||||
newStr->tag = tag;
|
||||
dStrcpy(newStr->string, str, len);
|
||||
|
||||
// Put into the hash table.
|
||||
hashTable[str] = newStr;
|
||||
|
||||
return newStr->start;
|
||||
}
|
||||
|
||||
U32 CompilerStringTable::addIntString(U32 value)
|
||||
{
|
||||
dSprintf(buf, sizeof(buf), "%d", value);
|
||||
return add(buf);
|
||||
}
|
||||
|
||||
U32 CompilerStringTable::addFloatString(F64 value)
|
||||
{
|
||||
dSprintf(buf, sizeof(buf), "%g", value);
|
||||
return add(buf);
|
||||
}
|
||||
|
||||
void CompilerStringTable::reset()
|
||||
{
|
||||
list = NULL;
|
||||
totalLen = 0;
|
||||
}
|
||||
|
||||
char *CompilerStringTable::build()
|
||||
{
|
||||
char *ret = new char[totalLen];
|
||||
dMemset(ret, 0, totalLen);
|
||||
for (Entry *walk = list; walk; walk = walk->next)
|
||||
dStrcpy(ret + walk->start, walk->string, totalLen - walk->start);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CompilerStringTable::write(Stream &st)
|
||||
{
|
||||
st.write(totalLen);
|
||||
for (Entry *walk = list; walk; walk = walk->next)
|
||||
st.write(walk->len, walk->string);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
void CompilerLocalVariableToRegisterMappingTable::add(StringTableEntry functionName, StringTableEntry namespaceName, StringTableEntry varName)
|
||||
{
|
||||
StringTableEntry funcLookupTableName = StringTable->insert(avar("%s::%s", namespaceName, functionName));
|
||||
|
||||
localVarToRegister[funcLookupTableName].varList.push_back(varName);;
|
||||
}
|
||||
|
||||
S32 CompilerLocalVariableToRegisterMappingTable::lookup(StringTableEntry namespaceName, StringTableEntry functionName, StringTableEntry varName)
|
||||
{
|
||||
StringTableEntry funcLookupTableName = StringTable->insert(avar("%s::%s", namespaceName, functionName));
|
||||
|
||||
auto functionPosition = localVarToRegister.find(funcLookupTableName);
|
||||
if (functionPosition != localVarToRegister.end())
|
||||
{
|
||||
const auto& table = localVarToRegister[funcLookupTableName].varList;
|
||||
auto varPosition = std::find(table.begin(), table.end(), varName);
|
||||
if (varPosition != table.end())
|
||||
{
|
||||
return std::distance(table.begin(), varPosition);
|
||||
}
|
||||
}
|
||||
|
||||
Con::errorf("Unable to find local variable %s in function name %s", varName, funcLookupTableName);
|
||||
return -1;
|
||||
}
|
||||
|
||||
CompilerLocalVariableToRegisterMappingTable CompilerLocalVariableToRegisterMappingTable::copy()
|
||||
{
|
||||
// Trivilly copyable as its all plain old data and using STL containers... (We want a deep copy though!)
|
||||
CompilerLocalVariableToRegisterMappingTable table;
|
||||
table.localVarToRegister = localVarToRegister;
|
||||
return table;
|
||||
}
|
||||
|
||||
void CompilerLocalVariableToRegisterMappingTable::reset()
|
||||
{
|
||||
localVarToRegister.clear();
|
||||
}
|
||||
|
||||
void CompilerLocalVariableToRegisterMappingTable::write(Stream& stream)
|
||||
{
|
||||
stream.write((U32)localVarToRegister.size());
|
||||
|
||||
for (const auto& pair : localVarToRegister)
|
||||
{
|
||||
StringTableEntry functionName = pair.first;
|
||||
stream.writeString(functionName);
|
||||
|
||||
const auto& localVariableTableForFunction = localVarToRegister[functionName].varList;
|
||||
stream.write((U32)localVariableTableForFunction.size());
|
||||
|
||||
for (const StringTableEntry& varName : localVariableTableForFunction)
|
||||
{
|
||||
stream.writeString(varName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
U32 CompilerFloatTable::add(F64 value)
|
||||
{
|
||||
Entry **walk;
|
||||
U32 i = 0;
|
||||
for (walk = &list; *walk; walk = &((*walk)->next), i++)
|
||||
if (value == (*walk)->val)
|
||||
return i;
|
||||
Entry *newFloat = (Entry *)consoleAlloc(sizeof(Entry));
|
||||
newFloat->val = value;
|
||||
newFloat->next = NULL;
|
||||
count++;
|
||||
*walk = newFloat;
|
||||
return count - 1;
|
||||
}
|
||||
void CompilerFloatTable::reset()
|
||||
{
|
||||
list = NULL;
|
||||
count = 0;
|
||||
}
|
||||
F64 *CompilerFloatTable::build()
|
||||
{
|
||||
F64 *ret = new F64[count];
|
||||
U32 i = 0;
|
||||
for (Entry *walk = list; walk; walk = walk->next, i++)
|
||||
ret[i] = walk->val;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CompilerFloatTable::write(Stream &st)
|
||||
{
|
||||
st.write(count);
|
||||
for (Entry *walk = list; walk; walk = walk->next)
|
||||
st.write(walk->val);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
void CompilerIdentTable::reset()
|
||||
{
|
||||
list = NULL;
|
||||
}
|
||||
|
||||
void CompilerIdentTable::add(StringTableEntry ste, U32 ip)
|
||||
{
|
||||
U32 index = gGlobalStringTable.add(ste, false);
|
||||
Entry *newEntry = (Entry *)consoleAlloc(sizeof(Entry));
|
||||
newEntry->offset = index;
|
||||
newEntry->ip = ip;
|
||||
for (Entry *walk = list; walk; walk = walk->next)
|
||||
{
|
||||
if (walk->offset == index)
|
||||
{
|
||||
newEntry->nextIdent = walk->nextIdent;
|
||||
walk->nextIdent = newEntry;
|
||||
return;
|
||||
}
|
||||
}
|
||||
newEntry->next = list;
|
||||
list = newEntry;
|
||||
newEntry->nextIdent = NULL;
|
||||
}
|
||||
|
||||
void CompilerIdentTable::write(Stream &st)
|
||||
{
|
||||
U32 count = 0;
|
||||
Entry * walk;
|
||||
for (walk = list; walk; walk = walk->next)
|
||||
count++;
|
||||
st.write(count);
|
||||
for (walk = list; walk; walk = walk->next)
|
||||
{
|
||||
U32 ec = 0;
|
||||
Entry * el;
|
||||
for (el = walk; el; el = el->nextIdent)
|
||||
ec++;
|
||||
st.write(walk->offset);
|
||||
st.write(ec);
|
||||
for (el = walk; el; el = el->nextIdent)
|
||||
st.write(el->ip);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
U8 *CodeStream::allocCode(U32 sz)
|
||||
{
|
||||
U8 *ptr = NULL;
|
||||
if (mCodeHead)
|
||||
{
|
||||
const U32 bytesLeft = BlockSize - mCodeHead->size;
|
||||
if (bytesLeft > sz)
|
||||
{
|
||||
ptr = mCodeHead->data + mCodeHead->size;
|
||||
mCodeHead->size += sz;
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
CodeData *data = new CodeData;
|
||||
data->data = (U8*)dMalloc(BlockSize);
|
||||
data->size = sz;
|
||||
data->next = NULL;
|
||||
|
||||
if (mCodeHead)
|
||||
mCodeHead->next = data;
|
||||
mCodeHead = data;
|
||||
if (mCode == NULL)
|
||||
mCode = data;
|
||||
return data->data;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
void CodeStream::fixLoop(U32 loopBlockStart, U32 breakPoint, U32 continuePoint)
|
||||
{
|
||||
AssertFatal(mFixStack.size() > 0, "Fix stack mismatch");
|
||||
|
||||
U32 fixStart = mFixStack[mFixStack.size() - 1];
|
||||
for (U32 i = fixStart; i<mFixList.size(); i += 2)
|
||||
{
|
||||
FixType type = (FixType)mFixList[i + 1];
|
||||
|
||||
U32 fixedIp = 0;
|
||||
bool valid = true;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case FIXTYPE_LOOPBLOCKSTART:
|
||||
fixedIp = loopBlockStart;
|
||||
break;
|
||||
case FIXTYPE_BREAK:
|
||||
fixedIp = breakPoint;
|
||||
break;
|
||||
case FIXTYPE_CONTINUE:
|
||||
fixedIp = continuePoint;
|
||||
break;
|
||||
default:
|
||||
//Con::warnf("Address %u fixed as %u", mFixList[i], mFixList[i+1]);
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (valid)
|
||||
{
|
||||
patch(mFixList[i], fixedIp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
void CodeStream::emitCodeStream(U32 *size, U32 **stream, U32 **lineBreaks)
|
||||
{
|
||||
// Alloc stream
|
||||
U32 numLineBreaks = getNumLineBreaks();
|
||||
*stream = new U32[mCodePos + (numLineBreaks * 2)];
|
||||
dMemset(*stream, '\0', mCodePos + (numLineBreaks * 2));
|
||||
*size = mCodePos;
|
||||
|
||||
// Dump chunks & line breaks
|
||||
U32 outBytes = mCodePos * sizeof(U32);
|
||||
U8 *outPtr = *((U8**)stream);
|
||||
for (CodeData *itr = mCode; itr != NULL; itr = itr->next)
|
||||
{
|
||||
U32 bytesToCopy = itr->size > outBytes ? outBytes : itr->size;
|
||||
dMemcpy(outPtr, itr->data, bytesToCopy);
|
||||
outPtr += bytesToCopy;
|
||||
outBytes -= bytesToCopy;
|
||||
}
|
||||
|
||||
*lineBreaks = *stream + mCodePos;
|
||||
dMemcpy(*lineBreaks, mBreakLines.address(), sizeof(U32) * mBreakLines.size());
|
||||
|
||||
// Apply patches on top
|
||||
for (U32 i = 0; i<mPatchList.size(); i++)
|
||||
{
|
||||
PatchEntry &e = mPatchList[i];
|
||||
(*stream)[e.addr] = e.value;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
void CodeStream::reset()
|
||||
{
|
||||
mCodePos = 0;
|
||||
mFixStack.clear();
|
||||
mFixLoopStack.clear();
|
||||
mFixList.clear();
|
||||
mBreakLines.clear();
|
||||
|
||||
// Pop down to one code block
|
||||
CodeData *itr = mCode ? mCode->next : NULL;
|
||||
while (itr != NULL)
|
||||
{
|
||||
CodeData *next = itr->next;
|
||||
dFree(itr->data);
|
||||
delete(itr);
|
||||
itr = next;
|
||||
}
|
||||
|
||||
if (mCode)
|
||||
{
|
||||
mCode->size = 0;
|
||||
mCode->next = NULL;
|
||||
mCodeHead = mCode;
|
||||
}
|
||||
}
|
||||
480
Engine/source/console/torquescript/compiler.h
Normal file
480
Engine/source/console/torquescript/compiler.h
Normal file
|
|
@ -0,0 +1,480 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef _COMPILER_H_
|
||||
#define _COMPILER_H_
|
||||
|
||||
//#define DEBUG_CODESTREAM
|
||||
|
||||
#ifdef DEBUG_CODESTREAM
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
class CodeStream;
|
||||
struct StmtNode;
|
||||
class Stream;
|
||||
class DataChunker;
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "ast.h"
|
||||
#include "codeBlock.h"
|
||||
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/util/tVector.h"
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
/// The opcodes for the TorqueScript VM.
|
||||
enum CompiledInstructions
|
||||
{
|
||||
OP_FUNC_DECL,
|
||||
OP_CREATE_OBJECT,
|
||||
OP_ADD_OBJECT,
|
||||
OP_END_OBJECT,
|
||||
// Added to fix the stack issue [7/9/2007 Black]
|
||||
OP_FINISH_OBJECT,
|
||||
|
||||
OP_JMPIFFNOT,
|
||||
OP_JMPIFNOT,
|
||||
OP_JMPIFF,
|
||||
OP_JMPIF,
|
||||
OP_JMPIFNOT_NP,
|
||||
OP_JMPIF_NP, // 10
|
||||
OP_JMP,
|
||||
OP_RETURN,
|
||||
// fixes a bug when not explicitly returning a value
|
||||
OP_RETURN_VOID,
|
||||
OP_RETURN_FLT,
|
||||
OP_RETURN_UINT,
|
||||
|
||||
|
||||
OP_CMPEQ,
|
||||
OP_CMPGR,
|
||||
OP_CMPGE,
|
||||
OP_CMPLT,
|
||||
OP_CMPLE,
|
||||
OP_CMPNE,
|
||||
OP_XOR, // 20
|
||||
OP_MOD,
|
||||
OP_BITAND,
|
||||
OP_BITOR,
|
||||
OP_NOT,
|
||||
OP_NOTF,
|
||||
OP_ONESCOMPLEMENT,
|
||||
|
||||
OP_SHR,
|
||||
OP_SHL,
|
||||
OP_AND,
|
||||
OP_OR, // 30
|
||||
|
||||
OP_ADD,
|
||||
OP_SUB,
|
||||
OP_MUL,
|
||||
OP_DIV,
|
||||
OP_NEG,
|
||||
OP_INC,
|
||||
|
||||
OP_SETCURVAR,
|
||||
OP_SETCURVAR_CREATE,
|
||||
OP_SETCURVAR_ARRAY,
|
||||
OP_SETCURVAR_ARRAY_CREATE,
|
||||
|
||||
OP_LOADVAR_UINT,// 40
|
||||
OP_LOADVAR_FLT,
|
||||
OP_LOADVAR_STR,
|
||||
|
||||
OP_SAVEVAR_UINT,
|
||||
OP_SAVEVAR_FLT,
|
||||
OP_SAVEVAR_STR,
|
||||
|
||||
OP_LOAD_LOCAL_VAR_UINT,
|
||||
OP_LOAD_LOCAL_VAR_FLT,
|
||||
OP_LOAD_LOCAL_VAR_STR,
|
||||
|
||||
OP_SAVE_LOCAL_VAR_UINT,
|
||||
OP_SAVE_LOCAL_VAR_FLT,
|
||||
OP_SAVE_LOCAL_VAR_STR,
|
||||
|
||||
OP_SETCUROBJECT,
|
||||
OP_SETCUROBJECT_NEW,
|
||||
OP_SETCUROBJECT_INTERNAL,
|
||||
|
||||
OP_SETCURFIELD,
|
||||
OP_SETCURFIELD_ARRAY, // 50
|
||||
OP_SETCURFIELD_TYPE,
|
||||
|
||||
OP_LOADFIELD_UINT,
|
||||
OP_LOADFIELD_FLT,
|
||||
OP_LOADFIELD_STR,
|
||||
|
||||
OP_SAVEFIELD_UINT,
|
||||
OP_SAVEFIELD_FLT,
|
||||
OP_SAVEFIELD_STR,
|
||||
|
||||
OP_POP_STK,
|
||||
|
||||
OP_LOADIMMED_UINT,
|
||||
OP_LOADIMMED_FLT,
|
||||
OP_TAG_TO_STR,
|
||||
OP_LOADIMMED_STR, // 70
|
||||
OP_DOCBLOCK_STR, // 76
|
||||
OP_LOADIMMED_IDENT,
|
||||
|
||||
OP_CALLFUNC,
|
||||
|
||||
OP_ADVANCE_STR_APPENDCHAR,
|
||||
OP_REWIND_STR,
|
||||
OP_TERMINATE_REWIND_STR,
|
||||
|
||||
OP_COMPARE_STR,
|
||||
|
||||
OP_PUSH,
|
||||
OP_PUSH_FRAME,
|
||||
|
||||
OP_ASSERT,
|
||||
OP_BREAK,
|
||||
|
||||
OP_ITER_BEGIN, ///< Prepare foreach iterator.
|
||||
OP_ITER_BEGIN_STR, ///< Prepare foreach$ iterator.
|
||||
OP_ITER, ///< Enter foreach loop.
|
||||
OP_ITER_END, ///< End foreach loop.
|
||||
|
||||
OP_INVALID, // 90
|
||||
|
||||
MAX_OP_CODELEN ///< The amount of op codes.
|
||||
};
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
F64 consoleStringToNumber(const char *str, StringTableEntry file = 0, U32 line = 0);
|
||||
|
||||
U32 compileBlock(StmtNode *block, CodeStream &codeStream, U32 ip);
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
struct CompilerIdentTable
|
||||
{
|
||||
struct Entry
|
||||
{
|
||||
U32 offset;
|
||||
U32 ip;
|
||||
Entry *next;
|
||||
Entry *nextIdent;
|
||||
};
|
||||
Entry *list;
|
||||
void add(StringTableEntry ste, U32 ip);
|
||||
void reset();
|
||||
void write(Stream &st);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
struct CompilerStringTable
|
||||
{
|
||||
U32 totalLen;
|
||||
struct Entry
|
||||
{
|
||||
char *string;
|
||||
U32 start;
|
||||
U32 len;
|
||||
bool tag;
|
||||
Entry *next;
|
||||
};
|
||||
Entry *list;
|
||||
|
||||
char buf[256];
|
||||
std::unordered_map<std::string, Entry*> hashTable;
|
||||
|
||||
U32 add(const char *str, bool caseSens = true, bool tag = false);
|
||||
U32 addIntString(U32 value);
|
||||
U32 addFloatString(F64 value);
|
||||
void reset();
|
||||
char *build();
|
||||
void write(Stream &st);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
struct CompilerFloatTable
|
||||
{
|
||||
struct Entry
|
||||
{
|
||||
F64 val;
|
||||
Entry *next;
|
||||
};
|
||||
U32 count;
|
||||
Entry *list;
|
||||
|
||||
U32 add(F64 value);
|
||||
void reset();
|
||||
F64 *build();
|
||||
void write(Stream &st);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
inline StringTableEntry CodeToSTE(U32 *code, U32 ip)
|
||||
{
|
||||
#if defined(TORQUE_CPU_X64) || defined(TORQUE_CPU_ARM64)
|
||||
return (StringTableEntry)(*((U64*)(code + ip)));
|
||||
#else
|
||||
return (StringTableEntry)(*(code + ip));
|
||||
#endif
|
||||
}
|
||||
|
||||
extern void(*STEtoCode)(StringTableEntry ste, U32 ip, U32 *ptr);
|
||||
|
||||
void evalSTEtoCode(StringTableEntry ste, U32 ip, U32 *ptr);
|
||||
void compileSTEtoCode(StringTableEntry ste, U32 ip, U32 *ptr);
|
||||
|
||||
CompilerStringTable *getCurrentStringTable();
|
||||
CompilerStringTable &getGlobalStringTable();
|
||||
CompilerStringTable &getFunctionStringTable();
|
||||
CompilerLocalVariableToRegisterMappingTable& getFunctionVariableMappingTable();
|
||||
|
||||
void setCurrentStringTable(CompilerStringTable* cst);
|
||||
|
||||
CompilerFloatTable *getCurrentFloatTable();
|
||||
CompilerFloatTable &getGlobalFloatTable();
|
||||
CompilerFloatTable &getFunctionFloatTable();
|
||||
|
||||
void setCurrentFloatTable(CompilerFloatTable* cst);
|
||||
|
||||
CompilerIdentTable &getIdentTable();
|
||||
|
||||
void precompileIdent(StringTableEntry ident);
|
||||
|
||||
/// Helper function to reset the float, string, and ident tables to a base
|
||||
/// starting state.
|
||||
void resetTables();
|
||||
|
||||
void *consoleAlloc(U32 size);
|
||||
void consoleAllocReset();
|
||||
|
||||
void scriptErrorHandler(const char* str);
|
||||
|
||||
extern bool gSyntaxError;
|
||||
extern bool gIsEvalCompile;
|
||||
};
|
||||
|
||||
class FuncVars
|
||||
{
|
||||
struct Var
|
||||
{
|
||||
S32 reg;
|
||||
TypeReq currentType;
|
||||
StringTableEntry name;
|
||||
bool isConstant;
|
||||
};
|
||||
|
||||
public:
|
||||
S32 assign(StringTableEntry var, TypeReq currentType, S32 lineNumber, bool isConstant = false);
|
||||
|
||||
S32 lookup(StringTableEntry var, S32 lineNumber);
|
||||
|
||||
TypeReq lookupType(StringTableEntry var, S32 lineNumber);
|
||||
|
||||
inline S32 count() { return counter; }
|
||||
|
||||
std::unordered_map<S32, StringTableEntry> variableNameMap;
|
||||
|
||||
void clear();
|
||||
|
||||
private:
|
||||
std::unordered_map<StringTableEntry, Var> vars;
|
||||
S32 counter = 0;
|
||||
};
|
||||
|
||||
/// Utility class to emit and patch bytecode
|
||||
class CodeStream
|
||||
{
|
||||
public:
|
||||
|
||||
enum FixType
|
||||
{
|
||||
// For loops
|
||||
FIXTYPE_LOOPBLOCKSTART,
|
||||
FIXTYPE_BREAK,
|
||||
FIXTYPE_CONTINUE
|
||||
};
|
||||
|
||||
enum Constants
|
||||
{
|
||||
BlockSize = 16384,
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
typedef struct PatchEntry
|
||||
{
|
||||
U32 addr; ///< Address to patch
|
||||
U32 value; ///< Value to place at addr
|
||||
|
||||
PatchEntry(): addr(0), value(0) { ; }
|
||||
PatchEntry(U32 a, U32 v) : addr(a), value(v) { ; }
|
||||
} PatchEntry;
|
||||
|
||||
typedef struct CodeData
|
||||
{
|
||||
U8 *data; ///< Allocated data (size is BlockSize)
|
||||
U32 size; ///< Bytes used in data
|
||||
CodeData *next; ///< Next block
|
||||
} CodeData;
|
||||
|
||||
/// @name Emitted code
|
||||
/// {
|
||||
CodeData *mCode;
|
||||
CodeData *mCodeHead;
|
||||
U32 mCodePos;
|
||||
/// }
|
||||
|
||||
/// @name Code fixing stacks
|
||||
/// {
|
||||
Vector<U32> mFixList;
|
||||
Vector<U32> mFixStack;
|
||||
Vector<bool> mFixLoopStack;
|
||||
Vector<PatchEntry> mPatchList;
|
||||
/// }
|
||||
|
||||
Vector<U32> mBreakLines; ///< Line numbers
|
||||
|
||||
public:
|
||||
|
||||
CodeStream() : mCode(0), mCodeHead(NULL), mCodePos(0)
|
||||
{
|
||||
}
|
||||
|
||||
~CodeStream()
|
||||
{
|
||||
reset();
|
||||
|
||||
if (mCode)
|
||||
{
|
||||
dFree(mCode->data);
|
||||
delete mCode;
|
||||
}
|
||||
}
|
||||
|
||||
U8 *allocCode(U32 sz);
|
||||
|
||||
inline U32 emit(U32 code)
|
||||
{
|
||||
U32 *ptr = (U32*)allocCode(4);
|
||||
*ptr = code;
|
||||
#ifdef DEBUG_CODESTREAM
|
||||
printf("code[%u] = %u\n", mCodePos, code);
|
||||
#endif
|
||||
return mCodePos++;
|
||||
}
|
||||
|
||||
inline void patch(U32 addr, U32 code)
|
||||
{
|
||||
#ifdef DEBUG_CODESTREAM
|
||||
printf("patch[%u] = %u\n", addr, code);
|
||||
#endif
|
||||
mPatchList.push_back(PatchEntry(addr, code));
|
||||
}
|
||||
|
||||
inline U32 emitSTE(const char *code)
|
||||
{
|
||||
U64 *ptr = (U64*)allocCode(8);
|
||||
*ptr = 0;
|
||||
Compiler::STEtoCode(code, mCodePos, (U32*)ptr);
|
||||
#ifdef DEBUG_CODESTREAM
|
||||
printf("code[%u] = %s\n", mCodePos, code);
|
||||
#endif
|
||||
mCodePos += 2;
|
||||
return mCodePos - 2;
|
||||
}
|
||||
|
||||
inline U32 tell()
|
||||
{
|
||||
return mCodePos;
|
||||
}
|
||||
|
||||
inline bool inLoop()
|
||||
{
|
||||
for (U32 i = 0; i<mFixLoopStack.size(); i++)
|
||||
{
|
||||
if (mFixLoopStack[i])
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline U32 emitFix(FixType type)
|
||||
{
|
||||
U32 *ptr = (U32*)allocCode(4);
|
||||
*ptr = (U32)type;
|
||||
|
||||
#ifdef DEBUG_CODESTREAM
|
||||
printf("code[%u] = [FIX:%u]\n", mCodePos, (U32)type);
|
||||
#endif
|
||||
|
||||
mFixList.push_back(mCodePos);
|
||||
mFixList.push_back((U32)type);
|
||||
return mCodePos++;
|
||||
}
|
||||
|
||||
inline void pushFixScope(bool isLoop)
|
||||
{
|
||||
mFixStack.push_back(mFixList.size());
|
||||
mFixLoopStack.push_back(isLoop);
|
||||
}
|
||||
|
||||
inline void popFixScope()
|
||||
{
|
||||
AssertFatal(mFixStack.size() > 0, "Fix stack mismatch");
|
||||
|
||||
U32 newSize = mFixStack[mFixStack.size() - 1];
|
||||
while (mFixList.size() > newSize)
|
||||
mFixList.pop_back();
|
||||
mFixStack.pop_back();
|
||||
mFixLoopStack.pop_back();
|
||||
}
|
||||
|
||||
void fixLoop(U32 loopBlockStart, U32 breakPoint, U32 continuePoint);
|
||||
|
||||
inline void addBreakLine(U32 lineNumber, U32 ip)
|
||||
{
|
||||
mBreakLines.push_back(lineNumber);
|
||||
mBreakLines.push_back(ip);
|
||||
}
|
||||
|
||||
inline U32 getNumLineBreaks()
|
||||
{
|
||||
return mBreakLines.size() / 2;
|
||||
}
|
||||
|
||||
void emitCodeStream(U32 *size, U32 **stream, U32 **lineBreaks);
|
||||
|
||||
void reset();
|
||||
};
|
||||
|
||||
#endif
|
||||
157
Engine/source/console/torquescript/evalState.cpp
Normal file
157
Engine/source/console/torquescript/evalState.cpp
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
|
||||
#include "evalState.h"
|
||||
|
||||
void ExprEvalState::pushFrame(StringTableEntry frameName, Namespace *ns, S32 registerCount)
|
||||
{
|
||||
#ifdef DEBUG_SPEW
|
||||
validate();
|
||||
|
||||
Platform::outputDebugString("[ConsoleInternal] Pushing new frame for '%s' at %i",
|
||||
frameName, mStackDepth);
|
||||
#endif
|
||||
|
||||
if (mStackDepth + 1 > stack.size())
|
||||
{
|
||||
#ifdef DEBUG_SPEW
|
||||
Platform::outputDebugString("[ConsoleInternal] Growing stack by one frame");
|
||||
#endif
|
||||
|
||||
stack.push_back(new Dictionary);
|
||||
}
|
||||
|
||||
Dictionary& newFrame = *(stack[mStackDepth]);
|
||||
newFrame.setState();
|
||||
|
||||
newFrame.scopeName = frameName;
|
||||
newFrame.scopeNamespace = ns;
|
||||
|
||||
Con::pushStackFrame(stack[mStackDepth]);
|
||||
mStackDepth++;
|
||||
currentVariable = NULL;
|
||||
|
||||
AssertFatal(!newFrame.getCount(), "ExprEvalState::pushFrame - Dictionary not empty!");
|
||||
|
||||
ConsoleValue* consoleValArray = new ConsoleValue[registerCount]();
|
||||
localStack.push_back(ConsoleValueFrame(consoleValArray, false));
|
||||
currentRegisterArray = &localStack.last();
|
||||
|
||||
AssertFatal(mStackDepth == localStack.size(), avar("Stack sizes do not match. mStackDepth = %d, localStack = %d", mStackDepth, localStack.size()));
|
||||
|
||||
#ifdef DEBUG_SPEW
|
||||
validate();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ExprEvalState::popFrame()
|
||||
{
|
||||
AssertFatal(mStackDepth > 0, "ExprEvalState::popFrame - Stack Underflow!");
|
||||
|
||||
#ifdef DEBUG_SPEW
|
||||
validate();
|
||||
|
||||
Platform::outputDebugString("[ConsoleInternal] Popping %sframe at %i",
|
||||
getCurrentFrame().isOwner() ? "" : "shared ", mStackDepth - 1);
|
||||
#endif
|
||||
|
||||
Con::popStackFrame();
|
||||
mStackDepth--;
|
||||
stack[mStackDepth]->reset();
|
||||
currentVariable = NULL;
|
||||
|
||||
const ConsoleValueFrame& frame = localStack.last();
|
||||
localStack.pop_back();
|
||||
if (!frame.isReference)
|
||||
delete[] frame.values;
|
||||
|
||||
currentRegisterArray = localStack.size() ? &localStack.last() : NULL;
|
||||
|
||||
AssertFatal(mStackDepth == localStack.size(), avar("Stack sizes do not match. mStackDepth = %d, localStack = %d", mStackDepth, localStack.size()));
|
||||
|
||||
#ifdef DEBUG_SPEW
|
||||
validate();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ExprEvalState::pushFrameRef(S32 stackIndex)
|
||||
{
|
||||
AssertFatal(stackIndex >= 0 && stackIndex < mStackDepth, "You must be asking for a valid frame!");
|
||||
|
||||
#ifdef DEBUG_SPEW
|
||||
validate();
|
||||
|
||||
Platform::outputDebugString("[ConsoleInternal] Cloning frame from %i to %i",
|
||||
stackIndex, mStackDepth);
|
||||
#endif
|
||||
|
||||
if (mStackDepth + 1 > stack.size())
|
||||
{
|
||||
#ifdef DEBUG_SPEW
|
||||
Platform::outputDebugString("[ConsoleInternal] Growing stack by one frame");
|
||||
#endif
|
||||
|
||||
stack.push_back(new Dictionary);
|
||||
}
|
||||
|
||||
Dictionary& newFrame = *(stack[mStackDepth]);
|
||||
newFrame.setState(stack[stackIndex]);
|
||||
|
||||
Con::pushStackFrame(stack[mStackDepth]);
|
||||
|
||||
mStackDepth++;
|
||||
currentVariable = NULL;
|
||||
|
||||
ConsoleValue* values = localStack[stackIndex].values;
|
||||
localStack.push_back(ConsoleValueFrame(values, true));
|
||||
currentRegisterArray = &localStack.last();
|
||||
|
||||
AssertFatal(mStackDepth == localStack.size(), avar("Stack sizes do not match. mStackDepth = %d, localStack = %d", mStackDepth, localStack.size()));
|
||||
|
||||
#ifdef DEBUG_SPEW
|
||||
validate();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ExprEvalState::pushDebugFrame(S32 stackIndex)
|
||||
{
|
||||
pushFrameRef(stackIndex);
|
||||
|
||||
Dictionary& newFrame = *(stack[mStackDepth - 1]);
|
||||
|
||||
// debugger needs to know this info...
|
||||
newFrame.scopeName = stack[stackIndex]->scopeName;
|
||||
newFrame.scopeNamespace = stack[stackIndex]->scopeNamespace;
|
||||
newFrame.module = stack[stackIndex]->module;
|
||||
newFrame.ip = stack[stackIndex]->ip;
|
||||
}
|
||||
|
||||
ExprEvalState::ExprEvalState()
|
||||
{
|
||||
VECTOR_SET_ASSOCIATION(stack);
|
||||
currentVariable = NULL;
|
||||
mStackDepth = 0;
|
||||
stack.reserve(64);
|
||||
mShouldReset = false;
|
||||
mResetLocked = false;
|
||||
copyVariable = NULL;
|
||||
currentRegisterArray = NULL;
|
||||
}
|
||||
|
||||
ExprEvalState::~ExprEvalState()
|
||||
{
|
||||
// Delete callframes.
|
||||
|
||||
while (!stack.empty())
|
||||
{
|
||||
delete stack.last();
|
||||
stack.decrement();
|
||||
}
|
||||
}
|
||||
|
||||
void ExprEvalState::validate()
|
||||
{
|
||||
AssertFatal(mStackDepth <= stack.size(),
|
||||
"ExprEvalState::validate() - Stack depth pointing beyond last stack frame!");
|
||||
|
||||
for (U32 i = 0; i < stack.size(); ++i)
|
||||
stack[i]->validate();
|
||||
}
|
||||
119
Engine/source/console/torquescript/evalState.h
Normal file
119
Engine/source/console/torquescript/evalState.h
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
#ifndef _EVALSTATE_H
|
||||
#define _EVALSTATE_H
|
||||
#include "console/consoleInternal.h"
|
||||
|
||||
class ExprEvalState
|
||||
{
|
||||
public:
|
||||
/// @name Expression Evaluation
|
||||
/// @{
|
||||
|
||||
///
|
||||
|
||||
Dictionary::Entry *currentVariable;
|
||||
Dictionary::Entry *copyVariable;
|
||||
|
||||
U32 mStackDepth;
|
||||
bool mShouldReset; ///< Designates if the value stack should be reset
|
||||
bool mResetLocked; ///< mShouldReset will be set at the end
|
||||
|
||||
ExprEvalState();
|
||||
~ExprEvalState();
|
||||
|
||||
/// @}
|
||||
|
||||
/// @name Stack Management
|
||||
/// @{
|
||||
|
||||
/// The stack of callframes. The extra redirection is necessary since Dictionary holds
|
||||
/// an interior pointer that will become invalid when the object changes address.
|
||||
Vector< Dictionary* > stack;
|
||||
|
||||
S32 getTopOfStack() { return (S32)mStackDepth; }
|
||||
|
||||
Vector< ConsoleValueFrame > localStack;
|
||||
ConsoleValueFrame* currentRegisterArray; // contains array at to top of localStack
|
||||
|
||||
///
|
||||
|
||||
void setCurVarName(StringTableEntry name);
|
||||
void setCurVarNameCreate(StringTableEntry name);
|
||||
|
||||
S32 getIntVariable();
|
||||
F64 getFloatVariable();
|
||||
const char *getStringVariable();
|
||||
void setIntVariable(S32 val);
|
||||
void setFloatVariable(F64 val);
|
||||
void setStringVariable(const char *str);
|
||||
|
||||
TORQUE_FORCEINLINE S32 getLocalIntVariable(S32 reg)
|
||||
{
|
||||
return currentRegisterArray->values[reg].getInt();
|
||||
}
|
||||
|
||||
TORQUE_FORCEINLINE F64 getLocalFloatVariable(S32 reg)
|
||||
{
|
||||
return currentRegisterArray->values[reg].getFloat();
|
||||
}
|
||||
|
||||
TORQUE_FORCEINLINE const char* getLocalStringVariable(S32 reg)
|
||||
{
|
||||
return currentRegisterArray->values[reg].getString();
|
||||
}
|
||||
|
||||
TORQUE_FORCEINLINE void setLocalIntVariable(S32 reg, S64 val)
|
||||
{
|
||||
currentRegisterArray->values[reg].setInt(val);
|
||||
}
|
||||
|
||||
TORQUE_FORCEINLINE void setLocalFloatVariable(S32 reg, F64 val)
|
||||
{
|
||||
currentRegisterArray->values[reg].setFloat(val);
|
||||
}
|
||||
|
||||
TORQUE_FORCEINLINE void setLocalStringVariable(S32 reg, const char* val, S32 len)
|
||||
{
|
||||
currentRegisterArray->values[reg].setString(val, len);
|
||||
}
|
||||
|
||||
TORQUE_FORCEINLINE void setLocalStringTableEntryVariable(S32 reg, StringTableEntry val)
|
||||
{
|
||||
currentRegisterArray->values[reg].setStringTableEntry(val);
|
||||
}
|
||||
|
||||
TORQUE_FORCEINLINE void moveConsoleValue(S32 reg, ConsoleValue val)
|
||||
{
|
||||
currentRegisterArray->values[reg] = std::move(val);
|
||||
}
|
||||
|
||||
void pushFrame(StringTableEntry frameName, Namespace *ns, S32 regCount);
|
||||
void popFrame();
|
||||
|
||||
/// Puts a reference to an existing stack frame
|
||||
/// on the top of the stack.
|
||||
void pushFrameRef(S32 stackIndex);
|
||||
|
||||
void pushDebugFrame(S32 stackIndex);
|
||||
|
||||
U32 getStackDepth() const
|
||||
{
|
||||
return mStackDepth;
|
||||
}
|
||||
|
||||
Dictionary& getCurrentFrame()
|
||||
{
|
||||
return *(stack[mStackDepth - 1]);
|
||||
}
|
||||
|
||||
Dictionary& getFrameAt(S32 depth)
|
||||
{
|
||||
return *(stack[depth]);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// Run integrity checks for debugging.
|
||||
void validate();
|
||||
};
|
||||
|
||||
#endif
|
||||
103
Engine/source/console/torquescript/optimizer.cpp
Normal file
103
Engine/source/console/torquescript/optimizer.cpp
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2013 GarageGames, LLC
|
||||
// Copyright (c) 2021 TGEMIT Authors & Contributors
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "codeBlock.h"
|
||||
|
||||
static bool isLiteralNumber(ExprNode* node)
|
||||
{
|
||||
ExprNodeName name = node->getExprNodeNameEnum();
|
||||
return name == NameFloatNode || name == NameIntNode;
|
||||
}
|
||||
|
||||
static F64 getFloatValue(ExprNode* node)
|
||||
{
|
||||
if (node->getExprNodeNameEnum() == NameFloatNode)
|
||||
return static_cast<FloatNode*>(node)->value;
|
||||
return (F64)static_cast<IntNode*>(node)->value;
|
||||
}
|
||||
|
||||
static S32 getIntValue(ExprNode* node)
|
||||
{
|
||||
if (node->getExprNodeNameEnum() == NameFloatNode)
|
||||
return (S32)static_cast<FloatNode*>(node)->value;
|
||||
return static_cast<IntNode*>(node)->value;
|
||||
}
|
||||
|
||||
bool FloatBinaryExprNode::optimize()
|
||||
{
|
||||
// Perform constant folding
|
||||
if (isLiteralNumber(right) && isLiteralNumber(left))
|
||||
{
|
||||
F64 rightValue = getFloatValue(right);
|
||||
F64 leftValue = getFloatValue(left);
|
||||
F64 result = 0.0;
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case '+':
|
||||
result = leftValue + rightValue;
|
||||
break;
|
||||
case '-':
|
||||
result = leftValue - rightValue;
|
||||
break;
|
||||
case '*':
|
||||
result = leftValue * rightValue;
|
||||
break;
|
||||
case '/':
|
||||
if (rightValue != 0.0)
|
||||
result = leftValue / rightValue;
|
||||
break;
|
||||
}
|
||||
|
||||
optimizedNode = FloatNode::alloc(dbgLineNumber, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IntBinaryExprNode::optimize()
|
||||
{
|
||||
if (op == '%' && left->getExprNodeNameEnum() == NameVarNode && isLiteralNumber(right))
|
||||
{
|
||||
// %a % intconst
|
||||
S32 val = getIntValue(right);
|
||||
switch (val)
|
||||
{
|
||||
case 2:
|
||||
op = '&';
|
||||
optimizedNode = IntNode::alloc(dbgLineNumber, 1);
|
||||
return true;
|
||||
case 4:
|
||||
op = '&';
|
||||
optimizedNode = IntNode::alloc(dbgLineNumber, 3);
|
||||
return true;
|
||||
case 8:
|
||||
op = '&';
|
||||
optimizedNode = IntNode::alloc(dbgLineNumber, 7);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
0
Engine/source/console/torquescript/parser.cpp
Normal file
0
Engine/source/console/torquescript/parser.cpp
Normal file
49
Engine/source/console/torquescript/parser.h
Normal file
49
Engine/source/console/torquescript/parser.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
#ifndef _TORQUESCRIPT_PARSER_H_
|
||||
#define _TORQUESCRIPT_PARSER_H_
|
||||
#include <cstdio>
|
||||
|
||||
#include "platform/types.h"
|
||||
|
||||
const char* CMDGetCurrentFile();
|
||||
S32 CMDGetCurrentLine();
|
||||
S32 CMDparse();
|
||||
void CMDrestart(FILE* in);
|
||||
void CMDSetScanBuffer(const char *sb, const char *fn);
|
||||
|
||||
extern void expandEscape(char *dest, const char *src);
|
||||
extern bool collapseEscape(char *buf);
|
||||
|
||||
class TorqueScriptParser
|
||||
{
|
||||
public:
|
||||
TorqueScriptParser() = default;
|
||||
|
||||
const char* mExtension;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \brief Function for GetCurrentFile from the lexer
|
||||
//-----------------------------------------------------------------------------
|
||||
const char* getCurrentFile() { return CMDGetCurrentFile(); }
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \brief Function for GetCurrentLine from the lexer
|
||||
//-----------------------------------------------------------------------------
|
||||
S32 getCurrentLine() { return CMDGetCurrentLine(); }
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \brief Function for Parse from the lexer
|
||||
//-----------------------------------------------------------------------------
|
||||
S32 parse() { return CMDparse(); }
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \brief Function for Restart from the lexer
|
||||
//-----------------------------------------------------------------------------
|
||||
void restart(FILE *pInputFile) { CMDrestart(pInputFile); }
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \brief Function for SetScanBuffer from the lexer
|
||||
//-----------------------------------------------------------------------------
|
||||
void setScanBuffer(const char* sb, const char* fn) { CMDSetScanBuffer(sb, fn); }
|
||||
};
|
||||
|
||||
#endif
|
||||
486
Engine/source/console/torquescript/runtime.cpp
Normal file
486
Engine/source/console/torquescript/runtime.cpp
Normal file
|
|
@ -0,0 +1,486 @@
|
|||
#include "runtime.h"
|
||||
|
||||
#include "codeBlock.h"
|
||||
#include "console/script.h"
|
||||
#include "console/runtime.h"
|
||||
#include "core/volume.h"
|
||||
#include "core/stream/fileStream.h"
|
||||
#include "core/util/timeClass.h"
|
||||
|
||||
|
||||
namespace TorqueScript
|
||||
{
|
||||
// Buffer for expanding script filenames.
|
||||
static char scriptFilenameBuffer[1024];
|
||||
|
||||
TorqueScriptRuntime::TorqueScriptRuntime()
|
||||
{
|
||||
Con::registerRuntime(0, this);
|
||||
}
|
||||
|
||||
TorqueScriptRuntime::~TorqueScriptRuntime()
|
||||
{
|
||||
}
|
||||
|
||||
Con::EvalResult TorqueScriptRuntime::evaluate(const char* string, bool echo, const char* fileName)
|
||||
{
|
||||
ConsoleStackFrameSaver stackSaver;
|
||||
stackSaver.save();
|
||||
|
||||
if (echo)
|
||||
{
|
||||
if (string[0] == '%')
|
||||
Con::printf("%s", string);
|
||||
else
|
||||
Con::printf("%s%s", Con::getVariable("$Con::Prompt"), string);
|
||||
}
|
||||
|
||||
if (fileName)
|
||||
fileName = StringTable->insert(fileName);
|
||||
|
||||
CodeBlock* newCodeBlock = new CodeBlock();
|
||||
return std::move(newCodeBlock->compileExec(fileName, string, false, fileName ? -1 : 0));
|
||||
}
|
||||
|
||||
Con::EvalResult TorqueScriptRuntime::evaluate(const char* script, S32 frame, bool echo, const char* fileName)
|
||||
{
|
||||
// Make sure we're passing a valid frame to the eval.
|
||||
if (frame > Script::gEvalState.getStackDepth())
|
||||
frame = Script::gEvalState.getStackDepth() - 1;
|
||||
if (frame < 0)
|
||||
frame = 0;
|
||||
|
||||
// Local variables use their own memory management and can't be queried by just executing
|
||||
// TorqueScript, we have to go digging into the interpreter.
|
||||
S32 evalBufferLen = dStrlen(script);
|
||||
bool isEvaluatingLocalVariable = evalBufferLen > 0 && script[0] == '%';
|
||||
if (isEvaluatingLocalVariable)
|
||||
{
|
||||
// See calculation of current frame in pushing a reference frame for console exec, we need access
|
||||
// to the proper scope.
|
||||
//frame = gEvalState.getTopOfStack() - frame - 1;
|
||||
S32 stackIndex = Script::gEvalState.getStackDepth() - frame - 1;
|
||||
|
||||
Script::gEvalState.pushDebugFrame(stackIndex);
|
||||
|
||||
Dictionary& stackFrame = Script::gEvalState.getCurrentFrame();
|
||||
StringTableEntry functionName = stackFrame.scopeName;
|
||||
StringTableEntry namespaceName = stackFrame.scopeNamespace->mName;
|
||||
StringTableEntry varToLookup = StringTable->insert(script);
|
||||
|
||||
S32 registerId = ((CodeBlock*)stackFrame.module)->variableRegisterTable.lookup(namespaceName, functionName, varToLookup);
|
||||
|
||||
if (registerId == -1)
|
||||
{
|
||||
// ERROR, can't read the variable!
|
||||
return Con::EvalResult("variable not found");
|
||||
}
|
||||
|
||||
const char* varResult = Script::gEvalState.getLocalStringVariable(registerId);
|
||||
|
||||
Script::gEvalState.popFrame();
|
||||
|
||||
ConsoleValue val;
|
||||
val.setString(varResult);
|
||||
|
||||
return Con::EvalResult("variable not found");
|
||||
}
|
||||
|
||||
// Execute the eval.
|
||||
CodeBlock* newCodeBlock = new CodeBlock();
|
||||
Con::EvalResult result = newCodeBlock->compileExec(NULL, script, false, frame);
|
||||
return result;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Con::EvalResult TorqueScriptRuntime::evaluatef(const char* string, ...)
|
||||
{
|
||||
char buffer[4096];
|
||||
va_list args;
|
||||
va_start(args, string);
|
||||
dVsprintf(buffer, sizeof(buffer), string, args);
|
||||
va_end(args);
|
||||
return evaluate(buffer);
|
||||
}
|
||||
|
||||
bool TorqueScriptRuntime::executeFile(const char* fileName, bool noCalls, bool journalScript)
|
||||
{
|
||||
bool journal = false;
|
||||
|
||||
U32 execDepth = 0;
|
||||
U32 journalDepth = 1;
|
||||
|
||||
execDepth++;
|
||||
if (journalDepth >= execDepth)
|
||||
journalDepth = execDepth + 1;
|
||||
else
|
||||
journal = true;
|
||||
|
||||
bool ret = false;
|
||||
|
||||
if (journalScript && !journal)
|
||||
{
|
||||
journal = true;
|
||||
journalDepth = execDepth;
|
||||
}
|
||||
|
||||
// Determine the filename we actually want...
|
||||
Con::expandScriptFilename(scriptFilenameBuffer, sizeof(scriptFilenameBuffer), fileName);
|
||||
|
||||
// since this function expects a script file reference, if it's a .dso
|
||||
// lets terminate the string before the dso so it will act like a .tscript
|
||||
if (dStrEndsWith(scriptFilenameBuffer, ".dso"))
|
||||
{
|
||||
scriptFilenameBuffer[dStrlen(scriptFilenameBuffer) - dStrlen(".dso")] = '\0';
|
||||
}
|
||||
|
||||
// Figure out where to put DSOs
|
||||
StringTableEntry dsoPath = Con::getDSOPath(scriptFilenameBuffer);
|
||||
|
||||
const char* ext = dStrrchr(scriptFilenameBuffer, '.');
|
||||
|
||||
if (!ext)
|
||||
{
|
||||
// Try appending the default script extension and see if that succeeds
|
||||
|
||||
if (executeFile(fileName + String("." TORQUE_SCRIPT_EXTENSION), noCalls, journalScript))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// We need an extension!
|
||||
Con::errorf(ConsoleLogEntry::Script, "exec: invalid script file name %s.", scriptFilenameBuffer);
|
||||
execDepth--;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check Editor Extensions
|
||||
bool isEditorScript = false;
|
||||
|
||||
// If the script file extension is '.ed.tscript' then compile it to a different compiled extension
|
||||
if (dStricmp(ext, "." TORQUE_SCRIPT_EXTENSION) == 0)
|
||||
{
|
||||
const char* ext2 = ext - 3;
|
||||
if (dStricmp(ext2, ".ed." TORQUE_SCRIPT_EXTENSION) == 0)
|
||||
isEditorScript = true;
|
||||
}
|
||||
else if (dStricmp(ext, ".gui") == 0)
|
||||
{
|
||||
const char* ext2 = ext - 3;
|
||||
if (dStricmp(ext2, ".ed.gui") == 0)
|
||||
isEditorScript = true;
|
||||
}
|
||||
|
||||
StringTableEntry scriptFileName = StringTable->insert(scriptFilenameBuffer);
|
||||
|
||||
// Is this a file we should compile? (anything in the prefs path should not be compiled)
|
||||
StringTableEntry prefsPath = Platform::getPrefsPath();
|
||||
bool compiled = dStricmp(ext, ".mis") && !journal && !Con::getBoolVariable("Scripts::ignoreDSOs");
|
||||
|
||||
// [tom, 12/5/2006] stripBasePath() fucks up if the filename is not in the exe
|
||||
// path, current directory or prefs path. Thus, getDSOFilename() will also screw
|
||||
// up and so this allows the scripts to still load but without a DSO.
|
||||
if (Platform::isFullPath(Platform::stripBasePath(scriptFilenameBuffer)))
|
||||
compiled = false;
|
||||
|
||||
// [tom, 11/17/2006] It seems to make sense to not compile scripts that are in the
|
||||
// prefs directory. However, getDSOPath() can handle this situation and will put
|
||||
// the dso along with the script to avoid name clashes with tools/game dsos.
|
||||
if ((dsoPath && *dsoPath == 0) || (prefsPath && prefsPath[0] && dStrnicmp(
|
||||
scriptFileName, prefsPath, dStrlen(prefsPath)) == 0))
|
||||
compiled = false;
|
||||
|
||||
// If we're in a journaling mode, then we will read the script
|
||||
// from the journal file.
|
||||
if (journal && Journal::IsPlaying())
|
||||
{
|
||||
char fileNameBuf[256];
|
||||
bool fileRead = false;
|
||||
U32 fileSize;
|
||||
|
||||
Journal::ReadString(fileNameBuf);
|
||||
Journal::Read(&fileRead);
|
||||
|
||||
if (!fileRead)
|
||||
{
|
||||
Con::errorf(ConsoleLogEntry::Script, "Journal script read (failed) for %s", fileNameBuf);
|
||||
execDepth--;
|
||||
return false;
|
||||
}
|
||||
Journal::Read(&fileSize);
|
||||
char* script = new char[fileSize + 1];
|
||||
Journal::Read(fileSize, script);
|
||||
script[fileSize] = 0;
|
||||
Con::printf("Executing (journal-read) %s.", scriptFileName);
|
||||
|
||||
CodeBlock *newCodeBlock = new CodeBlock();
|
||||
newCodeBlock->compileExec(scriptFileName, script, noCalls, 0);
|
||||
delete newCodeBlock;
|
||||
delete[] script;
|
||||
|
||||
execDepth--;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Ok, we let's try to load and compile the script.
|
||||
Torque::FS::FileNodeRef scriptFile = Torque::FS::GetFileNode(scriptFileName);
|
||||
Torque::FS::FileNodeRef dsoFile;
|
||||
|
||||
// ResourceObject *rScr = gResourceManager->find(scriptFileName);
|
||||
// ResourceObject *rCom = NULL;
|
||||
|
||||
char nameBuffer[512];
|
||||
char* script = NULL;
|
||||
U32 version;
|
||||
|
||||
Stream* compiledStream = NULL;
|
||||
Torque::Time scriptModifiedTime, dsoModifiedTime;
|
||||
|
||||
// Check here for .edso
|
||||
bool edso = false;
|
||||
if (dStricmp(ext, ".edso") == 0 && scriptFile != NULL)
|
||||
{
|
||||
edso = true;
|
||||
dsoFile = scriptFile;
|
||||
scriptFile = NULL;
|
||||
|
||||
dsoModifiedTime = dsoFile->getModifiedTime();
|
||||
dStrcpy(nameBuffer, scriptFileName, 512);
|
||||
}
|
||||
|
||||
// If we're supposed to be compiling this file, check to see if there's a DSO
|
||||
if (compiled && !edso)
|
||||
{
|
||||
const char* filenameOnly = dStrrchr(scriptFileName, '/');
|
||||
if (filenameOnly)
|
||||
++filenameOnly;
|
||||
else
|
||||
filenameOnly = scriptFileName;
|
||||
|
||||
char pathAndFilename[1024];
|
||||
Platform::makeFullPathName(filenameOnly, pathAndFilename, sizeof(pathAndFilename), dsoPath);
|
||||
|
||||
if (isEditorScript)
|
||||
dStrcpyl(nameBuffer, sizeof(nameBuffer), pathAndFilename, ".edso", NULL);
|
||||
else
|
||||
dStrcpyl(nameBuffer, sizeof(nameBuffer), pathAndFilename, ".dso", NULL);
|
||||
|
||||
dsoFile = Torque::FS::GetFileNode(nameBuffer);
|
||||
|
||||
if (scriptFile != NULL)
|
||||
scriptModifiedTime = scriptFile->getModifiedTime();
|
||||
|
||||
if (dsoFile != NULL)
|
||||
dsoModifiedTime = dsoFile->getModifiedTime();
|
||||
}
|
||||
|
||||
// Let's do a sanity check to complain about DSOs in the future.
|
||||
//
|
||||
// MM: This doesn't seem to be working correctly for now so let's just not issue
|
||||
// the warning until someone knows how to resolve it.
|
||||
//
|
||||
//if(compiled && rCom && rScr && Platform::compareFileTimes(comModifyTime, scrModifyTime) < 0)
|
||||
//{
|
||||
//Con::warnf("exec: Warning! Found a DSO from the future! (%s)", nameBuffer);
|
||||
//}
|
||||
|
||||
// If we had a DSO, let's check to see if we should be reading from it.
|
||||
//MGT: fixed bug with dsos not getting recompiled correctly
|
||||
//Note: Using Nathan Martin's version from the forums since its easier to read and understand
|
||||
if (compiled && dsoFile != NULL && (scriptFile == NULL || (dsoModifiedTime >= scriptModifiedTime)))
|
||||
{
|
||||
//MGT: end
|
||||
compiledStream = FileStream::createAndOpen(nameBuffer, Torque::FS::File::Read);
|
||||
if (compiledStream)
|
||||
{
|
||||
// Check the version!
|
||||
compiledStream->read(&version);
|
||||
if (version != Con::DSOVersion)
|
||||
{
|
||||
Con::warnf("exec: Found an old DSO (%s, ver %d < %d), ignoring.", nameBuffer, version, Con::DSOVersion);
|
||||
delete compiledStream;
|
||||
compiledStream = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we're journalling, let's write some info out.
|
||||
if (journal && Journal::IsRecording())
|
||||
Journal::WriteString(scriptFileName);
|
||||
|
||||
if (scriptFile != NULL && !compiledStream)
|
||||
{
|
||||
// If we have source but no compiled version, then we need to compile
|
||||
// (and journal as we do so, if that's required).
|
||||
|
||||
void* data;
|
||||
U32 dataSize = 0;
|
||||
Torque::FS::ReadFile(scriptFileName, data, dataSize, true);
|
||||
|
||||
if (journal && Journal::IsRecording())
|
||||
Journal::Write(bool(data != NULL));
|
||||
|
||||
if (data == NULL)
|
||||
{
|
||||
Con::errorf(ConsoleLogEntry::Script, "exec: invalid script file %s.", scriptFileName);
|
||||
execDepth--;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!dataSize)
|
||||
{
|
||||
execDepth--;
|
||||
return false;
|
||||
}
|
||||
|
||||
script = (char*)data;
|
||||
|
||||
if (journal && Journal::IsRecording())
|
||||
{
|
||||
Journal::Write(dataSize);
|
||||
Journal::Write(dataSize, data);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef TORQUE_NO_DSO_GENERATION
|
||||
if (compiled)
|
||||
{
|
||||
// compile this baddie.
|
||||
#ifdef TORQUE_DEBUG
|
||||
Con::printf("Compiling %s...", scriptFileName);
|
||||
#endif
|
||||
|
||||
CodeBlock *code = new CodeBlock();
|
||||
code->compile(nameBuffer, scriptFileName, script);
|
||||
delete code;
|
||||
code = NULL;
|
||||
|
||||
compiledStream = FileStream::createAndOpen(nameBuffer, Torque::FS::File::Read);
|
||||
if (compiledStream)
|
||||
{
|
||||
compiledStream->read(&version);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We have to exit out here, as otherwise we get double error reports.
|
||||
delete[] script;
|
||||
execDepth--;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
if (journal && Journal::IsRecording())
|
||||
Journal::Write(bool(false));
|
||||
}
|
||||
|
||||
if (compiledStream)
|
||||
{
|
||||
// Delete the script object first to limit memory used
|
||||
// during recursive execs.
|
||||
delete[] script;
|
||||
script = 0;
|
||||
|
||||
// We're all compiled, so let's run it.
|
||||
#ifdef TORQUE_DEBUG
|
||||
Con::printf("Loading compiled script %s.", scriptFileName);
|
||||
#endif
|
||||
CodeBlock* code = new CodeBlock;
|
||||
code->read(scriptFileName, *compiledStream);
|
||||
delete compiledStream;
|
||||
code->exec(0, scriptFileName, NULL, 0, NULL, noCalls, NULL, 0);
|
||||
delete code;
|
||||
ret = true;
|
||||
}
|
||||
else if (scriptFile)
|
||||
{
|
||||
// No compiled script, let's just try executing it
|
||||
// directly... this is either a mission file, or maybe
|
||||
// we're on a readonly volume.
|
||||
#ifdef TORQUE_DEBUG
|
||||
Con::printf("Executing %s.", scriptFileName);
|
||||
#endif
|
||||
|
||||
CodeBlock *newCodeBlock = new CodeBlock();
|
||||
StringTableEntry name = StringTable->insert(scriptFileName);
|
||||
|
||||
newCodeBlock->compileExec(name, script, noCalls, 0);
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Don't have anything.
|
||||
Con::warnf(ConsoleLogEntry::Script, "Missing file: %s!", scriptFileName);
|
||||
ret = false;
|
||||
}
|
||||
|
||||
delete[] script;
|
||||
execDepth--;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool TorqueScriptRuntime::compile(const char* fileName, bool overrideNoDso)
|
||||
{
|
||||
Con::expandScriptFilename( scriptFilenameBuffer, sizeof( scriptFilenameBuffer ), fileName );
|
||||
|
||||
// Figure out where to put DSOs
|
||||
StringTableEntry dsoPath = Con::getDSOPath(scriptFilenameBuffer);
|
||||
if(dsoPath && *dsoPath == 0)
|
||||
return false;
|
||||
|
||||
// If the script file extention is '.ed.tscript' then compile it to a different compiled extention
|
||||
bool isEditorScript = false;
|
||||
const char *ext = dStrrchr( scriptFilenameBuffer, '.' );
|
||||
if( ext && ( dStricmp( ext, "." TORQUE_SCRIPT_EXTENSION) == 0 ) )
|
||||
{
|
||||
const char* ext2 = ext - 3;
|
||||
if( dStricmp( ext2, ".ed." TORQUE_SCRIPT_EXTENSION) == 0 )
|
||||
isEditorScript = true;
|
||||
}
|
||||
else if( ext && ( dStricmp( ext, ".gui" ) == 0 ) )
|
||||
{
|
||||
const char* ext2 = ext - 3;
|
||||
if( dStricmp( ext2, ".ed.gui" ) == 0 )
|
||||
isEditorScript = true;
|
||||
}
|
||||
|
||||
const char *filenameOnly = dStrrchr(scriptFilenameBuffer, '/');
|
||||
if(filenameOnly)
|
||||
++filenameOnly;
|
||||
else
|
||||
filenameOnly = scriptFilenameBuffer;
|
||||
|
||||
char nameBuffer[512];
|
||||
|
||||
if( isEditorScript )
|
||||
dStrcpyl(nameBuffer, sizeof(nameBuffer), dsoPath, "/", filenameOnly, ".edso", NULL);
|
||||
else
|
||||
dStrcpyl(nameBuffer, sizeof(nameBuffer), dsoPath, "/", filenameOnly, ".dso", NULL);
|
||||
|
||||
void *data = NULL;
|
||||
U32 dataSize = 0;
|
||||
Torque::FS::ReadFile(scriptFilenameBuffer, data, dataSize, true);
|
||||
if(data == NULL)
|
||||
{
|
||||
Con::errorf(ConsoleLogEntry::Script, "compile: invalid script file %s.", scriptFilenameBuffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *script = static_cast<const char *>(data);
|
||||
|
||||
#ifdef TORQUE_DEBUG
|
||||
Con::printf("Compiling %s...", scriptFilenameBuffer);
|
||||
#endif
|
||||
|
||||
CodeBlock *code = new CodeBlock();
|
||||
code->compile(nameBuffer, scriptFilenameBuffer, script, overrideNoDso);
|
||||
delete code;
|
||||
delete[] script;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
27
Engine/source/console/torquescript/runtime.h
Normal file
27
Engine/source/console/torquescript/runtime.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef _TORQUESCRIPT_RUNTIME_H_
|
||||
#define _TORQUESCRIPT_RUNTIME_H_
|
||||
#include "ast.h"
|
||||
#include "console/runtime.h"
|
||||
|
||||
namespace TorqueScript
|
||||
{
|
||||
class TorqueScriptRuntime : public Con::Runtime
|
||||
{
|
||||
public:
|
||||
TorqueScriptRuntime();
|
||||
~TorqueScriptRuntime() override;
|
||||
|
||||
void expandEscapedCharacters(char* dest, const char* src) override { expandEscape(dest, src); }
|
||||
bool collapseEscapedCharacters(char* buf) override { return collapseEscape(buf); }
|
||||
Con::EvalResult evaluate(const char* string, bool echo = false, const char* fileName = NULL) override;
|
||||
Con::EvalResult evaluate(const char* script, S32 frame, bool echo = false, const char *fileName = NULL) override;
|
||||
Con::EvalResult evaluatef(const char* string, ...) override;
|
||||
bool executeFile(const char* fileName, bool noCalls, bool journalScript) override;
|
||||
bool compile(const char* fileName, bool overrideNoDso);
|
||||
};
|
||||
|
||||
inline TorqueScriptRuntime* gRuntime = new TorqueScriptRuntime();
|
||||
inline TorqueScriptRuntime* getRuntime() { return gRuntime; }
|
||||
}
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue