l_lint.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  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$ */
  6. /* Lint main routines */
  7. #include "lint.h"
  8. #ifdef LINT
  9. #include <alloc.h> /* for st_free */
  10. #include "debug.h"
  11. #include "interface.h"
  12. #include "assert.h"
  13. #ifdef ANSI
  14. #include <flt_arith.h>
  15. #endif /* ANSI */
  16. #include "arith.h" /* definition arith */
  17. #include "label.h" /* definition label */
  18. #include "expr.h"
  19. #include "idf.h"
  20. #include "def.h"
  21. #include "code.h" /* RVAL etc */
  22. #include "LLlex.h"
  23. #include "Lpars.h"
  24. #include "stack.h"
  25. #include "type.h"
  26. #include "level.h"
  27. #include "l_lint.h"
  28. #include "l_state.h"
  29. #include "l_outdef.h"
  30. extern char options[128];
  31. extern char *symbol2str();
  32. PRIVATE struct expr_state *expr2state();
  33. PRIVATE struct expr_state *value2state();
  34. PRIVATE struct expr_state *oper2state();
  35. PRIVATE expr_ignored();
  36. PRIVATE add_expr_state();
  37. PRIVATE referred_esp();
  38. PRIVATE free_expr_states();
  39. lint_init()
  40. {
  41. lint_init_comment();
  42. lint_init_stack();
  43. }
  44. lint_expr(expr, used)
  45. struct expr *expr;
  46. int used; /* USED or IGNORED */
  47. {
  48. register struct expr_state *esp;
  49. esp = expr2state(expr, RVAL, used);
  50. referred_esp(esp);
  51. free_expr_states(esp);
  52. }
  53. PRIVATE struct expr_state *
  54. expr2state(expr, val, used)
  55. register struct expr *expr;
  56. int val; /* RVAL or LVAL */
  57. int used; /* USED or IGNORED */
  58. {
  59. /* Main function to process an expression tree.
  60. * It returns a structure containing information about which variables
  61. * are set and which are used in the expression.
  62. * In addition it sets 'used' and 'set' fields of the corresponding
  63. * variables in the current state.
  64. * If the value of an operation without side-effects is not used,
  65. * a warning is given.
  66. */
  67. if (used == IGNORED) {
  68. expr_ignored(expr);
  69. }
  70. switch (expr->ex_class) {
  71. case Value:
  72. return value2state(expr, val);
  73. case Oper:
  74. return oper2state(expr, val, used);
  75. default: /* String, Float, Type */
  76. return 0;
  77. }
  78. }
  79. PRIVATE struct expr_state *
  80. value2state(expr, val)
  81. struct expr *expr;
  82. int val; /* RVAL or LVAL */
  83. {
  84. switch (expr->VL_CLASS) {
  85. case Const:
  86. case Label:
  87. return 0;
  88. case Name:
  89. {
  90. register struct idf *idf = expr->VL_IDF;
  91. struct expr_state *esp = 0;
  92. if (!idf || !idf->id_def)
  93. return 0;
  94. if (val == RVAL && expr->ex_lvalue == 1) {
  95. /* value of identifier used */
  96. change_state(idf, USED);
  97. add_expr_state(expr->EX_VALUE, USED, &esp);
  98. }
  99. if (val == RVAL && expr->ex_lvalue == 0) {
  100. /* address of identifier used */
  101. add_expr_state(expr->EX_VALUE, REFERRED, &esp);
  102. }
  103. return esp;
  104. }
  105. default:
  106. NOTREACHED();
  107. /* NOTREACHED */
  108. }
  109. }
  110. /* Let's get this straight.
  111. An assignment is performed by elaborating the LHS and the RHS
  112. collaterally, to use the A68 terminology, and then serially do the
  113. actual assignment. This means:
  114. 1. evaluate the LHS as an LVAL,
  115. 2. evaluate the RHS as an RVAL,
  116. 3. merge them checking for interference,
  117. 4. set the result of the LHS to SET, if it is a named variable
  118. */
  119. PRIVATE struct expr_state *
  120. oper2state(expr, val, used)
  121. struct expr *expr;
  122. int val; /* RVAL or LVAL */
  123. int used; /* USED or IGNORED */
  124. {
  125. register int oper = expr->OP_OPER;
  126. register struct expr *left = expr->OP_LEFT;
  127. register struct expr *right = expr->OP_RIGHT;
  128. struct expr_state *esp_l = 0;
  129. struct expr_state *esp_r = 0;
  130. switch (oper) {
  131. /* assignments */
  132. case '=':
  133. case PLUSAB:
  134. case MINAB:
  135. case TIMESAB:
  136. case DIVAB:
  137. case MODAB:
  138. case LEFTAB:
  139. case RIGHTAB:
  140. case ANDAB:
  141. case XORAB:
  142. case ORAB:
  143. /* evaluate the LHS, only once; see RM 7.14 */
  144. esp_l = expr2state(left, (oper == '=' ? LVAL : RVAL), USED);
  145. /* evaluate the RHS as an RVAL and merge */
  146. esp_r = expr2state(right, RVAL, USED);
  147. check_and_merge(expr, &esp_l, esp_r);
  148. /* set resulting variable, if any */
  149. if (ISNAME(left)) {
  150. change_state(left->VL_IDF, SET);
  151. add_expr_state(left->EX_VALUE, SET, &esp_l);
  152. }
  153. return esp_l;
  154. case POSTINCR:
  155. case POSTDECR:
  156. case PLUSPLUS:
  157. case MINMIN:
  158. esp_l = expr2state(left, RVAL, USED);
  159. /* set resulting variable, if any */
  160. if (ISNAME(left)) {
  161. change_state(left->VL_IDF, SET);
  162. add_expr_state(left->EX_VALUE, SET, &esp_l);
  163. }
  164. return esp_l;
  165. case '?':
  166. esp_l = expr2state(left, RVAL, USED);
  167. esp_r = expr2state(right->OP_LEFT, RVAL, USED);
  168. check_and_merge(expr, &esp_l, esp_r);
  169. esp_r = expr2state(right->OP_RIGHT, RVAL, USED);
  170. check_and_merge(expr, &esp_l, esp_r);
  171. return esp_l;
  172. case '(':
  173. if (right != 0) {
  174. /* function call with parameters */
  175. register struct expr *ex = right;
  176. while ( ex->ex_class == Oper
  177. && ex->OP_OPER == PARCOMMA
  178. ) {
  179. esp_r = expr2state(ex->OP_RIGHT, RVAL, USED);
  180. check_and_merge(expr, &esp_l, esp_r);
  181. ex = ex->OP_LEFT;
  182. }
  183. esp_r = expr2state(ex, RVAL, USED);
  184. check_and_merge(expr, &esp_l, esp_r);
  185. }
  186. if (ISNAME(left)) {
  187. fill_outcall(expr,
  188. expr->ex_type->tp_fund == VOID ?
  189. VOIDED : used
  190. );
  191. outcall();
  192. left->VL_IDF->id_def->df_used = 1;
  193. }
  194. else {
  195. esp_r = expr2state(left, RVAL, USED);
  196. check_and_merge(expr, &esp_l, esp_r);
  197. }
  198. referred_esp(esp_l);
  199. return esp_l;
  200. case '.':
  201. return expr2state(left, val, USED);
  202. case ARROW:
  203. return expr2state(left, RVAL, USED);
  204. case INT2INT:
  205. case INT2FLOAT:
  206. case FLOAT2INT:
  207. case FLOAT2FLOAT:
  208. return expr2state(right, RVAL, USED);
  209. /* monadic operators */
  210. case '-':
  211. case '*':
  212. if (left)
  213. goto dyadic;
  214. case '~':
  215. case '!':
  216. return expr2state(right, RVAL, USED);
  217. /* relational operators */
  218. case '<':
  219. case '>':
  220. case LESSEQ:
  221. case GREATEREQ:
  222. case EQUAL:
  223. case NOTEQUAL:
  224. goto dyadic;
  225. /* dyadic operators */
  226. dyadic:
  227. case '+':
  228. case '/':
  229. case '%':
  230. case ',':
  231. case LEFT:
  232. case RIGHT:
  233. case '&':
  234. case '|':
  235. case '^':
  236. case OR:
  237. case AND:
  238. esp_l = expr2state(left, RVAL,
  239. oper == ',' ? IGNORED : USED);
  240. esp_r = expr2state(right, RVAL,
  241. oper == ',' ? used : USED);
  242. check_and_merge(expr, &esp_l, esp_r);
  243. return esp_l;
  244. default:
  245. return 0; /* for initcomma */
  246. }
  247. }
  248. PRIVATE
  249. expr_ignored(expr)
  250. struct expr *expr;
  251. {
  252. switch (expr->ex_class) {
  253. int oper;
  254. case Oper:
  255. oper = expr->OP_OPER;
  256. switch (oper) {
  257. case '=':
  258. case TIMESAB:
  259. case DIVAB:
  260. case MODAB:
  261. case LEFTAB:
  262. case RIGHTAB:
  263. case ANDAB:
  264. case XORAB:
  265. case ORAB:
  266. case AND: /* doubtful but useful */
  267. case OR: /* doubtful but useful */
  268. case '(':
  269. case '?':
  270. case ',':
  271. oper = 0; /* ignore the ignoring */
  272. break;
  273. case PLUSAB:
  274. case MINAB:
  275. case POSTINCR:
  276. case POSTDECR:
  277. case PLUSPLUS:
  278. case MINMIN:
  279. oper = 0; /* ignore in priciple */
  280. /* may, however, hide the operator '*' */
  281. if ( /* operation on a pointer */
  282. expr->OP_TYPE->tp_fund == POINTER
  283. && /* the result is dereferenced, e.g. *p++; */
  284. expr->ex_type == expr->OP_TYPE->tp_up
  285. ) {
  286. oper = '*';
  287. }
  288. break;
  289. case '/':
  290. /* this is a specially weird case: the '/' may
  291. result from pointer subtraction
  292. */
  293. if ( expr->OP_TYPE->tp_fund == INT
  294. && expr->OP_LEFT->OP_OPER == '-'
  295. && expr->OP_LEFT->OP_TYPE->tp_fund == POINTER
  296. ) {
  297. oper = '-';
  298. }
  299. break;
  300. }
  301. if (oper) {
  302. hwarning("result of %s ignored", symbol2str(oper));
  303. }
  304. break;
  305. case Value:
  306. if (expr->VL_CLASS == Const) {
  307. hwarning("constant expression ignored");
  308. }
  309. else {
  310. hwarning("value ignored");
  311. }
  312. break;
  313. default: /* String Float */
  314. hwarning("constant ignored");
  315. break;
  316. }
  317. }
  318. PRIVATE
  319. add_expr_state(value, to_state, espp)
  320. struct value value;
  321. struct expr_state **espp;
  322. {
  323. register struct expr_state *esp = *espp;
  324. ASSERT(value.vl_class == Name);
  325. /* try to find the esp */
  326. while ( esp
  327. && !( esp->es_idf == value.vl_data.vl_idf
  328. && esp->es_offset == value.vl_value
  329. )
  330. ) {
  331. esp = esp->next;
  332. }
  333. /* if not found, add it */
  334. if (!esp) {
  335. esp = new_expr_state();
  336. esp->es_idf = value.vl_data.vl_idf;
  337. esp->es_offset = value.vl_value;
  338. esp->next = *espp;
  339. *espp = esp;
  340. }
  341. /* set state */
  342. switch (to_state) {
  343. case USED:
  344. esp->es_used = 1;
  345. break;
  346. case REFERRED:
  347. esp->es_referred = 1;
  348. break;
  349. case SET:
  350. esp->es_set = 1;
  351. break;
  352. default:
  353. NOTREACHED();
  354. /* NOTREACHED */
  355. }
  356. }
  357. PRIVATE
  358. referred_esp(esp)
  359. struct expr_state *esp;
  360. {
  361. /* raises all REFERRED items to SET and USED status */
  362. while (esp) {
  363. if (esp->es_referred) {
  364. esp->es_set = 1;
  365. change_state(esp->es_idf, SET);
  366. esp->es_used = 1;
  367. change_state(esp->es_idf, USED);
  368. esp->es_referred = 0;
  369. }
  370. esp = esp->next;
  371. }
  372. }
  373. PRIVATE
  374. free_expr_states(esp)
  375. register struct expr_state *esp;
  376. {
  377. while (esp) {
  378. register struct expr_state *esp2 = esp;
  379. esp = esp->next;
  380. free_expr_state(esp2);
  381. }
  382. }
  383. #ifdef DEBUG
  384. print_esp(msg, esp)
  385. char *msg;
  386. struct expr_state *esp;
  387. {
  388. print("%s: <", msg);
  389. while (esp) {
  390. print(" %s[%d]%c%c%c ",
  391. esp->es_idf->id_text, esp->es_offset,
  392. (esp->es_used ? 'U' : ' '),
  393. (esp->es_referred ? 'R' : ' '),
  394. (esp->es_set ? 'S' : ' ')
  395. );
  396. esp = esp->next;
  397. }
  398. print(">\n");
  399. }
  400. #endif /* DEBUG */
  401. #endif /* LINT */