ack/lang/cem/cemcom/l_lint.c
1988-11-03 15:18:46 +00:00

365 lines
7.1 KiB
C

/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
/* $Header$ */
/* Lint main routines */
#include "lint.h"
#ifdef LINT
#include <alloc.h> /* for st_free */
#include "assert.h"
#include "arith.h" /* definition arith */
#include "label.h" /* definition label */
#include "expr.h"
#include "idf.h"
#include "def.h"
#include "code.h" /* RVAL etc */
#include "LLlex.h"
#include "Lpars.h"
#include "stack.h"
#include "type.h"
#include "level.h"
#include "nofloat.h"
#include "l_lint.h"
#include "l_state.h"
#include "l_outdef.h"
extern char options[128];
extern char *symbol2str();
static struct expr_state *lint_expr();
static struct expr_state *lint_value();
static struct expr_state *lint_oper();
lint_init()
{
lint_init_comment();
lint_init_stack();
}
pre_lint_expr(expr, val, used)
struct expr *expr;
int val; /* LVAL or RVAL */
int used;
{
/* Introduced to dispose the returned expression states */
register struct expr_state *esp;
esp = lint_expr(expr, val, used);
free_expr_states(esp);
}
free_expr_states(esp)
register struct expr_state *esp;
{
register struct expr_state *esp2;
while (esp) {
esp2 = esp;
esp = esp->next;
free_expr_state(esp2);
}
}
static struct expr_state *
lint_expr(expr, val, used)
register struct expr *expr;
int val;
int used;
{
/* Main function to process an expression tree.
* It returns a structure containing information about which variables
* are set and which are used in the expression.
* In addition it sets 'used' and 'set' fields of the corresponding
* variables in the current state.
* If the value of an operation without side-effects is not used,
* a warning is given.
*/
if (used == IGNORED) {
expr_ignored(expr);
}
switch (expr->ex_class) {
case Value:
return lint_value(expr, val);
case Oper:
return lint_oper(expr, val, used);
default: /* String Float Type */
return 0;
}
}
static struct expr_state *
lint_value(expr, val)
register struct expr *expr;
{
switch (expr->VL_CLASS) {
case Const:
case Label:
return 0;
case Name:
{
register struct idf *idf = expr->VL_IDF;
struct expr_state *esp1 = 0;
if (!idf || !idf->id_def)
return 0;
if ( val == LVAL
|| ( val == RVAL
&& expr->ex_type->tp_fund == POINTER
&& !expr->ex_lvalue
)
) {
change_state(idf, SET);
idf->id_def->df_file =
Salloc(dot.tk_file,
strlen(dot.tk_file) + 1);
idf->id_def->df_line = dot.tk_line;
}
if (val == RVAL) {
change_state(idf, USED);
add_expr_state(expr->EX_VALUE, USED, &esp1);
}
return esp1;
}
default:
NOTREACHED();
/* NOTREACHED */
}
}
static struct expr_state *
lint_oper(expr, val, used)
struct expr *expr;
int val;
int used;
{
register int oper = expr->OP_OPER;
register struct expr *left = expr->OP_LEFT;
register struct expr *right = expr->OP_RIGHT;
struct expr_state *esp1 = 0;
struct expr_state *esp2 = 0;
switch (oper) {
case '=':
case PLUSAB:
case MINAB:
case TIMESAB:
case DIVAB:
case MODAB:
case LEFTAB:
case RIGHTAB:
case ANDAB:
case XORAB:
case ORAB:
/* for cases like i += l; */
esp1 = lint_expr(right, RVAL, USED);
if (oper != '=') {
/* i += 1; is interpreted as i = i + 1; */
esp2 = lint_expr(left, RVAL, USED);
check_and_merge(&esp1, esp2, oper);
}
esp2 = lint_expr(left, LVAL, USED);
/* for cases like i = i + 1; and i not set, this
** order is essential
*/
check_and_merge(&esp1, esp2, oper);
if ( left->ex_class == Value
&& left->VL_CLASS == Name
) {
add_expr_state(left->EX_VALUE, SET, &esp1);
}
return esp1;
case POSTINCR:
case POSTDECR:
case PLUSPLUS:
case MINMIN:
/* i++; is parsed as i = i + 1;
* This isn't quite correct :
* The first statement doesn't USE i,
* the second does.
*/
esp1 = lint_expr(left, RVAL, USED);
esp2 = lint_expr(left, LVAL, USED);
check_and_merge(&esp1, esp2, oper);
if ( left->ex_class == Value
&& left->VL_CLASS == Name
) {
add_expr_state(left->EX_VALUE, SET, &esp1);
add_expr_state(left->EX_VALUE, USED, &esp1);
}
return esp1;
case '-':
case '*':
if (left == 0) /* unary */
return lint_expr(right, RVAL, USED);
esp1 = lint_expr(left, RVAL, USED);
esp2 = lint_expr(right, RVAL, USED);
check_and_merge(&esp1, esp2, oper);
return esp1;
case '(':
if (right != 0) {
/* function call with parameters */
register struct expr *ex = right;
while ( ex->ex_class == Oper
&& ex->OP_OPER == PARCOMMA
) {
esp2 = lint_expr(ex->OP_RIGHT, RVAL,
USED);
check_and_merge(&esp1, esp2, oper);
ex = ex->OP_LEFT;
}
esp2 = lint_expr(ex, RVAL, USED);
check_and_merge(&esp1, esp2, oper);
}
if ( left->ex_class == Value
&& left->VL_CLASS == Name
) {
fill_outcall(expr,
expr->ex_type->tp_fund == VOID ?
VOIDED : used
);
outcall();
left->VL_IDF->id_def->df_used = 1;
}
else {
esp2 = lint_expr(left, val, USED);
check_and_merge(&esp1, esp2, oper);
}
return esp1;
case '.':
return lint_expr(left, val, USED);
case ARROW:
return lint_expr(left, RVAL, USED);
case '~':
case '!':
return lint_expr(right, RVAL, USED);
case '?':
esp1 = lint_expr(left, RVAL, USED);
esp2 = lint_expr(right->OP_LEFT, RVAL, USED);
check_and_merge(&esp1, esp2, 0);
esp2 = lint_expr(right->OP_RIGHT, RVAL, USED);
check_and_merge(&esp1, esp2, 0);
return esp1;
case INT2INT:
case INT2FLOAT:
case FLOAT2INT:
case FLOAT2FLOAT:
return lint_expr(right, RVAL, USED);
case '<':
case '>':
case LESSEQ:
case GREATEREQ:
case EQUAL:
case NOTEQUAL:
lint_relop(left, right, oper);
lint_relop(right, left,
oper == '<' ? '>' :
oper == '>' ? '<' :
oper == LESSEQ ? GREATEREQ :
oper == GREATEREQ ? LESSEQ :
oper
);
/*FALLTHROUGH*/
case '+':
case '/':
case '%':
case ',':
case LEFT:
case RIGHT:
case '&':
case '|':
case '^':
case OR:
case AND:
esp1 = lint_expr(left, RVAL,
oper == ',' ? IGNORED : USED);
esp2 = lint_expr(right, RVAL,
oper == ',' ? used : USED);
if (oper == OR || oper == AND || oper == ',')
check_and_merge(&esp1, esp2, 0);
else
check_and_merge(&esp1, esp2, oper);
return esp1;
default:
return 0; /* for initcomma */
}
}
expr_ignored(expr)
struct expr *expr;
{
switch (expr->ex_class) {
case Oper:
switch (expr->OP_OPER) {
case '=':
case TIMESAB:
case DIVAB:
case MODAB:
case LEFTAB:
case RIGHTAB:
case ANDAB:
case XORAB:
case ORAB:
case AND: /* doubtful but useful */
case OR: /* doubtful but useful */
case '(':
case '?':
case ',':
break;
case PLUSAB:
case MINAB:
case POSTINCR:
case POSTDECR:
case PLUSPLUS:
case MINMIN:
/* may hide the operator * */
if ( /* operation on a pointer */
expr->OP_TYPE->tp_fund == POINTER
&& /* the result is dereferenced, e.g. *p++; */
expr->ex_type == expr->OP_TYPE->tp_up
) {
hwarning("result of * ignored");
}
break;
default:
hwarning("result of %s ignored",
symbol2str(expr->OP_OPER));
break;
}
break;
case Value:
hwarning("value as statement");
break;
default: /* String Float */
hwarning("constant as statement");
break;
}
}
#endif LINT