Short: Patch for (: :) construct From: Righ@Finalfrontier <ron.koerner@gmx.de> Date: Thu, 25 Mar 1999 01:04:54 +0100 (MET) Type: Patch State: Done - implemented in 3.2.7-dev.122 Hi, hier ist ein Patch fuer den ldmud-32dev50 driver, um das (: ... :) Konstrukt zu unterstuetzen. Die Funktionsweise ist wiefolgt: (: statements; :) wird in #'__inline_function_filename_#### umgewandelt. Alle nicht-alphanumerischen Zeichen in 'filename' werden in '_' umgewandelt. #### ist eine laufende Nummer. Sie wird am Anfang jedes Files auf 0000 gesetzt. Nach der Benutzung von (: statements :) wird zu einem passenden Zeitpunkt (z.B. nach der Funktion in der das (:...:) Konstrukt vorkommt) die Funktion eingefuegt: varargs mixed __inline_function_filename_####(mixed $1,mixed $2,mixed $3, ...,mixed $9) { statements; } '$1' ist genau wie z.B. '_1' ein gueltiger Name fuer Variablen oder Funktionen und hat keine weitere spezielle Bedeutung. Man kann also NICHT mit $1 immer auf den ersten Parameter zugreifen. Da einfach der Text zwischen den (: :) zwischen die { } kopiert wird, kann man alles tun, was man von Funktionen gewohnt ist. Endet der Text zwischen den (: :) nicht mit ';' oder '}', dann wird er als Ausdruck angesehen, und (: expression :) wird umgewandelt in: varargs mixed __inline_function_filename_####(mixed $1,mixed $2,mixed $3, ...,mixed $9) { return expression; } Beispiele: x=({ (["name":"eins",..]), (["name":"test",...]), (["name":"zwo",...]), ... }) filter_array(x, (: $1["name"]!="test" :) ) filtert alle mappings aus x raus, die "name"=="test" haben. x=({1,6,8,34,-4,-7,3,7,-89}) map_array(x, (: if ($1>0) return 1; else if ($1<0) return -1; else return 0; :) ); gibt ({1,1,1,1,-1,-1,1,1,-1}) zurueck; map_array(x,(: $1+$2 :),7) addiert 7 zu jedem Element aus x. int nr; nr=0; z=map_array(x,(: $1+$2[$3++] :),y,&nr); Danach gilt z[i]==x[i]+y[i] fuer i=0..sizeof(x)-1 int sum; sum=0; map_array(x,(: $2+=$1; :),&sum); In sum steht die Summe aller Elemente aus x. Da das letzte Zeichen innerhalb der (: :) ein ';' ist, und kein 'return' vorkommt, wird immer 0 zurueckge- geben. diff -ur ldmud-dev/func_spec ldmud-dev-righ/func_spec --- ldmud-dev/func_spec Sat Mar 6 22:36:44 1999 +++ ldmud-dev-righ/func_spec Wed Mar 17 14:47:06 1999 @@ -51,6 +51,7 @@ /* These are the predefined functions that can be accessed from LPC. */ identifier + inline_fun return string number diff -ur ldmud-dev/lex.c ldmud-dev-righ/lex.c --- ldmud-dev/lex.c Sun Mar 7 20:18:05 1999 +++ ldmud-dev-righ/lex.c Wed Mar 17 15:09:05 1999 @@ -316,6 +316,19 @@ /*-------------------------------------------------------------------------*/ +struct inline_fun *first_inline_fun; + /* Linked list of saved function text for inline-functions */ + +int insert_inline_fun_now; + /* This is !=0, if we are at a suitable point to insert the saved functions + * now. This is at the end of a function or after a global variable decl. + */ + +int next_inline_fun; + /* Contains the running count for inline-functions */ + +/*-------------------------------------------------------------------------*/ + /* The stack to handle nested #if...#else...#endif constructs. */ @@ -1974,6 +1987,18 @@ #define TRY(c, t) if (*yyp == (c)) {yyp++; outp = yyp; return t;} + if (insert_inline_fun_now) + { + struct inline_fun* fun; + + insert_inline_fun_now = 0; + add_input(first_inline_fun->string); + fun=first_inline_fun->next; + xfree(first_inline_fun->string); + xfree(first_inline_fun); + first_inline_fun=fun; + } + yyp = outp; for(;;) { @@ -2265,11 +2290,141 @@ outp = yyp; return ':'; + /* --- Inline-Function --- */ + + case '(': + /* check (: but ignore (:: which can occur eg. in if (::remove()) + */ + if (*yyp==':' && yyp[1]!=':') + { + struct inline_fun* fun; + struct ident* p; + char name[256]; + int level; + char* start; + + /* allocate linked list cell */ + if (!first_inline_fun) + { + first_inline_fun + = fun + = (struct inline_fun*)xalloc(sizeof(struct inline_fun)); + } + else + { + fun=first_inline_fun; + while(fun->next) fun=fun->next; + fun->next + = (struct inline_fun*)xalloc(sizeof(struct inline_fun)); + fun = fun->next; + } + fun->next=0; + + /* create name for inline function */ + sprintf(name,"__inline_function_%s_%04x",current_file, + next_inline_fun); + /* convert all non-alnums to _. + * especially the / of the filename + */ + start=name; + while(*start) + { + if (!isalnum(*start)) *start='_'; + start++; + } + + next_inline_fun++; + + /* find end of (: ... :) */ + yyp++; + level=1; + start=yyp; + while(level) + { + if (yyp[0]=='(' && yyp[1]==':') level++,yyp++; + else if (yyp[0]==':' && yyp[1]==')') level--,yyp++; + else if (yyp[0]=='/') + { + c = *yyp++; + if (c == '*') { + outp=yyp; + skip_comment(); + yyp=outp; + if (lex_fatal) { + return -1; + } + continue; + } + if (c == '/') { + yyp = skip_pp_comment(yyp); + continue; + } + } + else if (yyp[0]=='\n') + { + store_line_number_info(); + nexpands=0; + current_line++; + total_lines++; + if (!*yyp) { + outp = yyp; + yyp = _myfilbuf(); + } + } + else if (yyp[0]=='\"') + { + yyp++; + while(*yyp!='\"') + { + if (*yyp=='\\') yyp++; + yyp++; + } + } + else if (!yyp[0]) + { + yyerror("end of file in (: ... :)"); + return -1; + } + yyp++; + } + outp=yyp; + + /* check if last char before :) is ';' or '}' */ + yyp-=3; + while(lexwhite(*yyp)) yyp--; + if (*yyp==';' || *yyp=='}') + { + /* (: ... :) contains statements */ + yyp++; + *yyp=0; + fun->string=(char*)xalloc(yyp-start+109+strlen(name)); + sprintf(fun->string, + "varargs mixed %smixed $1,mixed $2,mixed $3,\ +mixed $4,mixed $5,mixed $6,mixed $7,mixed $8,mixed $9){%s}", + name,start); + } + else + { + /* (: ... :) contains an expression */ + yyp++; + *yyp=0; + fun->string=(char*)xalloc(yyp-start+117+strlen(name)); + sprintf(fun->string, + "varargs mixed %s(mixed $1,mixed $2,mixed $3,\ +mixed $4,mixed $5,mixed $6,mixed $7,mixed $8,mixed $9){return %s;}", + name,start); + } + + /* return the ID of the name */ + yylval.ident=make_shared_identifier(name,I_TYPE_UNKNOWN); + return F_INLINE_FUN; + } + /* FALL THROUGH */ + /* --- Single-char Operators and Punctuation --- */ case ';': - case '(': case ')': case ',': case '{': @@ -3055,7 +3210,7 @@ case 'Y':case 'Z':case 'a':case 'b':case 'c':case 'd':case 'e':case 'f': case 'g':case 'h':case 'i':case 'j':case 'k':case 'l':case 'm':case 'n': case 'o':case 'p':case 'q':case 'r':case 's':case 't':case 'u':case 'v': - case 'w':case 'x':case 'y':case 'z':case '_': + case 'w':case 'x':case 'y':case 'z':case '_':case '$': { struct ident *p; char *wordstart = yyp-1; diff -ur ldmud-dev/lex.h ldmud-dev-righ/lex.h --- ldmud-dev/lex.h Thu Dec 10 03:37:36 1998 +++ ldmud-dev-righ/lex.h Wed Mar 17 15:16:21 1999 @@ -131,6 +131,17 @@ #define lookup_predef(p) (p->type == I_TYPE_GLOBAL ? p->u.global.efun : -1) +/* --- struct inline_fun: linked list of saved function texts --- + * + * The functions inlined by (: ... :) have their code saved for later parsing. + * This struct holds all unprocessed saved functions + */ + +struct inline_fun { + char *string; /* the function-text */ + struct inline_fun *next; /* list link */ +}; + /* --- Variables --- */ extern struct lpc_predef_s * lpc_predefs; @@ -143,6 +154,9 @@ extern /* TODO: BOOL */ int pragma_verbose_errors; extern char *last_lex_string; extern struct ident *all_efuns; +extern struct inline_fun* first_inline_fun; +extern int insert_inline_fun_now; +extern int next_inline_fun; /* Values of pragma_strict_types */ diff -ur ldmud-dev/prolang.y ldmud-dev-righ/prolang.y --- ldmud-dev/prolang.y Sun Mar 7 20:18:05 1999 +++ ldmud-dev-righ/prolang.y Wed Mar 17 15:25:36 1999 @@ -685,6 +685,9 @@ last_initializer_end = -3; variables_initialized = 0; %endif + first_inline_fun = 0; + insert_inline_fun_now = 0; + next_inline_fun = 0; } static int @@ -1369,6 +1372,7 @@ %type <numbers> condStart %type <ident> F_IDENTIFIER +%type <ident> F_INLINE_FUN %type <function_name> function_name %type <string> anchestor @@ -1385,6 +1389,7 @@ %endif %type <lrvalue> expr0 comma_expr +%type <lrvalue> inline_fun %type <lrvalue> note_start @@ -1600,12 +1605,64 @@ start + sizeof $3->name + 1, 0, $2); increment_string_ref($3->name); ins_f_byte(F_RETURN0); + if (first_inline_fun) insert_inline_fun_now=1; } free_all_local_names(); } - | type name_list ';' { if ($1 == 0) yyerror("Missing type"); } + | type name_list ';' + { + if ($1 == 0) yyerror("Missing type"); + if (first_inline_fun) insert_inline_fun_now=1; + } | inheritance ; +inline_fun: F_INLINE_FUN + { + struct ident *save_all_locals; + int save_current_number_of_locals; + int save_tol[10], save_ftol[10]; + char name[3]; + int num,i; + + save_all_locals = all_locals; + all_locals = 0; + save_current_number_of_locals = current_number_of_locals; + current_number_of_locals = 0; + + name[0]='$'; + name[2]=0; + + for(i=0;i<9;i++) + { + save_tol[i]=type_of_locals[i]; + save_ftol[i]=full_type_of_locals[i]; + name[1]=i+'1'; + add_local_name(make_shared_identifier(name,I_TYPE_UNKNOWN), + TYPE_ANY); + } + + num=define_new_function($1 /*id*/, 9, 0, 0, + NAME_UNDEFINED|NAME_PROTOTYPE, + TYPE_ANY|TYPE_MOD_VARARGS); + + free_all_local_names(); + + for(i=0;i<10;i++) + { + type_of_locals[i]=save_tol[i]; + full_type_of_locals[i]=save_ftol[i]; + } + + all_locals = save_all_locals; + current_number_of_locals = save_current_number_of_locals; + + $$.start = CURRENT_PROGRAM_SIZE; + $$.code = -1; + ins_f_byte(F_CLOSURE); + ins_short(num); + $$.type = TYPE_CLOSURE; + }; + new_arg_name: type optional_star F_IDENTIFIER { if (exact_types && $1 == 0) { @@ -3172,6 +3229,7 @@ expr4: function_call %prec '~' %// | F_STRING F_STRING %// { fatal("presence of rule should prevent its reduction"); } + | inline_fun | F_STRING { int string_number; @@ -5383,7 +5441,8 @@ CURRENT_PROGRAM_SIZE = current + 2; } -static void epilog() { +static void epilog() +{ int size, i; mp_int num_functions, num_strings, num_variables; char *p; @@ -5400,6 +5459,13 @@ if (last_string_constant) { free_string(last_string_constant); last_string_constant = 0; + } + while(first_inline_fun) + { + struct inline_fun* fun=first_inline_fun; + first_inline_fun=first_inline_fun->next; + xfree(fun->string); + xfree(fun); } while (case_blocks) { struct case_list_entry *tmp;