%{
#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);
}