summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorepoque11 <epoque11@54d463be-8e91-2dee-dedb-b68131a5f0ec>2012-04-27 13:28:51 +0000
committerepoque11 <epoque11@54d463be-8e91-2dee-dedb-b68131a5f0ec>2012-04-27 13:28:51 +0000
commitc18f438dd8363b0abee5fdb42336f9e240699a97 (patch)
tree67af7777599ab1d965160934601936a965408e56
parent10fb201916b42c7502e6557a6fb0afb5a6ab059f (diff)
downloadhercules-c18f438dd8363b0abee5fdb42336f9e240699a97.tar.gz
hercules-c18f438dd8363b0abee5fdb42336f9e240699a97.tar.bz2
hercules-c18f438dd8363b0abee5fdb42336f9e240699a97.tar.xz
hercules-c18f438dd8363b0abee5fdb42336f9e240699a97.zip
- Added initial support for direct variable assignment (allows assigning values to variables without the use of 'set')
- Note: the set; function is still required to be defined in the source git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@15982 54d463be-8e91-2dee-dedb-b68131a5f0ec
-rw-r--r--src/map/script.c191
-rw-r--r--src/map/script.h4
2 files changed, 190 insertions, 5 deletions
diff --git a/src/map/script.c b/src/map/script.c
index 4ba2b4cbf..9db770405 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -1044,6 +1044,174 @@ static void parse_nextline(bool first, const char* p)
str_data[LABEL_NEXTLINE].label = -1;
}
+/// Parse a variable assignment using the direct equals operator
+/// @param p script position where the function should run from
+/// @return NULL if not a variable assignment, the new position otherwise
+const char* parse_variable(const char* p)
+{
+ int i, j, set, word;
+ c_op type = C_NOP;
+ const char *p2 = NULL;
+ const char *var = p;
+
+ // skip the variable where applicable
+ p = skip_word(p);
+ p = skip_space(p);
+
+ if( p == NULL )
+ {// end of the line or invalid buffer
+ return NULL;
+ }
+
+ if( *p == '[' )
+ {// array variable so process the array as appropriate
+ for( p2 = p, i = 0, j = 1; p; ++ i )
+ {
+ if( *p ++ == ']' && --(j) == 0 ) break;
+ if( *p == '[' ) ++ j;
+ }
+
+ if( !(p = skip_space(p)) )
+ {// end of line or invalid characters remaining
+ disp_error_message("Missing right expression or closing bracket for variable.", p);
+ }
+ }
+
+ if( type == C_NOP &&
+ !( ( p[0] == '=' && p[1] != '=' && (type = C_EQ) ) // =
+ || ( p[0] == '+' && p[1] == '=' && (type = C_ADD) ) // +=
+ || ( p[0] == '-' && p[1] == '=' && (type = C_SUB) ) // -=
+ || ( p[0] == '^' && p[1] == '=' && (type = C_XOR) ) // ^=
+ || ( p[0] == '|' && p[1] == '=' && (type = C_OR ) ) // |=
+ || ( p[0] == '&' && p[1] == '=' && (type = C_AND) ) // &=
+ || ( p[0] == '*' && p[1] == '=' && (type = C_MUL) ) // *=
+ || ( p[0] == '/' && p[1] == '=' && (type = C_DIV) ) // /=
+ || ( p[0] == '%' && p[1] == '=' && (type = C_MOD) ) // %=
+ || ( p[0] == '~' && p[1] == '=' && (type = C_NOT) ) // ~=
+ || ( p[0] == '+' && p[1] == '+' && (type = C_ADD_PP) ) // ++
+ || ( p[0] == '-' && p[1] == '+' && (type = C_SUB_PP) ) // --
+ || ( p[0] == '<' && p[1] == '<' && p[2] == '=' && (type = C_L_SHIFT) ) // <<=
+ || ( p[0] == '>' && p[1] == '>' && p[2] == '=' && (type = C_R_SHIFT) ) // >>=
+ ) )
+ {// failed to find a matching operator combination so invalid
+ return NULL;
+ }
+
+ switch( type )
+ {
+ case C_EQ:
+ {// incremental modifier
+ p = skip_space( &p[1] );
+ }
+ break;
+
+ case C_L_SHIFT:
+ case C_R_SHIFT:
+ {// left or right shift modifier
+ p = skip_space( &p[3] );
+ }
+ break;
+
+ default:
+ {// normal incremental command
+ p = skip_space( &p[2] );
+ }
+ }
+
+ if( p == NULL )
+ {// end of line or invalid buffer
+ return NULL;
+ }
+
+ // find the set function within the source
+ set = search_str("set");
+
+ if( str_data[set].type != C_FUNC )
+ {// invalid function (could not find or match)
+ disp_error_message("Failed to find the buildin predicate 'set'.", p);
+ }
+
+ // push the set function onto the stack
+ add_scriptl(set);
+ add_scriptc(C_ARG);
+
+ // always append parenthesis to avoid errors
+ syntax.curly[syntax.curly_count].type = TYPE_ARGLIST;
+ syntax.curly[syntax.curly_count].count = 0;
+ syntax.curly[syntax.curly_count].flag = ARGLIST_PAREN;
+
+ // increment the total curly count for the position in the script
+ ++ syntax.curly_count;
+
+ // parse the variable currently being modified
+ word = add_word(var);
+
+ if( str_data[word].type == C_FUNC || str_data[word].type == C_USERFUNC || str_data[word].type == C_USERFUNC_POS )
+ {// cannot assign a variable which exists as a function or label
+ disp_error_message("Cannot modify a variable which has the same name as a function or label.", p);
+ }
+
+ // support for the variable array system
+ for( i = 0; 2 > i; ++ i )
+ {
+ if( p2 )
+ {// process the variable index
+ const char* p3 = NULL;
+
+ // push the getelementofarray method into the stack
+ add_scriptl(search_str("getelementofarray"));
+ add_scriptc(C_ARG);
+ add_scriptl(word);
+
+ // process the sub-expression for this assignment
+ p3 = parse_subexpr(p2 + 1, 1);
+ p3 = skip_space(p3);
+
+ if( *p3 != ']' )
+ {// closing parenthesis is required for this script
+ disp_error_message("Missing closing ']' parenthesis for the variable assignment.", p3);
+ }
+
+ // push the closing function stack operator onto the stack
+ add_scriptc(C_FUNC);
+ p3 ++;
+ }
+ else
+ {// simply push the variable or value onto the stack
+ add_scriptl(word);
+ }
+
+ if( type == C_EQ )
+ {// end of the list so ignore
+ break;
+ }
+ }
+
+ if( type == C_ADD_PP || type == C_SUB_PP )
+ {// incremental operator for the method
+ add_scripti(1);
+ add_scriptc(type == C_ADD_PP ? C_ADD : C_SUB);
+ }
+ else
+ {// process the value as an expression
+ p = parse_subexpr(p, -1);
+
+ if( type != C_EQ )
+ {// push the type of modifier onto the stack
+ add_scriptc(type);
+ }
+ }
+
+ // decrement the curly count for the position within the script
+ -- syntax.curly_count;
+
+ // close the script by appending the function operator
+ add_scriptc(C_FUNC);
+
+ // push the buffer from the method
+ return p;
+}
+
/*==========================================
* 項の解析
*------------------------------------------*/
@@ -1101,6 +1269,8 @@ const char* parse_simpleexpr(const char *p)
p++; //'"'
} else {
int l;
+ const char* pv;
+
// label , register , function etc
if(skip_word(p)==p)
disp_error_message("parse_simpleexpr: unexpected character",p);
@@ -1117,6 +1287,11 @@ const char* parse_simpleexpr(const char *p)
}
#endif
+ if( (pv = parse_variable(p)) )
+ {// successfully processed a variable assignment
+ return pv;
+ }
+
p=skip_word(p);
if( *p == '[' ){
// array(name[i] => getelementofarray(name,i) )
@@ -1240,15 +1415,23 @@ const char* parse_line(const char* p)
} else if(p[0] == '}') {
return parse_curly_close(p);
}
-
+
// 構文関連の処理
p2 = parse_syntax(p);
if(p2 != NULL)
return p2;
+ // attempt to process a variable assignment
+ p2 = parse_variable(p);
+
+ if( p2 != NULL )
+ {// variable assignment processed so leave the method
+ return parse_syntax_close(p2 + 1);
+ }
+
p = parse_callfunc(p,0);
p = skip_space(p);
-
+
if(parse_syntax_for_flag) {
if( *p != ')' )
disp_error_message("parse_line: need ')'",p);
@@ -1570,7 +1753,7 @@ const char* parse_syntax(const char* p)
if(*p != ';')
disp_error_message("parse_syntax: need ';'",p);
p++;
-
+
// ループ開始に飛ばす
sprintf(label,"goto __FR%x_BGN;",syntax.curly[pos].index);
syntax.curly[syntax.curly_count++].type = TYPE_NULL;
@@ -1581,7 +1764,7 @@ const char* parse_syntax(const char* p)
sprintf(label,"__FR%x_NXT",syntax.curly[pos].index);
l=add_str(label);
set_label(l,script_pos,p);
-
+
// 次のループに入る時の処理
// for 最後の ')' を ';' として扱うフラグ
parse_syntax_for_flag = 1;
diff --git a/src/map/script.h b/src/map/script.h
index 4815a438d..9f8752aff 100644
--- a/src/map/script.h
+++ b/src/map/script.h
@@ -70,7 +70,9 @@ typedef enum c_op {
C_LNOT, // ! a
C_NOT, // ~ a
C_R_SHIFT, // a >> b
- C_L_SHIFT // a << b
+ C_L_SHIFT, // a << b
+ C_ADD_PP, // ++a
+ C_SUB_PP, // --a
} c_op;
struct script_retinfo {