%{ #include <stdio.h> #include <ctype.h> #include <string.h> #include <fcntl.h> #ifdef __386BSD__ #include <stdlib.h> #endif #include "config.h" #include "mudlib_stats.h" #include "interpret.h" #include "mapping.h" #define _YACC_ #include "lint.h" #ifndef BUFSIZ #define BUFSIZ 1024 #endif #define NELEMS(arr) (sizeof arr / sizeof arr[0]) #define FUNC_SPEC "func_spec.cpp" #define MAX_FUNC 2048 /* If we need more than this we're in trouble! */ int num_buff; int op_code, efun_code; /* For quick sort purposes : */ char *key[MAX_FUNC], *buf[MAX_FUNC], has_token[MAX_FUNC]; char *oper_codes[MAX_FUNC], *efun_codes[MAX_FUNC]; #define EFUN_TABLE "efunctions.h" #define EFUN_PROTO "efun_protos.h" #define OPC_PROF "opc.h" #define OPCODES "opcodes.h" int min_arg = -1, limit_max = 0; /* * arg_types is the types of all arguments. A 0 is used as a delimiter, * marking next argument. An argument can have several types. */ int arg_types[200], last_current_type; /* * Store the types of the current efun. They will be copied into the * arg_types list if they were not already there (to save memory). */ int curr_arg_types[MAX_LOCAL], curr_arg_type_size; void yyerror PROT((char *)); int yylex(); int yyparse(); int ungetc PROT((int c, FILE *f)); char *type_str PROT((int)), *etype PROT((int)), *etype1 PROT((int)), *ctype PROT((int)); #ifndef toupper int toupper PROT((int)); #endif #define VOID 1 #define INT 2 #define STRING 3 #define OBJECT 4 #define MAPPING 5 #define MIXED 6 #define UNKNOWN 7 #define FLOAT 8 #define FUNCTION 9 struct type { char *name; int num; } types[] = { { "void", VOID }, { "int", INT }, { "string", STRING }, { "object", OBJECT }, { "mapping", MAPPING }, { "mixed", MIXED }, { "unknown", UNKNOWN }, { "float", FLOAT}, { "function", FUNCTION} }; void fatal(str) char *str; { fprintf(stderr, "%s", str); exit(1); } %} %union { int number; char *string; } %token ID DEFAULT OPERATOR %type <number> type arg_list basic typel arg_type typel2 %type <string> ID optional_ID optional_default %% specs: /* empty */ | specs spec ; spec: operator | func ; operator: OPERATOR op_list ';' ; op_list: op | op_list ',' op ; op: ID { char f_name[500]; int len, i; sprintf(f_name, "F_%s", $1); len = strlen(f_name); for (i=0; i < len; i++) { if (islower(f_name[i])) f_name[i] = toupper(f_name[i]); } oper_codes[op_code] = (char *) malloc(len + 1); strcpy(oper_codes[op_code], f_name); op_code++; } ; optional_ID: ID | /* empty */ { $$ = ""; } ; optional_default: DEFAULT ':' ID { $$ = $3; } | /* empty */ { $$="0"; } ; func: type ID optional_ID '(' arg_list optional_default ')' ';' { char buff[500]; char f_name[500]; int i, len; if (min_arg == -1) min_arg = $5; if ($3[0] == '\0') { if (strlen($2) + 1 + 2 > sizeof f_name) fatal("A local buffer was too small!(1)\n"); sprintf(f_name, "F_%s", $2); len = strlen(f_name); for (i=0; i < len; i++) { if (islower(f_name[i])) f_name[i] = toupper(f_name[i]); } has_token[num_buff]=1; efun_codes[efun_code] = (char *) malloc(len + 1); strcpy(efun_codes[efun_code], f_name); efun_code++; } else { if (strlen($3) + 1 > sizeof f_name) fatal("A local buffer was too small(2)!\n"); sprintf(f_name, "F_%s", $3); len = strlen(f_name); for (i=0; i < len; i++) { if (islower(f_name[i])) f_name[i] = toupper(f_name[i]); } has_token[num_buff]=0; } for(i=0; i < last_current_type; i++) { int j; for (j = 0; j+i<last_current_type && j < curr_arg_type_size; j++) { if (curr_arg_types[j] != arg_types[i+j]) break; } if (j == curr_arg_type_size) break; } if (i == last_current_type) { int j; for (j=0; j < curr_arg_type_size; j++) { arg_types[last_current_type++] = curr_arg_types[j]; if (last_current_type == NELEMS(arg_types)) yyerror("Array 'arg_types' is too small"); } } sprintf(buff, "{\"%s\",%s,%d,%d,%s,%s,%s,%d,%s},\n", $2, f_name, min_arg, limit_max ? -1 : $5, ctype($1), etype(0), etype(1), i, $6); if (strlen(buff) > sizeof buff) fatal("Local buffer overwritten !\n"); key[num_buff] = (char *) malloc(strlen($2) + 1); strcpy(key[num_buff], $2); buf[num_buff] = (char *) malloc(strlen(buff) + 1); strcpy(buf[num_buff], buff); num_buff++; min_arg = -1; limit_max = 0; curr_arg_type_size = 0; } ; type: basic | basic '*' { $$ = $1 | 0x10000; }; basic: ID { int i; $$ = 0; for (i=0; i < NELEMS(types); i++) { if (strcmp($1, types[i].name) == 0) { $$ = types[i].num; break; } } if (!$$) yyerror("Invalid type"); } ; arg_list: /* empty */ { $$ = 0; } | typel2 { $$ = 1; if ($1) min_arg = 0; } | arg_list ',' typel2 { $$ = $1 + 1; if ($3) min_arg = $$ - 1; } ; typel2: typel { $$ = $1; curr_arg_types[curr_arg_type_size++] = 0; if (curr_arg_type_size == NELEMS(curr_arg_types)) yyerror("Too many arguments"); } ; arg_type: type { if ($1 != VOID) { curr_arg_types[curr_arg_type_size++] = $1; if (curr_arg_type_size == NELEMS(curr_arg_types)) yyerror("Too many arguments"); } $$ = $1; } ; typel: arg_type { $$ = ($1 == VOID && min_arg == -1); } | typel '|' arg_type { $$ = (min_arg == -1 && ($1 || $3 == VOID));} | '.' '.' '.' { $$ = min_arg == -1 ; limit_max = 1; } ; %% FILE *f; int current_line = 1; int main(argc, argv) int argc; char **argv; { int i; void make_efun_tables(); num_buff = op_code = efun_code = 0; if ((f = fopen(FUNC_SPEC, "r")) == NULL) { perror(FUNC_SPEC); exit(1); } yyparse(); make_efun_tables(); /* Now sort the main_list */ for (i = 0; i < num_buff; i++) { int j; for (j = 0; j < i; j++) if (strcmp(key[i], key[j]) < 0) { char *tmp; int tmpi; tmp = key[i]; key[i] = key[j]; key[j] = tmp; tmp = buf[i]; buf[i] = buf[j]; buf[j] = tmp; tmpi = has_token[i]; has_token[i] = has_token[j]; has_token[j] = tmpi; } } /* Now display it... */ printf("{\n"); for (i = 0; i < num_buff; i++) printf("%s", buf[i]); printf("\n};\nint efun_arg_types[] = {\n"); for (i=0; i < last_current_type; i++) { if (arg_types[i] == 0) printf("0,\n"); else printf("%s,", ctype(arg_types[i])); } printf("};\n"); fclose(f); return 0; } void yyerror(str) char *str; { fprintf(stderr, "%s:%d: %s\n", FUNC_SPEC, current_line, str); exit(1); } int ident(c) int c; { char buff[100]; int len; for (len=0; isalnum(c) || c == '_'; c = getc(f)) { buff[len++] = c; if (len + 1 >= sizeof buff) fatal("Local buffer in ident() too small!\n"); if (len == sizeof buff - 1) { yyerror("Too long indentifier"); break; } } (void)ungetc(c, f); buff[len] = '\0'; if (strcmp(buff, "default") == 0) return DEFAULT; if (strcmp(buff, "operator") == 0) return OPERATOR; yylval.string = (char *)malloc(strlen(buff)+1); strcpy(yylval.string, buff); return ID; } char *type_str(n) int n; { int i, type = n & 0xffff; for (i=0; i < NELEMS(types); i++) { if (types[i].num == type) { if (n & 0x10000) { static char buff[100]; if (strlen(types[i].name) + 3 > sizeof buff) fatal("Local buffer too small in type_str()!\n"); sprintf(buff, "%s *", types[i].name); return buff; } return types[i].name; } } return "What?"; } int yylex1() { register int c; for(;;) { switch(c = getc(f)) { case ' ': case '\t': continue; case '#': { /* no prototype in <stdio.h> *sigh* */ #if defined(sun) && !defined(SunOS_5) extern int fscanf PROT((FILE *, char *, ...)); #endif int line; /* does any operating system support longer pathnames? */ char aBuf[2048]; fgets(aBuf, 2047, f); if (sscanf(aBuf, "%d", &line) == 2) current_line = line; current_line++; continue; } case '\n': current_line++; continue; case EOF: return -1; default: if (isalpha(c)) return ident(c); return c; } } } int yylex() { return yylex1(); } char *etype1(n) int n; { if (n & 0x10000) return "T_POINTER"; switch(n) { case FLOAT: return "T_REAL"; case FUNCTION: return "T_FUNCTION"; case INT: return "T_NUMBER"; case OBJECT: return "T_OBJECT"; case MAPPING: return "T_MAPPING"; case STRING: return "T_STRING"; case MIXED: return "0"; /* 0 means any type */ default: yyerror("Illegal type for argument"); } return "What?"; } char *etype(n) int n; { int i; int local_size = 100; char *buff = (char *)malloc(local_size); for (i=0; i < curr_arg_type_size; i++) { if (n == 0) break; if (curr_arg_types[i] == 0) n--; } if (i == curr_arg_type_size) return "0"; buff[0] = '\0'; for(; curr_arg_types[i] != 0; i++) { char *p; if (curr_arg_types[i] == VOID) continue; if (buff[0] != '\0') strcat(buff, "|"); p = etype1(curr_arg_types[i]); /* * The number 2 below is to include the zero-byte and the next * '|' (which may not come). */ if (strlen(p) + strlen(buff) + 2 > local_size) { fprintf(stderr, "Buffer overflow!\n"); exit(1); } strcat(buff, etype1(curr_arg_types[i])); } if (!strcmp(buff, "")) strcpy(buff, "T_ANY"); return buff; } char *ctype(n) int n; { static char buff[100]; /* 100 is such a comfortable size :-) */ char *p = (char *)NULL; if (n & 0x10000) strcpy(buff, "TYPE_MOD_POINTER|"); else buff[0] = '\0'; n &= ~0x10000; switch(n) { case FLOAT: p = "TYPE_REAL"; break; case FUNCTION: p = "TYPE_FUNCTION"; break; case VOID: p = "TYPE_VOID"; break; case STRING: p = "TYPE_STRING"; break; case INT: p = "TYPE_NUMBER"; break; case OBJECT: p = "TYPE_OBJECT"; break; case MAPPING: p = "TYPE_MAPPING"; break; case MIXED: p = "TYPE_ANY"; break; case UNKNOWN: p = "TYPE_UNKNOWN"; break; default: yyerror("Bad type!"); } strcat(buff, p); if (strlen(buff) + 1 > sizeof buff) fatal("Local buffer overwritten in ctype()"); return buff; } void make_efun_tables() { FILE *fp, *fp2, *fp3; int i; fp = fopen(EFUN_TABLE,"w"); if (!fp) { fprintf(stderr,"make_func: unable to open %s\n",EFUN_TABLE); exit(-1); } fp2 = fopen(OPC_PROF, "w"); if (!fp2) { fprintf(stderr,"make_func: unable to open %s\n",OPC_PROF); exit(-2); } fp3 = fopen(OPCODES, "w"); if (!fp3) { fprintf(stderr,"make_func: unable to open %s\n",OPCODES); exit(-3); } fprintf(fp,"/*\n\tThis file is automatically generated by make_func.\n"); fprintf(fp,"\tdo not make any manual changes to this file.\n*/\n\n"); fprintf(fp2,"/*\n\tThis file is automatically generated by make_func.\n"); fprintf(fp2,"\tdo not make any manual changes to this file.\n*/\n\n"); fprintf(fp3,"/*\n\tThis file is automatically generated by make_func.\n"); fprintf(fp3,"\tdo not make any manual changes to this file.\n*/\n\n"); fprintf(fp, "\ntypedef void (*func_t) PROT((int, int));\n\n"); fprintf(fp2,"\ntypedef struct opc_s { char *name; int count; } opc_t;\n\n"); fprintf(fp,"func_t efun_table[] = {\n"); fprintf(fp2,"opc_t opc_efun[] = {\n"); for (i = 0; i < (num_buff - 1); i++) { if (has_token[i]) { fprintf(fp,"\tf_%s,\n",key[i]); fprintf(fp2,"{\"%s\", 0},\n",key[i]); } } fprintf(fp,"\tf_%s};\n",key[num_buff - 1]); fprintf(fp2,"{\"%s\", 0}};\n",key[num_buff - 1]); for (i = 0; i < num_buff; i++) { if (has_token[i]) fprintf(fp,"void f_%s PROT((int, int));\n",key[i]); } fprintf(fp3, "\n/* operators */\n\n"); for (i = 0; i < op_code; i++) { fprintf(fp3,"#define %-30s %d\n", oper_codes[i], i+1); } fprintf(fp3,"\n/* efuns */\n#define BASE %d\n\n", op_code+1); for (i = 0; i < efun_code; i++) { fprintf(fp3,"#define %-30s %d\n", efun_codes[i], i+op_code+1); } fclose(fp); fclose(fp2); fclose(fp3); fp = fopen(EFUN_PROTO,"w"); fprintf(fp,"/*\n\tThis file is automatically generated by make_func.\n"); fprintf(fp,"\tdo not make any manual changes to this file.\n*/\n\n"); if (!fp) { fprintf(stderr,"make_func: unable to open %s\n",EFUN_TABLE); exit(-1); } for (i = 0; i < num_buff; i++) { if (has_token[i]) fprintf(fp,"void f_%s PROT((int, int));\n",key[i]); } fclose(fp); }