%{
/* Copyright 1991 - 1995, 1997 J"orn Rennecke */
#include <stdio.h>
#include <ctype.h>
#include <fcntl.h>
#define MAKE_FUNC
#include "common.h"
#include "config.h"
#include "exec.h"
#include "lex.h"
#define FUNC_SPEC "func_spec"
#define CONFIG "config.h"
#define PRO_LANG "prolang.y"
#define THE_LANG "lang.y"
#define THE_INSTRS "instrs.h"
/*
make_func has little problems with low memory. Therefore, I prefer to
be genorous with the maximum allowed line length and simply leave out
handling of overflow ( which can cause unpredictable behaviour this way...
but the same is true for some text-editors when faced with so long lines.)
*/
#define MAKE_FUNC_MAXLINE 4096
#define MAX_FUNC 2048
#define MAX_TOKENS 2048
#undef malloc
#undef realloc
#undef free
#undef isalunum
#define isalunum(c) (isascii(c) && (isalnum(c) || (c) == '_' ))
#define lexwhite(c) (isascii(c) && isspace(c) && (c) != '\n')
#undef lexdigit
#define lexdigit(c) (isascii(c) && isdigit(c))
#define MF_TYPE__ARRAY TYPE__ARRAY
#define MF_TYPE__REFERENCE TYPE_REFERENCE
#define C_TOKEN 0
#define C_CODE 1
#define C_EFUN 2
#define C_XCODE 3
#define C_XEFUN 4
#define C_TCODE 5
#define C_TEFUN 6
#define C_VCODE 7
#define C_VEFUN 8
#define C_ALIAS 9
#define C_TOTAL 10
#define C_IS_CODE(x) \
((x) == C_CODE || (x) == C_XCODE || (x) == C_TCODE || (x) == C_VCODE)
#define C_IS_EFUN(x) \
((x) == C_EFUN || (x) == C_XEFUN || (x) == C_TEFUN || (x) == C_VEFUN)
int num_buff = 0, num_instr[C_TOTAL] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
char *token_f_names[MAX_TOKENS];
static struct code {
char *key, *f_name, *Default;
short code_class, ordinal;
short min_arg, max_arg, check_arg, arg_start, return_type;
short is_const;
short padding[1];
} codes[MAX_FUNC];
int min_arg = -1, is_varargs = 0;
/*
* arg_types holds information for compile type checking of efun arguments.
* For each argument, there is a bitmask of type alternatives.
*/
long arg_types[500], *arg_types_end = &arg_types[0];
long curr_arg_types[MAX_PARAM], *curr_arg_types_end = &curr_arg_types[0];
void yyerror(char *);
int yylex(void);
int yyparse(void);
static void print_comp_type(int);
static void print_typemask(unsigned long m);
static void mf_fatal(char *);
int current_code_class;
/* ultrix 4.2 doesn't know strdup ?!? */
static char *mystrdup(char *str) {
char *copy = malloc(strlen(str)+1);
if (!copy) mf_fatal("strdup failed");
strcpy(copy, str);
return copy;
}
static void mf_fatal(char *str) {
fprintf(stderr, "%s\n", str);
fflush(stdout);
exit(1);
}
static char *make_f_name(char *str) {
char f_name[500];
int i, len;
if (strlen(str) + 1 + 2 > sizeof f_name)
mf_fatal("A local buffer was too small!(1)");
sprintf(f_name, "F_%s", str);
len = strlen(f_name);
for (i=0; i < len; i++) {
if (islower(f_name[i]))
f_name[i] = toupper(f_name[i]);
}
return mystrdup(f_name);
}
#define VOID 0
#define TYPE_ZERO 1
struct type {
char *name;
char *cname;
long mask;
} types[] = {
{"void", "TYPE_VOID"},
{"", "0"},
{"string", "TYPE_STRING", 1<<TYPE_STRING},
{"int", "TYPE_NUMBER", 1<<TYPE_NUMBER},
{"object", "TYPE_OBJECT", 1<<TYPE_OBJECT},
{"mapping", "TYPE_MAPPING", 1<<TYPE_MAPPING},
{"float", "TYPE_FLOAT", 1<<TYPE_FLOAT},
{"closure", "TYPE_CLOSURE", 1<<TYPE_CLOSURE},
{"symbol", "TYPE_SYMBOL", 1<<TYPE_SYMBOL},
{"varargs", "TYPE_VARARGS"},
{"mixed", "TYPE_ANY", ~(1<<TYPE_REFERENCE)},
{"unknown", "TYPE_UNKNOWN"},
{"quoted_array","TYPE_QUOTED_ARRAY"},
{"", "TYPE_REFERENCE", 1<<TYPE_REFERENCE},
{"", "TYPE_ANY", 1<<TYPE_ANY},
};
static int need_void = -1; /* >= 0 is true */
void store_arg_type(int mode, int arg) {
static long current_arg = 0;
if (mode != VOID) {
if ( !(arg & TYPE__ARRAY) ) {
current_arg |= types[arg].mask;
return;
}
if (arg == MF_TYPE__REFERENCE) {
current_arg |= 1<<TYPE_REFERENCE;
return;
}
current_arg |=
(types[arg & ~TYPE__ARRAY].mask << TYPE__ARRAY) &
~(1<<TYPE_REFERENCE);
return;
}
if (min_arg < 0) {
if (arg == VOID) {
min_arg = curr_arg_types_end - curr_arg_types;
return;
}
} else {
if (arg == VOID) {
need_void = -1;
return;
}
if (need_void >= 0) {
fprintf(stderr, "arg %d: ", curr_arg_types_end - curr_arg_types);
yyerror("non-void argument after void one");
}
}
need_void = min_arg;
if (!current_arg)
mf_fatal("storing 0 type\n");
*curr_arg_types_end++ = current_arg;
current_arg = 0;
if (curr_arg_types_end == &curr_arg_types[NELEM(curr_arg_types)])
yyerror("Too many arguments");
}
%}
%union {
int number;
char *string;
}
%token NAME ID
%token DEFAULT BASIC_TYPE CONST
%token TOKENS CODES EFUNS XCODES XEFUNS TCODES TEFUNS END
%type <number> BASIC_TYPE opt_star opt_ref
%type <number> arg_list type arg_alternative formal_arg
%type <number> optional_const
%type <string> ID optional_token optional_default NAME optional_name
%%
all: tokens END codes END efuns END xcodes END xefuns END tcodes END tefuns;
tokens: TOKENS
| tokens token;
codes: CODES
| codes code;
xcodes: XCODES
| xcodes code;
tcodes: TCODES
| tcodes code;
efuns: EFUNS funcs;
xefuns: XEFUNS funcs;
tefuns: TEFUNS funcs;
token: ID
{
token_f_names[num_instr[0]++] = make_f_name($1);
}
optional_name: /* empty */ { $$ = 0; }
| NAME;
code: optional_name ID
{
struct code *p;
num_instr[current_code_class]++;
p = &codes[num_buff];
p->code_class = current_code_class;
p->ordinal = ++num_buff;
p->f_name = make_f_name($2);
if ($1) {
p->key = $1;
free($2);
} else {
p->key = $2;
}
p->is_const = 1;
p->min_arg = p->max_arg = 0;
p->arg_start = 0;
p->return_type = TYPE_ZERO;
p->Default = "-1";
}
funcs: /* empty */ | funcs func ;
optional_token: ID | /* empty */ { $$ = ""; } ;
optional_default: DEFAULT ':' ID { $$ = $3; } | /* empty */ { $$ = "0"; } ;
optional_const: CONST { $$ = 0; } | /* empty */ { $$ = 1; } ;
func: optional_const type ID optional_token '(' arg_list optional_default ')' ';'
{
char *f_name;
long *haystack;
struct code *r;
need_void = -1;
if ($4[0] == '\0') {
f_name = make_f_name($3);
num_instr[
(int)(codes[num_buff].code_class =
is_varargs && current_code_class == C_TEFUN ?
C_VEFUN : current_code_class)
]++;
} else {
f_name = $4;
codes[num_buff].code_class = C_ALIAS;
num_instr[C_ALIAS]++;
}
for (haystack = arg_types;; haystack++) {
long *p = haystack, *q = curr_arg_types;
for (;;) {
if (q == curr_arg_types_end)
goto arguments_stored;
if (p == arg_types_end) {
do {
if (p == &arg_types[NELEM(arg_types)])
mf_fatal("Array 'arg_types' is too small");
*p++ = *q++;
} while(q < curr_arg_types_end);
arg_types_end = p;
goto arguments_stored;
}
if (*p++ != *q++)
break;
}
}
arguments_stored:
r = &codes[num_buff];
r->ordinal = ++num_buff;
r->key = $3;
r->f_name = f_name;
r->is_const = $1;
r->min_arg = min_arg < 0 ? $6 : min_arg;
r->max_arg = is_varargs | $6;
r->check_arg = curr_arg_types_end - curr_arg_types;
r->arg_start = haystack - arg_types;
r->Default = $7;
r->return_type = $2;
min_arg = -1;
is_varargs = 0;
curr_arg_types_end = &curr_arg_types[0];
} ;
type: BASIC_TYPE opt_star opt_ref { $$ = $1 | $2 | $3; };
opt_star : '*' { $$ = MF_TYPE__ARRAY; }
| { $$ = 0; } ;
opt_ref : '&' { $$ = MF_TYPE__REFERENCE; }
| { $$ = 0; } ;
arg_list: /* empty */ { $$ = 0; min_arg = 0; /* $$: length */ }
| formal_arg { $$ = 1; }
| arg_list ',' formal_arg { $$ = $1 + 1; };
formal_arg: arg_alternative
{
store_arg_type(VOID, TYPE_ZERO);
}
| '.' '.' '.'
{
is_varargs = 255;
if (min_arg < 0)
min_arg = curr_arg_types_end - curr_arg_types;
/* store_arg_type(VOID, TYPE_ZERO); */
};
arg_alternative: type { store_arg_type($1, $1); }
| arg_alternative '|' type { store_arg_type($3, $3); } ;
%%
int current_line;
char *current_file;
int last_line;
extern int hashstr(unsigned char *, mp_int, int);
#define MAKE_FUNC_DEFHASH 512
#define defhash(str) (idhash(str).hash & (MAKE_FUNC_DEFHASH - 1))
struct mf_defn {
char *name;
char *exps;
int num_arg;
struct mf_defn *next;
};
static struct mf_defn *deftab[MAKE_FUNC_DEFHASH];
static char *outp;
static int mygetc() {
return *outp++;
}
static void myungetc(int c) {
*--outp = c;
}
static void add_input(char *p) {
int l;
l = strlen(p);
outp -= l;
memcpy(outp, p, l);
}
static void add_define(char *name, int num_arg, char *exps) {
int i;
struct mf_defn *ndef;
i = defhash(name);
ndef = (struct mf_defn *)malloc(sizeof(struct mf_defn));
if (!ndef) {
abort();
}
ndef->next = deftab[i];
ndef->exps = mystrdup(exps);
ndef->num_arg = num_arg;
ndef->name = mystrdup(name);
deftab[i] = ndef;
}
static struct mf_defn *lookup_define(char *s) {
struct mf_defn *curr, *prev;
int h;
h = defhash(s);
curr = deftab[h];
prev = 0;
while (curr) {
if (!strcmp(curr->name, s)) { /* found it */
if (prev) { /* not at head of list */
prev->next = curr->next;
curr->next = deftab[h];
deftab[h] = curr;
}
return curr;
}
prev = curr;
curr = curr->next;
} /* not found */
return 0;
}
static int expand_define(char *s) {
struct mf_defn *p;
p = lookup_define(s);
if (!p)
return 0;
if (p->num_arg < 0) {
add_input(p->exps);
} else {
return -1;
}
return 1;
}
static char *nextword(char *str) {
char *cp;
while(!lexwhite(*str)) str++;
while( lexwhite(*str)) str++;
for(cp = str; isalunum(*cp); ) cp++;
*cp = '\0';
return str;
}
static struct ifstate {
struct ifstate *next;
int expect_else;
} *iftop = 0;
FILE *fpr, *fpw;
static int skip_to(char mark, char *token, char *atoken) {
char b[8], *p;
int c;
int nest;
FILE *fp = fpr;
for(nest = 0;;) {
current_line++;
c = fgetc(fp);
if (c == mark) {
do {
c = fgetc(fp);
} while(lexwhite(c));
for(p = b; isalpha(c) && p < &b[sizeof b - 1]; ) {
*p++ = c;
c = fgetc(fp);
}
*(isspace(c) ? p : b) = '\0';
while (c != '\n') {
if (c == EOF) {
fprintf(stderr, "%cendif expected\n", mark);
abort();
}
c = fgetc(fp);
}
if (*(short *)b == *(short *)"if") {
if (!b[2] || !strcmp(b+2, "def") || !strcmp(b+2, "ndef"))
nest++;
} else if (nest > 0) {
if (strcmp(b, "endif") == 0)
nest--;
} else {
if (strcmp(b, token) == 0)
return 1;
else if (atoken && strcmp(b, atoken) == 0)
return 0;
}
} else {
while (c != '\n') {
if (c == EOF) {
fprintf(stderr, "%cendif expected\n", mark);
abort();
}
c = fgetc(fp);
}
}
}
}
static void compensate_lines() {
for (; last_line <= current_line; last_line++)
fputc('\n', fpw);
}
static void handle_cond(char mark, int c) {
struct ifstate *p;
if (c || skip_to(mark, "else", "endif")) {
p = (struct ifstate *)malloc(sizeof(struct ifstate));
p->next = iftop;
p->expect_else = c;
iftop = p;
}
if (mark == '%')
compensate_lines();
}
static int cond_get_exp();
static void handle_if(char mark, char *str) {
int cond;
add_input(str);
cond = cond_get_exp(0);
if (mygetc() != '\n') {
yyerror("Condition too complex in #/%if");
fflush(stdout);
if (mark == '%') exit(1);
while(mygetc() != '\n');
} else
handle_cond(mark, cond );
}
static void handle_else(char mark) {
if (iftop && iftop->expect_else) {
struct ifstate *p = iftop;
iftop = p->next;
free((char *)p);
skip_to(mark, "endif", (char *)0);
} else {
fprintf(stderr, "Unexpected #/%%else line %d\n", current_line);
abort();
}
}
static void handle_endif() {
if (iftop) {
struct ifstate *p = iftop;
iftop = p->next;
free((char *)p);
} else {
fprintf(stderr, "Unexpected #/%%endif line %d\n", current_line);
abort();
}
}
static int name_to_type(char *name) {
while (isspace(*name))
name++;
if ( strncmp(name, "TYPE_", 5) )
return -1;
name += 5;
if ( !strcmp(name, "ANY") )
return TYPE_ANY;
if ( !strcmp(name, "NUMBER") )
return TYPE_NUMBER;
if ( !strcmp(name, "FLOAT") )
return TYPE_FLOAT;
if ( !strcmp(name, "OBJECT") )
return TYPE_OBJECT;
if ( !strcmp(name, "MAPPING") )
return TYPE_MAPPING;
if ( !strcmp(name, "CLOSURE") )
return TYPE_CLOSURE;
return -1;
}
static int name_to_hook(char *name) {
while (isspace(*name))
name++;
if ( strncmp(name, "H_", 2) )
return -1;
name += 2;
if ( !strcmp(name, "MOVE_OBJECT0") )
return H_MOVE_OBJECT0;
if ( !strcmp(name, "MOVE_OBJECT1") )
return H_MOVE_OBJECT1;
if ( !strcmp(name, "LOAD_UID") )
return H_LOAD_UID;
if ( !strcmp(name, "CLONE_UID") )
return H_CLONE_UID;
if ( !strcmp(name, "CREATE_SUPER") )
return H_CREATE_SUPER;
if ( !strcmp(name, "CREATE_OB") )
return H_CREATE_OB;
if ( !strcmp(name, "CREATE_CLONE") )
return H_CREATE_CLONE;
if ( !strcmp(name, "RESET") )
return H_RESET;
if ( !strcmp(name, "CLEAN_UP") )
return H_CLEAN_UP;
if ( !strcmp(name, "NO_IPC_SLOT") )
return H_NO_IPC_SLOT;
if ( !strcmp(name, "INCLUDE_DIRS") )
return H_INCLUDE_DIRS;
return -1;
}
static void handle_map(char *str, int size, int (*name_to_index)(char *)) {
char **map, deflt[256];
char *del = 0, *val;
int i;
char *output_del = "";
map = (char **)alloca(size * sizeof *map);
strcpy(deflt, "0");
for (i = 0; i < size; i++) {
map[i] = deflt;
}
do {
while (isspace(*str))
str++;
if (*str == '\\') {
str = alloca(MAKE_FUNC_MAXLINE + 1);
if (!fgets(str, MAKE_FUNC_MAXLINE, fpr))
break;
if (del) {
output_del = "\n";
}
}
del = strchr(str, ':');
if (!del)
break;
*del = '\0';
val = del+1;
del = strchr(val, ',');
if (!del) {
del = strchr(val, '\n');
if (del) {
*del = '\0';
del = 0;
}
} else {
*del = '\0';
}
if ( !strcmp(str, "default") ) {
strncpy(deflt, val, sizeof(deflt));
deflt[sizeof deflt - 1] = '\0';
} else {
i = (*name_to_index)(str);
if (i < 0)
exit(-1);
map[i] = val;
}
str = del+1;
} while (del);
fprintf(fpw, "{");
fprintf(fpw, output_del);
for (i = 0; i < size; i++) {
fprintf(fpw, "%s,", map[i]);
fprintf(fpw, output_del);
}
fprintf(fpw, "};\n");
}
static int exgetc() {
register char c;
c=mygetc();
while ( isalpha(c) || c=='_' ) {
char word[512], *p;
int space_left;
p = word;
space_left = sizeof(word);
do {
*p++ = c;
c=mygetc();
} while ( isalunum(c) && --space_left);
if (!space_left) mf_fatal("Too long word.");
myungetc(c);
*p='\0';
if (strcmp(word, "defined") == 0) {
/* handle the defined "function" in #if */
do c = mygetc(); while(lexwhite(c));
if (c != '(') {
yyerror("Missing ( in defined");
continue;
}
do c = mygetc(); while(lexwhite(c));
p = word;
space_left = sizeof(word);
while ( isalunum(c) && --space_left) {
*p++ = c;
c=mygetc();
}
*p='\0';
while(lexwhite(c)) c = mygetc();
if (c != ')') {
yyerror("Missing ) in defined");
continue;
}
if (lookup_define(word))
add_input(" 1 ");
else
add_input(" 0 ");
} else {
int res;
res = expand_define(word);
if (res < 0) {
yyerror("Unimplemented macro expansion");
return 0;
}
if (!res) add_input(" 0 ");
}
c=mygetc();
}
return c;
}
#define BNOT 1
#define LNOT 2
#define UMINUS 3
#define UPLUS 4
#define MULT 1
#define DIV 2
#define MOD 3
#define BPLUS 4
#define BMINUS 5
#define LSHIFT 6
#define RSHIFT 7
#define LESS 8
#define LEQ 9
#define GREAT 10
#define GEQ 11
#define EQ 12
#define NEQ 13
#define BAND 14
#define XOR 15
#define BOR 16
#define LAND 17
#define LOR 18
#define QMARK 19
static char _optab[]=
{0,4,0,0,0,26,56,0,0,0,18,14,0,10,0,22,0,0,0,0,0,0,0,0,0,0,0,0,30,50,40,74,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,63,0,1};
static char optab2[]=
{BNOT,0,0,LNOT,'=',NEQ,7,0,0,UMINUS,0,BMINUS,10,UPLUS,0,BPLUS,10,
0,0,MULT,11,0,0,DIV,11,0,0,MOD,11,
0,'<',LSHIFT,9,'=',LEQ,8,0,LESS,8,0,'>',RSHIFT,9,'=',GEQ,8,0,GREAT,8,
0,'=',EQ,7,0,0,0,'&',LAND,3,0,BAND,6,0,'|',LOR,2,0,BOR,4,
0,0,XOR,5,0,0,QMARK,1};
#define optab1 (_optab-' ')
static int cond_get_exp(int priority) {
int c;
int value,value2,x;
do c=exgetc(); while ( lexwhite(c) );
if ( c=='(' ) {
value=cond_get_exp(0);
do c=exgetc(); while ( lexwhite(c) );
if ( c!=')' ) {
yyerror("bracket not paired in #if");
if (!c) myungetc('\0');
}
} else if ( ispunct(c) ) {
x=optab1[c];
if (!x) {
yyerror("illegal character in #if");
return 0;
}
value=cond_get_exp(12);
switch ( optab2[x-1] ) {
case BNOT : value = ~value; break;
case LNOT : value = !value; break;
case UMINUS: value = -value; break;
case UPLUS : value = value; break;
default :
yyerror("illegal unary operator in #if");
return 0;
}
} else {
int base;
if ( !lexdigit(c) ) {
if (!c) {
yyerror("missing expression in #if");
myungetc('\0');
} else {
yyerror("illegal character in #if");
}
return 0;
}
value=0;
if ( c!='0' ) {
base=10;
} else {
c=mygetc();
if ( c=='x' || c=='X' ) {
base=16;
c=mygetc();
} else {
base=8;
}
}
for(;;) {
if ( isdigit(c) ) x = -'0';
else if ( isupper(c) ) x = -'A'+10;
else if ( islower(c) ) x = -'a'+10;
else break;
x+=c;
if ( x > base ) break;
value=value*base+x;
c=mygetc();
}
myungetc(c);
}
for (;;) {
do c=exgetc(); while ( lexwhite(c) );
if ( !ispunct(c) ) break;
x=optab1[c];
if (!x) break;
value2=mygetc();
for(;;x+=3) {
if ( !optab2[x] ) {
myungetc(value2);
if ( !optab2[x+1] ) {
yyerror("illegal operator use in #if");
return 0;
}
break;
}
if ( value2==optab2[x] ) break;
}
if ( priority >= optab2[x+2] ) {
if( optab2[x] ) myungetc(value2);
break;
}
value2=cond_get_exp(optab2[x+2]);
switch ( optab2[x+1] ) {
case MULT : value *= value2; break;
case DIV : value /= value2; break;
case MOD : value %= value2; break;
case BPLUS : value += value2; break;
case BMINUS : value -= value2; break;
case LSHIFT : value <<= value2; break;
case RSHIFT : value >>= value2; break;
case LESS : value = value < value2; break;
case LEQ : value = value <= value2; break;
case GREAT : value = value > value2; break;
case GEQ : value = value >= value2; break;
case EQ : value = value == value2; break;
case NEQ : value = value != value2; break;
case BAND : value &= value2; break;
case XOR : value ^= value2; break;
case BOR : value |= value2; break;
case LAND : value = value && value2; break;
case LOR : value = value || value2; break;
case QMARK :
do c=exgetc(); while( lexwhite(c) );
if ( c!=':' ) {
yyerror("'?' without ':' in #if");
myungetc(c);
return 0;
}
if ( value ) {
cond_get_exp(1);
value=value2;
} else {
value=cond_get_exp(1);
}
break;
}
}
myungetc(c);
return value;
}
static int make_func_isescaped(char c) {
switch(c) {
case '\007':
case '\b' :
case '\t' :
case '\n' :
case '\013':
case '\014':
case '\r' :
return 1;
}
if (c == '\\' || c == '\"') return 1;
return 0;
}
static int efuncmp(const void *x, const void *y) {
const struct code *a = x, *b = y;
int result;
if (result = a->code_class - b->code_class)
return result;
if (C_IS_CODE(a->code_class)) return a->ordinal - b->ordinal;
return strcmp(a->key, b->key);
}
void print_code(struct code *p) {
fputc('{', stdout);
print_comp_type(p->return_type);
printf(",%d,%d,%d,%d,%s,%d,\"%s\"},\n",
p->is_const, p->max_arg , p->min_arg, p->check_arg,
p->Default, p->arg_start, p->key);
}
int main(int argc, char **argv) {
int i, j, k;
int match_tmp;
unsigned char c;
char line_buffer[MAKE_FUNC_MAXLINE + 1];
char defbuf[MAKE_FUNC_MAXLINE + 1];
#ifdef AMIGA
add_define("AMIGA",-1,"");
#endif
#ifdef HAVE_GETRUSAGE
add_define("HAVE_GETRUSAGE",-1,"");
#endif
#ifdef TRACE_CODE
add_define("TRACE_CODE",-1,"");
#endif
if ((fpw = fopen(THE_LANG, "w")) == 0) {
perror(THE_LANG);
exit(1);
}
fprintf(fpw, "%s", "\
%union{ int i; char *p; }\n\
%type <p> all\n\
%%\n\
all: { $<p>$ = 0; } 'a'\n\
%%\n\
");
fclose(fpw);
sprintf(line_buffer, "%s %s", YACC, THE_LANG);
printf("#if 0\n");
fflush(stdout);
fprintf(stderr, "checking default & anonymous rules in %s\n", YACC);
if (system(line_buffer)) {
fprintf(
stderr,
"It seems to have trouble with this combination, I'll avoid the latter.\n"
);
add_define("YACC_CANNOT_MIX_ANONYMOUS_WITH_DEFAULT", -1, "");
}
printf("#endif\n\n");
outp = defbuf + sizeof(defbuf) - 1;
/* read in the defines of the configuration file */
if ((fpr = fopen(CONFIG, "r")) == 0) {
perror(CONFIG);
fflush(stdout);
exit(1);
}
current_line = 0;
current_file = CONFIG;
#define MATCH(str) (isspace(line_buffer[1+(match_tmp=strlen(str))]) &&\
strncmp(str, line_buffer+1, match_tmp) == 0)
while (fgets(line_buffer, MAKE_FUNC_MAXLINE, fpr)) {
char *name;
current_line++;
if ( *line_buffer != '#' )
continue;
if MATCH("if") {
handle_if('#', line_buffer+4);
continue;
}
if MATCH("ifdef") {
handle_cond('#', lookup_define(nextword(line_buffer)) != 0);
continue;
}
if MATCH("ifndef") {
handle_cond('#', lookup_define(nextword(line_buffer)) == 0);
continue;
}
if MATCH("else") {
handle_else('#');
continue;
}
if MATCH("endif") {
handle_endif();
continue;
}
if MATCH("undef") {
struct mf_defn *old_def;
old_def = lookup_define(nextword(line_buffer));
if (old_def)
old_def->name[0] = '\0';
continue;
}
if ( !MATCH("define") ) {
continue;
}
/* CONFIG is trusted to be syntactically correct. After all, it was
* included by the source of this program.
*/
{
char *cp, *exps;
int num_arg;
cp = line_buffer+8;
while( isspace(*cp)) cp++;
name = cp;
while(isalunum(*cp)) cp++;
num_arg = *cp == '(' ? 0 : -1;
if (*cp == '\n') {
exps = cp;
*cp = '\0';
} else {
*cp++ = '\0';
while( isspace(*cp)) cp++;
exps = cp;
while(*cp != '\n') cp++;
*cp = '\0';
}
add_define(name, num_arg, exps);
}
}
fclose(fpr);
if ((fpr = fopen(FUNC_SPEC, "r")) == NULL) {
perror(FUNC_SPEC);
exit(1);
}
current_line = 1;
current_file = FUNC_SPEC;
yyparse();
fclose(fpr);
fprintf(
stderr, "\
Primary codes: %d Secondary codes: %d\n\
Tabled codes: %d Tabled varargs codes: %d\n",
num_instr[C_CODE] + num_instr[C_EFUN],
num_instr[C_XCODE] + num_instr[C_XEFUN],
num_instr[C_TCODE] + num_instr[C_TEFUN],
num_instr[C_VCODE] + num_instr[C_VEFUN]
);
if ( num_instr[C_CODE] + num_instr[C_EFUN] & ~0xff ||
( num_instr[C_XCODE]+ num_instr[C_XEFUN] |
num_instr[C_TCODE]+ num_instr[C_TEFUN] |
num_instr[C_VCODE]+ num_instr[C_VEFUN] ) & ~0x7f)
{
mf_fatal("Codes exhausted!");
}
/* Now sort the efuns */
qsort(codes, num_buff, sizeof codes[0], efuncmp);
/* Now output the instrs array. */
printf("#include \"exec.h\" /* for size of struct instr */\n\n");
printf("struct instr instrs[]={\n");
j = num_instr[C_CODE] + num_instr[C_EFUN];
for (i = 0; i < j; i++) {
print_code(&codes[i]);
}
for (i -= 256 ; ++i <= 0; ) {
printf(" {0,0,0,0,0,-1,0,0},\n");
}
i = j;
j += num_instr[C_XCODE] + num_instr[C_XEFUN];
for (; i < j; i++) {
print_code(&codes[i]);
}
for (i = 128 - num_instr[C_XCODE] - num_instr[C_XEFUN]; --i >= 0; ) {
printf(" {0,0,0,0,0,-1,0,0},\n");
}
i = j;
j += num_instr[C_TCODE] + num_instr[C_TEFUN];
for (; i < j; i++) {
print_code(&codes[i]);
}
for (i = 128 - num_instr[C_TCODE] - num_instr[C_TEFUN]; --i >= 0; ) {
printf(" {0,0,0,0,0,-1,0,0},\n");
}
i = j;
for (; i < num_buff; i++) {
print_code(&codes[i]);
}
printf("};\nshort efun_aliases[]={\n");
for (i = 0; i < num_buff; i++) {
if (codes[i].code_class == C_ALIAS)
printf(" %s,\n", codes[i].f_name);
}
printf("};\nint32 efun_arg_types[] = {\n ");
{
long *p;
for (p = arg_types; p < arg_types_end; p++) {
print_typemask(*p);
fputs(",\n ", stdout);
}
}
printf("};\n\n");
for(j = 1, i = 0; j < C_TCODE; j++)
i += num_instr[j];
j = i + num_instr[C_TCODE] + num_instr[C_TEFUN];
k = i;
while(k < j) {
printf(
"union svalue *f_%s(union svalue *);\n", codes[k++].key);
}
printf("\nunion svalue *(*efun_table[])(union svalue *) = {\n");
while(i < j) {
printf(" f_%s,\n", codes[i++].key);
}
printf("};\n\n");
j = i + num_instr[C_VCODE] + num_instr[C_VEFUN];
k = i;
while(k < j) {
printf(
"union svalue *f_%s(union svalue *);\n", codes[k++].key);
}
printf("\nunion svalue *(*vefun_table[])(union svalue *) = {\n");
while(i < j) {
printf(" f_%s,\n", codes[i++].key);
}
printf("};\n\n");
/* Make our own character type classification. This is for two reasons:
* i) The standard isXXX macros are only defined on ascii values.
* there might be non-ascii characters in the compiled files.
* ii) We actually need some nonstandard classifications, and the lexical
* scanner can be costly in terms of cpu usage.
*/
printf("#define lexwhite(c) (_my_ctype[(unsigned char)(c)]&%d)\n",_MCTs);
printf("#define leXdigit(c) (_my_ctype[(unsigned char)(c)]&%d)\n",_MCTx);
printf("unsigned char _my_ctype[]={");
c = '\0';
do {
if (!(c & 0xf)) printf("\n ");
printf("%d,", !isascii(c) ? 0 :
( make_func_isescaped(c) ? _MCTe : 0 ) |
( isdigit (c) ? _MCTd : 0 ) |
( isspace (c) && c != '\n' ? _MCTs : 0 ) |
( isxdigit(c) ? _MCTx : 0 ) |
( isalnum (c) || c == '_' ? _MCTa : 0 ) );
c++;
} while (c != '\0');
printf("};\n\n");
/* Create a table to 'cook' backslash-escaped characters */
printf("char escchars[]={");
c = '\0';
do {
if (!(c & 0xf)) printf("\n ");
i = c;
switch(i) {
case '0': case '1': case '2': case '3': case '4': case '5':
case '6': case '7':
case '\n': case '\r':
case LC_DEFARG: case LC_IDENT: case LC_STRING: case LC_POP:
i = '0';
case 'a': case 'b': case 'e': case 'f': case 'n': case 'r':
case 't': case 'v': case '\\': case '\'': case '\"':
printf("\'\\%c\',", i);
break;
default:
printf((isascii(i) && isprint(i)) ? "\'%c\'," : "%d,", i);
break;
}
} while(++c != '\0');
printf("};\n");
if ((fpw = fopen(THE_INSTRS, "w")) == 0) {
perror(THE_INSTRS);
exit(1);
}
fprintf(fpw, "#include \"exec.h\" /* for size of struct instr */\n\n");
fprintf(fpw, "#define LAST_INSTRUCTION_CODE %d\n",
256+128+128+num_instr[C_VCODE]+num_instr[C_VEFUN] - 1
);
fprintf(fpw, "\nextern struct instr instrs[%d];\n",
256+128+128+num_instr[C_VCODE]+num_instr[C_VEFUN]+num_instr[C_ALIAS]
);
fprintf(fpw, "extern short efun_aliases[%d];\n\n", num_instr[C_ALIAS]);
for (i = j = 0; i < num_buff; i++) {
if (j == num_instr[C_CODE] + num_instr[C_EFUN]) {
j = 256;
}
if (j == 256 + num_instr[C_XCODE] + num_instr[C_XEFUN]) {
j = 256+128;
}
if (j == 256 + 128 + num_instr[C_TCODE] + num_instr[C_TEFUN]) {
j = 256+128+128;
}
if (codes[i].code_class != C_ALIAS) {
fprintf(fpw, "#define %s %d\n", codes[i].f_name, j);
j++;
}
}
fclose(fpw);
/*
* Create lang.y from prolang.y , doing some useful transformations
* and inserting the token list at the appropriate place.
*/
if ((fpr = fopen(PRO_LANG, "r")) == 0) {
perror(PRO_LANG);
exit(1);
}
if ((fpw = fopen(THE_LANG, "w")) == 0) {
perror(THE_LANG);
exit(1);
}
current_line = 0;
while (fgets(line_buffer, MAKE_FUNC_MAXLINE, fpr)) {
current_line++;
if (*line_buffer == '%') {
if MATCH("efuns") {
for (i = 0; i < num_instr[C_TOKEN]; i++) {
fprintf(fpw, "%%token YYF%s\n", token_f_names[i]+1);
}
for (i = 0; i < num_instr[C_CODE]; i++) {
if (codes[i].code_class != C_ALIAS) {
fprintf(fpw , "%%token YY%s\n", codes[i].f_name);
}
}
continue;
}
last_line = current_line;
if MATCH("if") {
handle_if('%', line_buffer+4);
continue;
}
if MATCH("ifdef") {
handle_cond('%', lookup_define(nextword(line_buffer)) != 0);
continue;
}
if MATCH("ifndef") {
handle_cond('%', lookup_define(nextword(line_buffer)) == 0);
continue;
}
if MATCH("else") {
handle_else('%');
compensate_lines();
continue;
}
if MATCH("endif") {
handle_endif();
compensate_lines();
continue;
}
if MATCH("line") {
fprintf(fpw, "#line %d \"%s\"\n", current_line+1, PRO_LANG);
continue;
}
if MATCH("typemap") {
handle_map(line_buffer+9, TYPEMAP_SIZE, name_to_type);
continue;
}
if MATCH("hookmap") {
handle_map(line_buffer+9, NUM_DRIVER_HOOKS, name_to_hook);
continue;
}
if MATCH("error_nargs") {
static void print_error_nargs();
print_error_nargs();
continue;
}
if MATCH("ce_error_nargs") {
static void print_ce_error_nargs();
print_ce_error_nargs();
continue;
}
if MATCH("//") {
/* c++ - resembling comment */
fputs("", fpw);
continue;
}
}
fputs(line_buffer, fpw);
}
fclose(fpr), fclose(fpw);
return 0;
}
#undef MATCH
void yyerror(char *str) {
fprintf(stderr, "%s:%d: %s\n", current_file, current_line, str);
exit(1);
}
static int ident(int c) {
char buff[96];
int len, i;
for (len = 0; isalunum(c); c = getc(fpr)) {
if (len == sizeof buff - 1)
yyerror("Too long indentifier");
buff[len++] = c;
}
ungetc(c, fpr);
buff[len] = '\0';
if ( C_IS_EFUN(current_code_class) ) {
for (i = NELEM(types); --i >= 0; ) {
if (!strcmp(buff, types[i].name)) {
yylval.number = i;
return BASIC_TYPE;
}
}
if (strcmp(buff, "default") == 0)
return DEFAULT;
if (strcmp(buff, "const") == 0)
return CONST;
}
yylval.string = mystrdup(buff);
return ID;
}
static void skip_comment() {
int c;
for(;;) {
while((c = getc(fpr)) != '*') {
if (c == EOF) {
yyerror("End of file in a comment");
return;
}
if (c == '\n') {
current_line++;
}
}
do {
if ((c = getc(fpr)) == '/')
return;
if (c == '\n') {
current_line++;
}
} while(c == '*');
}
}
static int yylex1() {
register int c;
for(;;) {
int match_tmp;
#define MATCH(str) (isspace(line_buffer[match_tmp=strlen(str)]) &&\
strncmp(str, line_buffer, match_tmp) == 0)
char line_buffer[MAKE_FUNC_MAXLINE+1];
switch(c = getc(fpr)) {
case ' ':
case '\t':
continue;
case '#':
{
int line;
char file[2048]; /* does any operating system support
longer pathnames? */
fgets(line_buffer, MAKE_FUNC_MAXLINE, fpr);
if ( sscanf(line_buffer, "%d \"%s\"",&line,file ) == 2 ) {
current_line = line+1;
continue;
}
current_line++;
if MATCH("if") {
handle_if('#', line_buffer+3);
} else if MATCH("ifdef") {
handle_cond('#', lookup_define(nextword(line_buffer)) != 0);
} else if MATCH("ifndef") {
handle_cond('#', lookup_define(nextword(line_buffer)) == 0);
continue;
} else if MATCH("else") {
handle_else('#');
} else if MATCH("endif") {
handle_endif();
} else {
yyerror("unrecognised '#' directive");
}
continue;
}
case '%':
{
static int send_end = 0;
if (send_end) {
send_end = 0;
ungetc('%', fpr);
return END;
}
send_end = 1;
fgets(line_buffer, MAKE_FUNC_MAXLINE, fpr);
current_line++;
if (MATCH("tokens")) { current_code_class=C_TOKEN; return TOKENS; }
if (MATCH("codes")) { current_code_class=C_CODE; return CODES; }
if (MATCH("efuns")) { current_code_class=C_EFUN; return EFUNS; }
if (MATCH("xcodes")) { current_code_class=C_XCODE; return XCODES; }
if (MATCH("xefuns")) { current_code_class=C_XEFUN; return XEFUNS; }
if (MATCH("tcodes")) { current_code_class=C_TCODE; return TCODES; }
if (MATCH("tefuns")) { current_code_class=C_TEFUN; return TEFUNS; }
return '%';
#undef MATCH
}
case '\"':
{
char buff[100];
int len;
for (len=0; c = getc(fpr),c != '\"';) {
if (len == sizeof buff - 1) {
yyerror("Too long name");
do
c = getc(fpr);
while (c != '\"' && c != '\n' && c != EOF);
(void)ungetc(c, fpr);
break;
}
if (c == '\n' || c == EOF) {
yyerror("unterminated name");
(void)ungetc(c, fpr);
break;
}
buff[len++] = c;
}
buff[len] = '\0';
yylval.string = mystrdup(buff);
return NAME;
}
case '\n':
current_line++;
continue;
case EOF:
return -1;
case '/':
if ( (c=getc(fpr)) == '*') {
skip_comment();
continue;
} else {
(void)ungetc(c, fpr);
return '/';
}
default:
return isalpha(c) ? ident(c) : c;
}
}
}
int yylex() {
int res;
res = yylex1();
#if 0
fprintf(stderr,"yylex returns %d '%c'\n",res,res);
#endif
return res;
}
static void print_comp_type(int n) {
if (n == TYPE_REFERENCE) {
fputs("TYPE_REFERENCE", stdout);
return;
}
if (n & MF_TYPE__ARRAY)
fputs("TYPE__ARRAY|", stdout);
n &= ~(MF_TYPE__ARRAY);
if ((unsigned)n >= NELEM(types)) {
mf_fatal("Bad type!");
}
fputs(types[n].cname, stdout);
}
static void print_typemask(unsigned long m) {
unsigned long m2;
if (m & ~(1<<TYPE_REFERENCE)) {
m |= 1<<TYPE_ANY;
}
if (m & ~(1<<TYPE_REFERENCE) & -1<<TYPE__ARRAY) {
m |= 1<<TYPE_ANY+TYPE__ARRAY;
}
if (m == ~(1<<TYPE_REFERENCE)) {
fputs("~(1<<TYPE_REFERENCE)", stdout);
return;
}
if (m == ~0) {
fputs("~0", stdout);
return;
}
if (m & 1<<TYPE_REFERENCE) {
fputs("1<<TYPE_REFERENCE", stdout);
m &= ~(1<<TYPE_REFERENCE);
if (m)
fputc('|', stdout);
else return;
}
if ((m | (1<<TYPE__ARRAY)-1 | 1<<TYPE_REFERENCE) == (unsigned long)(-1)) {
fputs("~(1<<TYPE_REFERENCE)&-1<<TYPE__ARRAY", stdout);
m &= ~( ~(1<<TYPE_REFERENCE) & -1<<TYPE__ARRAY );
if (m)
fputc('|', stdout);
else return;
}
for (m2 = 1; ;m2 <<= 1) {
if (m & m2) {
int i;
fputs("1<<", stdout);
for (i = 0; ; ) {
if (m2 == types[i].mask) {
fputs(types[i].cname, stdout);
break;
}
if (m2>>TYPE__ARRAY && m2>>TYPE__ARRAY == types[i].mask) {
fputs(types[i].cname, stdout);
fputs("+TYPE__ARRAY", stdout);
break;
}
if (++i >= NELEM(types)) {
fprintf(stderr, "%lx %lx\n", m, m2);
mf_fatal("Bad argument to print_typemask\n");
}
}
m &= ~m2;
if (!m)
break;
putc('|', stdout);
}
}
}
static void print_error_nargs() {
int i, nargs[IE_NUM_ERRORS];
for (i = 0; i < NELEM(nargs); i++) {
nargs[i] = 0;
}
nargs[IE_BAD_EFUN_ARG] = 2;
nargs[IE_PRIVILEGED ] = 2;
fputs("{\n", fpw);
for (i = 0; i < NELEM(nargs); i++) {
fprintf(fpw, "\t%d,\n", nargs[i]);
}
fputs("}\n", fpw);
}
static void print_ce_error_nargs() {
int i, nargs[CE_NUM_ERRORS];
for (i = 0; i < NELEM(nargs); i++) {
nargs[i] = 0;
}
nargs[CE_VARNDECL ] = 1;
nargs[CE_VARREDEF ] = 1;
nargs[CE_NPARAM ] = 1;
nargs[CE_DUPPAR ] = 1;
nargs[CE_BADTYPE ] = 2;
nargs[CE_NOMASK_SIM ] = 1;
nargs[CE_NO_NUMELSE ] = 1;
nargs[CE_NO_NUMENDIF] = 1;
nargs[CE_CL_FUN_UNDEF] = 1;
nargs[CE_MFILE] = 1;
nargs[CE_NFILE] = 1;
fputs("{\n", fpw);
for (i = 0; i < NELEM(nargs); i++) {
fprintf(fpw, "\t%d,\n", nargs[i]);
}
fputs("}\n", fpw);
}