|
@@ -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};
|
|
|
}
|