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;