Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More informative parse error messages #121

Merged
merged 4 commits into from
Dec 31, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 73 additions & 31 deletions pnut.c
Original file line number Diff line number Diff line change
Expand Up @@ -2011,11 +2011,54 @@ void get_tok() {
}

// parser

#if defined DEBUG_CPP || defined DEBUG_EXPAND_INCLUDES || defined NICE_ERR_MSG
#include "debug.c"
#endif



void parse_error(char * msg, int token) {

#ifdef NICE_ERR_MSG
#define ANSI_RED "\x1b[31m"
#define ANSI_GREEN "\x1b[32m"
#define ANSI_YELLOW "\x1b[33m"
#define ANSI_BLUE "\x1b[34m"
#define ANSI_MAGENTA "\x1b[35m"
#define ANSI_CYAN "\x1b[36m"
#define ANSI_RESET "\x1b[0m"

//Error header
putstr(ANSI_RED"Error occurred while parsing ");
putstr(ANSI_GREEN"\"");
putstr(include_stack->filepath);
putstr("\""ANSI_RESET"\n");

//Error message
putstr(" Message: "ANSI_YELLOW);
putstr(msg);
putstr(ANSI_RESET"\n");

//Error token
putstr(" Offending Token: "ANSI_YELLOW);
print_tok_type(token);
putstr(ANSI_RESET"\n");

//Error location
putstr(" Location: "ANSI_GREEN);
putstr(include_stack->filepath);
putchar(':');
putint(last_tok_line_number);
putchar(':');
putint(last_tok_column_number);
putstr(ANSI_RESET"\n");
#else
fatal_error(msg);
#endif
exit(1);
}


