standardising error messages
This commit is contained in:
parent
8571900105
commit
f50774f279
6
Makefile
6
Makefile
@ -5,7 +5,7 @@ RM=rm
|
|||||||
CFLAGS=-Wall -Werror -std=gnu99 -O0 -g
|
CFLAGS=-Wall -Werror -std=gnu99 -O0 -g
|
||||||
LIBS=
|
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
|
OUT=bin/pinky.out
|
||||||
|
|
||||||
all: $(FILES)
|
all: $(FILES)
|
||||||
@ -32,6 +32,10 @@ build/model.o: src/model.c
|
|||||||
@$(ECHO) "CC\t\t"$<
|
@$(ECHO) "CC\t\t"$<
|
||||||
@$(CC) $(CFLAGS) $< -c -o $@ $(LIBS)
|
@$(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
|
build/utils/vector.o: src/utils/vector.c
|
||||||
@$(ECHO) "CC\t\t"$<
|
@$(ECHO) "CC\t\t"$<
|
||||||
@$(CC) $(CFLAGS) $< -c -o $@ $(LIBS)
|
@$(CC) $(CFLAGS) $< -c -o $@ $(LIBS)
|
||||||
|
25
src/error.c
Normal file
25
src/error.c
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#include "error.h"
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
6
src/error.h
Normal file
6
src/error.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#ifndef __ERROR_H
|
||||||
|
#define __ERROR_H
|
||||||
|
|
||||||
|
void display_error (unsigned int lineno, const char *fmt, ...);
|
||||||
|
|
||||||
|
#endif
|
17
src/lexer.c
17
src/lexer.c
@ -1,13 +1,14 @@
|
|||||||
#include "lexer.h"
|
#include "lexer.h"
|
||||||
|
|
||||||
#include "token.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "error.h"
|
||||||
|
#include "token.h"
|
||||||
|
|
||||||
/* helper functions */
|
/* helper functions */
|
||||||
char
|
char
|
||||||
advance (struct lexer *l)
|
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))
|
while (peek (l) != quote && l->cur < buffer_length (l->source))
|
||||||
advance (l);
|
advance (l);
|
||||||
|
|
||||||
|
/* we reached the end of the file without closing the string */
|
||||||
if (l->cur >= buffer_length (l->source))
|
if (l->cur >= buffer_length (l->source))
|
||||||
{
|
display_error (l->line, "Unterminated string");
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
advance (l); /* consume the closing quote */
|
advance (l); /* consume the closing quote */
|
||||||
|
|
||||||
@ -300,8 +296,7 @@ lexer_lex (struct lexer *l)
|
|||||||
else if (isalpha (c) || c == '_')
|
else if (isalpha (c) || c == '_')
|
||||||
handle_identifier (l);
|
handle_identifier (l);
|
||||||
else
|
else
|
||||||
fprintf (stderr, "lexer_lex: unexpected character `%c' at line %d\n",
|
display_error (l->line, "Unexpected character `%c'", c);
|
||||||
c, l->line);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
42
src/parser.c
42
src/parser.c
@ -1,8 +1,10 @@
|
|||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "error.h"
|
||||||
#include "model.h"
|
#include "model.h"
|
||||||
|
|
||||||
/* prototypes */
|
/* prototypes */
|
||||||
@ -36,16 +38,6 @@ struct expression *expression (struct parser *p);
|
|||||||
/* return (struct token *)vector_at (p->curr, p->tokens); */
|
/* 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 *
|
static struct token *
|
||||||
prev_tok (struct parser *p)
|
prev_tok (struct parser *p)
|
||||||
{
|
{
|
||||||
@ -58,6 +50,29 @@ prev_tok (struct parser *p)
|
|||||||
return (struct token *)vector_at (p->curr - 1, p->tokens);
|
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 *
|
static struct token *
|
||||||
match (enum token_type type, struct parser *p)
|
match (enum token_type type, struct parser *p)
|
||||||
{
|
{
|
||||||
@ -87,11 +102,8 @@ primary (struct parser *p)
|
|||||||
if ((tok = match (TOK_LPAREN, p)))
|
if ((tok = match (TOK_LPAREN, p)))
|
||||||
{
|
{
|
||||||
struct expression *expr = expression (p);
|
struct expression *expr = expression (p);
|
||||||
if (!(tok = match (TOK_RPAREN, p)))
|
if (!match (TOK_RPAREN, p))
|
||||||
{
|
display_error (tok->line, "`)' expected");
|
||||||
fprintf (stderr, "Error: `)' expected at line %d.\n", tok->line);
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
return expression_create_grouping (expr);
|
return expression_create_grouping (expr);
|
||||||
}
|
}
|
||||||
return NULL; /* unmatched */
|
return NULL; /* unmatched */
|
||||||
|
61
src/token.c
61
src/token.c
@ -46,3 +46,64 @@ token_free_heap (struct token *t)
|
|||||||
buffer_free (&t->lexeme);
|
buffer_free (&t->lexeme);
|
||||||
free (t);
|
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 */
|
||||||
|
@ -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 (struct token *t);
|
||||||
void token_free_heap (struct token *t);
|
void token_free_heap (struct token *t);
|
||||||
|
|
||||||
|
/* utils */
|
||||||
|
const char *token_type_to_str (enum token_type type);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user