2 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
3 * See the copyright notice in the ACK home directory, in the file "Copyright".
5 /* $Id: l_lint.c,v 1.5 1994/06/27 08:00:52 ceriel Exp $ */
6 /* Lint main routines */
12 #include <alloc.h> /* for st_free */
14 #include "interface.h"
17 #include <flt_arith.h>
19 #include "arith.h" /* definition arith */
20 #include "label.h" /* definition label */
24 #include "code.h" /* RVAL etc */
34 extern char options[128];
35 extern char *symbol2str();
37 PRIVATE struct expr_state *expr2state();
38 PRIVATE struct expr_state *value2state();
39 PRIVATE struct expr_state *oper2state();
40 PRIVATE expr_ignored();
41 PRIVATE add_expr_state();
42 PRIVATE referred_esp();
43 PRIVATE free_expr_states();
53 int used; /* USED or IGNORED */
55 register struct expr_state *esp;
57 esp = expr2state(expr, RVAL, used);
59 free_expr_states(esp);
62 PRIVATE struct expr_state *
63 expr2state(expr, val, used)
64 register struct expr *expr;
65 int val; /* RVAL or LVAL */
66 int used; /* USED or IGNORED */
68 /* Main function to process an expression tree.
69 * It returns a structure containing information about which variables
70 * are set and which are used in the expression.
71 * In addition it sets 'used' and 'set' fields of the corresponding
72 * variables in the current state.
73 * If the value of an operation without side-effects is not used,
76 if (used == IGNORED) {
80 switch (expr->ex_class) {
82 return value2state(expr, val);
85 return oper2state(expr, val, used);
87 default: /* String, Float, Type */
92 PRIVATE struct expr_state *
93 value2state(expr, val)
95 int val; /* RVAL or LVAL */
97 switch (expr->VL_CLASS) {
104 register struct idf *idf = expr->VL_IDF;
105 struct expr_state *esp = 0;
107 if (!idf || !idf->id_def)
110 if (val == RVAL && expr->ex_lvalue == 1) {
111 /* value of identifier used */
112 change_state(idf, USED);
113 add_expr_state(expr->EX_VALUE, USED, &esp);
115 if (val == RVAL && expr->ex_lvalue == 0) {
116 /* address of identifier used */
117 add_expr_state(expr->EX_VALUE, REFERRED, &esp);
128 /* Let's get this straight.
129 An assignment is performed by elaborating the LHS and the RHS
130 collaterally, to use the A68 terminology, and then serially do the
131 actual assignment. This means:
132 1. evaluate the LHS as an LVAL,
133 2. evaluate the RHS as an RVAL,
134 3. merge them checking for interference,
135 4. set the result of the LHS to SET, if it is a named variable
138 PRIVATE struct expr_state *
139 oper2state(expr, val, used)
141 int val; /* RVAL or LVAL */
142 int used; /* USED or IGNORED */
144 register int oper = expr->OP_OPER;
145 register struct expr *left = expr->OP_LEFT;
146 register struct expr *right = expr->OP_RIGHT;
147 struct expr_state *esp_l = 0;
148 struct expr_state *esp_r = 0;
164 /* evaluate the LHS, only once; see RM 7.14 */
165 esp_l = expr2state(left, (oper == '=' ? LVAL : RVAL), USED);
167 /* evaluate the RHS as an RVAL and merge */
168 esp_r = expr2state(right, RVAL, USED);
169 check_and_merge(expr, &esp_l, esp_r);
171 /* set resulting variable, if any */
173 change_state(left->VL_IDF, SET);
174 add_expr_state(left->EX_VALUE, SET, &esp_l);
183 esp_l = expr2state(left, RVAL, USED);
185 /* set resulting variable, if any */
187 change_state(left->VL_IDF, SET);
188 add_expr_state(left->EX_VALUE, SET, &esp_l);
194 esp_l = expr2state(left, RVAL, USED);
195 esp_r = expr2state(right->OP_LEFT, RVAL, USED);
196 check_and_merge(expr, &esp_l, esp_r);
197 esp_r = expr2state(right->OP_RIGHT, RVAL, USED);
198 check_and_merge(expr, &esp_l, esp_r);
203 /* function call with parameters */
204 register struct expr *ex = right;
206 while ( ex->ex_class == Oper
207 && ex->OP_OPER == PARCOMMA
209 esp_r = expr2state(ex->OP_RIGHT, RVAL, USED);
210 check_and_merge(expr, &esp_l, esp_r);
213 esp_r = expr2state(ex, RVAL, USED);
214 check_and_merge(expr, &esp_l, esp_r);
219 expr->ex_type->tp_fund == VOID ?
223 left->VL_IDF->id_def->df_used = 1;
226 esp_r = expr2state(left, RVAL, USED);
227 check_and_merge(expr, &esp_l, esp_r);
233 return expr2state(left, val, USED);
236 return expr2state(left, RVAL, USED);
242 return expr2state(right, RVAL, USED);
244 /* monadic operators */
251 return expr2state(right, RVAL, USED);
253 /* relational operators */
262 /* dyadic operators */
275 esp_l = expr2state(left, RVAL,
276 oper == ',' ? IGNORED : USED);
277 esp_r = expr2state(right, RVAL,
278 oper == ',' ? used : USED);
279 check_and_merge(expr, &esp_l, esp_r);
284 return 0; /* for initcomma */
292 switch (expr->ex_class) {
295 oper = expr->OP_OPER;
306 case AND: /* doubtful but useful */
307 case OR: /* doubtful but useful */
311 oper = 0; /* ignore the ignoring */
320 oper = 0; /* ignore in priciple */
321 /* may, however, hide the operator '*' */
322 if ( /* operation on a pointer */
323 expr->OP_TYPE->tp_fund == POINTER
324 && /* the result is dereferenced, e.g. *p++; */
325 expr->ex_type == expr->OP_TYPE->tp_up
332 /* this is a specially weird case: the '/' may
333 result from pointer subtraction
335 if ( expr->OP_TYPE->tp_fund == INT
336 && expr->OP_LEFT->OP_OPER == '-'
337 && expr->OP_LEFT->OP_TYPE->tp_fund == POINTER
344 hwarning("result of %s ignored", symbol2str(oper));
349 if (expr->VL_CLASS == Const) {
350 hwarning("constant expression ignored");
353 hwarning("value ignored");
357 default: /* String Float */
358 hwarning("constant ignored");
364 add_expr_state(value, to_state, espp)
366 struct expr_state **espp;
368 register struct expr_state *esp = *espp;
370 ASSERT(value.vl_class == Name);
372 /* try to find the esp */
374 && !( esp->es_idf == value.vl_data.vl_idf
375 && esp->es_offset == value.vl_value
381 /* if not found, add it */
383 esp = new_expr_state();
384 esp->es_idf = value.vl_data.vl_idf;
385 esp->es_offset = value.vl_value;
396 esp->es_referred = 1;
409 struct expr_state *esp;
411 /* raises all REFERRED items to SET and USED status */
413 if (esp->es_referred) {
415 change_state(esp->es_idf, SET);
417 change_state(esp->es_idf, USED);
418 esp->es_referred = 0;
425 free_expr_states(esp)
426 register struct expr_state *esp;
429 register struct expr_state *esp2 = esp;
432 free_expr_state(esp2);
439 struct expr_state *esp;
443 print(" %s[%d]%c%c%c ",
444 esp->es_idf->id_text, esp->es_offset,
445 (esp->es_used ? 'U' : ' '),
446 (esp->es_referred ? 'R' : ' '),
447 (esp->es_set ? 'S' : ' ')