Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F139430338
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
59 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/usr.bin/xlint/lint1/Makefile b/usr.bin/xlint/lint1/Makefile
index d5e519a4cada..486801968e90 100644
--- a/usr.bin/xlint/lint1/Makefile
+++ b/usr.bin/xlint/lint1/Makefile
@@ -1,19 +1,19 @@
# $NetBSD: Makefile,v 1.3 1995/07/04 01:53:05 cgd Exp $
PROG= lint1
SRCS= cgram.c scan.c mem1.c mem.c err.c main1.c decl.c tree.c func.c \
init.c emit.c emit1.c
NOMAN=
LDADD+= -ll
DPADD+= ${LIBL}
YFLAGS= -d
CFLAGS+=-I.
LINTFLAGS=-aehpz
-CLEANFILES+=y.tab.h cgram.c scan.c
+CLEANFILES+=cgram.tab.h cgram.c scan.c
BINDIR= /usr/libexec
# XXX: -O causes the gcc to die on the i386, when compiling tree.o
CFLAGS+= -DXXX_BROKEN_GCC
.include <bsd.prog.mk>
diff --git a/usr.bin/xlint/lint1/func.c b/usr.bin/xlint/lint1/func.c
index 5d3a17218c3e..5f6b98921a9b 100644
--- a/usr.bin/xlint/lint1/func.c
+++ b/usr.bin/xlint/lint1/func.c
@@ -1,1261 +1,1261 @@
/* $NetBSD: func.c,v 1.7 1995/10/02 17:31:40 jpo Exp $ */
/*
* Copyright (c) 1994, 1995 Jochen Pohl
* All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Jochen Pohl for
* The NetBSD Project.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef lint
static char rcsid[] = "$NetBSD: func.c,v 1.7 1995/10/02 17:31:40 jpo Exp $";
#endif
#include <stdlib.h>
#include <string.h>
#include "lint1.h"
-#include "y.tab.h"
+#include "cgram.tab.h"
/*
* Contains a pointer to the symbol table entry of the current function
* definition.
*/
sym_t *funcsym;
/* Is set as long as a statement can be reached. Must be set at level 0. */
int reached = 1;
/*
* Is set as long as NOTREACHED is in effect.
* Is reset everywhere where reached can become 0.
*/
int rchflg;
/*
* In conjunction with reached ontrols printing of "fallthrough on ..."
* warnings.
* Reset by each statement and set by FALLTHROUGH, switch (switch1())
* and case (label()).
*
* Control statements if, for, while and switch do not reset ftflg because
* this must be done by the controled statement. At least for if this is
* important because ** FALLTHROUGH ** after "if (expr) stmnt" is evaluated
* befor the following token, wich causes reduction of above, is read.
* This means that ** FALLTHROUGH ** after "if ..." would always be ignored.
*/
int ftflg;
/* Top element of stack for control statements */
cstk_t *cstk;
/*
* Number of arguments which will be checked for usage in following
* function definition. -1 stands for all arguments.
*
* The position of the last ARGSUSED comment is stored in aupos.
*/
int nargusg = -1;
pos_t aupos;
/*
* Number of arguments of the following function definition whose types
* shall be checked by lint2. -1 stands for all arguments.
*
* The position of the last VARARGS comment is stored in vapos.
*/
int nvararg = -1;
pos_t vapos;
/*
* Both prflstr and scflstrg contain the number of the argument which
* shall be used to check the types of remaining arguments (for PRINTFLIKE
* and SCANFLIKE).
*
* prflpos and scflpos are the positions of the last PRINTFLIKE or
* SCANFLIKE comment.
*/
int prflstrg = -1;
int scflstrg = -1;
pos_t prflpos;
pos_t scflpos;
/*
* Are both plibflg and llibflg set, prototypes are writen as function
* definitions to the output file.
*/
int plibflg;
/*
* Nonzero means that no warnings about constands in conditional
* context are printed.
*/
int ccflg;
/*
* llibflg is set if a lint library shall be created. The effect of
* llibflg is that all defined symbols are treated as used.
* (The LINTLIBRARY comment also resets vflag.)
*/
int llibflg;
/*
* Nonzero if warnings are suppressed by a LINTED directive
*/
int nowarn;
/*
* Nonzero if complaints about use of "long long" are suppressed in
* the next statement or declaration.
*/
int quadflg;
/*
* Puts a new element at the top of the stack used for control statements.
*/
void
pushctrl(env)
int env;
{
cstk_t *ci;
ci = xcalloc(1, sizeof (cstk_t));
ci->c_env = env;
ci->c_nxt = cstk;
cstk = ci;
}
/*
* Removes the top element of the stack used for control statements.
*/
void
popctrl(env)
int env;
{
cstk_t *ci;
clst_t *cl;
if (cstk == NULL || cstk->c_env != env)
lerror("popctrl() 1");
cstk = (ci = cstk)->c_nxt;
while ((cl = ci->c_clst) != NULL) {
ci->c_clst = cl->cl_nxt;
free(cl);
}
if (ci->c_swtype != NULL)
free(ci->c_swtype);
free(ci);
}
/*
* Prints a warning if a statement cannot be reached.
*/
void
chkreach()
{
if (!reached && !rchflg) {
/* statement not reached */
warning(193);
reached = 1;
}
}
/*
* Called after a function declaration which introduces a function definition
* and before an (optional) old style argument declaration list.
*
* Puts all symbols declared in the Prototype or in an old style argument
* list back to the symbol table.
*
* Does the usual checking of storage class, type (return value),
* redeclaration etc..
*/
void
funcdef(fsym)
sym_t *fsym;
{
int n, warn;
sym_t *arg, *sym, *rdsym;
funcsym = fsym;
/*
* Put all symbols declared in the argument list back to the
* symbol table.
*/
for (sym = dcs->d_fpsyms; sym != NULL; sym = sym->s_dlnxt) {
if (sym->s_blklev != -1) {
if (sym->s_blklev != 1)
lerror("funcdef() 1");
inssym(1, sym);
}
}
/*
* In osfunc() we did not know whether it is an old style function
* definition or only an old style declaration, if there are no
* arguments inside the argument list ("f()").
*/
if (!fsym->s_type->t_proto && fsym->s_args == NULL)
fsym->s_osdef = 1;
chktyp(fsym);
/*
* chktyp() checks for almost all possible errors, but not for
* incomplete return values (these are allowed in declarations)
*/
if (fsym->s_type->t_subt->t_tspec != VOID &&
incompl(fsym->s_type->t_subt)) {
/* cannot return incomplete type */
error(67);
}
fsym->s_def = DEF;
if (fsym->s_scl == TYPEDEF) {
fsym->s_scl = EXTERN;
/* illegal storage class */
error(8);
}
if (dcs->d_inline)
fsym->s_inline = 1;
/*
* Arguments in new style function declarations need a name.
* (void is already removed from the list of arguments)
*/
n = 1;
for (arg = fsym->s_type->t_args; arg != NULL; arg = arg->s_nxt) {
if (arg->s_scl == ABSTRACT) {
if (arg->s_name != unnamed)
lerror("funcdef() 2");
/* formal parameter lacks name: param #%d */
error(59, n);
} else {
if (arg->s_name == unnamed)
lerror("funcdef() 3");
}
n++;
}
/*
* We must also remember the position. s_dpos is overwritten
* if this is an old style definition and we had already a
* prototype.
*/
STRUCT_ASSIGN(dcs->d_fdpos, fsym->s_dpos);
if ((rdsym = dcs->d_rdcsym) != NULL) {
if (!isredec(fsym, (warn = 0, &warn))) {
/*
* Print nothing if the newly defined function
* is defined in old style. A better warning will
* be printed in cluparg().
*/
if (warn && !fsym->s_osdef) {
/* redeclaration of %s */
(*(sflag ? error : warning))(27, fsym->s_name);
prevdecl(-1, rdsym);
}
/* copy usage information */
cpuinfo(fsym, rdsym);
/*
* If the old symbol was a prototype and the new
* one is none, overtake the position of the
* declaration of the prototype.
*/
if (fsym->s_osdef && rdsym->s_type->t_proto)
STRUCT_ASSIGN(fsym->s_dpos, rdsym->s_dpos);
/* complete the type */
compltyp(fsym, rdsym);
/* once a function is inline it remains inline */
if (rdsym->s_inline)
fsym->s_inline = 1;
}
/* remove the old symbol from the symbol table */
rmsym(rdsym);
}
if (fsym->s_osdef && !fsym->s_type->t_proto) {
if (sflag && hflag && strcmp(fsym->s_name, "main") != 0)
/* function definition is not a prototyp */
warning(286);
}
if (dcs->d_notyp)
/* return value is implizitly declared to be int */
fsym->s_rimpl = 1;
reached = 1;
}
/*
* Called at the end of a function definition.
*/
void
funcend()
{
sym_t *arg;
int n;
if (reached) {
cstk->c_noretval = 1;
if (funcsym->s_type->t_subt->t_tspec != VOID &&
!funcsym->s_rimpl) {
/* func. %s falls off bottom without returning value */
warning(217, funcsym->s_name);
}
}
/*
* This warning is printed only if the return value was implizitly
* declared to be int. Otherwise the wrong return statement
* has already printed a warning.
*/
if (cstk->c_noretval && cstk->c_retval && funcsym->s_rimpl)
/* function %s has return (e); and return; */
warning(216, funcsym->s_name);
/* Print warnings for unused arguments */
arg = dcs->d_fargs;
n = 0;
while (arg != NULL && (nargusg == -1 || n < nargusg)) {
chkusg1(dcs->d_asm, arg);
arg = arg->s_nxt;
n++;
}
nargusg = -1;
/*
* write the information about the function definition to the
* output file
* inline functions explicitely declared extern are written as
* declarations only.
*/
if (dcs->d_scl == EXTERN && funcsym->s_inline) {
outsym(funcsym, funcsym->s_scl, DECL);
} else {
outfdef(funcsym, &dcs->d_fdpos, cstk->c_retval,
funcsym->s_osdef, dcs->d_fargs);
}
/*
* remove all symbols declared during argument declaration from
* the symbol table
*/
if (dcs->d_nxt != NULL || dcs->d_ctx != EXTERN)
lerror("funcend() 1");
rmsyms(dcs->d_fpsyms);
/* must be set on level 0 */
reached = 1;
}
/*
* Process a label.
*
* typ type of the label (T_NAME, T_DEFAULT or T_CASE).
* sym symbol table entry of label if typ == T_NAME
* tn expression if typ == T_CASE
*/
void
label(typ, sym, tn)
int typ;
sym_t *sym;
tnode_t *tn;
{
cstk_t *ci;
clst_t *cl;
val_t *v, *nv;
tspec_t t;
switch (typ) {
case T_NAME:
if (sym->s_set) {
/* label %s redefined */
error(194, sym->s_name);
} else {
setsflg(sym);
}
break;
case T_CASE:
/* find the stack entry for the innermost switch statement */
for (ci = cstk; ci != NULL && !ci->c_switch; ci = ci->c_nxt) ;
if (ci == NULL) {
/* case not in switch */
error(195);
tn = NULL;
} else if (tn != NULL && tn->tn_op != CON) {
/* non-constant case expression */
error(197);
tn = NULL;
} else if (tn != NULL && !isityp(tn->tn_type->t_tspec)) {
/* non-integral case expression */
error(198);
tn = NULL;
}
if (tn != NULL) {
if (ci->c_swtype == NULL)
lerror("label() 1");
if (reached && !ftflg) {
if (hflag)
/* fallthrough on case statement */
warning(220);
}
t = tn->tn_type->t_tspec;
if (t == LONG || t == ULONG ||
t == QUAD || t == UQUAD) {
if (tflag)
/* case label must be of type ... */
warning(203);
}
/*
* get the value of the expression and convert it
* to the type of the switch expression
*/
v = constant(tn);
nv = xcalloc(1, sizeof (val_t));
cvtcon(CASE, 0, ci->c_swtype, nv, v);
free(v);
/* look if we had this value already */
for (cl = ci->c_clst; cl != NULL; cl = cl->cl_nxt) {
if (cl->cl_val.v_quad == nv->v_quad)
break;
}
if (cl != NULL && isutyp(nv->v_tspec)) {
/* duplicate case in switch, %lu */
error(200, (u_long)nv->v_quad);
} else if (cl != NULL) {
/* duplicate case in switch, %ld */
error(199, (long)nv->v_quad);
} else {
/*
* append the value to the list of
* case values
*/
cl = xcalloc(1, sizeof (clst_t));
STRUCT_ASSIGN(cl->cl_val, *nv);
cl->cl_nxt = ci->c_clst;
ci->c_clst = cl;
}
}
tfreeblk();
break;
case T_DEFAULT:
/* find the stack entry for the innermost switch statement */
for (ci = cstk; ci != NULL && !ci->c_switch; ci = ci->c_nxt) ;
if (ci == NULL) {
/* default outside switch */
error(201);
} else if (ci->c_default) {
/* duplicate default in switch */
error(202);
} else {
if (reached && !ftflg) {
if (hflag)
/* fallthrough on default statement */
warning(284);
}
ci->c_default = 1;
}
break;
};
reached = 1;
}
/*
* T_IF T_LPARN expr T_RPARN
*/
void
if1(tn)
tnode_t *tn;
{
if (tn != NULL)
tn = cconv(tn);
if (tn != NULL)
tn = promote(NOOP, 0, tn);
expr(tn, 0, 1);
pushctrl(T_IF);
}
/*
* if_without_else
* if_without_else T_ELSE
*/
void
if2()
{
cstk->c_rchif = reached ? 1 : 0;
reached = 1;
}
/*
* if_without_else
* if_without_else T_ELSE stmnt
*/
void
if3(els)
int els;
{
if (els) {
reached |= cstk->c_rchif;
} else {
reached = 1;
}
popctrl(T_IF);
}
/*
* T_SWITCH T_LPARN expr T_RPARN
*/
void
switch1(tn)
tnode_t *tn;
{
tspec_t t;
type_t *tp;
if (tn != NULL)
tn = cconv(tn);
if (tn != NULL)
tn = promote(NOOP, 0, tn);
if (tn != NULL && !isityp(tn->tn_type->t_tspec)) {
/* switch expression must have integral type */
error(205);
tn = NULL;
}
if (tn != NULL && tflag) {
t = tn->tn_type->t_tspec;
if (t == LONG || t == ULONG || t == QUAD || t == UQUAD) {
/* switch expr. must be of type `int' in trad. C */
warning(271);
}
}
/*
* Remember the type of the expression. Because its possible
* that (*tp) is allocated on tree memory the type must be
* duplicated. This is not too complicated because it is
* only an integer type.
*/
tp = xcalloc(1, sizeof (type_t));
if (tn != NULL) {
tp->t_tspec = tn->tn_type->t_tspec;
if ((tp->t_isenum = tn->tn_type->t_isenum) != 0)
tp->t_enum = tn->tn_type->t_enum;
} else {
tp->t_tspec = INT;
}
expr(tn, 1, 0);
pushctrl(T_SWITCH);
cstk->c_switch = 1;
cstk->c_swtype = tp;
reached = rchflg = 0;
ftflg = 1;
}
/*
* switch_expr stmnt
*/
void
switch2()
{
int nenum, nclab;
sym_t *esym;
clst_t *cl;
if (cstk->c_swtype == NULL)
lerror("switch2() 1");
/*
* If the switch expression was of type enumeration, count the case
* labels and the number of enumerators. If both counts are not
* equal print a warning.
*/
if (cstk->c_swtype->t_isenum) {
nenum = nclab = 0;
if (cstk->c_swtype->t_enum == NULL)
lerror("switch2() 2");
for (esym = cstk->c_swtype->t_enum->elem;
esym != NULL; esym = esym->s_nxt) {
nenum++;
}
for (cl = cstk->c_clst; cl != NULL; cl = cl->cl_nxt)
nclab++;
if (hflag && eflag && nenum != nclab && !cstk->c_default) {
/* enumeration value(s) not handled in switch */
warning(206);
}
}
if (cstk->c_break) {
/*
* end of switch alway reached (c_break is only set if the
* break statement can be reached).
*/
reached = 1;
} else if (!cstk->c_default &&
(!hflag || !cstk->c_swtype->t_isenum || nenum != nclab)) {
/*
* there are possible values which are not handled in
* switch
*/
reached = 1;
} /*
* otherwise the end of the switch expression is reached
* if the end of the last statement inside it is reached.
*/
popctrl(T_SWITCH);
}
/*
* T_WHILE T_LPARN expr T_RPARN
*/
void
while1(tn)
tnode_t *tn;
{
if (!reached) {
/* loop not entered at top */
warning(207);
reached = 1;
}
if (tn != NULL)
tn = cconv(tn);
if (tn != NULL)
tn = promote(NOOP, 0, tn);
if (tn != NULL && !issclt(tn->tn_type->t_tspec)) {
/* controlling expressions must have scalar type */
error(204);
tn = NULL;
}
pushctrl(T_WHILE);
cstk->c_loop = 1;
if (tn != NULL && tn->tn_op == CON) {
if (isityp(tn->tn_type->t_tspec)) {
cstk->c_infinite = tn->tn_val->v_quad != 0;
} else {
cstk->c_infinite = tn->tn_val->v_ldbl != 0.0;
}
}
expr(tn, 0, 1);
}
/*
* while_expr stmnt
* while_expr error
*/
void
while2()
{
/*
* The end of the loop can be reached if it is no endless loop
* or there was a break statement which was reached.
*/
reached = !cstk->c_infinite || cstk->c_break;
rchflg = 0;
popctrl(T_WHILE);
}
/*
* T_DO
*/
void
do1()
{
if (!reached) {
/* loop not entered at top */
warning(207);
reached = 1;
}
pushctrl(T_DO);
cstk->c_loop = 1;
}
/*
* do stmnt do_while_expr
* do error
*/
void
do2(tn)
tnode_t *tn;
{
/*
* If there was a continue statement the expression controlling the
* loop is reached.
*/
if (cstk->c_cont)
reached = 1;
if (tn != NULL)
tn = cconv(tn);
if (tn != NULL)
tn = promote(NOOP, 0, tn);
if (tn != NULL && !issclt(tn->tn_type->t_tspec)) {
/* controlling expressions must have scalar type */
error(204);
tn = NULL;
}
if (tn != NULL && tn->tn_op == CON) {
if (isityp(tn->tn_type->t_tspec)) {
cstk->c_infinite = tn->tn_val->v_quad != 0;
} else {
cstk->c_infinite = tn->tn_val->v_ldbl != 0.0;
}
}
expr(tn, 0, 1);
/*
* The end of the loop is only reached if it is no endless loop
* or there was a break statement which could be reached.
*/
reached = !cstk->c_infinite || cstk->c_break;
rchflg = 0;
popctrl(T_DO);
}
/*
* T_FOR T_LPARN opt_expr T_SEMI opt_expr T_SEMI opt_expr T_RPARN
*/
void
for1(tn1, tn2, tn3)
tnode_t *tn1, *tn2, *tn3;
{
/*
* If there is no initialisation expression it is possible that
* it is intended not to enter the loop at top.
*/
if (tn1 != NULL && !reached) {
/* loop not entered at top */
warning(207);
reached = 1;
}
pushctrl(T_FOR);
cstk->c_loop = 1;
/*
* Store the tree memory for the reinitialisation expression.
* Also remember this expression itself. We must check it at
* the end of the loop to get "used but not set" warnings correct.
*/
cstk->c_fexprm = tsave();
cstk->c_f3expr = tn3;
STRUCT_ASSIGN(cstk->c_fpos, curr_pos);
STRUCT_ASSIGN(cstk->c_cfpos, csrc_pos);
if (tn1 != NULL)
expr(tn1, 0, 0);
if (tn2 != NULL)
tn2 = cconv(tn2);
if (tn2 != NULL)
tn2 = promote(NOOP, 0, tn2);
if (tn2 != NULL && !issclt(tn2->tn_type->t_tspec)) {
/* controlling expressions must have scalar type */
error(204);
tn2 = NULL;
}
if (tn2 != NULL)
expr(tn2, 0, 1);
if (tn2 == NULL) {
cstk->c_infinite = 1;
} else if (tn2->tn_op == CON) {
if (isityp(tn2->tn_type->t_tspec)) {
cstk->c_infinite = tn2->tn_val->v_quad != 0;
} else {
cstk->c_infinite = tn2->tn_val->v_ldbl != 0.0;
}
}
/* Checking the reinitialisation expression is done in for2() */
reached = 1;
}
/*
* for_exprs stmnt
* for_exprs error
*/
void
for2()
{
pos_t cpos, cspos;
tnode_t *tn3;
if (cstk->c_cont)
reached = 1;
STRUCT_ASSIGN(cpos, curr_pos);
STRUCT_ASSIGN(cspos, csrc_pos);
/* Restore the tree memory for the reinitialisation expression */
trestor(cstk->c_fexprm);
tn3 = cstk->c_f3expr;
STRUCT_ASSIGN(curr_pos, cstk->c_fpos);
STRUCT_ASSIGN(csrc_pos, cstk->c_cfpos);
/* simply "statement not reached" would be confusing */
if (!reached && !rchflg) {
/* end-of-loop code not reached */
warning(223);
reached = 1;
}
if (tn3 != NULL) {
expr(tn3, 0, 0);
} else {
tfreeblk();
}
STRUCT_ASSIGN(curr_pos, cpos);
STRUCT_ASSIGN(csrc_pos, cspos);
/* An endless loop without break will never terminate */
reached = cstk->c_break || !cstk->c_infinite;
rchflg = 0;
popctrl(T_FOR);
}
/*
* T_GOTO identifier T_SEMI
* T_GOTO error T_SEMI
*/
void
dogoto(lab)
sym_t *lab;
{
setuflg(lab, 0, 0);
chkreach();
reached = rchflg = 0;
}
/*
* T_BREAK T_SEMI
*/
void
dobreak()
{
cstk_t *ci;
ci = cstk;
while (ci != NULL && !ci->c_loop && !ci->c_switch)
ci = ci->c_nxt;
if (ci == NULL) {
/* break outside loop or switch */
error(208);
} else {
if (reached)
ci->c_break = 1;
}
if (bflag)
chkreach();
reached = rchflg = 0;
}
/*
* T_CONTINUE T_SEMI
*/
void
docont()
{
cstk_t *ci;
for (ci = cstk; ci != NULL && !ci->c_loop; ci = ci->c_nxt) ;
if (ci == NULL) {
/* continue outside loop */
error(209);
} else {
ci->c_cont = 1;
}
chkreach();
reached = rchflg = 0;
}
/*
* T_RETURN T_SEMI
* T_RETURN expr T_SEMI
*/
void
doreturn(tn)
tnode_t *tn;
{
tnode_t *ln, *rn;
cstk_t *ci;
op_t op;
for (ci = cstk; ci->c_nxt != NULL; ci = ci->c_nxt) ;
if (tn != NULL) {
ci->c_retval = 1;
} else {
ci->c_noretval = 1;
}
if (tn != NULL && funcsym->s_type->t_subt->t_tspec == VOID) {
/* void function %s cannot return value */
error(213, funcsym->s_name);
tfreeblk();
tn = NULL;
} else if (tn == NULL && funcsym->s_type->t_subt->t_tspec != VOID) {
/*
* Assume that the function has a return value only if it
* is explicitly declared.
*/
if (!funcsym->s_rimpl)
/* function %s expects to return value */
warning(214, funcsym->s_name);
}
if (tn != NULL) {
/* Create a temporary node for the left side */
ln = tgetblk(sizeof (tnode_t));
ln->tn_op = NAME;
ln->tn_type = tduptyp(funcsym->s_type->t_subt);
ln->tn_type->t_const = 0;
ln->tn_lvalue = 1;
ln->tn_sym = funcsym; /* better than nothing */
tn = build(RETURN, ln, tn);
if (tn != NULL) {
rn = tn->tn_right;
while ((op = rn->tn_op) == CVT || op == PLUS)
rn = rn->tn_left;
if (rn->tn_op == AMPER && rn->tn_left->tn_op == NAME &&
rn->tn_left->tn_sym->s_scl == AUTO) {
/* %s returns pointer to automatic object */
warning(302, funcsym->s_name);
}
}
expr(tn, 1, 0);
} else {
chkreach();
}
reached = rchflg = 0;
}
/*
* Do some cleanup after a global declaration or definition.
* Especially remove informations about unused lint comments.
*/
void
glclup(silent)
int silent;
{
pos_t cpos;
STRUCT_ASSIGN(cpos, curr_pos);
if (nargusg != -1) {
if (!silent) {
STRUCT_ASSIGN(curr_pos, aupos);
/* must precede function definition: %s */
warning(282, "ARGSUSED");
}
nargusg = -1;
}
if (nvararg != -1) {
if (!silent) {
STRUCT_ASSIGN(curr_pos, vapos);
/* must precede function definition: %s */
warning(282, "VARARGS");
}
nvararg = -1;
}
if (prflstrg != -1) {
if (!silent) {
STRUCT_ASSIGN(curr_pos, prflpos);
/* must precede function definition: %s */
warning(282, "PRINTFLIKE");
}
prflstrg = -1;
}
if (scflstrg != -1) {
if (!silent) {
STRUCT_ASSIGN(curr_pos, scflpos);
/* must precede function definition: %s */
warning(282, "SCANFLIKE");
}
scflstrg = -1;
}
STRUCT_ASSIGN(curr_pos, cpos);
dcs->d_asm = 0;
}
/*
* ARGSUSED comment
*
* Only the first n arguments of the following function are checked
* for usage. A missing argument is taken to be 0.
*/
void
argsused(n)
int n;
{
if (n == -1)
n = 0;
if (dcs->d_ctx != EXTERN) {
/* must be outside function: ** %s ** */
warning(280, "ARGSUSED");
return;
}
if (nargusg != -1) {
/* duplicate use of ** %s ** */
warning(281, "ARGSUSED");
}
nargusg = n;
STRUCT_ASSIGN(aupos, curr_pos);
}
/*
* VARARGS comment
*
* Makes that lint2 checks only the first n arguments for compatibility
* to the function definition. A missing argument is taken to be 0.
*/
void
varargs(n)
int n;
{
if (n == -1)
n = 0;
if (dcs->d_ctx != EXTERN) {
/* must be outside function: ** %s ** */
warning(280, "VARARGS");
return;
}
if (nvararg != -1) {
/* duplicate use of ** %s ** */
warning(281, "VARARGS");
}
nvararg = n;
STRUCT_ASSIGN(vapos, curr_pos);
}
/*
* PRINTFLIKE comment
*
* Check all arguments until the (n-1)-th as usual. The n-th argument is
* used the check the types of remaining arguments.
*/
void
printflike(n)
int n;
{
if (n == -1)
n = 0;
if (dcs->d_ctx != EXTERN) {
/* must be outside function: ** %s ** */
warning(280, "PRINTFLIKE");
return;
}
if (prflstrg != -1) {
/* duplicate use of ** %s ** */
warning(281, "PRINTFLIKE");
}
prflstrg = n;
STRUCT_ASSIGN(prflpos, curr_pos);
}
/*
* SCANFLIKE comment
*
* Check all arguments until the (n-1)-th as usual. The n-th argument is
* used the check the types of remaining arguments.
*/
void
scanflike(n)
int n;
{
if (n == -1)
n = 0;
if (dcs->d_ctx != EXTERN) {
/* must be outside function: ** %s ** */
warning(280, "SCANFLIKE");
return;
}
if (scflstrg != -1) {
/* duplicate use of ** %s ** */
warning(281, "SCANFLIKE");
}
scflstrg = n;
STRUCT_ASSIGN(scflpos, curr_pos);
}
/*
* Set the linenumber for a CONSTCOND comment. At this and the following
* line no warnings about constants in conditional contexts are printed.
*/
/* ARGSUSED */
void
constcond(n)
int n;
{
ccflg = 1;
}
/*
* Suppress printing of "fallthrough on ..." warnings until next
* statement.
*/
/* ARGSUSED */
void
fallthru(n)
int n;
{
ftflg = 1;
}
/*
* Stop warnings about statements which cannot be reached. Also tells lint
* that the following statements cannot be reached (e.g. after exit()).
*/
/* ARGSUSED */
void
notreach(n)
int n;
{
reached = 0;
rchflg = 1;
}
/* ARGSUSED */
void
lintlib(n)
int n;
{
if (dcs->d_ctx != EXTERN) {
/* must be outside function: ** %s ** */
warning(280, "LINTLIBRARY");
return;
}
llibflg = 1;
vflag = 0;
}
/*
* Suppress most warnings at the current and the following line.
*/
/* ARGSUSED */
void
linted(n)
int n;
{
nowarn = 1;
}
/*
* PROTOTLIB in conjunction with LINTLIBRARY can be used to handle
* prototypes like function definitions. This is done if the argument
* to PROTOLIB is nonzero. Otherwise prototypes are handled normaly.
*/
void
protolib(n)
int n;
{
if (dcs->d_ctx != EXTERN) {
/* must be outside function: ** %s ** */
warning(280, "PROTOLIB");
return;
}
plibflg = n == 0 ? 0 : 1;
}
/*
* Set quadflg to nonzero which means that the next statement/declaration
* may use "long long" without an error or warning.
*/
/* ARGSUSED */
void
longlong(n)
int n;
{
quadflg = 1;
}
diff --git a/usr.bin/xlint/lint1/scan.l b/usr.bin/xlint/lint1/scan.l
index 53f0083e3078..3306dec3a247 100644
--- a/usr.bin/xlint/lint1/scan.l
+++ b/usr.bin/xlint/lint1/scan.l
@@ -1,1425 +1,1425 @@
%{
/* $NetBSD: scan.l,v 1.8 1995/10/23 13:38:51 jpo Exp $ */
/*
* Copyright (c) 1994, 1995 Jochen Pohl
* All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Jochen Pohl for
* The NetBSD Project.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef lint
static char rcsid[] = "$NetBSD: scan.l,v 1.8 1995/10/23 13:38:51 jpo Exp $";
#endif
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <float.h>
#include <ctype.h>
#include <errno.h>
#include <err.h>
#include "lint1.h"
-#include "y.tab.h"
+#include "cgram.tab.h"
#define CHAR_MASK (~(~0 << CHAR_BIT))
/* XXX declaration of strtouq() is missing in stdlib.h ? */
extern u_quad_t strtouq __P((const char *, char **, int));
/* Current position (its also updated when an included file is parsed) */
pos_t curr_pos = { 1, "" };
/*
* Current position in C source (not updated when an included file is
* parsed).
*/
pos_t csrc_pos = { 1, "" };
static void incline __P((void));
static void badchar __P((int));
static sbuf_t *allocsb __P((void));
static void freesb __P((sbuf_t *));
static int inpc __P((void));
static int hash __P((const char *));
static sym_t *search __P((sbuf_t *));
static int name __P((void));
static int keyw __P((sym_t *));
static int icon __P((int));
static int fcon __P((void));
static int operator __P((int, op_t));
static int ccon __P((void));
static int wccon __P((void));
static int getescc __P((int));
static void directive __P((void));
static void comment __P((void));
static int string __P((void));
static int wcstrg __P((void));
%}
L [_A-Za-z]
D [0-9]
NZD [1-9]
OD [0-7]
HD [0-9A-Fa-f]
EX ([eE][+-]?[0-9]+)
%%
{L}({L}|{D})* return (name());
0{OD}*[lLuU]* return (icon(8));
{NZD}{D}*[lLuU]* return (icon(10));
0[xX]{HD}+[lLuU]* return (icon(16));
{D}+\.{D}*{EX}?[fFlL]? |
{D}+{EX}[fFlL]? |
\.{D}+{EX}?[fFlL]? return (fcon());
"=" return (operator(T_ASSIGN, ASSIGN));
"*=" return (operator(T_OPASS, MULASS));
"/=" return (operator(T_OPASS, DIVASS));
"%=" return (operator(T_OPASS, MODASS));
"+=" return (operator(T_OPASS, ADDASS));
"-=" return (operator(T_OPASS, SUBASS));
"<<=" return (operator(T_OPASS, SHLASS));
">>=" return (operator(T_OPASS, SHRASS));
"&=" return (operator(T_OPASS, ANDASS));
"^=" return (operator(T_OPASS, XORASS));
"|=" return (operator(T_OPASS, ORASS));
"||" return (operator(T_LOGOR, LOGOR));
"&&" return (operator(T_LOGAND, LOGAND));
"|" return (operator(T_OR, OR));
"&" return (operator(T_AND, AND));
"^" return (operator(T_XOR, XOR));
"==" return (operator(T_EQOP, EQ));
"!=" return (operator(T_EQOP, NE));
"<" return (operator(T_RELOP, LT));
">" return (operator(T_RELOP, GT));
"<=" return (operator(T_RELOP, LE));
">=" return (operator(T_RELOP, GE));
"<<" return (operator(T_SHFTOP, SHL));
">>" return (operator(T_SHFTOP, SHR));
"++" return (operator(T_INCDEC, INC));
"--" return (operator(T_INCDEC, DEC));
"->" return (operator(T_STROP, ARROW));
"." return (operator(T_STROP, POINT));
"+" return (operator(T_ADDOP, PLUS));
"-" return (operator(T_ADDOP, MINUS));
"*" return (operator(T_MULT, MULT));
"/" return (operator(T_DIVOP, DIV));
"%" return (operator(T_DIVOP, MOD));
"!" return (operator(T_UNOP, NOT));
"~" return (operator(T_UNOP, COMPL));
"\"" return (string());
"L\"" return (wcstrg());
";" return (T_SEMI);
"{" return (T_LBRACE);
"}" return (T_RBRACE);
"," return (T_COMMA);
":" return (T_COLON);
"?" return (T_QUEST);
"[" return (T_LBRACK);
"]" return (T_RBRACK);
"(" return (T_LPARN);
")" return (T_RPARN);
"..." return (T_ELLIPSE);
"'" return (ccon());
"L'" return (wccon());
^#.*$ directive();
\n incline();
\t|" "|\f|\v ;
"/*" comment();
. badchar(yytext[0]);
%%
static void
incline()
{
curr_pos.p_line++;
if (curr_pos.p_file == csrc_pos.p_file)
csrc_pos.p_line++;
}
static void
badchar(c)
int c;
{
/* unknown character \%o */
error(250, c);
}
/*
* Keywords.
* During initialisation they are written to the symbol table.
*/
static struct kwtab {
const char *kw_name; /* keyword */
int kw_token; /* token returned by yylex() */
scl_t kw_scl; /* storage class if kw_token T_SCLASS */
tspec_t kw_tspec; /* type spec. if kw_token T_TYPE or T_SOU */
tqual_t kw_tqual; /* type qual. fi kw_token T_QUAL */
u_int kw_stdc : 1; /* STDC keyword */
u_int kw_gcc : 1; /* GCC keyword */
} kwtab[] = {
{ "asm", T_ASM, 0, 0, 0, 0, 1 },
{ "__asm", T_ASM, 0, 0, 0, 0, 0 },
{ "__asm__", T_ASM, 0, 0, 0, 0, 0 },
{ "auto", T_SCLASS, AUTO, 0, 0, 0, 0 },
{ "break", T_BREAK, 0, 0, 0, 0, 0 },
{ "case", T_CASE, 0, 0, 0, 0, 0 },
{ "char", T_TYPE, 0, CHAR, 0, 0, 0 },
{ "const", T_QUAL, 0, 0, CONST, 1, 0 },
{ "__const__", T_QUAL, 0, 0, CONST, 0, 0 },
{ "__const", T_QUAL, 0, 0, CONST, 0, 0 },
{ "continue", T_CONTINUE, 0, 0, 0, 0, 0 },
{ "default", T_DEFAULT, 0, 0, 0, 0, 0 },
{ "do", T_DO, 0, 0, 0, 0, 0 },
{ "double", T_TYPE, 0, DOUBLE, 0, 0, 0 },
{ "else", T_ELSE, 0, 0, 0, 0, 0 },
{ "enum", T_ENUM, 0, 0, 0, 0, 0 },
{ "extern", T_SCLASS, EXTERN, 0, 0, 0, 0 },
{ "float", T_TYPE, 0, FLOAT, 0, 0, 0 },
{ "for", T_FOR, 0, 0, 0, 0, 0 },
{ "goto", T_GOTO, 0, 0, 0, 0, 0 },
{ "if", T_IF, 0, 0, 0, 0, 0 },
{ "inline", T_SCLASS, INLINE, 0, 0, 0, 1 },
{ "__inline__", T_SCLASS, INLINE, 0, 0, 0, 0 },
{ "__inline", T_SCLASS, INLINE, 0, 0, 0, 0 },
{ "int", T_TYPE, 0, INT, 0, 0, 0 },
{ "long", T_TYPE, 0, LONG, 0, 0, 0 },
{ "register", T_SCLASS, REG, 0, 0, 0, 0 },
{ "return", T_RETURN, 0, 0, 0, 0, 0 },
{ "short", T_TYPE, 0, SHORT, 0, 0, 0 },
{ "signed", T_TYPE, 0, SIGNED, 0, 1, 0 },
{ "__signed__", T_TYPE, 0, SIGNED, 0, 0, 0 },
{ "__signed", T_TYPE, 0, SIGNED, 0, 0, 0 },
{ "sizeof", T_SIZEOF, 0, 0, 0, 0, 0 },
{ "static", T_SCLASS, STATIC, 0, 0, 0, 0 },
{ "struct", T_SOU, 0, STRUCT, 0, 0, 0 },
{ "switch", T_SWITCH, 0, 0, 0, 0, 0 },
{ "typedef", T_SCLASS, TYPEDEF, 0, 0, 0, 0 },
{ "union", T_SOU, 0, UNION, 0, 0, 0 },
{ "unsigned", T_TYPE, 0, UNSIGN, 0, 0, 0 },
{ "void", T_TYPE, 0, VOID, 0, 0, 0 },
{ "volatile", T_QUAL, 0, 0, VOLATILE, 1, 0 },
{ "__volatile__", T_QUAL, 0, 0, VOLATILE, 0, 0 },
{ "__volatile", T_QUAL, 0, 0, VOLATILE, 0, 0 },
{ "while", T_WHILE, 0, 0, 0, 0, 0 },
{ NULL, 0, 0, 0, 0, 0, 0 }
};
/* Symbol table */
static sym_t *symtab[HSHSIZ1];
/* bit i of the entry with index i is set */
u_quad_t qbmasks[sizeof(u_quad_t) * CHAR_BIT];
/* least significant i bits are set in the entry with index i */
u_quad_t qlmasks[sizeof(u_quad_t) * CHAR_BIT + 1];
/* least significant i bits are not set in the entry with index i */
u_quad_t qumasks[sizeof(u_quad_t) * CHAR_BIT + 1];
/* free list for sbuf structures */
static sbuf_t *sbfrlst;
/* Typ of next expected symbol */
symt_t symtyp;
/*
* All keywords are written to the symbol table. This saves us looking
* in a extra table for each name we found.
*/
void
initscan()
{
struct kwtab *kw;
sym_t *sym;
int h, i;
u_quad_t uq;
for (kw = kwtab; kw->kw_name != NULL; kw++) {
if (kw->kw_stdc && tflag)
continue;
if (kw->kw_gcc && !gflag)
continue;
sym = getblk(sizeof (sym_t));
sym->s_name = kw->kw_name;
sym->s_keyw = 1;
sym->s_value.v_quad = kw->kw_token;
if (kw->kw_token == T_TYPE || kw->kw_token == T_SOU) {
sym->s_tspec = kw->kw_tspec;
} else if (kw->kw_token == T_SCLASS) {
sym->s_scl = kw->kw_scl;
} else if (kw->kw_token == T_QUAL) {
sym->s_tqual = kw->kw_tqual;
}
h = hash(sym->s_name);
if ((sym->s_link = symtab[h]) != NULL)
symtab[h]->s_rlink = &sym->s_link;
(symtab[h] = sym)->s_rlink = &symtab[h];
}
/* initialize bit-masks for quads */
for (i = 0; i < sizeof (u_quad_t) * CHAR_BIT; i++) {
qbmasks[i] = (u_quad_t)1 << i;
uq = ~(u_quad_t)0 << i;
qumasks[i] = uq;
qlmasks[i] = ~uq;
}
qumasks[i] = 0;
qlmasks[i] = ~(u_quad_t)0;
}
/*
* Get a free sbuf structure, if possible from the free list
*/
static sbuf_t *
allocsb()
{
sbuf_t *sb;
if ((sb = sbfrlst) != NULL) {
sbfrlst = sb->sb_nxt;
} else {
sb = xmalloc(sizeof (sbuf_t));
}
(void)memset(sb, 0, sizeof (sb));
return (sb);
}
/*
* Put a sbuf structure to the free list
*/
static void
freesb(sb)
sbuf_t *sb;
{
sb->sb_nxt = sbfrlst;
sbfrlst = sb;
}
/*
* Read a character and ensure that it is positive (except EOF).
* Increment line count(s) if necessary.
*/
static int
inpc()
{
int c;
if ((c = input()) != EOF && (c &= CHAR_MASK) == '\n')
incline();
return (c);
}
static int
hash(s)
const char *s;
{
u_int v;
const u_char *us;
v = 0;
for (us = (const u_char *)s; *us != '\0'; us++) {
v = (v << sizeof (v)) + *us;
v ^= v >> (sizeof (v) * CHAR_BIT - sizeof (v));
}
return (v % HSHSIZ1);
}
/*
* Lex has found a letter followed by zero or more letters or digits.
* It looks for a symbol in the symbol table with the same name. This
* symbol must either be a keyword or a symbol of the type required by
* symtyp (label, member, tag, ...).
*
* If it is a keyword, the token is returned. In some cases it is described
* more deeply by data written to yylval.
*
* If it is a symbol, T_NAME is returned and the pointer to a sbuf struct
* is stored in yylval. This struct contains the name of the symbol, it's
* length and hash value. If there is already a symbol of the same name
* and type in the symbol table, the sbuf struct also contains a pointer
* to the symbol table entry.
*/
static int
name()
{
char *s;
sbuf_t *sb;
sym_t *sym;
int tok;
sb = allocsb();
sb->sb_name = yytext;
sb->sb_len = yyleng;
sb->sb_hash = hash(yytext);
if ((sym = search(sb)) != NULL && sym->s_keyw) {
freesb(sb);
return (keyw(sym));
}
sb->sb_sym = sym;
if (sym != NULL) {
if (blklev < sym->s_blklev)
lerror("name() 1");
sb->sb_name = sym->s_name;
sb->sb_len = strlen(sym->s_name);
tok = sym->s_scl == TYPEDEF ? T_TYPENAME : T_NAME;
} else {
s = getblk(yyleng + 1);
(void)memcpy(s, yytext, yyleng + 1);
sb->sb_name = s;
sb->sb_len = yyleng;
tok = T_NAME;
}
yylval.y_sb = sb;
return (tok);
}
static sym_t *
search(sb)
sbuf_t *sb;
{
sym_t *sym;
for (sym = symtab[sb->sb_hash]; sym != NULL; sym = sym->s_link) {
if (strcmp(sym->s_name, sb->sb_name) == 0) {
if (sym->s_keyw || sym->s_kind == symtyp)
return (sym);
}
}
return (NULL);
}
static int
keyw(sym)
sym_t *sym;
{
int t;
if ((t = (int)sym->s_value.v_quad) == T_SCLASS) {
yylval.y_scl = sym->s_scl;
} else if (t == T_TYPE || t == T_SOU) {
yylval.y_tspec = sym->s_tspec;
} else if (t == T_QUAL) {
yylval.y_tqual = sym->s_tqual;
}
return (t);
}
/*
* Convert a string representing an integer into internal representation.
* The value is returned in yylval. icon() (and yylex()) returns T_CON.
*/
static int
icon(base)
int base;
{
int l_suffix, u_suffix;
int len;
const char *cp;
char c, *eptr;
tspec_t typ;
u_long ul;
u_quad_t uq;
int ansiu;
static tspec_t contypes[2][3] = {
{ INT, LONG, QUAD },
{ UINT, ULONG, UQUAD }
};
cp = yytext;
len = yyleng;
/* skip 0x */
if (base == 16) {
cp += 2;
len -= 2;
}
/* read suffixes */
l_suffix = u_suffix = 0;
for ( ; ; ) {
if ((c = cp[len - 1]) == 'l' || c == 'L') {
l_suffix++;
} else if (c == 'u' || c == 'U') {
u_suffix++;
} else {
break;
}
len--;
}
if (l_suffix > 2 || u_suffix > 1) {
/* malformed integer constant */
warning(251);
if (l_suffix > 2)
l_suffix = 2;
if (u_suffix > 1)
u_suffix = 1;
}
if (tflag && u_suffix != 0) {
/* suffix U is illegal in traditional C */
warning(97);
}
typ = contypes[u_suffix][l_suffix];
errno = 0;
if (l_suffix < 2) {
ul = strtoul(cp, &eptr, base);
} else {
uq = strtouq(cp, &eptr, base);
}
if (eptr != cp + len)
lerror("icon() 1");
if (errno != 0)
/* integer constant out of range */
warning(252);
/*
* If the value is to big for the current type, we must choose
* another type.
*/
ansiu = 0;
switch (typ) {
case INT:
if (ul <= INT_MAX) {
/* ok */
} else if (ul <= (unsigned)UINT_MAX && base != 10) {
typ = UINT;
} else if (ul <= LONG_MAX) {
typ = LONG;
} else {
typ = ULONG;
}
if (typ == UINT || typ == ULONG) {
if (tflag) {
typ = LONG;
} else if (!sflag) {
/*
* Remember that the constant is unsigned
* only in ANSI C
*/
ansiu = 1;
}
}
break;
case UINT:
if (ul > (u_int)UINT_MAX)
typ = ULONG;
break;
case LONG:
if (ul > LONG_MAX && !tflag) {
typ = ULONG;
if (!sflag)
ansiu = 1;
}
break;
case QUAD:
if (uq > QUAD_MAX && !tflag) {
typ = UQUAD;
if (!sflag)
ansiu = 1;
}
break;
/* LINTED (enumeration values not handled in switch) */
}
if (typ != QUAD && typ != UQUAD) {
if (isutyp(typ)) {
uq = ul;
} else {
uq = (quad_t)(long)ul;
}
}
uq = (u_quad_t)xsign((quad_t)uq, typ, -1);
(yylval.y_val = xcalloc(1, sizeof (val_t)))->v_tspec = typ;
yylval.y_val->v_ansiu = ansiu;
yylval.y_val->v_quad = (quad_t)uq;
return (T_CON);
}
/*
* Returns 1 if t is a signed type and the value is negative.
*
* len is the number of significant bits. If len is -1, len is set
* to the width of type t.
*/
int
sign(q, t, len)
quad_t q;
tspec_t t;
int len;
{
if (t == PTR || isutyp(t))
return (0);
return (msb(q, t, len));
}
int
msb(q, t, len)
quad_t q;
tspec_t t;
int len;
{
if (len <= 0)
len = size(t);
return ((q & qbmasks[len - 1]) != 0);
}
/*
* Extends the sign of q.
*/
quad_t
xsign(q, t, len)
quad_t q;
tspec_t t;
int len;
{
if (len <= 0)
len = size(t);
if (t == PTR || isutyp(t) || !sign(q, t, len)) {
q &= qlmasks[len];
} else {
q |= qumasks[len];
}
return (q);
}
/*
* Convert a string representing a floating point value into its interal
* representation. Type and value are returned in yylval. fcon()
* (and yylex()) returns T_CON.
* XXX Currently it is not possible to convert constants of type
* long double which are greater then DBL_MAX.
*/
static int
fcon()
{
const char *cp;
int len;
tspec_t typ;
char c, *eptr;
double d;
float f;
cp = yytext;
len = yyleng;
if ((c = cp[len - 1]) == 'f' || c == 'F') {
typ = FLOAT;
len--;
} else if (c == 'l' || c == 'L') {
typ = LDOUBLE;
len--;
} else {
typ = DOUBLE;
}
if (tflag && typ != DOUBLE) {
/* suffixes F and L are illegal in traditional C */
warning(98);
}
errno = 0;
d = strtod(cp, &eptr);
if (eptr != cp + len)
lerror("fcon() 1");
if (errno != 0)
/* floating-point constant out of range */
warning(248);
if (typ == FLOAT) {
f = (float)d;
if (isinf(f)) {
/* floating-point constant out of range */
warning(248);
f = f > 0 ? FLT_MAX : -FLT_MAX;
}
}
(yylval.y_val = xcalloc(1, sizeof (val_t)))->v_tspec = typ;
if (typ == FLOAT) {
yylval.y_val->v_ldbl = f;
} else {
yylval.y_val->v_ldbl = d;
}
return (T_CON);
}
static int
operator(t, o)
int t;
op_t o;
{
yylval.y_op = o;
return (t);
}
/*
* Called if lex found a leading \'.
*/
static int
ccon()
{
int n, val, c;
char cv;
n = 0;
val = 0;
while ((c = getescc('\'')) >= 0) {
val = (val << CHAR_BIT) + c;
n++;
}
if (c == -2) {
/* unterminated character constant */
error(253);
} else {
if (n > sizeof (int) || (n > 1 && (pflag || hflag))) {
/* too many characters in character constant */
error(71);
} else if (n > 1) {
/* multi-character character constant */
warning(294);
} else if (n == 0) {
/* empty character constant */
error(73);
}
}
if (n == 1) {
cv = (char)val;
val = cv;
}
yylval.y_val = xcalloc(1, sizeof (val_t));
yylval.y_val->v_tspec = INT;
yylval.y_val->v_quad = val;
return (T_CON);
}
/*
* Called if lex found a leading L\'
*/
static int
wccon()
{
static char buf[MB_LEN_MAX + 1];
int i, c;
wchar_t wc;
i = 0;
while ((c = getescc('\'')) >= 0) {
if (i < MB_CUR_MAX)
buf[i] = (char)c;
i++;
}
wc = 0;
if (c == -2) {
/* unterminated character constant */
error(253);
} else if (c == 0) {
/* empty character constant */
error(73);
} else {
if (i > MB_CUR_MAX) {
i = MB_CUR_MAX;
/* too many characters in character constant */
error(71);
} else {
buf[i] = '\0';
(void)mbtowc(NULL, NULL, 0);
if (mbtowc(&wc, buf, MB_CUR_MAX) < 0)
/* invalid multibyte character */
error(291);
}
}
yylval.y_val = xcalloc(1, sizeof (val_t));
yylval.y_val->v_tspec = WCHAR;
yylval.y_val->v_quad = wc;
return (T_CON);
}
/*
* Read a character which is part of a character constant or of a string
* and handle escapes.
*
* The Argument is the character which delimits the character constant or
* string.
*
* Returns -1 if the end of the character constant or string is reached,
* -2 if the EOF is reached, and the charachter otherwise.
*/
static int
getescc(d)
int d;
{
static int pbc = -1;
int n, c, v;
if (pbc == -1) {
c = inpc();
} else {
c = pbc;
pbc = -1;
}
if (c == d)
return (-1);
switch (c) {
case '\n':
/* newline in string or char constant */
error(254);
return (-2);
case EOF:
return (-2);
case '\\':
switch (c = inpc()) {
case '"':
if (tflag && d == '\'')
/* \" inside character constant undef. ... */
warning(262);
return ('"');
case '\'':
return ('\'');
case '?':
if (tflag)
/* \? undefined in traditional C */
warning(263);
return ('?');
case '\\':
return ('\\');
case 'a':
if (tflag)
/* \a undefined in traditional C */
warning(81);
#ifdef __STDC__
return ('\a');
#else
return ('\007');
#endif
case 'b':
return ('\b');
case 'f':
return ('\f');
case 'n':
return ('\n');
case 'r':
return ('\r');
case 't':
return ('\t');
case 'v':
if (tflag)
/* \v undefined in traditional C */
warning(264);
#ifdef __STDC__
return ('\v');
#else
return ('\013');
#endif
case '8': case '9':
/* bad octal digit %c */
warning(77, c);
/* FALLTHROUGH */
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
n = 3;
v = 0;
do {
v = (v << 3) + (c - '0');
c = inpc();
} while (--n && isdigit(c) && (tflag || c <= '7'));
if (tflag && n > 0 && isdigit(c))
/* bad octal digit %c */
warning(77, c);
pbc = c;
if (v > UCHAR_MAX) {
/* character escape does not fit in char. */
warning(76);
v &= CHAR_MASK;
}
return (v);
case 'x':
if (tflag)
/* \x undefined in traditional C */
warning(82);
v = 0;
n = 0;
while ((c = inpc()) >= 0 && isxdigit(c)) {
c = isdigit(c) ?
c - '0' : toupper(c) - 'A' + 10;
v = (v << 4) + c;
if (n >= 0) {
if ((v & ~CHAR_MASK) != 0) {
/* overflow in hex escape */
warning(75);
n = -1;
} else {
n++;
}
}
}
pbc = c;
if (n == 0) {
/* no hex digits follow \x */
error(74);
} if (n == -1) {
v &= CHAR_MASK;
}
return (v);
case '\n':
return (getescc(d));
case EOF:
return (-2);
default:
if (isprint(c)) {
/* dubious escape \%c */
warning(79, c);
} else {
/* dubious escape \%o */
warning(80, c);
}
}
}
return (c);
}
/*
* Called for preprocessor directives. Currently implemented are:
* # lineno
* # lineno "filename"
*/
static void
directive()
{
const char *cp, *fn;
char c, *eptr;
size_t fnl;
long ln;
static int first = 1;
/* Go to first non-whitespace after # */
for (cp = yytext + 1; (c = *cp) == ' ' || c == '\t'; cp++) ;
if (!isdigit(c)) {
error:
/* undefined or invalid # directive */
warning(255);
return;
}
ln = strtol(--cp, &eptr, 10);
if (cp == eptr)
goto error;
if ((c = *(cp = eptr)) != ' ' && c != '\t' && c != '\0')
goto error;
while ((c = *cp++) == ' ' || c == '\t') ;
if (c != '\0') {
if (c != '"')
goto error;
fn = cp;
while ((c = *cp) != '"' && c != '\0')
cp++;
if (c != '"')
goto error;
if ((fnl = cp++ - fn) > PATH_MAX)
goto error;
while ((c = *cp++) == ' ' || c == '\t') ;
#if 0
if (c != '\0')
warning("extra character(s) after directive");
#endif
curr_pos.p_file = fnnalloc(fn, fnl);
/*
* If this is the first directive, the name is the name
* of the C source file as specified at the command line.
* It is written to the output file.
*/
if (first) {
csrc_pos.p_file = curr_pos.p_file;
outsrc(curr_pos.p_file);
first = 0;
}
}
curr_pos.p_line = (int)ln - 1;
if (curr_pos.p_file == csrc_pos.p_file)
csrc_pos.p_line = (int)ln - 1;
}
/*
* Handle lint comments. Following comments are currently understood:
* ARGSUSEDn
* CONSTCOND CONSTANTCOND CONSTANTCONDITION
* FALLTHRU FALLTHROUGH
* LINTLIBRARY
* LINTED NOSTRICT
* LONGLONG
* NOTREACHED
* PRINTFLIKEn
* PROTOLIB
* SCANFLIKEn
* VARARGSn
* If one of this comments is recognized, the arguments, if any, are
* parsed and a function which handles this comment is called.
*/
static void
comment()
{
int c, lc;
static struct {
const char *keywd;
int arg;
void (*func) __P((int));
} keywtab[] = {
{ "ARGSUSED", 1, argsused },
{ "CONSTCOND", 0, constcond },
{ "CONSTANTCOND", 0, constcond },
{ "CONSTANTCONDITION", 0, constcond },
{ "FALLTHRU", 0, fallthru },
{ "FALLTHROUGH", 0, fallthru },
{ "LINTLIBRARY", 0, lintlib },
{ "LINTED", 0, linted },
{ "LONGLONG", 0, longlong },
{ "NOSTRICT", 0, linted },
{ "NOTREACHED", 0, notreach },
{ "PRINTFLIKE", 1, printflike },
{ "PROTOLIB", 1, protolib },
{ "SCANFLIKE", 1, scanflike },
{ "VARARGS", 1, varargs },
};
char keywd[32];
char arg[32];
int l, i, a;
int eoc;
eoc = 0;
/* Skip white spaces after the start of the comment */
while ((c = inpc()) != EOF && isspace(c)) ;
/* Read the potential keyword to keywd */
l = 0;
while (c != EOF && isupper(c) && l < sizeof (keywd) - 1) {
keywd[l++] = (char)c;
c = inpc();
}
keywd[l] = '\0';
/* look for the keyword */
for (i = 0; i < sizeof (keywtab) / sizeof (keywtab[0]); i++) {
if (strcmp(keywtab[i].keywd, keywd) == 0)
break;
}
if (i == sizeof (keywtab) / sizeof (keywtab[0]))
goto skip_rest;
/* skip white spaces after the keyword */
while (c != EOF && isspace(c))
c = inpc();
/* read the argument, if the keyword accepts one and there is one */
l = 0;
if (keywtab[i].arg) {
while (c != EOF && isdigit(c) && l < sizeof (arg) - 1) {
arg[l++] = (char)c;
c = inpc();
}
}
arg[l] = '\0';
a = l != 0 ? atoi(arg) : -1;
/* skip white spaces after the argument */
while (c != EOF && isspace(c))
c = inpc();
if (c != '*' || (c = inpc()) != '/') {
if (keywtab[i].func != linted)
/* extra characters in lint comment */
warning(257);
} else {
/*
* remember that we have already found the end of the
* comment
*/
eoc = 1;
}
if (keywtab[i].func != NULL)
(*keywtab[i].func)(a);
skip_rest:
while (!eoc) {
lc = c;
if ((c = inpc()) == EOF) {
/* unterminated comment */
error(256);
break;
}
if (lc == '*' && c == '/')
eoc = 1;
}
}
/*
* Clear flags for lint comments LINTED, LONGLONG and CONSTCOND.
* clrwflgs() is called after function definitions and global and
* local declarations and definitions. It is also called between
* the controlling expression and the body of control statements
* (if, switch, for, while).
*/
void
clrwflgs()
{
nowarn = 0;
quadflg = 0;
ccflg = 0;
}
/*
* Strings are stored in a dynamically alloceted buffer and passed
* in yylval.y_xstrg to the parser. The parser or the routines called
* by the parser are responsible for freeing this buffer.
*/
static int
string()
{
u_char *s;
int c;
size_t len, max;
strg_t *strg;
s = xmalloc(max = 64);
len = 0;
while ((c = getescc('"')) >= 0) {
/* +1 to reserve space for a trailing NUL character */
if (len + 1 == max)
s = xrealloc(s, max *= 2);
s[len++] = (char)c;
}
s[len] = '\0';
if (c == -2)
/* unterminated string constant */
error(258);
strg = xcalloc(1, sizeof (strg_t));
strg->st_tspec = CHAR;
strg->st_len = len;
strg->st_cp = s;
yylval.y_strg = strg;
return (T_STRING);
}
static int
wcstrg()
{
char *s;
int c, i, n, wi;
size_t len, max, wlen;
wchar_t *ws;
strg_t *strg;
s = xmalloc(max = 64);
len = 0;
while ((c = getescc('"')) >= 0) {
/* +1 to save space for a trailing NUL character */
if (len + 1 >= max)
s = xrealloc(s, max *= 2);
s[len++] = (char)c;
}
s[len] = '\0';
if (c == -2)
/* unterminated string constant */
error(258);
/* get length of wide character string */
(void)mblen(NULL, 0);
for (i = 0, wlen = 0; i < len; i += n, wlen++) {
if ((n = mblen(&s[i], MB_CUR_MAX)) == -1) {
/* invalid multibyte character */
error(291);
break;
}
if (n == 0)
n = 1;
}
ws = xmalloc((wlen + 1) * sizeof (wchar_t));
/* convert from multibyte to wide char */
(void)mbtowc(NULL, NULL, 0);
for (i = 0, wi = 0; i < len; i += n, wi++) {
if ((n = mbtowc(&ws[wi], &s[i], MB_CUR_MAX)) == -1)
break;
if (n == 0)
n = 1;
}
ws[wi] = 0;
free(s);
strg = xcalloc(1, sizeof (strg_t));
strg->st_tspec = WCHAR;
strg->st_len = wlen;
strg->st_wcp = ws;
yylval.y_strg = strg;
return (T_STRING);
}
/*
* As noted above the scanner does not create new symbol table entries
* for symbols it cannot find in the symbol table. This is to avoid
* putting undeclared symbols into the symbol table if a syntax error
* occurs.
*
* getsym() is called as soon as it is probably ok to put the symbol to
* the symbol table. This does not mean that it is not possible that
* symbols are put to the symbol table which are than not completely
* declared due to syntax errors. To avoid too many problems in this
* case symbols get type int in getsym().
*
* XXX calls to getsym() should be delayed until decl1*() is called
*/
sym_t *
getsym(sb)
sbuf_t *sb;
{
dinfo_t *di;
char *s;
sym_t *sym;
sym = sb->sb_sym;
/*
* During member declaration it is possible that name() looked
* for symbols of type FVFT, although it should have looked for
* symbols of type FTAG. Same can happen for labels. Both cases
* are compensated here.
*/
if (symtyp == FMOS || symtyp == FLAB) {
if (sym == NULL || sym->s_kind == FVFT)
sym = search(sb);
}
if (sym != NULL) {
if (sym->s_kind != symtyp)
lerror("storesym() 1");
symtyp = FVFT;
freesb(sb);
return (sym);
}
/* create a new symbol table entry */
/* labels must always be allocated at level 1 (outhermost block) */
if (symtyp == FLAB) {
sym = getlblk(1, sizeof (sym_t));
s = getlblk(1, sb->sb_len + 1);
(void)memcpy(s, sb->sb_name, sb->sb_len + 1);
sym->s_name = s;
sym->s_blklev = 1;
di = dcs;
while (di->d_nxt != NULL && di->d_nxt->d_nxt != NULL)
di = di->d_nxt;
if (di->d_ctx != AUTO)
lerror("storesym() 2");
} else {
sym = getblk(sizeof (sym_t));
sym->s_name = sb->sb_name;
sym->s_blklev = blklev;
di = dcs;
}
STRUCT_ASSIGN(sym->s_dpos, curr_pos);
if ((sym->s_kind = symtyp) != FLAB)
sym->s_type = gettyp(INT);
symtyp = FVFT;
if ((sym->s_link = symtab[sb->sb_hash]) != NULL)
symtab[sb->sb_hash]->s_rlink = &sym->s_link;
(symtab[sb->sb_hash] = sym)->s_rlink = &symtab[sb->sb_hash];
*di->d_ldlsym = sym;
di->d_ldlsym = &sym->s_dlnxt;
freesb(sb);
return (sym);
}
/*
* Remove a symbol forever from the symbol table. s_blklev
* is set to -1 to avoid that the symbol will later be put
* back to the symbol table.
*/
void
rmsym(sym)
sym_t *sym;
{
if ((*sym->s_rlink = sym->s_link) != NULL)
sym->s_link->s_rlink = sym->s_rlink;
sym->s_blklev = -1;
sym->s_link = NULL;
}
/*
* Remove a list of symbols declared at one level from the symbol
* table.
*/
void
rmsyms(syms)
sym_t *syms;
{
sym_t *sym;
for (sym = syms; sym != NULL; sym = sym->s_dlnxt) {
if (sym->s_blklev != -1) {
if ((*sym->s_rlink = sym->s_link) != NULL)
sym->s_link->s_rlink = sym->s_rlink;
sym->s_link = NULL;
sym->s_rlink = NULL;
}
}
}
/*
* Put a symbol into the symbol table
*/
void
inssym(bl, sym)
int bl;
sym_t *sym;
{
int h;
h = hash(sym->s_name);
if ((sym->s_link = symtab[h]) != NULL)
symtab[h]->s_rlink = &sym->s_link;
(symtab[h] = sym)->s_rlink = &symtab[h];
sym->s_blklev = bl;
if (sym->s_link != NULL && sym->s_blklev < sym->s_link->s_blklev)
lerror("inssym()");
}
/*
* Called at level 0 after syntax errors
* Removes all symbols which are not declared at level 0 from the
* symbol table. Also frees all memory which is not associated with
* level 0.
*/
void
cleanup()
{
sym_t *sym, *nsym;
int i;
for (i = 0; i < HSHSIZ1; i++) {
for (sym = symtab[i]; sym != NULL; sym = nsym) {
nsym = sym->s_link;
if (sym->s_blklev >= 1) {
if ((*sym->s_rlink = nsym) != NULL)
nsym->s_rlink = sym->s_rlink;
}
}
}
for (i = mblklev; i > 0; i--)
freelblk(i);
}
/*
* Create a new symbol with the name of an existing symbol.
*/
sym_t *
pushdown(sym)
sym_t *sym;
{
int h;
sym_t *nsym;
h = hash(sym->s_name);
nsym = getblk(sizeof (sym_t));
if (sym->s_blklev > blklev)
lerror("pushdown()");
nsym->s_name = sym->s_name;
STRUCT_ASSIGN(nsym->s_dpos, curr_pos);
nsym->s_kind = sym->s_kind;
nsym->s_blklev = blklev;
if ((nsym->s_link = symtab[h]) != NULL)
symtab[h]->s_rlink = &nsym->s_link;
(symtab[h] = nsym)->s_rlink = &symtab[h];
*dcs->d_ldlsym = nsym;
dcs->d_ldlsym = &nsym->s_dlnxt;
return (nsym);
}
/*
* Free any dynamically allocated memory referenced by
* the value stack or yylval.
* The type of information in yylval is described by tok.
*/
void
freeyyv(sp, tok)
void *sp;
int tok;
{
if (tok == T_NAME || tok == T_TYPENAME) {
sbuf_t *sb = *(sbuf_t **)sp;
freesb(sb);
} else if (tok == T_CON) {
val_t *val = *(val_t **)sp;
free(val);
} else if (tok == T_STRING) {
strg_t *strg = *(strg_t **)sp;
if (strg->st_tspec == CHAR) {
free(strg->st_cp);
} else if (strg->st_tspec == WCHAR) {
free(strg->st_wcp);
} else {
lerror("fryylv() 1");
}
free(strg);
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Dec 14, 12:20 AM (1 d, 16 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
26916383
Default Alt Text
(59 KB)
Attached To
Mode
rG FreeBSD src repository
Attached
Detach File
Event Timeline
Log In to Comment