/* ------------------------------------------------------------------------
@NAME : error.c
@DESCRIPTION: Anything relating to reporting or recording errors and
warnings.
@GLOBALS : errclass_names
errclass_counts
@CALLS :
@CREATED : 1996/08/28, Greg Ward
@MODIFIED :
@VERSION : $Id: error.c,v 1.10 1997/09/07 02:36:28 greg Exp $
@COPYRIGHT : Copyright (c) 1996-97 by Gregory P. Ward. All rights reserved.
This file is part of the btparse library. This library is
free software; you can redistribute it and/or modify it under
the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
-------------------------------------------------------------------------- */
#include "bt_config.h"
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include "btparse.h"
#include "error.h"
#include "my_dmalloc.h"
char *errclass_names[NUM_ERRCLASSES] =
{
NULL, /* E_NOTIFY */
"warning", /* E_CONTENT */
"warning", /* E_STRUCTURAL */
"warning", /* E_LEXWARN */
"error", /* E_LEXERR */
"syntax error", /* E_SYNTAX */
"fatal error", /* E_FATAL */
"internal error" /* E_INTERNAL */
};
int errclass_counts[NUM_ERRCLASSES] = { 0, 0, 0, 0, 0, 0, 0, 0 };
/*
* vprint_message()
*
* low-level driver for printing errors, warnings, etc. of any kind.
* Depends on no global variables (except errclass_names), does no policing
* or decision -- just prints the damn thing.
*
* Inputs: filename - name of file where error found
* line - line number in file (1-based)
* column - column in line (0-based; currently ignored)
* show_line - print the offending line? (currently ignored)
* errclass - class of error message (content warning, structure
* warning, lexer error, syntax error)
* format - a printf format for your message
* arglist - the "..." to fill in your format
*
* TO DO: in the lexer (?) we need to build a data structure that will keep
* track of where each line of the file begins. Then, whenever we
* find an error, we remember it for later. When the file is done,
* we go back to print error messages; for each one, we can quickly
* seek to the start of the offending line using the line-start
* data.
*/
static void
vprint_message (char *filename,
int line,
int column,
int show_line,
errclass_t errclass,
char *format,
va_list arglist)
{
char *name;
if (filename)
fprintf (stderr, filename);
if (filename && line > 0)
fprintf (stderr, ", ");
if (line > 0)
fprintf (stderr, "line %d", line);
name = errclass_names[(int) errclass];
if (name)
{
if (filename || line > 0)
fprintf (stderr, ", ");
fprintf (stderr, name);
}
if (filename || line > 0 || name)
fprintf (stderr, ": ");
vfprintf (stderr, format, arglist);
fputc ('\n', stderr);
}
/*------------------------------------------------------------------------
* Functions that call vprint_message(), and are called from elsewhere.
* These freely use the InputFilename global variable, and modify the
* errclass_counts array.
*
* There are three kinds of error functions, all of which are sufficiently
* similar to be generated by macros, but sufficiently different that there
* is one generating macro for each kind of function. Sigh. They are:
* - ordinary error functions, which print no filename or line number info
* (these are: notify(), fatal_error(), internal_error())
* - parser error functions, which get filename from global InputFilename
* and line number from zzline
* (lexical_warning(), lexical_error(), syntax_error())
* - AST error functions, which get filename from global InputFilename
* and line number from a passed-in AST node
* (content_warning(), structural_warning())
*-----------------------------------------------------------------------*/
#define ERRFUNC(func,class,action) \
void func (char *format, ...) \
{ \
va_list arglist; \
\
va_start (arglist, format); \
vprint_message (NULL, 0, -1, 0, \
class, format, arglist); \
errclass_counts[(int) class]++; \
va_end (arglist); \
action; \
}
#define PARSER_ERRFUNC(func,class,action) \
void func (char *format, ...) \
{ \
extern char *InputFilename; \
extern int zzline, zzendcol; \
va_list arglist; \
\
va_start (arglist, format); \
vprint_message (InputFilename, zzline, zzendcol, 1, \
class, format, arglist); \
errclass_counts[(int) class]++; \
va_end (arglist); \
action; \
}
#define AST_ERRFUNC(func,class,action) \
void func (AST *ast, char *format, ...) \
{ \
extern char *InputFilename; \
va_list arglist; \
\
va_start (arglist, format); \
vprint_message (InputFilename, ast->line, ast->offset, 1, \
class, format, arglist); \
\
errclass_counts[(int) class]++; \
va_end (arglist); \
action; \
}
#define GENERAL_ERRFUNC(func,class,action) \
void func (char *filename, int line, char *format, ...) \
{ \
va_list arglist; \
\
va_start (arglist, format); \
vprint_message (filename, line, -1, 1, \
class, format, arglist); \
\
errclass_counts[(int) class]++; \
va_end (arglist); \
action; \
}
ERRFUNC (notify, E_NOTIFY, return)
ERRFUNC (fatal_error, E_FATAL, exit(1))
ERRFUNC (internal_error, E_INTERNAL, abort())
PARSER_ERRFUNC (lexical_warning, E_LEXWARN, return)
PARSER_ERRFUNC (lexical_error, E_LEXERR, return)
PARSER_ERRFUNC (syntax_error, E_SYNTAX, return)
AST_ERRFUNC (content_warning, E_CONTENT, return)
AST_ERRFUNC (structural_warning, E_STRUCTURAL, return)
GENERAL_ERRFUNC(name_warning, E_CONTENT, return)
#undef ERRFUNC
#undef PARSER_ERRFUNC
#undef AST_ERRFUNC
#undef GENERAL_ERRFUNC
/* ------------------------------------------------------------------------
@NAME : reset_error_counts()
@INPUT :
@OUTPUT :
@RETURNS :
@DESCRIPTION: Resets all the error counters to zero.
@GLOBALS :
@CALLS :
@CREATED : 1997/01/08, GPW
@MODIFIED :
-------------------------------------------------------------------------- */
void reset_error_counts (void)
{
int i;
for (i = 0; i < NUM_ERRCLASSES; i++)
errclass_counts[i] = 0;
}
/* ------------------------------------------------------------------------
@NAME : get_error_count()
@INPUT : errclass
@OUTPUT :
@RETURNS :
@DESCRIPTION: Returns number of errors seen in the specified class.
@GLOBALS : errclass_counts
@CALLS :
@CREATED :
@MODIFIED :
-------------------------------------------------------------------------- */
int get_error_count (errclass_t errclass)
{
return errclass_counts[errclass];
}
/* ------------------------------------------------------------------------
@NAME : get_error_counts()
@INPUT : counts - pointer to an array big enough to hold all the
counts, or NULL to make get_error_counts alloc it
@OUTPUT :
@RETURNS : counts - either the passed-in pointer, or the newly-
allocated array if you pass in NULL
@DESCRIPTION: Returns a newly-allocated array with the number of errors
in each error class, indexed by the members of the
eclass_t enum.
@GLOBALS : errclass_counts
@CALLS :
@CREATED : 1997/01/06, GPW
@MODIFIED :
-------------------------------------------------------------------------- */
int *get_error_counts (int *counts)
{
int i;
if (counts == NULL)
counts = (int *) malloc (sizeof (int) * NUM_ERRCLASSES);
for (i = 0; i < NUM_ERRCLASSES; i++)
counts[i] = errclass_counts[i];
return counts;
}
/* ------------------------------------------------------------------------
@NAME : error_status
@INPUT : saved_counts - an array of error counts as returned by
get_error_counts, or NULL to not compare
to a previous watermark
@OUTPUT :
@RETURNS :
@DESCRIPTION: Computes a bitmap where a bit is set for each error class
that has more errors now than it used to have (or, if
saved_counts is NULL, the bit is set of there are have been
any errors in the corresponding error class).
Eg. "x & (1<<E_SYNTAX)" (where x is returned by error_status)
is true if there have been any syntax errors.
@GLOBALS :
@CALLS :
@CREATED :
@MODIFIED :
-------------------------------------------------------------------------- */
ushort error_status (int *saved_counts)
{
int i;
ushort status;
status = 0;
if (saved_counts)
{
for (i = 0; i < NUM_ERRCLASSES; i++)
status |= ( (errclass_counts[i] > saved_counts[i]) << i);
}
else
{
for (i = 0; i < NUM_ERRCLASSES; i++)
status |= ( (errclass_counts[i] > 0) << i);
}
return status;
}