diff options
Diffstat (limited to 'attocc.c')
-rw-r--r-- | attocc.c | 117 |
1 files changed, 88 insertions, 29 deletions
@@ -20,6 +20,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <time.h> #include <unistd.h> #ifdef LINT @@ -222,7 +223,7 @@ union token_data { struct token { enum token_kind kind; union token_data data; - int position; + unsigned long position; }; char is_numeric(char c) { return c >= '0' && c <= '9'; } @@ -309,6 +310,46 @@ char *strdup_failsafe(char *s) { return p; } +struct error { + char *message; + unsigned long position; +}; + +unsigned long *build_linemap(char *source) { + unsigned long i = 0; + unsigned long *lines = realloc_failsafe(NULL, sizeof(unsigned long)); + int num_lines = 1; + lines[0] = 0; + while (source[i]) { + if (source[i] == '\n') { + num_lines += 1; + lines = realloc_failsafe(lines, num_lines * sizeof(unsigned long)); + lines[num_lines - 1] = i; + } + i += 1; + } + lines = realloc_failsafe(lines, (num_lines + 1) * sizeof(unsigned long)); + lines[num_lines] = 0xffffffff; + return lines; +} + +int find_line(unsigned long *linemap, unsigned long position) { + int line = 0; + while (linemap[line] < position) + line += 1; + return line; +} + +void print_error(struct error error, char *filename, char *source, + unsigned long *linemap) { + int line = find_line(linemap, error.position); + int column = error.position - linemap[line]; + if (!error.message) + error.message = "<no message>"; + printf("error: %s\n", error.message); + printf("\tin %s:%i:%i\n", filename, line + 1, column + 1); +} + struct token *token_push(struct token **tokens, unsigned long *num_tokens) { *num_tokens += 1; *tokens = realloc_failsafe(*tokens, sizeof(struct token) * *num_tokens); @@ -639,22 +680,18 @@ struct node { } data; }; -struct node *parse_enum_decl(int *p, struct token *tokens, char **error); -struct node *parse_function(int *p, struct token *tokens, char **error); -struct node *parse_type(int *p, struct token *tokens, char **error); -struct node *parse_toplevel(int *p, struct token *tokens, char **error); +struct node *parse_enum_decl(int *p, struct token *tokens, struct error *error); +struct node *parse_function(int *p, struct token *tokens, struct error *error); +struct node *parse_type(int *p, struct token *tokens, struct error *error); +struct node *parse_toplevel(int *p, struct token *tokens, struct error *error); -struct node *parse(int *p, struct token *tokens, char **error) { +struct node *parse(int *p, struct token *tokens, struct error *error) { int num_elements = 0; struct node **elements = NULL; - while (1) { + while (tokens[*p].kind != TOK_END) { struct node *el = parse_toplevel(p, tokens, error); - if (!el) { - if (tokens[*p].kind == TOK_END) - break; - else - return NULL; - } + if (!el) + return NULL; num_elements += 1; elements = realloc_failsafe(elements, num_elements * sizeof(struct node *)); elements[num_elements - 1] = el; @@ -666,7 +703,7 @@ struct node *parse(int *p, struct token *tokens, char **error) { return node; } -struct node *parse_toplevel(int *p, struct token *tokens, char **error) { +struct node *parse_toplevel(int *p, struct token *tokens, struct error *error) { struct node *out; out = parse_type(p, tokens, error); if (out) @@ -678,7 +715,7 @@ struct node *parse_toplevel(int *p, struct token *tokens, char **error) { return NULL; } -struct node *parse_type(int *p, struct token *tokens, char **error) { +struct node *parse_type(int *p, struct token *tokens, struct error *error) { struct node *out; out = parse_enum_decl(p, tokens, error); if (out) @@ -690,10 +727,12 @@ struct node *parse_type(int *p, struct token *tokens, char **error) { node->data.primitive_type = PRIMTY_I32; } + error->message = "type expected"; + error->position = tokens[*p].position; return NULL; } -struct node *parse_function(int *p, struct token *tokens, char **error) { +struct node *parse_function(int *p, struct token *tokens, struct error *error) { struct node *return_type = parse_type(p, tokens, error); if (!return_type) return NULL; @@ -742,9 +781,13 @@ struct node *parse_function(int *p, struct token *tokens, char **error) { return node; } -struct node *parse_enum_decl(int *p, struct token *tokens, char **error) { - if (tokens[*p].kind != TOK_KEYWORD || tokens[*p].data.keyword != KW_ENUM) - return 0; +struct node *parse_enum_decl(int *p, struct token *tokens, + struct error *error) { + if (tokens[*p].kind != TOK_KEYWORD || tokens[*p].data.keyword != KW_ENUM) { + error->message = "expected enum keyword"; + error->position = tokens[*p].position; + return NULL; + } *p += 1; char *ident = NULL; @@ -769,8 +812,11 @@ struct node *parse_enum_decl(int *p, struct token *tokens, char **error) { tokens[*p].data.seperator == SEP_RCURLY) break; - if (tokens[*p].kind == TOK_END) + if (tokens[*p].kind == TOK_END) { + error->message = "unexpected eof in enum decl"; + error->position = tokens[*p].position; return NULL; + } if (tokens[*p].kind == TOK_SEPERATOR && tokens[*p].data.seperator == SEP_COMMA) { @@ -778,8 +824,11 @@ struct node *parse_enum_decl(int *p, struct token *tokens, char **error) { continue; } - if (tokens[*p].kind != TOK_IDENTIFIER) + if (tokens[*p].kind != TOK_IDENTIFIER) { + error->message = "expected identifier in enum decl"; + error->position = tokens[*p].position; return NULL; + } char *m_ident = tokens[*p].data.identifier; @@ -787,12 +836,18 @@ struct node *parse_enum_decl(int *p, struct token *tokens, char **error) { tokens[*p].data.operator== OP_ASSIGN) { *p += 1; - if (tokens[*p].kind == TOK_END) + if (tokens[*p].kind == TOK_END) { + error->message = "unexpected eof in enum decl"; + error->position = tokens[*p].position; return NULL; + } if (tokens[*p].kind != TOK_CONSTANT || - tokens[*p].data.constant_kind != CONST_INT) + tokens[*p].data.constant_kind != CONST_INT) { + error->message = "expected integer constant as enum value"; + error->position = tokens[*p].position; return NULL; + } value = tokens[*p].data.constant_int_value; *p += 1; @@ -811,7 +866,8 @@ struct node *parse_enum_decl(int *p, struct token *tokens, char **error) { tokens[*p].data.seperator == SEP_SEMICOLON) { } else { - printf("expected members or semicolon\n"); + error->message = "expected semicolon or enum variants"; + error->position = tokens[*p].position; return NULL; } @@ -912,9 +968,9 @@ void test() { assert(is_alpha('z'), "alpha 2"); assert(is_alpha('k'), "alpha 3"); assert(!!tokenize("enum"), "tok 1"); - assert(!!tokenize("int x = 0"), "tok 1"); - // assert(!!tokenize("\"Hello\""), "tok 1"); - assert(!!tokenize("'\n'"), "tok 1"); + assert(!!tokenize("int x = 0"), "tok 2"); + assert(!!tokenize("\"Hello\""), "tok 3"); + assert(!!tokenize("'\n'"), "tok 4"); } #endif @@ -979,10 +1035,13 @@ int main(int argc, char **argv) { #endif int p = 0; - char *error = "no message"; + struct error error; + error.message = NULL; + error.position = 0; struct node *node = parse(&p, tokens, &error); if (!node) { - printf("parse failed: %s\n", error); + unsigned long *linemap = build_linemap(source); + print_error(error, input, source, linemap); return 1; } |