aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2025-08-30 01:13:30 +0900
committernsfisis <nsfisis@gmail.com>2025-08-30 01:13:30 +0900
commit941691595382f55c588a2d8fea79142be5146791 (patch)
treee3b17487e72ad88719bbacbcfca64e56da9974a4
parent194e87a88290a4b3025436709e1f3064aecd00cd (diff)
downloadducc-941691595382f55c588a2d8fea79142be5146791.tar.gz
ducc-941691595382f55c588a2d8fea79142be5146791.tar.zst
ducc-941691595382f55c588a2d8fea79142be5146791.zip
feat: implement ## operator
-rw-r--r--src/preprocess.c73
-rw-r--r--src/std.h1
-rw-r--r--tests/107.sh42
3 files changed, 115 insertions, 1 deletions
diff --git a/src/preprocess.c b/src/preprocess.c
index e47a390..b94f004 100644
--- a/src/preprocess.c
+++ b/src/preprocess.c
@@ -770,6 +770,48 @@ static MacroArgArray* pp_parse_macro_arguments(Preprocessor* pp) {
return args;
}
+static Token* concat_two_tokens(Token* left, Token* right) {
+ StrBuilder builder;
+ strbuilder_init(&builder);
+
+ // Left
+ if (left->kind == TokenKind_ident) {
+ strbuilder_append_string(&builder, left->value.string);
+ } else if (left->kind == TokenKind_literal_int) {
+ char buf[32];
+ sprintf(buf, "%d", left->value.integer);
+ strbuilder_append_string(&builder, buf);
+ } else {
+ strbuilder_append_string(&builder, token_stringify(left));
+ }
+
+ // Right
+ if (right->kind == TokenKind_ident) {
+ strbuilder_append_string(&builder, right->value.string);
+ } else if (right->kind == TokenKind_literal_int) {
+ char buf[32];
+ sprintf(buf, "%d", right->value.integer);
+ strbuilder_append_string(&builder, buf);
+ } else {
+ strbuilder_append_string(&builder, token_stringify(right));
+ }
+
+ // Concat
+ Token* result = calloc(1, sizeof(Token));
+
+ char* endptr;
+ int val = strtol(builder.buf, &endptr, 10);
+ if (*endptr == '\0') {
+ result->kind = TokenKind_literal_int;
+ result->value.integer = val;
+ } else {
+ result->kind = TokenKind_ident;
+ result->value.string = builder.buf;
+ }
+
+ return result;
+}
+
static BOOL expand_macro(Preprocessor* pp) {
int macro_name_pos = pp->pos;
Token* macro_name = next_pp_token(pp);
@@ -783,6 +825,8 @@ static BOOL expand_macro(Preprocessor* pp) {
if (macro->kind == MacroKind_func) {
MacroArgArray* args = pp_parse_macro_arguments(pp);
replace_pp_tokens(pp, macro_name_pos, pp->pos, &macro->replacements);
+
+ // Parameter substitution
for (size_t i = 0; i < macro->replacements.len; ++i) {
Token* tok = pp_token_at(pp, macro_name_pos + i);
int macro_param_idx = macro_find_param(macro, tok);
@@ -790,8 +834,35 @@ static BOOL expand_macro(Preprocessor* pp) {
replace_pp_tokens(pp, macro_name_pos + i, macro_name_pos + i + 1, &args->data[macro_param_idx].tokens);
}
}
+
+ // Handle ## operator
+ size_t result_len = 0;
+ for (int i = macro_name_pos; i < pp->pos && pp_token_at(pp, i)->kind != TokenKind_newline; ++i) {
+ Token* tok = pp_token_at(pp, i);
+ if (tok->kind == TokenKind_hashhash) {
+ // Concatenate previous and next tokens
+ if (result_len > 0 && i + 1 < pp->pos) {
+ Token* left = pp_token_at(pp, i - 1);
+ Token* right = pp_token_at(pp, i + 1);
+ Token* concatenated = concat_two_tokens(left, right);
+
+ // Replace the three tokens (left ## right) with the concatenated one
+ TokenArray single_token;
+ tokens_init(&single_token, 1);
+ *tokens_push_new(&single_token) = *concatenated;
+ int new_pos = replace_pp_tokens(pp, i - 1, i + 2, &single_token);
+ i = new_pos - 1;
+ ++result_len;
+ } else {
+ fatal_error("invalid usage of ## operator");
+ }
+ } else {
+ ++result_len;
+ }
+ }
+
// Inherit a source location from the original macro token.
- for (size_t i = 0; i < macro->replacements.len; ++i) {
+ for (size_t i = 0; i < result_len; ++i) {
pp_token_at(pp, macro_name_pos + i)->loc = original_loc;
}
} else if (macro->kind == MacroKind_obj) {
diff --git a/src/std.h b/src/std.h
index 0792ce4..2353026 100644
--- a/src/std.h
+++ b/src/std.h
@@ -34,6 +34,7 @@ int strncmp(const char*, const char*, size_t);
char* strdup(const char*);
char* strndup(const char*, size_t);
char* strstr(const char*, const char*);
+long strtol(const char*, char**, int);
int system(const char*);
#define assert(x) \
diff --git a/tests/107.sh b/tests/107.sh
new file mode 100644
index 0000000..bb0c1a2
--- /dev/null
+++ b/tests/107.sh
@@ -0,0 +1,42 @@
+cat <<'EOF' > expected
+foobar=100
+prefix_test=200
+test_suffix=300
+var_1=10
+var_2=20
+var_A=30
+number_12=12
+EOF
+
+test_diff <<'EOF'
+int printf();
+
+#define CONCAT(a, b) a##b
+#define PREFIX(name) prefix_##name
+#define SUFFIX(name) name##_suffix
+
+int CONCAT(foo, bar) = 100;
+int PREFIX(test) = 200;
+int SUFFIX(test) = 300;
+
+#define MAKE_VAR(n) var_##n
+int MAKE_VAR(1) = 10;
+int MAKE_VAR(2) = 20;
+
+#define A 0
+int MAKE_VAR(A) = 30;
+
+#define NUMBER(x, y) number_##x##y
+int NUMBER(1, 2) = 12;
+
+int main() {
+ printf("foobar=%d\n", foobar);
+ printf("prefix_test=%d\n", prefix_test);
+ printf("test_suffix=%d\n", test_suffix);
+ printf("var_1=%d\n", var_1);
+ printf("var_2=%d\n", var_2);
+ printf("var_A=%d\n", var_A);
+ printf("number_12=%d\n", number_12);
+ return 0;
+}
+EOF