ast2firm: Factorise code to convert a value to its storage type.
[cparser] / diagnostic.c
index 6376abb..7c0f8a1 100644 (file)
 #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;
-bool     show_column         = true;
+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->lineno);
        if (show_column)
-               fprintf(out, ":%u", pos->colno);
+               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 == '%') {
-                       ++f;
+       for (char const *f; (f = strchr(fmt, '%')); fmt = f) {
+               fwrite(fmt, sizeof(*fmt), f - fmt, stderr); // Print till '%'.
+               ++f; // Skip '%'.
 
-                       bool extended = false;
-                       if (*f == '#') {
-                               extended = true;
-                               ++f;
+               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:;
 
-                       switch (*f) {
-                               case '%':
-                                       fputc(*f, stderr);
-                                       break;
-
-                               case 'c': {
-                                       const unsigned char val = (unsigned char) va_arg(ap, int);
-                                       fputc(val, stderr);
-                                       break;
-                               }
+               int field_width = 0;
+               if (*f == '*') {
+                       ++f;
+                       field_width = va_arg(ap, int);
+               }
 
-                               case 'd': {
-                                       const int val = va_arg(ap, int);
-                                       fprintf(stderr, "%d", val);
-                                       break;
-                               }
+               switch (*f++) {
+               case '%':
+                       fputc('%', stderr);
+                       break;
 
-                               case 's': {
-                                       const char* const str = va_arg(ap, const char*);
-                                       fputs(str, 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;
+               }
 
-                               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 'd': {
+                       const int val = va_arg(ap, int);
+                       fprintf(stderr, "%d", val);
+                       break;
+               }
 
-                               case 'u': {
-                                       const unsigned int val = va_arg(ap, unsigned int);
-                                       fprintf(stderr, "%u", val);
-                                       break;
-                               }
+               case 's': {
+                       const char* const str = va_arg(ap, const char*);
+                       fputs(str, 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 '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 'E': {
-                                       const expression_t* const expr = va_arg(ap, const expression_t*);
-                                       print_expression(expr);
-                                       break;
-                               }
+               case 'u': {
+                       const unsigned int val = va_arg(ap, unsigned int);
+                       fprintf(stderr, "%u", val);
+                       break;
+               }
 
-                               case 'Q': {
-                                       const unsigned qualifiers = va_arg(ap, unsigned);
-                                       print_type_qualifiers(qualifiers, QUAL_SEP_NONE);
-                                       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 '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 '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 't': {
-                                       const token_t *const token = va_arg(ap, const token_t*);
-                                       print_pp_token(stderr, token);
-                                       break;
-                               }
+               case 'E': {
+                       const expression_t* const expr = va_arg(ap, const expression_t*);
+                       print_expression(expr);
+                       break;
+               }
 
-                               case 'K': {
-                                       const token_t* const token = va_arg(ap, const token_t*);
-                                       print_token(stderr, token);
-                                       break;
-                               }
+               case 'Q': {
+                       const unsigned qualifiers = va_arg(ap, unsigned);
+                       print_type_qualifiers(qualifiers, QUAL_SEP_NONE);
+                       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 '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 '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 'K': {
+                       const token_t* const token = va_arg(ap, const token_t*);
+                       print_token(stderr, token);
+                       break;
+               }
 
-                               case 'P': {
-                                       const source_position_t *pos = va_arg(ap, const source_position_t *);
-                                       print_source_position(stderr, pos);
-                                       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;
+               }
 
-                               default:
-                                       panic("unknown format specifier");
+               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);
+                               }
                        }
-               } else {
-                       fputc(*f, stderr);
+                       break;
+               }
+
+               case 'P': {
+                       const position_t *pos = va_arg(ap, const position_t *);
+                       print_position(stderr, pos);
+                       break;
+               }
+
+               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 diagnosticposvf(source_position_t const *const pos, char const *const kind, char const *const fmt, va_list ap)
+static void diagnosticposvf(position_t const *const pos, char const *const kind, char const *const fmt, va_list ap)
 {
        FILE *const out = stderr;
-       fprintf(out, "%s:%u:", pos->input_name, pos->lineno);
-       if (show_column)
-               fprintf(out, "%u:", pos->colno);
-       fprintf(out, " %s: ", kind);
+       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);
 }
 
-static void errorvf(const source_position_t *pos,
+static void errorvf(const position_t *pos,
                     const char *const fmt, va_list ap)
 {
-       curr_pos = pos;
        ++error_count;
        diagnosticposvf(pos, "error", fmt, ap);
        fputc('\n', stderr);
@@ -232,7 +267,7 @@ static void errorvf(const source_position_t *pos,
                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);
@@ -240,47 +275,47 @@ void errorf(const source_position_t *pos, const char *const fmt, ...)
        va_end(ap);
 }
 
-void warningf(warning_t const warn, source_position_t const* pos, char const *const fmt, ...)
+void warningf(warning_t const warn, position_t const* pos, char const *const fmt, ...)
 {
        va_list ap;
        va_start(ap, fmt);
        warning_switch_t const *const s = get_warn_switch(warn);
-       switch (s->level) {
-               case WARN_LEVEL_OFF:
-                       break;
-
+       switch ((unsigned) s->state) {
                        char const* kind;
-               case WARN_LEVEL_ON:
+               case WARN_STATE_ON:
                        if (is_warn_on(WARN_ERROR)) {
-               case WARN_LEVEL_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);
-                       fprintf(stderr, " [-W%s]\n", s->name);
+                       if (diagnostics_show_option)
+                               fprintf(stderr, " [-W%s]\n", s->name);
+                       else
+                               fputc('\n', stderr);
                        break;
 
                default:
-                       panic("invalid warning level");
+                       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)
 {
        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();