summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlavioJS <FlavioJS@54d463be-8e91-2dee-dedb-b68131a5f0ec>2007-04-28 09:57:29 +0000
committerFlavioJS <FlavioJS@54d463be-8e91-2dee-dedb-b68131a5f0ec>2007-04-28 09:57:29 +0000
commitf2aa0cc3c716b5c8320777cc1049f22e63f626f2 (patch)
treee02e68957aac150491c7bf37335e84af528023f8
parentf823790981543fbae9f22845558970137f8b0cc1 (diff)
downloadhercules-f2aa0cc3c716b5c8320777cc1049f22e63f626f2.tar.gz
hercules-f2aa0cc3c716b5c8320777cc1049f22e63f626f2.tar.bz2
hercules-f2aa0cc3c716b5c8320777cc1049f22e63f626f2.tar.xz
hercules-f2aa0cc3c716b5c8320777cc1049f22e63f626f2.zip
* Internal changes to the script engine:
- modulus division detects division by 0. dividing by zero stops the script and gives an error - underflow/overflow messages differentiated (warnings) - when a script function doesn't return a value, a C_NOP value is pushed instead (avoids stack corruption) - op_add merged with op_2+op_2num/op2_str - better type checking in the operators, int/string is never assumed. The script ends when an invalid type is found. - other minor code cleanups Changes made in consequence of: Ref: http://www.eathena.ws/board/index.php?s=&showtopic=149237&view=findpost&p=823195 git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@10379 54d463be-8e91-2dee-dedb-b68131a5f0ec
-rw-r--r--Changelog-Trunk.txt11
-rw-r--r--src/map/script.c566
-rw-r--r--src/map/script.h12
3 files changed, 305 insertions, 284 deletions
diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt
index 5504f9a22..42366bb96 100644
--- a/Changelog-Trunk.txt
+++ b/Changelog-Trunk.txt
@@ -3,6 +3,17 @@ Date Added
AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK.
IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
+2007/04/29
+ * Internal changes to the script engine: [FlavioJS]
+ - modulus division detects division by 0.
+ dividing by zero stops the script and gives an error
+ - underflow/overflow messages differentiated (warnings)
+ - when a script function doesn't return a value, a C_NOP value is pushed
+ instead (avoids stack corruption)
+ - op_add merged with op_2+op_2num/op2_str
+ - better type checking in the operators, int/string is never assumed.
+ The script ends when an invalid type is found.
+ - other minor code cleanups
2007/04/26
* Corrected High Jump so it works on Guild Castles when WoE is off.
* Moonlit petals now always knocks to the back of the character rather than
diff --git a/src/map/script.c b/src/map/script.c
index 6805dbff2..1538e8d10 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -55,8 +55,8 @@
// struct script_state* st;
//
-/// Returns the stack_data at the target index
-#define script_getdata(st,i) &((st)->stack->stack_data[(st)->start+(i)])
+/// Returns the script_data at the target index
+#define script_getdata(st,i) ( &((st)->stack->stack_data[(st)->start + (i)]) )
/// Returns if the stack contains data at the target index
#define script_hasdata(st,i) ( (st)->end > (st)->start + (i) )
/// Returns the index of the last data in the stack
@@ -65,10 +65,25 @@
#define script_pushint(st,val) push_val((st)->stack, C_INT, (val))
#define script_pushstr(st,val) push_str((st)->stack, C_STR, (val))
#define script_pushconststr(st,val) push_str((st)->stack, C_CONSTSTR, (val))
+/// Pushes a nil into the stack
+#define script_pushnil(st) push_val((st)->stack, C_NOP, 0)
+/// Pushes a copy of the data in the target index
+#define script_pushcopy(st,i) push_copy((st)->stack, (st)->start + (i))
#define script_getnum(st,val) conv_num(st, script_getdata(st,val))
#define script_getstr(st,val) conv_str(st, script_getdata(st,val))
#define script_getref(st,val) ((st)->stack->stack_data[(st)->start+(val)].ref)
+
+// Note: "top" functions/defines use indexes relative to the top of the stack
+// -1 is the index of the data at the top
+
+/// Returns the script_data at the target index relative to the top of the stack
+#define script_getdatatop(st,i) ( &((st)->stack->stack_data[(st)->stack->sp + (i)]) )
+/// Pushes a copy of the data in the target index relative to the top of the stack
+#define script_pushcopytop(st,i) push_copy((st)->stack, (st)->stack->sp + (i))
+/// Removes the range of values [start,end[ relative to the top of the stack
+#define script_removetop(st,start,end) ( pop_stack((st)->stack, ((st)->stack->sp + (start)), (st)->stack->sp + (end)) )
+
//
// struct script_data* data;
//
@@ -84,6 +99,9 @@
/// Returns if the script data is an internal script function label
#define data_isfunclabel(data) ( (data)->type == C_USERFUNC_POS )
+/// Returns the name of the reference
+#define data_referencename(data) ( str_buf + str_data[(data)->u.num&0x00ffffff].str )
+
#define FETCH(n, t) \
if( script_hasdata(st,n) ) \
(t)=script_getnum(st,n);
@@ -209,7 +227,7 @@ int mapreg_setreg(int num,int val);
int mapreg_setregstr(int num,const char *str);
enum c_op {
- C_NOP,
+ C_NOP, // end of script/no value (nil)
C_POS,
C_INT, // number
C_PARAM, // parameter variable (see pc_readparam/pc_setparam)
@@ -2159,99 +2177,97 @@ int conv_num(struct script_state *st,struct script_data *data)
return data->u.num;
}
-/*==========================================
- * スタックへ数値をプッシュ
- *------------------------------------------
- */
-void push_val(struct script_stack *stack,int type,int val)
+//
+// Stack operations
+//
+
+/// Increases the size of the stack
+void stack_expand(struct script_stack* stack)
{
- if(stack->sp >= stack->sp_max){
- stack->sp_max += 64;
- stack->stack_data = (struct script_data *)aRealloc(stack->stack_data,
- sizeof(stack->stack_data[0]) * stack->sp_max);
- memset(stack->stack_data + (stack->sp_max - 64), 0,
- 64 * sizeof(*(stack->stack_data)));
- }
-// if(battle_config.etc_log)
-// printf("push (%d,%d)-> %d\n",type,val,stack->sp);
- stack->stack_data[stack->sp].type=type;
- stack->stack_data[stack->sp].u.num=val;
- stack->stack_data[stack->sp].ref = NULL;
- stack->sp++;
+ stack->sp_max += 64;
+ stack->stack_data = (struct script_data*)aRealloc(stack->stack_data,
+ stack->sp_max * sizeof(stack->stack_data[0]) );
+ memset(stack->stack_data + (stack->sp_max - 64), 0,
+ 64 * sizeof(stack->stack_data[0]) );
}
-/*==========================================
- * スタックへ数値+リファレンスをプッシュ
- *------------------------------------------
- */
+/// Pushes a value into the stack
+#define push_val(stack,type,val) push_val2(stack, type, val, NULL)
-void push_val2(struct script_stack *stack,int type,int val,struct linkdb_node** ref) {
- push_val(stack,type,val);
- stack->stack_data[stack->sp-1].ref = ref;
+/// Pushes a value into the stack (with reference)
+void push_val2(struct script_stack* stack, int type, int val, struct linkdb_node** ref)
+{
+ if( stack->sp >= stack->sp_max )
+ stack_expand(stack);
+ stack->stack_data[stack->sp].type = type;
+ stack->stack_data[stack->sp].u.num = val;
+ stack->stack_data[stack->sp].ref = ref;
+ stack->sp++;
}
-/*==========================================
- * スタックへ文字列をプッシュ
- *------------------------------------------
- */
-void push_str(struct script_stack *stack,int type,char *str)
+/// Pushes a string into the stack
+void push_str(struct script_stack* stack, int type, char* str)
{
- if(stack->sp>=stack->sp_max){
- stack->sp_max += 64;
- stack->stack_data = (struct script_data *)aRealloc(stack->stack_data,
- sizeof(stack->stack_data[0]) * stack->sp_max);
- memset(stack->stack_data + (stack->sp_max - 64), '\0',
- 64 * sizeof(*(stack->stack_data)));
- }
-// if(battle_config.etc_log)
-// printf("push (%d,%x)-> %d\n",type,str,stack->sp);
- stack->stack_data[stack->sp].type =type;
- stack->stack_data[stack->sp].u.str=str;
- stack->stack_data[stack->sp].ref =NULL;
+ if( stack->sp >= stack->sp_max )
+ stack_expand(stack);
+ stack->stack_data[stack->sp].type = type;
+ stack->stack_data[stack->sp].u.str = str;
+ stack->stack_data[stack->sp].ref = NULL;
stack->sp++;
}
-/*==========================================
- * スタックへ複製をプッシュ
- *------------------------------------------
- */
-void push_copy(struct script_stack *stack,int pos)
+/// Pushes a copy of the target position into the stack
+void push_copy(struct script_stack* stack, int pos)
{
- switch(stack->stack_data[pos].type){
+ switch( stack->stack_data[pos].type )
+ {
case C_CONSTSTR:
- push_str(stack,C_CONSTSTR,stack->stack_data[pos].u.str);
+ push_str(stack, C_CONSTSTR, stack->stack_data[pos].u.str);
break;
case C_STR:
- push_str(stack,C_STR,aStrdup(stack->stack_data[pos].u.str));
+ push_str(stack, C_STR, aStrdup(stack->stack_data[pos].u.str));
break;
default:
push_val2(
- stack,stack->stack_data[pos].type,stack->stack_data[pos].u.num,
+ stack,stack->stack_data[pos].type,
+ stack->stack_data[pos].u.num,
stack->stack_data[pos].ref
);
break;
}
}
-/*==========================================
- * スタックからポップ
- *------------------------------------------
- */
-void pop_stack(struct script_stack* stack,int start,int end)
+/// Removes the values in indexes [start,end[ from the stack
+void pop_stack(struct script_stack* stack, int start, int end)
{
+ struct script_data* data;
int i;
- for(i=start;i<end;i++){
- if(stack->stack_data[i].type==C_STR){
- aFree(stack->stack_data[i].u.str);
- stack->stack_data[i].type=C_INT; //Might not be correct, but it's done in case to prevent pointer errors later on. [Skotlex]
- }
- }
- if(stack->sp>end){
- memmove(&stack->stack_data[start],&stack->stack_data[end],sizeof(stack->stack_data[0])*(stack->sp-end));
+
+ if( start < 0 )
+ start = 0;
+ if( end > stack->sp_max )
+ end = stack->sp_max;
+ if( start >= end )
+ return;// nothing to pop
+
+ // free stack elements
+ for( i = start; i < end; i++ )
+ {
+ data = &stack->stack_data[i];
+ if( data->type == C_STR )
+ aFree(data->u.str);
+ data->type = C_NOP;
}
- stack->sp-=end-start;
+ // move the rest of the elements
+ if( stack->sp > end )
+ memmove(&stack->stack_data[start], &stack->stack_data[end], sizeof(stack->stack_data[0])*(stack->sp - end));
+ stack->sp -= end - start;
}
+///
+///
+///
+
/*==========================================
* スクリプト依存変数、関数依存変数の解放
*------------------------------------------
@@ -2379,134 +2395,82 @@ int isstr(struct script_data *c) {
return 0;
}
-/*==========================================
- * Three-section operator
- * test ? if_true : if_false
- *------------------------------------------
- */
-void op_3(struct script_state *st) {
+/// Triary operators
+/// test ? if_true : if_false
+void op_3(struct script_state* st, int op)
+{
+ struct script_data* data;
int flag = 0;
- if( isstr(&st->stack->stack_data[st->stack->sp-3])) {
- const char *str = conv_str(st,& (st->stack->stack_data[st->stack->sp-3]));
- flag = str[0];
- } else {
- flag = conv_num(st,& (st->stack->stack_data[st->stack->sp-3]));
- }
- if( flag ) {
- push_copy(st->stack, st->stack->sp-2 );
- } else {
- push_copy(st->stack, st->stack->sp-1 );
- }
- pop_stack(st->stack,st->stack->sp-4,st->stack->sp-1);
-}
-/*==========================================
- * 加算演算子
- *------------------------------------------
- */
-void op_add(struct script_state* st)
-{
- st->stack->sp--;
- get_val(st,&(st->stack->stack_data[st->stack->sp]));
- get_val(st,&(st->stack->stack_data[st->stack->sp-1]));
-
- if(isstr(&st->stack->stack_data[st->stack->sp]) || isstr(&st->stack->stack_data[st->stack->sp-1])){
- conv_str(st,&(st->stack->stack_data[st->stack->sp]));
- conv_str(st,&(st->stack->stack_data[st->stack->sp-1]));
- }
- if(st->stack->stack_data[st->stack->sp].type==C_INT){ // ii
- int *i1 = &st->stack->stack_data[st->stack->sp-1].u.num;
- int *i2 = &st->stack->stack_data[st->stack->sp].u.num;
- int ret = *i1 + *i2;
- double ret_double = (double)*i1 + (double)*i2;
- if(ret_double > INT_MAX|| ret_double < INT_MIN) {
- ShowWarning("script::op_add overflow detected op:%d\n",C_ADD);
- report_src(st);
- ret = cap_value(ret, INT_MIN, INT_MAX);
- }
- *i1 = ret;
- } else { // ssの予定
- char *buf;
- buf=(char *)aMallocA((strlen(st->stack->stack_data[st->stack->sp-1].u.str)+
- strlen(st->stack->stack_data[st->stack->sp].u.str)+1)*sizeof(char));
- strcpy(buf,st->stack->stack_data[st->stack->sp-1].u.str);
- strcat(buf,st->stack->stack_data[st->stack->sp].u.str);
- if(st->stack->stack_data[st->stack->sp-1].type==C_STR)
- {
- aFree(st->stack->stack_data[st->stack->sp-1].u.str);
- st->stack->stack_data[st->stack->sp-1].type=C_INT;
- }
- if(st->stack->stack_data[st->stack->sp].type==C_STR)
- {
- aFree(st->stack->stack_data[st->stack->sp].u.str);
- st->stack->stack_data[st->stack->sp].type=C_INT;
- }
- st->stack->stack_data[st->stack->sp-1].type=C_STR;
- st->stack->stack_data[st->stack->sp-1].u.str=buf;
+ data = script_getdatatop(st, -3);
+ get_val(st, data);
+
+ if( data_isstring(data) )
+ flag = data->u.str[0];
+ else if( data_isint(data) )
+ flag = data->u.num;
+ else
+ {
+ ShowError("script:op_3: invalid type of data op:%d data:%d\n", op, data->type);
+ report_src(st);
+ script_removetop(st, -3, 0);
+ script_pushnil(st);
+ return;
}
- st->stack->stack_data[st->stack->sp-1].ref = NULL;
+ if( flag )
+ script_pushcopytop(st, -2);
+ else
+ script_pushcopytop(st, -1);
+ script_removetop(st, -4, -1);
}
-/*==========================================
- * 二項演算子(文字列)
- *------------------------------------------
- */
-void op_2str(struct script_state *st,int op,int sp1,int sp2)
+/// Binary string operators
+/// s1 EQ s2 -> i
+/// s1 NE s2 -> i
+/// s1 GT s2 -> i
+/// s1 GE s2 -> i
+/// s1 LT s2 -> i
+/// s1 LE s2 -> i
+/// s1 ADD s2 -> s
+void op_2str(struct script_state* st, int op, const char* s1, const char* s2)
{
- char *s1=st->stack->stack_data[sp1].u.str,
- *s2=st->stack->stack_data[sp2].u.str;
- int a=0;
+ int a = 0;
switch(op){
- case C_EQ:
- a= (strcmp(s1,s2)==0);
- break;
- case C_NE:
- a= (strcmp(s1,s2)!=0);
- break;
- case C_GT:
- a= (strcmp(s1,s2)> 0);
- break;
- case C_GE:
- a= (strcmp(s1,s2)>=0);
- break;
- case C_LT:
- a= (strcmp(s1,s2)< 0);
- break;
- case C_LE:
- a= (strcmp(s1,s2)<=0);
- break;
+ case C_EQ: a = (strcmp(s1,s2) == 0); break;
+ case C_NE: a = (strcmp(s1,s2) != 0); break;
+ case C_GT: a = (strcmp(s1,s2) > 0); break;
+ case C_GE: a = (strcmp(s1,s2) >= 0); break;
+ case C_LT: a = (strcmp(s1,s2) < 0); break;
+ case C_LE: a = (strcmp(s1,s2) <= 0); break;
+ case C_ADD:
+ {
+ char* buf = (char *)aMallocA((strlen(s1)+strlen(s2)+1)*sizeof(char));
+ strcpy(buf, s1);
+ strcat(buf, s2);
+ script_pushstr(st, buf);
+ return;
+ }
default:
- ShowWarning("script: illegal string operator\n");
- break;
+ ShowError("script:op2_str: unexpected string operator op:%d\n", op);
+ report_src(st);
+ script_pushnil(st);
+ st->state = END;
+ return;
}
- // Because push_val() overwrite stack_data[sp1], C_STR on stack_data[sp1] won't be freed.
- // So, call push_val() after freeing strings. [jA1783]
- // script_pushint(st,a);
- if(st->stack->stack_data[sp1].type==C_STR)
- {
- aFree(s1);
- st->stack->stack_data[sp1].type=C_INT;
- }
- if(st->stack->stack_data[sp2].type==C_STR)
- {
- aFree(s2);
- st->stack->stack_data[sp2].type=C_INT;
- }
script_pushint(st,a);
}
-/*==========================================
- * 二項演算子(数値)
- *------------------------------------------
- */
-void op_2num(struct script_state *st,int op,int i1,int i2)
+/// Binary number operators
+/// i OP i -> i
+void op_2num(struct script_state* st, int op, int i1, int i2)
{
- int ret = 0;
- double ret_double = 0;
- switch(op){
- case C_MOD: ret = i2 ? i1 % i2 : 0; break;
+ int ret;
+ double ret_double;
+
+ switch( op )
+ {
case C_AND: ret = i1 & i2; break;
case C_OR: ret = i1 | i2; break;
case C_XOR: ret = i1 ^ i2; break;
@@ -2520,90 +2484,131 @@ void op_2num(struct script_state *st,int op,int i1,int i2)
case C_LE: ret = (i1 <= i2); break;
case C_R_SHIFT: ret = i1>>i2; break;
case C_L_SHIFT: ret = i1<<i2; break;
+ case C_DIV:
+ case C_MOD:
+ if( i2 == 0 )
+ {
+ ShowError("script:op_2num: division by zero detected op:%d\n", op);
+ report_src(st);
+ script_pushnil(st);
+ st->state = END;
+ return;
+ }
+ else if( op == C_DIV )
+ ret = i1 / i2;
+ else//if( op == C_MOD )
+ ret = i1 % i2;
+ break;
default:
- switch(op) {
+ switch( op )
+ {// operators that can overflow/underflow
+ case C_ADD: ret = i1 + i2; ret_double = (double)i1 + (double)i2; break;
case C_SUB: ret = i1 - i2; ret_double = (double)i1 - (double)i2; break;
case C_MUL: ret = i1 * i2; ret_double = (double)i1 * (double)i2; break;
- case C_DIV:
- if(i2 == 0) {
- printf("script::op_2num division by zero.\n");
- ret = INT_MAX;
- ret_double = 0; // doubleの精度が怪しいのでオーバーフロー対策を飛ばす
- } else {
- ret = i1 / i2; ret_double = (double)i1 / (double)i2;
- }
- break;
+ default:
+ ShowError("script:op_2num: unexpected number operator op:%d\n", op);
+ report_src(st);
+ script_pushnil(st);
+ return;
+ }
+ if( ret_double < INT_MIN )
+ {
+ ShowWarning("script:op_2num: underflow detected op:%d\n", op);
+ report_src(st);
+ ret = INT_MIN;
}
- if(ret_double > INT_MAX || ret_double < INT_MIN) {
- printf("script::op_2num overflow detected op:%d\n",op);
+ else if( ret_double > INT_MAX )
+ {
+ ShowWarning("script:op_2num: overflow detected op:%d\n", op);
report_src(st);
- ret = (int)cap_value(ret_double,INT_MAX,INT_MIN);
+ ret = INT_MAX;
}
}
- script_pushint(st,ret);
+ script_pushint(st, ret);
}
-/*==========================================
- * 二項演算子
- *------------------------------------------
- */
-void op_2(struct script_state *st,int op)
+/// Binary operators
+void op_2(struct script_state *st, int op)
{
- int i1,i2;
- char *s1=NULL,*s2=NULL;
+ struct script_data* left;
+ struct script_data* right;
- i2=pop_val(st);
- if( isstr(&st->stack->stack_data[st->stack->sp]) )
- s2=st->stack->stack_data[st->stack->sp].u.str;
+ left = script_getdatatop(st, -2);
+ right = script_getdatatop(st, -1);
- i1=pop_val(st);
- if( isstr(&st->stack->stack_data[st->stack->sp]) )
- s1=st->stack->stack_data[st->stack->sp].u.str;
+ get_val(st, left);
+ get_val(st, right);
- if( s1!=NULL && s2!=NULL ){
- // ss => op_2str
- op_2str(st,op,st->stack->sp,st->stack->sp+1);
- }else if( s1==NULL && s2==NULL ){
- // ii => op_2num
- op_2num(st,op,i1,i2);
- }else{
- // si,is => error
- ShowWarning("script: op_2: int&str, str&int not allow.\n");
- report_src(st);
- if(s1 && st->stack->stack_data[st->stack->sp].type == C_STR)
- {
- aFree(s1);
- st->stack->stack_data[st->stack->sp].type = C_INT;
- }
- if(s2 && st->stack->stack_data[st->stack->sp+1].type == C_STR)
- {
- aFree(s2);
- st->stack->stack_data[st->stack->sp+1].type = C_INT;
+ // automatic conversions
+ switch( op )
+ {
+ case C_ADD:
+ if( data_isstring(left) || data_isstring(right) )
+ {// convert to string
+ conv_str(st, left);
+ conv_str(st, right);
}
- script_pushint(st,0);
+ break;
+ }
+
+ if( data_isstring(left) && data_isstring(right) )
+ {// ss => op_2str
+ op_2str(st, op, left->u.str, right->u.str);
+ script_removetop(st, -3, -1);// pop the two values before the top one
+ }
+ else if( data_isint(left) && data_isint(right) )
+ {// ii => op_2num
+ int i1 = left->u.num;
+ int i2 = right->u.num;
+ script_removetop(st, -2, 0);
+ op_2num(st, op, i1, i2);
+ }
+ else
+ {// invalid argument
+ ShowError("script:op_2: invalid type of data op:%d left:%d right:%d\n", op, left->type, right->type);
+ report_src(st);
+ script_removetop(st, -2, 0);
+ script_pushnil(st);
+ st->state = END;
}
}
-/*==========================================
- * 単項演算子
- *------------------------------------------
- */
-void op_1num(struct script_state *st,int op)
+/// Unary operators
+/// NEG i -> i
+/// NOT i -> i
+/// LNOT i -> i
+void op_1(struct script_state* st, int op)
{
+ struct script_data* data;
int i1;
- i1=pop_val(st);
- switch(op){
- case C_NEG:
- i1=-i1;
- break;
- case C_NOT:
- i1=~i1;
- break;
- case C_LNOT:
- i1=!i1;
- break;
+
+ data = script_getdatatop(st, -1);
+ get_val(st, data);
+
+ if( !data_isint(data) )
+ {// not a number
+ ShowError("script:op_1: invalid type of data op:%d data:%d\n", op, data->type);
+ report_src(st);
+ script_pushnil(st);
+ st->state = END;
+ return;
}
- script_pushint(st,i1);
+
+ i1 = data->u.num;
+ script_removetop(st, -1, 0);
+ switch( op )
+ {
+ case C_NEG: i1 = -i1; break;
+ case C_NOT: i1 = ~i1; break;
+ case C_LNOT: i1 = !i1; break;
+ default:
+ ShowError("script:op_1: unexpected operator op:%d\n", op);
+ report_src(st);
+ script_pushnil(st);
+ st->state = END;
+ return;
+ }
+ script_pushint(st, i1);
}
@@ -2896,10 +2901,13 @@ void run_script_main(struct script_state *st)
}
break;
- case C_ADD:
- op_add(st);
+ case C_NEG:
+ case C_NOT:
+ case C_LNOT:
+ op_1(st ,c);
break;
+ case C_ADD:
case C_SUB:
case C_MUL:
case C_DIV:
@@ -2917,17 +2925,11 @@ void run_script_main(struct script_state *st)
case C_LOR:
case C_R_SHIFT:
case C_L_SHIFT:
- op_2(st,c);
- break;
-
- case C_NEG:
- case C_NOT:
- case C_LNOT:
- op_1num(st,c);
+ op_2(st, c);
break;
case C_OP3:
- op_3(st);
+ op_3(st, c);
break;
case C_NOP:
@@ -3888,7 +3890,7 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(goto,"l"),
BUILDIN_DEF(callsub,"i*"),
BUILDIN_DEF(callfunc,"s*"),
- BUILDIN_DEF(return,"*"),
+ BUILDIN_DEF(return,"?"),
BUILDIN_DEF(getarg,"i"),
BUILDIN_DEF(jobchange,"i*"),
BUILDIN_DEF(jobname,"i"),
@@ -4690,35 +4692,41 @@ BUILDIN_FUNC(getarg)
return 0;
}
-/*==========================================
- * サブルーチン/ユーザー定義関数の終了
- *------------------------------------------
- */
+/// Returns from the current function, optionaly returning a value from the functions.
+/// Don't use outside script functions.
+///
+/// return;
+/// return <value>;
BUILDIN_FUNC(return)
{
- if(script_hasdata(st,2)){ // 戻り値有り
- struct script_data *sd;
- push_copy(st->stack,st->start+2);
- sd = &st->stack->stack_data[st->stack->sp-1];
- if(data_isreference(sd)) {
- char *name = str_buf + str_data[sd->u.num&0x00ffffff].str;
- if( name[0] == '.' && name[1] == '@') {
- // '@ 変数を参照渡しにすると危険なので値渡しにする
- get_val(st,sd);
- //Fix dangling pointer crash due when returning a temporary
- // script variable (from Rayce/jA)
- if(isstr(sd)) {
- sd->type = C_STR;
- sd->u.str = (char *)aStrdup(sd->u.str);
+ if( script_hasdata(st,2) )
+ {// return value
+ struct script_data* data;
+ script_pushcopy(st, 2);
+ data = script_getdatatop(st, -1);
+ if( data_isreference(data) )
+ {
+ char* name = data_referencename(data);
+ if( name[0] == '.' && name[1] == '@' )
+ {// temporary script variable, convert to value
+ get_val(st, data);
+ if( data_isstring(data) )
+ {// duplicate the string
+ data->type = C_STR;
+ data->u.str = aStrdup(data->u.str);
}
- } else if( name[0] == '.' && !sd->ref) {
- // ' 変数は参照渡しでも良いが、参照元が設定されていないと
- // 元のスクリプトの値を差してしまうので補正する。
- sd->ref = &st->script->script_vars;
+ }
+ else if( name[0] == '.' && !data->ref )
+ {// script variable, link to current script
+ data->ref = &st->script->script_vars;
}
}
}
- st->state=RETFUNC;
+ else
+ {// no return value
+ script_pushnil(st);
+ }
+ st->state = RETFUNC;
return 0;
}
diff --git a/src/map/script.h b/src/map/script.h
index d6542700d..4152999d6 100644
--- a/src/map/script.h
+++ b/src/map/script.h
@@ -43,12 +43,14 @@ struct script_code {
struct linkdb_node* script_vars;
};
+struct script_stack {
+ int sp,sp_max,defsp;
+ struct script_data *stack_data;
+ struct linkdb_node **var_function; // 関数依存変数
+};
+
struct script_state {
- struct script_stack {
- int sp,sp_max,defsp;
- struct script_data *stack_data;
- struct linkdb_node **var_function; // 関数依存変数
- } *stack;
+ struct script_stack* stack;
int start,end;
int pos,state;
int rid,oid;