#include "std.h" #include "lpc_incl.h" #include "compiler.h" #include "trees.h" #include "lex.h" #include "functab_tree.h" #include "generate.h" #include "swap.h" #include "scratchpad.h" #include "qsort.h" #include "file.h" #include "binaries.h" /* This should be moved with initializers move out of here */ #include "icode.h" static void clean_parser PROT((void)); static void prolog PROT((int, char *)); static void epilog PROT((void)); static void show_overload_warnings PROT((void)); #define CT(x) (1 << (x)) #define CT_SIMPLE(x) (CT(TYPE_ANY) | CT(x)) short compatible[11] = { /* UNKNOWN */ 0, /* ANY */ 0xfff, /* NOVALUE */ CT_SIMPLE(TYPE_NOVALUE) | CT(TYPE_VOID) | CT(TYPE_NUMBER), /* VOID */ CT_SIMPLE(TYPE_VOID) | CT(TYPE_NOVALUE) | CT(TYPE_NUMBER), /* NUMBER */ CT_SIMPLE(TYPE_NUMBER) | CT(TYPE_NOVALUE) | CT(TYPE_REAL) | CT(TYPE_VOID), /* STRING */ CT_SIMPLE(TYPE_STRING), /* OBJECT */ CT_SIMPLE(TYPE_OBJECT), /* MAPPING */ CT_SIMPLE(TYPE_MAPPING), /* FUNCTION */ CT_SIMPLE(TYPE_FUNCTION), /* REAL */ CT_SIMPLE(TYPE_REAL) | CT(TYPE_NUMBER), /* BUFFER */ CT_SIMPLE(TYPE_BUFFER), }; short is_type[11] = { /* UNKNOWN */ 0, /* ANY */ 0xfff, /* NOVALUE */ CT_SIMPLE(TYPE_NOVALUE) | CT(TYPE_VOID), /* VOID */ CT_SIMPLE(TYPE_VOID) | CT(TYPE_NOVALUE), /* NUMBER */ CT_SIMPLE(TYPE_NUMBER), /* STRING */ CT_SIMPLE(TYPE_STRING), /* OBJECT */ CT_SIMPLE(TYPE_OBJECT), /* MAPPING */ CT_SIMPLE(TYPE_MAPPING), /* FUNCTION */CT_SIMPLE(TYPE_FUNCTION), /* REAL */ CT_SIMPLE(TYPE_REAL), /* BUFFER */ CT_SIMPLE(TYPE_BUFFER), }; mem_block_t mem_block[NUMAREAS]; function_context_t function_context; int exact_types, global_modifiers; int current_type; int current_block; char *prog_code; char *prog_code_max; program_t NULL_program; program_t *prog; static short string_idx[0x100]; unsigned char string_tags[0x20]; short freed_string; unsigned short *type_of_locals; ident_hash_elem_t **locals; char *runtime_locals; unsigned short *type_of_locals_ptr; ident_hash_elem_t **locals_ptr; char *runtime_locals_ptr; int locals_size = 0; int type_of_locals_size = 0; int current_number_of_locals = 0; int max_num_locals = 0; #ifdef OPTIMIZE_FUNCTION_TABLE_SEARCH unsigned short a_functions_root = (unsigned short) 0xffff; #endif char *get_two_types P2(int, type1, int, type2) { static char buff[100]; strcpy(buff, "( "); strcat(buff, get_type_name(type1)); strcat(buff, "vs "); strcat(buff, get_type_name(type2)); strcat(buff, ")"); return buff; } void init_locals() { type_of_locals = CALLOCATE(MAX_LOCAL,unsigned short, TAG_LOCALS, "init_locals:1"); locals = CALLOCATE(MAX_LOCAL, ident_hash_elem_t *, TAG_LOCALS, "init_locals:2"); runtime_locals = CALLOCATE(MAX_LOCAL, char, TAG_LOCALS, "init_locals:3"); type_of_locals_ptr = type_of_locals; locals_ptr = locals; runtime_locals_ptr = runtime_locals; locals_size = type_of_locals_size = MAX_LOCAL; current_number_of_locals = max_num_locals = 0; } void free_all_local_names() { int i; for (i=0; i < current_number_of_locals; i++) { locals_ptr[i]->sem_value--; locals_ptr[i]->dn.local_num = -1; } current_number_of_locals = 0; max_num_locals = 0; } void deactivate_current_locals(){ int i; for (i = 0; i < current_number_of_locals; i++){ runtime_locals_ptr[i] = locals_ptr[i]->dn.local_num; locals_ptr[i]->dn.local_num = -1; } } void reactivate_current_locals(){ int i; for (i = 0; i < current_number_of_locals; i++){ locals_ptr[i]->dn.local_num = runtime_locals_ptr[i]; locals_ptr[i]->sem_value++; } } void clean_up_locals() { int offset; offset = locals_ptr + current_number_of_locals - locals; while (offset--){ locals[offset]->sem_value--; locals[offset]->dn.local_num = -1; } current_number_of_locals = 0; max_num_locals = 0; locals_ptr = locals; type_of_locals_ptr = type_of_locals; runtime_locals_ptr = runtime_locals; } void pop_n_locals P1(int, num) { while (num--) { locals_ptr[--current_number_of_locals]->sem_value--; locals_ptr[current_number_of_locals]->dn.local_num = -1; } } int add_local_name P2(char *, str, int, type) { if (max_num_locals == MAX_LOCAL) { yyerror("Too many local variables"); return 0; } else { ident_hash_elem_t *ihe; ihe = find_or_add_ident(str,FOA_NEEDS_MALLOC); type_of_locals_ptr[max_num_locals] = type; locals_ptr[current_number_of_locals++] = ihe; if (ihe->dn.local_num == -1) ihe->sem_value++; return ihe->dn.local_num = max_num_locals++; } } void reallocate_locals(){ int offset; offset = type_of_locals_ptr - type_of_locals; type_of_locals = RESIZE(type_of_locals, type_of_locals_size += MAX_LOCAL, unsigned short, TAG_LOCALS, "reallocate_locals:1"); type_of_locals_ptr = type_of_locals + offset; offset = locals_ptr - locals; locals = RESIZE(locals, locals_size, ident_hash_elem_t *, TAG_LOCALS, "reallocate_locals:2"); locals_ptr = locals + offset; runtime_locals = RESIZE(runtime_locals, locals_size, char, TAG_LOCALS, "reallocate_locals:3"); runtime_locals_ptr = runtime_locals + offset; } /* * Copy all variable names from the object that is inherited from. * It is very important that they are stored in the same order with the * same index. */ void copy_variables P2(program_t *, from, int, type) { int i, numvars = from->num_variables, n; variable_t *from_vars = from->variable_names; ident_hash_elem_t *ihe; int new_type; for (i = 0; (unsigned) i < numvars; i++) { new_type = type; /* * 'public' variables should not become private when inherited * 'private'. */ if (from_vars[i].type & TYPE_MOD_PUBLIC) new_type &= ~TYPE_MOD_PRIVATE; if ((ihe = lookup_ident(from->variable_names[i].name)) && ((n = ihe->dn.global_num) != -1)) { char tmp[2048]; if (VARIABLE(n)->type & TYPE_MOD_NO_MASK) { sprintf(tmp, "Illegal to redefine 'nomask' variable \"%s\"", VARIABLE(n)->name); yyerror(tmp); } } define_variable(from->variable_names[i].name, from->variable_names[i].type | new_type, from->variable_names[i].type & TYPE_MOD_PRIVATE); } } static void copy_function_details P2(function_t *, to, function_t *, from) { to->offset = from->offset; to->function_index_offset = from->function_index_offset; to->type = from->type; if (to->type & TYPE_MOD_PRIVATE) to->type |= TYPE_MOD_HIDDEN; to->num_local = from->num_local; to->num_arg = from->num_arg; to->flags = (from->flags & NAME_MASK) | NAME_DEF_BY_INHERIT | NAME_UNDEFINED; } /* copy a function verbatim into this object, and possibly add it to the list of functions in this object, as well */ static function_t *copy_function P2(function_t *, new, int, add) { function_t *ret; int num = mem_block[A_FUNCTIONS].current_size/sizeof(function_t); ident_hash_elem_t *ihe; ret = (function_t *)allocate_in_mem_block(A_FUNCTIONS, sizeof(function_t)); *ret = *new; if (ret->type & TYPE_MOD_PRIVATE) ret->type |= TYPE_MOD_HIDDEN; ref_string(new->name); /* increment ref count */ /* don't propagate certain flags forward */ ret->flags &= NAME_MASK; if (!(new->flags & NAME_UNDEFINED)) ret->flags |= NAME_DEF_BY_INHERIT; if (add) { #ifdef OPTIMIZE_FUNCTION_TABLE_SEARCH add_function((function_t *) mem_block[A_FUNCTIONS].block, &a_functions_root, num); #endif /* add the identifier */ ihe = find_or_add_ident(new->name, FOA_GLOBAL_SCOPE); if (ihe->dn.function_num == -1) ihe->sem_value++; ihe->dn.function_num = num; } return ret; } void copy_structures P1(program_t *, prog) { class_def_t *sd; class_member_entry_t *sme; ident_hash_elem_t *ihe; char *str; int sm_off = mem_block[A_CLASS_MEMBER].current_size / sizeof(class_member_entry_t); int sd_off = mem_block[A_CLASS_DEF].current_size / sizeof(class_def_t); int i, num = 0; sd = (class_def_t *)allocate_in_mem_block(A_CLASS_DEF, prog->num_classes * sizeof(class_def_t)); for (i = 0; i < prog->num_classes; i++) { sd[i].size = prog->classes[i].size; num += sd[i].size; sd[i].index = prog->classes[i].index + sm_off; str = prog->strings[prog->classes[i].name]; sd[i].name = store_prog_string(str); ihe = find_or_add_ident(str, FOA_GLOBAL_SCOPE); if (ihe->dn.class_num == -1) ihe->sem_value++; ihe->dn.class_num = i + sd_off; } sme = (class_member_entry_t *)allocate_in_mem_block(A_CLASS_MEMBER, sizeof(class_member_entry_t) * num); while (num--) { sme[num].type = prog->class_members[num].type; sme[num].name = store_prog_string(prog->strings[prog->class_members[num].name]); } } typedef struct ovlwarn_s { struct ovlwarn_s *next; char *func; char *warn; } ovlwarn_t; ovlwarn_t *overload_warnings = 0; static void remove_overload_warnings P1(char *, func) { ovlwarn_t **p; ovlwarn_t *tmp; p = &overload_warnings; while (*p) { if (!func || (*p)->func == func) { FREE((*p)->warn); tmp = *p; *p = (*p)->next; FREE(tmp); } else p = &(*p)->next; } } static void show_overload_warnings() { ovlwarn_t *p, *next; p = overload_warnings; while (p) { yywarn(p->warn); FREE(p->warn); next = p->next; FREE(p); p = next; } overload_warnings = 0; } /* Overload the function index with the new definition */ static function_t *overload_function P3(int, index, program_t *, prog, int, newindex) { function_t *funp, *alias; function_t *new; new = &prog->functions[newindex]; funp = (function_t *)mem_block[A_FUNCTIONS].block + index; /* Be careful with nomask; if both functions exists and either is nomask, we error. */ if (!(new->flags & NAME_NO_CODE) && REAL_FUNCTION(funp) && ((new->type & TYPE_MOD_NO_MASK) || (funp->type & TYPE_MOD_NO_MASK)) ) { char buf[2048]; sprintf(buf, "Illegal to redefine 'nomask' function \"%s\"", funp->name); yyerror(buf); } /* Try to prevent some confusion re: overloading. * Warn them about the behavior of inheriting the same function * from two branches. * * Note that we don't want to scream now, b/c if the function is * overloaded later this becomes irrelevant. * * Note also that this is real spammy if you inherit the same object * twice. Something should be done about that. */ if ((pragmas & PRAGMA_WARNINGS) && REAL_FUNCTION(funp) && !(new->flags & NAME_NO_CODE)) { /* don't scream if one is private. Why not? Because I said so. * private is pretty screwed up anyway. In the future there * won't be such a clash b/c private won't come up the tree. * This also give the coder a way to shut the compiler up when * you do inherit the same object twice in different branches :) */ if (!(funp->type & TYPE_MOD_PRIVATE) && !(new->type & TYPE_MOD_PRIVATE)) { char buf[1024]; char *from1 ; ovlwarn_t *ow; from1 = ((inherit_t *) mem_block[A_INHERITS].block + funp->offset)->prog->name; sprintf(buf, "%s() inherited from both %s and %s; using the definition in %s.", funp->name, from1, prog->name, prog->name); ow = ALLOCATE(ovlwarn_t, TAG_COMPILER, "overload warning"); ow->next = overload_warnings; ow->func = funp->name; ow->warn = alloc_cstring(buf, "overload warning"); overload_warnings = ow; } } /* A new function also has to be inserted, since this spot will be used when this function is called in an object beneath us. Point it at the overloaded function. */ alias = copy_function(new, 0); /* Ick! copy_functions calls allocate_in_mem_block(), so funp might be dangling now. Be safe and find it again. */ funp = (function_t *)mem_block[A_FUNCTIONS].block + index; alias->flags = NAME_ALIAS; /* offset to the real def */ alias->offset = alias - funp; /* The rule here is that the latest function wins, so if it's not defined at this level and defined in the new object, we copy it in */ if ((funp->flags & NAME_UNDEFINED) && (!(new->flags & NAME_NO_CODE))) copy_function_details(funp, new); else funp = 0; /* we aren't overloading */ return funp; } /* * Copy all function definitions from an inherited object. They are added * as undefined, so that they can be redefined by a local definition. * If they are not redefined, then they will be updated, so that they * point to the inherited definition. See epilog(). Types will be copied * at that moment (if available). * * A call to an inherited function will not be * done through this entry (because this entry can be replaced by a new * definition). If an function defined by inheritance is called, then one * special definition will be made at first call. */ int copy_functions P2(program_t *, from, int, type) { int i, initializer = -1, num_functions = from->num_functions; unsigned short tmp_short; function_t *from_funcs = from->functions; function_t *funp; int new_type; ident_hash_elem_t *ihe; int num; if (num_functions && (*from_funcs[num_functions-1].name == APPLY___INIT_SPECIAL_CHAR)){ initializer = --num_functions; } for (i = 0; i < num_functions; i++) { ihe = lookup_ident(from_funcs[i].name); if (ihe && ((num = ihe->dn.function_num)!=-1)) { /* The function has already been defined in this object */ funp = overload_function(num, from, i); } else { funp = copy_function(&from_funcs[i], 1); /* the function hasn't been defined at this level yet */ funp->flags |= NAME_UNDEFINED; } if (funp) { /* point the new function entry at the one in the inherited file, in case it's not overloaded and this becomes a real function */ funp->offset = mem_block[A_INHERITS].current_size / sizeof(inherit_t) - 1; funp->function_index_offset = i; #ifdef PROFILE_FUNCTIONS funp->calls = 0L; funp->self = 0L; funp->children = 0L; #endif /* * public functions should not become private when inherited * 'private' */ new_type = type; if (funp->type & TYPE_MOD_PUBLIC) new_type &= ~TYPE_MOD_PRIVATE; funp->type |= new_type; } /* Beek - some of this stuff below belongs above where we decide * whether to copy the function or not. But this code doesn't * do anything yet anyway. * shouldn't this depend on save_types anyway? Anyway, future * work. */ /* * Copy information about the types of the arguments, if it is * available. */ tmp_short = INDEX_START_NONE; /* Presume not available. */ if (exact_types && from->type_start != 0 && from->type_start[i] != INDEX_START_NONE) { /* * They are available for function number 'i'. Copy types of * all arguments, and remember where they started. */ tmp_short = mem_block[A_ARGUMENT_TYPES].current_size / sizeof from->argument_types[0]; add_to_mem_block(A_ARGUMENT_TYPES, (char *) &from->argument_types[from->type_start[i]], sizeof(unsigned short) * from->functions[i].num_arg); } /* * Save the index where they started. Every function will have an * index where the type info of arguments starts. */ add_to_mem_block(A_ARGUMENT_INDEX, (char *) &tmp_short, sizeof tmp_short); } return initializer; } void type_error P2(char *, str, int, type) { static char buff[100]; char *p; p = get_type_name(type); if (strlen(str) + strlen(p) + 5 >= sizeof buff) { yyerror(str); } else { strcpy(buff, str); strcat(buff, ": \""); strcat(buff, p); strcat(buff, "\""); yyerror(buff); } } /* * Compare two types, and return true if they are compatible. */ int compatible_types P2(int, t1, int, t2) { #ifdef OLD_TYPE_BEHAVIOR /* The old version effectively was almost always was true */ return 1; #else t1 &= TYPE_MOD_MASK; t2 &= TYPE_MOD_MASK; if (t1 == TYPE_ANY || t2 == TYPE_ANY) return 1; if ((t1 == (TYPE_ANY | TYPE_MOD_ARRAY) && (t2 & TYPE_MOD_ARRAY))) return 1; if ((t2 == (TYPE_ANY | TYPE_MOD_ARRAY) && (t1 & TYPE_MOD_ARRAY))) return 1; if (t1 & TYPE_MOD_CLASS) return t1 == t2; if (t1 & TYPE_MOD_ARRAY) { if (!(t2 & TYPE_MOD_ARRAY)) return 0; return t1 == (TYPE_MOD_ARRAY | TYPE_ANY) || t2 == (TYPE_MOD_ARRAY | TYPE_ANY) || (t1 == t2); } else if (t2 & TYPE_MOD_ARRAY) return 0; return compatible[t1] & (1 << t2); #endif } /* * Patch a function definition of an inherited function, to what it really * should be. * The name of the function can be one of: * object::name * ::name * Where 'object' is the name of the superclass. * * Note: this function is now only used for resolving :: references */ void arrange_call_inherited P2(char *, name, parse_node_t *, node) { int i; inherit_t *ip; int num_inherits, super_length = 0; char *super_name = 0, *p, *real_name = name; char *shared_string; if (real_name[0] == ':') real_name += 2; /* There will be exactly two ':' */ else if ((p = strchr(real_name, ':'))) { super_name = name; real_name = p+2; super_length = real_name - super_name - 2; } num_inherits = mem_block[A_INHERITS].current_size / sizeof(inherit_t); /* no need to look for it unless its in the shared string table */ if ((shared_string = findstring(real_name))) { ip = (inherit_t *) mem_block[A_INHERITS].block; for (; num_inherits > 0; ip++, num_inherits--) { if (super_name) { int l = strlen(ip->prog->name); /* Including .c */ if (l - 2 < super_length) continue; if (strncmp(super_name, ip->prog->name + l - 2 -super_length, super_length) != 0 || !((l - 2 == super_length) || ((ip->prog->name + l - 3 - super_length)[0] == '/'))) continue; } #ifdef OPTIMIZE_FUNCTION_TABLE_SEARCH i = lookup_function(ip->prog->functions, ip->prog->tree_r, shared_string); if (i != -1 && !(ip->prog->functions[i].flags & NAME_UNDEFINED)) { #else for (i = 0; (unsigned) i < ip->prog->num_functions; i++) { if (ip->prog->functions[i].flags & NAME_UNDEFINED) continue; /* can use pointer compare because both are shared */ if (ip->prog->functions[i].name != shared_string) continue; #endif node->kind = NODE_CALL_2; node->v.number = F_CALL_INHERITED; node->l.number = i + ((ip - (inherit_t *) mem_block[A_INHERITS].block) << 16); node->type = ip->prog->functions[i].type; return; } } } /* if in shared string table */ { char buff[MAXLINE + 30]; sprintf(buff, "No such inherited function %.50s", name); yyerror(buff); node->kind = NODE_CALL_2; node->v.number = F_CALL_INHERITED; node->l.number = 0; node->type = TYPE_ANY; } } /* * Define a new function. Note that this function is called at least twice * for all function definitions. First as a prototype, then as the real * function. Thus, there are tests to avoid generating error messages more * than once by looking at (flags & NAME_PROTOTYPE). */ int define_new_function P5(char *, name, int, num_arg, int, num_local, int, flags, int, type) { int num; function_t fun; unsigned short argument_start_index; ident_hash_elem_t *ihe; num = (ihe = lookup_ident(name)) ? ihe->dn.function_num : -1; if (num >= 0) { function_t *funp; /* * The function was already defined. It may be one of several * reasons: * * 1. There has been a prototype. * 2. There was the same function defined by inheritance. * 3. This function has been called, but not yet defined. * 4. The function is doubly defined. * 5. A "late" prototype has been encountered. */ funp = (function_t *) (mem_block[A_FUNCTIONS].block) + num; if (!(funp->flags & NAME_UNDEFINED) && !(flags & NAME_PROTOTYPE)) { char buff[500]; sprintf(buff, "Redeclaration of function %s.", name); yyerror(buff); return num; } /* * It was either an undefined but used funtion, or an inherited * function. In both cases, we now consider this to be THE new * definition. It might also have been a prototype to an already * defined function. * * Check arguments only when types are supposed to be tested, and if * this function really has been defined already. * * 'nomask' functions may not be redefined. */ if ((funp->type & TYPE_MOD_NO_MASK) && !(funp->flags & NAME_PROTOTYPE) && !(flags & NAME_PROTOTYPE)) { char p[2048]; sprintf(p, "Illegal to redefine 'nomask' function \"%s\"", name); yyerror(p); } /* only check prototypes for matching. It shouldn't be required that overloading a function must have the same signature */ if (exact_types && (funp->flags & NAME_PROTOTYPE) && funp->type != TYPE_UNKNOWN) { int i; /* This should be changed to catch two prototypes which disagree */ if (funp->num_arg != num_arg && !(funp->type & TYPE_MOD_VARARGS) && !(flags & NAME_PROTOTYPE)) yyerror("Number of arguments disagrees with previous definition."); else if (!(funp->flags & NAME_STRICT_TYPES) && !(flags & NAME_PROTOTYPE)) yyerror("Called function not compiled with type testing."); else { /* Now check that argument types wasn't changed. */ if ((type & TYPE_MOD_MASK) != (funp->type & TYPE_MOD_MASK)) { char buff[200]; sprintf(buff, "Return type doesn't match prototype %s", get_two_types(type, funp->type)); yywarn(buff); } for (i = 0; i < num_arg; i++) { /* FIXME: check arg types here */ } } } /* If it was yet another prototype, then simply return. */ if (flags & NAME_PROTOTYPE) { return num; } if (pragmas & PRAGMA_WARNINGS) remove_overload_warnings(funp->name); funp->num_arg = num_arg; funp->num_local = num_local; funp->flags = flags; funp->offset = 0; funp->function_index_offset = 0; funp->type = type; if (exact_types) funp->flags |= NAME_STRICT_TYPES; return num; } fun.name = make_shared_string(name); fun.offset = 0; fun.flags = flags; fun.num_arg = num_arg; fun.num_local = num_local; fun.function_index_offset = 0; fun.type = type; #ifdef PROFILE_FUNCTIONS fun.calls = 0L; fun.self = 0L; fun.children = 0L; #endif if (exact_types) fun.flags |= NAME_STRICT_TYPES; num = mem_block[A_FUNCTIONS].current_size / sizeof fun; /* Number of local variables will be updated later */ add_to_mem_block(A_FUNCTIONS, (char *) &fun, sizeof fun); #ifdef OPTIMIZE_FUNCTION_TABLE_SEARCH add_function((function_t *) mem_block[A_FUNCTIONS].block, &a_functions_root, num); #endif if (exact_types == 0 || num_arg == 0) { argument_start_index = INDEX_START_NONE; } else { int i; /* * Save the start of argument types. */ argument_start_index = mem_block[A_ARGUMENT_TYPES].current_size / sizeof(unsigned short); for (i = 0; i < num_arg; i++) { add_to_mem_block(A_ARGUMENT_TYPES, (char *) &type_of_locals_ptr[i], sizeof type_of_locals_ptr[i]); } } add_to_mem_block(A_ARGUMENT_INDEX, (char *) &argument_start_index, sizeof argument_start_index); ihe = find_or_add_ident(fun.name, FOA_GLOBAL_SCOPE); if (ihe->dn.function_num == -1) ihe->sem_value++; ihe->dn.function_num = num; return num; } int define_variable P3(char *, name, int, type, int, hide) { variable_t *dummy; int n; char *str; ident_hash_elem_t *ihe; str = make_shared_string(name); n = (mem_block[A_VARIABLES].current_size / sizeof(variable_t)); ihe = find_or_add_ident(str, FOA_GLOBAL_SCOPE); if (ihe->dn.global_num == -1) { ihe->sem_value++; ihe->dn.global_num = n; } else { if (VARIABLE(ihe->dn.global_num)->type & TYPE_MOD_NO_MASK) { char p[2048]; sprintf(p, "Illegal to redefine 'nomask' variable \"%s\"", name); yyerror(p); } /* Okay, the nasty idiots have two variables of the same name in the same object. This causes headaches for save_object(). To keep save_object sane, we need to make one static */ if (!(type & TYPE_MOD_STATIC)) { /* this one isn't static, make the other one static */ VARIABLE(ihe->dn.global_num)->type |= TYPE_MOD_STATIC; } /* hidden variables don't cause variables that are visible to become invisible; we only add them above (in the !hide case) for better error messages */ if (!hide) ihe->dn.global_num = n; } dummy = (variable_t *)allocate_in_mem_block(A_VARIABLES,sizeof(variable_t)); dummy->name = str; dummy->type = type; if (hide) dummy->type |= TYPE_MOD_HIDDEN; return n; } char *compiler_type_names[] = {"unknown", "mixed", "void", "void", "int", "string", "object", "mapping", "function", "float", "buffer" }; char *get_type_name P1(int, type) { static char buff[100]; int pointer = 0; buff[0] = 0; if (type & TYPE_MOD_STATIC) strcat(buff, "static "); if (type & TYPE_MOD_NO_MASK) strcat(buff, "nomask "); if (type & TYPE_MOD_PRIVATE) strcat(buff, "private "); if (type & TYPE_MOD_PROTECTED) strcat(buff, "protected "); if (type & TYPE_MOD_PUBLIC) strcat(buff, "public "); if (type & TYPE_MOD_VARARGS) strcat(buff, "varargs "); type &= TYPE_MOD_MASK; if (type & TYPE_MOD_ARRAY) { pointer = 1; type &= ~TYPE_MOD_ARRAY; } if (type & TYPE_MOD_CLASS) { strcat(buff, "class "); strcat(buff, PROG_STRING(CLASS(type & ~TYPE_MOD_CLASS)->name)); } else { DEBUG_CHECK(type >= sizeof compiler_type_names / sizeof compiler_type_names[0], "Bad type\n"); strcat(buff, compiler_type_names[type]); } strcat(buff, " "); if (pointer) strcat(buff, "* "); return buff; } #define STRING_HASH(var,str) \ var = (long)str ^ (long)str >> 16; \ var = (var ^ var >> 8) & 0xff; short store_prog_string P1(char *, str) { short i, next, *next_tab, *idxp; char **p; unsigned char hash, mask, *tagp; str = make_shared_string(str); STRING_HASH(hash, str); idxp = &string_idx[hash]; /* string_tags is a big bit-array, so find correct bit */ mask = 1 << (hash & 7); tagp = &string_tags[hash >> 3]; p = (char **)&PROG_STRING(0); next_tab = (short *) mem_block[A_STRING_NEXT].block; if (*tagp & mask) { /* search hash chain to see if it's there */ for (i = *idxp; i >= 0; i = next_tab[i]) { if (p[i] == str) { free_string(str); /* needed as string is only free'ed * once. */ ((short *) mem_block[A_STRING_REFS].block)[i]++; return i; } } next = *idxp; } else { *tagp |= mask; next = -1; } /* * New string, add to table */ if (freed_string >= 0) { /* reuse freed string */ int top; i = freed_string; top = mem_block[A_STRINGS].current_size / sizeof str; for (freed_string++; freed_string < top; freed_string++) { if (p[freed_string] == 0) break; } if (freed_string >= top) freed_string = -1; } else { /* grow by one element. */ add_to_mem_block(A_STRINGS, 0, sizeof str); add_to_mem_block(A_STRING_NEXT, 0, sizeof(short)); add_to_mem_block(A_STRING_REFS, 0, sizeof(short)); /* test if number of strings isn't too large ? */ i = mem_block[A_STRINGS].current_size / sizeof str - 1; } PROG_STRING(i) = str; ((short *) mem_block[A_STRING_NEXT].block)[i] = next; ((short *) mem_block[A_STRING_REFS].block)[i] = 1; *idxp = i; return i; } void free_prog_string P1(short, num) { short i, prv, *next_tab, top, *idxp; char **p, *str; unsigned char hash, mask; top = mem_block[A_STRINGS].current_size / sizeof(char *) - 1; if (num < 0 || num > top) { yyerror("free_prog_string: index out of range.\n"); return; } if (--((short *) mem_block[A_STRING_REFS].block)[num] >= 1) return; p = (char **) mem_block[A_STRINGS].block; next_tab = (short *) mem_block[A_STRING_NEXT].block; str = p[num]; STRING_HASH(hash, str); idxp = &string_idx[hash]; for (prv = -1, i = *idxp; i != num; prv = i, i = next_tab[i]) { if (i == -1) { yyerror("free_prog_string: string not in prog table.\n"); return; } } if (prv == -1) { /* string is head of list */ *idxp = next_tab[i]; if (*idxp == -1) { /* clear tag bit since hash chain now empty */ mask = 1 << (hash & 7); string_tags[hash >> 3] &= ~mask; } } else { /* easy unlink */ next_tab[prv] = next_tab[i]; } free_string(str); /* important */ p[i] = 0; if (i != top) { if (i < freed_string || freed_string == -1) freed_string = i; } else { /* shrink table */ mem_block[A_STRINGS].current_size -= sizeof str; mem_block[A_STRING_REFS].current_size -= sizeof(short); mem_block[A_STRING_NEXT].current_size -= sizeof(short); } } int validate_function_call P3(function_t *, funp, int, f, parse_node_t *, args) { int num_arg = ( args ? args->kind : 0 ); int num_var = 0; parse_node_t *pn = args; while (pn) { if (pn->type & 1) num_var++; pn = pn->r.expr; } /* * Verify that the function has been defined already. */ if ((funp->flags & NAME_UNDEFINED) && !(funp->flags & (NAME_PROTOTYPE | NAME_DEF_BY_INHERIT)) && exact_types) { char buff[256]; sprintf(buff, "Function %.50s undefined", funp->name); yyerror(buff); } /* * Check number of arguments. */ if (!(funp->type & TYPE_MOD_VARARGS) && (funp->flags & NAME_STRICT_TYPES) && exact_types) { char buff[100]; if (num_var) { sprintf(buff, "Illegal to pass a variable number of arguments to non-varargs function %.60s\n", funp->name); yyerror(buff); } else if (funp->num_arg != num_arg) { sprintf(buff, "Wrong number of arguments to %.60s\n Expected: %d Got: %d", funp->name, funp->num_arg, num_arg); yyerror(buff); } } /* * Check the argument types. */ if (exact_types && *(unsigned short *) &mem_block[A_ARGUMENT_INDEX].block[f * sizeof(unsigned short)] != INDEX_START_NONE) { int i, first, tmp; unsigned short *arg_types; parse_node_t *enode = args; arg_types = (unsigned short *) mem_block[A_ARGUMENT_TYPES].block; first = *(unsigned short *) &mem_block[A_ARGUMENT_INDEX].block[f * sizeof(unsigned short)]; for (i = 0; (unsigned) i < funp->num_arg && i < num_arg; i++) { if (enode->type & 1) break; tmp = enode->v.expr->type; if (!compatible_types(tmp, arg_types[first + i])) { char buff[100]; sprintf(buff, "Bad type for argument %d %s", i + 1, get_two_types(arg_types[first + i], tmp)); yyerror(buff); } enode = enode->r.expr; } } return funp->type & TYPE_MOD_MASK; } parse_node_t * promote_to_float P1(parse_node_t *, node) { parse_node_t *expr; if (node->kind == NODE_NUMBER) { node->kind = NODE_REAL; node->v.real = node->v.number; return node; } expr = new_node(); expr->kind = NODE_EFUN; expr->v.number = F_TO_FLOAT; expr->type = TYPE_REAL; expr->l.number = 1; expr->r.expr = new_node_no_line(); expr->r.expr->kind = 1; expr->r.expr->l.expr = expr->r.expr; expr->r.expr->type = 0; expr->r.expr->v.expr = node; expr->r.expr->r.expr = 0; return expr; } parse_node_t * promote_to_int P1(parse_node_t *, node) { parse_node_t *expr; if (node->kind == NODE_REAL) { node->kind = NODE_NUMBER; node->v.number = node->v.real; return node; } expr = new_node(); expr->kind = NODE_EFUN; expr->v.number = F_TO_INT; expr->type = TYPE_NUMBER; expr->l.number = 1; expr->r.expr = new_node_no_line(); expr->r.expr->kind = 1; expr->r.expr->l.expr = expr->r.expr; expr->r.expr->type = 0; expr->r.expr->v.expr = node; expr->r.expr->r.expr = 0; return expr; } parse_node_t *do_promotions P2(parse_node_t *, node, int, type) { if (type == TYPE_REAL) { if (node->type == TYPE_NUMBER || node->kind == NODE_NUMBER) return promote_to_float(node); } if (type == TYPE_NUMBER && node->type == TYPE_REAL) return promote_to_int(node); return node; } /* Take a NODE_CALL, and discard the call, preserving only the args with side effects */ parse_node_t * throw_away_call P1(parse_node_t *, pn) { parse_node_t *enode; parse_node_t *ret = 0; parse_node_t *arg; enode = pn->r.expr; while (enode) { arg = insert_pop_value(enode->v.expr); if (arg) { /* woops. Don't lose the side effect. */ if (ret) { parse_node_t *tmp; CREATE_STATEMENTS(tmp, ret, arg); ret = tmp; } else { ret = arg; } } enode = enode->r.expr; } return ret; } parse_node_t * throw_away_mapping P1(parse_node_t *, pn) { parse_node_t *enode; parse_node_t *ret = 0; parse_node_t *arg; enode = pn->r.expr; while (enode) { arg = insert_pop_value(enode->v.expr->l.expr); if (arg) { /* woops. Don't lose the side effect. */ if (ret) { parse_node_t *tmp; CREATE_STATEMENTS(tmp, ret, arg); ret = tmp; } else { ret = arg; } } arg = insert_pop_value(enode->v.expr->r.expr); if (arg) { /* woops. Don't lose the side effect. */ if (ret) { parse_node_t *tmp; CREATE_STATEMENTS(tmp, ret, arg); ret = tmp; } else { ret = arg; } } enode = enode->r.expr; } return ret; } parse_node_t * validate_efun_call P2(int, f, parse_node_t *, args) { int num = args->v.number; int min_arg, max_arg, def, *argp; int num_var = 0; parse_node_t *pn = args->r.expr; while (pn) { if (pn->type & 1) num_var++; pn = pn->r.expr; } if (f != -1) { /* should this move out of here? */ switch (predefs[f].token) { case F_SIZEOF: /* Obscene crap like: sizeof( ({ 1, i++, x + 1, foo() }) ) * -> i++, foo(), 4 */ if (!pn && num == 1 && IS_NODE(args->r.expr->v.expr, NODE_CALL, F_AGGREGATE)) { parse_node_t *repl, *ret, *node; CREATE_NUMBER(node, args->r.expr->v.expr->l.number); ret = throw_away_call(args->r.expr->v.expr); CREATE_TWO_VALUES(repl, TYPE_NUMBER, ret, node); return repl; } } min_arg = predefs[f].min_args; max_arg = predefs[f].max_args; def = predefs[f].Default; if (!num_var && def != DEFAULT_NONE && num == min_arg -1) { parse_node_t *tmp; tmp = new_node_no_line(); tmp->r.expr = 0; tmp->type = 0; args->l.expr->r.expr = tmp; if (def == DEFAULT_THIS_OBJECT) { tmp->v.expr = new_node_no_line(); tmp->v.expr->kind = NODE_EFUN; tmp->v.expr->v.number = F_THIS_OBJECT; tmp->v.expr->l.number = 0; tmp->v.expr->type = TYPE_ANY; tmp->v.expr->r.expr = 0; } else { CREATE_NUMBER(tmp->v.expr, def); } args->v.number++; num++; } else if (num_var && max_arg != -1) { char bff[100]; sprintf(bff, "Illegal to pass variable number of arguments to non-varargs efun %s", predefs[f].word); yyerror(bff); return args; } else if ((num - num_var) < min_arg) { char bff[100]; sprintf(bff, "Too few arguments to %s", predefs[f].word); yyerror(bff); return args; } else if (num > max_arg && max_arg != -1) { char bff[100]; sprintf(bff, "Too many arguments to %s", predefs[f].word); yyerror(bff); return args; } if (max_arg != -1 && exact_types) { /* * Now check all types of arguments to efuns. */ int i, argn, tmp; char buff[100]; parse_node_t *enode = args; argp = &efun_arg_types[predefs[f].arg_index]; for (argn = 0; argn < num; argn++) { enode = enode->r.expr; if (enode->type & 1) break; /* this can happen for default args */ if (!enode->v.expr) break; tmp = enode->v.expr->type; for (i=0; !compatible_types(argp[i], tmp) && argp[i] != 0; i++) ; if (argp[i] == 0) { sprintf(buff, "Bad argument %d to efun %s()", argn+1, predefs[f].word); yyerror(buff); } else { /* check for (int) -> (float) promotion */ if (tmp == TYPE_NUMBER && argp[i] == TYPE_REAL) { for (i++; argp[i] && argp[i] != TYPE_NUMBER; i++) ; if (!argp[i]) enode->v.expr = promote_to_float(enode->v.expr); } else if (tmp == TYPE_REAL && argp[i] == TYPE_NUMBER) { for (i++; argp[i] && argp[i] != TYPE_REAL; i++) ; if (!argp[i]) enode->v.expr = promote_to_int(enode->v.expr); } } while (argp[i] != 0) i++; argp += i + 1; } } args->l.number = num; args->v.number = predefs[f].token; args->type = predefs[f].ret_type; if (args->type == TYPE_NOVALUE) { args->v.number += NOVALUE_USED_FLAG; args->type = TYPE_VOID; } args->kind = NODE_EFUN; } else { CREATE_ERROR(args); } return args; } /* * Initialization code is now more compact. It's collected in * A_INITIALIZER and put at the end of the program. For compatibility, * there is a jump to it at address 0. */ void switch_to_block P1(int, block) { UPDATE_PROGRAM_SIZE; prog_code = mem_block[block].block + mem_block[block].current_size; prog_code_max = mem_block[block].block + mem_block[block].max_size; current_block = block; } void yyerror P1(char *, str) { extern int num_parse_error; function_context.num_parameters = -1; if (num_parse_error > 5) return; smart_log(current_file, current_line, str, 0); #ifdef PACKAGE_MUDLIB_STATS add_errors_for_file (current_file, 1); #endif num_parse_error++; } void yywarn P1(char *, str) { if (!(pragmas & PRAGMA_WARNINGS)) return; smart_log(current_file, current_line, str, 1); } /* * Compile an LPC file. */ void compile_file P2(int, f, char *, name) { int yyparse PROT((void)); prolog(f, name); yyparse(); epilog(); } int get_id_number() { static int current_id_number = 1; return current_id_number++; } INLINE void copy_in P2(int, which, char **, start) { char *block; int size; size = mem_block[which].current_size; if (!size) return; block = mem_block[which].block; memcpy(*start, block, size); *start += align(size); } /* * The program has been compiled. Prepare a 'program_t' to be returned. */ static void epilog() { int size, i, lnsz, lnoff; char *p; function_t *funp; ident_hash_elem_t *ihe; /* don't need the parse trees any more */ release_tree(); if (num_parse_error > 0 || inherit_file) { /* don't print these; they can be wrong, since we didn't parse the entire file */ if (pragmas & PRAGMA_WARNINGS) remove_overload_warnings(0); clean_parser(); end_new_file(); free_string(current_file); current_file = 0; return; } if (pragmas & PRAGMA_WARNINGS) show_overload_warnings(); /* * Define the __INIT function, but only if there was any code * to initialize. */ UPDATE_PROGRAM_SIZE; if (mem_block[A_INITIALIZER].current_size) { parse_node_t *pn; int fun; /* end the __INIT function */ switch_to_block(A_INITIALIZER); CREATE_RETURN(pn, 0); generate(pn); switch_to_block(A_PROGRAM); fun = define_new_function(APPLY___INIT, 0, 0, NAME_STRICT_TYPES, TYPE_VOID | TYPE_MOD_PRIVATE); FUNCTION(fun)->offset = CURRENT_PROGRAM_SIZE; generate___INIT(); } generate_final_program(0); UPDATE_PROGRAM_SIZE; /* * If functions are undefined, replace them by definitions done * by inheritance. All explicit "name::func" are already resolved. * Also replace aliases with the updated info. We use aliases * so that only one function definition has to be fooled with for * overloading during compile time, but here we want to make sure * they're all the same again. */ for (i = 0; i < mem_block[A_FUNCTIONS].current_size; i += sizeof *funp) { funp = (function_t *)(mem_block[A_FUNCTIONS].block + i); if ((funp->flags & NAME_UNDEFINED) && (funp->flags & NAME_DEF_BY_INHERIT)) funp->flags = (funp->flags & ~NAME_UNDEFINED) | NAME_INHERITED; if (funp->flags & NAME_ALIAS) { *funp = *(funp - funp->offset); funp->flags |= NAME_ALIAS; } } generate_final_program(1); size = align(sizeof (program_t)); /* delete argument information if we're not saving it */ if (!(pragmas & PRAGMA_SAVE_TYPES)) mem_block[A_ARGUMENT_TYPES].current_size = 0; if (!(mem_block[A_ARGUMENT_TYPES].current_size)) mem_block[A_ARGUMENT_INDEX].current_size = 0; for (i=0; i<NUMPAREAS; i++) if (i != A_LINENUMBERS) size += align(mem_block[i].current_size); p = (char *)DXALLOC(size, TAG_PROGRAM, "epilog: 1"); prog = (program_t *)p; *prog = NULL_program; prog->total_size = size; prog->ref = 0; prog->func_ref = 0; ihe = lookup_ident("heart_beat"); prog->heart_beat = (ihe ? ihe->dn.function_num : -1); prog->name = current_file; current_file = 0; prog->id_number = get_id_number(); total_prog_block_size += prog->total_size; total_num_prog_blocks += 1; #ifdef OPTIMIZE_FUNCTION_TABLE_SEARCH prog->tree_r = a_functions_root; #endif prog->line_swap_index = -1; /* Format is now: * <short total size> <short line_info_offset> <file info> <line info> */ lnoff = 2 + (mem_block[A_FILE_INFO].current_size / sizeof(short)); lnsz = lnoff * sizeof(short) + mem_block[A_LINENUMBERS].current_size; prog->file_info = (unsigned short *)DXALLOC(lnsz, TAG_LINENUMBERS , "epilog"); prog->file_info[0] = (unsigned short)lnsz; prog->file_info[1] = (unsigned short)lnoff; memcpy(((char*)&prog->file_info[2]), mem_block[A_FILE_INFO].block, mem_block[A_FILE_INFO].current_size); prog->line_info = (unsigned char *)(&prog->file_info[lnoff]); memcpy(((char*)&prog->file_info[lnoff]), mem_block[A_LINENUMBERS].block, mem_block[A_LINENUMBERS].current_size); p += align(sizeof (program_t)); prog->program = p; prog->program_size = mem_block[A_PROGRAM].current_size; copy_in(A_PROGRAM, &p); prog->functions = (function_t *)p; prog->num_functions = mem_block[A_FUNCTIONS].current_size / sizeof (function_t); copy_in(A_FUNCTIONS, &p); prog->classes = (class_def_t *)p; prog->num_classes = mem_block[A_CLASS_DEF].current_size / sizeof (class_def_t); copy_in(A_CLASS_DEF, &p); prog->class_members = (class_member_entry_t *)p; copy_in(A_CLASS_MEMBER, &p); prog->strings = (char **)p; prog->num_strings = mem_block[A_STRINGS].current_size / sizeof (char *); copy_in(A_STRINGS, &p); prog->variable_names = (variable_t *)p; prog->num_variables = mem_block[A_VARIABLES].current_size / sizeof (variable_t); copy_in(A_VARIABLES, &p); prog->num_inherited = mem_block[A_INHERITS].current_size / sizeof (inherit_t); if (prog->num_inherited) { prog->inherit = (inherit_t *)p; copy_in(A_INHERITS, &p); } else prog->inherit = 0; if (mem_block[A_ARGUMENT_TYPES].current_size) { prog->argument_types = (unsigned short *) p; copy_in(A_ARGUMENT_TYPES, &p); prog->type_start = (unsigned short *) p; copy_in(A_ARGUMENT_INDEX, &p); } else { prog->argument_types = 0; prog->type_start = 0; } #ifdef BINARIES if ((pragmas & PRAGMA_SAVE_BINARY) #ifdef LPC_TO_C || compile_to_c #endif ) { save_binary(prog, &mem_block[A_INCLUDES], &mem_block[A_PATCH]); } #endif swap_line_numbers(prog); /* do this after saving binary */ for (i=0; i<NUMAREAS; i++) FREE((char *)mem_block[i].block); /* marion Do referencing here - avoid multiple referencing when an object inherits more than one object and one of the inherited is already loaded and not the last inherited */ reference_prog (prog, "epilog"); for (i = 0; (unsigned)i < prog->num_inherited; i++) { reference_prog (prog->inherit[i].prog, "inheritance"); } scratch_destroy(); clean_up_locals(); free_unused_identifiers(); end_new_file(); } /* * Initialize the environment that the compiler needs. */ static void prolog P2(int, f, char *, name) { int i; function_context.num_parameters = -1; prog = 0; /* 0 means fail to load. */ num_parse_error = 0; global_modifiers = 0; #ifdef OPTIMIZE_FUNCTION_TABLE_SEARCH a_functions_root = (unsigned short)0xffff; #endif /* Initialize memory blocks where the result of the compilation * will be stored. */ for (i=0; i < NUMAREAS; i++) { mem_block[i].block = DXALLOC(START_BLOCK_SIZE, TAG_COMPILER, "prolog: 2"); mem_block[i].current_size = 0; mem_block[i].max_size = START_BLOCK_SIZE; } memset(string_tags, 0, sizeof(string_tags)); freed_string = -1; initialize_parser(); current_file = make_shared_string(name); current_file_id = add_program_file(name, 1); start_new_file(f); } /* * The program has errors, clean things up. */ static void clean_parser() { int i; function_t *funp; variable_t dummy; char *s; /* * Free function stuff. */ for (i = 0; i < mem_block[A_FUNCTIONS].current_size; i += sizeof *funp) { funp = (function_t *)(mem_block[A_FUNCTIONS].block + i); if (funp->name) free_string(funp->name); } for (i = 0; i < mem_block[A_STRINGS].current_size; i += sizeof(char *)) { COPY_PTR(&s, mem_block[A_STRINGS].block + i); free_string(s); } for (i = 0; i < mem_block[A_VARIABLES].current_size; i += sizeof dummy) { memcpy(&dummy, mem_block[A_VARIABLES].block + i, sizeof dummy); free_string(dummy.name); } prog = 0; for (i=0; i<NUMAREAS; i++) FREE(mem_block[i].block); clean_up_locals(); scratch_destroy(); free_unused_identifiers(); } char * the_file_name P1(char *, name) { char *tmp; int len; len = strlen(name); if (len < 3) { return string_copy(name, "the_file_name"); } tmp = new_string(len - 1, "the_file_name"); if (!tmp) { return string_copy(name, "the_file_name"); } tmp[0] = '/'; strncpy(tmp + 1, name, len - 2); tmp[len - 1] = '\0'; return tmp; } int case_compare P2(parse_node_t **, c1, parse_node_t **, c2) { if ((*c1)->kind == NODE_DEFAULT) return -1; if ((*c2)->kind == NODE_DEFAULT) return 1; return ((*c1)->r.number - (*c2)->r.number); } int string_case_compare P2(parse_node_t **, c1, parse_node_t **, c2) { int i1, i2; char *p1, *p2; if ((*c1)->kind == NODE_DEFAULT) return -1; if ((*c2)->kind == NODE_DEFAULT) return 1; i1 = (*c1)->r.number; i2 = (*c2)->r.number; p1 = (i1 ? PROG_STRING(i1) : 0); p2 = (i2 ? PROG_STRING(i2) : 0); return (p1 - p2); } void prepare_cases P2(parse_node_t *, pn, int, start) { parse_node_t **ce_start, **ce_end, **ce; int end, last_key, this_key; int direct = 1; ce_start = (parse_node_t **)&mem_block[A_CASES].block[start]; end = mem_block[A_CASES].current_size; ce_end = (parse_node_t **)&mem_block[A_CASES].block[end]; if (ce_start == ce_end) { /* no cases */ pn->v.expr = 0; mem_block[A_CASES].current_size = start; return; } if (pn->kind == NODE_SWITCH_STRINGS) quickSort((char *)ce_start, ce_end - ce_start, sizeof(parse_node_t *), string_case_compare); else quickSort((char *)ce_start, ce_end - ce_start, sizeof(parse_node_t *), case_compare); ce = ce_start; if ((*ce)->kind == NODE_DEFAULT) { if (ce + 1 == ce_end) { /* only a default */ pn->v.expr = *ce; (*ce)->l.expr = 0; mem_block[A_CASES].current_size = start; return; } ce++; (*(ce-1))->l.expr = *ce; } if ((*ce)->v.expr) { last_key = (*ce)->v.expr->r.number; direct = 0; } else last_key = (*ce)->r.number; ce++; while (ce < ce_end) { this_key = (*ce)->r.number; if (pn->kind == NODE_SWITCH_RANGES && this_key <= last_key) { char buf[1024]; char *f1, *f2; int fi1, fi2; int l1, l2; /* make sure line numbers exist for the cases */ save_file_info(current_file_id, current_line - current_line_saved); current_line_saved = current_line; translate_absolute_line((*ce)->line, (unsigned short *)mem_block[A_FILE_INFO].block, &fi1, &l1); translate_absolute_line((*(ce-1))->line, (unsigned short *)mem_block[A_FILE_INFO].block, &fi2, &l2); f1 = PROG_STRING(fi1); f2 = PROG_STRING(fi2); sprintf(buf, "Overlapping cases: %s%s%d and %s%s%d.", f1 ? f1 : "", f1 ? ":" : "line ", l1, f2 ? f2 : "", f2 ? ":" : "line ", l2); yyerror(buf); } (*(ce-1))->l.expr = *ce; if ((*ce)->v.expr) { last_key = (*ce)->v.expr->r.number; direct = 0; } else { if (last_key + 1 != this_key) direct = 0; last_key = this_key; } ce++; } (*(ce_end-1))->l.expr = 0; if (direct && pn->kind == NODE_SWITCH_NUMBERS) pn->kind = NODE_SWITCH_DIRECT; pn->v.expr = *(ce_start); mem_block[A_CASES].current_size = start; } void save_file_info P2(int, file_id, int, lines) { short fi[2]; fi[0] = lines; fi[1] = file_id; add_to_mem_block(A_FILE_INFO, (char *)&fi[0], sizeof(fi)); } int add_program_file P2(char *, name, int, top) { if (!top) add_to_mem_block(A_INCLUDES, name, strlen(name)+1); return store_prog_string(name) + 1; }