Beispiel #1
0
/************************************************************************
**	can_expand:		tries to expand the macro passed to it - returns
**		true if it succeeded in expanding it.  It will only return FALSE
**		if a macro name was found, a paren was expected, and a paren was
**		not the next non white character.
************************************************************************/
int can_expand(pdefn_t pdef)
{
    UCHAR		c;
    int			n_formals;
    int			return_value = FALSE;

    Tiny_lexer_nesting = 0;
    Save_Exp_ptr = Exp_ptr;		/* not necessarily EXP_BUFFER */
    Macro_line = Linenumber;
expand_name:

    P_actuals = Act_ptr;
    N_actuals = 0;

    n_formals = DEFN_NFORMALS(pdef);
    if( PRE_DEFINED(pdef) ) {
	push_macro(pdef);
	DEFN_EXPANDING(CURRENT_MACRO)++;
	if(rescan_expansion()) {
	    return(TRUE);			/* could expand macro */
	}
    }
    else if( n_formals == 0 ) {
	return_value = TRUE;
	if(DEFN_TEXT(pdef)) {
	    push_macro(pdef);
	    expand_definition();
	}
	else {
	    /*
		**	Macro expands to nothing (no definition).  Since it
		**	didn't have any actuals, Act_ptr is already correct.
		**	Exp_ptr must be changed however to delete the
		**	identifier from the expanded text.
		*/
	    Exp_ptr = Save_Exp_ptr;
	}
    }
    else {
	if( n_formals == -1 ) {
	    n_formals = 0;
	}
name_comment_paren:
	if( can_get_non_white()) {
	    if(CHARMAP(CHECKCH()) == LX_SLASH) {
		SKIPCH();
		if(skip_comment()) {
		    goto name_comment_paren;
		}
		else {
		    UNGETCH();
		}
	    }
	    if(CHARMAP(CHECKCH())==LX_OPAREN) {
		SKIPCH();
		return_value = TRUE;
		get_actuals(pdef, n_formals);
	    }
	    else {
		/*
				**	#define xx(a) a
				**  xx bar();
				**  don't lose white space between "xx" and "bar"
				*/
		ptext_t	p = Exp_ptr;

		push_macro(pdef);
		DEFN_EXPANDING(CURRENT_MACRO)++;
		Exp_ptr = p;
		if( rescan_expansion() ) {
		    return(FALSE);
		}
	    }
	}
	else {
	}
    }
    /*
	**	makes sure a macro is being worked on. At this point, there will
	**	be a macro to expand, unless the macro expand_the_named_macro was
	**	passed had no definition text.  If it had no defintion text,
	**	Tiny_lexer_nesting was not incremented.
	*/
    while(Tiny_lexer_nesting != 0) {
	if(Exp_ptr >= ELIMIT) {
	    fatal_in_macro(10056);
	}
	switch(CHARMAP(c = GETCH())) {
	case LX_ID:
	case LX_MACFORMAL:
	    Save_Exp_ptr = Exp_ptr;
	    if(tl_getid(c) && ((pdef = get_defined())!= 0)) {
		if(DEFN_EXPANDING(pdef)) {
		    /*
						**	the macro is already being expanded, so just
						**	write the do not expand marker and the
						**	identifier to the expand area.  The do not
						**	expand marker is necessary so this macro
						**	doesn't get expanded on the rescan
						*/
		    int		len = Reuse_1_length - 1;

		    *Exp_ptr++ = LX_NOEXPANDMARK;
		    *Exp_ptr++ = ((UCHAR)len);
		}
		else {
		    /*
						** a legal identifier was read, it is defined, and
						** it is not currently being expanded.  This means
						** there is reason to believe it can be expanded.
						*/
		    goto expand_name;
		}
	    }
	    if(InIf &&(memcmp(Reuse_1, "defined", 8) ==0)) {
		do_defined(Reuse_1);
	    }
	    continue;
	    break;
	case LX_NUMBER:
	    /* getnum with Prep on to keep leading 0x on number */
	    {
		int	Save_prep = Prep;
		Prep = TRUE;
		getnum(c);
		Prep = Save_prep;
	    }
	    continue;
	    break;
	case LX_DOT:
	    *Exp_ptr++ = '.';
dot_switch:
	    switch(CHARMAP(c = GETCH())) {
	    case LX_EOS:
		if(handle_eos() != BACKSLASH_EOS) {
		    if(Tiny_lexer_nesting > 0) {
			goto dot_switch;
		    }
		    continue;
		}
		break;
	    case LX_DOT:
		*Exp_ptr++ = '.';
		if( ! checkop('.')) {
		    break;	/* error will be caught on rescan */
		}
		*Exp_ptr++ = '.';
		continue;
		break;
	    case LX_NUMBER:
		*Exp_ptr++ = c;
		get_real(Exp_ptr);
		continue;
	    }
	    UNGETCH();
	    continue;
	case LX_CHARFORMAL:
	    move_to_exp_esc('\'', do_strformal());
	    continue;
	    break;
	case LX_STRFORMAL:
	    move_to_exp_esc('"', do_strformal());
	    continue;
	    break;
	case LX_DQUOTE:
	case LX_SQUOTE:
	    /*
	    ** 	gather_chars is called even though the error reported
	    **	on overflow may need to be changed.
	    */
	    Exp_ptr = gather_chars(Exp_ptr, c);
	    continue;
	    break;
	case LX_WHITE:
	    while(LXC_IS_WHITE(GETCH())) {
		;
	    }
	    UNGETCH();
	    c = ' ';
	    break;
	case LX_EOS:
	    if(handle_eos() == BACKSLASH_EOS) {
		*Exp_ptr++ = c;
		c = GETCH();
		break;
	    }
	    continue;
	    break;
	}
	*Exp_ptr++ = c;
    }
    return(return_value);
}
Beispiel #2
0
void handle_macro(preprocessor_state* preproc, int macro)
{
	FILE* input = preproc->input;
	FILE* output = preproc->output;
	lexer_state* lexer = &preproc->lexer;

	rsw_cstr expansion;
	init_cstr_str(&expansion, preproc->values.a[macro], strlen(preproc->values.a[macro]));

	macro_params* p = GET_PARAM(&preproc->params, macro);
	
	//do initial argument expansion
	if (p->num_params >= 0)
		parse_params(preproc, macro, &expansion);

	cvector_i valid_macros;
	cvec_i(&valid_macros, preproc->macros.size, preproc->macros.size);
	for (int i=0; i < preproc->macros.size; ++i) {
		valid_macros.a[i] = i;
	}

	rescan_expansion(preproc, &expansion, &valid_macros, macro);

	lexer_state save_lex;
	long fpos;
	token_lex t;

	save_lex = *lexer;
	if ((fpos = ftell(input)) == -1) {
		perror("ftell error in handle_macro");
		exit(0);
	}
	t = read_token(input, lexer, NULL);
	*lexer = save_lex;
	if (fseek(input, fpos, SEEK_SET)) {
		perror("fseek failure in handle_macro");
		exit(0);
	}
	
	if (t.tok.type == LPAREN) { 
		char* search, *found;
		search = expansion.a;

		int len;
		for (int i=0; i < preproc->macros.size; ++i) {
			if (i == macro)
				continue;

			len = strlen(preproc->macros.a[i]);
			search = expansion.a;
			while (1) {
				found = strstr(search, preproc->macros.a[i]);
				if (!found)
					break;
				if (found[len]) {
					search = found + len;
					continue;
				}

				if (found != expansion.a) {
					if (isalpha(found[-1]) || found[-1] == '_') {
						search = found + len;
						continue;
					}
				}
				//don't need to check the end because we already did
				
				p = GET_PARAM(&preproc->params, i);
				if (p->num_params != -1) {
					*found = 0; //cut off matched macro
					fprintf(output, "%s", expansion.a);
					handle_macro(preproc, i);

					goto exit;
				}

				search = found + len;
			}
		}
	} else if (t.tok.type == ID || t.tok.type == STR_LITERAL) {
		free(t.tok.v.id);
	}

	fprintf(output, "%s", expansion.a);

exit:

	free_cstr(&expansion);
	cvec_free_i(&valid_macros);
}
Beispiel #3
0
/************************************************************************
**  handle_eos : handle the end of a string.
************************************************************************/
int   handle_eos(void)
{
    if(PREVCH() == '\\') {
	if(checknl()) {
	    return(FILE_EOS);
	}
	else {
	    return(BACKSLASH_EOS);
	}
    }
    if(Macro_depth == 0) {	/* found end of file buffer or backslash */
	if(io_eob()) {		/* end of buffer in here is bad */
	    Msg_Temp = GET_MSG(1004);
	    SET_MSG (Msg_Text, Msg_Temp);
	    fatal (1004);
	}
	return(FILE_EOS);
    }

    again:
    switch(GETCH()) {
    case EOS_PAD:
        goto again;
    case EOS_ACTUAL:
	/*
	** Just finished expanding actual.  Check to see if there are
	** any more actuals to be expanded.  If there are, set up to
	** expand them and return.  Otherwise, set up to expand defn
	*/

	/* move expanded text of this actual to act_buffer */
	move_to_actual(CURRENT_TEXT, Exp_ptr);

	/* reset Exp_ptr for more expansions at this macro depth */
	Exp_ptr = CURRENT_TEXT;

	/* expand next actual if there, otherwise expand definition */
	expand_macro();

	return(ACTUAL_EOS);
	break;
    case EOS_DEFINITION:
	if(rescan_expansion()) {
	    return(RESCAN_EOS);
	}
	else {
	    return(DEFINITION_EOS);
	}
	break;
    case EOS_RESCAN:
	/*
	** Reset Current_char, Exp_ptr and Act_ptr, pop the macro
	*/

	/*	get input from the previous stream */
	Current_char = CURRENT_STRING;

	/* mark this macro as not expanding */
	DEFN_EXPANDING(CURRENT_MACRO)--;


	/*
	**	if looking for the actuals of a macro, these pointers
	**	should really not be reset, however, it is cleaner to
	**	save them before calling handle_eos, and restore them
	**	upon returning, than check a static variable here.
	*/
	if(Macro_depth == 1) {
	    Act_ptr = ACT_BUFFER;
	    Exp_ptr = EXP_BUFFER;
	}
	--Macro_depth;
	return(DEFINITION_EOS);
	break;
	/* the following conditional compile is so brackets match */
    }
}
Beispiel #4
0
unsigned int macro_expansion(preprocessor_state* preproc, rsw_cstr* expansion, unsigned long beginning, cvector_i* valid_macros, int macro_index)
{
	//vaild_macros should never be NULL unless I uncomment that alternative method in prescan_argument
	//int macro = (valid_macros) ? valid_macros->a[macro_index] : macro_index;
	int macro = valid_macros->a[macro_index];

	rsw_cstr local_expansion, scratch;
	init_cstr_str(&local_expansion, preproc->values.a[macro], strlen(preproc->values.a[macro]));
	init_cstr_str(&scratch, local_expansion.a, local_expansion.size);

	rsw_cstr arg_expansion;
	init_cstr_cap(&arg_expansion, 50);

	macro_params* p = GET_PARAM(&preproc->params, macro);
	int param_len, val_len, parens, loc;

	char* search, *found, *c;

	//beginning is start of macro name so jump forward len (the first c++ will jump over '(' )
	c = &expansion->a[beginning + strlen(preproc->macros.a[macro])];
	if (p->num_params != -1)
		while (isspace(*c)) ++c;

	parens = 0;
	for (int i=0; i < p->num_params; ++i) {
		val_len = 0;

		c++;
		while (isspace(*c)) ++c; //ignore spaces on edges ie after ( and ,

		if (*c == '(')
			parens++;
		do {
			val_len += snprintf(macro_buf+val_len, MAX_MACRO_LEN-val_len, "%c", *c);

			c++;
			if (*c == '(') {
				parens++;
			} else if (*c == ')') {
				parens--;
				if (parens == -1) {
					if (i != p->num_params-1)
						preprocessor_error(NULL, &preproc->lexer, "more arguments expected for macro\n");
					break;
				}
			}
		} while (*c != ',' || parens > 0);

		cstr_insert_str(&arg_expansion, 0, macro_buf, val_len);
		prescan_argument(preproc, &arg_expansion);

		param_len = strlen(p->names[i]);
		
		loc = cstr_find_str(&scratch, p->names[i]);
		while (loc != (size_t)-1) {
			cstr_replace_substr(&local_expansion, loc, param_len, arg_expansion.a, arg_expansion.size); //assuming size doesn't include \0
			cstr_replace_substr(&scratch, loc, param_len, arg_expansion.a, arg_expansion.size); //assuming size doesn't include \0

			for (int j=loc; j < loc+arg_expansion.size; ++j)
				scratch.a[j] = '*';

			loc = cstr_find_str_start_at(&scratch, p->names[i], loc+arg_expansion.size); //-1 here?
		}

		arg_expansion.size = 0;
	}
	
	if (!p->num_params) // increment for ) because it didn't get it in loop
		++c;

	//TODO test without this
	if (p->num_params == -1)
		--c;

	rescan_expansion(preproc, &local_expansion, valid_macros, macro_index);

	cstr_replace_substr(expansion, beginning, (c - expansion->a) - beginning + 1, local_expansion.a, local_expansion.size);

	unsigned int local_size = local_expansion.size;

	free_cstr(&local_expansion);
	free_cstr(&scratch);
	free_cstr(&arg_expansion);

	return beginning + local_size;
}