support 'enum' & add a test examples/enum.c
authoryu.dongliang <18588496441@163.com>
Mon, 2 Sep 2024 06:47:01 +0000 (14:47 +0800)
committeryu.dongliang <18588496441@163.com>
Mon, 2 Sep 2024 06:47:01 +0000 (14:47 +0800)
core/scf_lex_word.h
core/scf_node.h
examples/enum.c [new file with mode: 0644]
lex/scf_lex.c
parse/Makefile
parse/scf_dfa_enum.c [new file with mode: 0644]
parse/scf_dfa_parse.c
parse/scf_dfa_union.c
parse/scf_dfa_util.h

index c10952b9d41ae977d3764be9095807909b6b8a88..75434772045a29fb5281565c77146e056e08e992 100644 (file)
@@ -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
index edde26f919e54ad0ffcafb1b1920cb8847337695..e39fe4de0f866d0e77b37123397573c8b472cae5 100644 (file)
@@ -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 (file)
index 0000000..c48fdf1
--- /dev/null
@@ -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;
+}
index 6b953b0bedbeafecd90533cc37608ba230e765e2..adda7005f5605111db65bd596663bac58ded1e01 100644 (file)
@@ -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},
 };
index b097b8a2ec41bfbca398328da0b99cffe8556b1d..b3c380fd59afbd30bacaf5d48b1ff573488ca437 100644 (file)
@@ -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 (file)
index 0000000..a8fd9f8
--- /dev/null
@@ -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,
+};
index 5a4e61c07bdb484bbe88b717ffb25d8be96bfff8..0ae935ffaa16f0d4d8c88e555fdc674282b1dc0a 100644 (file)
@@ -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,
 
index 1b4dfd213652b68222f83c2ecb245a367e165f5a..eb6754cfaea7cf949f0742082742578fe0da9436 100644 (file)
@@ -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,
 };
-
index 181e5bd0e999ee62d3e5421b6b920185b987f9e8..17ad5130407e43005448620a17abf56f8315c525 100644 (file)
@@ -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;