better evaluation order checking in expressions
This commit is contained in:
parent
f7df668450
commit
f70dfe4d00
16 changed files with 367 additions and 227 deletions
|
@ -126,7 +126,7 @@ LINT = /usr/bin/lint
|
||||||
LINTFLAGS =
|
LINTFLAGS =
|
||||||
|
|
||||||
MYLINT = ../lpass2/lint
|
MYLINT = ../lpass2/lint
|
||||||
MYLINTFLAGS = #-xh
|
MYLINTFLAGS = -xh
|
||||||
|
|
||||||
#EXCLEXCLEXCLEXCL
|
#EXCLEXCLEXCLEXCL
|
||||||
|
|
||||||
|
@ -800,6 +800,7 @@ l_lint.o: def.h
|
||||||
l_lint.o: expr.h
|
l_lint.o: expr.h
|
||||||
l_lint.o: file_info.h
|
l_lint.o: file_info.h
|
||||||
l_lint.o: idf.h
|
l_lint.o: idf.h
|
||||||
|
l_lint.o: interface.h
|
||||||
l_lint.o: l_lint.h
|
l_lint.o: l_lint.h
|
||||||
l_lint.o: l_outdef.h
|
l_lint.o: l_outdef.h
|
||||||
l_lint.o: l_state.h
|
l_lint.o: l_state.h
|
||||||
|
@ -822,6 +823,7 @@ l_states.o: def.h
|
||||||
l_states.o: expr.h
|
l_states.o: expr.h
|
||||||
l_states.o: file_info.h
|
l_states.o: file_info.h
|
||||||
l_states.o: idf.h
|
l_states.o: idf.h
|
||||||
|
l_states.o: interface.h
|
||||||
l_states.o: l_brace.h
|
l_states.o: l_brace.h
|
||||||
l_states.o: l_comment.h
|
l_states.o: l_comment.h
|
||||||
l_states.o: l_lint.h
|
l_states.o: l_lint.h
|
||||||
|
@ -844,6 +846,7 @@ l_misc.o: def.h
|
||||||
l_misc.o: expr.h
|
l_misc.o: expr.h
|
||||||
l_misc.o: file_info.h
|
l_misc.o: file_info.h
|
||||||
l_misc.o: idf.h
|
l_misc.o: idf.h
|
||||||
|
l_misc.o: interface.h
|
||||||
l_misc.o: l_state.h
|
l_misc.o: l_state.h
|
||||||
l_misc.o: label.h
|
l_misc.o: label.h
|
||||||
l_misc.o: level.h
|
l_misc.o: level.h
|
||||||
|
@ -864,6 +867,7 @@ l_ev_ord.o: def.h
|
||||||
l_ev_ord.o: expr.h
|
l_ev_ord.o: expr.h
|
||||||
l_ev_ord.o: file_info.h
|
l_ev_ord.o: file_info.h
|
||||||
l_ev_ord.o: idf.h
|
l_ev_ord.o: idf.h
|
||||||
|
l_ev_ord.o: interface.h
|
||||||
l_ev_ord.o: l_lint.h
|
l_ev_ord.o: l_lint.h
|
||||||
l_ev_ord.o: l_state.h
|
l_ev_ord.o: l_state.h
|
||||||
l_ev_ord.o: label.h
|
l_ev_ord.o: label.h
|
||||||
|
@ -879,12 +883,14 @@ l_outdef.o: LLlex.h
|
||||||
l_outdef.o: Lpars.h
|
l_outdef.o: Lpars.h
|
||||||
l_outdef.o: arith.h
|
l_outdef.o: arith.h
|
||||||
l_outdef.o: assert.h
|
l_outdef.o: assert.h
|
||||||
|
l_outdef.o: code.h
|
||||||
l_outdef.o: debug.h
|
l_outdef.o: debug.h
|
||||||
l_outdef.o: def.h
|
l_outdef.o: def.h
|
||||||
l_outdef.o: expr.h
|
l_outdef.o: expr.h
|
||||||
l_outdef.o: field.h
|
l_outdef.o: field.h
|
||||||
l_outdef.o: file_info.h
|
l_outdef.o: file_info.h
|
||||||
l_outdef.o: idf.h
|
l_outdef.o: idf.h
|
||||||
|
l_outdef.o: interface.h
|
||||||
l_outdef.o: l_class.h
|
l_outdef.o: l_class.h
|
||||||
l_outdef.o: l_comment.h
|
l_outdef.o: l_comment.h
|
||||||
l_outdef.o: l_lint.h
|
l_outdef.o: l_lint.h
|
||||||
|
@ -900,6 +906,8 @@ l_outdef.o: stack.h
|
||||||
l_outdef.o: struct.h
|
l_outdef.o: struct.h
|
||||||
l_outdef.o: type.h
|
l_outdef.o: type.h
|
||||||
l_comment.o: arith.h
|
l_comment.o: arith.h
|
||||||
|
l_comment.o: interface.h
|
||||||
|
l_comment.o: l_comment.h
|
||||||
l_comment.o: l_state.h
|
l_comment.o: l_state.h
|
||||||
l_comment.o: lint.h
|
l_comment.o: lint.h
|
||||||
l_comment.o: spec_arith.h
|
l_comment.o: spec_arith.h
|
||||||
|
@ -991,7 +999,6 @@ ival.o: LLlex.h
|
||||||
ival.o: Lpars.h
|
ival.o: Lpars.h
|
||||||
ival.o: arith.h
|
ival.o: arith.h
|
||||||
ival.o: assert.h
|
ival.o: assert.h
|
||||||
ival.o: code.h
|
|
||||||
ival.o: debug.h
|
ival.o: debug.h
|
||||||
ival.o: def.h
|
ival.o: def.h
|
||||||
ival.o: estack.h
|
ival.o: estack.h
|
||||||
|
|
|
@ -258,7 +258,7 @@ ch7cast(expp, oper, tp)
|
||||||
expr_warning(*expp, "incompatible pointers in %s",
|
expr_warning(*expp, "incompatible pointers in %s",
|
||||||
symbol2str(oper));
|
symbol2str(oper));
|
||||||
#ifdef LINT
|
#ifdef LINT
|
||||||
if (oper == CAST)
|
if (oper != CAST)
|
||||||
lint_ptr_conv(oldtp->tp_up->tp_fund, tp->tp_up->tp_fund);
|
lint_ptr_conv(oldtp->tp_up->tp_fund, tp->tp_up->tp_fund);
|
||||||
#endif LINT
|
#endif LINT
|
||||||
(*expp)->ex_type = tp; /* free conversion */
|
(*expp)->ex_type = tp; /* free conversion */
|
||||||
|
|
|
@ -71,9 +71,7 @@ ch7mon(oper, expp)
|
||||||
expr_error(*expp, "& applied to non-lvalue");
|
expr_error(*expp, "& applied to non-lvalue");
|
||||||
else {
|
else {
|
||||||
/* assume that enums are already filtered out */
|
/* assume that enums are already filtered out */
|
||||||
if ( (*expp)->ex_class == Value
|
if (ISNAME(*expp)) {
|
||||||
&& (*expp)->VL_CLASS == Name
|
|
||||||
) {
|
|
||||||
register struct def *def =
|
register struct def *def =
|
||||||
(*expp)->VL_IDF->id_def;
|
(*expp)->VL_IDF->id_def;
|
||||||
|
|
||||||
|
@ -147,10 +145,7 @@ ch7mon(oper, expp)
|
||||||
ch7incr(expp, oper);
|
ch7incr(expp, oper);
|
||||||
break;
|
break;
|
||||||
case SIZEOF:
|
case SIZEOF:
|
||||||
if ( (*expp)->ex_class == Value
|
if (ISNAME(*expp) && (*expp)->VL_IDF->id_def->df_formal_array)
|
||||||
&& (*expp)->VL_CLASS == Name
|
|
||||||
&& (*expp)->VL_IDF->id_def->df_formal_array
|
|
||||||
)
|
|
||||||
warning("sizeof formal array %s is sizeof pointer!",
|
warning("sizeof formal array %s is sizeof pointer!",
|
||||||
(*expp)->VL_IDF->id_text);
|
(*expp)->VL_IDF->id_text);
|
||||||
expr = intexpr((*expp)->ex_type == string_type ?
|
expr = intexpr((*expp)->ex_type == string_type ?
|
||||||
|
|
|
@ -559,7 +559,7 @@ code_expr(expr, val, code, tlbl, flbl)
|
||||||
C_lin((arith)(expr->ex_line));
|
C_lin((arith)(expr->ex_line));
|
||||||
EVAL(expr, val, code, tlbl, flbl);
|
EVAL(expr, val, code, tlbl, flbl);
|
||||||
#else LINT
|
#else LINT
|
||||||
pre_lint_expr(expr, RVAL, code ? USED : IGNORED);
|
lint_expr(expr, code ? USED : IGNORED);
|
||||||
#endif LINT
|
#endif LINT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -453,7 +453,7 @@ EVAL(expr, val, code, true_label, false_label)
|
||||||
arith ParSize = (arith)0;
|
arith ParSize = (arith)0;
|
||||||
label setjmp_label = 0;
|
label setjmp_label = 0;
|
||||||
|
|
||||||
if (left->ex_class == Value && left->VL_CLASS == Name) {
|
if (ISNAME(left)) {
|
||||||
if (left->VL_IDF->id_special == SP_SETJMP) {
|
if (left->VL_IDF->id_special == SP_SETJMP) {
|
||||||
label addr_label = data_label();
|
label addr_label = data_label();
|
||||||
|
|
||||||
|
@ -480,7 +480,7 @@ EVAL(expr, val, code, true_label, false_label)
|
||||||
NO_LABEL, NO_LABEL);
|
NO_LABEL, NO_LABEL);
|
||||||
ParSize += ATW(ex->ex_type->tp_size);
|
ParSize += ATW(ex->ex_type->tp_size);
|
||||||
}
|
}
|
||||||
if (left->ex_class == Value && left->VL_CLASS == Name) {
|
if (ISNAME(left)) {
|
||||||
/* e.g., main() { (*((int (*)())0))(); } */
|
/* e.g., main() { (*((int (*)())0))(); } */
|
||||||
C_cal(left->VL_IDF->id_text);
|
C_cal(left->VL_IDF->id_text);
|
||||||
if (setjmp_label) {
|
if (setjmp_label) {
|
||||||
|
@ -913,7 +913,7 @@ load_val(expr, rlval)
|
||||||
register struct idf *id = expr->VL_IDF;
|
register struct idf *id = expr->VL_IDF;
|
||||||
register struct def *df = id->id_def;
|
register struct def *df = id->id_def;
|
||||||
|
|
||||||
ASSERT(expr->VL_CLASS == Name);
|
ASSERT(ISNAME(expr));
|
||||||
if (df->df_type->tp_fund == FUNCTION) {
|
if (df->df_type->tp_fund == FUNCTION) {
|
||||||
/* the previous statement tried to catch a function
|
/* the previous statement tried to catch a function
|
||||||
identifier, which may be cast to a pointer to a
|
identifier, which may be cast to a pointer to a
|
||||||
|
|
|
@ -104,8 +104,11 @@ struct expr {
|
||||||
|
|
||||||
#define NILEXPR ((struct expr *)0)
|
#define NILEXPR ((struct expr *)0)
|
||||||
|
|
||||||
|
/* some useful tests */
|
||||||
|
#define ISNAME(e) ((e)->ex_class == Value && (e)->VL_CLASS == Name)
|
||||||
|
#define ISCOMMA(e) ((e)->ex_class == Oper && (e)->OP_OPER == INITCOMMA)
|
||||||
|
|
||||||
extern struct expr *intexpr(), *new_oper();
|
extern struct expr *intexpr(), *new_oper();
|
||||||
|
|
||||||
/* ALLOCDEF "expr" 20 */
|
/* ALLOCDEF "expr" 20 */
|
||||||
|
|
||||||
#define ISCOMMA(e) ((e)->ex_class == Oper && (e)->OP_OPER == INITCOMMA)
|
|
||||||
|
|
|
@ -3,6 +3,6 @@
|
||||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||||
*/
|
*/
|
||||||
#define PRIVATE
|
#define PRIVATE /*static /* or not */
|
||||||
#define IMPORT extern
|
#define IMPORT extern
|
||||||
#define EXPORT
|
#define EXPORT
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
#include "LLlex.h"
|
#include "LLlex.h"
|
||||||
#include "noRoption.h"
|
#include "noRoption.h"
|
||||||
#include "estack.h"
|
#include "estack.h"
|
||||||
#include "code.h"
|
|
||||||
#ifdef LINT
|
#ifdef LINT
|
||||||
#include "l_lint.h"
|
#include "l_lint.h"
|
||||||
#endif LINT
|
#endif LINT
|
||||||
|
@ -54,7 +53,7 @@ initial_value(register struct type **tpp; register struct expr **expp;) :
|
||||||
assignment_expression(expp)
|
assignment_expression(expp)
|
||||||
{
|
{
|
||||||
#ifdef LINT
|
#ifdef LINT
|
||||||
pre_lint_expr(*expp, RVAL, USED);
|
lint_expr(*expp, USED);
|
||||||
#endif LINT
|
#endif LINT
|
||||||
if ((*expp)->ex_type->tp_fund == ARRAY)
|
if ((*expp)->ex_type->tp_fund == ARRAY)
|
||||||
array2pointer(*expp);
|
array2pointer(*expp);
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#ifdef LINT
|
#ifdef LINT
|
||||||
|
|
||||||
#include <alloc.h>
|
#include <alloc.h>
|
||||||
|
#include "interface.h"
|
||||||
#include "arith.h"
|
#include "arith.h"
|
||||||
#include "l_state.h"
|
#include "l_state.h"
|
||||||
#include "l_comment.h"
|
#include "l_comment.h"
|
||||||
|
@ -24,13 +25,15 @@ extern char loptions[];
|
||||||
one token later.
|
one token later.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int notreached;
|
PRIVATE int notreached;
|
||||||
static int varargsN = -1;
|
PRIVATE int varargsN = -1;
|
||||||
static int argsused;
|
PRIVATE int argsused;
|
||||||
static int formatN;
|
PRIVATE int formatN;
|
||||||
static int formatVAR;
|
PRIVATE int formatVAR;
|
||||||
static char *format;
|
PRIVATE char *format;
|
||||||
static char *prev_format;
|
PRIVATE char *prev_format;
|
||||||
|
|
||||||
|
PRIVATE make_format();
|
||||||
|
|
||||||
int LINTLIB; /* file is lint library */
|
int LINTLIB; /* file is lint library */
|
||||||
int s_NOTREACHED; /* statement not reached */
|
int s_NOTREACHED; /* statement not reached */
|
||||||
|
@ -71,8 +74,8 @@ lint_comment_function()
|
||||||
formatVAR = 0;
|
formatVAR = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char buf[1000];
|
PRIVATE char buf[1000];
|
||||||
static char *bufpos; /* next free position in buf */
|
PRIVATE char *bufpos; /* next free position in buf */
|
||||||
|
|
||||||
lint_start_comment()
|
lint_start_comment()
|
||||||
{
|
{
|
||||||
|
@ -139,6 +142,7 @@ lint_end_comment()
|
||||||
#define LETGIT 1
|
#define LETGIT 1
|
||||||
#define LETGITSPACE 2
|
#define LETGITSPACE 2
|
||||||
|
|
||||||
|
PRIVATE
|
||||||
make_format(argn, oldf)
|
make_format(argn, oldf)
|
||||||
int argn;
|
int argn;
|
||||||
char *oldf;
|
char *oldf;
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#ifdef LINT
|
#ifdef LINT
|
||||||
|
|
||||||
#include <alloc.h> /* for st_free */
|
#include <alloc.h> /* for st_free */
|
||||||
|
#include "interface.h"
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
#include "arith.h" /* definition arith */
|
#include "arith.h" /* definition arith */
|
||||||
#include "label.h" /* definition label */
|
#include "label.h" /* definition label */
|
||||||
|
@ -28,42 +29,56 @@
|
||||||
|
|
||||||
extern char *symbol2str();
|
extern char *symbol2str();
|
||||||
|
|
||||||
check_and_merge(espp, esp, com_oper)
|
PRIVATE check_ev_order();
|
||||||
|
|
||||||
|
check_and_merge(expr, espp, esp)
|
||||||
|
struct expr *expr;
|
||||||
struct expr_state **espp, *esp;
|
struct expr_state **espp, *esp;
|
||||||
{
|
{
|
||||||
/* Checks for undefined evaluation orders in case of a commutative operator.
|
/* Checks for undefined evaluation orders in case of a non-sequencing operator.
|
||||||
* In addition the sets of used and set variables of both expressions are
|
* In addition the sets of used and set variables of both expressions are
|
||||||
* united.
|
* united.
|
||||||
* *espp will be pointing to this new list. esp is used for this list.
|
* *espp will be pointing to this new list. esp is used for this list.
|
||||||
*/
|
*/
|
||||||
register struct expr_state **pp, *p1, *p2;
|
register struct expr_state **pp, *p1, *p2;
|
||||||
|
int oper = expr->OP_OPER;
|
||||||
|
int is_sequencer =
|
||||||
|
(oper == '?' || oper == OR || oper == AND || oper ==',');
|
||||||
|
|
||||||
for (p1 = *espp; p1; p1 = p1->next) {
|
for (p1 = *espp; p1; p1 = p1->next) {
|
||||||
|
/* scan the list esp for the same variable */
|
||||||
p2 = esp;
|
p2 = esp;
|
||||||
pp = &esp;
|
pp = &esp;
|
||||||
while (p2) {
|
while (p2) {
|
||||||
if ( /* p1 and p2 are the same */
|
if ( /* p1 and p2 refer to the same location */
|
||||||
p1->es_idf == p2->es_idf
|
p1->es_idf == p2->es_idf
|
||||||
&& p1->es_offset == p2->es_offset
|
&& p1->es_offset == p2->es_offset
|
||||||
) {
|
) {
|
||||||
if (com_oper)
|
/* check */
|
||||||
check_ev_order(p1, p2, com_oper);
|
if (!is_sequencer)
|
||||||
|
check_ev_order(p1, p2, expr);
|
||||||
|
|
||||||
|
/* merge the info */
|
||||||
p1->es_used |= p2->es_used;
|
p1->es_used |= p2->es_used;
|
||||||
|
p1->es_referred |= p2->es_referred;
|
||||||
p1->es_set |= p2->es_set;
|
p1->es_set |= p2->es_set;
|
||||||
|
|
||||||
|
/* and remove the entry from esp */
|
||||||
*pp = p2->next;
|
*pp = p2->next;
|
||||||
free_expr_state(p2);
|
free_expr_state(p2);
|
||||||
p2 = *pp;
|
p2 = *pp;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
/* skip over the entry in esp */
|
||||||
pp = &p2->next;
|
pp = &p2->next;
|
||||||
p2 = p2->next;
|
p2 = p2->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* The rest of the list esp is pointing to, is put in front of the list
|
/* If there is anything left in the list esp, this is put in
|
||||||
* *espp is now pointing to.
|
front of the list *espp is now pointing to, and *espp will be
|
||||||
* *espp will be pointing to this new list.
|
left pointing to this new list.
|
||||||
*/
|
*/
|
||||||
if (!esp)
|
if (!esp)
|
||||||
return;
|
return;
|
||||||
p1 = *espp;
|
p1 = *espp;
|
||||||
|
@ -73,44 +88,20 @@ check_and_merge(espp, esp, com_oper)
|
||||||
esp->next = p1;
|
esp->next = p1;
|
||||||
}
|
}
|
||||||
|
|
||||||
check_ev_order(esp1, esp2, com_oper)
|
PRIVATE
|
||||||
|
check_ev_order(esp1, esp2, expr)
|
||||||
struct expr_state *esp1, *esp2;
|
struct expr_state *esp1, *esp2;
|
||||||
|
struct expr *expr;
|
||||||
{
|
{
|
||||||
if ( (esp1->es_used && esp2->es_set)
|
if ( (esp1->es_used && esp2->es_set)
|
||||||
|| (esp1->es_set && esp2->es_used)
|
|| (esp1->es_set && esp2->es_used)
|
||||||
|| (esp1->es_set && esp2->es_set)
|
|| (esp1->es_set && esp2->es_set)
|
||||||
) {
|
) {
|
||||||
warning("result of %s depends on evaluation order on %s",
|
expr_warning(expr,
|
||||||
symbol2str(com_oper),
|
"result of %s depends on evaluation order on %s",
|
||||||
|
symbol2str(expr->OP_OPER),
|
||||||
esp1->es_idf->id_text);
|
esp1->es_idf->id_text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
add_expr_state(value, to_state, espp)
|
|
||||||
struct value value;
|
|
||||||
struct expr_state **espp;
|
|
||||||
{
|
|
||||||
register struct expr_state *esp = *espp;
|
|
||||||
|
|
||||||
ASSERT(value.vl_class == Name);
|
|
||||||
while ( esp
|
|
||||||
&& !( esp->es_idf == value.vl_data.vl_idf
|
|
||||||
&& esp->es_offset == value.vl_value
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
esp = esp->next;
|
|
||||||
}
|
|
||||||
if (!esp) { /* create new expr_state */
|
|
||||||
esp = new_expr_state();
|
|
||||||
esp->es_idf = value.vl_data.vl_idf;
|
|
||||||
esp->es_offset = value.vl_value;
|
|
||||||
esp->next = *espp;
|
|
||||||
*espp = esp;
|
|
||||||
}
|
|
||||||
if (to_state == SET)
|
|
||||||
esp->es_set = 1;
|
|
||||||
else /* USED */
|
|
||||||
esp->es_used = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif LINT
|
#endif LINT
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#ifdef LINT
|
#ifdef LINT
|
||||||
|
|
||||||
#include <alloc.h> /* for st_free */
|
#include <alloc.h> /* for st_free */
|
||||||
|
#include "debug.h"
|
||||||
|
#include "interface.h"
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
#include "arith.h" /* definition arith */
|
#include "arith.h" /* definition arith */
|
||||||
#include "label.h" /* definition label */
|
#include "label.h" /* definition label */
|
||||||
|
@ -30,9 +32,13 @@
|
||||||
extern char options[128];
|
extern char options[128];
|
||||||
extern char *symbol2str();
|
extern char *symbol2str();
|
||||||
|
|
||||||
static struct expr_state *lint_expr();
|
PRIVATE struct expr_state *expr2state();
|
||||||
static struct expr_state *lint_value();
|
PRIVATE struct expr_state *value2state();
|
||||||
static struct expr_state *lint_oper();
|
PRIVATE struct expr_state *oper2state();
|
||||||
|
PRIVATE expr_ignored();
|
||||||
|
PRIVATE add_expr_state();
|
||||||
|
PRIVATE referred_esp();
|
||||||
|
PRIVATE free_expr_states();
|
||||||
|
|
||||||
lint_init()
|
lint_init()
|
||||||
{
|
{
|
||||||
|
@ -40,36 +46,22 @@ lint_init()
|
||||||
lint_init_stack();
|
lint_init_stack();
|
||||||
}
|
}
|
||||||
|
|
||||||
pre_lint_expr(expr, val, used)
|
lint_expr(expr, used)
|
||||||
struct expr *expr;
|
struct expr *expr;
|
||||||
int val; /* LVAL or RVAL */
|
int used; /* USED or IGNORED */
|
||||||
int used;
|
|
||||||
{
|
{
|
||||||
/* Introduced to dispose the returned expression states */
|
|
||||||
|
|
||||||
register struct expr_state *esp;
|
register struct expr_state *esp;
|
||||||
|
|
||||||
esp = lint_expr(expr, val, used);
|
esp = expr2state(expr, RVAL, used);
|
||||||
|
referred_esp(esp);
|
||||||
free_expr_states(esp);
|
free_expr_states(esp);
|
||||||
}
|
}
|
||||||
|
|
||||||
free_expr_states(esp)
|
PRIVATE struct expr_state *
|
||||||
register struct expr_state *esp;
|
expr2state(expr, val, used)
|
||||||
{
|
|
||||||
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;
|
register struct expr *expr;
|
||||||
int val;
|
int val; /* RVAL or LVAL */
|
||||||
int used;
|
int used; /* USED or IGNORED */
|
||||||
{
|
{
|
||||||
/* Main function to process an expression tree.
|
/* Main function to process an expression tree.
|
||||||
* It returns a structure containing information about which variables
|
* It returns a structure containing information about which variables
|
||||||
|
@ -85,19 +77,20 @@ lint_expr(expr, val, used)
|
||||||
|
|
||||||
switch (expr->ex_class) {
|
switch (expr->ex_class) {
|
||||||
case Value:
|
case Value:
|
||||||
return lint_value(expr, val);
|
return value2state(expr, val);
|
||||||
|
|
||||||
case Oper:
|
case Oper:
|
||||||
return lint_oper(expr, val, used);
|
return oper2state(expr, val, used);
|
||||||
|
|
||||||
default: /* String Float Type */
|
default: /* String, Float, Type */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct expr_state *
|
PRIVATE struct expr_state *
|
||||||
lint_value(expr, val)
|
value2state(expr, val)
|
||||||
register struct expr *expr;
|
struct expr *expr;
|
||||||
|
int val; /* RVAL or LVAL */
|
||||||
{
|
{
|
||||||
switch (expr->VL_CLASS) {
|
switch (expr->VL_CLASS) {
|
||||||
case Const:
|
case Const:
|
||||||
|
@ -107,28 +100,21 @@ lint_value(expr, val)
|
||||||
case Name:
|
case Name:
|
||||||
{
|
{
|
||||||
register struct idf *idf = expr->VL_IDF;
|
register struct idf *idf = expr->VL_IDF;
|
||||||
struct expr_state *esp1 = 0;
|
struct expr_state *esp = 0;
|
||||||
|
|
||||||
if (!idf || !idf->id_def)
|
if (!idf || !idf->id_def)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if ( val == LVAL
|
if (val == RVAL && expr->ex_lvalue == 1) {
|
||||||
|| ( val == RVAL
|
/* value of identifier used */
|
||||||
&& 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);
|
change_state(idf, USED);
|
||||||
add_expr_state(expr->EX_VALUE, USED, &esp1);
|
add_expr_state(expr->EX_VALUE, USED, &esp);
|
||||||
}
|
}
|
||||||
return esp1;
|
if (val == RVAL && expr->ex_lvalue == 0) {
|
||||||
|
/* address of identifier used */
|
||||||
|
add_expr_state(expr->EX_VALUE, REFERRED, &esp);
|
||||||
|
}
|
||||||
|
return esp;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -137,19 +123,31 @@ lint_value(expr, val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct expr_state *
|
/* Let's get this straight.
|
||||||
lint_oper(expr, val, used)
|
An assignment is performed by elaborating the LHS and the RHS
|
||||||
|
collaterally, to use the A68 terminology, and then serially do the
|
||||||
|
actual assignment. This means:
|
||||||
|
1. evaluate the LHS as an LVAL,
|
||||||
|
2. evaluate the RHS as an RVAL,
|
||||||
|
3. merge them checking for interference,
|
||||||
|
4. set the result of the LHS to SET, if it is a named variable
|
||||||
|
*/
|
||||||
|
|
||||||
|
PRIVATE struct expr_state *
|
||||||
|
oper2state(expr, val, used)
|
||||||
struct expr *expr;
|
struct expr *expr;
|
||||||
int val;
|
int val; /* RVAL or LVAL */
|
||||||
int used;
|
int used; /* USED or IGNORED */
|
||||||
{
|
{
|
||||||
register int oper = expr->OP_OPER;
|
register int oper = expr->OP_OPER;
|
||||||
register struct expr *left = expr->OP_LEFT;
|
register struct expr *left = expr->OP_LEFT;
|
||||||
register struct expr *right = expr->OP_RIGHT;
|
register struct expr *right = expr->OP_RIGHT;
|
||||||
struct expr_state *esp1 = 0;
|
struct expr_state *esp_l = 0;
|
||||||
struct expr_state *esp2 = 0;
|
struct expr_state *esp_r = 0;
|
||||||
|
|
||||||
switch (oper) {
|
switch (oper) {
|
||||||
|
|
||||||
|
/* assignments */
|
||||||
case '=':
|
case '=':
|
||||||
case PLUSAB:
|
case PLUSAB:
|
||||||
case MINAB:
|
case MINAB:
|
||||||
|
@ -161,53 +159,42 @@ lint_oper(expr, val, used)
|
||||||
case ANDAB:
|
case ANDAB:
|
||||||
case XORAB:
|
case XORAB:
|
||||||
case ORAB:
|
case ORAB:
|
||||||
/* for cases like i += l; */
|
/* evaluate the LHS, only once; see RM 7.14 */
|
||||||
esp1 = lint_expr(right, RVAL, USED);
|
esp_l = expr2state(left, (oper == '=' ? LVAL : RVAL), USED);
|
||||||
if (oper != '=') {
|
|
||||||
/* i += 1; is interpreted as i = i + 1; */
|
/* evaluate the RHS as an RVAL and merge */
|
||||||
esp2 = lint_expr(left, RVAL, USED);
|
esp_r = expr2state(right, RVAL, USED);
|
||||||
check_and_merge(&esp1, esp2, oper);
|
check_and_merge(expr, &esp_l, esp_r);
|
||||||
|
|
||||||
|
/* set resulting variable, if any */
|
||||||
|
if (ISNAME(left)) {
|
||||||
|
change_state(left->VL_IDF, SET);
|
||||||
|
add_expr_state(left->EX_VALUE, SET, &esp_l);
|
||||||
}
|
}
|
||||||
esp2 = lint_expr(left, LVAL, USED);
|
|
||||||
/* for cases like i = i + 1; and i not set, this
|
return esp_l;
|
||||||
** 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 POSTINCR:
|
||||||
case POSTDECR:
|
case POSTDECR:
|
||||||
case PLUSPLUS:
|
case PLUSPLUS:
|
||||||
case MINMIN:
|
case MINMIN:
|
||||||
/* i++; is parsed as i = i + 1;
|
esp_l = expr2state(left, RVAL, USED);
|
||||||
* 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 '-':
|
/* set resulting variable, if any */
|
||||||
case '*':
|
if (ISNAME(left)) {
|
||||||
if (left == 0) /* unary */
|
change_state(left->VL_IDF, SET);
|
||||||
return lint_expr(right, RVAL, USED);
|
add_expr_state(left->EX_VALUE, SET, &esp_l);
|
||||||
esp1 = lint_expr(left, RVAL, USED);
|
}
|
||||||
esp2 = lint_expr(right, RVAL, USED);
|
|
||||||
check_and_merge(&esp1, esp2, oper);
|
return esp_l;
|
||||||
return esp1;
|
|
||||||
|
case '?':
|
||||||
|
esp_l = expr2state(left, RVAL, USED);
|
||||||
|
esp_r = expr2state(right->OP_LEFT, RVAL, USED);
|
||||||
|
check_and_merge(expr, &esp_l, esp_r);
|
||||||
|
esp_r = expr2state(right->OP_RIGHT, RVAL, USED);
|
||||||
|
check_and_merge(expr, &esp_l, esp_r);
|
||||||
|
return esp_l;
|
||||||
|
|
||||||
case '(':
|
case '(':
|
||||||
if (right != 0) {
|
if (right != 0) {
|
||||||
|
@ -217,17 +204,15 @@ lint_oper(expr, val, used)
|
||||||
while ( ex->ex_class == Oper
|
while ( ex->ex_class == Oper
|
||||||
&& ex->OP_OPER == PARCOMMA
|
&& ex->OP_OPER == PARCOMMA
|
||||||
) {
|
) {
|
||||||
esp2 = lint_expr(ex->OP_RIGHT, RVAL,
|
esp_r = expr2state(ex->OP_RIGHT, RVAL, USED);
|
||||||
USED);
|
check_and_merge(expr, &esp_l, esp_r);
|
||||||
check_and_merge(&esp1, esp2, oper);
|
|
||||||
ex = ex->OP_LEFT;
|
ex = ex->OP_LEFT;
|
||||||
}
|
}
|
||||||
esp2 = lint_expr(ex, RVAL, USED);
|
esp_r = expr2state(ex, RVAL, USED);
|
||||||
check_and_merge(&esp1, esp2, oper);
|
check_and_merge(expr, &esp_l, esp_r);
|
||||||
}
|
}
|
||||||
if ( left->ex_class == Value
|
|
||||||
&& left->VL_CLASS == Name
|
if (ISNAME(left)) {
|
||||||
) {
|
|
||||||
fill_outcall(expr,
|
fill_outcall(expr,
|
||||||
expr->ex_type->tp_fund == VOID ?
|
expr->ex_type->tp_fund == VOID ?
|
||||||
VOIDED : used
|
VOIDED : used
|
||||||
|
@ -236,35 +221,34 @@ lint_oper(expr, val, used)
|
||||||
left->VL_IDF->id_def->df_used = 1;
|
left->VL_IDF->id_def->df_used = 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
esp2 = lint_expr(left, val, USED);
|
esp_r = expr2state(left, RVAL, USED);
|
||||||
check_and_merge(&esp1, esp2, oper);
|
check_and_merge(expr, &esp_l, esp_r);
|
||||||
}
|
}
|
||||||
return esp1;
|
referred_esp(esp_l);
|
||||||
|
return esp_l;
|
||||||
|
|
||||||
case '.':
|
case '.':
|
||||||
return lint_expr(left, val, USED);
|
return expr2state(left, val, USED);
|
||||||
|
|
||||||
case ARROW:
|
case ARROW:
|
||||||
return lint_expr(left, RVAL, USED);
|
return expr2state(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 INT2INT:
|
||||||
case INT2FLOAT:
|
case INT2FLOAT:
|
||||||
case FLOAT2INT:
|
case FLOAT2INT:
|
||||||
case FLOAT2FLOAT:
|
case FLOAT2FLOAT:
|
||||||
return lint_expr(right, RVAL, USED);
|
return expr2state(right, RVAL, USED);
|
||||||
|
|
||||||
|
/* monadic operators */
|
||||||
|
case '-':
|
||||||
|
case '*':
|
||||||
|
if (left)
|
||||||
|
goto dyadic;
|
||||||
|
case '~':
|
||||||
|
case '!':
|
||||||
|
return expr2state(right, RVAL, USED);
|
||||||
|
|
||||||
|
/* relational operators */
|
||||||
case '<':
|
case '<':
|
||||||
case '>':
|
case '>':
|
||||||
case LESSEQ:
|
case LESSEQ:
|
||||||
|
@ -279,7 +263,10 @@ lint_oper(expr, val, used)
|
||||||
oper == GREATEREQ ? LESSEQ :
|
oper == GREATEREQ ? LESSEQ :
|
||||||
oper
|
oper
|
||||||
);
|
);
|
||||||
/*FALLTHROUGH*/
|
goto dyadic;
|
||||||
|
|
||||||
|
/* dyadic operators */
|
||||||
|
dyadic:
|
||||||
case '+':
|
case '+':
|
||||||
case '/':
|
case '/':
|
||||||
case '%':
|
case '%':
|
||||||
|
@ -291,21 +278,20 @@ lint_oper(expr, val, used)
|
||||||
case '^':
|
case '^':
|
||||||
case OR:
|
case OR:
|
||||||
case AND:
|
case AND:
|
||||||
esp1 = lint_expr(left, RVAL,
|
esp_l = expr2state(left, RVAL,
|
||||||
oper == ',' ? IGNORED : USED);
|
oper == ',' ? IGNORED : USED);
|
||||||
esp2 = lint_expr(right, RVAL,
|
esp_r = expr2state(right, RVAL,
|
||||||
oper == ',' ? used : USED);
|
oper == ',' ? used : USED);
|
||||||
if (oper == OR || oper == AND || oper == ',')
|
check_and_merge(expr, &esp_l, esp_r);
|
||||||
check_and_merge(&esp1, esp2, 0);
|
|
||||||
else
|
return esp_l;
|
||||||
check_and_merge(&esp1, esp2, oper);
|
|
||||||
return esp1;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 0; /* for initcomma */
|
return 0; /* for initcomma */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRIVATE
|
||||||
expr_ignored(expr)
|
expr_ignored(expr)
|
||||||
struct expr *expr;
|
struct expr *expr;
|
||||||
{
|
{
|
||||||
|
@ -334,7 +320,7 @@ expr_ignored(expr)
|
||||||
case POSTDECR:
|
case POSTDECR:
|
||||||
case PLUSPLUS:
|
case PLUSPLUS:
|
||||||
case MINMIN:
|
case MINMIN:
|
||||||
/* may hide the operator * */
|
/* may hide the operator '*' */
|
||||||
if ( /* operation on a pointer */
|
if ( /* operation on a pointer */
|
||||||
expr->OP_TYPE->tp_fund == POINTER
|
expr->OP_TYPE->tp_fund == POINTER
|
||||||
&& /* the result is dereferenced, e.g. *p++; */
|
&& /* the result is dereferenced, e.g. *p++; */
|
||||||
|
@ -361,4 +347,96 @@ expr_ignored(expr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRIVATE
|
||||||
|
add_expr_state(value, to_state, espp)
|
||||||
|
struct value value;
|
||||||
|
struct expr_state **espp;
|
||||||
|
{
|
||||||
|
register struct expr_state *esp = *espp;
|
||||||
|
|
||||||
|
ASSERT(value.vl_class == Name);
|
||||||
|
|
||||||
|
/* try to find the esp */
|
||||||
|
while ( esp
|
||||||
|
&& !( esp->es_idf == value.vl_data.vl_idf
|
||||||
|
&& esp->es_offset == value.vl_value
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
esp = esp->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if not found, add it */
|
||||||
|
if (!esp) {
|
||||||
|
esp = new_expr_state();
|
||||||
|
esp->es_idf = value.vl_data.vl_idf;
|
||||||
|
esp->es_offset = value.vl_value;
|
||||||
|
esp->next = *espp;
|
||||||
|
*espp = esp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set state */
|
||||||
|
switch (to_state) {
|
||||||
|
case USED:
|
||||||
|
esp->es_used = 1;
|
||||||
|
break;
|
||||||
|
case REFERRED:
|
||||||
|
esp->es_referred = 1;
|
||||||
|
break;
|
||||||
|
case SET:
|
||||||
|
esp->es_set = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NOTREACHED();
|
||||||
|
/* NOTREACHED */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PRIVATE
|
||||||
|
referred_esp(esp)
|
||||||
|
struct expr_state *esp;
|
||||||
|
{
|
||||||
|
/* raises all REFERRED items to SET and USED status */
|
||||||
|
while (esp) {
|
||||||
|
if (esp->es_referred) {
|
||||||
|
esp->es_set = 1;
|
||||||
|
change_state(esp->es_idf, SET);
|
||||||
|
esp->es_used = 1;
|
||||||
|
change_state(esp->es_idf, USED);
|
||||||
|
esp->es_referred = 0;
|
||||||
|
}
|
||||||
|
esp = esp->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PRIVATE
|
||||||
|
free_expr_states(esp)
|
||||||
|
register struct expr_state *esp;
|
||||||
|
{
|
||||||
|
while (esp) {
|
||||||
|
register struct expr_state *esp2 = esp;
|
||||||
|
|
||||||
|
esp = esp->next;
|
||||||
|
free_expr_state(esp2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
print_esp(msg, esp)
|
||||||
|
char *msg;
|
||||||
|
struct expr_state *esp;
|
||||||
|
{
|
||||||
|
print("%s: <", msg);
|
||||||
|
while (esp) {
|
||||||
|
print(" %s[%d]%c%c%c ",
|
||||||
|
esp->es_idf->id_text, esp->es_offset,
|
||||||
|
(esp->es_used ? 'U' : ' '),
|
||||||
|
(esp->es_referred ? 'R' : ' '),
|
||||||
|
(esp->es_set ? 'S' : ' ')
|
||||||
|
);
|
||||||
|
esp = esp->next;
|
||||||
|
}
|
||||||
|
print(">\n");
|
||||||
|
}
|
||||||
|
#endif DEBUG
|
||||||
|
|
||||||
#endif LINT
|
#endif LINT
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#define IGNORED 1
|
#define IGNORED 1
|
||||||
#define SET 2
|
#define SET 2
|
||||||
#define VOIDED 3
|
#define VOIDED 3
|
||||||
|
#define REFERRED 4
|
||||||
|
|
||||||
/* for od_valreturned */
|
/* for od_valreturned */
|
||||||
#define NOVALRETURNED 0
|
#define NOVALRETURNED 0
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#ifdef LINT
|
#ifdef LINT
|
||||||
|
|
||||||
#include <alloc.h> /* for st_free */
|
#include <alloc.h> /* for st_free */
|
||||||
|
#include "interface.h"
|
||||||
#include "arith.h" /* definition arith */
|
#include "arith.h" /* definition arith */
|
||||||
#include "label.h" /* definition label */
|
#include "label.h" /* definition label */
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
|
@ -27,6 +28,10 @@
|
||||||
extern char *symbol2str();
|
extern char *symbol2str();
|
||||||
extern struct type *func_type;
|
extern struct type *func_type;
|
||||||
|
|
||||||
|
PRIVATE lint_enum_arith();
|
||||||
|
PRIVATE lint_conversion();
|
||||||
|
PRIVATE int numsize();
|
||||||
|
|
||||||
lint_new_oper(expr)
|
lint_new_oper(expr)
|
||||||
struct expr *expr;
|
struct expr *expr;
|
||||||
{
|
{
|
||||||
|
@ -210,6 +215,7 @@ lint_new_oper(expr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRIVATE
|
||||||
lint_enum_arith(l_fund, oper, r_fund)
|
lint_enum_arith(l_fund, oper, r_fund)
|
||||||
int l_fund, oper, r_fund;
|
int l_fund, oper, r_fund;
|
||||||
{
|
{
|
||||||
|
@ -228,10 +234,11 @@ lint_enum_arith(l_fund, oper, r_fund)
|
||||||
&& l_fund != INT
|
&& l_fund != INT
|
||||||
) {
|
) {
|
||||||
warning("%s on %s and enum",
|
warning("%s on %s and enum",
|
||||||
symbol2str(oper), symbol2str(r_fund));
|
symbol2str(oper), symbol2str(l_fund));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRIVATE
|
||||||
lint_conversion(from_expr, to_fund)
|
lint_conversion(from_expr, to_fund)
|
||||||
struct expr *from_expr;
|
struct expr *from_expr;
|
||||||
int to_fund;
|
int to_fund;
|
||||||
|
@ -267,7 +274,7 @@ lint_conversion(from_expr, to_fund)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
PRIVATE int
|
||||||
numsize(fund)
|
numsize(fund)
|
||||||
{
|
{
|
||||||
switch (fund) {
|
switch (fund) {
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#ifdef LINT
|
#ifdef LINT
|
||||||
|
|
||||||
#include <alloc.h>
|
#include <alloc.h>
|
||||||
|
#include "interface.h"
|
||||||
#include "arith.h"
|
#include "arith.h"
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
#include "type.h"
|
#include "type.h"
|
||||||
|
@ -33,7 +34,18 @@ extern char *bts2str();
|
||||||
extern char *symbol2str();
|
extern char *symbol2str();
|
||||||
|
|
||||||
int stat_number = 9999; /* static scope number */
|
int stat_number = 9999; /* static scope number */
|
||||||
struct outdef OutDef, OutCall;
|
struct outdef OutDef;
|
||||||
|
|
||||||
|
PRIVATE struct outdef OutCall;
|
||||||
|
|
||||||
|
PRIVATE local_EFDC();
|
||||||
|
PRIVATE output_def();
|
||||||
|
PRIVATE outargs();
|
||||||
|
PRIVATE outarg();
|
||||||
|
PRIVATE outargstring();
|
||||||
|
PRIVATE outargtype();
|
||||||
|
PRIVATE implicit_func_decl();
|
||||||
|
PRIVATE fill_arg();
|
||||||
|
|
||||||
lint_declare_idf(idf, sc)
|
lint_declare_idf(idf, sc)
|
||||||
struct idf *idf;
|
struct idf *idf;
|
||||||
|
@ -111,6 +123,7 @@ set_od_valreturned(n)
|
||||||
OutDef.od_valreturned = n;
|
OutDef.od_valreturned = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRIVATE
|
||||||
local_EFDC(idf)
|
local_EFDC(idf)
|
||||||
struct idf *idf;
|
struct idf *idf;
|
||||||
{
|
{
|
||||||
|
@ -251,6 +264,7 @@ outcall()
|
||||||
output_def(&OutCall);
|
output_def(&OutCall);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRIVATE
|
||||||
output_def(od)
|
output_def(od)
|
||||||
struct outdef *od;
|
struct outdef *od;
|
||||||
{
|
{
|
||||||
|
@ -319,6 +333,7 @@ output_def(od)
|
||||||
printf(":%u:%s\n", od->od_line, od->od_file);
|
printf(":%u:%s\n", od->od_line, od->od_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRIVATE
|
||||||
outargs(arg, n)
|
outargs(arg, n)
|
||||||
struct argument *arg;
|
struct argument *arg;
|
||||||
{
|
{
|
||||||
|
@ -341,6 +356,7 @@ outargs(arg, n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRIVATE
|
||||||
outarg(arg)
|
outarg(arg)
|
||||||
struct argument *arg;
|
struct argument *arg;
|
||||||
{
|
{
|
||||||
|
@ -379,6 +395,7 @@ outarg(arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRIVATE
|
||||||
outargstring(arg)
|
outargstring(arg)
|
||||||
struct argument *arg;
|
struct argument *arg;
|
||||||
{
|
{
|
||||||
|
@ -393,6 +410,7 @@ outargstring(arg)
|
||||||
printf("\"%s\"", buff);
|
printf("\"%s\"", buff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRIVATE
|
||||||
outargtype(tp)
|
outargtype(tp)
|
||||||
struct type *tp;
|
struct type *tp;
|
||||||
{
|
{
|
||||||
|
@ -436,6 +454,7 @@ outargtype(tp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRIVATE
|
||||||
implicit_func_decl(idf, file, line)
|
implicit_func_decl(idf, file, line)
|
||||||
struct idf *idf;
|
struct idf *idf;
|
||||||
char *file;
|
char *file;
|
||||||
|
@ -485,6 +504,7 @@ fill_outcall(ex, used)
|
||||||
OutCall.od_valused = used; /* USED, IGNORED or VOIDED */
|
OutCall.od_valused = used; /* USED, IGNORED or VOIDED */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRIVATE
|
||||||
fill_arg(e)
|
fill_arg(e)
|
||||||
struct expr *e;
|
struct expr *e;
|
||||||
{
|
{
|
||||||
|
|
|
@ -66,6 +66,7 @@ struct expr_state {
|
||||||
struct idf *es_idf;
|
struct idf *es_idf;
|
||||||
arith es_offset;
|
arith es_offset;
|
||||||
int es_used;
|
int es_used;
|
||||||
|
int es_referred;
|
||||||
int es_set;
|
int es_set;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,9 @@
|
||||||
#ifdef LINT
|
#ifdef LINT
|
||||||
|
|
||||||
#include <alloc.h> /* for st_free */
|
#include <alloc.h> /* for st_free */
|
||||||
|
#include "interface.h"
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
|
#include "debug.h"
|
||||||
#include "arith.h" /* definition arith */
|
#include "arith.h" /* definition arith */
|
||||||
#include "label.h" /* definition label */
|
#include "label.h" /* definition label */
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
|
@ -38,15 +40,29 @@ extern int func_notypegiven;
|
||||||
extern char loptions[];
|
extern char loptions[];
|
||||||
|
|
||||||
/* global variables for the lint_stack */
|
/* global variables for the lint_stack */
|
||||||
struct lint_stack_entry stack_bottom;
|
PRIVATE struct lint_stack_entry stack_bottom;
|
||||||
struct lint_stack_entry *top_ls = &stack_bottom;
|
PRIVATE struct lint_stack_entry *top_ls = &stack_bottom;
|
||||||
|
|
||||||
/* global variables for the brace stack */
|
/* global variables for the brace stack */
|
||||||
int brace_count;
|
PRIVATE int brace_count;
|
||||||
struct brace brace_bottom;
|
PRIVATE struct brace brace_bottom;
|
||||||
struct brace *top_br = &brace_bottom;
|
PRIVATE struct brace *top_br = &brace_bottom;
|
||||||
|
|
||||||
static print_autos();
|
PRIVATE end_brace();
|
||||||
|
PRIVATE lint_1_local();
|
||||||
|
PRIVATE lint_1_global();
|
||||||
|
PRIVATE check_autos();
|
||||||
|
PRIVATE struct auto_def *copy_st_auto_list();
|
||||||
|
PRIVATE free_st_auto_list();
|
||||||
|
PRIVATE struct state *copy_state();
|
||||||
|
PRIVATE Free_state();
|
||||||
|
PRIVATE remove_settings();
|
||||||
|
PRIVATE struct auto_def *merge_autos();
|
||||||
|
PRIVATE merge_states();
|
||||||
|
PRIVATE struct lint_stack_entry *find_wdf(), *find_wdfc(), *find_cs();
|
||||||
|
PRIVATE cont_break_merge();
|
||||||
|
PRIVATE lint_push();
|
||||||
|
PRIVATE lint_pop();
|
||||||
|
|
||||||
lint_init_stack()
|
lint_init_stack()
|
||||||
{
|
{
|
||||||
|
@ -90,6 +106,7 @@ lint_local_level(stl)
|
||||||
end_brace(stl);
|
end_brace(stl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRIVATE
|
||||||
end_brace(stl)
|
end_brace(stl)
|
||||||
struct stack_level *stl;
|
struct stack_level *stl;
|
||||||
{
|
{
|
||||||
|
@ -113,6 +130,7 @@ end_brace(stl)
|
||||||
free_brace(br);
|
free_brace(br);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRIVATE
|
||||||
lint_1_local(idf, def)
|
lint_1_local(idf, def)
|
||||||
struct idf *idf;
|
struct idf *idf;
|
||||||
struct def *def;
|
struct def *def;
|
||||||
|
@ -158,6 +176,7 @@ lint_global_level(stl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRIVATE
|
||||||
lint_1_global(idf, def)
|
lint_1_global(idf, def)
|
||||||
struct idf *idf;
|
struct idf *idf;
|
||||||
struct def *def;
|
struct def *def;
|
||||||
|
@ -219,6 +238,7 @@ lint_1_global(idf, def)
|
||||||
|
|
||||||
change_state(idf, to_state)
|
change_state(idf, to_state)
|
||||||
struct idf *idf;
|
struct idf *idf;
|
||||||
|
int to_state; /* SET or USED */
|
||||||
{
|
{
|
||||||
/* Changes the state of the variable identified by idf in the current state
|
/* Changes the state of the variable identified by idf in the current state
|
||||||
* on top of the stack.
|
* on top of the stack.
|
||||||
|
@ -228,10 +248,14 @@ change_state(idf, to_state)
|
||||||
register struct auto_def *a = top_ls->ls_current->st_auto_list;
|
register struct auto_def *a = top_ls->ls_current->st_auto_list;
|
||||||
|
|
||||||
if (def) {
|
if (def) {
|
||||||
if (to_state == SET)
|
switch (to_state) {
|
||||||
|
case SET:
|
||||||
def->df_set = 1;
|
def->df_set = 1;
|
||||||
else
|
break;
|
||||||
|
case USED:
|
||||||
def->df_used = 1;
|
def->df_used = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (def->df_firstbrace == 0) {
|
if (def->df_firstbrace == 0) {
|
||||||
def->df_firstbrace = brace_count;
|
def->df_firstbrace = brace_count;
|
||||||
|
@ -256,20 +280,22 @@ change_state(idf, to_state)
|
||||||
if (a == 0) /* identifier not in list */
|
if (a == 0) /* identifier not in list */
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (to_state == SET) {
|
switch (to_state) {
|
||||||
|
case SET:
|
||||||
a->ad_maybe_set = 0;
|
a->ad_maybe_set = 0;
|
||||||
a->ad_set = 1;
|
a->ad_set = 1;
|
||||||
return;
|
break;
|
||||||
|
case USED:
|
||||||
|
if (!a->ad_set) {
|
||||||
|
warning("%s%s uninitialized", idf->id_text,
|
||||||
|
(a->ad_maybe_set ? " possibly" : "")
|
||||||
|
);
|
||||||
|
a->ad_maybe_set = 0;
|
||||||
|
a->ad_set = 1; /* one warning */
|
||||||
|
}
|
||||||
|
a->ad_used = 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
/* else to_state == USED */
|
|
||||||
if (!a->ad_set) {
|
|
||||||
warning("%s%s uninitialized", idf->id_text,
|
|
||||||
(a->ad_maybe_set ? " possibly" : "")
|
|
||||||
);
|
|
||||||
a->ad_maybe_set = 0;
|
|
||||||
a->ad_set = 1; /* one warning */
|
|
||||||
}
|
|
||||||
a->ad_used = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern struct stack_level *local_level;
|
extern struct stack_level *local_level;
|
||||||
|
@ -301,6 +327,7 @@ add_auto(idf) /* to current state on top of lint_stack */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRIVATE
|
||||||
check_autos()
|
check_autos()
|
||||||
{
|
{
|
||||||
/* Before leaving a block remove the auto_defs of the automatic
|
/* Before leaving a block remove the auto_defs of the automatic
|
||||||
|
@ -348,7 +375,7 @@ check_args_used()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct auto_def *
|
PRIVATE struct auto_def *
|
||||||
copy_st_auto_list(from_al, lvl)
|
copy_st_auto_list(from_al, lvl)
|
||||||
struct auto_def *from_al;
|
struct auto_def *from_al;
|
||||||
{
|
{
|
||||||
|
@ -370,6 +397,7 @@ copy_st_auto_list(from_al, lvl)
|
||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRIVATE
|
||||||
free_st_auto_list(au)
|
free_st_auto_list(au)
|
||||||
register struct auto_def *au;
|
register struct auto_def *au;
|
||||||
{
|
{
|
||||||
|
@ -382,7 +410,7 @@ free_st_auto_list(au)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct state *
|
PRIVATE struct state *
|
||||||
copy_state(from_st, lvl)
|
copy_state(from_st, lvl)
|
||||||
struct state *from_st;
|
struct state *from_st;
|
||||||
{
|
{
|
||||||
|
@ -397,7 +425,7 @@ copy_state(from_st, lvl)
|
||||||
return st;
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
PRIVATE
|
||||||
Free_state(stp)
|
Free_state(stp)
|
||||||
struct state **stp;
|
struct state **stp;
|
||||||
{
|
{
|
||||||
|
@ -408,6 +436,7 @@ Free_state(stp)
|
||||||
*stp = 0;
|
*stp = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRIVATE
|
||||||
remove_settings(state, lvl)
|
remove_settings(state, lvl)
|
||||||
struct state *state;
|
struct state *state;
|
||||||
{
|
{
|
||||||
|
@ -430,7 +459,7 @@ remove_settings(state, lvl)
|
||||||
#define CASE_BREAK 1
|
#define CASE_BREAK 1
|
||||||
#define USE_ONLY 2
|
#define USE_ONLY 2
|
||||||
|
|
||||||
struct auto_def *
|
PRIVATE struct auto_def *
|
||||||
merge_autos(a1, a2, lvl, mode)
|
merge_autos(a1, a2, lvl, mode)
|
||||||
struct auto_def *a1, *a2;
|
struct auto_def *a1, *a2;
|
||||||
int mode;
|
int mode;
|
||||||
|
@ -491,6 +520,7 @@ merge_autos(a1, a2, lvl, mode)
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRIVATE
|
||||||
merge_states(st1, st2, lvl, mode)
|
merge_states(st1, st2, lvl, mode)
|
||||||
struct state *st1, *st2;
|
struct state *st1, *st2;
|
||||||
int mode;
|
int mode;
|
||||||
|
@ -532,7 +562,7 @@ merge_states(st1, st2, lvl, mode)
|
||||||
* The letters mean : w: WHILE; d: DO; f: FOR; s: SWITCH; c: CASE.
|
* The letters mean : w: WHILE; d: DO; f: FOR; s: SWITCH; c: CASE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct lint_stack_entry *
|
PRIVATE struct lint_stack_entry *
|
||||||
find_wdf()
|
find_wdf()
|
||||||
{
|
{
|
||||||
register struct lint_stack_entry *lse = top_ls;
|
register struct lint_stack_entry *lse = top_ls;
|
||||||
|
@ -549,7 +579,7 @@ find_wdf()
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct lint_stack_entry *
|
PRIVATE struct lint_stack_entry *
|
||||||
find_wdfc()
|
find_wdfc()
|
||||||
{
|
{
|
||||||
register struct lint_stack_entry *lse = top_ls;
|
register struct lint_stack_entry *lse = top_ls;
|
||||||
|
@ -567,7 +597,7 @@ find_wdfc()
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct lint_stack_entry *
|
PRIVATE struct lint_stack_entry *
|
||||||
find_cs()
|
find_cs()
|
||||||
{
|
{
|
||||||
register struct lint_stack_entry *lse = top_ls;
|
register struct lint_stack_entry *lse = top_ls;
|
||||||
|
@ -691,6 +721,7 @@ end_do_stmt(const, cond)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRIVATE
|
||||||
cont_break_merge(lse)
|
cont_break_merge(lse)
|
||||||
struct lint_stack_entry *lse;
|
struct lint_stack_entry *lse;
|
||||||
{
|
{
|
||||||
|
@ -988,7 +1019,7 @@ lint_statement()
|
||||||
return;
|
return;
|
||||||
if (top_ls->ls_current->st_notreached) {
|
if (top_ls->ls_current->st_notreached) {
|
||||||
if (DOT != CASE && DOT != DEFAULT && AHEAD != ':') {
|
if (DOT != CASE && DOT != DEFAULT && AHEAD != ':') {
|
||||||
if (DOT != BREAK || !loptions['b'])
|
if (DOT != BREAK || loptions['b'])
|
||||||
warning("statement cannot be reached");
|
warning("statement cannot be reached");
|
||||||
top_ls->ls_current->st_warned = 1;
|
top_ls->ls_current->st_warned = 1;
|
||||||
}
|
}
|
||||||
|
@ -999,6 +1030,7 @@ lint_statement()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRIVATE
|
||||||
lint_push(lse)
|
lint_push(lse)
|
||||||
struct lint_stack_entry *lse;
|
struct lint_stack_entry *lse;
|
||||||
{
|
{
|
||||||
|
@ -1007,13 +1039,14 @@ lint_push(lse)
|
||||||
top_ls = lse;
|
top_ls = lse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRIVATE
|
||||||
lint_pop()
|
lint_pop()
|
||||||
{
|
{
|
||||||
top_ls = top_ls->ls_previous;
|
top_ls = top_ls->ls_previous;
|
||||||
free_lint_stack_entry(top_ls->next);
|
free_lint_stack_entry(top_ls->next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
/* FOR DEBUGGING */
|
/* FOR DEBUGGING */
|
||||||
|
|
||||||
print_lint_stack()
|
print_lint_stack()
|
||||||
|
@ -1082,7 +1115,6 @@ print_lint_stack()
|
||||||
print(" |--------------\n\n");
|
print(" |--------------\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
|
||||||
print_autos(a)
|
print_autos(a)
|
||||||
register struct auto_def *a;
|
register struct auto_def *a;
|
||||||
{
|
{
|
||||||
|
@ -1094,4 +1126,6 @@ print_autos(a)
|
||||||
}
|
}
|
||||||
print("\n");
|
print("\n");
|
||||||
}
|
}
|
||||||
|
#endif DEBUG
|
||||||
|
|
||||||
#endif LINT
|
#endif LINT
|
||||||
|
|
Loading…
Reference in a new issue