static token_t pp_token;
static bool resolve_escape_sequences = false;
static bool ignore_unknown_chars = true;
-static bool in_pp_directive;
static bool skip_mode;
static FILE *out;
static struct obstack pp_obstack;
static source_position_t expansion_pos;
static pp_definition_t *current_expansion = NULL;
static strset_t stringset;
-static preprocessor_token_kind_t last_token = TP_ERROR;
+static preprocessor_token_kind_t last_token;
static searchpath_entry_t *searchpath;
source_position.input_name = pp_token.base.source_position.input_name;
source_position.lineno = start_linenr;
errorf(&source_position, "string has no end");
- pp_token.kind = TP_ERROR;
- return;
+ goto end_of_string;
}
case '"':
case EOF:
parse_error("EOF while parsing character constant");
- pp_token.kind = TP_ERROR;
- return;
+ goto end_of_wide_char_constant;
default:
obstack_grow_symbol(&symbol_obstack, input.c);
source_position.input_name = pp_token.base.source_position.input_name;
source_position.lineno = start_linenr;
errorf(&source_position, "EOF while parsing character constant");
- pp_token.kind = TP_ERROR;
- return;
+ goto end_of_char_constant;
}
case '\'':
return;
/* if it was an identifier then we might need to expand again */
- pp_definition_t *symbol_definition = pp_token.identifier.symbol->pp_definition;
+ pp_definition_t *const symbol_definition = pp_token.base.symbol->pp_definition;
if (symbol_definition != NULL && !symbol_definition->is_expanding) {
symbol_definition->parent_expansion = definition;
symbol_definition->expand_pos = 0;
case '*':
next_char();
if (input.c == '/') {
+ if (input.position.lineno != input.output_line)
+ info.whitespace = input.position.colno;
next_char();
- info.whitespace += input.position.colno-1;
return;
}
break;
MATCH_NEWLINE(
- info.at_line_begin |= !in_pp_directive;
break;
)
}
}
-static void eat_pp(int type)
+static void eat_pp(preprocessor_token_kind_t const type)
{
(void) type;
assert(pp_token.kind == type);
symbol_t *symbol = symbol_table_insert(string);
- pp_token.kind = symbol->pp_ID;
- pp_token.identifier.symbol = symbol;
+ pp_token.kind = symbol->pp_ID;
+ pp_token.base.symbol = symbol;
/* we can free the memory from symbol obstack if we already had an entry in
* the symbol table */
info.had_whitespace = false;
restart:
pp_token.base.source_position = input.position;
+ pp_token.base.symbol = NULL;
+
switch (input.c) {
case ' ':
case '\t':
if (!ignore_unknown_chars) {
errorf(&pp_token.base.source_position,
"unknown character '%c' found\n", input.c);
- pp_token.kind = TP_ERROR;
+ goto restart;
} else {
pp_token.kind = input.c;
+ return;
}
- return;
}
}
input.output_line = pos->lineno-1;
}
-static void emit_newlines(void)
+static bool emit_newlines(void)
{
unsigned delta = pp_token.base.source_position.lineno - input.output_line;
+ if (delta == 0)
+ return false;
if (delta >= 9) {
fputc('\n', out);
}
}
input.output_line = pp_token.base.source_position.lineno;
+
+ for (unsigned i = 0; i < info.whitespace; ++i)
+ fputc(' ', out);
+
+ return true;
}
static void emit_pp_token(void)
if (skip_mode)
return;
- if (info.at_line_begin) {
- emit_newlines();
-
- for (unsigned i = 0; i < info.whitespace; ++i)
- fputc(' ', out);
-
- } else if (info.had_whitespace ||
- tokens_would_paste(last_token, pp_token.kind)) {
+ if (!emit_newlines() &&
+ (info.had_whitespace || tokens_would_paste(last_token, pp_token.kind)))
fputc(' ', out);
- }
switch (pp_token.kind) {
case TP_IDENTIFIER:
- fputs(pp_token.identifier.symbol->string, out);
+ fputs(pp_token.base.symbol->string, out);
break;
case TP_NUMBER:
fputs(pp_token.number.number.begin, out);
switch (token1->kind) {
case TP_IDENTIFIER:
- return token1->identifier.symbol == token2->identifier.symbol;
+ return token1->base.symbol == token2->base.symbol;
+
case TP_NUMBER:
case TP_CHARACTER_CONSTANT:
case TP_STRING_LITERAL:
"expected identifier after #define, got '%t'", &pp_token);
goto error_out;
}
- symbol_t *symbol = pp_token.identifier.symbol;
+ symbol_t *const symbol = pp_token.base.symbol;
pp_definition_t *new_definition
= obstack_alloc(&pp_obstack, sizeof(new_definition[0]));
}
break;
case TP_IDENTIFIER:
- obstack_ptr_grow(&pp_obstack, pp_token.identifier.symbol);
+ obstack_ptr_grow(&pp_obstack, pp_token.base.symbol);
next_preprocessing_token();
if (pp_token.kind == ',') {
return;
}
- symbol_t *symbol = pp_token.identifier.symbol;
- symbol->pp_definition = NULL;
+ pp_token.base.symbol->pp_definition = NULL;
next_preprocessing_token();
if (!info.at_line_begin) {
eat_pp_directive();
}
-static const char *parse_headername(void)
+static void parse_headername(void)
{
+ const source_position_t start_position = input.position;
+ string_t string = {NULL, 0};
+ assert(obstack_object_size(&symbol_obstack) == 0);
+
/* behind an #include we can have the special headername lexems.
* They're only allowed behind an #include so they're not recognized
* by the normal next_preprocessing_token. We handle them as a special
* exception here */
if (info.at_line_begin) {
parse_error("expected headername after #include");
- return NULL;
+ goto finish_error;
}
- assert(obstack_object_size(&symbol_obstack) == 0);
-
/* check wether we have a "... or <... headername */
switch (input.c) {
case '<':
/* fallthrough */
MATCH_NEWLINE(
parse_error("header name without closing '>'");
- return NULL;
+ goto finish_error;
)
case '>':
next_char();
/* fallthrough */
MATCH_NEWLINE(
parse_error("header name without closing '>'");
- return NULL;
+ goto finish_error;
)
case '"':
next_char();
finished_headername:
obstack_1grow(&symbol_obstack, '\0');
- char *headername = obstack_finish(&symbol_obstack);
-
- /* TODO: iterate search-path to find the file */
-
- skip_whitespace();
-
- return identify_string(headername);
+ const size_t size = (size_t)obstack_object_size(&symbol_obstack);
+ char *const headername = obstack_finish(&symbol_obstack);
+ string = make_string(headername, size);
+
+finish_error:
+ pp_token.base.source_position = start_position;
+ pp_token.kind = TP_HEADERNAME;
+ pp_token.string.string = string;
}
static bool do_include(bool system_include, const char *headername)
{
+ size_t headername_len = strlen(headername);
if (!system_include) {
- /* for "bla" includes first try current dir
- * TODO: this isn't correct, should be the directory of the source file
- */
+ /* put dirname of current input on obstack */
+ const char *filename = input.position.input_name;
+ const char *last_slash = strrchr(filename, '/');
+ if (last_slash != NULL) {
+ size_t len = last_slash - filename;
+ obstack_grow(&symbol_obstack, filename, len + 1);
+ obstack_grow0(&symbol_obstack, headername, headername_len);
+ char *complete_path = obstack_finish(&symbol_obstack);
+ headername = identify_string(complete_path);
+ }
+
FILE *file = fopen(headername, "r");
if (file != NULL) {
switch_input(file, headername);
}
}
- size_t headername_len = strlen(headername);
- assert(obstack_object_size(&pp_obstack) == 0);
+ assert(obstack_object_size(&symbol_obstack) == 0);
/* check searchpath */
for (searchpath_entry_t *entry = searchpath; entry != NULL;
entry = entry->next) {
const char *path = entry->path;
size_t len = strlen(path);
- obstack_grow(&pp_obstack, path, len);
+ obstack_grow(&symbol_obstack, path, len);
if (path[len-1] != '/')
- obstack_1grow(&pp_obstack, '/');
- obstack_grow(&pp_obstack, headername, headername_len+1);
+ obstack_1grow(&symbol_obstack, '/');
+ obstack_grow(&symbol_obstack, headername, headername_len+1);
- char *complete_path = obstack_finish(&pp_obstack);
+ char *complete_path = obstack_finish(&symbol_obstack);
FILE *file = fopen(complete_path, "r");
if (file != NULL) {
const char *filename = identify_string(complete_path);
switch_input(file, filename);
return true;
+ } else {
+ obstack_free(&symbol_obstack, complete_path);
}
- obstack_free(&pp_obstack, complete_path);
}
return false;
}
+/* read till next newline character, only for parse_include_directive(),
+ * use eat_pp_directive() in all other cases */
+static void skip_till_newline(void)
+{
+ /* skip till newline */
+ while (true) {
+ switch (input.c) {
+ MATCH_NEWLINE(
+ return;
+ )
+ case EOF:
+ return;
+ }
+ next_char();
+ }
+}
+
static bool parse_include_directive(void)
{
/* don't eat the TP_include here!
* we need an alternative parsing for the next token */
skip_whitespace();
bool system_include = input.c == '<';
- const char *headername = parse_headername();
- if (headername == NULL) {
+ parse_headername();
+ string_t headername = pp_token.string.string;
+ if (headername.begin == NULL) {
eat_pp_directive();
return false;
}
+ skip_whitespace();
if (!info.at_line_begin) {
warningf(WARN_OTHER, &pp_token.base.source_position,
"extra tokens at end of #include directive");
- eat_pp_directive();
+ skip_till_newline();
}
if (n_inputs > INCLUDE_LIMIT) {
return false;
}
- /* we have to reenable space counting and macro expansion here,
- * because it is still disabled in directive parsing,
- * but we will trigger a preprocessing token reading of the new file
- * now and need expansions/space counting */
- in_pp_directive = false;
-
/* switch inputs */
emit_newlines();
push_input();
- bool res = do_include(system_include, headername);
+ bool res = do_include(system_include, pp_token.string.string.begin);
if (!res) {
errorf(&pp_token.base.source_position,
- "failed including '%s': %s", headername, strerror(errno));
+ "failed including '%S': %s", pp_token.string, strerror(errno));
pop_restore_input();
return false;
}
/* just take the true case in the hope to avoid further errors */
condition = true;
} else {
- symbol_t *symbol = pp_token.identifier.symbol;
- pp_definition_t *pp_definition = symbol->pp_definition;
+ /* evaluate wether we are in true or false case */
+ condition = !pp_token.base.symbol->pp_definition == is_ifndef;
+
next_preprocessing_token();
if (!info.at_line_begin) {
is_ifndef ? "ifndef" : "ifdef");
eat_pp_directive();
}
-
- /* evaluate wether we are in true or false case */
- condition = is_ifndef ? pp_definition == NULL : pp_definition != NULL;
}
pp_conditional_t *conditional = push_conditional();
static void parse_preprocessing_directive(void)
{
- in_pp_directive = true;
eat_pp('#');
+ if (info.at_line_begin) {
+ /* empty directive */
+ return;
+ }
+
if (skip_mode) {
switch (pp_token.kind) {
case TP_ifdef:
}
}
- in_pp_directive = false;
assert(info.at_line_begin);
}
/* simplistic commandline parser */
const char *filename = NULL;
+ const char *output = NULL;
for (int i = 1; i < argc; ++i) {
const char *opt = argv[i];
if (streq(opt, "-I")) {
continue;
} else if (streq(opt, "-E")) {
/* ignore */
+ } else if (streq(opt, "-o")) {
+ output = argv[++i];
+ continue;
} else if (opt[0] == '-') {
fprintf(stderr, "Unknown option '%s'\n", opt);
} else {
return 1;
}
- out = stdout;
+ if (output == NULL) {
+ out = stdout;
+ } else {
+ out = fopen(output, "w");
+ if (out == NULL) {
+ fprintf(stderr, "Couldn't open output '%s'\n", output);
+ return 1;
+ }
+ }
/* just here for gcc compatibility */
fprintf(out, "# 1 \"%s\"\n", filename);
continue;
} else if (pp_token.kind == TP_EOF) {
goto end_of_main_loop;
- } else if (pp_token.kind == TP_IDENTIFIER && !in_pp_directive) {
- symbol_t *symbol = pp_token.identifier.symbol;
- pp_definition_t *pp_definition = symbol->pp_definition;
+ } else if (pp_token.kind == TP_IDENTIFIER) {
+ symbol_t *const symbol = pp_token.base.symbol;
+ pp_definition_t *const pp_definition = symbol->pp_definition;
if (pp_definition != NULL && !pp_definition->is_expanding) {
expansion_pos = pp_token.base.source_position;
if (pp_definition->has_parameters) {
token_t next_token = pp_token;
/* restore identifier token */
pp_token.kind = TP_IDENTIFIER;
- pp_token.identifier.symbol = symbol;
+ pp_token.base.symbol = symbol;
pp_token.base.source_position = position;
info = old_info;
emit_pp_token();
fputc('\n', out);
check_unclosed_conditionals();
close_input();
+ if (out != stdout)
+ fclose(out);
obstack_free(&input_obstack, NULL);
obstack_free(&pp_obstack, NULL);