From: yu.dongliang <18588496441@163.com> Date: Sat, 1 Aug 2026 08:09:54 +0000 (+0800) Subject: 1, support macro: __VA_ARGS__, #error, support 'defined' with () in #if, X-Git-Url: http://baseworks.info/?a=commitdiff_plain;h=eb46170723cc0fdc59653aa87ac398dd351540ba;p=scf.git 1, support macro: __VA_ARGS__, #error, support 'defined' with () in #if, 2, ingnore macro: #pragma, #line, 3, add some 'lex check' for wrong source code. --- diff --git a/core/scf_lex_word.h b/core/scf_lex_word.h index 71f0edc..fae6d83 100644 --- a/core/scf_lex_word.h +++ b/core/scf_lex_word.h @@ -75,7 +75,7 @@ enum scf_lex_words SCF_LEX_N_OPS, // number of operators SCF_LEX_WORD_RANGE, // .. range - SCF_LEX_WORD_VAR_ARGS, // ... variable args + SCF_LEX_WORD_VA_ARGS, // ... variable args SCF_LEX_WORD_LB, // { left brace SCF_LEX_WORD_RB, // } right brace @@ -113,10 +113,15 @@ enum scf_lex_words SCF_LEX_WORD_KEY_OPERATOR, // operator SCF_LEX_WORD_KEY_UNDERLINE, // _ underline + // macro key word SCF_LEX_WORD_KEY_INCLUDE, // #include SCF_LEX_WORD_KEY_DEFINE, // #define SCF_LEX_WORD_KEY_UNDEF, // #undef + SCF_LEX_WORD_KEY_ERROR, // #error + SCF_LEX_WORD_KEY_LINE, // #line + SCF_LEX_WORD_KEY_PRAGMA, // #pragma + SCF_LEX_WORD_KEY_IFDEF, // #ifdef SCF_LEX_WORD_KEY_IFNDEF, // #ifndef SCF_LEX_WORD_KEY_ELIF, // #elif @@ -216,6 +221,7 @@ struct scf_macro_s int refs; uint8_t def_flag:1; + uint8_t vargs_flag:1; scf_lex_word_t* w; scf_vector_t* argv; diff --git a/examples/macro_defined.c b/examples/macro_defined.c new file mode 100644 index 0000000..5739bc3 --- /dev/null +++ b/examples/macro_defined.c @@ -0,0 +1,13 @@ +#define A + +#if defined(A) +int printf(const char* fmt, ...); +#endif + +int main() +{ + int define = 5; + + printf("define: %d\n", define); + return 0; +} diff --git a/examples/macro_error.c b/examples/macro_error.c new file mode 100644 index 0000000..190ba69 --- /dev/null +++ b/examples/macro_error.c @@ -0,0 +1,15 @@ +#pragma A + +#define P + +#ifdef P +int printf(const char* fmt, ...); +#else +#error "printf() NOT include!" +#endif + +int main() +{ + printf("macro '#error' test ok\n"); + return 0; +} diff --git a/examples/macro_if.c b/examples/macro_if.c index d3bd497..90ec3e3 100644 --- a/examples/macro_if.c +++ b/examples/macro_if.c @@ -1,4 +1,4 @@ -#if 1 ? 2 < 3 ? 0 : 4 : 5 +#if 1 ? 3 < 3 ? 0 : 4 : 5 int printf(const char* fmt, ...); #else #endif diff --git a/examples/macro_str.c b/examples/macro_str.c index 354799b..cbf19f8 100644 --- a/examples/macro_str.c +++ b/examples/macro_str.c @@ -1,9 +1,9 @@ -#define A(x) #x +#define A(x, y) #x, (y) int printf(const char* fmt, ...); int main() { - printf("%s\n", A(zzz)); + printf("%s, %d\n", A(zzz, 1)); return 0; } diff --git a/examples/macro_varg.c b/examples/macro_varg.c new file mode 100644 index 0000000..b81c59a --- /dev/null +++ b/examples/macro_varg.c @@ -0,0 +1,9 @@ +int printf(const char* fmt, ...); + +#define logi(fmt, ...) printf("%s(), %d, info: "fmt, __func__, __LINE__, ##__VA_ARGS__) + +int main() +{ + logi("hello, %d, %lg\n", 1, 3.14); + return 0; +} diff --git a/lex/scf_lex.c b/lex/scf_lex.c index 998adfb..c2c69c1 100644 --- a/lex/scf_lex.c +++ b/lex/scf_lex.c @@ -1,20 +1,30 @@ #include"scf_lex.h" -static scf_key_word_t key_words[] = +static scf_key_word_t macro_key_words[] = { - {SCF_CSTR("if"), SCF_LEX_WORD_KEY_IF}, - {SCF_CSTR("else"), SCF_LEX_WORD_KEY_ELSE}, - {SCF_CSTR("include"), SCF_LEX_WORD_KEY_INCLUDE}, {SCF_CSTR("define"), SCF_LEX_WORD_KEY_DEFINE}, - {SCF_CSTR("defined"), SCF_LEX_WORD_KEY_DEFINED}, - {SCF_CSTR("undef"), SCF_LEX_WORD_KEY_UNDEF}, - {SCF_CSTR("ifdef"), SCF_LEX_WORD_KEY_IFDEF}, {SCF_CSTR("ifndef"), SCF_LEX_WORD_KEY_IFNDEF}, + {SCF_CSTR("ifdef"), SCF_LEX_WORD_KEY_IFDEF}, + + {SCF_CSTR("if"), SCF_LEX_WORD_KEY_IF}, + {SCF_CSTR("else"), SCF_LEX_WORD_KEY_ELSE}, {SCF_CSTR("elif"), SCF_LEX_WORD_KEY_ELIF}, {SCF_CSTR("endif"), SCF_LEX_WORD_KEY_ENDIF}, + {SCF_CSTR("undef"), SCF_LEX_WORD_KEY_UNDEF}, + + {SCF_CSTR("pragma"), SCF_LEX_WORD_KEY_PRAGMA}, + {SCF_CSTR("line"), SCF_LEX_WORD_KEY_LINE}, + {SCF_CSTR("error"), SCF_LEX_WORD_KEY_ERROR}, +}; + +static scf_key_word_t key_words[] = +{ + {SCF_CSTR("if"), SCF_LEX_WORD_KEY_IF}, + {SCF_CSTR("else"), SCF_LEX_WORD_KEY_ELSE}, + {SCF_CSTR("for"), SCF_LEX_WORD_KEY_FOR}, {SCF_CSTR("while"), SCF_LEX_WORD_KEY_WHILE}, {SCF_CSTR("do"), SCF_LEX_WORD_KEY_DO}, @@ -110,13 +120,13 @@ static scf_escape_char_t escape_chars[] = {'0', '\0'}, }; -int _find_key_word(const scf_string_t* text) +static int __find_key_word(const scf_string_t* text, const scf_key_word_t* key_words, int n) { - scf_key_word_t* key; + const scf_key_word_t* key; int i; - for (i = 0; i < sizeof(key_words) / sizeof(key_words[0]); i++) { - key = &key_words[i]; + for (i = 0; i < n; i++) { + key = &key_words[i]; if (text->len == key->len && !memcmp(text->data, key->text, key->len)) return key->type; @@ -125,6 +135,16 @@ int _find_key_word(const scf_string_t* text) return -1; } +int _find_key_word(const scf_string_t* text) +{ + return __find_key_word(text, key_words, sizeof(key_words) / sizeof(key_words[0])); +} + +static int _find_macro_key_word(const scf_string_t* text) +{ + return __find_key_word(text, macro_key_words, sizeof(macro_key_words) / sizeof(macro_key_words[0])); +} + static int _find_escape_char(const int c) { int i; @@ -583,7 +603,7 @@ static int _lex_string(scf_lex_t* lex, scf_lex_word_t** pword, scf_char_t* c0) } } -static int _lex_macro(scf_lex_t* lex) +static int _lex_macro_LF(scf_lex_t* lex) { scf_char_t* h = NULL; scf_char_t** pp = &h; @@ -914,20 +934,47 @@ int __lex_pop_word(scf_lex_t* lex, scf_lex_word_t** pword) if ('#' == c->c) { w->type = SCF_LEX_WORD_HASH2; - w->text = scf_string_cstr("##"); + w->text = scf_string_cstr_len("##", 2); lex->pos += 2; free(c); } else { - w->text = scf_string_cstr("#"); + w->text = scf_string_cstr_len("#", 1); lex->pos++; _lex_push_char(lex, c); } c = NULL; + + int ret = _lex_macro_LF(lex); + if (ret < 0) { + scf_lex_word_free(w); + return ret; + } + + if (SCF_LEX_WORD_HASH == w->type) { + scf_lex_word_t* key = NULL; + + ret = __lex_pop_word(lex, &key); + if (ret < 0) { + scf_lex_word_free(w); + return ret; + } + + if (SCF_LEX_WORD_ID == key->type) { + + int type = _find_macro_key_word(key->text); + if (type >= 0) + key->type = type; + } + + scf_lex_push_word(lex, key); + key = NULL; + } + *pword = w; - return _lex_macro(lex); + return 0; } if ('$' == c->c && lex->asm_flag) @@ -1021,6 +1068,17 @@ int scf_lex_pop_word(scf_lex_t* lex, scf_lex_word_t** pword) ret = __parse_macro_define(lex, 0); break; + case SCF_LEX_WORD_KEY_PRAGMA: + case SCF_LEX_WORD_KEY_LINE: + ret = __macro_drop_to_LF(lex); + break; + + case SCF_LEX_WORD_KEY_ERROR: + scf_loge("#error "); + __macro_print_to_LF(lex); + ret = -EINVAL; + break; + default: if (lex->asm_flag) { scf_lex_push_word(lex, w1); diff --git a/lex/scf_lex.h b/lex/scf_lex.h index a5c15f9..79b9391 100644 --- a/lex/scf_lex.h +++ b/lex/scf_lex.h @@ -53,6 +53,7 @@ struct scf_lex_s uint8_t asm_flag:1; }; +int _find_key_word(const scf_string_t* text); scf_char_t* _lex_pop_char (scf_lex_t* lex); void _lex_push_char(scf_lex_t* lex, scf_char_t* c); @@ -70,7 +71,9 @@ int __macro_if_expr(scf_lex_t* lex); int __macro_pop_to (scf_lex_t* lex, scf_lex_word_t** h, scf_lex_word_t** pw1, scf_lex_word_t** pw2); int __macro_drop_to(scf_lex_t* lex, scf_lex_word_t** pw1, scf_lex_word_t** pw2); -int __macro_drop_to_LF(scf_lex_t* lex); + +int __macro_drop_to_LF (scf_lex_t* lex); +int __macro_print_to_LF(scf_lex_t* lex); int __parse_macro_define(scf_lex_t* lex, int def_flag); int __parse_macro_ifdef (scf_lex_t* lex, int def_flag); diff --git a/lex/scf_lex_util.c b/lex/scf_lex_util.c index 5de3bd4..a6360e2 100644 --- a/lex/scf_lex_util.c +++ b/lex/scf_lex_util.c @@ -1,7 +1,5 @@ #include"scf_lex.h" -int _find_key_word(const char* text); - static scf_key_word_t number_postfix[] = { {SCF_CSTR("l"), SCF_LEX_WORD_CONST_INT}, @@ -721,7 +719,7 @@ int _lex_dot(scf_lex_t* lex, scf_lex_word_t** pword, scf_char_t* c0) free(c2); c2 = NULL; - w = scf_lex_word_alloc(lex->file, lex->nb_lines, lex->pos, SCF_LEX_WORD_VAR_ARGS); + w = scf_lex_word_alloc(lex->file, lex->nb_lines, lex->pos, SCF_LEX_WORD_VA_ARGS); w->text = s; s = NULL; } else { @@ -752,7 +750,7 @@ int _lex_dot(scf_lex_t* lex, scf_lex_word_t** pword, scf_char_t* c0) _lex_push_char(lex, c1); c1 = NULL; - int type = _find_key_word(s->data); + int type = _find_key_word(s); if (type < 0) { scf_loge("unknown asm key word '%s', file: %s, line: %d\n", s->data, lex->file->data, lex->nb_lines); diff --git a/lex/scf_macro.c b/lex/scf_macro.c index 8afdd56..b4c8f3d 100644 --- a/lex/scf_macro.c +++ b/lex/scf_macro.c @@ -18,6 +18,35 @@ scf_macro_t* __find_macro(scf_lex_t* lex, scf_lex_word_t* w) return NULL; } +int __macro_print_to_LF(scf_lex_t* lex) +{ + scf_lex_word_t* w = NULL; + int type; + + do { + int ret = __lex_pop_word(lex, &w); + if (ret < 0) + return ret; + + type = w->type; + + if (SCF_LEX_WORD_LF != type) { + + printf("%s ", w->text->data); + } + + scf_lex_word_free(w); + w = NULL; + + if (SCF_LEX_WORD_EOF == type) + return -EINVAL; + + } while (SCF_LEX_WORD_LF != type); + + printf("\n"); + return 0; +} + int __macro_drop_to_LF(scf_lex_t* lex) { scf_lex_word_t* w = NULL; @@ -198,7 +227,8 @@ static int __parse_macro_argv(scf_lex_t* lex, scf_macro_t* m) } } - if (!scf_lex_is_identity(w)) { + if (SCF_LEX_WORD_ID != w->type && SCF_LEX_WORD_VA_ARGS != w->type) { + scf_loge("macro arg '%s' should be an identity, file: %s, line: %d\n", w->text->data, w->file->data, w->line); scf_lex_word_free(w); return -EINVAL; @@ -223,10 +253,21 @@ static int __parse_macro_argv(scf_lex_t* lex, scf_macro_t* m) scf_logw("macro '%s' arg: %s\n", m->w->text->data, w->text->data); - ret = scf_vector_add(m->argv, w); - if (ret < 0) { + if (m->vargs_flag) { + scf_loge("macro has arg '%s' after '...' which must be the last arg, file: %s, line: %d\n", w->text->data, w->file->data, w->line); scf_lex_word_free(w); - return ret; + return -EINVAL; + } + + if (SCF_LEX_WORD_VA_ARGS == w->type) { + m->vargs_flag = 1; + scf_lex_word_free(w); + } else { + ret = scf_vector_add(m->argv, w); + if (ret < 0) { + scf_lex_word_free(w); + return ret; + } } w = NULL; @@ -485,8 +526,10 @@ static int __fill_macro_argv(scf_lex_t* lex, scf_macro_t* m, scf_lex_word_t* use goto error; } - scf_lex_word_free(w); - w = NULL; + w->next = NULL; + + *pp = w; + pp = &w->next; if (n_rps == n_lps) pp = NULL; @@ -520,7 +563,9 @@ static int __fill_macro_argv(scf_lex_t* lex, scf_macro_t* m, scf_lex_word_t* use w = NULL; } - if (m->argv->size != argv->size) { + if (m->argv->size > argv->size + || (m->argv->size < argv->size && !m->vargs_flag)) { + scf_loge("macro '%s' needs %d args, but in fact give %d args, file: %s, line: %d\n", m->w->text->data, m->argv->size, argv->size, use->file->data, use->line); ret = -1; @@ -544,6 +589,9 @@ static int __convert_str(scf_lex_word_t* h) scf_lex_word_t* w; scf_string_t* s; + if (SCF_LEX_WORD_COMMA == h->type && !h->next) + return 0; + if (h->type != SCF_LEX_WORD_CONST_STRING) { h->type = SCF_LEX_WORD_CONST_STRING; @@ -555,6 +603,9 @@ static int __convert_str(scf_lex_word_t* h) while ( h->next) { w = h->next; + if (SCF_LEX_WORD_COMMA == w->type && !w->next) + break; + if (SCF_LEX_WORD_CONST_STRING != w->type) s = w->text; else @@ -613,7 +664,7 @@ static int __use_macro(scf_lex_t* lex, scf_macro_t* m, scf_lex_word_t* use) continue; } - scf_logd("p: '%s', line: %d, hash: %d\n", p->text->data, p->line, hash); + scf_logd("p: '%s', line: %d:%d, hash: %d\n", p->text->data, p->line, p->pos, hash); if (m->argv) { assert(argv); @@ -626,22 +677,43 @@ static int __use_macro(scf_lex_t* lex, scf_macro_t* m, scf_lex_word_t* use) break; } + int j = 0; + int n = 0; + if (i < m->argv->size) { + j = i; + n = i + 1; + + } else if (m->vargs_flag && !strcmp(p->text->data, "__VA_ARGS__")) { + j = i; + n = argv->size; + } + + if (j < n) { scf_lex_word_t** tmp = pp; - for (w = argv->data[i]; w; w = w->next) { + do { + for (w = argv->data[j]; w; w = w->next) { - *pp = scf_lex_word_clone(w); - if (!*pp) { - ret = -ENOMEM; - goto error; - } + if (j < m->argv->size + && SCF_LEX_WORD_COMMA == w->type + && !w->next) + break; - if (!strcmp((*pp)->text->data, "__LINE__")) - (*pp)->data.u64 = use->line; + *pp = scf_lex_word_clone(w); + if (!*pp) { + ret = -ENOMEM; + goto error; + } - pp = &(*pp)->next; - } + if (!strcmp((*pp)->text->data, "__LINE__")) + (*pp)->data.u64 = use->line; + + scf_logd("\033[32m p: '%s', line: %d:%d, hash: %d\033[0m\n", (*pp)->text->data, (*pp)->line, (*pp)->pos, hash); + + pp = &(*pp)->next; + } + } while (++j < n); if (1 == hash) { ret = __convert_str(*tmp); @@ -688,6 +760,56 @@ error: return ret; } + w = h; + while (w) { + scf_lex_word_t* w2; + scf_lex_word_t* w1 = w->next; + + if (!w1) + break; + + if (SCF_LEX_WORD_CONST_STRING == w1->type) { + + if (SCF_LEX_WORD_CONST_STRING == w->type) { + + if ((ret = scf_string_cat(w->text, w1->text)) < 0 + || (ret = scf_string_cat(w->data.s, w1->data.s)) < 0) { + + scf_slist_clear(h, scf_lex_word_t, next, scf_lex_word_free); + return ret; + } + + w->next = w1->next; + + scf_lex_word_free(w1); + w1 = NULL; + continue; + } + + } else if (SCF_LEX_WORD_COMMA == w1->type) { + w2 = w1->next; + + if (w2 && SCF_LEX_WORD_HASH2 == w2->type) { + w1->next = w2->next; + + scf_lex_word_free(w2); + w2 = w1->next; + + if (w2 && SCF_LEX_WORD_ID == w2->type && !strcmp(w2->text->data, "__VA_ARGS__")) { + + w->next = w2->next; + + scf_lex_word_free(w1); + scf_lex_word_free(w2); + w1 = NULL; + w2 = NULL; + } + } + } + + w = w->next; + } + #if 0 w = h; while (w) { @@ -695,6 +817,7 @@ error: w = w->next; } #endif + *pp = lex->word_list; lex->word_list = h; return 0; diff --git a/lex/scf_macro_expr.c b/lex/scf_macro_expr.c index e5ae60d..6602c93 100644 --- a/lex/scf_macro_expr.c +++ b/lex/scf_macro_expr.c @@ -56,6 +56,9 @@ static int __macro_unary_operand(scf_lex_t* lex, scf_macro_ctx_t* ctx, scf_lex_w if (ret < 0) return ret; + if (SCF_LEX_WORD_ID == w0->type && !strcmp(w0->text->data, "defined")) + w0->type = SCF_LEX_WORD_KEY_DEFINED; + switch (w0->type) { case SCF_LEX_WORD_PLUS: @@ -108,6 +111,8 @@ static int __macro_binary_operand(scf_lex_t* lex, scf_macro_ctx_t* ctx, scf_lex_ *ctx->pp = op2; ctx->pp = &op2->next; + + ctx->n_rps++; return 0; } @@ -180,19 +185,36 @@ MACRO_OPERATOR_BINARY(logic_or, ||) static int __macro_operator_defined(scf_lex_t* lex, scf_macro_ctx_t* ctx, scf_lex_word_t* w_op, int n_consts, scf_lex_word_t** operand) { scf_lex_word_t* w0 = NULL; + int ret; - int ret = __lex_pop_word(lex, &w0); - if (ret < 0) - return ret; + int n_lps = 0; + int n_rps = 0; + + while (1) { + ret = __lex_pop_word(lex, &w0); + if (ret < 0) + return ret; + + w0->next = NULL; + *ctx->pp = w0; + ctx->pp = &w0->next; - if (SCF_LEX_WORD_ID != w0->type) { - scf_loge("'%s' after 'defined' in #if is NOT an macro identity, file: %s, line: %d\n", - w0->text->data, w0->file->data, w0->line); + if (SCF_LEX_WORD_ID == w0->type) + break; + + if (SCF_LEX_WORD_LP != w0->type) { + + scf_loge("'%s' after 'defined' in #if is NOT an macro identity, file: %s, line: %d\n", + w0->text->data, w0->file->data, w0->line); + return -EINVAL; + } - ret = -EINVAL; - goto error; + n_lps++; + w0 = NULL; } + assert(SCF_LEX_WORD_ID == w0->type); + if (__find_macro(lex, w0)) w0->data.i64 = 1; else @@ -203,13 +225,30 @@ static int __macro_operator_defined(scf_lex_t* lex, scf_macro_ctx_t* ctx, scf_le scf_logi("w0: %s, result: %ld\n", w0->text->data, w0->data.i64); - ret = 0; + w0 = NULL; -error: - w0->next = NULL; - *ctx->pp = w0; - ctx->pp = &w0->next; - return ret; + while (n_rps < n_lps) { + + ret = __lex_pop_word(lex, &w0); + if (ret < 0) + return ret; + + w0->next = NULL; + *ctx->pp = w0; + ctx->pp = &w0->next; + + if (SCF_LEX_WORD_RP != w0->type) { + + scf_loge("too less ')' before '%s' in #if, file: %s, line: %d\n", + w0->text->data, w0->file->data, w0->line); + return -EINVAL; + } + + n_rps++; + w0 = NULL; + } + + return 0; } #define MACRO_OPERATOR_UNARY(name, op) \ @@ -362,6 +401,13 @@ static int __macro_operator_lp(scf_lex_t* lex, scf_macro_ctx_t* ctx, scf_lex_wor static int __macro_operator_rp(scf_lex_t* lex, scf_macro_ctx_t* ctx, scf_lex_word_t* w_op, int n_consts, scf_lex_word_t** operand) { + if (++ctx->n_rps > ctx->n_lps) { + + scf_loge("too many '%s', file: %s, line: %d, pos: %d\n", + w_op->text->data, w_op->file->data, w_op->line, w_op->pos); + return -EINVAL; + } + return 0; } @@ -431,11 +477,14 @@ static int __macro_operator_lp(scf_lex_t* lex, scf_macro_ctx_t* ctx, scf_lex_wor *ctx->pp = op2; ctx->pp = &op2->next; + ctx->n_lps++; + scf_macro_operator_pt f; switch (op2->type) { case SCF_LEX_WORD_RP: + ctx->n_rps++; break; case SCF_LEX_WORD_STAR: @@ -496,6 +545,9 @@ static int __macro_expr(scf_lex_t* lex, scf_macro_ctx_t* ctx, scf_lex_word_t* w, return -EINVAL; } + if (SCF_LEX_WORD_ID == w->type && !strcmp(w->text->data, "defined")) + w->type = SCF_LEX_WORD_KEY_DEFINED; + if (scf_lex_is_operator(w)) { w->next = NULL; @@ -555,6 +607,9 @@ int __macro_if_expr(scf_lex_t* lex) goto error; } + if (SCF_LEX_WORD_ID == w->type && !strcmp(w->text->data, "defined")) + w->type = SCF_LEX_WORD_KEY_DEFINED; + if (scf_lex_is_operator(w)) { scf_macro_operator_pt f = macro_operators[w->type]; if (!f) { @@ -595,6 +650,14 @@ int __macro_if_expr(scf_lex_t* lex) goto error; } + if (operand) { + scf_loge("NO binary operator before operand '%s', file: %s, line: %d\n", + w->text->data, w->file->data, w->line); + + ret = -EINVAL; + goto error; + } + scf_logi("w: %s, w->data.u64: %ld\n", w->text->data, w->data.u64); operand = w; diff --git a/parse/scf_dfa_util.h b/parse/scf_dfa_util.h index ece4260..b38ea2e 100644 --- a/parse/scf_dfa_util.h +++ b/parse/scf_dfa_util.h @@ -183,7 +183,7 @@ static inline int scf_dfa_is_vargs(scf_dfa_t* dfa, void* word) { scf_lex_word_t* w = word; - return SCF_LEX_WORD_VAR_ARGS == w->type; + return SCF_LEX_WORD_VA_ARGS == w->type; } static inline int scf_dfa_is_const(scf_dfa_t* dfa, void* word)