diff options
author | Haru <haru@dotalux.com> | 2013-09-09 12:47:48 +0200 |
---|---|---|
committer | Haru <haru@dotalux.com> | 2013-11-28 01:30:13 +0100 |
commit | ac6ae8c932efbca30ef1650fa5d7bd94ead336f5 (patch) | |
tree | b69f10556ad98f894c7c5346f57670debfd8961e /src/map/script.c | |
parent | 83d2d9343ab965c22816ac231973205ee67035e1 (diff) | |
download | hercules-ac6ae8c932efbca30ef1650fa5d7bd94ead336f5.tar.gz hercules-ac6ae8c932efbca30ef1650fa5d7bd94ead336f5.tar.bz2 hercules-ac6ae8c932efbca30ef1650fa5d7bd94ead336f5.tar.xz hercules-ac6ae8c932efbca30ef1650fa5d7bd94ead336f5.zip |
Added pre de/increment operators. Fixed post de/increment operators.
- [ This commit is part of a larger script engine related update ]
- Suffix ++ and -- operators now behave like in other languages
(updating the variable *after* its value is returned.)
- Prefix ++ and -- operators are added for parity with other
scripting/programming languages. They update the variable they're
applied to *before* returning its value.
- Please note that the implementation of the prefix form of those
operators (like it happens in most languages) is more efficient than
the suffix form. '++.@i' is (slightly) faster than '.@i++', or at
least not slower.
- Fixed some outdated script debug functions.
- Follow-up to c18f438.
Signed-off-by: Haru <haru@dotalux.com>
Diffstat (limited to 'src/map/script.c')
-rw-r--r-- | src/map/script.c | 246 |
1 files changed, 146 insertions, 100 deletions
diff --git a/src/map/script.c b/src/map/script.c index fd16bdbad..2c4178d9b 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -66,11 +66,9 @@ static inline void SETVALUE(unsigned char* buf, int i, int n) { struct script_interface script_s; -const char* script_op2name(int op) -{ +const char* script_op2name(int op) { #define RETURN_OP_NAME(type) case type: return #type - switch( op ) - { + switch( op ) { RETURN_OP_NAME(C_NOP); RETURN_OP_NAME(C_POS); RETURN_OP_NAME(C_INT); @@ -85,6 +83,8 @@ const char* script_op2name(int op) RETURN_OP_NAME(C_USERFUNC); RETURN_OP_NAME(C_USERFUNC_POS); + RETURN_OP_NAME(C_REF); + // operators RETURN_OP_NAME(C_OP3); RETURN_OP_NAME(C_LOR); @@ -108,6 +108,10 @@ const char* script_op2name(int op) RETURN_OP_NAME(C_NOT); RETURN_OP_NAME(C_R_SHIFT); RETURN_OP_NAME(C_L_SHIFT); + RETURN_OP_NAME(C_ADD_POST); + RETURN_OP_NAME(C_SUB_POST); + RETURN_OP_NAME(C_ADD_PRE); + RETURN_OP_NAME(C_SUB_PRE); default: ShowDebug("script_op2name: unexpected op=%d\n", op); @@ -819,6 +823,38 @@ void parse_nextline(bool first, const char* p) script->str_data[LABEL_NEXTLINE].label = -1; } +/** + * Pushes a variable into stack, processing its array index if needed. + * @see parse_variable + */ +void parse_variable_sub_push(int word, const char *p2) { + const char* p3 = NULL; + + if( p2 ) { + // process the variable index + + // push the getelementofarray method into the stack + script->addl(script->buildin_getelementofarray_ref); + script->addc(C_ARG); + script->addl(word); + + // process the sub-expression for this assignment + p3 = script->parse_subexpr(p2 + 1, 1); + p3 = script->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 + script->addc(C_FUNC); + p3++; + } else { + // No array index, simply push the variable or value onto the stack + script->addl(word); + } +} + /// 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 @@ -828,21 +864,30 @@ const char* parse_variable(const char* p) { const char *p2 = NULL; const char *var = p; + if( ( p[0] == '+' && p[1] == '+' && (type = C_ADD_PRE) ) // pre ++ + || ( p[1] == '-' && p[1] == '-' && (type = C_SUB_PRE) ) // pre -- + ) { + var = p = script->skip_space(&p[2]); + } + // skip the variable where applicable p = script->skip_word(p); p = script->skip_space(p); - if( p == NULL ) {// end of the line or invalid buffer + if( p == NULL ) { + // end of the line or invalid buffer return NULL; } - if( *p == '[' ) {// array variable so process the array as appropriate + 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 = script->skip_space(p)) ) {// end of line or invalid characters remaining + if( !(p = script->skip_space(p)) ) { + // end of line or invalid characters remaining disp_error_message("Missing right expression or closing bracket for variable.", p); } } @@ -857,8 +902,8 @@ const char* parse_variable(const char* p) { || ( 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_ADD_PP) ) // ++ - || ( p[0] == '-' && p[1] == '-' && (type = C_SUB_PP) ) // -- + || ( p[0] == '+' && p[1] == '+' && (type = C_ADD_POST) ) // post ++ + || ( p[0] == '-' && p[1] == '-' && (type = C_SUB_POST) ) // post -- || ( p[0] == '<' && p[1] == '<' && p[2] == '=' && (type = C_L_SHIFT) ) // <<= || ( p[0] == '>' && p[1] == '>' && p[2] == '=' && (type = C_R_SHIFT) ) // >>= ) ) @@ -867,23 +912,26 @@ const char* parse_variable(const char* p) { } switch( type ) { - case C_EQ: {// incremental modifier + case C_ADD_PRE: // pre ++ + case C_SUB_PRE: // pre -- + // (nothing more to skip) + break; + + case C_EQ: // = p = script->skip_space( &p[1] ); - } - break; + break; - case C_L_SHIFT: - case C_R_SHIFT: {// left or right shift modifier + case C_L_SHIFT: // <<= + case C_R_SHIFT: // >>= p = script->skip_space( &p[3] ); - } - break; + break; - default: {// normal incremental command + default: // everything else p = script->skip_space( &p[2] ); - } } - if( p == NULL ) {// end of line or invalid buffer + if( p == NULL ) { + // end of line or invalid buffer return NULL; } @@ -897,56 +945,44 @@ const char* parse_variable(const char* p) { script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_PAREN; // increment the total curly count for the position in the script - ++ script->syntax.curly_count; + ++script->syntax.curly_count; // parse the variable currently being modified word = script->add_word(var); - if( script->str_data[word].type == C_FUNC || script->str_data[word].type == C_USERFUNC || script->str_data[word].type == C_USERFUNC_POS ) - {// cannot assign a variable which exists as a function or label + if( script->str_data[word].type == C_FUNC + || script->str_data[word].type == C_USERFUNC + || script->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); } - if( p2 ) {// process the variable index - const char* p3 = NULL; - - // push the getelementofarray method into the stack - script->addl(script->buildin_getelementofarray_ref); - script->addc(C_ARG); - script->addl(word); - - // process the sub-expression for this assignment - p3 = script->parse_subexpr(p2 + 1, 1); - p3 = script->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 - script->addc(C_FUNC); - p3 ++; - } else {// simply push the variable or value onto the stack - script->addl(word); - } + parse_variable_sub_push(word, p2); // Push variable onto the stack if( type != C_EQ ) script->addc(C_REF); - if( type == C_ADD_PP || type == C_SUB_PP ) {// incremental operator for the method + if( type == C_ADD_POST || type == C_SUB_POST ) { // post ++ / -- + script->addi(1); + script->addc(type == C_ADD_POST ? C_ADD : C_SUB); + + parse_variable_sub_push(word, p2); // Push variable onto the stack (third argument of setr) + } else if( type == C_ADD_PRE || type == C_SUB_PRE ) { // pre ++ / -- script->addi(1); - script->addc(type == C_ADD_PP ? C_ADD : C_SUB); - } else {// process the value as an expression + script->addc(type == C_ADD_PRE ? C_ADD : C_SUB); + } else { + // process the value as an expression p = script->parse_subexpr(p, -1); - if( type != C_EQ ) - {// push the type of modifier onto the stack + if( type != C_EQ ) { + // push the type of modifier onto the stack script->addc(type); } } // decrement the curly count for the position within the script - -- script->syntax.curly_count; + --script->syntax.curly_count; // close the script by appending the function operator script->addc(C_FUNC); @@ -1104,48 +1140,51 @@ const char* parse_simpleexpr(const char *p) { /*========================================== * Analysis of the expression *------------------------------------------*/ -const char* script_parse_subexpr(const char* p,int limit) -{ +const char* script_parse_subexpr(const char* p,int limit) { int op,opl,len; const char* tmpp; p=script->skip_space(p); - if( *p == '-' ){ + if( *p == '-' ) { tmpp = script->skip_space(p+1); - if( *tmpp == ';' || *tmpp == ',' ){ + if( *tmpp == ';' || *tmpp == ',' ) { script->addl(LABEL_NEXTLINE); p++; return p; } } - if((op=C_NEG,*p=='-') || (op=C_LNOT,*p=='!') || (op=C_NOT,*p=='~')){ + if( (op=C_ADD_PRE,p[0]=='+'&&p[1]=='+') || (op=C_SUB_PRE,p[0]=='-'&&p[1]=='-') ) { // Pre ++ -- operators + p=script->parse_variable(p); + } else if( (op=C_NEG,*p=='-') || (op=C_LNOT,*p=='!') || (op=C_NOT,*p=='~') ) { // Unary - ! ~ operators p=script->parse_subexpr(p+1,10); script->addc(op); - } else + } else { p=script->parse_simpleexpr(p); + } p=script->skip_space(p); while(( - (op=C_OP3,opl=0,len=1,*p=='?') || - (op=C_ADD,opl=8,len=1,*p=='+') || - (op=C_SUB,opl=8,len=1,*p=='-') || - (op=C_MUL,opl=9,len=1,*p=='*') || - (op=C_DIV,opl=9,len=1,*p=='/') || - (op=C_MOD,opl=9,len=1,*p=='%') || - (op=C_LAND,opl=2,len=2,*p=='&' && p[1]=='&') || - (op=C_AND,opl=6,len=1,*p=='&') || - (op=C_LOR,opl=1,len=2,*p=='|' && p[1]=='|') || - (op=C_OR,opl=5,len=1,*p=='|') || - (op=C_XOR,opl=4,len=1,*p=='^') || - (op=C_EQ,opl=3,len=2,*p=='=' && p[1]=='=') || - (op=C_NE,opl=3,len=2,*p=='!' && p[1]=='=') || - (op=C_R_SHIFT,opl=7,len=2,*p=='>' && p[1]=='>') || - (op=C_GE,opl=3,len=2,*p=='>' && p[1]=='=') || - (op=C_GT,opl=3,len=1,*p=='>') || - (op=C_L_SHIFT,opl=7,len=2,*p=='<' && p[1]=='<') || - (op=C_LE,opl=3,len=2,*p=='<' && p[1]=='=') || - (op=C_LT,opl=3,len=1,*p=='<')) && opl>limit){ + (op=C_OP3, opl=0,len=1,*p=='?') // ?: + || (op=C_ADD, opl=8,len=1,*p=='+') // + + || (op=C_SUB, opl=8,len=1,*p=='-') // - + || (op=C_MUL, opl=9,len=1,*p=='*') // * + || (op=C_DIV, opl=9,len=1,*p=='/') // / + || (op=C_MOD, opl=9,len=1,*p=='%') // % + || (op=C_LAND, opl=2,len=2,*p=='&' && p[1]=='&') // && + || (op=C_AND, opl=6,len=1,*p=='&') // & + || (op=C_LOR, opl=1,len=2,*p=='|' && p[1]=='|') // || + || (op=C_OR, opl=5,len=1,*p=='|') // | + || (op=C_XOR, opl=4,len=1,*p=='^') // ^ + || (op=C_EQ, opl=3,len=2,*p=='=' && p[1]=='=') // == + || (op=C_NE, opl=3,len=2,*p=='!' && p[1]=='=') // != + || (op=C_R_SHIFT,opl=7,len=2,*p=='>' && p[1]=='>') // >> + || (op=C_GE, opl=3,len=2,*p=='>' && p[1]=='=') // >= + || (op=C_GT, opl=3,len=1,*p=='>') // > + || (op=C_L_SHIFT,opl=7,len=2,*p=='<' && p[1]=='<') // << + || (op=C_LE, opl=3,len=2,*p=='<' && p[1]=='=') // <= + || (op=C_LT, opl=3,len=1,*p=='<') // < + ) && opl>limit) { p+=len; if(op == C_OP3) { p=script->parse_subexpr(p,-1); @@ -2329,7 +2368,7 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o i += 3; break; case C_STR: - j = strlen(script->buf + i); + j = strlen((char*)script->buf + i); ShowMessage(" %s", script->buf + i); i += j+1; break; @@ -5120,8 +5159,7 @@ BUILDIN(copyarray); /// The value is converted to the type of the variable. /// /// set(<variable>,<value>) -> <variable> -BUILDIN(set) -{ +BUILDIN(setr) { TBL_PC* sd = NULL; struct script_data* data; //struct script_data* datavalue; @@ -5131,8 +5169,7 @@ BUILDIN(set) data = script_getdata(st,2); //datavalue = script_getdata(st,3); - if( !data_isreference(data) ) - { + if( !data_isreference(data) ) { ShowError("script:set: not a variable\n"); script->reportdata(script_getdata(st,2)); st->state = END; @@ -5143,31 +5180,30 @@ BUILDIN(set) name = reference_getname(data); prefix = *name; - if( not_server_variable(prefix) ) - { + if( not_server_variable(prefix) ) { sd = script->rid2sd(st); - if( sd == NULL ) - { + if( sd == NULL ) { ShowError("script:set: no player attached for player variable '%s'\n", name); return true; } } #if 0 - if( data_isreference(datavalue) ) - {// the value being referenced is a variable + // TODO: see de43fa0f73be01080bd11c08adbfb7c158324c81 + if( data_isreference(datavalue) ) { + // the value being referenced is a variable const char* namevalue = reference_getname(datavalue); - if( !not_array_variable(*namevalue) ) - {// array variable being copied into another array variable - if( sd == NULL && not_server_variable(*namevalue) && !(sd = script->rid2sd(st)) ) - {// player must be attached in order to copy a player variable + if( !not_array_variable(*namevalue) ) { + // array variable being copied into another array variable + if( sd == NULL && not_server_variable(*namevalue) && !(sd = script->rid2sd(st)) ) { + // player must be attached in order to copy a player variable ShowError("script:set: no player attached for player variable '%s'\n", namevalue); return true; } - if( is_string_variable(namevalue) != is_string_variable(name) ) - {// non-matching array value types + if( is_string_variable(namevalue) != is_string_variable(name) ) { + // non-matching array value types ShowWarning("script:set: two array variables do not match in type.\n"); return true; } @@ -5181,14 +5217,23 @@ BUILDIN(set) } #endif + if( script_hasdata(st, 4) ) { + // Optional argument used by post-increment/post-decrement constructs to return the previous value + if( is_string_variable(name) ) { + script_pushstrcopy(st, script_getstr(st, 4)); + } else { + script_pushint(st, script_getnum(st, 4)); + } + } else { + // return a copy of the variable reference + script_pushcopy(st,2); + } + if( is_string_variable(name) ) script->set_reg(st,sd,num,name,(void*)script_getstr(st,3),script_getref(st,2)); else script->set_reg(st,sd,num,name,(void*)__64BPTRSIZE(script_getnum(st,3)),script_getref(st,2)); - // return a copy of the variable reference - script_pushcopy(st,2); - return true; } @@ -17993,7 +18038,8 @@ void script_parse_builtin(void) { BUILDIN_DEF(warpguild,"siii"), // [Fredzilla] BUILDIN_DEF(setlook,"ii"), BUILDIN_DEF(changelook,"ii"), // Simulates but don't Store it - BUILDIN_DEF(set,"rv"), + BUILDIN_DEF2(setr,"set","rv"), + BUILDIN_DEF(setr,"rv?"), // Not meant to be used directly, required for var++/var-- BUILDIN_DEF(setarray,"rv*"), BUILDIN_DEF(cleararray,"rvi"), BUILDIN_DEF(copyarray,"rri"), @@ -18486,10 +18532,10 @@ void script_parse_builtin(void) { int slen = strlen(BUILDIN[i].arg), offset = start + i; n = script->add_str(BUILDIN[i].name); - if (!strcmp(BUILDIN[i].name, "set")) script->buildin_set_ref = n; - else if (!strcmp(BUILDIN[i].name, "callsub")) script->buildin_callsub_ref = n; - else if (!strcmp(BUILDIN[i].name, "callfunc")) script->buildin_callfunc_ref = n; - else if (!strcmp(BUILDIN[i].name, "getelementofarray") ) script->buildin_getelementofarray_ref = n; + if (!strcmp(BUILDIN[i].name, "setr")) script->buildin_set_ref = n; + else if (!strcmp(BUILDIN[i].name, "callsub")) script->buildin_callsub_ref = n; + else if (!strcmp(BUILDIN[i].name, "callfunc")) script->buildin_callfunc_ref = n; + else if (!strcmp(BUILDIN[i].name, "getelementofarray") ) script->buildin_getelementofarray_ref = n; if( script->str_data[n].func && script->str_data[n].func != BUILDIN[i].func ) continue;/* something replaced it, skip. */ |