/* * RscAddCallback: Called for each new resource that's loaded from a file. * Add given resource to table. */ bool RscAddCallback(char *fname, int res, int lang_id, char *string) { resource_type r; // Check for existing resource first, since we might want to add // another language string to it. r = (resource_type) table_lookup(t, &res, IdHash, IdResourceCompare); if (r == NULL) { r = (resource_type) SafeMalloc(sizeof(resource_struct)); r->idnum = res; for (int i = 0; i < MAX_LANGUAGE_ID; i++) r->resource[i] = NULL; } else table_delete_item(t, r, ResourceHash, ResourceCompare); // Shouldn't be able to compile blakod with multiple strings // of the same language type. if (r->resource[lang_id]) SafeFree(r->resource[lang_id]); r->resource[lang_id] = (char *) SafeMalloc(strlen(string) + 1); strcpy(r->resource[lang_id], string); available_languages[lang_id] = True; // Replace the existing resource if we used it. table_insert(t, r, ResourceHash, ResourceCompare); return true; }
/* * RscAddCallback: Called for each new resource that's loaded from a file. * Add given resource to table. */ bool RscAddCallback(char *fname, int res, char *string) { resource_type entry, r; entry = (resource_type) SafeMalloc(sizeof(resource_struct)); entry->idnum = res; entry->data = (char *) SafeMalloc(strlen(string) + 1); strcpy(entry->data, string); if (table_insert(t, entry, ResourceHash, ResourceCompare) != 0) { if (!ignore_duplicates) { ClientError(hInst, hMain, IDS_DUPRESOURCE, res, fname); FreeRsc(entry); } else { // Free existing resource r = (resource_type) table_lookup(t, &res, IdHash, IdResourceCompare); if (r != NULL) { table_delete_item(t, r, ResourceHash, ResourceCompare); FreeRsc(r); table_insert(t, entry, ResourceHash, ResourceCompare); } } } return true; }
param_type make_parameter(id_type id, expr_type e) { param_type p = (param_type) SafeMalloc(sizeof(param_struct)); if (e->type != E_CONSTANT) { action_error("Parameter can only be initialized to a constant"); return p; } lookup_id(id); /* Left-hand side must not have appeared before, except perhaps as a parameter */ switch (id->type) { case I_MISSING: /* The parameter has been referenced in a function call, but not declared anywhere * We should use the existent id # and remove the id from the missing list. * First we must make sure that the missing id is supposed to be a missing parameter. */ if (id->source != I_PARAMETER) { action_error("Parameter %s was referenced elsewhere with different type", id->name); break; } /* Insert directly into global table to preserve id # */ id->type = I_PARAMETER; id->source = COMPILE; table_insert(st.globalvars, (void *) id, id_hash, id_compare); /* Remove from missing list */ table_delete_item(st.missingvars, id, id_hash, id_compare); break; case I_UNDEFINED: /* New parameter # */ id->ownernum = st.curmessage; add_identifier(id, I_PARAMETER); break; case I_PARAMETER: /* Legal only if it hasn't yet appeared in this message */ if (id->ownernum == st.curmessage && id->source == COMPILE) action_error("Parameter %s appears twice", id->name); break; default: /* Other types indicate name already used */ action_error("Duplicate identifier %s", id->name); } p->lhs = id; p->rhs = e->value.constval; return p; }
void ChangeResource(ID res, char *value) { resource_type r, entry; // debug(("got new resource %d, type = %d, value = %s\n", res, type, value)); r = (resource_type) table_lookup(t, &res, IdHash, IdResourceCompare); if (r != NULL) { table_delete_item(t, r, ResourceHash, ResourceCompare); FreeRsc(r); } entry = (resource_type) SafeMalloc(sizeof(resource_struct)); entry->data = (char *) SafeMalloc(strlen(value) + 1); strcpy(entry->data, value); entry->idnum = res; table_insert(t, entry, ResourceHash, ResourceCompare); }
property_type make_property(id_type id, expr_type e) { property_type p = (property_type) SafeMalloc(sizeof(property_struct)); if (e->type != E_CONSTANT) { action_error("Property can only be initialized to a constant"); return p; } /* Left-hand side must not have appeared as a property before, except possibly as a * property of one of our superclasses. Properties shadow other global names. */ lookup_id(id); switch(id->type) { case I_CONSTANT: action_error("Duplicate identifier %s", id->name); break; /* Legal if it hasn't yet appeared in this class */ case I_PROPERTY: if (id->ownernum == st.curclass && id->source == COMPILE) action_error("Property %s appears twice", id->name); else { id->ownernum = st.curclass; id->source = COMPILE; add_identifier(id, I_PROPERTY); } break; case I_CLASSVAR: if (id->ownernum == st.curclass && id->source == COMPILE) action_error("Property and classvar %s both appear in same class\n", id->name); else { classvar_type new_cv; id_type new_id; const_type new_const; // Override classvar with special tag value new_cv = (classvar_type) SafeMalloc(sizeof(classvar_struct)); new_const = (const_type) SafeMalloc(sizeof(const_struct)); new_id = duplicate_id(id); new_cv->id = new_id; new_cv->rhs = new_const; new_id->ownernum = st.curclass; new_id->source = COMPILE; new_const->type = C_OVERRIDE; // Replace classvar with property in table table_delete_item(st.classvars, id, id_hash, id_compare); id->ownernum = st.curclass; id->source = COMPILE; add_identifier(id, I_PROPERTY); // Store # of property in class var new_const->value.numval = id->idnum; st.override_classvars = list_add_item(st.override_classvars, new_cv); } break; default: id->source = COMPILE; id->ownernum = st.curclass; add_identifier(id, I_PROPERTY); break; } p->id = id; p->rhs = e->value.constval; return p; }
class_type make_class_signature(id_type class_id, id_type superclass_id) { list_type l; id_type old_id; class_type c = (class_type) SafeMalloc(sizeof(class_struct)); c->superclass = NULL; /* Will be set for real below */ c->class_id = class_id; /* Class name must not have appeared before */ old_id = lookup_id(class_id); switch(class_id->type) { case I_MISSING: /* The class has been referenced in a function call, but not declared anywhere * We should use the existent class # and remove the id from the missing list */ if (class_id->source != I_CLASS) { action_error("Class %s was referenced elsewhere with different type", class_id->name); break; } /* Insert directly into global table to preserve id # */ class_id->type = I_CLASS; class_id->source = COMPILE; table_insert(st.globalvars, (void *) class_id, id_hash, id_compare); /* Remove from missing list */ table_delete_item(st.missingvars, class_id, id_hash, id_compare); break; case I_UNDEFINED: /* New class name--continue normally */ add_identifier(class_id, I_CLASS); break; case I_CLASS: /* We are recompiling a previously existing class. This is rather ugly, since * we want to replace all the old class's data with our new data. However, to give * previously compiled subclasses a chance of working with the new version, we * should try to match class numbers, message #s, etc. with the old class. * At this point, all the old class's data have been inserted into our hash * tables. The new class will be inserted into st.globalvars. We must remove the old class * from the class list. */ /* If class is given twice in source files, that's an error */ if (class_id->source == COMPILE) action_error("Class %s is given twice", class_id->name); else /* Change the existent class id to reflect the fact that the class has now * been recompiled. */ old_id->source = COMPILE; class_id->source = COMPILE; /* Delete self from list of existent classes. Give warnings for subclasses. */ for (l = st.classes; l != NULL; l = l->next) if (is_parent(c, (class_type) l->data)) { if (((class_type) l->data)->class_id->idnum == c->class_id->idnum) st.classes = list_delete_item(st.classes, l->data, class_compare); else /* Don't give warning if deleted self from list */ { recompile_type recompile_info = (recompile_type) SafeMalloc(sizeof(recompile_struct)); recompile_info->class_id = ((class_type) (l->data))->class_id; recompile_info->superclass = c->class_id; /* Only add to list if it isn't already there */ if (list_find_item(st.recompile_list, recompile_info->class_id, recompile_compare) == NULL) st.recompile_list = list_add_item(st.recompile_list, (void *) recompile_info); } } break; default: action_error("Duplicate identifier %s", class_id->name); } /* Delete this class from list of those that need to be recompiled */ st.recompile_list = list_delete_item(st.recompile_list, (void *) c->class_id, recompile_compare); c->resources = NULL; c->properties = NULL; c->messages = NULL; c->is_new = True; /* We should generate code for this class */ /* Superclass must be defined, if one is given */ if (superclass_id != NULL) { lookup_id(superclass_id); if (superclass_id->type != I_CLASS) action_error("Can't find superclass %s", superclass_id->name); else if (class_id->idnum == superclass_id->idnum) action_error("Can't subclass from self", superclass_id->name); else { /* Find superclass's data and store a pointer to it. */ for (l = st.classes; l != NULL; l = l->next) if (superclass_id->idnum == ((class_type) (l->data))->class_id->idnum) { c->superclass = (class_type) l->data; break; } if (c->superclass == NULL) action_error("Unable to find superclass %s", superclass_id->name); } } else c->superclass = NULL; st.curclass = class_id->idnum; /* Now add superclasses' properties to our own property table, but delete * them from our property list. This way the table will hold all properties * that can be referenced in the class, but the property list will only * hold those that were declared in this class (need to know this for code gen) */ add_parent_properties(c, c->superclass); /* Similarly, add superclasses' classvars. This must be done AFTER adding the properties, * since some properties in a superclass could be overriding classvars in a superclass */ add_parent_classvars(NULL, c, c->superclass); /* Add to list of classes */ st.classes = list_add_item(st.classes, (void *) c); return c; }
message_header_type make_message_header(id_type id, list_type args) { message_header_type s = (message_header_type) SafeMalloc(sizeof(message_header_struct)); id_type old_id, temp_id; param_type param; list_type l; /* Messsage name must be unique in this class, but may be the same * as a message in a different class. */ old_id = lookup_id(id); switch (id->type) { case I_MISSING: /* The message has been referenced in a function call, but not declared anywhere. * We should use the existent message # and remove the id from the missing list */ if (id->source != I_MESSAGE) { action_error("Message %s was referenced elsewhere with different type", id->name); break; } /* Insert directly into global table to preserve id # */ id->type = I_MESSAGE; id->ownernum = st.curclass; id->source = COMPILE; table_insert(st.globalvars, (void *) id, id_hash, id_compare); /* Remove from missing list */ table_delete_item(st.missingvars, id, id_hash, id_compare); break; case I_UNDEFINED: /* New message # */ id->ownernum = st.curclass; add_identifier(id, I_MESSAGE); break; case I_MESSAGE: /* Make sure message hasn't appeared in this class */ if (id->ownernum == st.curclass && id->source == COMPILE) action_error("Message handler %s defined twice in same class", id->name); old_id->ownernum = st.curclass; old_id->source = COMPILE; break; default: /* Other types indicate name already used */ action_error("Duplicate identifier %s", id->name); } s->message_id = id; /* Sort parameters in increasing id # order */ s->params = SortParameterList(args); /* Add parameters as handler's local variables--this must be done AFTER sorting */ for (l = s->params; l != NULL; l = l->next) { param = (param_type) l->data; /* Make a copy of the id for the local table */ temp_id = duplicate_id(param->lhs); temp_id->type = I_LOCAL; if (table_insert(st.localvars, (void *) temp_id, id_hash, id_compare) == 0) temp_id->idnum = ++st.maxlocals; } st.curmessage = id->idnum; return s; }