diff options
Diffstat (limited to 'gcc/f/bad.c')
-rw-r--r-- | gcc/f/bad.c | 537 |
1 files changed, 537 insertions, 0 deletions
diff --git a/gcc/f/bad.c b/gcc/f/bad.c new file mode 100644 index 00000000000..bed9734ecc7 --- /dev/null +++ b/gcc/f/bad.c @@ -0,0 +1,537 @@ +/* bad.c -- Implementation File (module.c template V1.0) + Copyright (C) 1995, 2002, 2003 Free Software Foundation, Inc. + Contributed by James Craig Burley. + +This file is part of GNU Fortran. + +GNU Fortran is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Fortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Fortran; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. + + Related Modules: + None + + Description: + Handles the displaying of diagnostic messages regarding the user's source + files. + + Modifications: +*/ + +/* If there's a %E or %4 in the messages, set this to at least 5, + for example. */ + +#define FFEBAD_MAX_ 6 + +/* Include files. */ + +#include "proj.h" +#include "bad.h" +#include "flags.h" +#include "com.h" +#include "toplev.h" +#include "where.h" +#include "intl.h" +#include "diagnostic.h" + +/* Externals defined here. */ + +bool ffebad_is_inhibited_ = FALSE; + +/* Simple definitions and enumerations. */ + +#define FFEBAD_LONG_MSGS_ 1 /* 0 to use short (or same) messages. */ + +/* Internal typedefs. */ + + +/* Private include files. */ + + +/* Internal structure definitions. */ + +struct _ffebad_message_ + { + const ffebadSeverity severity; + const char *const message; + }; + +/* Static objects accessed by functions in this module. */ + +static const struct _ffebad_message_ ffebad_messages_[] += +{ +#define FFEBAD_MSG(kwd,sev,msgid) { sev, msgid }, +#if FFEBAD_LONG_MSGS_ == 0 +#define LONG(m) +#define SHORT(m) m +#else +#define LONG(m) m +#define SHORT(m) +#endif +#include "bad.def" +#undef FFEBAD_MSG +#undef LONG +#undef SHORT +}; + +static struct + { + ffewhereLine line; + ffewhereColumn col; + ffebadIndex tag; + } + +ffebad_here_[FFEBAD_MAX_]; +static const char *ffebad_string_[FFEBAD_MAX_]; +static ffebadIndex ffebad_order_[FFEBAD_MAX_]; +static ffebad ffebad_errnum_; +static ffebadSeverity ffebad_severity_; +static const char *ffebad_message_; +static unsigned char ffebad_index_; +static ffebadIndex ffebad_places_; +static bool ffebad_is_temp_inhibited_; /* Effective setting of + _is_inhibited_ for this + _start/_finish invocation. */ + +/* Static functions (internal). */ + +static int ffebad_bufputs_ (char buf[], int bufi, const char *s); + +/* Internal macros. */ + +#define ffebad_bufflush_(buf, bufi) \ + (((buf)[bufi] = '\0'), fputs ((buf), stderr), 0) +#define ffebad_bufputc_(buf, bufi, c) \ + (((bufi) == ARRAY_SIZE (buf)) \ + ? (ffebad_bufflush_ ((buf), (bufi)), ((buf)[0] = (c)), 1) \ + : (((buf)[bufi] = (c)), (bufi) + 1)) + + +static int +ffebad_bufputs_ (char buf[], int bufi, const char *s) +{ + for (; *s != '\0'; ++s) + bufi = ffebad_bufputc_ (buf, bufi, *s); + return bufi; +} + +/* ffebad_init_0 -- Initialize + + ffebad_init_0(); */ + +void +ffebad_init_0 (void) +{ + assert (FFEBAD == ARRAY_SIZE (ffebad_messages_)); +} + +ffebadSeverity +ffebad_severity (ffebad errnum) +{ + return ffebad_messages_[errnum].severity; +} + +/* ffebad_start_ -- Start displaying an error message + + ffebad_start(FFEBAD_SOME_ERROR_CODE); + + Call ffebad_start to establish the message, ffebad_here and ffebad_string + to send run-time data to it as necessary, then ffebad_finish when through + to actually get it to print (to stderr). + + Note: ffebad_start(errnum) turns into ffebad_start_(FALSE,errnum). No + outside caller should call ffebad_start_ directly (as indicated by the + trailing underscore). + + Call ffebad_start to start a normal message, one that might be inhibited + by the current state of statement guessing. Call ffebad_start_lex + instead to start a message that is global to all statement guesses and + happens only once for all guesses (i.e. the lexer). + + sev and message are overrides for the severity and messages when errnum + is FFEBAD, meaning the caller didn't want to have to put a message in + bad.def to produce a diagnostic. */ + +bool +ffebad_start_ (bool lex_override, ffebad errnum, ffebadSeverity sev, + const char *msgid) +{ + unsigned char i; + + if (ffebad_is_inhibited_ && !lex_override) + { + ffebad_is_temp_inhibited_ = TRUE; + return FALSE; + } + + if (errnum != FFEBAD) + { + ffebad_severity_ = ffebad_messages_[errnum].severity; + ffebad_message_ = gettext (ffebad_messages_[errnum].message); + } + else + { + ffebad_severity_ = sev; + ffebad_message_ = gettext (msgid); + } + + switch (ffebad_severity_) + { /* Tell toplev.c about this message. */ + case FFEBAD_severityINFORMATIONAL: + case FFEBAD_severityTRIVIAL: + if (inhibit_warnings) + { /* User wants no warnings. */ + ffebad_is_temp_inhibited_ = TRUE; + return FALSE; + } + /* Fall through. */ + case FFEBAD_severityWARNING: + case FFEBAD_severityPECULIAR: + case FFEBAD_severityPEDANTIC: + if ((ffebad_severity_ != FFEBAD_severityPEDANTIC) + || !flag_pedantic_errors) + { + if (!diagnostic_report_warnings_p ()) + { /* User wants no warnings. */ + ffebad_is_temp_inhibited_ = TRUE; + return FALSE; + } + diagnostic_kind_count (global_dc, DK_WARNING)++; + break; + } + /* Fall through (PEDANTIC && flag_pedantic_errors). */ + case FFEBAD_severityFATAL: + case FFEBAD_severityWEIRD: + case FFEBAD_severitySEVERE: + case FFEBAD_severityDISASTER: + diagnostic_kind_count (global_dc, DK_ERROR)++; + break; + + default: + break; + } + + ffebad_is_temp_inhibited_ = FALSE; + ffebad_errnum_ = errnum; + ffebad_index_ = 0; + ffebad_places_ = 0; + for (i = 0; i < FFEBAD_MAX_; ++i) + { + ffebad_string_[i] = NULL; + ffebad_here_[i].line = ffewhere_line_unknown (); + ffebad_here_[i].col = ffewhere_column_unknown (); + } + + return TRUE; +} + +/* ffebad_here -- Establish source location of some diagnostic concern + + ffebad_here(ffebadIndex i,ffewhereLine line,ffewhereColumn col); + + Call ffebad_start to establish the message, ffebad_here and ffebad_string + to send run-time data to it as necessary, then ffebad_finish when through + to actually get it to print (to stderr). */ + +void +ffebad_here (ffebadIndex index, ffewhereLine line, ffewhereColumn col) +{ + ffewhereLineNumber line_num; + ffewhereLineNumber ln; + ffewhereColumnNumber col_num; + ffewhereColumnNumber cn; + ffebadIndex i; + ffebadIndex j; + + if (ffebad_is_temp_inhibited_) + return; + + assert (index < FFEBAD_MAX_); + ffebad_here_[index].line = ffewhere_line_use (line); + ffebad_here_[index].col = ffewhere_column_use (col); + if (ffewhere_line_is_unknown (line) + || ffewhere_column_is_unknown (col)) + { + ffebad_here_[index].tag = FFEBAD_MAX_; + return; + } + ffebad_here_[index].tag = 0; /* For now, though it shouldn't matter. */ + + /* Sort the source line/col points into the order they occur in the source + file. Deal with duplicates appropriately. */ + + line_num = ffewhere_line_number (line); + col_num = ffewhere_column_number (col); + + /* Determine where in the ffebad_order_ array this new place should go. */ + + for (i = 0; i < ffebad_places_; ++i) + { + ln = ffewhere_line_number (ffebad_here_[ffebad_order_[i]].line); + cn = ffewhere_column_number (ffebad_here_[ffebad_order_[i]].col); + if (line_num < ln) + break; + if (line_num == ln) + { + if (col_num == cn) + { + ffebad_here_[index].tag = i; + return; /* Shouldn't go in, has equivalent. */ + } + else if (col_num < cn) + break; + } + } + + /* Before putting new place in ffebad_order_[i], first increment all tags + that are i or greater. */ + + if (i != ffebad_places_) + { + for (j = 0; j < FFEBAD_MAX_; ++j) + { + if (ffebad_here_[j].tag >= i) + ++ffebad_here_[j].tag; + } + } + + /* Then slide all ffebad_order_[] entries at and above i up one entry. */ + + for (j = ffebad_places_; j > i; --j) + ffebad_order_[j] = ffebad_order_[j - 1]; + + /* Finally can put new info in ffebad_order_[i]. */ + + ffebad_order_[i] = index; + ffebad_here_[index].tag = i; + ++ffebad_places_; +} + +/* Establish string for next index (always in order) of message + + ffebad_string(const char *string); + + Call ffebad_start to establish the message, ffebad_here and ffebad_string + to send run-time data to it as necessary, then ffebad_finish when through + to actually get it to print (to stderr). Note: don't trash the string + until after calling ffebad_finish, since we just maintain a pointer to + the argument passed in until then. */ + +void +ffebad_string (const char *string) +{ + if (ffebad_is_temp_inhibited_) + return; + + assert (ffebad_index_ != FFEBAD_MAX_); + ffebad_string_[ffebad_index_++] = string; +} + +/* ffebad_finish -- Display error message with where & run-time info + + ffebad_finish(); + + Call ffebad_start to establish the message, ffebad_here and ffebad_string + to send run-time data to it as necessary, then ffebad_finish when through + to actually get it to print (to stderr). */ + +void +ffebad_finish (void) +{ +#define MAX_SPACES 132 + static const char *const spaces + = "...>\ +\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\ +\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\ +\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\ +\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\ +\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\ +\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\ +\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\ +\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\ +\040\040\040"; /* MAX_SPACES - 1 spaces. */ + ffewhereLineNumber last_line_num; + ffewhereLineNumber ln; + ffewhereLineNumber rn; + ffewhereColumnNumber last_col_num; + ffewhereColumnNumber cn; + ffewhereColumnNumber cnt; + ffewhereLine l; + ffebadIndex bi; + unsigned short i; + char pointer; + unsigned char c; + unsigned const char *s; + const char *fn; + static char buf[1024]; + int bufi; + int index; + + if (ffebad_is_temp_inhibited_) + return; + + switch (ffebad_severity_) + { + case FFEBAD_severityINFORMATIONAL: + s = _("note:"); + break; + + case FFEBAD_severityWARNING: + s = _("warning:"); + break; + + case FFEBAD_severitySEVERE: + s = _("fatal:"); + break; + + default: + s = ""; + break; + } + + /* Display the annoying source references. */ + + last_line_num = 0; + last_col_num = 0; + + for (bi = 0; bi < ffebad_places_; ++bi) + { + if (ffebad_places_ == 1) + pointer = '^'; + else + pointer = '1' + bi; + + l = ffebad_here_[ffebad_order_[bi]].line; + ln = ffewhere_line_number (l); + rn = ffewhere_line_filelinenum (l); + cn = ffewhere_column_number (ffebad_here_[ffebad_order_[bi]].col); + fn = ffewhere_line_filename (l); + if (ln != last_line_num) + { + if (bi != 0) + fputc ('\n', stderr); + diagnostic_report_current_function (global_dc); + fprintf (stderr, + /* the trailing space on the <file>:<line>: line + fools emacs19 compilation mode into finding the + report */ + "%s:%" ffewhereLineNumber_f "u: %s\n %s\n %s%c", + fn, rn, + s, + ffewhere_line_content (l), + &spaces[cn > MAX_SPACES ? 0 : MAX_SPACES - cn + 4], + pointer); + last_line_num = ln; + last_col_num = cn; + s = _("(continued):"); + } + else + { + cnt = cn - last_col_num; + fprintf (stderr, + "%s%c", &spaces[cnt > MAX_SPACES + ? 0 : MAX_SPACES - cnt + 4], + pointer); + last_col_num = cn; + } + } + if (ffebad_places_ == 0) + { + /* Didn't output "warning:" string, capitalize it for message. */ + if (s[0] != '\0') + { + char c; + + c = TOUPPER (s[0]); + fprintf (stderr, "%c%s ", c, &s[1]); + } + else if (s[0] != '\0') + fprintf (stderr, "%s ", s); + } + else + fputc ('\n', stderr); + + /* Release the ffewhere info. */ + + for (bi = 0; bi < FFEBAD_MAX_; ++bi) + { + ffewhere_line_kill (ffebad_here_[bi].line); + ffewhere_column_kill (ffebad_here_[bi].col); + } + + /* Now display the message. */ + + bufi = 0; + for (i = 0; (c = ffebad_message_[i]) != '\0'; ++i) + { + if (c == '%') + { + c = ffebad_message_[++i]; + if (ISUPPER (c)) + { + index = c - 'A'; + + if ((index < 0) || (index >= FFEBAD_MAX_)) + { + bufi = ffebad_bufputs_ (buf, bufi, _("[REPORT BUG!!] %")); + bufi = ffebad_bufputc_ (buf, bufi, c); + } + else + { + s = ffebad_string_[index]; + if (s == NULL) + bufi = ffebad_bufputs_ (buf, bufi, _("[REPORT BUG!!]")); + else + bufi = ffebad_bufputs_ (buf, bufi, s); + } + } + else if (ISDIGIT (c)) + { + index = c - '0'; + + if ((index < 0) || (index >= FFEBAD_MAX_)) + { + bufi = ffebad_bufputs_ (buf, bufi, _("[REPORT BUG!!] %")); + bufi = ffebad_bufputc_ (buf, bufi, c); + } + else + { + pointer = ffebad_here_[index].tag + '1'; + if (pointer == FFEBAD_MAX_ + '1') + pointer = '?'; + else if (ffebad_places_ == 1) + pointer = '^'; + bufi = ffebad_bufputc_ (buf, bufi, '('); + bufi = ffebad_bufputc_ (buf, bufi, pointer); + bufi = ffebad_bufputc_ (buf, bufi, ')'); + } + } + else if (c == '\0') + break; + else if (c == '%') + bufi = ffebad_bufputc_ (buf, bufi, '%'); + else + { + bufi = ffebad_bufputs_ (buf, bufi, _("[REPORT BUG!!]")); + bufi = ffebad_bufputc_ (buf, bufi, '%'); + bufi = ffebad_bufputc_ (buf, bufi, c); + } + } + else + bufi = ffebad_bufputc_ (buf, bufi, c); + } + bufi = ffebad_bufputc_ (buf, bufi, '\n'); + bufi = ffebad_bufflush_ (buf, bufi); +} |