diff --git a/Makefile b/Makefile index edaa0d6..9eb1fa2 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ RM=rm CFLAGS=-Wall -Werror -std=gnu99 -O0 -g LIBS= -FILES=build/main.o build/lexer.o build/token.o build/parser.o build/model.o build/utils/vector.o build/utils/buffer.o +FILES=build/main.o build/lexer.o build/token.o build/parser.o build/model.o build/error.o build/utils/vector.o build/utils/buffer.o OUT=bin/pinky.out all: $(FILES) @@ -32,6 +32,10 @@ build/model.o: src/model.c @$(ECHO) "CC\t\t"$< @$(CC) $(CFLAGS) $< -c -o $@ $(LIBS) +build/error.o: src/error.c + @$(ECHO) "CC\t\t"$< + @$(CC) $(CFLAGS) $< -c -o $@ $(LIBS) + build/utils/vector.o: src/utils/vector.c @$(ECHO) "CC\t\t"$< @$(CC) $(CFLAGS) $< -c -o $@ $(LIBS) diff --git a/src/error.c b/src/error.c new file mode 100644 index 0000000..c2a5645 --- /dev/null +++ b/src/error.c @@ -0,0 +1,25 @@ +#include "error.h" + +#include +#include +#include + +#include "colors.h" +#include "utils/buffer.h" + +void +display_error (unsigned int lineno, const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + + struct buffer buf = buffer_create (); + buffer_printf (&buf, COLOR_RED "[Line %d] Error: %s.\n" COLOR_WHITE, lineno, + fmt); + vprintf (buffer_get (&buf), args); + buffer_free (&buf); + + va_end (args); + + exit (1); +} diff --git a/src/error.h b/src/error.h new file mode 100644 index 0000000..68caa07 --- /dev/null +++ b/src/error.h @@ -0,0 +1,6 @@ +#ifndef __ERROR_H +#define __ERROR_H + +void display_error (unsigned int lineno, const char *fmt, ...); + +#endif diff --git a/src/lexer.c b/src/lexer.c index 59e7c68..9bcdfe5 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -1,13 +1,14 @@ #include "lexer.h" -#include "token.h" - #include #include #include #include +#include "error.h" +#include "token.h" + /* helper functions */ char advance (struct lexer *l) @@ -133,14 +134,9 @@ handle_string (char quote, struct lexer *l) while (peek (l) != quote && l->cur < buffer_length (l->source)) advance (l); + /* we reached the end of the file without closing the string */ if (l->cur >= buffer_length (l->source)) - { - /* we reached the end of the file without closing the string */ - fprintf (stderr, - "lexer.c: handle_string - unterminated string on line %d\n", - l->line); - exit (EXIT_FAILURE); - } + display_error (l->line, "Unterminated string"); advance (l); /* consume the closing quote */ @@ -300,8 +296,7 @@ lexer_lex (struct lexer *l) else if (isalpha (c) || c == '_') handle_identifier (l); else - fprintf (stderr, "lexer_lex: unexpected character `%c' at line %d\n", - c, l->line); + display_error (l->line, "Unexpected character `%c'", c); } } diff --git a/src/parser.c b/src/parser.c index 334fe6d..9c9647c 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1,8 +1,10 @@ #include "parser.h" +#include #include #include +#include "error.h" #include "model.h" /* prototypes */ @@ -36,16 +38,6 @@ struct expression *expression (struct parser *p); /* return (struct token *)vector_at (p->curr, p->tokens); */ /* } */ -/* static _Bool */ -/* expect (enum token_type type, struct parser *p) */ -/* { */ -/* if (!p) */ -/* return 0; */ - -/* struct token *tok = (struct token *)vector_at (p->curr, p->tokens); */ -/* return tok->type == type; */ -/* } */ - static struct token * prev_tok (struct parser *p) { @@ -58,6 +50,29 @@ prev_tok (struct parser *p) return (struct token *)vector_at (p->curr - 1, p->tokens); } +/* static _Bool */ +/* expect (enum token_type type, struct parser *p) */ +/* { */ +/* if (!p) */ +/* return 0; */ + +/* struct token *tok = (struct token *)vector_at (p->curr, p->tokens); */ +/* if (!tok) */ +/* { */ +/* struct token *prev = prev_tok (p); */ +/* display_error (prev->line, "Found `%s' at the end of + * parsing"); */ +/* } */ + +/* if (tok->type != type) */ +/* display_error (tok->line, "Expected token of type `%s', found + * `%s'", */ +/* token_type_to_str + * (type), token_type_to_str (tok->type)); */ + +/* return 1; */ +/* } */ + static struct token * match (enum token_type type, struct parser *p) { @@ -87,11 +102,8 @@ primary (struct parser *p) if ((tok = match (TOK_LPAREN, p))) { struct expression *expr = expression (p); - if (!(tok = match (TOK_RPAREN, p))) - { - fprintf (stderr, "Error: `)' expected at line %d.\n", tok->line); - exit (1); - } + if (!match (TOK_RPAREN, p)) + display_error (tok->line, "`)' expected"); return expression_create_grouping (expr); } return NULL; /* unmatched */ diff --git a/src/token.c b/src/token.c index 44d2e05..79beb4f 100644 --- a/src/token.c +++ b/src/token.c @@ -46,3 +46,64 @@ token_free_heap (struct token *t) buffer_free (&t->lexeme); free (t); } + +/* utils */ +/* clang-format off */ +const char *token_type_to_str(enum token_type type) { + switch (type) { + case TOK_LPAREN: return "TOK_LPAREN"; + case TOK_RPAREN: return "TOK_RPAREN"; + case TOK_LCURLY: return "TOK_LCURLY"; + case TOK_RCURLY: return "TOK_RCURLY"; + case TOK_LSQUAR: return "TOK_LSQUAR"; + case TOK_RSQUAR: return "TOK_RSQUAR"; + case TOK_COMMA: return "TOK_COMMA"; + case TOK_DOT: return "TOK_DOT"; + case TOK_PLUS: return "TOK_PLUS"; + case TOK_MINUS: return "TOK_MINUS"; + case TOK_STAR: return "TOK_STAR"; + case TOK_SLASH: return "TOK_SLASH"; + case TOK_CARET: return "TOK_CARET"; + case TOK_MOD: return "TOK_MOD"; + case TOK_COLON: return "TOK_COLON"; + case TOK_SEMICOLON: return "TOK_SEMICOLON"; + case TOK_QUESTION: return "TOK_QUESTION"; + case TOK_NOT: return "TOK_NOT"; + case TOK_GT: return "TOK_GT"; + case TOK_LT: return "TOK_LT"; + case TOK_EQ: return "TOK_EQ"; + + case TOK_GE: return "TOK_GE"; + case TOK_LE: return "TOK_LE"; + case TOK_NE: return "TOK_NE"; + case TOK_EQEQ: return "TOK_EQEQ"; + case TOK_ASSIGN: return "TOK_ASSIGN"; + case TOK_GTGT: return "TOK_GTGT"; + case TOK_LTLT: return "TOK_LTLT"; + + case TOK_IDENTIFIER:return "TOK_IDENTIFIER"; + case TOK_STRING: return "TOK_STRING"; + case TOK_INTEGER: return "TOK_INTEGER"; + case TOK_FLOAT: return "TOK_FLOAT"; + + case TOK_IF: return "TOK_IF"; + case TOK_THEN: return "TOK_THEN"; + case TOK_ELSE: return "TOK_ELSE"; + case TOK_TRUE: return "TOK_TRUE"; + case TOK_FALSE: return "TOK_FALSE"; + case TOK_AND: return "TOK_AND"; + case TOK_OR: return "TOK_OR"; + case TOK_WHILE: return "TOK_WHILE"; + case TOK_DO: return "TOK_DO"; + case TOK_FOR: return "TOK_FOR"; + case TOK_FUNC: return "TOK_FUNC"; + case TOK_NULL: return "TOK_NULL"; + case TOK_END: return "TOK_END"; + case TOK_PRINT: return "TOK_PRINT"; + case TOK_PRINTLN: return "TOK_PRINTLN"; + case TOK_RET: return "TOK_RET"; + + default: return "UNKNOWN_TOKEN"; + } +} +/* clang-format on */ diff --git a/src/token.h b/src/token.h index 0faf4bc..7624f0b 100644 --- a/src/token.h +++ b/src/token.h @@ -77,4 +77,7 @@ struct token *token_create_heap (enum token_type type, unsigned int line, void token_free (struct token *t); void token_free_heap (struct token *t); +/* utils */ +const char *token_type_to_str (enum token_type type); + #endif