Pristine Ack-5.5
[Ack-5.5.git] / lang / cem / cemcom / l_lint.c
1 /*
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".
4  */
5 /* $Id: l_lint.c,v 3.11 1994/06/24 12:04:40 ceriel Exp $ */
6 /*      Lint main routines      */
7
8 #include        "lint.h"
9
10 #ifdef  LINT
11
12 #include        <alloc.h>       /* for st_free */
13 #include        "debug.h"
14 #include        "interface.h"
15 #include        "assert.h"
16 #ifdef ANSI
17 #include        <flt_arith.h>
18 #endif /* ANSI */
19 #include        "arith.h"       /* definition arith */
20 #include        "label.h"       /* definition label */
21 #include        "expr.h"
22 #include        "idf.h"
23 #include        "def.h"
24 #include        "code.h"        /* RVAL etc */
25 #include        "LLlex.h"
26 #include        "Lpars.h"
27 #include        "stack.h"
28 #include        "type.h"
29 #include        "level.h"
30 #include        "l_lint.h"
31 #include        "l_state.h"
32 #include        "l_outdef.h"
33
34 extern char options[128];
35 extern char *symbol2str();
36
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();
44
45 lint_init()
46 {
47         lint_init_comment();
48         lint_init_stack();
49 }
50
51 lint_expr(expr, used)
52         struct expr *expr;
53         int used;                       /* USED or IGNORED */
54 {
55         register struct expr_state *esp;
56
57         esp = expr2state(expr, RVAL, used);
58         referred_esp(esp);
59         free_expr_states(esp);
60 }
61
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 */
67 {
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,
74  * a warning is given.
75  */
76         if (used == IGNORED) {
77                 expr_ignored(expr);
78         }
79
80         switch (expr->ex_class) {
81         case Value:
82                 return value2state(expr, val);
83
84         case Oper:
85                 return oper2state(expr, val, used);
86
87         default:                        /* String, Float, Type */
88                 return 0;
89         }
90 }
91
92 PRIVATE struct expr_state *
93 value2state(expr, val)
94         struct expr *expr;
95         int val;                        /* RVAL or LVAL */
96 {
97         switch (expr->VL_CLASS) {
98         case Const:
99         case Label:
100                 return 0;
101
102         case Name:
103         {
104                 register struct idf *idf = expr->VL_IDF;
105                 struct expr_state *esp = 0;
106
107                 if (!idf || !idf->id_def)
108                         return 0;
109
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);
114                 }
115                 if (val == RVAL && expr->ex_lvalue == 0) {
116                         /* address of identifier used */
117                         add_expr_state(expr->EX_VALUE, REFERRED, &esp);
118                 }
119                 return esp;
120         }
121
122         default:
123                 NOTREACHED();
124                 /* NOTREACHED */
125         }
126 }
127
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
136 */
137
138 PRIVATE struct expr_state *
139 oper2state(expr, val, used)
140         struct expr *expr;
141         int val;                        /* RVAL or LVAL */
142         int used;                       /* USED or IGNORED */
143 {
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;
149
150         switch (oper) {
151
152         /* assignments */
153         case '=':
154         case PLUSAB:
155         case MINAB:
156         case TIMESAB:
157         case DIVAB:
158         case MODAB:
159         case LEFTAB:
160         case RIGHTAB:
161         case ANDAB:
162         case XORAB:
163         case ORAB:
164                 /* evaluate the LHS, only once; see RM 7.14 */
165                 esp_l = expr2state(left, (oper == '=' ? LVAL : RVAL), USED);
166
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);
170
171                 /* set resulting variable, if any */
172                 if (ISNAME(left)) {
173                         change_state(left->VL_IDF, SET);
174                         add_expr_state(left->EX_VALUE, SET, &esp_l);
175                 }
176
177                 return esp_l;
178
179         case POSTINCR:
180         case POSTDECR:
181         case PLUSPLUS:
182         case MINMIN:
183                 esp_l = expr2state(left, RVAL, USED);
184
185                 /* set resulting variable, if any */
186                 if (ISNAME(left)) {
187                         change_state(left->VL_IDF, SET);
188                         add_expr_state(left->EX_VALUE, SET, &esp_l);
189                 }
190
191                 return esp_l;
192
193         case '?':
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);
199                 return esp_l;
200
201         case '(':
202                 if (right != 0) {
203                         /* function call with parameters */
204                         register struct expr *ex = right;
205
206                         while ( ex->ex_class == Oper
207                         &&      ex->OP_OPER == PARCOMMA
208                         ) {
209                                 esp_r = expr2state(ex->OP_RIGHT, RVAL, USED);
210                                 check_and_merge(expr, &esp_l, esp_r);
211                                 ex = ex->OP_LEFT;
212                         }
213                         esp_r = expr2state(ex, RVAL, USED);
214                         check_and_merge(expr, &esp_l, esp_r);
215                 }
216
217                 if (ISNAME(left)) {
218                         fill_outcall(expr,
219                                 expr->ex_type->tp_fund == VOID ?
220                                 VOIDED : used
221                         );
222                         outcall();
223                         left->VL_IDF->id_def->df_used = 1;
224                 }
225                 else {
226                         esp_r = expr2state(left, RVAL, USED);
227                         check_and_merge(expr, &esp_l, esp_r);
228                 }
229                 referred_esp(esp_l);
230                 return esp_l;
231
232         case '.':
233                 return expr2state(left, val, USED);
234
235         case ARROW:
236                 return expr2state(left, RVAL, USED);
237
238         case INT2INT:
239         case INT2FLOAT:
240         case FLOAT2INT:
241         case FLOAT2FLOAT:
242                 return expr2state(right, RVAL, USED);
243
244         /* monadic operators */
245         case '-':
246         case '*':
247                 if (left)
248                         goto dyadic;
249         case '~':
250         case '!':
251                 return expr2state(right, RVAL, USED);
252
253         /* relational operators */
254         case '<':
255         case '>':
256         case LESSEQ:
257         case GREATEREQ:
258         case EQUAL:
259         case NOTEQUAL:
260                 goto dyadic;
261
262         /* dyadic operators */
263         dyadic:
264         case '+':
265         case '/':
266         case '%':
267         case ',':
268         case LEFT:
269         case RIGHT:
270         case '&':
271         case '|':
272         case '^':
273         case OR:
274         case AND:
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);
280
281                 return esp_l;
282
283         default:
284                 return 0;       /* for initcomma */
285         }
286 }
287
288 PRIVATE
289 expr_ignored(expr)
290         struct expr *expr;
291 {
292         switch (expr->ex_class) {
293                 int oper;
294         case Oper:
295                 oper = expr->OP_OPER;
296                 switch (oper) {
297                 case '=':
298                 case TIMESAB:
299                 case DIVAB:
300                 case MODAB:
301                 case LEFTAB:
302                 case RIGHTAB:
303                 case ANDAB:
304                 case XORAB:
305                 case ORAB:
306                 case AND:                       /* doubtful but useful */
307                 case OR:                        /* doubtful but useful */
308                 case '(':
309                 case '?':
310                 case ',':
311                         oper = 0;               /* ignore the ignoring */
312                         break;
313
314                 case PLUSAB:
315                 case MINAB:
316                 case POSTINCR:
317                 case POSTDECR:
318                 case PLUSPLUS:
319                 case MINMIN:
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
326                         ) {
327                                 oper = '*';
328                         }
329                         break;
330
331                 case '/':
332                         /*      this is a specially weird case: the '/' may
333                                 result from pointer subtraction
334                         */
335                         if (    expr->OP_TYPE->tp_fund == INT
336                         &&      expr->OP_LEFT->OP_OPER == '-'
337                         &&      expr->OP_LEFT->OP_TYPE->tp_fund == POINTER
338                         ) {
339                                 oper = '-';
340                         }
341                         break;
342                 }
343                 if (oper) {
344                         hwarning("result of %s ignored", symbol2str(oper));
345                 }
346                 break;
347
348         case Value:
349                 if (expr->VL_CLASS == Const) {
350                         hwarning("constant expression ignored");
351                 }
352                 else {
353                         hwarning("value ignored");
354                 }
355                 break;
356
357         default:                        /* String Float */
358                 hwarning("constant ignored");
359                 break;
360         }
361 }
362
363 PRIVATE
364 add_expr_state(value, to_state, espp)
365         struct value value;
366         struct expr_state **espp;
367 {
368         register struct expr_state *esp = *espp;
369
370         ASSERT(value.vl_class == Name);
371
372         /* try to find the esp */
373         while ( esp
374         &&      !(      esp->es_idf == value.vl_data.vl_idf
375                 &&      esp->es_offset == value.vl_value
376                 )
377         ) {
378                 esp = esp->next;
379         }
380
381         /* if not found, add it */
382         if (!esp) {
383                 esp = new_expr_state();
384                 esp->es_idf = value.vl_data.vl_idf;
385                 esp->es_offset = value.vl_value;
386                 esp->next = *espp;
387                 *espp = esp;
388         }
389
390         /* set state */
391         switch (to_state) {
392         case USED:
393                 esp->es_used = 1;
394                 break;
395         case REFERRED:
396                 esp->es_referred = 1;
397                 break;
398         case SET:
399                 esp->es_set = 1;
400                 break;
401         default:
402                 NOTREACHED();
403                 /* NOTREACHED */
404         }
405 }
406
407 PRIVATE
408 referred_esp(esp)
409         struct expr_state *esp;
410 {
411         /* raises all REFERRED items to SET and USED status */
412         while (esp) {
413                 if (esp->es_referred) {
414                         esp->es_set = 1;
415                         change_state(esp->es_idf, SET);
416                         esp->es_used = 1;
417                         change_state(esp->es_idf, USED);
418                         esp->es_referred = 0;
419                 }
420                 esp = esp->next;
421         }
422 }
423
424 PRIVATE
425 free_expr_states(esp)
426         register struct expr_state *esp;
427 {
428         while (esp) {
429                 register struct expr_state *esp2 = esp;
430
431                 esp = esp->next;
432                 free_expr_state(esp2);
433         }
434 }
435
436 #ifdef  DEBUG
437 print_esp(msg, esp)
438         char *msg;
439         struct expr_state *esp;
440 {
441         print("%s: <", msg);
442         while (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' : ' ')
448                 );
449                 esp = esp->next;
450         }
451         print(">\n");
452 }
453 #endif  /* DEBUG */
454
455 #endif  /* LINT */