formats introduced
This commit is contained in:
parent
bcb3b108a5
commit
ac21f8d98a
|
@ -7,7 +7,7 @@
|
|||
|
||||
# Machine and environ dependent definitions
|
||||
EMHOME = /usr/em
|
||||
LPASS1 = ../lpass1
|
||||
LPASS1 = $(EMHOME)/lang/cem/cemcom
|
||||
|
||||
# Libraries and EM interface definitions
|
||||
SYSLIB = $(EMHOME)/modules/lib/libsystem.a
|
||||
|
@ -24,12 +24,13 @@ CFLAGS = -I$(EMHOME)/modules/h -I$(EMHOME)/modules/pkg -I/usr/include
|
|||
.str.h:
|
||||
$(LPASS1)/make.allocd <$*.str >$*.h
|
||||
|
||||
SRC = lpass2.c read.c report.c class.c
|
||||
OBJ = lpass2.o read.o report.o class.o
|
||||
SRC = lpass2.c checkargs.c read.c report.c class.c l_print3ack.c
|
||||
OBJ = lpass2.o checkargs.o read.o report.o class.o l_print3ack.o
|
||||
|
||||
test: lpass2
|
||||
make lint
|
||||
# lpass2 -xh <.i
|
||||
lpass2 -xh <.i
|
||||
# make lint
|
||||
|
||||
|
||||
lpass2: $(OBJ) Makefile next.o
|
||||
$(CC) $(COPTIONS) $(LDFLAGS) $(OBJ) next.o $(LLIBS) -o lpass2
|
||||
|
|
248
lang/cem/lint/lpass2/checkargs.c
Normal file
248
lang/cem/lint/lpass2/checkargs.c
Normal file
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* $Header$ */
|
||||
|
||||
/******** A R G U M E N T T Y P E C H E C K I N G ********/
|
||||
|
||||
#include "private.h"
|
||||
#include "inpdef.h"
|
||||
|
||||
extern char *strcpy();
|
||||
|
||||
#define streq(s1,s2) (strcmp(s1, s2) == 0)
|
||||
|
||||
/* a format is developed into a normal parameter definition */
|
||||
PRIVATE int is_formatargs; /* present or not */
|
||||
PRIVATE char formatargs[1000]; /* the definitions */
|
||||
|
||||
PRIVATE chk_argtps();
|
||||
PRIVATE char *next_atype();
|
||||
PRIVATE int type_match();
|
||||
|
||||
int
|
||||
type_equal(act, form)
|
||||
char *act, *form;
|
||||
{
|
||||
return streq(act, form)
|
||||
|| streq(act, "erroneous")
|
||||
|| streq(form, "erroneous");
|
||||
}
|
||||
|
||||
chk_args(id, def)
|
||||
struct inpdef *id, *def;
|
||||
{
|
||||
char *act_tp = id->id_argtps;
|
||||
int nrargs = 0; /* number of args */
|
||||
|
||||
/* clear format */
|
||||
is_formatargs = 0;
|
||||
|
||||
/* check normal arguments */
|
||||
chk_argtps(id, def, &nrargs, act_tp, def->id_argtps);
|
||||
|
||||
if (is_formatargs) {
|
||||
/* there was a format */
|
||||
register int i;
|
||||
|
||||
/* skip over the actuals already covered */
|
||||
for (i = 0; i < nrargs; i++) {
|
||||
act_tp = next_atype(act_tp);
|
||||
}
|
||||
|
||||
/* and check the format arguments */
|
||||
chk_argtps(id, (struct inpdef *)0, &nrargs,
|
||||
act_tp, &formatargs[0]);
|
||||
}
|
||||
}
|
||||
|
||||
PRIVATE chk_argtps(id, def, nrargs, act_tp, form_tp)
|
||||
struct inpdef *id; /* the actual call */
|
||||
struct inpdef *def; /* 0 for format-derived definition */
|
||||
int *nrargs; /* in-out parameter, counting */
|
||||
char *act_tp; /* actual types */
|
||||
char *form_tp; /* formal type definitions */
|
||||
{
|
||||
while (*act_tp && *form_tp) {
|
||||
register char *act_start = act_tp;
|
||||
register char *form_start = form_tp;
|
||||
|
||||
/* isolate actual argument type */
|
||||
act_tp = next_atype(act_tp);
|
||||
act_tp[-1] = '\0';
|
||||
|
||||
/* isolate formal argument type */
|
||||
form_tp = next_atype(form_tp);
|
||||
form_tp[-1] = '\0';
|
||||
|
||||
(*nrargs)++;
|
||||
if (!type_match(id, act_start, form_start)) {
|
||||
report("%L: arg %d of %s differs from that in %L",
|
||||
id, *nrargs, id->id_name, def);
|
||||
}
|
||||
act_tp[-1] = ':';
|
||||
form_tp[-1] = ':';
|
||||
}
|
||||
|
||||
if (*form_tp) {
|
||||
/* formal type definitions not exhausted */
|
||||
report("%L: %s has fewer arguments than in %L",
|
||||
id, id->id_name, def);
|
||||
}
|
||||
if (*act_tp) {
|
||||
/* actual types not exhausted */
|
||||
if (def && def->id_nrargs < 0) {
|
||||
/* the function had VARARGS */
|
||||
}
|
||||
else {
|
||||
report("%L: %s has more arguments than in %L",
|
||||
id, id->id_name, def);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PRIVATE char *
|
||||
next_atype(tp)
|
||||
char *tp;
|
||||
{
|
||||
while (*tp && *tp != ':') {
|
||||
tp++;
|
||||
}
|
||||
if (*tp == ':') {
|
||||
tp++;
|
||||
}
|
||||
return tp;
|
||||
}
|
||||
|
||||
int
|
||||
PRIVATE type_match(id, act, form)
|
||||
struct inpdef *id;
|
||||
char *act, *form;
|
||||
{
|
||||
if (form[0] == '"' && act[0] == '"') {
|
||||
conv_format(id, act, form);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( (form[0] == '"' && streq(act, "char*"))
|
||||
|| (act[0] == '"' && streq(form, "char*"))
|
||||
) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (type_equal(act, form))
|
||||
return 1;
|
||||
|
||||
if (act[0] == '+') {
|
||||
/* a non-negative constant */
|
||||
/* might be signed or unsigned */
|
||||
if (type_equal(&act[1], form))
|
||||
return 1;
|
||||
if ( strncmp(form, "unsigned ", strlen("unsigned ")) == 0
|
||||
&& type_equal(&act[1], &form[strlen("unsigned ")])
|
||||
) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
PRIVATE conv_format(id, act, form)
|
||||
struct inpdef *id;
|
||||
char *act, *form;
|
||||
{
|
||||
/* convert the actual format into a def-list, using the
|
||||
formal format (form) as a map to convert from %X to type
|
||||
*/
|
||||
register char *fmt = &formatargs[0];
|
||||
|
||||
is_formatargs = 1;
|
||||
while (*act) {
|
||||
register char *map;
|
||||
|
||||
/* find next conversion specification */
|
||||
while (*act && *act != '%') {
|
||||
act++;
|
||||
}
|
||||
if (*act++ != '%')
|
||||
break;
|
||||
if (*act == '%') {
|
||||
/* %% */
|
||||
act++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* process options */
|
||||
if (*act && *act == '-') {
|
||||
act++;
|
||||
}
|
||||
while (*act && ('0' <= *act && *act <= '9')) {
|
||||
act++;
|
||||
}
|
||||
if (*act == '*') {
|
||||
act++;
|
||||
strcpy(fmt, "int:");
|
||||
fmt += 4;
|
||||
}
|
||||
if (*act && *act == '.') {
|
||||
act++;
|
||||
}
|
||||
while (*act && ('0' <= *act && *act <= '9')) {
|
||||
act++;
|
||||
}
|
||||
if (*act == '*') {
|
||||
act++;
|
||||
strcpy(fmt, "int:");
|
||||
fmt += 4;
|
||||
}
|
||||
|
||||
map = form;
|
||||
while (*map) {
|
||||
register char *cs = act;
|
||||
|
||||
/* find next conversion mapping */
|
||||
while (*map && *map != '%') {
|
||||
map++;
|
||||
}
|
||||
if (*map++ != '%') {
|
||||
/* we ran off the map */
|
||||
report("%L: unknown conversion specification in format",
|
||||
id);
|
||||
break;
|
||||
}
|
||||
|
||||
while (*map && *map != '=') {
|
||||
register int match = 0;
|
||||
|
||||
if (*map == '[') {
|
||||
while (*map && *map != ']') {
|
||||
if (*map == *cs) {
|
||||
match = 1;
|
||||
}
|
||||
map++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
match = (*map == *cs);
|
||||
}
|
||||
|
||||
if (match) {
|
||||
map++, cs++;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
if (*map++ == '=') {
|
||||
/* found the type belonging to %*cs */
|
||||
while (*map && *map != '%' && *map != '"') {
|
||||
*fmt++ = *map++;
|
||||
}
|
||||
*fmt++ = ':';
|
||||
act = cs;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*fmt++ = '\0';
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
class[] contains a bit pattern for each letter, with those bits set
|
||||
that correspond to the lint class meaning of the letter.
|
||||
|
||||
This facility is used through the macro is_class(inpdef_var, CL_???)
|
||||
This facility is used through the macro is_class(inpdef_var, CL_XXX)
|
||||
*/
|
||||
|
||||
#define CL_DEF (1<<0)
|
||||
|
|
30
lang/cem/lint/lpass2/l_print3ack.c
Normal file
30
lang/cem/lint/lpass2/l_print3ack.c
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* $Header$ */
|
||||
|
||||
/* A C K P R I N T M O D U L E D E F I N T I O N S */
|
||||
|
||||
#ifdef lint
|
||||
|
||||
#include <system.h>
|
||||
|
||||
/* LINTLIBRARY */
|
||||
|
||||
/* FORMAT0 $
|
||||
%[bdox] = int %l[bdox] = long
|
||||
%c = int %s = char *
|
||||
%u = unsigned int
|
||||
$ */
|
||||
print(format) char *format; { ; }
|
||||
|
||||
/* FORMAT1 */
|
||||
fprint(filep, format) File *filep; char *format; { ; }
|
||||
/* FORMAT1 */
|
||||
sprint(s, format) char *s; char *format; { ; }
|
||||
/* FORMAT1 */
|
||||
doprnt(filep, format) File *filep; char *format; { ; }
|
||||
|
||||
#endif lint
|
||||
|
|
@ -15,13 +15,11 @@
|
|||
extern char *strcpy();
|
||||
|
||||
#define streq(s1,s2) (strcmp(s1, s2) == 0)
|
||||
#define min(a,b) ((a) <= (b) ? (a) : (b))
|
||||
|
||||
PRIVATE char cur_name[NAMESIZE];
|
||||
PRIVATE struct inpdef *dot, *lib, *ext, *sta;
|
||||
|
||||
PRIVATE check_args();
|
||||
PRIVATE check_def();
|
||||
PRIVATE chk_def();
|
||||
PRIVATE ext_decls();
|
||||
PRIVATE ext_def();
|
||||
PRIVATE get_dot();
|
||||
|
@ -32,8 +30,6 @@ PRIVATE one_func_call();
|
|||
PRIVATE one_var_usage();
|
||||
PRIVATE stat_def();
|
||||
PRIVATE statics();
|
||||
PRIVATE int type_equal();
|
||||
PRIVATE int type_match();
|
||||
PRIVATE usage();
|
||||
|
||||
#define same_name() (dot && streq(cur_name, dot->id_name))
|
||||
|
@ -67,7 +63,7 @@ main(argc, argv)
|
|||
ext_decls();
|
||||
usage(0);
|
||||
if (ext)
|
||||
check_def(ext);
|
||||
chk_def(ext);
|
||||
statics();
|
||||
if (same_name()) {
|
||||
/* there are more lines for this name that have
|
||||
|
@ -199,6 +195,7 @@ PRIVATE one_ext_decl(kind, other_kind, other_class)
|
|||
report("%L: %s %s %s as %s at %L",
|
||||
dot, kind, dot->id_name, defdec(def), other_kind, def);
|
||||
/* no further testing possible */
|
||||
get_dot();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -264,7 +261,7 @@ PRIVATE one_func_call(def)
|
|||
def->id_called = 1;
|
||||
|
||||
if (def->id_args) {
|
||||
check_args(dot, def);
|
||||
chk_args(dot, def);
|
||||
if ( dot->id_valused == USED
|
||||
&& def->id_valreturned == NOVALRETURNED
|
||||
) {
|
||||
|
@ -284,7 +281,7 @@ PRIVATE one_func_call(def)
|
|||
def->id_voided = 1;
|
||||
break;
|
||||
default:
|
||||
panic("invalid dot->id_valused in check");
|
||||
panic("invalid dot->id_valused in one_func_call()");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -326,7 +323,7 @@ PRIVATE statics()
|
|||
stat_def(stnr);
|
||||
usage(stnr);
|
||||
if (sta)
|
||||
check_def(sta);
|
||||
chk_def(sta);
|
||||
|
||||
if (same_obj(stnr))
|
||||
panic("sequence error in input");
|
||||
|
@ -360,7 +357,7 @@ PRIVATE stat_def(stnr)
|
|||
}
|
||||
}
|
||||
|
||||
PRIVATE check_def(def)
|
||||
PRIVATE chk_def(def)
|
||||
struct inpdef *def;
|
||||
{
|
||||
if (!def)
|
||||
|
@ -396,104 +393,6 @@ PRIVATE check_def(def)
|
|||
}
|
||||
|
||||
|
||||
/******** T Y P E C H E C K I N G ********/
|
||||
|
||||
PRIVATE check_args(id, def)
|
||||
struct inpdef *id, *def;
|
||||
{
|
||||
register char *act_tp = id->id_argtps;
|
||||
register char *def_tp = def->id_argtps;
|
||||
register int i;
|
||||
register int nrargs; /* # of args to be type-checked */
|
||||
register int varargs;
|
||||
|
||||
/* determine nrargs */
|
||||
if (def->id_nrargs < 0) {
|
||||
varargs = 1;
|
||||
nrargs = -def->id_nrargs - 1;
|
||||
}
|
||||
else {
|
||||
varargs = 0;
|
||||
nrargs = def->id_nrargs;
|
||||
}
|
||||
|
||||
/* adjust nrargs, if necessary */
|
||||
if (varargs) {
|
||||
if (nrargs > id->id_nrargs) {
|
||||
report("%L: number of args to %s differs from %L",
|
||||
id, id->id_name, def);
|
||||
nrargs = id->id_nrargs;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (nrargs != id->id_nrargs) {
|
||||
report("%L: number of args to %s differs from %L",
|
||||
id, id->id_name, def);
|
||||
nrargs = min(nrargs, id->id_nrargs);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 1; i <= nrargs; i++) {
|
||||
register char *act_par = act_tp;
|
||||
register char *def_par = def_tp;
|
||||
|
||||
/* isolate actual argument type */
|
||||
while (*act_tp) {
|
||||
if (*act_tp == ':') {
|
||||
*act_tp = '\0';
|
||||
break;
|
||||
}
|
||||
act_tp++;
|
||||
}
|
||||
/* isolate formal argument type */
|
||||
while (*def_tp) {
|
||||
if (*def_tp == ':') {
|
||||
*def_tp = '\0';
|
||||
break;
|
||||
}
|
||||
def_tp++;
|
||||
}
|
||||
|
||||
if (!type_match(act_par, def_par)) {
|
||||
report("%L: arg %d of %s differs from that at %L",
|
||||
id, i, id->id_name, def);
|
||||
}
|
||||
*act_tp++ = ':';
|
||||
*def_tp++ = ':';
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
PRIVATE type_equal(act, def)
|
||||
char *act, *def;
|
||||
{
|
||||
return streq(act, def)
|
||||
|| streq(act, "erroneous")
|
||||
|| streq(def, "erroneous");
|
||||
}
|
||||
|
||||
int
|
||||
PRIVATE type_match(act, def)
|
||||
char *act, *def;
|
||||
{
|
||||
if (type_equal(act, def))
|
||||
return 1;
|
||||
|
||||
if (act[0] == '+') {
|
||||
/* a non-negative constant */
|
||||
/* might be signed or unsigned */
|
||||
if (type_equal(&act[1], def))
|
||||
return 1;
|
||||
if ( strncmp(def, "unsigned ", strlen("unsigned ")) == 0
|
||||
&& type_equal(&act[1], &def[strlen("unsigned ")])
|
||||
) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/******** D E B U G G I N G ********/
|
||||
|
||||
print_id(name, id)
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
#include "private.h"
|
||||
|
||||
PRIVATE int LineNr = 1;
|
||||
int LineNr = 1;
|
||||
|
||||
/* Two dangerous macro's. They replace a single statement by
|
||||
* two statements
|
||||
|
@ -25,10 +25,13 @@ PRIVATE int LineNr = 1;
|
|||
#define loadchar(ch) LoadChar(ch); if (ch=='\n') LineNr++
|
||||
#define pushback(ch) PushBack(); if (ch=='\n') LineNr--
|
||||
|
||||
/* all the ReadX() functions return 0 upon EOI */
|
||||
PRIVATE int ReadString();
|
||||
PRIVATE int ReadInt();
|
||||
PRIVATE SkipChar();
|
||||
PRIVATE int ReadArgs();
|
||||
PRIVATE int ReadArg();
|
||||
|
||||
PRIVATE SkipChar();
|
||||
|
||||
int
|
||||
get_id(id)
|
||||
|
@ -79,20 +82,18 @@ get_id(id)
|
|||
|
||||
if (!ReadString(id->id_file, '\n', FNAMESIZE))
|
||||
return 0;
|
||||
return (1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
PRIVATE int
|
||||
ReadString(buf, delim, maxsize)
|
||||
char *buf;
|
||||
{
|
||||
/* Reads a string until 'delim' is encountered.
|
||||
Delim is discarded.
|
||||
If 'maxsize-1' is exceeded, "string too long" is written
|
||||
by panic().
|
||||
/* Reads a string until 'delim' is encountered; delim is
|
||||
discarded.
|
||||
If 'maxsize-1' is exceeded or the string contains a newline
|
||||
(which is not delim), panic() is called.
|
||||
A '\0' is appended to the string.
|
||||
At EOI 0 is returned, else the length of the string (including
|
||||
the appended '\0') is returned.
|
||||
*/
|
||||
|
||||
int ch = 0;
|
||||
|
@ -104,14 +105,18 @@ ReadString(buf, delim, maxsize)
|
|||
return 0;
|
||||
if (ch == delim)
|
||||
break;
|
||||
if (ch == '\n') {
|
||||
panic("newline in string");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
buf[nread++] = (char)ch;
|
||||
}
|
||||
buf[nread++] = '\0';
|
||||
if (ch != delim) {
|
||||
panic("line %d: string too long: %s", LineNr, buf);
|
||||
panic("string too long");
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
return (nread);
|
||||
return 1;
|
||||
}
|
||||
|
||||
PRIVATE int
|
||||
|
@ -123,7 +128,6 @@ ReadInt(ip)
|
|||
* Non-digits except minus-sign in front of the number are discarded.
|
||||
* Doesn't check on overflow.
|
||||
* Just a minus-sign is interpreted as 0. (To prevent a look-ahead.)
|
||||
* At EOI 0 is returned, else 1.
|
||||
*/
|
||||
int ch;
|
||||
int negative = 0;
|
||||
|
@ -148,24 +152,12 @@ ReadInt(ip)
|
|||
return 1;
|
||||
}
|
||||
|
||||
PRIVATE SkipChar(ch)
|
||||
{
|
||||
int c;
|
||||
|
||||
loadchar(c);
|
||||
if (c != ch) {
|
||||
panic("line %d: bad format, '%c' expected; '%c' read",
|
||||
LineNr, ch, c);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
}
|
||||
|
||||
PRIVATE int
|
||||
ReadArgs(nrargs, buf)
|
||||
char *buf;
|
||||
{
|
||||
/* Reads a string into buf with format
|
||||
<type1>:<type2>: ... :<typeN>:
|
||||
<type1>:<type2>: ... :<typeN>:\0
|
||||
Note: format must include the final colon.
|
||||
*/
|
||||
int i;
|
||||
|
@ -179,7 +171,7 @@ ReadArgs(nrargs, buf)
|
|||
for (i = 0; i < nrargs; i++) {
|
||||
int n;
|
||||
|
||||
if (!ReadString(buf, ':', ARGTPSSIZE-charcount-1))
|
||||
if (!ReadArg(buf, ARGTPSSIZE-charcount-1))
|
||||
return 0;
|
||||
n = strlen(buf) + 1;
|
||||
charcount += n;
|
||||
|
@ -190,3 +182,40 @@ ReadArgs(nrargs, buf)
|
|||
return 1;
|
||||
}
|
||||
|
||||
PRIVATE int
|
||||
ReadArg(buf, size)
|
||||
char *buf;
|
||||
int size;
|
||||
{
|
||||
int ch;
|
||||
|
||||
loadchar(ch);
|
||||
switch (ch) {
|
||||
case '"': /* formal format or actual string */
|
||||
*buf++ = ch;
|
||||
if (!ReadString(buf, ch, size-1))
|
||||
return 0;
|
||||
buf += strlen(buf);
|
||||
*buf++ = ch;
|
||||
*buf++ = '\0';
|
||||
SkipChar(':');
|
||||
return 1;
|
||||
default: /* normal type */
|
||||
pushback(ch);
|
||||
return ReadString(buf, ':', size);
|
||||
case EOI:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
PRIVATE SkipChar(ch)
|
||||
{
|
||||
int c;
|
||||
|
||||
loadchar(c);
|
||||
if (c != ch) {
|
||||
panic("bad format, '%c' expected; '%c' read", ch, c);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#define MSGOUT STDERR /* filedes on which to write the messages */
|
||||
#define ERROUT STDERR /* filedes on which to write the panics */
|
||||
|
||||
extern int LineNr;
|
||||
|
||||
PRIVATE rep_loc();
|
||||
|
||||
/* VARARGS */
|
||||
|
@ -90,6 +92,11 @@ PRIVATE
|
|||
rep_loc(id)
|
||||
struct inpdef *id;
|
||||
{
|
||||
/* a definition can come from a number of places */
|
||||
if (!id) {
|
||||
fprint(MSGOUT, "format");
|
||||
}
|
||||
else
|
||||
if (is_class(id, CL_LIB)) {
|
||||
fprint(MSGOUT, "library file %s", id->id_file);
|
||||
}
|
||||
|
@ -103,7 +110,7 @@ rep_loc(id)
|
|||
panic(fmt, args)
|
||||
char *fmt;
|
||||
{
|
||||
fprint(ERROUT, "PANIC, lint, pass2: ");
|
||||
fprint(ERROUT, "PANIC, lint, pass2: line %d: ", LineNr);
|
||||
doprnt(ERROUT, fmt, &args);
|
||||
fprint(ERROUT, "\n");
|
||||
exit(1);
|
||||
|
|
Loading…
Reference in a new issue