/* * For UNIONs, we first have to find the correct alternative to map the * initializer to. This function maps the structure of the initializer to * the UNION members recursively. * Returns the type of the first `fitting' member. */ static sym_link * matchIvalToUnion (initList *list, sym_link *type, int size) { symbol *sym; assert (type); if (IS_PTR(type) || IS_CHAR(type) || IS_INT(type) || IS_LONG(type) || IS_FLOAT(type)) { if (!list || (list->type == INIT_NODE)) { DEBUGprintf ("OK, simple type\n"); return (type); } else { DEBUGprintf ("ERROR, simple type\n"); return (NULL); } } else if (IS_BITFIELD(type)) { if (!list || (list->type == INIT_NODE)) { DEBUGprintf ("OK, bitfield\n"); return (type); } else { DEBUGprintf ("ERROR, bitfield\n"); return (NULL); } } else if (IS_STRUCT(type) && SPEC_STRUCT(getSpec(type))->type == STRUCT) { if (!list || (list->type == INIT_DEEP)) { if (list) list = list->init.deep; sym = SPEC_STRUCT(type)->fields; while (sym) { DEBUGprintf ("Checking STRUCT member %s\n", sym->name); if (!matchIvalToUnion(list, sym->type, 0)) { DEBUGprintf ("ERROR, STRUCT member %s\n", sym->name); return (NULL); } if (list) list = list->next; sym = sym->next; } // while // excess initializers? if (list) { DEBUGprintf ("ERROR, excess initializers\n"); return (NULL); } DEBUGprintf ("OK, struct\n"); return (type); } return (NULL); } else if (IS_STRUCT(type) && SPEC_STRUCT(getSpec(type))->type == UNION) { if (!list || (list->type == INIT_DEEP)) { if (list) list = list->init.deep; sym = SPEC_STRUCT(type)->fields; while (sym) { DEBUGprintf ("Checking UNION member %s.\n", sym->name); if (((IS_STRUCT(sym->type) || getSize(sym->type) == size)) && matchIvalToUnion(list, sym->type, size)) { DEBUGprintf ("Matched UNION member %s.\n", sym->name); return (sym->type); } sym = sym->next; } // while } // if // no match found DEBUGprintf ("ERROR, no match found.\n"); return (NULL); } else { assert ( !"Unhandled type in UNION." ); } assert ( !"No match found in UNION for the given initializer structure." ); return (NULL); }
/* * Parse the type and its initializer and emit it (recursively). */ static void emitInitVal(struct dbuf_s *oBuf, symbol *topsym, sym_link *my_type, initList *list) { symbol *sym; int size, i; long lit; unsigned char *str; size = getSize(my_type); if (IS_PTR(my_type)) { DEBUGprintf ("(pointer, %d byte) %p\n", size, list ? (void *)(long)list2int(list) : NULL); emitIvals(oBuf, topsym, list, 0, size); return; } if (IS_ARRAY(my_type) && topsym && topsym->isstrlit) { str = (unsigned char *)SPEC_CVAL(topsym->etype).v_char; emitIvalLabel(oBuf, topsym); do { dbuf_printf (oBuf, "\tretlw 0x%02x ; '%c'\n", str[0], (str[0] >= 0x20 && str[0] < 128) ? str[0] : '.'); } while (*(str++)); return; } if (IS_ARRAY(my_type) && list && list->type == INIT_NODE) { fprintf (stderr, "Unhandled initialized symbol: %s\n", topsym->name); assert ( !"Initialized char-arrays are not yet supported, assign at runtime instead." ); return; } if (IS_ARRAY(my_type)) { DEBUGprintf ("(array, %d items, %d byte) below\n", DCL_ELEM(my_type), size); assert (!list || list->type == INIT_DEEP); if (list) list = list->init.deep; for (i = 0; i < DCL_ELEM(my_type); i++) { emitInitVal(oBuf, topsym, my_type->next, list); topsym = NULL; if (list) list = list->next; } // for i return; } if (IS_FLOAT(my_type)) { // float, 32 bit DEBUGprintf ("(float, %d byte) %lf\n", size, list ? list2int(list) : 0.0); emitIvals(oBuf, topsym, list, 0, size); return; } if (IS_CHAR(my_type) || IS_INT(my_type) || IS_LONG(my_type)) { // integral type, 8, 16, or 32 bit DEBUGprintf ("(integral, %d byte) 0x%lx/%ld\n", size, list ? (long)list2int(list) : 0, list ? (long)list2int(list) : 0); emitIvals(oBuf, topsym, list, 0, size); return; } else if (IS_STRUCT(my_type) && SPEC_STRUCT(my_type)->type == STRUCT) { // struct DEBUGprintf ("(struct, %d byte) handled below\n", size); assert (!list || (list->type == INIT_DEEP)); // iterate over struct members and initList if (list) list = list->init.deep; sym = SPEC_STRUCT(my_type)->fields; while (sym) { long bitfield = 0; int len = 0; if (IS_BITFIELD(sym->type)) { while (sym && IS_BITFIELD(sym->type)) { int bitoff = SPEC_BSTR(getSpec(sym->type)) + 8 * sym->offset; assert (!list || ((list->type == INIT_NODE) && IS_AST_LIT_VALUE(list->init.node))); lit = (long) (list ? list2int(list) : 0); DEBUGprintf ( "(bitfield member) %02lx (%d bit, starting at %d, bitfield %02lx)\n", lit, SPEC_BLEN(getSpec(sym->type)), bitoff, bitfield); bitfield |= (lit & ((1ul << SPEC_BLEN(getSpec(sym->type))) - 1)) << bitoff; len += SPEC_BLEN(getSpec(sym->type)); sym = sym->next; if (list) list = list->next; } // while assert (len < sizeof (long) * 8); // did we overflow our initializer?!? len = (len + 7) & ~0x07; // round up to full bytes emitIvals(oBuf, topsym, NULL, bitfield, len / 8); topsym = NULL; } // if if (sym) { emitInitVal(oBuf, topsym, sym->type, list); topsym = NULL; sym = sym->next; if (list) list = list->next; } // if } // while if (list) { assert ( !"Excess initializers." ); } // if return; } else if (IS_STRUCT(my_type) && SPEC_STRUCT(my_type)->type == UNION) { // union DEBUGprintf ("(union, %d byte) handled below\n", size); assert (list && list->type == INIT_DEEP); // iterate over union members and initList, try to map number and type of fields and initializers my_type = matchIvalToUnion(list, my_type, size); if (my_type) { emitInitVal(oBuf, topsym, my_type, list->init.deep); topsym = NULL; size -= getSize(my_type); if (size > 0) { // pad with (leading) zeros emitIvals(oBuf, NULL, NULL, 0, size); } return; } // if assert ( !"No UNION member matches the initializer structure."); } else if (IS_BITFIELD(my_type)) { assert ( !"bitfields should only occur in structs..." ); } else { printf ("SPEC_NOUN: %d\n", SPEC_NOUN(my_type)); assert( !"Unhandled initialized type."); } }
static REBOOL parse_field_type(struct Struct_Field *field, REBVAL *spec, REBVAL *inner, REBVAL **init) { REBVAL *val = VAL_BLK_DATA(spec); if (IS_WORD(val)){ switch (VAL_WORD_CANON(val)) { case SYM_UINT8: field->type = STRUCT_TYPE_UINT8; field->size = 1; break; case SYM_INT8: field->type = STRUCT_TYPE_INT8; field->size = 1; break; case SYM_UINT16: field->type = STRUCT_TYPE_UINT16; field->size = 2; break; case SYM_INT16: field->type = STRUCT_TYPE_INT16; field->size = 2; break; case SYM_UINT32: field->type = STRUCT_TYPE_UINT32; field->size = 4; break; case SYM_INT32: field->type = STRUCT_TYPE_INT32; field->size = 4; break; case SYM_UINT64: field->type = STRUCT_TYPE_UINT64; field->size = 8; break; case SYM_INT64: field->type = STRUCT_TYPE_INT64; field->size = 8; break; case SYM_FLOAT: field->type = STRUCT_TYPE_FLOAT; field->size = 4; break; case SYM_DOUBLE: field->type = STRUCT_TYPE_DOUBLE; field->size = 8; break; case SYM_POINTER: field->type = STRUCT_TYPE_POINTER; field->size = sizeof(void*); break; case SYM_STRUCT_TYPE: ++ val; if (IS_BLOCK(val)) { REBFLG res; res = MT_Struct(inner, val, REB_STRUCT); if (!res) { //RL_Print("Failed to make nested struct!\n"); return FALSE; } field->size = SERIES_TAIL(VAL_STRUCT_DATA_BIN(inner)); field->type = STRUCT_TYPE_STRUCT; field->fields = VAL_STRUCT_FIELDS(inner); field->spec = VAL_STRUCT_SPEC(inner); *init = inner; /* a shortcut for struct intialization */ } else raise Error_Unexpected_Type(REB_BLOCK, VAL_TYPE(val)); break; case SYM_REBVAL: field->type = STRUCT_TYPE_REBVAL; field->size = sizeof(REBVAL); break; default: raise Error_Has_Bad_Type(val); } } else if (IS_STRUCT(val)) { //[b: [struct-a] val-a] field->size = SERIES_TAIL(VAL_STRUCT_DATA_BIN(val)); field->type = STRUCT_TYPE_STRUCT; field->fields = VAL_STRUCT_FIELDS(val); field->spec = VAL_STRUCT_SPEC(val); *init = val; } else raise Error_Has_Bad_Type(val); ++ val; if (IS_BLOCK(val)) {// make struct! [a: [int32 [2]] [0 0]] REBVAL ret; if (DO_ARRAY_THROWS(&ret, val)) { // !!! Does not check for thrown cases...what should this // do in case of THROW, BREAK, QUIT? raise Error_No_Catch_For_Throw(&ret); } if (!IS_INTEGER(&ret)) raise Error_Unexpected_Type(REB_INTEGER, VAL_TYPE(val)); field->dimension = cast(REBCNT, VAL_INT64(&ret)); field->array = TRUE; ++ val; } else { field->dimension = 1; /* scalar */ field->array = FALSE; } if (NOT_END(val)) raise Error_Has_Bad_Type(val); return TRUE; }