Explorar o código

* 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://svn.code.sf.net/p/rathena/svn/trunk@10379 54d463be-8e91-2dee-dedb-b68131a5f0ec

FlavioJS %!s(int64=18) %!d(string=hai) anos
pai
achega
c292b087b5
Modificáronse 3 ficheiros con 305 adicións e 284 borrados
  1. 11 0
      Changelog-Trunk.txt
  2. 287 279
      src/map/script.c
  3. 7 5
      src/map/script.h

+ 11 - 0
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

+ 287 - 279
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;
 }
 

+ 7 - 5
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;