X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=diagnostic.c;h=7c0f8a1da7c77ca5777deaa25fe2995831d19c91;hb=a4ad64eb41a4fc3393fb264922925aa041421c11;hp=0b92ae578c64389b97684db1aaf3d0f35522f66c;hpb=2beaa4f65961fe297663e1cec9e5632b7f3e1cba;p=cparser diff --git a/diagnostic.c b/diagnostic.c index 0b92ae5..7c0f8a1 100644 --- a/diagnostic.c +++ b/diagnostic.c @@ -22,233 +22,300 @@ #include "diagnostic.h" #include "adt/error.h" +#include "entity_t.h" +#include "separator_t.h" #include "symbol_t.h" #include "token_t.h" #include "ast.h" #include "type.h" #include "warning.h" -/** Number of occurred diagnostics. */ -unsigned diagnostic_count = 0; /** Number of occurred errors. */ -unsigned error_count = 0; +unsigned error_count = 0; /** Number of occurred warnings. */ -unsigned warning_count = 0; +unsigned warning_count = 0; +bool show_column = true; +bool diagnostics_show_option = true; -static const source_position_t *curr_pos = NULL; +static const position_t *curr_pos = NULL; /** * prints an additional source position */ -static void print_source_position(FILE *out, const source_position_t *pos) +static void print_position(FILE *out, const position_t *pos) { - fprintf(out, "at line %u", pos->linenr); + fprintf(out, "at line %u", pos->lineno); + if (show_column) + fprintf(out, ":%u", (unsigned)pos->colno); if (curr_pos == NULL || curr_pos->input_name != pos->input_name) fprintf(out, " of \"%s\"", pos->input_name); } +static void fpututf32(utf32 const c, FILE *const out) +{ + if (c < 0x80U) { + fputc(c, out); + } else if (c < 0x800) { + fputc(0xC0 | (c >> 6), out); + fputc(0x80 | (c & 0x3F), out); + } else if (c < 0x10000) { + fputc(0xE0 | ( c >> 12), out); + fputc(0x80 | ((c >> 6) & 0x3F), out); + fputc(0x80 | ( c & 0x3F), out); + } else { + fputc(0xF0 | ( c >> 18), out); + fputc(0x80 | ((c >> 12) & 0x3F), out); + fputc(0x80 | ((c >> 6) & 0x3F), out); + fputc(0x80 | ( c & 0x3F), out); + } +} + /** * Issue a diagnostic message. */ -static void diagnosticvf(const char *const fmt, va_list ap) +static void diagnosticvf(char const *fmt, va_list ap) { - for (const char* f = fmt; *f != '\0'; ++f) { - if (*f == '%') { + for (char const *f; (f = strchr(fmt, '%')); fmt = f) { + fwrite(fmt, sizeof(*fmt), f - fmt, stderr); // Print till '%'. + ++f; // Skip '%'. + + bool extended = false; + bool flag_zero = false; + bool flag_long = false; + for (;; ++f) { + switch (*f) { + case '#': extended = true; break; + case '0': flag_zero = true; break; + case 'l': flag_long = true; break; + default: goto done_flags; + } + } +done_flags:; + + int field_width = 0; + if (*f == '*') { ++f; + field_width = va_arg(ap, int); + } - bool extended = false; - if (*f == '#') { - extended = true; - ++f; + switch (*f++) { + case '%': + fputc('%', stderr); + break; + + case 'c': { + if (flag_long) { + const utf32 val = va_arg(ap, utf32); + fpututf32(val, stderr); + } else { + const unsigned char val = (unsigned char) va_arg(ap, int); + fputc(val, stderr); } + break; + } - switch (*f) { - case '%': - fputc(*f, stderr); - break; - - case 'c': { - const unsigned char val = (unsigned char) va_arg(ap, int); - fputc(val, stderr); - break; - } + case 'd': { + const int val = va_arg(ap, int); + fprintf(stderr, "%d", val); + break; + } - case 'd': { - const int val = va_arg(ap, int); - fprintf(stderr, "%d", val); - break; - } + case 's': { + const char* const str = va_arg(ap, const char*); + fputs(str, stderr); + break; + } - case 's': { - const char* const str = va_arg(ap, const char*); - fputs(str, stderr); - break; - } + case 'S': { + const string_t *str = va_arg(ap, const string_t*); + for (size_t i = 0; i < str->size; ++i) { + fputc(str->begin[i], stderr); + } + break; + } - case 'S': { - const string_t *str = va_arg(ap, const string_t*); - for (size_t i = 0; i < str->size; ++i) { - fputc(str->begin[i], stderr); - } - break; - } + case 'u': { + const unsigned int val = va_arg(ap, unsigned int); + fprintf(stderr, "%u", val); + break; + } - case 'u': { - const unsigned int val = va_arg(ap, unsigned int); - fprintf(stderr, "%u", val); - break; - } + case 'X': { + unsigned int const val = va_arg(ap, unsigned int); + char const *const fmt = flag_zero ? "%0*X" : "%*X"; + fprintf(stderr, fmt, field_width, val); + break; + } - case 'Y': { - const symbol_t *const symbol = va_arg(ap, const symbol_t*); - if (symbol == NULL) - fputs("(null)", stderr); - else - fputs(symbol->string, stderr); - break; - } + case 'Y': { + const symbol_t *const symbol = va_arg(ap, const symbol_t*); + if (symbol == NULL) + fputs("(null)", stderr); + else + fputs(symbol->string, stderr); + break; + } - case 'E': { - const expression_t* const expr = va_arg(ap, const expression_t*); - print_expression(expr); - break; - } + case 'E': { + const expression_t* const expr = va_arg(ap, const expression_t*); + print_expression(expr); + break; + } - case 'Q': { - const unsigned qualifiers = va_arg(ap, unsigned); - print_type_qualifiers(qualifiers); - break; - } + case 'Q': { + const unsigned qualifiers = va_arg(ap, unsigned); + print_type_qualifiers(qualifiers, QUAL_SEP_NONE); + break; + } - case 'T': { - const type_t* const type = va_arg(ap, const type_t*); - const symbol_t* sym = NULL; - if (extended) { - sym = va_arg(ap, const symbol_t*); - } - print_type_ext(type, sym, NULL); - break; - } + case 'T': { + const type_t* const type = va_arg(ap, const type_t*); + const symbol_t* sym = NULL; + if (extended) { + sym = va_arg(ap, const symbol_t*); + } + print_type_ext(type, sym, NULL); + break; + } - case 't': { - const token_t *const token = va_arg(ap, const token_t*); - print_pp_token(stderr, token); - break; - } + case 'K': { + const token_t* const token = va_arg(ap, const token_t*); + print_token(stderr, token); + break; + } - case 'K': { - const token_t* const token = va_arg(ap, const token_t*); - print_token(stderr, token); - break; + case 'k': { + if (extended) { + va_list* const toks = va_arg(ap, va_list*); + separator_t sep = { "", va_arg(ap, const char*) }; + for (;;) { + const token_kind_t tok = (token_kind_t)va_arg(*toks, int); + if (tok == 0) + break; + fputs(sep_next(&sep), stderr); + print_token_kind(stderr, tok); } + } else { + const token_kind_t token = (token_kind_t)va_arg(ap, int); + print_token_kind(stderr, token); + } + break; + } - case 'k': { - if (extended) { - bool first = true; - va_list* toks = va_arg(ap, va_list*); - const char* const delimiter = va_arg(ap, const char*); - for (;;) { - const token_type_t tok = va_arg(*toks, token_type_t); - if (tok == 0) - break; - if (first) { - first = false; - } else { - fputs(delimiter, stderr); - } - print_token_type(stderr, tok); - } - } else { - const token_type_t token = va_arg(ap, token_type_t); - print_token_type(stderr, token); - } - break; + case 'N': { + entity_t const *const ent = va_arg(ap, entity_t const*); + if (extended && is_declaration(ent)) { + print_type_ext(ent->declaration.type, ent->base.symbol, NULL); + } else { + char const *const kind = get_entity_kind_name(ent->kind); + symbol_t const *const sym = ent->base.symbol; + if (sym) { + fprintf(stderr, "%s %s", kind, sym->string); + } else { + fprintf(stderr, "anonymous %s", kind); } + } + break; + } - case 'P': { - const source_position_t *pos = va_arg(ap, const source_position_t *); - print_source_position(stderr, pos); - break; - } + case 'P': { + const position_t *pos = va_arg(ap, const position_t *); + print_position(stderr, pos); + break; + } - default: - panic("unknown format specifier"); - } - } else { - fputc(*f, stderr); + default: + panic("unknown format specifier"); } } + fputs(fmt, stderr); // Print rest. } void diagnosticf(const char *const fmt, ...) { va_list ap; va_start(ap, fmt); - ++diagnostic_count; curr_pos = NULL; diagnosticvf(fmt, ap); va_end(ap); } -static void errorvf(const source_position_t *pos, - const char *const fmt, va_list ap) +static void diagnosticposvf(position_t const *const pos, char const *const kind, char const *const fmt, va_list ap) { - fprintf(stderr, "%s:%u: error: ", pos->input_name, pos->linenr); - ++error_count; + FILE *const out = stderr; + if (pos) { + fprintf(out, "%s:", pos->input_name); + if (pos->lineno != 0) { + fprintf(out, "%u:", pos->lineno); + if (show_column) + fprintf(out, "%u:", (unsigned)pos->colno); + } + fputc(' ', out); + } + fprintf(out, "%s: ", kind); curr_pos = pos; diagnosticvf(fmt, ap); - fputc('\n', stderr); +} - if (warning.fatal_errors) +static void errorvf(const position_t *pos, + const char *const fmt, va_list ap) +{ + ++error_count; + diagnosticposvf(pos, "error", fmt, ap); + fputc('\n', stderr); + if (is_warn_on(WARN_FATAL_ERRORS)) exit(EXIT_FAILURE); } -void errorf(const source_position_t *pos, const char *const fmt, ...) +void errorf(const position_t *pos, const char *const fmt, ...) { va_list ap; va_start(ap, fmt); - curr_pos = pos; errorvf(pos, fmt, ap); va_end(ap); } -static void warningvf(const source_position_t *pos, - const char *const fmt, va_list ap) -{ - fprintf(stderr, "%s:%u: warning: ", pos->input_name, pos->linenr); - ++warning_count; - curr_pos = pos; - diagnosticvf(fmt, ap); - fputc('\n', stderr); -} - -void warningf(const source_position_t *pos, const char *const fmt, ...) +void warningf(warning_t const warn, position_t const* pos, char const *const fmt, ...) { va_list ap; va_start(ap, fmt); - curr_pos = pos; - if (warning.s_are_errors) { - errorvf(pos, fmt, ap); - } else { - warningvf(pos, fmt, ap); + warning_switch_t const *const s = get_warn_switch(warn); + switch ((unsigned) s->state) { + char const* kind; + case WARN_STATE_ON: + if (is_warn_on(WARN_ERROR)) { + case WARN_STATE_ON | WARN_STATE_ERROR: + ++error_count; + kind = "error"; + } else { + case WARN_STATE_ON | WARN_STATE_NO_ERROR: + ++warning_count; + kind = "warning"; + } + diagnosticposvf(pos, kind, fmt, ap); + if (diagnostics_show_option) + fprintf(stderr, " [-W%s]\n", s->name); + else + fputc('\n', stderr); + break; + + default: + break; } va_end(ap); } -static void internal_errorvf(const source_position_t *pos, +static void internal_errorvf(const position_t *pos, const char *const fmt, va_list ap) { - fprintf(stderr, "%s:%u: internal error: ", pos->input_name, pos->linenr); - curr_pos = pos; - diagnosticvf(fmt, ap); + diagnosticposvf(pos, "internal error", fmt, ap); fputc('\n', stderr); } -void internal_errorf(const source_position_t *pos, const char *const fmt, ...) +void internal_errorf(const position_t *pos, const char *const fmt, ...) { va_list ap; va_start(ap, fmt); - curr_pos = pos; internal_errorvf(pos, fmt, ap); va_end(ap); abort();