Trailing-Edge
-
PDP-10 Archives
-
SRI_NIC_PERM_FS_1_19910112
-
c/kcc/ccerr.c
There are 8 other files named ccerr.c in the archive. Click here to see a list.
/* CCERR.C - Error Handling
**
** (c) Copyright Ken Harrenstien 1989
** All changes after v.57, 15-Apr-1988
** (c) Copyright Ken Harrenstien, SRI International 1985, 1986
** All changes after v.23, 8-Aug-1985
**
** Original version (C) 1981 K. Chen
*/
#include "cc.h"
#include "cclex.h" /* For access to error line buffer */
#include "ccchar.h" /* For isprint() */
#include <stdarg.h> /* For printf-type args */
#include <stdlib.h> /* For exit() return vals */
#include <string.h>
#ifndef __STDC__
#define __STDC__ 0
#endif
/* Exported functions declared in ccerr.h */
/* Imported functions */
extern char *estrcpy(); /* CCASMB for string hacking */
extern int nextoken(); /* CCLEX */
extern void tokpush(); /* CCLEX */
/* Internal functions */
static char *errmak();
static int evsprintf();
static void context(), recover(), ectran();
#if __STDC__
#define PRFUN(f) f(char *fmt, ...) { va_list ap; va_start(ap, fmt);
#else
#define PRFUN(f) f(fmt) char *fmt; { va_list ap; va_start(ap, fmt);
#endif
/* NOTE - print notification message
*/
void PRFUN(note)
if (wrnlev < WLEV_NOTE)
context("[Note] ", fmt, ap);
}
/* ADVISE - print advisory message
*/
void PRFUN(advise)
if (wrnlev < WLEV_ADVISE)
context("[Advisory] ", fmt, ap);
}
/* WARN - print warning message
*/
void PRFUN(warn)
if (wrnlev < WLEV_WARN)
context("[Warning] ", fmt, ap);
}
void PRFUN(int_warn)
context("[Warning][Internal error] ", fmt, ap);
}
/* ERROR - print error message
** INT_ERROR - same, but prefixes with "Internal error - "
*/
void PRFUN(error)
nerrors++; /* Mark this as an error */
context("", fmt, ap); /* Show context */
}
void PRFUN(int_error)
nerrors++; /* Mark this as an error */
context("[Internal error] ", fmt, ap); /* Show context */
}
/* EFATAL - print fatal error message, with context.
*/
void PRFUN(efatal)
context("[FATAL] ", fmt, ap); /* Show context */
exit(EXIT_FAILURE);
}
/* JMSG - print job error message (no context).
** JERR - print job error message and bump error count for current module.
** FATAL - print fatal job error message and die.
*/
static char jerrhdr[] = /* Header differs, sigh */
#if SYS_CSI
"? KCC";
#else
"?KCC";
#endif
void PRFUN(jmsg)
fprintf(stderr, "%s - %s\n", jerrhdr, errmak(fmt, ap));
}
void PRFUN(jerr)
++nerrors;
fprintf(stderr, "%s - %s\n", jerrhdr, errmak(fmt, ap));
}
void PRFUN(fatal)
fprintf(stderr, "%s - Fatal error: %s\n", jerrhdr, errmak(fmt, ap));
exit(EXIT_FAILURE); /* stop program */
}
/* ERRFOPEN - Auxiliary for CC and CCOUT, invoked after failing fopen()s
*/
void
errfopen(desc, fnam)
char *desc, *fnam;
{
jerr("Could not open %s file \"%s\"", desc, fnam);
}
/* ERRNOMEM - Auxiliary invoked when a malloc fails.
*/
void
errnomem(s)
char *s;
{
efatal("Out of memory %s", s);
}
/* ERRMAK - Return pointer to a static buffer containing error msg text.
** This does not contain a newline.
*/
static char *
errmak(fmt, ap)
char *fmt;
va_list ap;
{
static char emsgbuf[2000]; /* Want lots of room to be real safe */
evsprintf(emsgbuf, fmt, &ap);
va_end(ap);
return emsgbuf;
}
/* CONTEXT - print context of error
** If "fline" is set 0 (normally never, since it starts at 1)
** the input buffer context will not be shown.
** This feature is used when emitting warnings after a file has been
** completely compiled.
*/
static void
context(etype, fmt, ap)
char *etype, *fmt;
va_list ap;
{
char *estr;
char *cp, *ep;
char conbuf[ERRLSIZE*6]; /* Allow for lots of "big" chars */
int cnt, colcnt;
int here = line; /* Line # on page */
estr = errmak(fmt, ap); /* Build error message */
if (erptr != errlin && erptr[-1] == '\n')
--here; /* Find right line # on current page */
/* (KLH: but probably not worth the trouble) */
#if 1 /* New version */
fprintf(stderr, "\"%s\", line %d: %s%s\n",
inpfname, fline, etype, estr);
/* Someday may wish to make further context optional (runtime switch) */
if (!fline || 0) return; /* Omit buffer context if at EOF */
cp = estrcpy(conbuf, " ("); /* Indented by 6 */
if (curfn != NULL) { /* are we in some function? */
cp = estrcpy(cp, curfn->Sname); /* yes, give its name */
if (fline > curfnloc) {
sprintf(cp, "+%d", fline - curfnloc);
cp += strlen(cp);
}
cp = estrcpy(cp, ", "); /* separate from page/line info */
}
sprintf(cp, "p.%d l.%d): ", page, here);
colcnt = strlen(conbuf); /* # cols so far */
fputs(conbuf, stderr);
/* Show current input context */
#if 1
/* Unroll circular buffer */
if (!ercsiz) ercsiz = 79; /* Set default if needed (# cols of context) */
colcnt = ercsiz - colcnt; /* Get # columns available for input context */
cp = conbuf;
ep = erptr;
cnt = erpleft;
while (*ep == 0 && --cnt > 0) ++ep; /* Scan to find first non-null */
if (cnt > 0) {
ectran(conbuf, ep, cnt); /* Translate cnt chars from ep to buf*/
ectran(conbuf+strlen(conbuf), /* then initial part */
errlin, ERRLSIZE - erpleft);
} else {
ep = errlin;
cnt = ERRLSIZE - erpleft;
while (*ep == 0 && --cnt > 0) ++ep;
ectran(conbuf, ep, cnt);
}
if ((cnt = strlen(cp = conbuf)) > colcnt)
cp += cnt - colcnt; /* If too long, show only last N chars */
fputs(cp, stderr); /* Output the context string! */
fputc('\n', stderr);
fputc('\n', stderr); /* Extra newline between msgs for clarity */
#else
if (erptr != errlin) *erptr = 0; /* terminate line for printf */
fprintf(stderr, "%s\n", errlin); /* print where we were */
#endif
#else /* Old version */
fprintf(stderr, "\n%s at ", etype); /* start error message */
if (curfn != NULL) { /* are we in some function? */
fputs(curfn->Sname, stderr); /* yes, give its name */
if (fline > curfnloc) fprintf(stderr, "+%d", fline - curfnloc);
fputs(", ", stderr); /* separate from absolute loc */
}
if (page > 1) fprintf(stderr, "page %d ", page); /* page number */
fprintf(stderr,"line %d of %s:\n", here, inpfname);
if (erptr != errlin) *erptr = 0; /* terminate line for printf */
fputs(errlin, stderr); /* print where we were */
#endif
}
/* ECTRAN - translate file input string to something nice for
** error message output. Always adds a NUL after "cnt" chars.
*/
static void
ectran(to, from, cnt)
char *to, *from;
int cnt;
{
int c;
char *exp;
char expbuf[8];
while (--cnt >= 0) {
if (isprint(c = *from++)) {
*to++ = c;
continue;
} else switch (c) {
case (char)-1: exp = "<EOF>"; break;
case '\b': exp = "<\\b>"; break; /* Show unusual whitespace */
case '\f': exp = "<\\f>"; break;
case '\v': exp = "<\\v>"; break;
case '\r': exp = "<\\r>"; break;
#if 1
case '\t':
case '\n': exp = " "; break; /* Just use whitespace */
#else
case '\t': exp = "<\\t>"; break;
case '\n': exp = "<\\n>"; break;
#endif
default: sprintf(exp = expbuf,"<\\%o>", c); break;
}
to = estrcpy(to, exp);
}
*to = '\0'; /* Ensure string ends with null. */
}
static int edefarg();
static char *tokname();
static int
evsprintf(cp, fmt, aap)
char *cp, *fmt;
va_list *aap;
{
int i, max;
char *str;
NODE *n;
SYMBOL *s;
int cnt = 0;
va_list ap = *aap;
for (*cp = *fmt; *cp; *++cp = *++fmt) {
if (*cp != '%') { ++cnt; continue; }
switch (*++fmt) {
case '%': continue;
case 'E': /* Substitute new format string */
fmt = va_arg(ap, char *);
--fmt;
i = 0;
break;
case 'N': /* Node op printout */
n = va_arg(ap, NODE *);
i = sprintf(cp, "(node %d: %d=%s)", nodeidx(n), n->Nop,
tokname(n->Nop));
break;
case 'Q': /* Token printout */
i = va_arg(ap, int);
i = sprintf(cp, "(token %d=%s)", i, tokname(i));
break;
case 'S': /* Symbol printout */
s = va_arg(ap, SYMBOL *);
str = s->Sname;
i = '"'; /* Default quoting char */
max = IDENTSIZE-1; /* Max ident length */
switch (str[0]) {
case SPC_IDQUOT:
i = '`'; /* Different quote char, then drop thru */
case SPC_SMEM:
case SPC_TAG:
case SPC_LABEL: /* Don't show prefix char */
--max;
++str;
}
i = sprintf(cp, "%c%.*s%c", i, max, str, i);
break;
default:
i = edefarg(cp, &fmt, &ap);
break;
}
cnt += i;
cp += i-1;
}
*aap = ap; /* Update arglist pointer */
return cnt;
}
static char *
tokname(tok)
{
return (0 < tok && tok < NTOKDEFS) ? nopname[tok] : "??";
}
/* EDEFARG - auxiliary to handle default %-specifications.
** Simple-mindedly copies anything that looks like a sprintf format
** spec, and invokes sprintf on it with an appropriate argument
** plucked from the arglist.
** Return value is # chars written, and
** FMT is updated to point at last char read.
*/
static int
edefarg(cp, afmt, aap)
char *cp; /* Points to place to deposit */
char **afmt; /* Points to 1st char after % */
va_list *aap;
{
int c;
char fmtbuf[50];
char *fmt = *afmt;
char *bp = fmtbuf;
int typ = 0;
*bp = '%';
for (c = *fmt; ; c = *++fmt) {
switch (*++bp = c) {
case '*': /* Can't handle this */
default: /* Or end-of-string or anything unknown */
*++cp = **afmt;
return 2;
case '-': case '+': case '0': /* Prefix flags */
case ' ': case '#': case '.':
case '1': case '2': case '3': /* Width or precision specs */
case '4': case '5': case '6':
case '7': case '8': case '9':
continue;
case 'h': case 'l': case 'L': /* Type size flags */
typ = c;
continue;
case 's':
typ = c;
break;
case 'f': case 'e': case 'E': case 'g': case 'G':
if (!typ) typ = 'd';
break;
case 'c': /* Types that take (int) unless h or l seen */
case 'i': case 'd': case 'o': case 'u': case 'x': case 'X':
break;
}
/* Done, assume last char is conversion specifier */
*++bp = 0; /* Tie off format string */
*afmt = fmt; /* Won, update format ptr */
switch (typ) { /* Default type size is (int) */
default: return sprintf(cp, fmtbuf, va_arg(*aap, int));
case 'l': return sprintf(cp, fmtbuf, va_arg(*aap, long));
case 'h': return sprintf(cp, fmtbuf, va_arg(*aap, short));
case 's': return sprintf(cp, fmtbuf, va_arg(*aap, char *));
case 'd': return sprintf(cp, fmtbuf, va_arg(*aap, double));
case 'L': return sprintf(cp, fmtbuf, va_arg(*aap, long double));
}
}
}
/* ---------------------- */
/* expect token */
/* ---------------------- */
int
expect(t)
{
char *s, str[32];
if (t == token) {
nextoken();
return 1;
}
switch (t) {
case T_LPAREN: s = "left parenthesis"; break;
case T_RPAREN: s = "right parenthesis"; break;
case T_LBRACK: s = "left bracket"; break;
case T_RBRACK: s = "right bracket"; break;
case T_SCOLON: s = "semicolon"; break;
case T_COMMA: s = "comma"; break;
case T_COLON: s = "colon"; break;
case Q_IDENT: s = "identifier"; break;
case T_RBRACE: s = "close brace"; break;
case Q_WHILE: s = "\"while\" keyword"; break;
default: sprintf(s = str, "[token %d]", t); break;
}
error("Expected token (%s) not found", s);
recover(t);
return 0;
}
/* ------------------------ */
/* error recovery */
/* ------------------------ */
/* KLH: this is pretty poor; someday work on it. */
static void
recover(n)
{
if (n == T_SCOLON) {
while (!eof && token != T_SCOLON && token != T_RBRACE) nextoken();
if (token == T_SCOLON) nextoken();
return;
}
tokpush(token, csymbol);
token = n;
}
int
errflush()
{
for(;;) switch (token) {
case T_EOF: case T_SCOLON: case T_RBRACE:
return nextoken();
default:
nextoken();
}
}