From ee962088e5fb03ff6cc72fc2f28ff4be7a9ee028 Mon Sep 17 00:00:00 2001 From: Robert Burnett Date: Tue, 31 Dec 2024 13:54:23 -0600 Subject: [PATCH 1/4] added nicer error printing function for parse errors --- pnut.c | 108 ++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 77 insertions(+), 31 deletions(-) diff --git a/pnut.c b/pnut.c index 69e4c25c..5c5e107e 100644 --- a/pnut.c +++ b/pnut.c @@ -6,6 +6,7 @@ #include #include // for intptr_t + #define ast int #define true 1 #define false 0 @@ -38,6 +39,8 @@ #define OPTIMIZE_LONG_LINES #endif + + // Use positional parameter directly for function parameters that are constants #define OPTIMIZE_CONSTANT_PARAM_not #define SUPPORT_ADDRESS_OF_OP_not @@ -226,6 +229,9 @@ void fatal_error(char *msg) { exit(1); } + + + void syntax_error(char *msg) { #ifdef INCLUDE_LINE_NUMBER_ON_ERROR putstr(include_stack->filepath); putchar(':'); @@ -2011,11 +2017,52 @@ void get_tok() { } // parser - #if defined DEBUG_CPP || defined DEBUG_EXPAND_INCLUDES || defined NICE_ERR_MSG #include "debug.c" #endif + +#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" + +void parse_error(char * msg, int token) { +#ifdef NICE_ERR_MSG + /*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 @@ -2025,7 +2072,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(); } @@ -2043,26 +2090,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 @@ -2075,7 +2122,7 @@ ast parse_type() { } if (type_kw == 0) { - syntax_error("type expected"); + parse_error("type expected", tok); } return new_ast0(type_kw, 0); @@ -2142,7 +2189,7 @@ ast parse_enum() { while (tok != '}') { if (tok != IDENTIFIER) { - syntax_error("identifier expected"); + parse_error("identifier expected", tok); } ident = new_ast0(IDENTIFIER, val); get_tok(); @@ -2150,7 +2197,7 @@ ast parse_enum() { 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 @@ -2205,13 +2252,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) { @@ -2221,7 +2268,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); @@ -2231,12 +2278,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(';'); @@ -2267,7 +2314,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 @@ -2324,7 +2371,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; @@ -2341,7 +2388,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(); @@ -2363,7 +2410,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 == '[') { @@ -2375,7 +2422,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(']'); @@ -2404,7 +2451,7 @@ ast parse_definition(int local) { get_tok(); continue; // Continue to the next declaration } else { - syntax_error("';' or ',' expected"); + parse_error("';' or ',' expected", tok); } } } @@ -2421,7 +2468,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. @@ -2443,8 +2490,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; } } @@ -2511,7 +2557,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; } @@ -2548,7 +2594,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(); @@ -2557,7 +2603,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(); @@ -2628,7 +2674,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; } @@ -2664,7 +2710,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()); From b7b77c71438b49f7ddad6b347c8937008b3e79b1 Mon Sep 17 00:00:00 2001 From: Robert Burnett Date: Tue, 31 Dec 2024 14:00:35 -0600 Subject: [PATCH 2/4] removed some whitespace, moved to C99 comments --- pnut.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/pnut.c b/pnut.c index 5c5e107e..9181d87b 100644 --- a/pnut.c +++ b/pnut.c @@ -6,7 +6,6 @@ #include #include // for intptr_t - #define ast int #define true 1 #define false 0 @@ -39,8 +38,6 @@ #define OPTIMIZE_LONG_LINES #endif - - // Use positional parameter directly for function parameters that are constants #define OPTIMIZE_CONSTANT_PARAM_not #define SUPPORT_ADDRESS_OF_OP_not @@ -229,9 +226,6 @@ void fatal_error(char *msg) { exit(1); } - - - void syntax_error(char *msg) { #ifdef INCLUDE_LINE_NUMBER_ON_ERROR putstr(include_stack->filepath); putchar(':'); @@ -2032,23 +2026,23 @@ void get_tok() { void parse_error(char * msg, int token) { #ifdef NICE_ERR_MSG - /*Error header*/ + //Error header putstr(ANSI_RED"Error occurred while parsing "); putstr(ANSI_GREEN"\""); putstr(include_stack->filepath); putstr("\""ANSI_RESET"\n"); - /*Error message*/ + //Error message putstr(" Message: "ANSI_YELLOW); putstr(msg); putstr(ANSI_RESET"\n"); - /*Error token*/ + //Error token putstr(" Offending Token: "ANSI_YELLOW); print_tok_type(token); putstr(ANSI_RESET"\n"); - /*Error location*/ + //Error location putstr(" Location: "ANSI_GREEN); putstr(include_stack->filepath); putchar(':'); From 7e98a071c0f90c461e2f21f8215cad246988938c Mon Sep 17 00:00:00 2001 From: Robert Burnett Date: Tue, 31 Dec 2024 14:44:22 -0600 Subject: [PATCH 3/4] move ANSI_* macros inside #ifdef --- pnut.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/pnut.c b/pnut.c index 9181d87b..df3d5241 100644 --- a/pnut.c +++ b/pnut.c @@ -2016,16 +2016,19 @@ void get_tok() { #endif -#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" 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"\""); From 93504f1f917a9c429dac88f800cf8c78c78e88ed Mon Sep 17 00:00:00 2001 From: Robert Burnett Date: Tue, 31 Dec 2024 14:46:58 -0600 Subject: [PATCH 4/4] remove some trailing whitespace --- pnut.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pnut.c b/pnut.c index df3d5241..addb5eaa 100644 --- a/pnut.c +++ b/pnut.c @@ -2019,8 +2019,7 @@ void get_tok() { void parse_error(char * msg, int token) { - -#ifdef NICE_ERR_MSG +#ifdef NICE_ERR_MSG #define ANSI_RED "\x1b[31m" #define ANSI_GREEN "\x1b[32m" #define ANSI_YELLOW "\x1b[33m" @@ -2030,9 +2029,9 @@ void parse_error(char * msg, int token) { #define ANSI_RESET "\x1b[0m" //Error header - putstr(ANSI_RED"Error occurred while parsing "); + putstr(ANSI_RED"Error occurred while parsing "); putstr(ANSI_GREEN"\""); - putstr(include_stack->filepath); + putstr(include_stack->filepath); putstr("\""ANSI_RESET"\n"); //Error message