Ejemplo n.º 1
0
Archivo: lex.c Proyecto: jgshort/oo
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;
}
Ejemplo n.º 2
0
Archivo: type.c Proyecto: certik/nwcc
/*
 * 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;
}	
Ejemplo n.º 3
0
token_t *gc_alloc_token( gbg_collector_t *gc ){
	token_t *ret = gc_register( gc, alloc_token( ));

	return ret;
}