From b753b5885e0d467850659af1fcf138a6adabc36a Mon Sep 17 00:00:00 2001 From: "yu.dongliang" <18588496441@163.com> Date: Mon, 2 Sep 2024 14:47:01 +0800 Subject: [PATCH] support 'enum' & add a test examples/enum.c --- core/scf_lex_word.h | 1 + core/scf_node.h | 1 + examples/enum.c | 23 +++ lex/scf_lex.c | 1 + parse/Makefile | 1 + parse/scf_dfa_enum.c | 385 ++++++++++++++++++++++++++++++++++++++++++ parse/scf_dfa_parse.c | 2 + parse/scf_dfa_union.c | 9 +- parse/scf_dfa_util.h | 14 ++ 9 files changed, 429 insertions(+), 8 deletions(-) create mode 100644 examples/enum.c create mode 100644 parse/scf_dfa_enum.c diff --git a/core/scf_lex_word.h b/core/scf_lex_word.h index c10952b..7543477 100644 --- a/core/scf_lex_word.h +++ b/core/scf_lex_word.h @@ -165,6 +165,7 @@ enum scf_lex_words SCF_LEX_WORD_KEY_ASYNC, // async SCF_LEX_WORD_KEY_AWAIT, // await + SCF_LEX_WORD_KEY_ENUM, // enum SCF_LEX_WORD_KEY_UNION, // union SCF_LEX_WORD_KEY_STRUCT, // struct SCF_LEX_WORD_KEY_END_STRUCT,// end struct diff --git a/core/scf_node.h b/core/scf_node.h index edde26f..e39fe4d 100644 --- a/core/scf_node.h +++ b/core/scf_node.h @@ -36,6 +36,7 @@ struct scf_node_s { uint32_t root_flag :1; // set when node is root block uint32_t file_flag :1; // set when node is a file block + uint32_t enum_flag :1; // set when node is a enum type uint32_t class_flag :1; // set when node is a class type uint32_t union_flag :1; // set when node is a union type uint32_t define_flag :1; // set when node is a function & is defined not only declared diff --git a/examples/enum.c b/examples/enum.c new file mode 100644 index 0000000..c48fdf1 --- /dev/null +++ b/examples/enum.c @@ -0,0 +1,23 @@ +int printf(const char* fmt, ...); + +enum { + ANON_0, + ANON_1, + ANON_2 = ANON_1, + ANON_3, +}; + +enum TEST { + TEST_0 = 7, + TEST_1, + TEST_2, + TEST_3 +}; + +int main() +{ + printf("ANON_0: %d, ANON_1: %d, ANON_2: %d, ANON_3: %d\n", ANON_0, ANON_1, ANON_2, ANON_3); + printf("TEST_0: %d, TEST_1: %d, TEST_2: %d, TEST_3: %d\n", TEST_0, TEST_1, TEST_2, TEST_3); + + return 0; +} diff --git a/lex/scf_lex.c b/lex/scf_lex.c index 6b953b0..adda700 100644 --- a/lex/scf_lex.c +++ b/lex/scf_lex.c @@ -67,6 +67,7 @@ static scf_key_word_t key_words[] = {"include", SCF_LEX_WORD_KEY_INCLUDE}, + {"enum", SCF_LEX_WORD_KEY_ENUM}, {"union", SCF_LEX_WORD_KEY_UNION}, {"struct", SCF_LEX_WORD_KEY_STRUCT}, }; diff --git a/parse/Makefile b/parse/Makefile index b097b8a..b3c380f 100644 --- a/parse/Makefile +++ b/parse/Makefile @@ -132,6 +132,7 @@ CFILES += scf_dfa_container.c CFILES += scf_dfa_va_arg.c CFILES += scf_dfa_expr.c +CFILES += scf_dfa_enum.c CFILES += scf_dfa_union.c CFILES += scf_dfa_class.c diff --git a/parse/scf_dfa_enum.c b/parse/scf_dfa_enum.c new file mode 100644 index 0000000..a8fd9f8 --- /dev/null +++ b/parse/scf_dfa_enum.c @@ -0,0 +1,385 @@ +#include"scf_dfa.h" +#include"scf_dfa_util.h" +#include"scf_parse.h" + +extern scf_dfa_module_t dfa_module_enum; + +typedef struct { + scf_lex_word_t* current_enum; + scf_variable_t* current_v; + + scf_dfa_hook_t* hook; + + scf_vector_t* vars; + + int nb_lbs; + int nb_rbs; + +} enum_module_data_t; + +static int _enum_action_type(scf_dfa_t* dfa, scf_vector_t* words, void* data) +{ + scf_parse_t* parse = dfa->priv; + dfa_parse_data_t* d = data; + enum_module_data_t* md = d->module_datas[dfa_module_enum.index]; + scf_lex_word_t* w = words->data[words->size - 1]; + + if (md->current_enum) { + scf_loge("\n"); + return SCF_DFA_ERROR; + } + + scf_type_t* t = scf_block_find_type(parse->ast->root_block, w->text->data); + if (!t) { + t = scf_type_alloc(w, w->text->data, SCF_STRUCT + parse->ast->nb_structs, 0); + if (!t) { + scf_loge("type alloc failed\n"); + return SCF_DFA_ERROR; + } + + parse->ast->nb_structs++; + t->node.enum_flag = 1; + scf_scope_push_type(parse->ast->root_block->scope, t); + } + + md->current_enum = w; + + return SCF_DFA_NEXT_WORD; +} + +static int _enum_action_lb(scf_dfa_t* dfa, scf_vector_t* words, void* data) +{ + scf_parse_t* parse = dfa->priv; + dfa_parse_data_t* d = data; + enum_module_data_t* md = d->module_datas[dfa_module_enum.index]; + scf_lex_word_t* w = words->data[words->size - 1]; + scf_type_t* t = NULL; + + if (md->nb_lbs > 0) { + scf_loge("too many '{' in enum, file: %s, line: %d\n", w->file->data, w->line); + return SCF_DFA_ERROR; + } + + if (md->current_enum) { + + t = scf_block_find_type(parse->ast->root_block, md->current_enum->text->data); + if (!t) { + scf_loge("type '%s' not found\n", md->current_enum->text->data); + return SCF_DFA_ERROR; + } + } else { + t = scf_type_alloc(w, "anonymous", SCF_STRUCT + parse->ast->nb_structs, 0); + if (!t) { + scf_loge("type alloc failed\n"); + return SCF_DFA_ERROR; + } + + parse->ast->nb_structs++; + t->node.enum_flag = 1; + scf_scope_push_type(parse->ast->root_block->scope, t); + + md->current_enum = w; + } + + md->nb_lbs++; + + return SCF_DFA_NEXT_WORD; +} + +static int _enum_action_var(scf_dfa_t* dfa, scf_vector_t* words, void* data) +{ + scf_parse_t* parse = dfa->priv; + dfa_parse_data_t* d = data; + enum_module_data_t* md = d->module_datas[dfa_module_enum.index]; + scf_lex_word_t* w = words->data[words->size - 1]; + + scf_variable_t* v0 = NULL; + scf_variable_t* v = NULL; + scf_type_t* t = NULL; + + if (!md->current_enum) { + scf_loge("\n"); + return SCF_DFA_ERROR; + } + + if (scf_ast_find_type_type(&t, parse->ast, SCF_VAR_INT) < 0) { + scf_loge("\n"); + return SCF_DFA_ERROR; + } + + v = scf_block_find_variable(parse->ast->root_block, w->text->data); + if (v) { + scf_loge("repeated declared enum var '%s', 1st in file: %s, line: %d\n", w->text->data, v->w->file->data, v->w->line); + return SCF_DFA_ERROR; + } + + v = SCF_VAR_ALLOC_BY_TYPE(w, t, 1, 0, NULL); + if (!v) { + scf_loge("var alloc failed\n"); + return SCF_DFA_ERROR; + } + + v->const_literal_flag = 1; + + if (md->vars->size > 0) { + v0 = md->vars->data[md->vars->size - 1]; + v->data.i64 = v0->data.i64 + 1; + } else + v->data.i64 = 0; + + if (scf_vector_add(md->vars, v) < 0) { + scf_loge("var add failed\n"); + return SCF_DFA_ERROR; + } + + scf_scope_push_var(parse->ast->root_block->scope, v); + + md->current_v = v; + + scf_logi("enum var: '%s', type: %d, size: %d\n", w->text->data, v->type, v->size); + + return SCF_DFA_NEXT_WORD; +} + +static int _enum_action_assign(scf_dfa_t* dfa, scf_vector_t* words, void* data) +{ + scf_parse_t* parse = dfa->priv; + dfa_parse_data_t* d = data; + enum_module_data_t* md = d->module_datas[dfa_module_enum.index]; + scf_lex_word_t* w = words->data[words->size - 1]; + + if (!md->current_v) { + scf_loge("no enum var before '=' in file: %s, line: %d\n", w->file->data, w->line); + return SCF_DFA_ERROR; + } + + assert(!d->expr); + d->expr_local_flag++; + + md->hook = SCF_DFA_PUSH_HOOK(scf_dfa_find_node(dfa, "enum_comma"), SCF_DFA_HOOK_POST); + + return SCF_DFA_NEXT_WORD; +} + +static int _enum_action_comma(scf_dfa_t* dfa, scf_vector_t* words, void* data) +{ + scf_parse_t* parse = dfa->priv; + dfa_parse_data_t* d = data; + enum_module_data_t* md = d->module_datas[dfa_module_enum.index]; + scf_lex_word_t* w = words->data[words->size - 1]; + scf_variable_t* r = NULL; + + if (!md->current_v) { + scf_loge("enum var before ',' not found, in file: %s, line: %d\n", w->file->data, w->line); + return SCF_DFA_ERROR; + } + + if (d->expr) { + while(d->expr->parent) + d->expr = d->expr->parent; + + if (scf_expr_calculate(parse->ast, d->expr, &r) < 0) { + scf_loge("scf_expr_calculate\n"); + return SCF_DFA_ERROR; + } + + md->current_v->data.i64 = r->data.i64; + + scf_variable_free(r); + r = NULL; + + scf_expr_free(d->expr); + d->expr = NULL; + d->expr_local_flag--; + } + + md->current_v = NULL; + + return SCF_DFA_SWITCH_TO; +} + +static int _enum_action_rb(scf_dfa_t* dfa, scf_vector_t* words, void* data) +{ + scf_parse_t* parse = dfa->priv; + dfa_parse_data_t* d = data; + enum_module_data_t* md = d->module_datas[dfa_module_enum.index]; + scf_lex_word_t* w = words->data[words->size - 1]; + scf_variable_t* r = NULL; + + if (md->nb_lbs > 1) { + scf_loge("too many '{' in enum, file: %s, line: %d\n", w->file->data, w->line); + return SCF_DFA_ERROR; + } + + md->nb_rbs++; + + assert(md->nb_rbs == md->nb_lbs); + + if (d->expr) { + while(d->expr->parent) + d->expr = d->expr->parent; + + if (scf_expr_calculate(parse->ast, d->expr, &r) < 0) { + scf_loge("scf_expr_calculate\n"); + return SCF_DFA_ERROR; + } + + md->current_v->data.i64 = r->data.i64; + + scf_variable_free(r); + r = NULL; + + scf_expr_free(d->expr); + d->expr = NULL; + d->expr_local_flag--; + } + + if (md->hook) { + scf_dfa_del_hook(&(dfa->hooks[SCF_DFA_HOOK_POST]), md->hook); + md->hook = NULL; + } + + md->nb_lbs = 0; + md->nb_rbs = 0; + + md->current_enum = NULL; + md->current_v = NULL; + + scf_vector_clear(md->vars, NULL); + + return SCF_DFA_NEXT_WORD; +} + +static int _enum_action_semicolon(scf_dfa_t* dfa, scf_vector_t* words, void* data) +{ + scf_parse_t* parse = dfa->priv; + dfa_parse_data_t* d = data; + enum_module_data_t* md = d->module_datas[dfa_module_enum.index]; + scf_lex_word_t* w = words->data[words->size - 1]; + + if (0 != md->nb_rbs || 0 != md->nb_lbs) { + scf_loge("'{' and '}' not same in enum, file: %s, line: %d\n", w->file->data, w->line); + + md->nb_rbs = 0; + md->nb_lbs = 0; + return SCF_DFA_ERROR; + } + + if (md->current_v) { + scf_loge("enum var '%s' should be followed by ',' or '}', file: %s, line: %d\n", + md->current_v->w->text->data, + md->current_v->w->file->data, + md->current_v->w->line); + + md->current_v = NULL; + return SCF_DFA_ERROR; + } + + return SCF_DFA_OK; +} + +static int _dfa_init_module_enum(scf_dfa_t* dfa) +{ + SCF_DFA_MODULE_NODE(dfa, enum, _enum, scf_dfa_is_enum, NULL); + + SCF_DFA_MODULE_NODE(dfa, enum, type, scf_dfa_is_identity, _enum_action_type); + + SCF_DFA_MODULE_NODE(dfa, enum, lb, scf_dfa_is_lb, _enum_action_lb); + SCF_DFA_MODULE_NODE(dfa, enum, rb, scf_dfa_is_rb, _enum_action_rb); + SCF_DFA_MODULE_NODE(dfa, enum, semicolon, scf_dfa_is_semicolon, _enum_action_semicolon); + + SCF_DFA_MODULE_NODE(dfa, enum, var, scf_dfa_is_identity, _enum_action_var); + SCF_DFA_MODULE_NODE(dfa, enum, assign, scf_dfa_is_assign, _enum_action_assign); + SCF_DFA_MODULE_NODE(dfa, enum, comma, scf_dfa_is_comma, _enum_action_comma); + + scf_parse_t* parse = dfa->priv; + dfa_parse_data_t* d = parse->dfa_data; + enum_module_data_t* md = d->module_datas[dfa_module_enum.index]; + + assert(!md); + + md = calloc(1, sizeof(enum_module_data_t)); + if (!md) { + scf_loge("\n"); + return SCF_DFA_ERROR; + } + + md->vars = scf_vector_alloc(); + if (!md->vars) { + scf_loge("\n"); + free(md); + return SCF_DFA_ERROR; + } + + d->module_datas[dfa_module_enum.index] = md; + + return SCF_DFA_OK; +} + +static int _dfa_fini_module_enum(scf_dfa_t* dfa) +{ + scf_parse_t* parse = dfa->priv; + dfa_parse_data_t* d = parse->dfa_data; + enum_module_data_t* md = d->module_datas[dfa_module_enum.index]; + + if (md) { + free(md); + md = NULL; + d->module_datas[dfa_module_enum.index] = NULL; + } + + return SCF_DFA_OK; +} + +static int _dfa_init_syntax_enum(scf_dfa_t* dfa) +{ + SCF_DFA_GET_MODULE_NODE(dfa, enum, _enum, _enum); + SCF_DFA_GET_MODULE_NODE(dfa, enum, type, type); + SCF_DFA_GET_MODULE_NODE(dfa, enum, lb, lb); + SCF_DFA_GET_MODULE_NODE(dfa, enum, rb, rb); + SCF_DFA_GET_MODULE_NODE(dfa, enum, semicolon, semicolon); + + SCF_DFA_GET_MODULE_NODE(dfa, enum, assign, assign); + SCF_DFA_GET_MODULE_NODE(dfa, enum, comma, comma); + SCF_DFA_GET_MODULE_NODE(dfa, enum, var, var); + SCF_DFA_GET_MODULE_NODE(dfa, expr, entry, expr); + + scf_vector_add(dfa->syntaxes, _enum); + + // enum start + scf_dfa_node_add_child(_enum, type); + scf_dfa_node_add_child(type, semicolon); + scf_dfa_node_add_child(type, lb); + + // anonymous enum + scf_dfa_node_add_child(_enum, lb); + + // empty enum + scf_dfa_node_add_child(lb, rb); + + // const member var + scf_dfa_node_add_child(lb, var); + scf_dfa_node_add_child(var, comma); + scf_dfa_node_add_child(var, assign); + scf_dfa_node_add_child(assign, expr); + scf_dfa_node_add_child(expr, comma); + scf_dfa_node_add_child(comma, var); + + scf_dfa_node_add_child(var, rb); + scf_dfa_node_add_child(expr, rb); + + // end + scf_dfa_node_add_child(rb, semicolon); + + scf_logi("\n"); + return 0; +} + +scf_dfa_module_t dfa_module_enum = +{ + .name = "enum", + .init_module = _dfa_init_module_enum, + .init_syntax = _dfa_init_syntax_enum, + + .fini_module = _dfa_fini_module_enum, +}; diff --git a/parse/scf_dfa_parse.c b/parse/scf_dfa_parse.c index 5a4e61c..0ae935f 100644 --- a/parse/scf_dfa_parse.c +++ b/parse/scf_dfa_parse.c @@ -13,6 +13,7 @@ extern scf_dfa_module_t dfa_module_container; extern scf_dfa_module_t dfa_module_init_data; extern scf_dfa_module_t dfa_module_va_arg; +extern scf_dfa_module_t dfa_module_enum; extern scf_dfa_module_t dfa_module_union; extern scf_dfa_module_t dfa_module_class; @@ -53,6 +54,7 @@ scf_dfa_module_t* dfa_modules[] = &dfa_module_init_data, &dfa_module_va_arg, + &dfa_module_enum, &dfa_module_union, &dfa_module_class, diff --git a/parse/scf_dfa_union.c b/parse/scf_dfa_union.c index 1b4dfd2..eb6754c 100644 --- a/parse/scf_dfa_union.c +++ b/parse/scf_dfa_union.c @@ -18,12 +18,6 @@ typedef struct { } union_module_data_t; -static int _union_is_union(scf_dfa_t* dfa, void* word) -{ - scf_lex_word_t* w = word; - return SCF_LEX_WORD_KEY_UNION == w->type; -} - static int _union_action_identity(scf_dfa_t* dfa, scf_vector_t* words, void* data) { scf_parse_t* parse = dfa->priv; @@ -224,7 +218,7 @@ static int _union_action_semicolon(scf_dfa_t* dfa, scf_vector_t* words, void* da static int _dfa_init_module_union(scf_dfa_t* dfa) { - SCF_DFA_MODULE_NODE(dfa, union, _union, _union_is_union, NULL); + SCF_DFA_MODULE_NODE(dfa, union, _union, scf_dfa_is_union, NULL); SCF_DFA_MODULE_NODE(dfa, union, identity, scf_dfa_is_identity, _union_action_identity); @@ -314,4 +308,3 @@ scf_dfa_module_t dfa_module_union = .fini_module = _dfa_fini_module_union, }; - diff --git a/parse/scf_dfa_util.h b/parse/scf_dfa_util.h index 181e5bd..17ad513 100644 --- a/parse/scf_dfa_util.h +++ b/parse/scf_dfa_util.h @@ -67,6 +67,20 @@ static inline int scf_dfa_is_semicolon(scf_dfa_t* dfa, void* word) return SCF_LEX_WORD_SEMICOLON == w->type; } +static inline int scf_dfa_is_enum(scf_dfa_t* dfa, void* word) +{ + scf_lex_word_t* w = word; + + return SCF_LEX_WORD_KEY_ENUM == w->type; +} + +static inline int scf_dfa_is_union(scf_dfa_t* dfa, void* word) +{ + scf_lex_word_t* w = word; + + return SCF_LEX_WORD_KEY_UNION == w->type; +} + static inline int scf_dfa_is_end_struct(scf_dfa_t* dfa, void* word) { scf_lex_word_t* w = word; -- 2.25.1