diff options
| author | Mistivia <i@mistivia.com> | 2025-03-25 13:07:21 +0800 |
|---|---|---|
| committer | Mistivia <i@mistivia.com> | 2025-03-25 13:07:21 +0800 |
| commit | fb7664e087cb1afb64aae2128365f703beb30b57 (patch) | |
| tree | 6d4e2a4cc695052e489ec9e3fd28538a79a08f4c /src | |
| parent | dc87ff4b0c9f311be7fad652594e3766a4ddb0c6 (diff) | |
add result style error handling
Diffstat (limited to 'src')
| -rw-r--r-- | src/as_parser.c | 144 | ||||
| -rw-r--r-- | src/as_parser.h | 12 | ||||
| -rw-r--r-- | src/as_tokenizer.c | 43 | ||||
| -rw-r--r-- | src/as_tokenizer.h | 9 | ||||
| -rw-r--r-- | src/utils.c | 32 | ||||
| -rw-r--r-- | src/utils.h | 7 |
6 files changed, 177 insertions, 70 deletions
diff --git a/src/as_parser.c b/src/as_parser.c index 39f8859..0fcb1f4 100644 --- a/src/as_parser.c +++ b/src/as_parser.c @@ -16,20 +16,38 @@ // <label> ::= tag ":" // <op> ::= "add" | "sub" | "mul" | "div" | "mod" | "eq" | ... -struct prog * parse_prog(struct allocator * alct, struct token_stream * ts) { +struct result parse_prog(struct allocator * alct, struct token_stream * ts) { + struct result result; struct prog * p = allocate(alct, sizeof(struct prog)); - p->stmts = parse_stmts(alct, ts); - return p; + result = parse_stmts(alct, ts); + if (result.errmsg != NULL) return result; + p->stmts = result.value; + return (struct result){.value = p, .errmsg = NULL}; } -struct stmts * parse_stmts(struct allocator * alct, struct token_stream * ts) { +struct result parse_stmts(struct allocator * alct, struct token_stream * ts) { + struct token *token; + struct result result; + const char* errmsg; struct stmts * ss = allocate(alct, sizeof(struct stmts)); ss->stmts = allocate(alct, sizeof(struct stmt *)); ss->stmts[0] = NULL; int capacity = 0; int len = 0; - while (peek_token(alct, ts)->type != TK_ENDOFFILE) { - struct stmt * s = parse_stmt(alct, ts); + + while (1) { + result = peek_token(alct, ts); + if (result.errmsg != NULL) return result; + token = result.value; + if (token->type == TK_ENDOFFILE) { + break; + } + + result = parse_stmt(alct, ts); + if (result.errmsg != NULL) { + return result; + } + struct stmt * s = result.value; if (s == NULL) continue; if (len == capacity) { size_t new_capacity = capacity * 2 + 1; @@ -39,84 +57,126 @@ struct stmts * parse_stmts(struct allocator * alct, struct token_stream * ts) { capacity = new_capacity; } // expect newline - if (peek_token(alct, ts)->type == TK_NEWLINE) { - next_token(alct, ts); + result = peek_token(alct, ts); + if (result.errmsg != NULL) return result; + token = result.value; + if (token->type == TK_NEWLINE) { + result = next_token(alct, ts); + if (result.errmsg != NULL) return result; } else { - fprintf(stderr, "%d:%d expect newline.\n", peek_token(alct, ts)->line, peek_token(alct, ts)->col); + errmsg = safe_sprintf(alct, "%d:%d expect newline.\n", token->line, token->col); + return (struct result){.value = NULL, .errmsg = errmsg}; } ss->stmts[len] = s; len++; } ss->stmts[len] = NULL; - return ss; + return (struct result){.value = ss, .errmsg = NULL}; } -struct label * parse_label(struct allocator * alct, struct token_stream * ts) { - struct token * t = next_token(alct, ts); +struct result parse_label(struct allocator * alct, struct token_stream * ts) { + const char *errmsg; + struct result result; + struct token * t; + result = next_token(alct, ts); + if (result.errmsg != NULL) return result; + t = result.value; if (t->type != TK_TAG) { - fprintf(stderr, "%d:%d expect label.\n", t->line, t->col); - exit(-1); + errmsg = safe_sprintf(alct, "%d:%d expect label.\n", t->line, t->col); + return (struct result){.value = NULL, .errmsg = errmsg}; } struct label * l = allocate(alct, sizeof(struct label *)); l->name = t->sval; - t = next_token(alct, ts); + result = next_token(alct, ts); + if (result.errmsg != NULL) return result; + t = result.value; if (t->type != TK_COLON) { - fprintf(stderr, "%d:%d expect colon.\n", t->line, t->col); - exit(-1); + errmsg = safe_sprintf(alct, "%d:%d expect colon.\n", t->line, t->col); + return (struct result){.value = NULL, .errmsg = errmsg}; } - return l; + return (struct result){.value = l, .errmsg = NULL}; } -struct stmt * parse_stmt(struct allocator * alct, struct token_stream * ts) { - struct token * t = peek_token(alct, ts); +struct result parse_stmt(struct allocator * alct, struct token_stream * ts) { + const char *errmsg; + struct result result; + struct token * t; + result = peek_token(alct, ts); + if (result.errmsg != NULL) return result; + t = result.value; struct stmt * stmt = allocate(alct, sizeof(struct stmt)); stmt->label = NULL; stmt->instr = NULL; if (t->type == TK_TAG) { - stmt->label = parse_label(alct, ts); - if (peek_token(alct, ts)->type == TK_NEWLINE) { - return stmt; + result = parse_label(alct, ts); + if (result.errmsg != NULL) return result; + stmt->label = result.value; + result = peek_token(alct, ts); + if (result.errmsg != NULL) return result; + t = result.value; + if (t->type == TK_NEWLINE) { + return (struct result){.value = stmt, .errmsg = NULL}; } - t = peek_token(alct, ts); + result = peek_token(alct, ts); + if (result.errmsg != NULL) return result; + t = result.value; } if (t->type == TK_OP) { - stmt->instr = parse_instr(alct, ts); - if (peek_token(alct, ts)->type == TK_NEWLINE) { - return stmt; + result = parse_instr(alct, ts); + if (result.errmsg != NULL) return result; + stmt->instr = result.value; + + result = peek_token(alct, ts); + if (result.errmsg != NULL) return result; + t = result.value; + if (t->type == TK_NEWLINE) { + return (struct result){.value = stmt, .errmsg = NULL}; } } if (t->type == TK_NEWLINE) { - return NULL; + return (struct result){.value = NULL, .errmsg = NULL}; } - fprintf(stderr, "%d:%d expect lable + instruction, lable, or instruction.\n", t->line, t->col); - exit(-1); + errmsg = safe_sprintf(alct, "%d:%d expect lable + instruction, lable, or instruction.\n", t->line, t->col); + return (struct result){.value = NULL, .errmsg = errmsg}; } -enum op parse_op(struct allocator * alct, struct token_stream * ts) { - struct token * t = next_token(alct, ts); +struct result parse_op(struct allocator * alct, struct token_stream * ts) { + const char *errmsg; + struct result result; + struct token * t; + result = next_token(alct, ts); + if (result.errmsg != NULL) return result; + t = result.value; enum op op; if (t->type == TK_OP) { op = str2op(t->sval); if (op == OP_END) { - fprintf(stderr, "%d:%d invalid op.\n", t->line, t->col); - exit(-1); + errmsg = safe_sprintf(alct, "%d:%d invalid op.\n", t->line, t->col); + return (struct result){.value = NULL, .errmsg = errmsg}; } } else { - fprintf(stderr, "%d:%d expect op.\n", t->line, t->col); - exit(-1); + errmsg = safe_sprintf(alct, "%d:%d expect op.\n", t->line, t->col); + return (struct result){.value = NULL, .errmsg = errmsg}; } - return op; + return (struct result){.value = (void*)op, .errmsg = NULL}; } -struct instr * parse_instr(struct allocator * alct, struct token_stream * ts) { - struct token * t = peek_token(alct, ts); +struct result parse_instr(struct allocator * alct, struct token_stream * ts) { + struct result result; + struct token * t; + result = peek_token(alct, ts); + if (result.errmsg != NULL) return result; + t = result.value; struct instr * i = allocate(alct, sizeof(struct instr)); i->tag_name = NULL; i->arg = NULL; i->op = OP_END; if (t->type == TK_OP) { - i->op = parse_op(alct, ts); - t = peek_token(alct, ts); + result = parse_op(alct, ts); + i->op = (enum op)(result.value); + result = peek_token(alct, ts); + if (result.errmsg != NULL) return result; + t = result.value; if (t->type == TK_ARG) { struct arg * a = allocate(alct, sizeof(struct arg)); a->ival = t->ival; @@ -128,5 +188,5 @@ struct instr * parse_instr(struct allocator * alct, struct token_stream * ts) { next_token(alct, ts); } } - return i; + return (struct result){.value = i, .errmsg = NULL}; } diff --git a/src/as_parser.h b/src/as_parser.h index 4630186..5d850c9 100644 --- a/src/as_parser.h +++ b/src/as_parser.h @@ -34,11 +34,11 @@ struct prog { struct stmts * stmts; }; -struct prog * parse_prog(struct allocator * alct, struct token_stream * ts); -struct stmt * parse_stmt(struct allocator * alct, struct token_stream * ts); -struct stmts * parse_stmts(struct allocator * alct, struct token_stream * ts); -struct instr * parse_instr(struct allocator * alct, struct token_stream * ts); -struct label * parse_label(struct allocator * alct, struct token_stream * ts); -enum op parse_op(struct allocator * alct, struct token_stream * ts); +struct result parse_prog(struct allocator * alct, struct token_stream * ts); +struct result parse_stmt(struct allocator * alct, struct token_stream * ts); +struct result parse_stmts(struct allocator * alct, struct token_stream * ts); +struct result parse_instr(struct allocator * alct, struct token_stream * ts); +struct result parse_label(struct allocator * alct, struct token_stream * ts); +struct result parse_op(struct allocator * alct, struct token_stream * ts); #endif diff --git a/src/as_tokenizer.c b/src/as_tokenizer.c index 6c40b9f..f2c3ccb 100644 --- a/src/as_tokenizer.c +++ b/src/as_tokenizer.c @@ -71,8 +71,9 @@ int is_part_of_identifier(int c) { return 0; } -struct token * next_token_impl(struct allocator * alct, struct input_stream * s) { - struct token * t = allocate(alct, sizeof(struct token)); +struct result next_token_impl(struct allocator * alct, struct input_stream * s) { + const char *errmsg; + struct token * t = allocate(alct, sizeof(struct token)); int c; while (1) { c = input_stream_peek_char(s); @@ -82,12 +83,12 @@ struct token * next_token_impl(struct allocator * alct, struct input_stream * s) if (c == '\n') { input_stream_next_char(s); *t = (struct token){.type = TK_NEWLINE, .line = s->line, .col = s->col}; - return t; + return (struct result){.value = t, .errmsg = NULL}; } if (c == ':') { input_stream_next_char(s); *t = (struct token){.type = TK_COLON, .line = s->line, .col = s->col}; - return t; + return (struct result){.value = t, .errmsg = NULL}; } if (c == ' ' || c == '\t') { input_stream_next_char(s); @@ -104,17 +105,17 @@ struct token * next_token_impl(struct allocator * alct, struct input_stream * s) } } *t = (struct token){.type = TK_ARG, .ival = ival, .line = s->line, .col = s->col}; - return t; + return (struct result){.value = t, .errmsg = NULL}; } if (is_start_of_identifier(c)) { size_t line = s->line; size_t col = s->col; char *sval = allocate(alct, 256); size_t i = 0; - while(1) { + while (1) { if (i >= 255) { - fprintf(stderr, "error: identifier too long\n"); - exit(1); + errmsg = safe_sprintf(alct, "error: identifier too long\n"); + return (struct result){.value = NULL, .errmsg = errmsg}; } input_stream_next_char(s); sval[i++] = c; @@ -126,34 +127,36 @@ struct token * next_token_impl(struct allocator * alct, struct input_stream * s) sval[i] = '\0'; if (isOp(sval)) { *t = (struct token){.type = TK_OP, .sval = sval, .line = line, .col = col}; - return t; + return (struct result){.value = t, .errmsg = NULL}; } *t = (struct token){.type = TK_TAG, .sval = sval, .line = line, .col = col}; - return t; + return (struct result){.value = t, .errmsg = NULL}; } - fprintf(stderr, "error: invalid character %c at line %d, col %d\n", c, s->line, s->col); + errmsg = safe_sprintf(alct, "error: invalid character %c at line %d, col %d\n", c, s->line, s->col); + return (struct result){.value = NULL, .errmsg = errmsg}; } // end of file *t = (struct token){.type = TK_ENDOFFILE}; - return t; + return (struct result){.value = t, .errmsg = NULL}; } -struct token * next_token(struct allocator * alct, struct token_stream * ts) { +struct result next_token(struct allocator * alct, struct token_stream * ts) { if (ts->buf != NULL) { struct token * t = ts->buf; ts->buf = NULL; - return t; + return (struct result){.value = t, .errmsg = NULL}; } - struct token * t = next_token_impl(alct, ts->s); - return t; + return next_token_impl(alct, ts->s); } -struct token * peek_token(struct allocator * alct, struct token_stream * ts) { +struct result peek_token(struct allocator * alct, struct token_stream * ts) { if (ts->buf != NULL) { - return ts->buf; + return (struct result){.value = ts->buf, .errmsg = NULL}; } - ts->buf = next_token_impl(alct, ts->s); - return ts->buf; + struct result result = next_token_impl(alct, ts->s); + if (result.errmsg != NULL) return result; + ts->buf = result.value; + return result; } void print_token(struct token * t) { diff --git a/src/as_tokenizer.h b/src/as_tokenizer.h index d22ab55..192e381 100644 --- a/src/as_tokenizer.h +++ b/src/as_tokenizer.h @@ -35,9 +35,14 @@ struct token_stream { struct input_stream *s; }; -struct token* next_token(struct allocator * alct, struct token_stream * ts); -struct token* peek_token(struct allocator * alct, struct token_stream * ts); +// result<token*> +struct result next_token(struct allocator * alct, struct token_stream * ts); + +// result<token*> +struct result peek_token(struct allocator * alct, struct token_stream * ts); + void print_token(struct token *t); + struct token_stream * new_token_stream(struct allocator * alct, FILE* fp); #endif // FMV_AS_TOKENIZER_H_ diff --git a/src/utils.c b/src/utils.c index fdd8452..2a0e286 100644 --- a/src/utils.c +++ b/src/utils.c @@ -2,6 +2,7 @@ #include <stdio.h> #include <assert.h> +#include <stdarg.h> struct allocator { void** bufs; @@ -39,4 +40,35 @@ void * allocate(struct allocator * alct, size_t size) { return ptr; } +char* safe_sprintf(struct allocator *alct, const char* format, ...) { + va_list args; + va_list args_copy; + int length; + char* buffer; + va_start(args, format); + va_copy(args_copy, args); + + length = vsnprintf(NULL, 0, format, args); + + if (length < 0) { + va_end(args); + va_end(args_copy); + return NULL; + } + + buffer = (char*)allocate(alct, length + 1); + + if (buffer == NULL) { + va_end(args); + va_end(args_copy); + return NULL; + } + + vsprintf(buffer, format, args_copy); + + va_end(args); + va_end(args_copy); + + return buffer; +} diff --git a/src/utils.h b/src/utils.h index 2381385..5f7c0ff 100644 --- a/src/utils.h +++ b/src/utils.h @@ -5,9 +5,16 @@ struct allocator; +struct result { + void *value; + const char* errmsg; +}; + struct allocator * new_allocator(); void delete_allocator(struct allocator * allocator); void* allocate(struct allocator * allocator, size_t size); +char* safe_sprintf(struct allocator *alct, const char* format, ...); + #endif // FVM_UTILS_H_ |
