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