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