Exemplo n.º 1
0
Arquivo: proto.c Projeto: run4flat/qcc
// suck all the global function, struct, union, enum, and typedef prototypes out of the token stream
// -- which means creating a new "defs" token stream, and splitting out a defs_idx from the idx_tbl
uint32_t proto_pass(struct proto_info *inf, uint8_t *new_eb)
{
	int32_t i;
	uint32_t j, k, m;
	uint8_t bol_flag, *p, *c, *sp;
	int8_t level, def_flg;

	bol_flag = 1;
	def_flg = level = 0;
	i = k = m = 0;
	p = sp = wrksp_top;
	if (new_eb != NULL)
		p = sp = new_eb;
	while (1)
	{
// At top level, the only thing I should ever encounter at bol are typespecs/declspecs and typedefs?
// HIHI!! I must also copydown the EMIT buffer! Use the c pointer for that! But there is a problem for the defs = -1 case that gets cancelled ...
		if (level == 0 && def_flg == 0)
		{
			inf->idx_strt = k;		// save the *next* idx index
			sp = p;					// save a ptr to the beginning of any prototype
		}
		switch (*p)
		{
	// HIHI!! how to detect the beginning of a function definition?? It's the only thing that's not a typespec or declspec or variable name?
		case TOK_STRUCT:
		case TOK_UNION:
		case TOK_ENUM:
			if (level == 0) def_flg = -1;
			break;

		case TOK_NAME_IDX:
			j = idx_tbl[k++];
			if (++m != k) idx_tbl[m - 1] = j;			// rebuild a compressed idx_tbl
			c = name_strings + j;
//			if (level == 0 && def_flg == 0)				// HIHI debugging!
//				bol_flag = 0;
			break;

		case TOK_INT_CONST:
		case TOK_FP_CONST:
		case TOK_NONAME_IDX:
			j = idx_tbl[k++];							// must keep k aligned with the token stream
			if (++m != k) idx_tbl[m - 1] = j;			// rebuild a compressed idx_tbl
			break;

		case TOK_TYPEDEF:
			if (bol_flag != 0)
			{
				if (level == 0) def_flg = 2;
		// HIHI can you do typedefs with only local scope?
			}
			// else show_error (0, "typedef syntax error", NULL, 1, inf);		// must recalculate the line number and fname first!
			break;

		case TOK_SEMIC:
			if (level == 0 && def_flg != 0) def_flg = 32;
			bol_flag = 1;
			break;

		case TOK_OCURLY:
			if (def_flg < 0) def_flg = 1;
			bol_flag = 1;
			++level;
			break;

		case TOK_CCURLY:
			if (--level == 0)
			{
				if (def_flg == 1) def_flg = 16;
			}
			bol_flag = 1;
			break;

		case TOK_ENDOFBUF:
			if (inf->infd < 0) return m;
		// HIHI!! if (def_flg != 0) then I must do a partial copy to the wrkbuf! (and reset sp = p;)
			read_tok (&p);
			break;

		default:
			if (def_flg < 0) def_flg = 0;
			bol_flag = 0;

		}		// end of switch on *p

		++p;
		if (def_flg > 2)			// found a definition?
		{
			m -= k - inf->idx_strt;
			j = p - sp;
			inf->wrkbuf = sp;		// HIHI getting rid of the wrkbuf ptr?
			if (def_flg == 32) parse_typedef(j, inf);
//			else if (def_flg == 16) parse_struct(j, inf->cur_ptr, inf->idx_strt, inf);
	// HIHI!!! then send it into a parsing routine, to break the whole thing into pieces and store it in defs
	// -- but I think I want separate parsing routines for typedefs, functions, and structs
//					parse_proto(&p, inf, 0);
			def_flg = 0;
		}

//		if ((uint32_t) (emit_ptr - wrksp) > wrk_rem - 30 * 1024) handle_emit_overflow();
		// HIHI!! do the dealie that guarantees 16K or whatever in the buffer -- at least *nxt_pass_info amount

	}		// infinite loop
}
static int
process_line(struct protolib *plib, struct locus *loc, char *buf)
{
	char *str = buf;
	char *tmp;

	debug(3, "Reading line %d of `%s'", loc->line_no, loc->filename);
	eat_spaces(&str);

	/* A comment or empty line.  */
	if (*str == ';' || *str == 0 || *str == '\n' || *str == '#')
		return 0;

	if (strncmp(str, "typedef", 7) == 0) {
		parse_typedef(plib, loc, &str);
		return 0;
	}

	struct prototype fun;
	prototype_init(&fun);

	struct param *extra_param = NULL;
	char *proto_name = NULL;
	int own;
	fun.return_info = parse_lens(plib, loc, &str, NULL, 0, &own, NULL);
	if (fun.return_info == NULL) {
	err:
		debug(3, " Skipping line %d", loc->line_no);

		if (extra_param != NULL) {
			param_destroy(extra_param);
			free(extra_param);
		}

		prototype_destroy(&fun);
		free(proto_name);
		return -1;
	}
	fun.own_return_info = own;
	debug(4, " return_type = %d", fun.return_info->type);

	eat_spaces(&str);
	tmp = start_of_arg_sig(str);
	if (tmp == NULL) {
		report_error(loc->filename, loc->line_no, "syntax error");
		goto err;
	}
	*tmp = '\0';

	proto_name = strdup(str);
	if (proto_name == NULL) {
	oom:
		report_error(loc->filename, loc->line_no,
			     "%s", strerror(errno));
		goto err;
	}

	str = tmp + 1;
	debug(3, " name = %s", proto_name);

	int have_stop = 0;

	while (1) {
		eat_spaces(&str);
		if (*str == ')')
			break;

		if (str[0] == '+') {
			if (have_stop == 0) {
				struct param param;
				param_init_stop(&param);
				if (prototype_push_param(&fun, &param) < 0)
					goto oom;
				have_stop = 1;
			}
			str++;
		}

		int own;
		size_t param_num = prototype_num_params(&fun) - have_stop;
		struct arg_type_info *type
			= parse_lens(plib, loc, &str, &extra_param,
				     param_num, &own, NULL);
		if (type == NULL) {
			report_error(loc->filename, loc->line_no,
				     "unknown argument type");
			goto err;
		}

		struct param param;
		param_init_type(&param, type, own);
		if (prototype_push_param(&fun, &param) < 0)
			goto oom;

		eat_spaces(&str);
		if (*str == ',') {
			str++;
			continue;
		} else if (*str == ')') {
			continue;
		} else {
			if (str[strlen(str) - 1] == '\n')
				str[strlen(str) - 1] = '\0';
			report_error(loc->filename, loc->line_no,
				     "syntax error around \"%s\"", str);
			goto err;
		}
	}

	/* We used to allow void parameter as a synonym to an argument
	 * that shouldn't be displayed.  But backends really need to
	 * know the exact type that they are dealing with.  The proper
	 * way to do this these days is to use the hide lens.
	 *
	 * So if there are any voids in the parameter list, show a
	 * warning and assume that they are ints.  If there's a sole
	 * void, assume the function doesn't take any arguments.  The
	 * latter is conservative, we can drop the argument
	 * altogether, instead of fetching and then not showing it,
	 * without breaking any observable behavior.  */
	if (prototype_num_params(&fun) == 1
	    && param_is_void(prototype_get_nth_param(&fun, 0))) {
		if (0)
			/* Don't show this warning.  Pre-0.7.0
			 * ltrace.conf often used this idiom.  This
			 * should be postponed until much later, when
			 * extant uses are likely gone.  */
			report_warning(loc->filename, loc->line_no,
				       "sole void parameter ignored");
		prototype_destroy_nth_param(&fun, 0);
	} else {
		prototype_each_param(&fun, NULL, void_to_hidden_int, loc);
	}

	if (extra_param != NULL) {
		prototype_push_param(&fun, extra_param);
		free(extra_param);
		extra_param = NULL;
	}

	if (protolib_add_prototype(plib, proto_name, 1, &fun) < 0) {
		report_error(loc->filename, loc->line_no,
			     "couldn't add prototype: %s",
			     strerror(errno));
		goto err;
	}

	return 0;
}