示例#1
0
expression* make_expression(program_state* prog)
{
	expr_block* b = (expr_block*)cvec_back_void(&prog->expressions);
	if (b->n == b->used) {
		expr_block b_new;
		make_expression_block(32, &b_new);
		cvec_push_void(&prog->expressions, &b_new);
		b = (expr_block*)cvec_back_void(&prog->expressions);
	}
	return &b->data[b->used++];
}
示例#2
0
void handle_define(preprocessor_state* preproc)
{
	FILE* input = preproc->input;
	lexer_state* lexer = &preproc->lexer;

	cvector_token_lex tlex;
	cvec_token_lex(&tlex, 0, 10, free_token_lex, NULL);
	
	token_lex tok_lex[4];
	tok_lex[0] = read_token(input, lexer, NULL);

	if (tok_lex[0].tok.type != ID) {
		preprocessor_error(&tok_lex[0], lexer, "expected ID for macro name,");
	}
	
	macro_params p = { -1, NULL };
	char* check_val = look_up_macro(preproc, tok_lex[0].tok.v.id);

	lexer_state save_lex = *lexer;
	long fpos = ftell(input);
	tok_lex[1] = read_token(input, lexer, NULL);

	if (tok_lex[1].line != tok_lex[0].line) { //object macro empty string
		*lexer = save_lex;
		if (fseek(input, fpos, SEEK_SET)) {
			perror("fseek failure in handle_define");
			exit(0);
		}

		if (check_val && strcmp(check_val, "")) {
			preprocessor_error(NULL, lexer, "redefinition of %s\n", tok_lex[0].tok.v.id);
		}
		if (!check_val) {
			cvec_push_str(&preproc->macros, tok_lex[0].tok.v.id);
			cvec_push_str(&preproc->values, "");
			cvec_push_void(&preproc->params, &p);
		}
		goto exit;
	}
	
	if (tok_lex[1].tok.type == LPAREN) { //function style macro
		int n = 0, i;
		tok_lex[2] = read_token(input, lexer, NULL);
		while (tok_lex[2].tok.type == ID) {
			n++;
			cvec_push_token_lex(&tlex, &tok_lex[2]);
			//don't free id because vector will
			tok_lex[3] = read_token(input, lexer, NULL);
			if (tok_lex[3].tok.type != COMMA)
				break;

			tok_lex[2] = read_token(input, lexer, NULL);
		}

		//TODO better way to express error logic?
		if (tok_lex[2].tok.type != ID) {
 		   	if (n != 0 || n == 0 && tok_lex[2].tok.type != RPAREN)
				preprocessor_error(NULL, lexer, "improperly formed function style macro\n");
		} else if (tok_lex[3].tok.type != RPAREN) {
			preprocessor_error(NULL, lexer, "improperly formed function style macro\n");
		}

		p.num_params = n;
		if (n) {
			p.names = malloc(n * sizeof(char*)); assert(p.names);
		}

		for (i=0; i < n; ++i) {
			p.names[i] = mystrdup(tlex.a[i].tok.v.id);
		}
	} else {
		//put it back, it's part of the macro value
		//it's handled below
		*lexer = save_lex;
		if (fseek(input, fpos, SEEK_SET)) {
			perror("fseek failure in preprocess_file");
			exit(0);
		}
	}

	memset(macro_buf, 0, MAX_MACRO_LEN);

	save_lex = *lexer;
	if ((fpos = ftell(input)) == -1) {
		perror("ftell failure in handle_define");
		exit(0);
	}

	tok_lex[2] = read_token(input, lexer, NULL);

	while (tok_lex[0].line == lexer->cur_line) {
		cvec_push_token_lex(&tlex, &tok_lex[2]);
		save_lex = *lexer;
		if ((fpos = ftell(input)) == -1) {
			perror("ftell failure in handle_define");
			exit(0);
		}
		//don't free id bceause vector will do it
		tok_lex[2] = read_token(input, lexer, NULL);
	}

	if (tok_lex[2].tok.type == ID || tok_lex[2].tok.type == STR_LITERAL)
		free(tok_lex[2].tok.v.id);

	*lexer = save_lex;
	if (fseek(input, fpos, SEEK_SET)) {
		perror("fseek failue in handle_define");
		exit(0);
	}

	int buf_pos = 0;
	int res, len;

	for (int i= (p.num_params == -1) ? 0 : p.num_params; i < tlex.size; ++i) {
		res = print_token_to_str(&tlex.a[i].tok, &macro_buf[buf_pos], MAX_MACRO_LEN-buf_pos);

		if (res < 0 || res >= MAX_MACRO_LEN - buf_pos) {
			preprocessor_error(NULL, lexer, "macro is too long or output error\n");
		}
		len = res;
		buf_pos += res;

		//	inserting a space for each whitespace character
		//	ie it wouldn't look the same if the programmer used any tabs etc but it's good enough
		if (i != tlex.size-1 && tlex.a[i+1].pos > tlex.a[i].pos + len) {
			res = snprintf(&macro_buf[buf_pos], MAX_MACRO_LEN-buf_pos, "%*s", tlex.a[i+1].pos - (tlex.a[i].pos + len), ""); 

			if (res < 0 || res >= MAX_MACRO_LEN - buf_pos) {
				preprocessor_error(NULL, lexer, "macro is too long or output error\n");
			}
			buf_pos += res;
		}
	}

	//benign redefinitions are allowed (ie the definitions are the same)
	if (check_val && strcmp(check_val, macro_buf)) {
		preprocessor_error(NULL, lexer, "redefinition of macro %s\n", tlex.a[0].tok.v.id);
	}

	//push new macro
	cvec_push_str(&preproc->macros, tok_lex[0].tok.v.id);
	cvec_push_str(&preproc->values, macro_buf);
	cvec_push_void(&preproc->params, &p);

exit:
	free(tok_lex[0].tok.v.id);  // name of macro

	if (tok_lex[1].tok.type == ID || tok_lex[1].tok.type == STR_LITERAL)
		free(tok_lex[1].tok.v.id);


	cvec_free_token_lex(&tlex);
}