Implements error handling of parser.

This commit is contained in:
falsycat 2020-12-22 00:00:00 +00:00
parent 9c751437c6
commit 5f375dff74
5 changed files with 145 additions and 69 deletions

View File

@ -1,5 +1,8 @@
X parser 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 expression resolving
enum support enum support
union support union support

66
biner.l
View File

@ -1,7 +1,6 @@
%option noinput nounput noyywrap %option noinput nounput noyywrap
%{ %{
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <inttypes.h> #include <inttypes.h>
@ -11,10 +10,34 @@
#include "generated/biner.y.h" #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) { D [0-9]
return biner_zone_strnew(&ctx.zone, str); 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) { static inline intmax_t parse_int_(int base) {
char* end = NULL; char* end = NULL;
@ -27,26 +50,15 @@ static inline intmax_t parse_int_(int base) {
return v; return v;
} }
%} static inline void count_(void) {
const char* s = yytext;
D [0-9] while (*s) {
I [A-Za-z_] if (*s == '\n') {
H [0-9A-Fa-f] biner_tree_parse_context_.column = 0;
++biner_tree_parse_context_.line;
%% } else {
++biner_tree_parse_context_.column;
"//".* ; }
[/][*][^*]*[*]+([^*/][^*]*[*]+)*[/] ; /* TODO: detect unterminated comment */ ++s;
}
"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) ;
%%

134
biner.y
View File

@ -11,26 +11,34 @@
#define ctx (biner_tree_parse_context_) #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)) #define ref(T, p) ((T*) (ctx.zone.ptr+p))
extern int yylex(void); extern char* yytext;
extern void yyerror(const char*);
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) static inline biner_zone_ptr(biner_tree_struct_member_t)
find_struct_member_( find_struct_member_by_name_(
biner_zone_ptr(biner_tree_struct_member_t) itr, biner_zone_ptr(biner_tree_struct_member_t) last_member,
biner_zone_ptr(char) name) { biner_zone_ptr(char) name);
while (itr) {
const biner_tree_struct_member_t* m = ref(biner_tree_struct_member_t, itr); static inline biner_zone_ptr(biner_tree_struct_member_t)
if (strcmp(ref(char, m->name), ref(char, name)) == 0) { find_child_struct_member_by_name_(
return itr; biner_zone_ptr(biner_tree_struct_member_t) member,
} biner_zone_ptr(char) name);
itr = m->prev;
} static inline biner_zone_ptr(biner_tree_struct_member_t)
yyerror("unknown member"); unwrap_struct_member_ref_(
return 0; biner_zone_ptr(biner_tree_struct_member_reference_t) memref);
}
%} %}
%union { %union {
@ -66,6 +74,10 @@ decl_list
decl decl
: STRUCT IDENT '{' struct_body '}' ';' { : 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); $$ = alloc_(biner_tree_decl_t);
*ref(biner_tree_decl_t, $$) = (biner_tree_decl_t) { *ref(biner_tree_decl_t, $$) = (biner_tree_decl_t) {
.name = $2, .name = $2,
@ -88,6 +100,10 @@ struct_body
struct_member struct_member
: struct_member_type IDENT ';' { : 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); $$ = alloc_(biner_tree_struct_member_t);
*ref(biner_tree_struct_member_t, $$) = *ref(biner_tree_struct_member_t, $$) =
(biner_tree_struct_member_t) { (biner_tree_struct_member_t) {
@ -113,7 +129,7 @@ struct_member_type
*ref(biner_tree_struct_member_type_t, $$) = *ref(biner_tree_struct_member_type_t, $$) =
(biner_tree_struct_member_type_t) { (biner_tree_struct_member_type_t) {
.kind = BINER_TREE_STRUCT_MEMBER_TYPE_KIND_GENERIC, .kind = BINER_TREE_STRUCT_MEMBER_TYPE_KIND_GENERIC,
.generic = $1, .generic = $1,
.qualifier = BINER_TREE_STRUCT_MEMBER_TYPE_QUALIFIER_DYNAMIC_ARRAY, .qualifier = BINER_TREE_STRUCT_MEMBER_TYPE_QUALIFIER_DYNAMIC_ARRAY,
.expr = $3, .expr = $3,
}; };
@ -180,34 +196,82 @@ operand
struct_member_reference struct_member_reference
: IDENT { : 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); $$ = alloc_(biner_tree_struct_member_reference_t);
*ref(biner_tree_struct_member_reference_t, $$) = *ref(biner_tree_struct_member_reference_t, $$) =
(biner_tree_struct_member_reference_t) { (biner_tree_struct_member_reference_t) { .member = member, };
.member = find_struct_member_(ctx.last_member, $1),
};
} }
| struct_member_reference '.' IDENT { | struct_member_reference '.' IDENT {
const biner_tree_struct_member_t* p = const biner_zone_ptr(biner_tree_struct_member_t) member =
ref(biner_tree_struct_member_t, $1); find_child_struct_member_by_name_(unwrap_struct_member_ref_($1), $3);
if (member == 0) {
const biner_tree_struct_member_type_t* t = yyerrorf("unknown member '%s'", ref(char, $3));
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");
YYABORT; 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); $$ = alloc_(biner_tree_struct_member_reference_t);
*ref(biner_tree_struct_member_reference_t, $$) = *ref(biner_tree_struct_member_reference_t, $$) =
(biner_tree_struct_member_reference_t) { (biner_tree_struct_member_reference_t) { .member = member, };
.member = find_struct_member_(d->member, $3),
};
} }
; ;
%% %%
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;
}

6
tree.c
View File

@ -14,12 +14,6 @@
biner_tree_parse_context_t biner_tree_parse_context_ = {0}; 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) { const uint8_t* biner_tree_parse(FILE* fp) {
if (atomic_flag_test_and_set(&biner_tree_parse_context_.dirty)) { if (atomic_flag_test_and_set(&biner_tree_parse_context_.dirty)) {
fprintf(stderr, "parsing context is dirty now\n"); fprintf(stderr, "parsing context is dirty now\n");

3
tree.h
View File

@ -94,6 +94,9 @@ typedef struct biner_tree_parse_context_t {
atomic_flag dirty; atomic_flag dirty;
biner_zone_t zone; biner_zone_t zone;
size_t line;
size_t column;
biner_zone_ptr(biner_tree_root_t) root; biner_zone_ptr(biner_tree_root_t) root;
biner_zone_ptr(biner_tree_decl_t) last_decl; biner_zone_ptr(biner_tree_decl_t) last_decl;
biner_zone_ptr(biner_tree_struct_member_t) last_member; biner_zone_ptr(biner_tree_struct_member_t) last_member;