aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2025-08-26 21:57:09 +0900
committernsfisis <nsfisis@gmail.com>2025-08-26 21:57:09 +0900
commitdd08b39ac5fc2eeb555bf40596279487fcea5f95 (patch)
tree859e4c45cc783f9fd9e29a5968f3964c04d5fb1f
parenta70bc7804c4c1cb07976d684b64b5a2fe3b68f93 (diff)
downloadducc-dd08b39ac5fc2eeb555bf40596279487fcea5f95.tar.gz
ducc-dd08b39ac5fc2eeb555bf40596279487fcea5f95.tar.zst
ducc-dd08b39ac5fc2eeb555bf40596279487fcea5f95.zip
feat: improve handling of non-directive preprocessing directives
-rw-r--r--src/preprocess.c60
-rw-r--r--src/token.c8
-rw-r--r--src/token.h1
-rw-r--r--tests/083.sh16
4 files changed, 57 insertions, 28 deletions
diff --git a/src/preprocess.c b/src/preprocess.c
index 8890800..a0193a8 100644
--- a/src/preprocess.c
+++ b/src/preprocess.c
@@ -168,7 +168,7 @@ static PpLexer* pplexer_new(InFile* src) {
return ppl;
}
-static TokenKind pplexer_tokenize_pp_directive(PpLexer* ppl) {
+static void pplexer_tokenize_pp_directive(PpLexer* ppl, Token* tok) {
// Skip whitespaces after '#'.
char c;
while (isspace((c = infile_peek_char(ppl->src)))) {
@@ -178,7 +178,8 @@ static TokenKind pplexer_tokenize_pp_directive(PpLexer* ppl) {
}
// '#' new-line
if (c == '\n') {
- return TokenKind_pp_directive_nop;
+ tok->kind = TokenKind_pp_directive_nop;
+ return;
}
SourceLocation pp_directive_name_start_loc = ppl->src->loc;
@@ -192,43 +193,43 @@ static TokenKind pplexer_tokenize_pp_directive(PpLexer* ppl) {
const char* pp_directive_name = builder.buf;
if (builder.len == 0) {
- return TokenKind_hash;
+ tok->kind = TokenKind_hash;
} else if (strcmp(pp_directive_name, "define") == 0) {
- return TokenKind_pp_directive_define;
+ tok->kind = TokenKind_pp_directive_define;
} else if (strcmp(pp_directive_name, "elif") == 0) {
- return TokenKind_pp_directive_elif;
+ tok->kind = TokenKind_pp_directive_elif;
} else if (strcmp(pp_directive_name, "elifdef") == 0) {
- return TokenKind_pp_directive_elifdef;
+ tok->kind = TokenKind_pp_directive_elifdef;
} else if (strcmp(pp_directive_name, "elifndef") == 0) {
- return TokenKind_pp_directive_elifndef;
+ tok->kind = TokenKind_pp_directive_elifndef;
} else if (strcmp(pp_directive_name, "else") == 0) {
- return TokenKind_pp_directive_else;
+ tok->kind = TokenKind_pp_directive_else;
} else if (strcmp(pp_directive_name, "embed") == 0) {
- return TokenKind_pp_directive_embed;
+ tok->kind = TokenKind_pp_directive_embed;
} else if (strcmp(pp_directive_name, "endif") == 0) {
- return TokenKind_pp_directive_endif;
+ tok->kind = TokenKind_pp_directive_endif;
} else if (strcmp(pp_directive_name, "error") == 0) {
- return TokenKind_pp_directive_error;
+ tok->kind = TokenKind_pp_directive_error;
} else if (strcmp(pp_directive_name, "if") == 0) {
- return TokenKind_pp_directive_if;
+ tok->kind = TokenKind_pp_directive_if;
} else if (strcmp(pp_directive_name, "ifdef") == 0) {
- return TokenKind_pp_directive_ifdef;
+ tok->kind = TokenKind_pp_directive_ifdef;
} else if (strcmp(pp_directive_name, "ifndef") == 0) {
- return TokenKind_pp_directive_ifndef;
+ tok->kind = TokenKind_pp_directive_ifndef;
} else if (strcmp(pp_directive_name, "include") == 0) {
ppl->expect_header_name = TRUE;
- return TokenKind_pp_directive_include;
+ tok->kind = TokenKind_pp_directive_include;
} else if (strcmp(pp_directive_name, "line") == 0) {
- return TokenKind_pp_directive_line;
+ tok->kind = TokenKind_pp_directive_line;
} else if (strcmp(pp_directive_name, "pragma") == 0) {
- return TokenKind_pp_directive_pragma;
+ tok->kind = TokenKind_pp_directive_pragma;
} else if (strcmp(pp_directive_name, "undef") == 0) {
- return TokenKind_pp_directive_undef;
+ tok->kind = TokenKind_pp_directive_undef;
} else if (strcmp(pp_directive_name, "warning") == 0) {
- return TokenKind_pp_directive_warning;
+ tok->kind = TokenKind_pp_directive_warning;
} else {
- fatal_error("%s:%d: unknown preprocessor directive (%s)", pp_directive_name_start_loc.filename,
- pp_directive_name_start_loc.line, pp_directive_name);
+ tok->kind = TokenKind_pp_directive_non_directive;
+ tok->value.string = pp_directive_name;
}
}
@@ -448,7 +449,11 @@ static void pplexer_tokenize_all(PpLexer* ppl) {
if (infile_consume_if(ppl->src, '#')) {
tok->kind = TokenKind_hashhash;
} else {
- tok->kind = ppl->at_bol ? pplexer_tokenize_pp_directive(ppl) : TokenKind_hash;
+ if (ppl->at_bol) {
+ pplexer_tokenize_pp_directive(ppl, tok);
+ } else {
+ tok->kind = TokenKind_hash;
+ }
}
} else if (c == '\'') {
infile_next_char(ppl->src);
@@ -512,7 +517,7 @@ static void pplexer_tokenize_all(PpLexer* ppl) {
}
if (ppl->at_bol && infile_peek_char(ppl->src) == '#') {
infile_next_char(ppl->src);
- tok->kind = pplexer_tokenize_pp_directive(ppl);
+ pplexer_tokenize_pp_directive(ppl, tok);
} else {
tok->kind = TokenKind_whitespace;
}
@@ -963,6 +968,13 @@ static void process_nop_directive(Preprocessor* pp, int directive_token_pos) {
remove_directive_tokens(pp, directive_token_pos, pp->pos);
}
+static void process_non_directive_directive(Preprocessor* pp, int directive_token_pos) {
+ Token* tok = pp_token_at(pp, directive_token_pos);
+ // C23 6.10.1.13:
+ // The execution of a non-directive preprocessing directive results in undefined behavior.
+ fatal_error("%s:%d: invalid preprocessing directive, '%s'", tok->loc.filename, tok->loc.line, token_stringify(tok));
+}
+
// ws ::= many0(<Whitespace>)
// macro-arguments ::= '(' <ws> opt(<any-token> <ws> many0(',' <ws> <any-token> <ws>)) ')'
static MacroArgArray* pp_parse_macro_arguments(Preprocessor* pp) {
@@ -1070,6 +1082,8 @@ static void process_pp_directive(Preprocessor* pp) {
process_pragma_directive(pp, first_token_pos);
} else if (tok->kind == TokenKind_pp_directive_nop) {
process_nop_directive(pp, first_token_pos);
+ } else if (tok->kind == TokenKind_pp_directive_non_directive) {
+ process_non_directive_directive(pp, first_token_pos);
} else if (tok->kind == TokenKind_ident) {
BOOL expanded = expand_macro(pp);
if (expanded) {
diff --git a/src/token.c b/src/token.c
index 71eabaf..e08e07f 100644
--- a/src/token.c
+++ b/src/token.c
@@ -44,6 +44,8 @@ const char* token_kind_stringify(TokenKind k) {
return "#include";
else if (k == TokenKind_pp_directive_line)
return "#line";
+ else if (k == TokenKind_pp_directive_non_directive)
+ return "#<non-directive>";
else if (k == TokenKind_pp_directive_nop)
return "#";
else if (k == TokenKind_pp_directive_pragma)
@@ -272,7 +274,11 @@ const char* token_kind_stringify(TokenKind k) {
const char* token_stringify(Token* t) {
TokenKind k = t->kind;
- if (k == TokenKind_literal_int) {
+ if (k == TokenKind_pp_directive_non_directive) {
+ char* buf = calloc(strlen(t->value.string) + 1 + 1, sizeof(char));
+ sprintf(buf, "#%s", t->value.string);
+ return buf;
+ } else if (k == TokenKind_literal_int) {
const char* kind_str = token_kind_stringify(k);
char* buf = calloc(10 + strlen(kind_str) + 3 + 1, sizeof(char));
sprintf(buf, "%d (%s)", t->value.integer, kind_str);
diff --git a/src/token.h b/src/token.h
index 034b3b3..3ff5e2b 100644
--- a/src/token.h
+++ b/src/token.h
@@ -27,6 +27,7 @@ enum TokenKind {
TokenKind_pp_directive_ifndef,
TokenKind_pp_directive_include,
TokenKind_pp_directive_line,
+ TokenKind_pp_directive_non_directive,
TokenKind_pp_directive_nop,
TokenKind_pp_directive_pragma,
TokenKind_pp_directive_undef,
diff --git a/tests/083.sh b/tests/083.sh
index 64d03e5..2152666 100644
--- a/tests/083.sh
+++ b/tests/083.sh
@@ -1,7 +1,6 @@
cat <<'EOF' > expected
-main.c:1: unknown preprocessor directive (foo)
+main.c:1: invalid preprocessing directive, '#foo'
EOF
-
test_compile_error <<'EOF'
#foo
@@ -9,11 +8,20 @@ int main() {}
EOF
cat <<'EOF' > expected
-main.c:1: unknown preprocessor directive (bar)
+main.c:1: invalid preprocessing directive, '#bar'
EOF
-
test_compile_error <<'EOF'
# bar 1 2 3
int main() {}
EOF
+
+cat <<'EOF' > expected
+EOF
+test_diff <<'EOF'
+#if 0
+#baz
+#endif
+
+int main() {}
+EOF