summaryrefslogtreecommitdiff
path: root/attocc.c
diff options
context:
space:
mode:
Diffstat (limited to 'attocc.c')
-rw-r--r--attocc.c117
1 files changed, 88 insertions, 29 deletions
diff --git a/attocc.c b/attocc.c
index c81db15..cb78617 100644
--- a/attocc.c
+++ b/attocc.c
@@ -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;
}