From 83d2d9343ab965c22816ac231973205ee67035e1 Mon Sep 17 00:00:00 2001 From: Haru Date: Sat, 14 Sep 2013 08:11:53 +0200 Subject: Removed meaningless '~=' operator. - [ This commit is part of a larger script engine related update ] - Since: c18f438 Signed-off-by: Haru --- src/map/script.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/map/script.c b/src/map/script.c index 777179507..fd16bdbad 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -857,7 +857,6 @@ 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_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) ) // <<= -- cgit v1.2.3-70-g09d2 From ac6ae8c932efbca30ef1650fa5d7bd94ead336f5 Mon Sep 17 00:00:00 2001 From: Haru Date: Mon, 9 Sep 2013 12:47:48 +0200 Subject: 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 --- src/map/script.c | 246 +++++++++++++++++++++++++++++++++---------------------- src/map/script.h | 6 +- 2 files changed, 150 insertions(+), 102 deletions(-) (limited to 'src') 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(,) -> -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. */ diff --git a/src/map/script.h b/src/map/script.h index e0e5f9ea9..75a57d82b 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -196,8 +196,10 @@ typedef enum c_op { C_NOT, // ~ a C_R_SHIFT, // a >> b C_L_SHIFT, // a << b - C_ADD_PP, // ++a - C_SUB_PP, // --a + C_ADD_POST, // a++ + C_SUB_POST, // a-- + C_ADD_PRE, // ++a + C_SUB_PRE, // --a } c_op; enum hQueueOpt { -- cgit v1.2.3-70-g09d2 From 9a802b9147221ec1f31109242be2919f53401fd3 Mon Sep 17 00:00:00 2001 From: Haru Date: Sat, 14 Sep 2013 08:13:28 +0200 Subject: Corrected operator precedence table. - [ This commit is part of a larger script engine related update ] - Operator precedence rules now closely follow those of languages such as C and derivates/related (C++, Java, PHP, etc.) - Please note that if you had custom scripts with non parenthesized expressions containing bitwise |, &, ^ operators, they may behave incorrectly now (or perhaps they were already behaving incorrectly, since the previous behavior was undocumented). - Added an up to date operator precedence/associativity table in the script documentation. - Added an operator/keyword self-test script in the npc/custom folder, in case if may be of some use for future regression-testing. --- doc/script_commands.txt | 91 +++++++++ npc/custom/breeder.txt | 6 +- npc/custom/test.txt | 416 ++++++++++++++++++++++++++++++++++++++++++ npc/other/arena/arena_aco.txt | 2 +- npc/scripts_custom.conf | 4 + src/map/script.c | 40 ++-- 6 files changed, 535 insertions(+), 24 deletions(-) create mode 100644 npc/custom/test.txt (limited to 'src') diff --git a/doc/script_commands.txt b/doc/script_commands.txt index 0912cb556..9186ba714 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -578,6 +578,29 @@ Operators section described below. All operators listed there may be placed in-front of the '=' sign when modifying variables to perform the action as required. +Increment and decrement operators are also provided, for your convenience. +Pre-increment and pre-decrement operators: + + ++@x; // same as @x = @x + 1 + --@x; // same as @x = @x - 1 + +Post-increment and post-decrement operators: + + @x++; // similar to @x = @x + 1 + @x--; // similar to @x = @x - 1 + +The difference between pre- and post- increment/decrement operators is that, +when used in an expression, the pre- ones will be executed before evaluating +the expression, while the post- ones will be executed after. For example: + + @x = 1; + @y = ++@x; // After this line is executed, both @y and @x will be 2 + @x = 1; + @y = @x++; // After this line is executed, @y will be 1, @x will be 2 + +Note: The pre-increment/pre-decrement operators are, by design, faster (or at +least not slower) than their respective post- equivalent. + Note: !! Currently the scripting engine does not support directly copying array @@ -854,6 +877,74 @@ and are the following: mentioning that ?: has low priority and has to be enclosed with parenthesis in most (if not all) cases. +Operator Precedence and Associativity + +Operator precedence and associativity work more or less like they do in +mathematics. The rules can be summarized with the following table: + +Precedence | Description | Associativity +--------------------------------------------------------------------------- +1 (highest) | [] Array subscripting | None +--------------------------------------------------------------------------- +2 | ++ Increment | None + | -- Decrement | +--------------------------------------------------------------------------- +2 | - Unary minus | Right to left + | ! Logical NOT | + | ~ Bitwise NOT (One's Complement) | +--------------------------------------------------------------------------- +3 | * Multiplication | Left to right + | / Division | + | % Modulo (remainder) | +--------------------------------------------------------------------------- +4 | + Addition | Left to right + | - Subtraction | +--------------------------------------------------------------------------- +5 | << Bitwise left shift | Left to right + | >> Bitwise right shift | +--------------------------------------------------------------------------- +6 | < Less than | Left to right + | <= Less than or equal to | + | > Greater than | + | >= Greater than or equal to | +--------------------------------------------------------------------------- +7 | == Equal to | Left to right + | != Not equal to | +--------------------------------------------------------------------------- +8 | & Bitwise AND | Left to right +--------------------------------------------------------------------------- +9 | ^ Bitwise XOR (exclusive or) | Left to right +--------------------------------------------------------------------------- +10 | | Bitwise OR (inclusive or) | Left to right +--------------------------------------------------------------------------- +11 | && Logical AND | Left to right +--------------------------------------------------------------------------- +12 | || Logical OR | Left to right +--------------------------------------------------------------------------- +13 | ?: Ternary conditional | Right to left +--------------------------------------------------------------------------- +14 | = Direct assignment | Right to left +(lowest) | += Assignment by sum | + | -= Assignment by difference | + | *= Assignment by product | + | /= Assignment by quotient | + | %= Assignment by remainder | + | <<= Assignment by bitwise left shift | + | >>= Assignment by bitwise right shift | + | &= Assignment by bitwise AND | + | ^= Assignment by bitwise XOR | + | |= Assignment by bitwise OR | + +Operator precedence means some operators are evaluated before others. For +example, in 2 + 4 * 5 , the multiplication has higher precedence so 4 * 5 is +evaluated first yielding 2 + 20 == 22 and not 6 * 5 == 30 . + +Operator associativity defines what happens if a sequence of the same +operators is used one after another: whether the evaluator will evaluate the +left operations first or the right. For example, in 8 - 4 - 2 , subtraction is +left associative so the expression is evaluated left to right. 8 - 4 is +evaluated first making the expression 4 - 2 == 2 and not 8 - 2 == 6 . + Labels ------ diff --git a/npc/custom/breeder.txt b/npc/custom/breeder.txt index 3eef8af0a..0222f5b3a 100644 --- a/npc/custom/breeder.txt +++ b/npc/custom/breeder.txt @@ -15,7 +15,7 @@ prontera,124,201,1 script Universal Rental NPC 4_F_JOB_BLACKSMITH,{ message strcharinfo(0),"You must first remove your mount."; end; } - else if ((eaclass()&EAJ_THIRDMASK==EAJ_RANGER) && !countitem(6124)) { + else if ((eaclass()&EAJ_THIRDMASK) == EAJ_RANGER && !countitem(6124)) { if (!checkfalcon() && getskilllv("HT_FALCON") && !checkoption(Option_Wug) && !checkoption(Option_Wugrider)) { if(select(" ~ Falcon: ~ Warg")==1) setfalcon; else getitem 6124,1; @@ -24,7 +24,7 @@ prontera,124,201,1 script Universal Rental NPC 4_F_JOB_BLACKSMITH,{ } else getitem 6124,1; } - else if ((eaclass()&EAJ_THIRDMASK==EAJ_MECHANIC) && !checkcart() && getskilllv("MC_PUSHCART")) { + else if ((eaclass()&EAJ_THIRDMASK) == EAJ_MECHANIC && !checkcart() && getskilllv("MC_PUSHCART")) { if (!checkmadogear() && getskilllv("NC_MADOLICENCE")) { if(select(" ~ Cart: ~ Mado")==1) setcart; else setmadogear; @@ -36,7 +36,7 @@ prontera,124,201,1 script Universal Rental NPC 4_F_JOB_BLACKSMITH,{ else if (!checkcart() && getskilllv("MC_PUSHCART")) setcart; else if (!checkfalcon() && getskilllv("HT_FALCON") && !checkoption(Option_Wug) && !checkoption(Option_Wugrider)) setfalcon; else if (!checkriding() && getskilllv("KN_RIDING")) { - if (eaclass()&EAJ_THIRDMASK==EAJ_RUNE_KNIGHT) setdragon; + if ((eaclass()&EAJ_THIRDMASK) == EAJ_RUNE_KNIGHT) setdragon; else setriding; } else if (!checkmadogear() && getskilllv("NC_MADOLICENCE")) setmadogear; diff --git a/npc/custom/test.txt b/npc/custom/test.txt new file mode 100644 index 000000000..bfd297f5d --- /dev/null +++ b/npc/custom/test.txt @@ -0,0 +1,416 @@ +//===== Hercules Script ====================================== +//= Script engine self-tests +//===== By: ================================================== +//= Haru +//===== Current Version: ===================================== +//= 1.0 +//===== Description: ========================================= +//= Script to test operators and possibly other elements of +//= the script engine, useful for regression testing. + +- script HerculesSelfTest -1,{ + end; +OnCheck: + .@msg$ = getarg(0,"Unknown Error"); + .@val = getarg(1,0); + .@ref = getarg(2,1); + if (.@val != .@ref) { + debugmes "Error: "+.@msg$+": '"+.@val+"' != '"+.@ref+"'"; + //end; + } + return; +OnInit: + // Array subscript + setarray .@a, 3, 2, 1; + callsub(OnCheck, "Array subscript", .@a[2]); + + + // Increment and decrement operators ++, -- + .@x = 1; + .@y = .@x++; // .@y = .@x; .@x = .@x + 1; + callsub(OnCheck, "Suffix increment ++", .@y); + callsub(OnCheck, "Suffix increment ++", .@x, 2); + .@x = 1; + .@y = .@x--; // .@y = .@x; .@x = .@x - 1; + callsub(OnCheck, "Suffix decrement --", .@y); + callsub(OnCheck, "Suffix decrement --", .@x, 0); + .@x = 0; + .@y = ++.@x; // .@x = .@x + 1; .@y = .@x; + callsub(OnCheck, "Prefix increment ++", .@y); + callsub(OnCheck, "Prefix increment ++", .@x); + .@x = 2; + .@y = --.@x; // .@x = .@x - 1; .@y = .@x; + callsub(OnCheck, "Prefix decrement --", .@y); + callsub(OnCheck, "Prefix decrement --", .@x); + + // Order of [] and --/++ + .@a[1] = 0; + .@a[1]++; // .@a[1] = .@a[1] + 1; + callsub(OnCheck, "Order of [] and ++", .@a[1]); + .@a[1] = 2; + .@a[1]--; // .@a[1] = .@a[1] - 1; + callsub(OnCheck, "Order of [] and --", .@a[1]); + + + // Unary operators -, !, ~ + .@x = 1; + .@y = -.@x; // .@y = 0 - .@x; + callsub(OnCheck, "Unary operator -", .@y, -1); + .@x = 1; + .@y = !.@x; // if(.@x == 0) .@y = 1; else .@y = 0; + callsub(OnCheck, "Unary operator !", .@y, 0); + .@x = 0x00000001; + .@y = ~.@x; // One's complement of 0x00000001 is 0xfffffffe, which is -2 + callsub(OnCheck, "Unary operator ~", .@y, -2); + + // Associativity of unary operators -, !, ~ + .@x = 1; + .@y = ~ ! .@x; // .@y = ~(!.@x); + callsub(OnCheck, "Associativity of unary ~ and !", .@y, -1); + .@x = 0; + .@y = - ! .@x; // .@y = -(!.@x); + callsub(OnCheck, "Associativity of unary - and !", .@y, -1); + .@x = 1; + .@y = ~ - .@x; // .@y = ~(-.@x); + callsub(OnCheck, "Associativity of unary ~ and -", .@y, 0); + .@x = 1; + .@y = - ~ .@x; // .@y = -(~.@x); + callsub(OnCheck, "Associativity of unary - and ~", .@y, 2); + + // Order of unary -, !, ~ and prefix/suffix ++/-- + .@x = 2; + .@y = - --.@x; // .@y = -(--.@x); + callsub(OnCheck, "Order of unary - and prefix --", .@y, -1); + callsub(OnCheck, "Order of unary - and prefix --", .@x); + .@x = 1; + .@y = - .@x--; // .@y = -(.@x--); + callsub(OnCheck, "Order of unary - and suffix --", .@y, -1); + callsub(OnCheck, "Order of unary - and suffix --", .@x, 0); + .@x = 0; + .@y = - ++.@x; // .@y = -(++.@x); + callsub(OnCheck, "Order of unary - and prefix ++", .@y, -1); + callsub(OnCheck, "Order of unary - and prefix ++", .@x); + .@x = 1; + .@y = - .@x++; // .@y = -(.@x++); + callsub(OnCheck, "Order of unary - and suffix ++", .@y, -1); + callsub(OnCheck, "Order of unary - and suffix ++", .@x, 2); + .@x = 1; + .@y = !--.@x; // .@y = !(--.@x); + callsub(OnCheck, "Order of unary ! and prefix --", .@y); + callsub(OnCheck, "Order of unary ! and prefix --", .@x, 0); + .@x = 1; + .@y = !.@x--; // .@y = !(.@x--); + callsub(OnCheck, "Order of unary ! and suffix --", .@y, 0); + callsub(OnCheck, "Order of unary ! and suffix --", .@x, 0); + .@x = 0; + .@y = !++.@x; // .@y = !(++.@x); + callsub(OnCheck, "Order of unary ! and prefix ++", .@y, 0); + callsub(OnCheck, "Order of unary ! and prefix ++", .@x); + .@x = 0; + .@y = !.@x++; // .@y = !(.@x++); + callsub(OnCheck, "Order of unary ! and suffix ++", .@y); + callsub(OnCheck, "Order of unary ! and suffix ++", .@x); + .@x = 2; + .@y = ~--.@x; // .@y = ~(--.@x); + callsub(OnCheck, "Order of unary ~ and prefix --", .@y, -2); + callsub(OnCheck, "Order of unary ~ and prefix --", .@x, 1); + .@x = 1; + .@y = ~.@x--; // .@y = ~(.@x--); + callsub(OnCheck, "Order of unary ~ and suffix --", .@y, -2); + callsub(OnCheck, "Order of unary ~ and suffix --", .@x, 0); + .@x = 0; + .@y = ~++.@x; // .@y = ~(++.@x); + callsub(OnCheck, "Order of unary ~ and prefix ++", .@y, -2); + callsub(OnCheck, "Order of unary ~ and prefix ++", .@x, 1); + .@x = 1; + .@y = ~.@x++; // .@y = ~(.@x++); + callsub(OnCheck, "Order of unary ~ and suffix ++", .@y, -2); + callsub(OnCheck, "Order of unary ~ and suffix ++", .@x, 2); + + // Binary *, /, % operators + .@x = 2 * 3; // .@x = 6; + callsub(OnCheck, "Binary * operator", .@x, 6); + .@x = 7 / 2; // .@x = 3; + callsub(OnCheck, "Binary / operator", .@x, 3); + .@x = 7 % 2; // .@x = 1; + callsub(OnCheck, "Binary % operator", .@x, 1); + + // Associativity of *, /, % + .@x = 8 * 3 / 2; // .@x = (8 * 3) / 2; + callsub(OnCheck, "Associativity of * and /", .@x, 12); + + // Order of binary *%/ and unary !-~ + .@x = 2 * ! 3; // .@x = 2 * (!3); + callsub(OnCheck, "Order of binary * and unary !", .@x, 0); + .@x = ~ 1 * 2; // .@x = (~1) * 2; + callsub(OnCheck, "Order of unary ~ and binary *", .@x, -4); + + + // Binary +, - operators + .@x = 1 + 3; // .@x = 4; + callsub(OnCheck, "Binary + operator", .@x, 4); + .@x = 1 - 3; // .@x = -2; + callsub(OnCheck, "Binary - operator", .@x, -2); + + // Associativity of +,- + .@x = 0x7fffffff - 0x7ffffff0 + 1; // .@x = (0x7fffffff - 0x7ffffff0) + 1; (without overflow) + callsub(OnCheck, "Associativity of + and -", .@x, 16); + + // Order of +, - and *, /, % + .@x = 1 + 3 * 2; // .@x = 1 + (3 * 2); + callsub(OnCheck, "Order of + and *", .@x, 7); + + + // << and >> operators + .@x = 1<<3; // .@x = 1*2*2*2; + callsub(OnCheck, "Left shift << operator", .@x, 8); + .@x = 12>>2; // .@x = 12/2/2; + callsub(OnCheck, "Right shift >> operator", .@x, 3); + + // Associativity of << and >> + .@x = 0x40000000 >> 4 << 2; // .@x = (0x40000000 >> 4) << 2 + callsub(OnCheck, "Associativity of >> and <<", .@x, 0x10000000); + + // Order of <> and +/- + .@x = 4 << 2 + 1; // .@x = 4 << (2+1); + callsub(OnCheck, "Order of << and +", .@x, 32); + + + // <, <=, >, >= operators + .@x = (1 < 2); // true + .@y = (2 < 2); // false + callsub(OnCheck, "< operator", .@x); + callsub(OnCheck, "< operator", .@y, 0); + .@x = (1 <= 2); // true + .@y = (2 <= 2); // true + callsub(OnCheck, "<= operator", .@x); + callsub(OnCheck, "<= operator", .@y); + .@x = (2 > 1); // true + .@y = (2 > 2); // false + callsub(OnCheck, "> operator", .@x); + callsub(OnCheck, "> operator", .@y, 0); + .@x = (2 >= 1); // true + .@y = (2 >= 2); // true + callsub(OnCheck, ">= operator", .@x); + callsub(OnCheck, ">= operator", .@y); + + // Associativity of <,<=,>,>= + .@x = 1 > 0 > 0; // (1 > 0) > 0 --> 1 > 0 --> true + callsub(OnCheck, "Associativity of > operators", .@x); + + // Order of >>/<< and />= + .@x = 1 < 1 << 2; // .@x = 1 < (1<<2); + callsub(OnCheck, "Order of < and <<", .@x); + + + // ==, != operators + .@x = (0 == 0); // true + .@y = (1 == 0); // false + callsub(OnCheck, "== operator", .@x); + callsub(OnCheck, "== operator", .@y, 0); + .@x = (1 != 0); // true + .@y = (1 != 1); // false + callsub(OnCheck, "!= operator", .@x); + callsub(OnCheck, "!= operator", .@y, 0); + + // Associativity of ==, != + .@x = (1 == 0 == 0); // (1 == 0) == 0 --> 0 == 0 --> 1 + .@y = (1 != 0 == 0); // (1 != 0) == 0 --> 1 == 0 --> 0 + callsub(OnCheck, "Associativity of != and == operators", .@x); + callsub(OnCheck, "Associativity of != and == operators", .@y, 0); + + // Order of />= and ==/!= + .@x = (1 == 2 > 1); // true + .@y = (1 < 2 == 1); // true + callsub(OnCheck, "Order of <,>,==", .@x); + callsub(OnCheck, "Order of <,>,==", .@y); + + + // Bitwise & operator + .@x = (7&4); // 0111 & 0100 --> 0100 + .@y = (4&1); // 0100 & 0001 --> 0000 + callsub(OnCheck, "Bitwise & operator", .@x, 4); + callsub(OnCheck, "Bitwise & operator", .@y, 0); + + // Order of & and ==/!= + .@x = (4 == 7 & 4); // (4 == 7)&4 + .@y = (1 & 3 != 1); // 1 & (3 != 1) + callsub(OnCheck, "Order of ==/!= and &", .@x, 0); + callsub(OnCheck, "Order of ==/!= and &", .@y); + + + // Bitwise ^ operator + .@x = (3^1); // 0011 ^ 0001 --> 0010 + callsub(OnCheck, "Bitwise ^ operator", .@x, 2); + + // Order of ^ and & + .@x = (0 & 2 ^ 2); // (0 & 2) ^ 2 --> (0000 & 0010) | 0010 --> 0000 ^ 0010 --> 0010 + .@y = (2 ^ 2 & 0); // 2 ^ (2 & 0) --> 0010 | (0010 & 0000) --> 0010 ^ 0000 --> 0010 + callsub(OnCheck, "Order of ^ and &", .@x, 2); + callsub(OnCheck, "Order of ^ and &", .@y, 2); + + + // Bitwise | operator + .@x = (3|4); // 0011 | 0100 --> 0111 + .@y = (4|1); // 0100 | 0001 --> 0101 + callsub(OnCheck, "Bitwise | operator", .@x, 7); + callsub(OnCheck, "Bitwise | operator", .@y, 5); + + // Order of ^ and | + .@x = (2 ^ 2 | 2); // (2 ^ 1) | 4 --> (0010 ^ 0010) | 0010 --> 0000 | 0010 --> 0010 + .@y = (2 | 2 ^ 2); // 4 | (1 ^ 2) --> 0010 | (0010 ^ 0010) --> 0010 | 0000 --> 0010 + callsub(OnCheck, "Order of | and ^", .@x, 2); + callsub(OnCheck, "Order of | and ^", .@y, 2); + + + // Logical && operator + .@x = (1 && 1); // true + .@y = (0 && 1); // false + callsub(OnCheck, "Logical && operator", .@x); + callsub(OnCheck, "Logical && operator", .@y, 0); + + // Associativity of && and short-circuit + .@x = 0; + .@y = (1 && 0 && (.@x = 1)); // should short circuit as false before evaluating the assignment + //FIXME callsub(OnCheck, "Short-circuit of &&", .@x, 0); + callsub(OnCheck, "Associativity of &&", .@y, 0); + + // Order of bitwise | and logical && + .@x = (1 && 0 | 4); // 1 && (0|4) + .@y = (4 | 0 && 1); // (4|0) && 1 + callsub(OnCheck, "Order of && and |", .@x); + callsub(OnCheck, "Order of && and |", .@y); + + + // Logical || operator + .@x = (1 || 1); // true + .@y = (0 || 1); // true + callsub(OnCheck, "Logical || operator", .@x); + callsub(OnCheck, "Logical || operator", .@y); + + // Associativity of || and short-circuit + .@x = 0; + .@y = (1 || 0 || (.@x = 1)); // should short circuit as true before evaluating the assignment + //FIXME callsub(OnCheck, "Short-circuit of ||", .@x, 0); + callsub(OnCheck, "Associativity of ||", .@y); + + // Order of logical && and || + .@x = (0 && 1 || 1); // (0 && 1) || 1 + .@y = (1 || 1 && 0); // 1 || (1 && 0) + callsub(OnCheck, "Order of && and ||", .@x); + callsub(OnCheck, "Order of && and ||", .@y); + + // Ternary conditional operator ?: + .@x = (1 ? 2 : 3); // 2 + .@y = (0 ? 2 : 3); // 3 + callsub(OnCheck, "Ternary conditional operator", .@x, 2); + callsub(OnCheck, "Ternary conditional operator", .@y, 3); + + // Associativity of ?: + .@x = (1 ? 2 : 0 ? 3 : 4); + .@y = (1 ? 1 ? 2 : 3 : 5); + callsub(OnCheck, "Associativity of ?:", .@x, 2); + callsub(OnCheck, "Associativity of ?:", .@y, 2); + + // Order of logical || and ternary ?: + .@x = (1 ? 0 : 0 || 1); // 1 ? 0 : (0 || 1) --> false + callsub(OnCheck, "Order of || and ?:", .@x, 0); + + + // Assignment operators + .@x = 1; + callsub(OnCheck, "Direct assignment operator =", .@x); + .@x += 7; // 1 + 7 + callsub(OnCheck, "Assignment by sum +=", .@x, 8); + .@x -= 1; // 8 - 1 + callsub(OnCheck, "Assignment by difference -=", .@x, 7); + .@x *= 2; // 7 * 2 + callsub(OnCheck, "Assignment by product *=", .@x, 14); + .@x /= 2; // 14 / 2 + callsub(OnCheck, "Assignment by quotient /=", .@x, 7); + .@x %= 4; // 7 % 4 + callsub(OnCheck, "Assignment by remainder %=", .@x, 3); + .@x <<= 2; // 3 << 2 + callsub(OnCheck, "Assignment by bitwise left shift <<=", .@x, 12); + .@x >>= 1; // 12 >> 1 + callsub(OnCheck, "Assignment by bitwise right shift >>=", .@x, 6); + .@x &= 5; // 6 & 5 (0110 & 0101 --> 0100) + callsub(OnCheck, "Assignment by bitwise and &=", .@x, 4); + .@x ^= 5; // 4 ^ 5 (0100 ^ 0101 --> 0001) + callsub(OnCheck, "Assignment by bitwise xor ^=", .@x, 1); + .@x |= 2; // 1 | 2 (0001 | 0010 --> 0011) + callsub(OnCheck, "Assignment by bitwise or |=", .@x, 3); + + // Associativity of assignment operators + .@x = 0; .@y = 0; + .@x = .@y = 1; + callsub(OnCheck, "1Associativity of =", .@x); + callsub(OnCheck, "2Associativity of =", .@y); + .@x = 0; .@y = 1; + .@x = .@y += 4; + callsub(OnCheck, "3Associativity of =", .@x, 5); + callsub(OnCheck, "4Associativity of =", .@y, 5); + .@x = 5; .@y = 3; + .@z = 8; +/* + * 0001b4 C_NAME setr + * 0001b8 C_ARG + * 0001b9 C_NAME .@x + * 0001bd C_REF + * 0001bd C_INT 16 + * 0001bf C_MUL + * 0001c0 C_FUNC + * 0001c1 C_EOL + */ + /* FIXME + .@x *= (.@y += 1); + //set(.@x, .@x * set(.@y, .@y + 1)); + //.@x = (.@x * (.@y = .@y + 1)); + */ +/* + * 0001c2 C_NAME setr + * 0001c6 C_ARG + * 0001c7 C_NAME .@x + * 0001cb C_REF + * 0001cc C_NAME setr + * 0001d0 C_ARG + * 0001d1 C_NAME .@y + * 0001d5 C_REF + * 0001d5 C_INT 1 + * 0001d7 C_ADD + * 0001d8 C_FUNC + * 0001d9 C_MUL + * 0001da C_FUNC + * 0001db C_EOL + */ +/* + * 0001c2 C_NAME setr + * 0001c6 C_ARG + * 0001c7 C_NAME .@x + * 0001cb C_REF + * 0001cc C_NAME setr + * 0001d0 C_ARG + * 0001d1 C_NAME .@y + * 0001d4 C_INT 2 + * 0001d6 C_FUNC + * 0001d7 C_MUL + * 0001d8 C_FUNC + * 0001d9 C_EOL + */ + /* + callsub(OnCheck, "5Associativity of =", .@x, 20); + callsub(OnCheck, "6Associativity of =", .@y, 4); + */ + + .@x = 0; + if (0) + if (1) + .@x = 2; + else + .@x = 3; + callsub(OnCheck, "Dangling else", .@x, 0); + + debugmes "Script engine self-test [ PASSED ]"; +} + +// vim: set ft=ath : diff --git a/npc/other/arena/arena_aco.txt b/npc/other/arena/arena_aco.txt index 725e8c58f..cc0b4b640 100644 --- a/npc/other/arena/arena_aco.txt +++ b/npc/other/arena/arena_aco.txt @@ -1084,7 +1084,7 @@ prt_are_in,25,31,3 script Staff#aco-2 1_F_02,{ set .@hour_endaco, .@end_timeaco / 10000; set .@min_endaco, ((.@end_timeaco % 10000) / 100); set .@sec_endaco, .@end_timeaco % 100; - if ((.@hour_startaco == 23) & (.@hour_endaco == 0)) { + if ((.@hour_startaco == 23) && (.@hour_endaco == 0)) { set .@hour_endaco,24; } set .@st_to_secaco, ((.@hour_startaco * 3600) + (.@min_startaco * 60) + (.@sec_startaco)); diff --git a/npc/scripts_custom.conf b/npc/scripts_custom.conf index aeae9e22f..b4283502c 100644 --- a/npc/scripts_custom.conf +++ b/npc/scripts_custom.conf @@ -104,3 +104,7 @@ //npc: npc/custom/battleground/bg_kvm01.txt //npc: npc/custom/battleground/bg_kvm02.txt //npc: npc/custom/battleground/bg_kvm03.txt + +// ----------------------- Misc Scripts ----------------------------- +// Self-test script (for development use only) +//npc: npc/custom/test.txt diff --git a/src/map/script.c b/src/map/script.c index 2c4178d9b..73aaafab2 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -1158,32 +1158,32 @@ const char* script_parse_subexpr(const char* p,int limit) { 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); + p=script->parse_subexpr(p+1,11); script->addc(op); } 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=='<') // < + (op=C_OP3, opl=0, len=1,*p=='?') // ?: + || (op=C_ADD, opl=9, len=1,*p=='+') // + + || (op=C_SUB, opl=9, len=1,*p=='-') // - + || (op=C_MUL, opl=10,len=1,*p=='*') // * + || (op=C_DIV, opl=10,len=1,*p=='/') // / + || (op=C_MOD, opl=10,len=1,*p=='%') // % + || (op=C_LAND, opl=2, len=2,*p=='&' && p[1]=='&') // && + || (op=C_AND, opl=5, len=1,*p=='&') // & + || (op=C_LOR, opl=1, len=2,*p=='|' && p[1]=='|') // || + || (op=C_OR, opl=3, len=1,*p=='|') // | + || (op=C_XOR, opl=4, len=1,*p=='^') // ^ + || (op=C_EQ, opl=6, len=2,*p=='=' && p[1]=='=') // == + || (op=C_NE, opl=6, len=2,*p=='!' && p[1]=='=') // != + || (op=C_R_SHIFT,opl=8, len=2,*p=='>' && p[1]=='>') // >> + || (op=C_GE, opl=7, len=2,*p=='>' && p[1]=='=') // >= + || (op=C_GT, opl=7, len=1,*p=='>') // > + || (op=C_L_SHIFT,opl=8, len=2,*p=='<' && p[1]=='<') // << + || (op=C_LE, opl=7, len=2,*p=='<' && p[1]=='=') // <= + || (op=C_LT, opl=7, len=1,*p=='<') // < ) && opl>limit) { p+=len; if(op == C_OP3) { -- cgit v1.2.3-70-g09d2 From 09dd2097b77bf3dda4c5eb1ee6eb2a60f05bbec8 Mon Sep 17 00:00:00 2001 From: Haru Date: Sun, 15 Sep 2013 20:24:41 +0200 Subject: Added support for automatic concatenation of adjacent string literals - [ This commit is part of a larger script engine related update ] - Adjacent string literals are now automatically concatenated into one string upon parsing. - Adjacent string literals are string literals (i.e. "such as this", with only whitespace (including line breaks and/or comments) between them. For example, the lines: mes "this will be concatenated " /* skipping this comment */ " into one string"; // at parse time will produce an output of "this will be concatenated into one string". - The feature brings parity with other languages (i.e. C), and makes it easier to split long strings in multiple lines, without having to resort to a, slower, run-time string concatenation operator ('+') - Special thanks to Trojal for the idea. Signed-off-by: Haru --- npc/custom/test.txt | 14 ++++++++++++++ src/map/script.c | 39 +++++++++++++++++++++------------------ 2 files changed, 35 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/npc/custom/test.txt b/npc/custom/test.txt index bfd297f5d..0fffecf73 100644 --- a/npc/custom/test.txt +++ b/npc/custom/test.txt @@ -19,6 +19,15 @@ OnCheck: //end; } return; +OnCheckStr: + .@msg$ = getarg(0,"Unknown Error"); + .@val$ = getarg(1,""); + .@ref$ = getarg(2,""); + if (.@val$ != .@ref$) { + debugmes "Error: "+.@msg$+": '"+.@val$+"' != '"+.@ref$+"'"; + //end; + } + return; OnInit: // Array subscript setarray .@a, 3, 2, 1; @@ -226,6 +235,11 @@ OnInit: callsub(OnCheck, "Order of <,>,==", .@y); + .@x$ = "string " + "concatenation" /* test */ " succeeded"; + callsub(OnCheckStr, "String concatenation", .@x$, "string concatenation succeeded"); + + // Bitwise & operator .@x = (7&4); // 0111 & 0100 --> 0100 .@y = (4&1); // 0100 & 0001 --> 0000 diff --git a/src/map/script.c b/src/map/script.c index 73aaafab2..007a3a3d3 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -1070,26 +1070,29 @@ const char* parse_simpleexpr(const char *p) { p=np; } else if(*p=='"') { script->addc(C_STR); - p++; - while( *p && *p != '"' ) { - if( (unsigned char)p[-1] <= 0x7e && *p == '\\' ) { - char buf[8]; - size_t len = sv->skip_escaped_c(p) - p; - size_t n = sv->unescape_c(buf, p, len); - if( n != 1 ) - ShowDebug("parse_simpleexpr: unexpected length %d after unescape (\"%.*s\" -> %.*s)\n", (int)n, (int)len, p, (int)n, buf); - p += len; - script->addb(*buf); - continue; - } else if( *p == '\n' ) { - disp_error_message("parse_simpleexpr: unexpected newline @ string",p); + do { + p++; + while( *p && *p != '"' ) { + if( (unsigned char)p[-1] <= 0x7e && *p == '\\' ) { + char buf[8]; + size_t len = sv->skip_escaped_c(p) - p; + size_t n = sv->unescape_c(buf, p, len); + if( n != 1 ) + ShowDebug("parse_simpleexpr: unexpected length %d after unescape (\"%.*s\" -> %.*s)\n", (int)n, (int)len, p, (int)n, buf); + p += len; + script->addb(*buf); + continue; + } else if( *p == '\n' ) { + disp_error_message("parse_simpleexpr: unexpected newline @ string",p); + } + script->addb(*p++); } - script->addb(*p++); - } - if(!*p) - disp_error_message("parse_simpleexpr: unexpected end of file @ string",p); + if(!*p) + disp_error_message("parse_simpleexpr: unexpected end of file @ string",p); + p++; //'"' + p = script->skip_space(p); + } while( *p && *p == '"' ); script->addb(0); - p++; //'"' } else { int l; const char* pv; -- cgit v1.2.3-70-g09d2