From 1600b2069d640c1d199811d4c83814efb180cd5c Mon Sep 17 00:00:00 2001 From: skotlex Date: Fri, 19 Jan 2007 15:27:53 +0000 Subject: - Merged Rayce's cleanups of the script engine that account for duplicate labels, non-numeric labels and makes the engine case-insensitive towards keywords like if/case/switch/etc/ - Added the icons for the Food boosts (need packet version 8 to get them). git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@9673 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/map/script.c | 151 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 83 insertions(+), 68 deletions(-) (limited to 'src/map/script.c') diff --git a/src/map/script.c b/src/map/script.c index 401653fdc..c7368e6b3 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -140,6 +140,7 @@ static struct { int index; int count; int flag; + struct linkdb_node *case_label; } curly[256]; // 右カッコの情報 int curly_count; // 右カッコの数 int index; // スクリプト内で使用した構文の数 @@ -957,7 +958,7 @@ const char* parse_curly_close(const char* p) { sprintf(label,"__SW%x_FIN",syntax.curly[pos].index); l=add_str(label); set_label(l,script_pos, p); - + linkdb_final(&syntax.curly[pos].case_label); // free the list of case label syntax.curly_count--; return p+1; } else { @@ -970,9 +971,12 @@ const char* parse_curly_close(const char* p) { // break, case, continue, default, do, for, function, // if, switch, while をこの内部で処理します。 const char* parse_syntax(const char* p) { + const char *p2 = skip_word(p); + switch(*p) { + case 'B': case 'b': - if(!strncasecmp(p,"break",5) && !ISALPHA(p[5])) { + if(p2 - p == 5 && !strncasecmp(p,"break",5)) { // break の処理 char label[256]; int pos = syntax.curly_count - 1; @@ -999,7 +1003,10 @@ const char* parse_syntax(const char* p) { parse_line(label); syntax.curly_count--; } - p = skip_word(p); + p = skip_space(p2); + if(*p != ';') { + disp_error_message("parse_syntax: need ';'",p); + } p++; // if, for , while の閉じ判定 p = parse_syntax_close(p + 1); @@ -1007,17 +1014,17 @@ const char* parse_syntax(const char* p) { } break; case 'c': - if(!strncasecmp(p,"case",4) && !ISALPHA(p[4])) { + case 'C': + if(p2 - p == 4 && !strncasecmp(p,"case",4)) { // case の処理 - if(syntax.curly_count <= 0 || syntax.curly[syntax.curly_count - 1].type != TYPE_SWITCH) { + int pos = syntax.curly_count-1; + if(pos < 0 || syntax.curly[pos].type != TYPE_SWITCH) { disp_error_message("parse_syntax: unexpected 'case' ",p); return p+1; } else { - const char *p2; + char *np; char label[256]; - int l; - int len; - int pos = syntax.curly_count-1; + int l,v; if(syntax.curly[pos].count != 1) { // FALLTHRU 用のジャンプ sprintf(label,"goto __SW%x_%xJ;",syntax.curly[pos].index,syntax.curly[pos].count); @@ -1031,18 +1038,24 @@ const char* parse_syntax(const char* p) { set_label(l,script_pos, p); } // switch 判定文 + p = skip_space(p2); + if(p == p2) { + disp_error_message("parse_syntax: expect space ' '",p); + } + // check whether case label is integer or not + v = strtol(p,&np,0); + if(np == p) + disp_error_message("parse_syntax: 'case' label not integer",p); + if((*p == '-' || *p == '+') && isdigit(p[1])) // pre-skip because '-' can not skip_word + p++; p = skip_word(p); - p = skip_space(p); - p2 = p; - p = skip_word(p); - len = p-p2; // length of word at p2 + if(np != p) + disp_error_message("parse_syntax: 'case' label not integer",np); p = skip_space(p); if(*p != ':') disp_error_message("parse_syntax: expect ':'",p); - memcpy(label,"if(",3); - memcpy(label+3,p2,len); - sprintf(label+3+len," != $@__SW%x_VAL) goto __SW%x_%x;", - syntax.curly[pos].index,syntax.curly[pos].index,syntax.curly[pos].count+1); + sprintf(label,"if(%d != $@__SW%x_VAL) goto __SW%x_%x;", + v,syntax.curly[pos].index,syntax.curly[pos].index,syntax.curly[pos].count+1); syntax.curly[syntax.curly_count++].type = TYPE_NULL; // 2回parse しないとダメ p2 = parse_line(label); @@ -1054,15 +1067,21 @@ const char* parse_syntax(const char* p) { l=add_str(label); set_label(l,script_pos,p); } - // 一時変数を消す + + // check duplication of case label [Rayce] + if(linkdb_search(&syntax.curly[pos].case_label, (void*)v) != NULL) + disp_error_message("parse_syntax: dup 'case'",p); + linkdb_insert(&syntax.curly[pos].case_label, (void*)v, (void*)1); + sprintf(label,"set $@__SW%x_VAL,0;",syntax.curly[pos].index); syntax.curly[syntax.curly_count++].type = TYPE_NULL; + parse_line(label); syntax.curly_count--; syntax.curly[pos].count++; } return p + 1; - } else if(!strncasecmp(p,"continue",8) && !ISALPHA(p[8])) { + } else if(p2 - p == 8 && !strncasecmp(p,"continue",8)) { // continue の処理 char label[256]; int pos = syntax.curly_count - 1; @@ -1087,7 +1106,9 @@ const char* parse_syntax(const char* p) { parse_line(label); syntax.curly_count--; } - p = skip_word(p); + p = skip_space(p2); + if(*p != ';') + disp_error_message("parse_syntax: need ';'",p); p++; // if, for , while の閉じ判定 p = parse_syntax_close(p + 1); @@ -1095,25 +1116,22 @@ const char* parse_syntax(const char* p) { } break; case 'd': - if(!strncasecmp(p,"default",7) && !ISALPHA(p[7])) { + case 'D': + if(p2 - p == 7 && !strncasecmp(p,"default",7)) { // switch - default の処理 - if(syntax.curly_count <= 0 || syntax.curly[syntax.curly_count - 1].type != TYPE_SWITCH) { + int pos = syntax.curly_count-1; + if(pos < 0 || syntax.curly[pos].type != TYPE_SWITCH) { disp_error_message("parse_syntax: unexpected 'default'",p); - return p+1; - } else if(syntax.curly[syntax.curly_count - 1].flag) { + } else if(syntax.curly[pos].flag) { disp_error_message("parse_syntax: dup 'default'",p); - return p+1; } else { char label[256]; int l; - int pos = syntax.curly_count-1; // 現在地のラベルを付ける - p = skip_word(p); - p = skip_space(p); + p = skip_space(p2); if(*p != ':') { disp_error_message("parse_syntax: need ':'",p); } - p++; sprintf(label,"__SW%x_%x",syntax.curly[pos].index,syntax.curly[pos].count); l=add_str(label); set_label(l,script_pos,p); @@ -1131,15 +1149,12 @@ const char* parse_syntax(const char* p) { syntax.curly[syntax.curly_count - 1].flag = 1; syntax.curly[pos].count++; - - p = skip_word(p); - return p + 1; } - } else if(!strncasecmp(p,"do",2) && !ISALPHA(p[2])) { + return p + 1; + } else if(p2 - p == 2 && !strncasecmp(p,"do",2)) { int l; char label[256]; - p=skip_word(p); - p=skip_space(p); + p=skip_space(p2); syntax.curly[syntax.curly_count].type = TYPE_DO; syntax.curly[syntax.curly_count].count = 1; @@ -1154,7 +1169,8 @@ const char* parse_syntax(const char* p) { } break; case 'f': - if(!strncasecmp(p,"for",3) && !ISALPHA(p[3])) { + case 'F': + if(p2 - p == 3 && !strncasecmp(p,"for",3)) { int l; char label[256]; int pos = syntax.curly_count; @@ -1164,13 +1180,10 @@ const char* parse_syntax(const char* p) { syntax.curly[syntax.curly_count].flag = 0; syntax.curly_count++; - p=skip_word(p); - p=skip_space(p); + p=skip_space(p2); - if(*p != '(') { + if(*p != '(') disp_error_message("parse_syntax: need '('",p); - return p+1; - } p++; // 初期化文を実行する @@ -1197,10 +1210,8 @@ const char* parse_syntax(const char* p) { add_scriptl(add_str(label)); add_scriptc(C_FUNC); } - if(*p != ';') { + if(*p != ';') disp_error_message("parse_syntax: need ';'",p); - return p+1; - } p++; // ループ開始に飛ばす @@ -1233,11 +1244,12 @@ const char* parse_syntax(const char* p) { l=add_str(label); set_label(l,script_pos,p); return p; - } else if(!strncasecmp(p,"function",8) && !ISALPHA(p[8])) { + } else if(p2 - p == 8 && !strncasecmp(p,"function",8)) { const char *func_name; // function - p=skip_word(p); - p=skip_space(p); + p=skip_space(p2); + if(p == p2) + disp_error_message("parse_syntax: expect space ' '",p); // function - name func_name = p; p=skip_word(p); @@ -1276,11 +1288,11 @@ const char* parse_syntax(const char* p) { } break; case 'i': - if(!strncasecmp(p,"if",2) && !ISALPHA(p[2])) { + case 'I': + if(p2 - p == 2 && !strncasecmp(p,"if",2)) { // if() の処理 char label[256]; - p=skip_word(p); - p=skip_space(p); + p=skip_space(p2); if(*p != '(') { //Prevent if this {} non-c syntax. from Rayce (jA) disp_error_message("need '('",p); } @@ -1300,11 +1312,11 @@ const char* parse_syntax(const char* p) { } break; case 's': - if(!strncasecmp(p,"switch",6) && !ISALPHA(p[6])) { + case 'S': + if(p2 - p == 6 && !strncasecmp(p,"switch",6)) { // switch() の処理 char label[256]; - p=skip_word(p); - p=skip_space(p); + p=skip_space(p2); if(*p != '(') { disp_error_message("need '('",p); } @@ -1327,11 +1339,11 @@ const char* parse_syntax(const char* p) { } break; case 'w': - if(!strncasecmp(p,"while",5) && !ISALPHA(p[5])) { + case 'W': + if(p2 - p == 5 && !strncasecmp(p,"while",5)) { int l; char label[256]; - p=skip_word(p); - p=skip_space(p); + p=skip_space(p2); if(*p != '(') { disp_error_message("need '('",p); } @@ -1383,7 +1395,8 @@ const char* parse_syntax_close_sub(const char* p,int* flag) { *flag = 0; return p; } else if(syntax.curly[pos].type == TYPE_IF) { - const char *p2 = p; + const char *bp = p; + const char *p2; // if 最終場所へ飛ばす sprintf(label,"goto __IF%x_FIN;",syntax.curly[pos].index); syntax.curly[syntax.curly_count++].type = TYPE_NULL; @@ -1397,14 +1410,14 @@ const char* parse_syntax_close_sub(const char* p,int* flag) { syntax.curly[pos].count++; p = skip_space(p); - if(!syntax.curly[pos].flag && !strncasecmp(p,"else",4) && !ISALPHA(p[4])) { + p2 = skip_word(p); + if(!syntax.curly[pos].flag && p2 - p == 4 && !strncasecmp(p,"else",4)) { // else or else - if - p = skip_word(p); - p = skip_space(p); - if(!strncasecmp(p,"if",2) && !ISALPHA(p[2])) { + p = skip_space(p2); + p2 = skip_word(p); + if(p2 - p == 2 && !strncasecmp(p,"if",2)) { // else - if - p=skip_word(p); - p=skip_space(p); + p=skip_space(p2); if(*p != '(') { disp_error_message("need '('",p); } @@ -1434,7 +1447,7 @@ const char* parse_syntax_close_sub(const char* p,int* flag) { set_label(l,script_pos,p); if(syntax.curly[pos].flag == 1) { // このifに対するelseじゃないのでポインタの位置は同じ - return p2; + return bp; } return p; } else if(syntax.curly[pos].type == TYPE_DO) { @@ -1452,9 +1465,8 @@ const char* parse_syntax_close_sub(const char* p,int* flag) { // 条件が偽なら終了地点に飛ばす p = skip_space(p); p2 = skip_word(p); - if(p2 - p != 5 || strncasecmp("while",p,5)) { + if(p2 - p != 5 || strncasecmp(p,"while",5)) disp_error_message("parse_syntax: need 'while'",p); - } p = skip_space(p2); if(*p != '(') { @@ -1696,6 +1708,8 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o if( setjmp( error_jump ) != 0 ) { //Restore program state when script has problems. [from jA] + int i; + const int size = sizeof(syntax.curly)/sizeof(syntax.curly[0]); if( error_report ) script_error(src,file,line,error_msg,error_pos); aFree( error_msg ); @@ -1703,9 +1717,10 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o script_pos = 0; script_size = 0; script_buf = NULL; - for(i=LABEL_START;i