From 5f375dff740a3a1401eb902fec6fc3468ee799af Mon Sep 17 00:00:00 2001 From: falsycat Date: Tue, 22 Dec 2020 00:00:00 +0000 Subject: [PATCH] Implements error handling of parser. --- TODO.TXT | 5 ++- biner.l | 66 ++++++++++++++++----------- biner.y | 134 ++++++++++++++++++++++++++++++++++++++++--------------- tree.c | 6 --- tree.h | 3 ++ 5 files changed, 145 insertions(+), 69 deletions(-) diff --git a/TODO.TXT b/TODO.TXT index b21f012..98d9bc6 100644 --- a/TODO.TXT +++ b/TODO.TXT @@ -1,5 +1,8 @@ X parser - error handling (compiler message) +X error handling (compiler message) + user-defined type resolving + make enum for generic types + location for each declarations expression resolving enum support union support diff --git a/biner.l b/biner.l index a149e97..904979b 100644 --- a/biner.l +++ b/biner.l @@ -1,7 +1,6 @@ %option noinput nounput noyywrap %{ - #include #include #include @@ -11,10 +10,34 @@ #include "generated/biner.y.h" -#define ctx (biner_tree_parse_context_) +static inline biner_zone_ptr(char) strnew_(void); +static inline intmax_t parse_int_(int base); +static inline void count_(void); +%} -static inline uintptr_t strnew_(const char* str) { - return biner_zone_strnew(&ctx.zone, str); +D [0-9] +I [A-Za-z_] +H [0-9A-Fa-f] + +%% + +"//".* count_(); +[/][*][^*]*[*]+([^*/][^*]*[*]+)*[/] count_(); /* TODO: detect unterminated comment */ + +"struct" { count_(); return STRUCT; } + +{I}({I}|{D})* { yylval.ptr = strnew_(); count_(); return IDENT; } + +{D}+ { yylval.i = parse_int_(10); count_(); return INTEGER; } +0[xX]{H}+ { yylval.i = parse_int_(16); count_(); return INTEGER; } + +[\+\-\*\/\.\(\)[\]\{\}\;] { count_(); return yytext[0]; } + +(.|\n) count_(); + +%% +static inline uintptr_t strnew_(void) { + return biner_zone_strnew(&biner_tree_parse_context_.zone, yytext); } static inline intmax_t parse_int_(int base) { char* end = NULL; @@ -27,26 +50,15 @@ static inline intmax_t parse_int_(int base) { return v; } -%} - -D [0-9] -I [A-Za-z_] -H [0-9A-Fa-f] - -%% - -"//".* ; -[/][*][^*]*[*]+([^*/][^*]*[*]+)*[/] ; /* TODO: detect unterminated comment */ - -"struct" return STRUCT; - -{I}({I}|{D})* { yylval.ptr = strnew_(yytext); return IDENT; } - -{D}+ { yylval.i = parse_int_(10); return INTEGER; } -0[xX]{H}+ { yylval.i = parse_int_(16); return INTEGER; } - -[\+\-\*\/\.\(\)[\]\{\}\;] return yytext[0]; - -(.|\n) ; - -%% +static inline void count_(void) { + const char* s = yytext; + while (*s) { + if (*s == '\n') { + biner_tree_parse_context_.column = 0; + ++biner_tree_parse_context_.line; + } else { + ++biner_tree_parse_context_.column; + } + ++s; + } +} diff --git a/biner.y b/biner.y index 473cabd..29d1428 100644 --- a/biner.y +++ b/biner.y @@ -11,26 +11,34 @@ #define ctx (biner_tree_parse_context_) -#define alloc_(T) (biner_zone_alloc(&ctx.zone, sizeof(T))) +#define alloc_(T) (biner_zone_alloc(&ctx.zone, sizeof(T))) #define ref(T, p) ((T*) (ctx.zone.ptr+p)) -extern int yylex(void); -extern void yyerror(const char*); +extern char* yytext; + +extern int yylex(void); + +#define yyerrorf(fmt, ...) \ + fprintf(stderr, "[%zu:%zu] "fmt"\n", ctx.line+1, ctx.column+1, __VA_ARGS__) +#define yyerror(msg) \ + fprintf(stderr, "[%zu:%zu] "msg"\n", ctx.line+1, ctx.column+1) + +static inline biner_zone_ptr(biner_tree_decl_t) find_decl_by_name_( + biner_zone_ptr(char) name); static inline biner_zone_ptr(biner_tree_struct_member_t) -find_struct_member_( - biner_zone_ptr(biner_tree_struct_member_t) itr, - biner_zone_ptr(char) name) { - while (itr) { - const biner_tree_struct_member_t* m = ref(biner_tree_struct_member_t, itr); - if (strcmp(ref(char, m->name), ref(char, name)) == 0) { - return itr; - } - itr = m->prev; - } - yyerror("unknown member"); - return 0; -} +find_struct_member_by_name_( + biner_zone_ptr(biner_tree_struct_member_t) last_member, + biner_zone_ptr(char) name); + +static inline biner_zone_ptr(biner_tree_struct_member_t) +find_child_struct_member_by_name_( + biner_zone_ptr(biner_tree_struct_member_t) member, + biner_zone_ptr(char) name); + +static inline biner_zone_ptr(biner_tree_struct_member_t) +unwrap_struct_member_ref_( + biner_zone_ptr(biner_tree_struct_member_reference_t) memref); %} %union { @@ -66,6 +74,10 @@ decl_list decl : STRUCT IDENT '{' struct_body '}' ';' { + if (find_decl_by_name_($2) != 0) { + yyerrorf("duplicated declaration of '%s'", ref(char, $2)); + YYABORT; + } $$ = alloc_(biner_tree_decl_t); *ref(biner_tree_decl_t, $$) = (biner_tree_decl_t) { .name = $2, @@ -88,6 +100,10 @@ struct_body struct_member : struct_member_type IDENT ';' { + if (find_struct_member_by_name_(ctx.last_member, $2) != 0) { + yyerrorf("duplicated struct member of '%s'", ref(char, $2)); + YYABORT; + } $$ = alloc_(biner_tree_struct_member_t); *ref(biner_tree_struct_member_t, $$) = (biner_tree_struct_member_t) { @@ -113,7 +129,7 @@ struct_member_type *ref(biner_tree_struct_member_type_t, $$) = (biner_tree_struct_member_type_t) { .kind = BINER_TREE_STRUCT_MEMBER_TYPE_KIND_GENERIC, - .generic = $1, + .generic = $1, .qualifier = BINER_TREE_STRUCT_MEMBER_TYPE_QUALIFIER_DYNAMIC_ARRAY, .expr = $3, }; @@ -180,34 +196,82 @@ operand struct_member_reference : IDENT { + const biner_zone_ptr(biner_tree_struct_member_t) member = + find_struct_member_by_name_(ctx.last_member, $1); + if (member == 0) { + yyerrorf("unknown member '%s'", ref(char, $1)); + YYABORT; + } + $$ = alloc_(biner_tree_struct_member_reference_t); *ref(biner_tree_struct_member_reference_t, $$) = - (biner_tree_struct_member_reference_t) { - .member = find_struct_member_(ctx.last_member, $1), - }; + (biner_tree_struct_member_reference_t) { .member = member, }; } | struct_member_reference '.' IDENT { - const biner_tree_struct_member_t* p = - ref(biner_tree_struct_member_t, $1); - - const biner_tree_struct_member_type_t* t = - ref(biner_tree_struct_member_type_t, p->type); - if (t->kind != BINER_TREE_STRUCT_MEMBER_TYPE_KIND_USER_DEFINED) { - yyerror("not user-defined data"); + const biner_zone_ptr(biner_tree_struct_member_t) member = + find_child_struct_member_by_name_(unwrap_struct_member_ref_($1), $3); + if (member == 0) { + yyerrorf("unknown member '%s'", ref(char, $3)); YYABORT; } - const biner_tree_decl_t* d = ref(biner_tree_decl_t, t->decl); - if (d->type != BINER_TREE_DECL_TYPE_STRUCT) { - yyerror("not struct"); - YYABORT; - } $$ = alloc_(biner_tree_struct_member_reference_t); *ref(biner_tree_struct_member_reference_t, $$) = - (biner_tree_struct_member_reference_t) { - .member = find_struct_member_(d->member, $3), - }; + (biner_tree_struct_member_reference_t) { .member = member, }; } ; %% +static inline biner_zone_ptr(biner_tree_decl_t) find_decl_by_name_( + biner_zone_ptr(char) name) { + biner_zone_ptr(biner_tree_decl_t) itr = ctx.last_decl; + while (itr) { + const biner_tree_decl_t* decl = ref(biner_tree_decl_t, itr); + if (strcmp(ref(char, decl->name), ref(char, name)) == 0) return itr; + itr = decl->prev; + } + return 0; +} + +static inline biner_zone_ptr(biner_tree_struct_member_t) +find_struct_member_by_name_( + biner_zone_ptr(biner_tree_struct_member_t) last_member, + biner_zone_ptr(char) name) { + biner_zone_ptr(biner_tree_struct_member_t) itr = last_member; + while (itr) { + const biner_tree_struct_member_t* m = ref(biner_tree_struct_member_t, itr); + if (strcmp(ref(char, m->name), ref(char, name)) == 0) return itr; + itr = m->prev; + } + return 0; +} + +static inline biner_zone_ptr(biner_tree_struct_member_t) +find_child_struct_member_by_name_( + biner_zone_ptr(biner_tree_struct_member_t) member, + biner_zone_ptr(char) name) { + const biner_tree_struct_member_t* m = ref(biner_tree_struct_member_t, member); + + const biner_tree_struct_member_type_t* t = + ref(biner_tree_struct_member_type_t, m->type); + if (t->kind != BINER_TREE_STRUCT_MEMBER_TYPE_KIND_USER_DEFINED) { + yyerrorf("typeof '%s' is not user-defined", ref(char, m->name)); + return 0; + } + const biner_tree_decl_t* d = ref(biner_tree_decl_t, t->decl); + if (d->type != BINER_TREE_DECL_TYPE_STRUCT) { + yyerrorf("'%s' (typeof '%s') is not struct", + ref(char, d->name), + ref(char, m->name)); + return 0; + } + return find_struct_member_by_name_(d->member, name); +} + +static inline biner_zone_ptr(biner_tree_struct_member_t) +unwrap_struct_member_ref_( + biner_zone_ptr(biner_tree_struct_member_reference_t) memref) { + const biner_tree_struct_member_reference_t* r = + ref(biner_tree_struct_member_reference_t, memref); + return r->member; +} diff --git a/tree.c b/tree.c index ac5c848..a4ab2cf 100644 --- a/tree.c +++ b/tree.c @@ -14,12 +14,6 @@ biner_tree_parse_context_t biner_tree_parse_context_ = {0}; -int yyerror(char* str) { - extern char* yytext; - fprintf(stderr, "error: %s: %s\n", str, yytext); - return 0; -} - const uint8_t* biner_tree_parse(FILE* fp) { if (atomic_flag_test_and_set(&biner_tree_parse_context_.dirty)) { fprintf(stderr, "parsing context is dirty now\n"); diff --git a/tree.h b/tree.h index 2ffea9c..03051d5 100644 --- a/tree.h +++ b/tree.h @@ -94,6 +94,9 @@ typedef struct biner_tree_parse_context_t { atomic_flag dirty; biner_zone_t zone; + size_t line; + size_t column; + biner_zone_ptr(biner_tree_root_t) root; biner_zone_ptr(biner_tree_decl_t) last_decl; biner_zone_ptr(biner_tree_struct_member_t) last_member;