oo_token *lex(FILE *fp, size_t sz) { size_t l; char *source = malloc(sz); oo_token *head = NULL, *curr = NULL; if(!source) goto err1; if(fseek(fp, 0L, SEEK_SET) != 0) goto err0; l = fread(source, sizeof(char), sz, fp); source[++l] = 0; char *cp = source; oo_floc empty = { .line = 0, .column = 0, .offset = 0}; curr = head = alloc_token(oot_START, empty, 0, NULL); oo_floc loc = { .line = 1, .column = 1, .offset = -1 }; oo_states state = oos_start, prev = state; uint32_t end_offset = 0; oo_floc block; do { char a = *cp; oo_tokens token = oot_UNKNOWN; step(&state, &cp, &loc); if(state == oos_err) goto syn; if (state == oos_str || state == oos_ident || state == oos_num) { block.line = loc.line; block.column = loc.column; block.offset = loc.offset; } int end_of_str = (state == oos_eo_str || state == oos_eo_id || state == oos_eo_num); if (end_of_str) { /* id, num & str */ end_offset = loc.offset; int t = -1; if (state == oos_eo_id) t = oot_IDENT; if (state == oos_eo_str) t = oot_STR; if (state == oos_eo_num) t = oot_NUM; if (t == oot_IDENT || t == oot_STR || t == oot_NUM) { curr = alloc_token(t, block, end_offset - block.offset, curr); } if(state == oos_eo_id || state == oos_eo_num) { cp--; loc.offset--; } end_offset = 0; } else { /* sym */ if (state == oos_sym) { char c = *(source + (loc.offset)); token = oo_tokens_from_char(c); } if(token != oot_UNKNOWN) { curr = alloc_token(token, loc, 1, curr); } } syn: printf("o: %d, s -> %d, s_s = '%s' (%d)", (int)loc.offset, (int)state, oo_state_to_string(state), (int)a); if(isalpha(a) || isdigit(a) || issym(a)) { printf(", '%c'", a); } printf("\n"); if(state == oos_err) { if(prev == oos_in_str) { printf("Syntax error, unterminated string constant, line %d column %d\n", block.line, block.column - 1); } /* TODO: Add oot_ERR token */ curr = alloc_token(oot_EOF, loc, 1, curr); return head; } prev = state; } while(state != oos_eof); if(state == oos_eof) { curr = alloc_token(oot_EOF, loc, 0, curr); } err0: if(source) free(source), source = NULL; err1: return head; } static void step(oo_states *state, char **cp, oo_floc *loc) { int c = **cp, k = 0; int i = -1; /* unknown */ if(c != 0 && *(*cp+1) != 0) k = *(*cp +1); i = isspace(c) ? 0 : i; /* ws */ i = c == '\n' ? 1 : i; /* new line */ i = issym(c) ? 2 : i; /* sym */ i = isdigit(c) ? 3 : i; /* numeric */ i = isid(c) ? 4 : i; /* id */ i = c == '"' ? 5 : i; /* str */ i = isesc(c, k) ? 6 : i; /* escape */ i = c == 0 ? 7 : i; /* eof */ if(i == -1) printf("---> '%c'\n", c); oo_branch *b = &table[*state][i]; *state = b->state; if(b->advance) { if(b->state == oos_nl) { loc->line++; loc->column = 0; } loc->column++; loc->offset++; (*cp)++; } } static oo_tokens oo_tokens_from_char(int t) { if (t == '~') return oot_TILDE; if (t == '`') return oot_GACCENT; if (t == '!') return oot_BANG; if (t == '@') return oot_AT; if (t == '#') return oot_POUND; if (t == '$') return oot_DOLLAR; if (t == '%') return oot_PERCENT; if (t == '^') return oot_EXP; if (t == '&') return oot_AND; if (t == '*') return oot_STAR; if (t == '(') return oot_LPAREN; if (t == ')') return oot_RPAREN; if (t == '-') return oot_MINUS; if (t == '=') return oot_EQUAL; if (t == '_') return oot_UNDER; if (t == '+') return oot_PLUS; if (t == '[') return oot_LBRACKET; if (t == ']') return oot_RBRACKET; if (t == '\\') return oot_BSLASH; if (t == '{') return oot_LBRACE; if (t == '}') return oot_RBRACE; if (t == '|') return oot_BAR; if (t == ';') return oot_SEMI; if (t == '\'') return oot_SQUOTE; if (t == ':') return oot_COLON; if (t == '"') return oot_DQUOTE; if (t == ',') return oot_COMMA; if (t == '.') return oot_DOT; if (t == '/') return oot_FSLASH; if (t == '<') return oot_LT; if (t == '>') return oot_GT; if (t == '?') return oot_WHAT; return oot_UNKNOWN; } char *string_from_oo_tokens(oo_tokens t) { if (t == oot_START) return "oot_START"; if (t == '~') return "oot_TILDE"; if (t == '`') return "oot_GACCENT"; if (t == '!') return "oot_BANG"; if (t == '@') return "oot_AT"; if (t == '#') return "oot_POUND"; if (t == '$') return "oot_DOLLAR"; if (t == '%') return "oot_PERCENT"; if (t == '^') return "oot_EXP"; if (t == '&') return "oot_AND"; if (t == '*') return "oot_STAR"; if (t == '(') return "oot_LPAREN"; if (t == ')') return "oot_RPAREN"; if (t == '-') return "oot_MINUS"; if (t == '=') return "oot_EQUAL"; if (t == '_') return "oot_UNDER"; if (t == '+') return "oot_PLUS"; if (t == '[') return "oot_LBRACKET"; if (t == ']') return "oot_RBRACKET"; if (t == '\\') return "oot_BSLASH"; if (t == '{') return "oot_LBRACE"; if (t == '}') return "oot_RBRACE"; if (t == '|') return "oot_BAR"; if (t == ';') return "oot_SEMI"; if (t == '\'') return "oot_SQUOTE"; if (t == ':') return "oot_COLON"; if (t == '"') return "oot_DQUOTE"; if (t == ',') return "oot_COMMA"; if (t == '.') return "oot_DOT"; if (t == '/') return "oot_FSLASH"; if (t == '<') return "oot_LT"; if (t == '>') return "oot_GT"; if (t == '?') return "oot_WHAT"; if (t == oot_IDENT) return "oot_IDENT"; if (t == oot_NUM) return "oot_NUM"; if (t == oot_STR) return "oot_STR"; if (t == oot_EOF) return "oot_EOF"; return "oot_UNKNOWN"; } static char *oo_state_to_string(oo_states state) { if (state == oos_start) return "oos_start"; if (state == oos_ws) return "oos_ws"; if (state == oos_nl) return "oos_nl"; if (state == oos_sym) return "oos_sym"; if (state == oos_num) return "oos_num"; if (state == oos_ident) return "oos_ident"; if (state == oos_str) return "oos_str"; if (state == oos_esc) return "oos_esc"; if (state == oos_in_str) return "oos_in_str"; if (state == oos_in_id) return "oos_in_id"; if (state == oos_in_num) return "oos_in_num"; if (state == oos_eo_str) return "oos_eo_str"; if (state == oos_eo_id) return "oos_eo_id"; if (state == oos_eo_num) return "oos_eo_num"; if (state == oos_err) return "oos_err"; if (state == oos_eof) return "oos_eof"; return "undefined"; } static int issym(int c) { return c == '[' || c == ']' || c == '\\' || c == '{' || c == '}' || c == '|' || c == ';' || c == '\''|| c == ':' || c == '"' || c == ',' || c == '.' || c == '/' || c == '<' || c == '>' || c == '?' || c == '~' || c == '`' || c == '!' || c == '@' || c == '#' || c == '$' || c == '%' || c == '^' || c == '&' || c == '*' || c == '(' || c == ')' || c == '-' || c == '_' || c == '=' || c == '+' ; } static int isid(int c) { return isalpha(c) || c == '_'; } static int isesc(int c, int k) { if(c == 0) return 0; if(k == 0) return 0; if(c == '\\') { if (k == '"') return 1; if (k == '\\') return 1; if (k == 'r') return 1; if (k == 'n') return 1; } return 0; }
/* * XXX warn about ``unsigned char *'' vs ``char *'', * unlike gcc */ static int compare_tlist(struct type_node *dest, struct type_node *src, int flag) { struct type_node *dest_start = dest; for (; dest != NULL && src != NULL; dest = dest->next, src = src->next) { if (src->type == TN_FUNCTION || dest->type == TN_FUNCTION) { if (dest->type != src->type) { /* XXX fix this later */ if (dest == dest_start) { /* * Ordinary function symbols are * compatible with pointers to * functions */ if (dest->type == TN_FUNCTION) { if (src->type == TN_POINTER_TO) { src = src->next; } else { return -1; } } else { if (dest->type == TN_POINTER_TO) { dest = dest->next; } else { return -1; } } } } } if (dest->type != src->type) { /* Pointer vs array vs function */ if (flag & CMPTY_ARRAYPTR) { if ((dest->type == TN_ARRAY_OF || src->type == TN_ARRAY_OF || dest->type == TN_VARARRAY_OF || src->type == TN_VARARRAY_OF) && (dest->type == TN_POINTER_TO || src->type == TN_POINTER_TO)) { continue; } } return -1; } switch (dest->type) { case TN_ARRAY_OF: case TN_VARARRAY_OF: if (flag & CMPTY_TENTDEC) { #if REMOVE_ARRARG if (!dest->have_array_size || !src->have_array_size) { #else if (dest->arrarg->const_value == NULL || src->arrarg->const_value == NULL) { #endif /* * probably * extern int foo[]; * int foo[123]; * -> OK! */ break; } } if (dest->arrarg_const != src->arrarg_const && ((flag & CMPTY_ARRAYPTR) == 0 || dest_start != dest)) { #if REMOVE_ARRARG if (!src->have_array_size || !dest->have_array_size) { #else if (src->arrarg->const_value == NULL || dest->arrarg->const_value == NULL) { #endif /* * One side has unspecified size, this * is OK! * extern char foo[]; * char (*p)[5] = &foo; * char bar[5]; * char (*p2)[] = &bar; */ break; } else { /* Array sizes differ */ return -1; } } break; case TN_POINTER_TO: break; case TN_FUNCTION: if (compare_tfunc(dest->tfunc, src->tfunc) == -1) { return -1; } break; } } if (dest != NULL || src != NULL) { /* One list is longer, so it differs by definition */ return -1; } return 0; } #endif /* #ifndef PREPROCESSOR */ int compare_types(struct type *dest, struct type *src, int flag) { int is_void_ptr = 0; /* 04/08/08: Changed this (for the better, hopefully!) */ if (dest->tlist != NULL && dest->tlist->type == TN_POINTER_TO && dest->tlist->next == NULL && dest->code == TY_VOID) { is_void_ptr = 1; } else if (src->tlist != NULL && src->tlist->type == TN_POINTER_TO && src->tlist->next == NULL && src->code == TY_VOID) { is_void_ptr = 1; } if (dest->code != src->code) { /* * Differing base type - This is ok if we have a void * pointer vs a non-void pointer, otherwise return error */ if (!is_void_ptr || src->tlist == NULL || dest->tlist == NULL) { return -1; } } if (flag & CMPTY_SIGN) { if (dest->sign != dest->sign) { /* Differing sign */ return -1; } } if (flag & CMPTY_CONST) { if (IS_CONST(dest->flags) != IS_CONST(src->flags)) { /* One is const-qualified */ /*return -1;*/ } } /* * 04/08/08: Skip the tlist comparison if this is void pointer * vs non-void pointer; Otherwise tlists of different length * will compare uneven, as in void * vs int **, which is wrong */ if (is_void_ptr) { return 0; } #ifndef PREPROCESSOR return compare_tlist(dest->tlist, src->tlist, flag); #else return -1; #endif } int check_init_type(struct type *ofwhat, struct expr *init) { if (ofwhat->tlist == NULL) { if (init->next != NULL) { } } else if (ofwhat->tlist->type == TN_ARRAY_OF) { if (init->type->code == TOK_STRING_LITERAL) { return 0; } else { struct expr *ex; for (ex = init; ex != NULL; ex = ex->next) { } } } return 0; } void copy_type(struct type *dest, const struct type *src, int fullcopy) { if (fullcopy) { memcpy(dest, src, sizeof *dest); } else { memcpy(dest, src, sizeof *dest); } } struct type_node * copy_tlist(struct type_node **dest, const struct type_node *src) { struct type_node *head; struct type_node *tail; struct type_node *tn; if (src == NULL) { *dest = NULL; return NULL; } head = tail = NULL; do { tn = n_xmalloc(sizeof *tn); memcpy(tn, src, sizeof *tn); if (head == NULL) { head = tail = tn; } else { tail->next = tn; tail = tail->next; } } while ((src = src->next) != NULL); *dest = head; return tail; } void set_type_sign(struct type *ty) { if (ty->code == TY_UCHAR || ty->code == TY_USHORT || ty->code == TY_UINT || ty->code == TY_ULONG || ty->code == TY_ULLONG) { ty->sign = TOK_KEY_UNSIGNED; } else if (!IS_FLOATING(ty->code) && ty->code != TY_STRUCT && ty->code != TY_UNION) { ty->sign = TOK_KEY_SIGNED; } } struct type * make_basic_type(int code) { #define N_TYPES (TY_MAX - TY_MIN) #if 0 static struct type basic_types[N_TYPES]; #endif static int inited; static struct type *basic_types; if (!inited) { int i; int nbytes = N_TYPES * sizeof(struct type); int need_mprotect = 1; basic_types = debug_malloc_pages(nbytes); if (basic_types == NULL) { /* * Probably debug_malloc_pages() doesn't work * on this system */ basic_types = n_xmalloc(nbytes); need_mprotect = 0; } memset(basic_types, 0, nbytes); for (i = 0; i < N_TYPES; ++i) { basic_types[i].code = i + TY_MIN; set_type_sign(&basic_types[i]); } inited = 1; if (need_mprotect) { /* * We make the array unwritable because it really * should not be written to; Modifying it is a bug * that has happend more than once. * * The void cast is necessary because of a broken * Solaris prototype that takes caddr_t :-/ */ mprotect((void *)basic_types, nbytes, PROT_READ); } } if (code < 0 || (code - TY_MIN) >= N_TYPES) { printf("BUG: bad code for make_basic_type: %d\n", code); abort(); } #if 0 if (code == TY_PSEUDEO_SIZE_T) { static struct type ty; static struct type *p; if (p == NULL) { ty = basic_types[TY_UINT]; } } #endif #if 0 /* As of Jan 6 2007, the basic types may not be modified anymore */ basic_types[code - TY_MIN].tlist = NULL; #endif return &basic_types[code - TY_MIN]; } struct type * make_void_ptr_type(void) { static struct type *ty; if (ty == NULL) { ty = make_basic_type(TY_VOID); ty = n_xmemdup(ty, sizeof *ty); append_typelist(ty, TN_POINTER_TO, NULL, NULL, NULL); } return ty; } struct type * make_array_type(int size, int is_wide_char) { struct type *ret = alloc_type(); if (is_wide_char) { ret->code = backend->get_wchar_t()->code; ret->sign = backend->get_wchar_t()->sign; } else { ret->code = TY_CHAR; if (CHAR_MAX == UCHAR_MAX) { /* XXX */ ret->sign = TOK_KEY_UNSIGNED; } else { ret->sign = TOK_KEY_SIGNED; } } ret->storage = TOK_KEY_STATIC; ret->tlist = alloc_type_node(); ret->tlist->type = TN_ARRAY_OF; ret->tlist->arrarg_const = size; #if REMOVE_ARRARG ret->tlist->have_array_size = 1; #endif return ret; } /* * Helper function for parse_declarator()- stores pointer/array-of/function * property (specified by ``type'' argument) with optional arguments type_arg * (for pointer/array-of) and tf (for function) in type specified by t * * 01/26/08: Extended to do some sanity checking (functions may not return * functions or arrays). This means some type constructions are now REQUIRED * to go through append_typelist()! May not be the best approach, needs * testing?! */ void append_typelist(struct type *t, int type, void *type_arg, struct ty_func *tf, struct token *tok) { struct type_node *te; struct expr *ex; (void) tok; /* XXX unneeded?!?! */ /* Allocate and insert new type node */ if (t->tlist == NULL) { te = t->tlist = t->tlist_tail = alloc_type_node(); te->prev = NULL; if (type == TN_FUNCTION) { /* * If the first node in the type list is a function * designator, this means we are dealing with a genuine * function declaration/definition (as opposed to a * pointer) */ t->is_func = 1; } } else { /* * 01/26/08: Some sanity checking! */ int tailtype = t->tlist_tail->type; if (tailtype == TN_ARRAY_OF || tailtype == TN_VARARRAY_OF) { if (type == TN_FUNCTION) { errorfl(tok, "Invalid declaration of `array of " "functions' - Maybe you meant `array " "of pointer to function'; `void (*ar[N])();'?"); return /* -1 XXX */ ; } } else if (tailtype == TN_FUNCTION) { if (type == TN_ARRAY_OF || type == TN_VARARRAY_OF) { errorfl(tok, "Invalid declaration of `function " "returning array' - If you really want " "to return an array by value, put it " "into a structure!"); return /* -1 XXX */ ; } else if (type == TN_FUNCTION) { errorfl(tok, "Invalid declaration of `function " "returning function' - You can at most " "return a pointer to a function; " "`void (*foo())();'"); return /* -1 XXX */ ; } } te = alloc_type_node(); te->prev = t->tlist_tail; t->tlist_tail->next = te; t->tlist_tail = t->tlist_tail->next; } te->next = NULL; te->type = type; switch (type) { case TN_VARARRAY_OF: case TN_ARRAY_OF: #if REMOVE_ARRARG ex = type_arg; if (ex->const_value == NULL) { /* Size not specified - extern char buf[]; */ te->have_array_size = 0; } else { te->have_array_size = 1; ex->const_value->type = n_xmemdup(ex->const_value->type, sizeof(struct type)); cross_convert_tyval(ex->const_value, NULL, NULL); te->arrarg_const = cross_to_host_size_t( ex->const_value); if (te->arrarg_const == 0) { /* * In GNU C, * int foo[0]; * may be a flexible array member */ te->have_array_size = 0; #if 0 errorfl(tok, "Cannot create zero-sized arrays"); #endif } } if (type == TN_VARARRAY_OF) { te->variable_arrarg = ex; } #else /* Using arrarg */ te->arrarg = type_arg; if (te->arrarg->const_value) { te->arrarg->const_value->type = n_xmemdup(te->arrarg->const_value->type, sizeof(struct type)); cross_convert_tyval(te->arrarg->const_value, NULL, NULL); te->arrarg_const = /* *(size_t *) */ cross_to_host_size_t( te->arrarg->const_value); /*->value; */ if (te->arrarg_const == 0) { /* * In GNU C, * int foo[0]; * may be a flexible array member */ te->arrarg->const_value = NULL; #if 0 errorfl(tok, "Cannot create zero-sized arrays"); #endif } } #endif /* REMOVE_ARRARG is disabled */ break; case TN_POINTER_TO: te->ptrarg = type_arg? *(int *)type_arg: 0; break; case TN_FUNCTION: te->tfunc = tf; break; } } static struct { char *name; int code; } basic_type_names[] = { { "char", TY_CHAR }, { "unsigned char", TY_UCHAR }, { "signed char", TY_SCHAR }, { "short", TY_SHORT }, { "unsigned short", TY_USHORT }, { "int", TY_INT }, { "unsigned int", TY_UINT }, { "long", TY_LONG }, { "unsigned long", TY_ULONG }, { "float", TY_FLOAT }, { "double", TY_DOUBLE }, { "long double", TY_LDOUBLE }, { "struct", TY_STRUCT }, { "union", TY_UNION }, { "enum", TY_ENUM }, { "void", TY_VOID }, { "long long", TY_LLONG }, { "unsigned long long", TY_ULLONG }, { "_Bool", TY_BOOL }, { NULL, 0 } }; char * ret_type_to_text(struct type *ty) { struct type_node *orig_tlist = NULL; char *ret; if (ty->tlist != NULL) { orig_tlist = ty->tlist; if (ty->tlist->type == TN_FUNCTION) { ty->tlist = ty->tlist->next; } else if (ty->tlist->type == TN_POINTER_TO && ty->tlist->next != NULL && ty->tlist->next->type == TN_FUNCTION) { ty->tlist = ty->tlist->next->next; } ret = type_to_text(ty); ty->tlist = orig_tlist; } else { ret = type_to_text(ty); } return ret; } char * type_to_text(struct type *dt) { struct type_node *t; char *buf = NULL; char *p = NULL; size_t size = 0; size_t used = 0; int i; for (t = dt->tlist; t != NULL; t = t->next) { switch (t->type) { case TN_ARRAY_OF: case TN_VARARRAY_OF: make_room(&buf, &size, used + 64); used += sprintf(buf+used, "an array of %d ", (int)t->arrarg_const); break; case TN_POINTER_TO: { char *quali = ""; if (t->ptrarg != 0) { switch (t->ptrarg) { case TOK_KEY_VOLATILE: quali = "volatile"; break; case TOK_KEY_CONST: quali = "constant"; break; case TOK_KEY_RESTRICT: quali = "restricted"; break; } } make_room(&buf, &size, used + 32); used += sprintf(buf+used, "a %s pointer to ", quali); break; } case TN_FUNCTION: make_room(&buf, &size, used + 32); used += sprintf(buf+used, "a function (with %d args) returning ", t->tfunc->nargs); break; } } #if 0 p = basic_type_names[dt->code - TY_MIN]; #endif for (i = 0; basic_type_names[i].name != NULL; ++i) { if (dt->code == basic_type_names[i].code) { p = basic_type_names[i].name; break; } } make_room(&buf, &size, strlen(p) + 5); used += sprintf(buf+used, "%s", p); if (dt->code == TY_STRUCT) { if (dt->tstruc && dt->tstruc->tag) { make_room(&buf, &size, used + strlen(dt->tstruc->tag) + 2); sprintf(buf+used, " %s", dt->tstruc->tag); } } return buf; } #ifndef PREPROCESSOR extern void put_ppc_llong(struct num *); /* * XXX same stupid size_t cross-compilaion bug as const_from_value().. * this stuff SUCKS!!! */ struct token * const_from_type(struct type *ty, int from_alignment, int extype, struct token *t) { struct token *ret = alloc_token(); size_t size; int size_t_size; #if 0 ret->type = TY_ULONG; /* XXX size_t */ #endif ret->type = backend->get_size_t()->code; if (from_alignment) { size = backend->get_align_type(ty); } else { size = backend->get_sizeof_type(ty, t); } /*ret->data = n_xmemdup(&size, sizeof size);*/ ret->data = n_xmalloc(16); /* XXX */ size_t_size = backend->get_sizeof_type(backend->get_size_t(), NULL); if (sizeof size == size_t_size) { memcpy(ret->data, &size, sizeof size); } else if (sizeof(int) == size_t_size) { unsigned int i = (unsigned int)size; memcpy(ret->data, &i, sizeof i); } else if (sizeof(long) == size_t_size) { unsigned long l = (unsigned long)size; memcpy(ret->data, &l, sizeof l); } else if (sizeof(long long) == size_t_size) { unsigned long long ll = (unsigned long long)size; memcpy(ret->data, &ll, sizeof ll); } else { unimpl(); } if (backend->abi == ABI_POWER64 && extype != EXPR_CONST && extype != EXPR_CONSTINIT /* What about EXPR_OPTCONSTINIT?! */ ) { struct num *n = n_xmalloc(sizeof *n); /* * XXX see definition of put_ppc_llong() for an * explanation of this mess */ n->type = ret->type; n->value = ret->data; put_ppc_llong(n); /*ret->data = llong_const;*/ ret->data2 = llong_const; } return ret; } /* * XXX this interface is ROTTEN!! * too easy to pass a ``size_t'' for value with ty=NULL by accident!! * * XXXX WOAH this was totally broken WRT cross-compilation! ``type'' * is interpreted as host type when dealing with ``value'', and as * target type too by making it the type of the token! Current ad-hoc * kludge sucks! */ struct token * const_from_value(void *value, struct type *ty) { struct token *ret = alloc_token(); size_t size; if (ty == NULL) { ret->type = TY_INT; size = backend->get_sizeof_type(make_basic_type( TY_INT), NULL);; } else { ret->type = ty->code; size = backend->get_sizeof_type(ty, NULL); } if (ty && (IS_LONG(ty->code) || IS_LLONG(ty->code))) { if (sizeof(long) == size) { /* Size matches - nothing to do */ ; } else { static long long llv; llv = *(int *)value; value = &llv; } } ret->data = n_xmemdup(value, size); if (backend->abi == ABI_POWER64 && ty != NULL && is_integral_type(ty) && size == 8) { struct num *n = n_xmalloc(sizeof *n); static struct num nullnum; *n = nullnum; n->type = ret->type; n->value = ret->data; put_ppc_llong(n); ret->data2 = llong_const; } return ret; } /* * Construct a floating point constant token of type ``type'' * containing ``value'' (which must be a string parsable by sscanf().) */ struct token * fp_const_from_ascii(const char *value, int type) { struct num *n; struct token *ret = n_xmalloc(sizeof *ret); n = cross_scan_value(value, type, 0, 0, 1); if (n == NULL) { return NULL; } /* * XXX token.data is ``struct ty_float'', not * ``struct num''. Because the interfaces are * still messed up, we have to get the current * ty_float corresponding to ``n'' from the * float list. This SUCKS! */ ret->data = float_const/*n->value*/; ret->type = type; ret->ascii = n_xstrdup(value); return ret; } struct token * const_from_string(const char *value) { struct token *ret = alloc_token(); struct type *ty; struct ty_string *tmpstr; tmpstr = alloc_ty_string(); tmpstr->size = strlen(value) + 1; tmpstr->str = n_xmemdup(value, tmpstr->size); tmpstr->is_wide_char = 0; ret->type = TOK_STRING_LITERAL; ty = make_array_type(tmpstr->size, tmpstr->is_wide_char); tmpstr->ty = ty; ret->data = tmpstr; return ret; } int is_integral_type(struct type *t) { if (t->tlist != NULL) { return 0; } if (IS_CHAR(t->code) || IS_SHORT(t->code) || IS_INT(t->code) || IS_LONG(t->code) || IS_LLONG(t->code) || t->code == TY_ENUM) { return 1; } return 0; } int is_floating_type(struct type *t) { if (t->tlist != NULL) { return 0; } if (t->code == TY_FLOAT || t->code == TY_DOUBLE || t->code == TY_LDOUBLE) { return 1; } return 0; } int is_arithmetic_type(struct type *t) { if (t->tlist != NULL) { return 0; } if (IS_FLOATING(t->code) || is_integral_type(t)) { return 1; } return 0; } int is_array_type(struct type *t) { struct type_node *tn; if (t->tlist == NULL) { return 0; } for (tn = t->tlist; tn != NULL; tn = tn->next) { if (tn->type != TN_ARRAY_OF) { return 0; } else { break; } } return 1; } int is_basic_agg_type(struct type *t) { if (t->tlist == NULL) { if (t->code == TY_STRUCT || t->code == TY_UNION) { return 1; } } else if (is_array_type(t)) { return 1; } return 0; } int is_scalar_type(struct type *t) { if (t->tlist == NULL && (t->code == TY_STRUCT || t->code == TY_UNION || t->code == TY_VOID)) { return 0; } return 1; } int is_arr_of_ptr(struct type *t) { struct type_node *tn; for (tn = t->tlist; tn != NULL; tn = tn->next) { if (tn->type == TN_POINTER_TO) { return 1; } else if (tn->type == TN_FUNCTION) { return 0; } } return 0; } int is_nullptr_const(struct token *constant, struct type *ty) { if (IS_INT(ty->code) && *(unsigned *)constant->data == 0) { return 1; } else if (IS_LONG(ty->code) && *(unsigned long *)constant->data == 0) { return 1; } return 0; } /* * The source type must be passed with a vreg because we need the null * pointer constant and object backing information it gives us */ int check_types_assign( struct token *t, struct type *left, struct vreg *right, int to_const_ok, int silent) { struct type *ltype = left; struct type *rtype = right->type; if (ltype == NULL || rtype == NULL) { printf("attempt to assign to/from value without type :(\n"); abort(); } /* * 01/26/08: Changed this to call is_modifyable(), which also * rules out assignment to const-qualified pointers */ /*if (ltype->tlist == NULL && ltype->is_const && !to_const_ok) { */ if (!is_modifyable(ltype) && !to_const_ok) { if (!silent) { errorfl(t, "Assignment to const-qualified object"); } return -1; } if (is_arithmetic_type(ltype)) { if (!is_arithmetic_type(rtype)) { if (ltype->code == TY_BOOL && rtype->tlist != NULL) { /* ok - pointer to bool */ return 0; } else { int allow = 0; if (rtype->tlist != NULL && is_integral_type(ltype)) { /* * 03/09/09: Give in and allow pointer * to integer assignment with a warning */ allow = 1; } if (!silent) { if (allow) { warningfl(t, "Assignment from non-arithmetic to " "arithmetic type"); } else { errorfl(t, "Assignment from non-arithmetic to " "arithmetic type"); } } if (allow) { return 0; } else { return -1; } } } else if (ltype->sign != rtype->sign && !right->from_const) { /* * Do not warn about signedness differences if the * right side is a constant! */ #if 0 /* XXX Too verbose */ warningfl(t, "Assignment from type of differing signedness"); #endif return 0; } return 0; } else if (ltype->tlist == NULL) { /* Must be struct/union */ if (rtype->tlist != NULL) { if (ltype->code == TY_BOOL) { return 0; } else { if (!silent) { /* 06/01/08: Warn, not error */ warningfl(t, "Assignment from pointer to non-pointer type"); } /* * 07/20/08: The return below was commented out! * That's wrong because pointer to struct will * compare assignable to struct * Why was this removed? */ return -1; } } else if (ltype->code == TY_BOOL) { return 0; /* _Bool b = ptr; is OK */ } else if (rtype->code != ltype->code || rtype->tstruc != ltype->tstruc) { if (!silent) { errorfl(t, "Assignment from incompatible type"); } return -1; } else { return 0; } } else { /* Left is pointer of some sort */ if (right->is_nullptr_const) { ; /* ok */ } else if (rtype->tlist == NULL) { if (!silent) { warningfl(t, "Assignment from non-pointer " "to pointer type"); } /* return -1;*/ } else if (rtype->code == TY_VOID && rtype->tlist->type == TN_POINTER_TO && rtype->tlist->next == NULL) { ; /* void pointer - compatible */ } else if (ltype->code == TY_VOID && ltype->tlist->type == TN_POINTER_TO && ltype->tlist->next == NULL) { ; /* void pointer - compatible */ } else if (compare_tlist(ltype->tlist, rtype->tlist, CMPTY_ARRAYPTR)) { if (!silent) { warningfl(t, "Assignment from incompatible pointer type" " (illegal in ISO C, and very " "probably not what you want)"); } else { /* * This is only used for transparent_union * right now... in that case we do not want * to allow this assignment because type- * checking is the whole point of that * language extension */ return -1; } return 0; } else if (!IS_CONST(ltype->flags) && IS_CONST(rtype->flags)) { if (!silent) { warningfl(t, "Assignment from const-qualified type " "to unqualified one"); } return 0; } else if (rtype->code != ltype->code && rtype->code != TY_VOID && ltype->code != TY_VOID /* XXX */ && (!IS_CHAR(ltype->code) || !IS_CHAR(rtype->code))) { if (type_without_sign(ltype->code) == type_without_sign(rtype->code)) { if (!silent) { warningfl(t, "Assignment from pointer of " "differing signedness"); } else { return -1; } return 0; } else { if (!silent) { warningfl(t, "Assignment from incompatible " "pointer type (illegal in ISO C, and " "very probably not what you want)"); } else { return -1; } #if 0 return -1; #endif return 0; } } else if (IS_CONST(ltype->flags) && !IS_CONST(rtype->flags) && ltype->tlist != NULL && ltype->tlist->next != NULL) { if (!silent) { warningfl(t, "ISO C does not allow assignment " "from `T **' to `const T **' without a " "cast (otherwise invalid code like " "`const char dont_modify; char *p; const " "char **cp = &p; *cp = &dont_modify; *p = 0;' " "would pass without warning)"); } return 0; } } return 0; } struct type * addrofify_type(struct type *ty) { struct type *ret = n_xmemdup(ty, sizeof *ty); struct type_node *tn; copy_tlist(&ret->tlist, ret->tlist); tn = alloc_type_node(); tn->type = TN_POINTER_TO; tn->next = ret->tlist; ret->tlist = tn; return ret; } int type_without_sign(int code) { int rc = code; if (code == TY_UCHAR) rc = TY_CHAR; else if (code == TY_USHORT) rc = TY_SHORT; else if (code == TY_UINT) rc = TY_INT; else if (code == TY_ULONG) rc = TY_LONG; else if (code == TY_ULLONG) rc = TY_LLONG; return rc; }
token_t *gc_alloc_token( gbg_collector_t *gc ){ token_t *ret = gc_register( gc, alloc_token( )); return ret; }