void expect_tok(int expected_tok) {
if (tok != expected_tok) {
#ifdef NICE_ERR_MSG
Expand All @@ -2025,7 +2068,7 @@ void expect_tok(int expected_tok) {
putstr("expected tok="); putint(expected_tok);
putstr("\ncurrent tok="); putint(tok); putchar('\n');
#endif
syntax_error("unexpected token");
parse_error("unexpected token", tok);
}
get_tok();
}
Expand All @@ -2043,26 +2086,26 @@ ast parse_type() {

while (1) {
if (tok == INT_KW || tok == SHORT_KW || tok == LONG_KW || tok == SIGNED_KW) {
if (type_kw != 0 && type_kw != INT_KW) syntax_error("inconsistent type");
if (type_kw != 0 && type_kw != INT_KW) parse_error("inconsistent type", tok);
type_kw = INT_KW;
get_tok();
} else if (tok == CHAR_KW) {
if (type_kw != 0) syntax_error("inconsistent type");
if (type_kw != 0) parse_error("inconsistent type", tok);
type_kw = CHAR_KW;
get_tok();
} else if ((tok == UNSIGNED_KW) || (tok == FLOAT_KW) || (tok == DOUBLE_KW)) {
syntax_error("unsupported type");
parse_error("unsupported type", tok);
} else if (tok == VOID_KW) {
if (type_kw != 0) syntax_error("inconsistent type");
if (type_kw != 0) parse_error("inconsistent type", tok);
type_kw = VOID_KW;
get_tok();
} else if (tok == CONST_KW) {
get_tok(); // ignore const
} else if (tok == ENUM_KW) {
if (type_kw != 0) syntax_error("inconsistent type");
if (type_kw != 0) parse_error("inconsistent type", tok);
return parse_enum();
} else if (tok == STRUCT_KW || tok == UNION_KW) {
if (type_kw != 0) syntax_error("inconsistent type");
if (type_kw != 0) parse_error("inconsistent type", tok);
return parse_struct_or_union(tok);
} else if (tok == TYPE) {
// Look in types table. It's a type, not a type_kw, but we reuse the variable
Expand All @@ -2075,7 +2118,7 @@ ast parse_type() {
}

if (type_kw == 0) {
syntax_error("type expected");
parse_error("type expected", tok);
}

return new_ast0(type_kw, 0);
Expand Down Expand Up @@ -2142,15 +2185,15 @@ ast parse_enum() {

while (tok != '}') {
if (tok != IDENTIFIER) {
syntax_error("identifier expected");
parse_error("identifier expected", tok);
}
ident = new_ast0(IDENTIFIER, val);
get_tok();

if (tok == '=') {
get_tok();

if (tok != INTEGER) syntax_error("integer expected");
if (tok != INTEGER) parse_error("integer expected", tok);
value = new_ast0(INTEGER, val);
next_value = val - 1; // Next value is the current value + 1, but val is negative
get_tok(); // skip
Expand Down Expand Up @@ -2205,13 +2248,13 @@ ast parse_struct_or_union(int struct_or_union_tok) {
get_tok();

while (tok != '}') {
if (!is_type_starter(tok)) syntax_error("type expected in struct declaration");
if (ends_in_flex_array) syntax_error("flexible array member must be last");
if (!is_type_starter(tok)) parse_error("type expected in struct declaration", tok);
if (ends_in_flex_array) parse_error("flexible array member must be last", tok);

type = parse_type_with_stars();

if (get_val(type) == 0 && get_op(type) == VOID_KW)
syntax_error("variable with void type");
parse_error("variable with void type", tok);

ident = 0; // Anonymous struct
if (tok == IDENTIFIER) {
Expand All @@ -2221,7 +2264,7 @@ ast parse_struct_or_union(int struct_or_union_tok) {
if (tok == '[') { // Array
get_tok();
if (tok == ']') {
if (struct_or_union_tok != STRUCT_KW) syntax_error("flexible array member must be in a struct");
if (struct_or_union_tok != STRUCT_KW) parse_error("flexible array member must be in a struct", tok);
ends_in_flex_array = true;
val = 0; // Flex array are arrays with no size, using 0 for now
type = new_ast2('[', new_ast0(INTEGER, 0), type);
Expand All @@ -2231,12 +2274,12 @@ ast parse_struct_or_union(int struct_or_union_tok) {
get_tok();
expect_tok(']');
} else {
syntax_error("array size must be an integer constant");
parse_error("array size must be an integer constant", tok);
}

}
} else if (get_op(type) != STRUCT_KW && get_op(type) != UNION_KW) {
syntax_error("Anonymous struct/union member must have be a struct or union type");
parse_error("Anonymous struct/union member must have be a struct or union type", tok);
}

expect_tok(';');
Expand Down Expand Up @@ -2267,7 +2310,7 @@ ast parse_param_decl() {
type = parse_type_with_stars();
name = val;
expect_tok(IDENTIFIER);
if (get_val(type) == 0 && get_op(type) == VOID_KW) syntax_error("variable with void type");
if (get_val(type) == 0 && get_op(type) == VOID_KW) parse_error("variable with void type", tok);
result = new_ast3(VAR_DECL, name, type, 0);
} else if (tok == IDENTIFIER) {
// Support K&R param syntax in function definition
Expand Down Expand Up @@ -2324,7 +2367,7 @@ ast parse_definition(int local) {
// global enum/struct/union declaration
if (tok == ';') {
if (get_op(type) != ENUM_KW && get_op(type) != STRUCT_KW && get_op(type) != UNION_KW) {
syntax_error("enum/struct/union declaration expected");
parse_error("enum/struct/union declaration expected", tok);
}
get_tok();
return type;
Expand All @@ -2341,7 +2384,7 @@ ast parse_definition(int local) {
if (tok == '(') {

if (local) {
syntax_error("function declaration only allowed at global level");
parse_error("function declaration only allowed at global level", tok);
}

get_tok();
Expand All @@ -2363,7 +2406,7 @@ ast parse_definition(int local) {
} else {

if (get_val(this_type) == 0 && get_op(this_type) == VOID_KW) {
syntax_error("variable with void type");
parse_error("variable with void type", tok);
}

if (tok == '[') {
Expand All @@ -2375,7 +2418,7 @@ ast parse_definition(int local) {
this_type = new_ast2('[', new_ast0(INTEGER, -val), this_type);
get_tok();
} else {
syntax_error("array size must be an integer constant");
parse_error("array size must be an integer constant", tok);
}

expect_tok(']');
Expand Down Expand Up @@ -2404,7 +2447,7 @@ ast parse_definition(int local) {
get_tok();
continue; // Continue to the next declaration
} else {
syntax_error("';' or ',' expected");
parse_error("';' or ',' expected", tok);
}
}
}
Expand All @@ -2421,7 +2464,7 @@ ast parse_definition(int local) {
// it was defined in (global or in function).
get_tok();
type = parse_type_with_stars();
if (tok != IDENTIFIER) { syntax_error("identifier expected"); }
if (tok != IDENTIFIER) { parse_error("identifier expected", tok); }

#ifdef sh
// If the struct/union/enum doesn't have a name, we give it the name of the typedef.
Expand All @@ -2443,8 +2486,7 @@ ast parse_definition(int local) {
expect_tok(';');
return result;
} else {
putstr("tok="); putint(tok); putchar('\n');
syntax_error("unknown decl: type expected");
parse_error("unknown decl: type expected", tok);
return result;
}
}
Expand Down Expand Up @@ -2511,7 +2553,7 @@ ast parse_primary_expression() {
result = parse_parenthesized_expression();

} else {
syntax_error("identifier, literal, or '(' expected");
parse_error("identifier, literal, or '(' expected", tok);
return 0;
}

Expand Down Expand Up @@ -2548,7 +2590,7 @@ ast parse_postfix_expression() {

get_tok();
if (tok != IDENTIFIER) {
syntax_error("identifier expected");
parse_error("identifier expected", tok);
}
result = new_ast2('.', result, new_ast0(IDENTIFIER, val));
get_tok();
Expand All @@ -2557,7 +2599,7 @@ ast parse_postfix_expression() {

get_tok();
if (tok != IDENTIFIER) {
syntax_error("identifier expected");
parse_error("identifier expected", tok);
}
result = new_ast2(ARROW, result, new_ast0(IDENTIFIER, val));
get_tok();
Expand Down Expand Up @@ -2628,7 +2670,7 @@ ast parse_unary_expression() {
result = new_ast2('(', new_ast0(IDENTIFIER, DEFINED_ID), tok);
get_tok_macro();
} else {
syntax_error("identifier or '(' expected");
parse_error("identifier or '(' expected", tok);
return 0;
}

Expand Down Expand Up @@ -2664,7 +2706,7 @@ ast parse_cast_expression() {
type = parse_type_with_stars();

if (get_val(type) == 0 && get_op(type) == VOID_KW)
syntax_error("variable with void type");
parse_error("variable with void type", tok);

expect_tok(')');
result = new_ast2(CAST, type, parse_cast_expression());
Expand Down
Loading