123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
- /*
- * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
- * See the copyright notice in the ACK home directory, in the file "Copyright".
- */
- /* $Header$ */
- /* Lint main routines */
- #include "lint.h"
- #ifdef LINT
- #include <alloc.h> /* for st_free */
- #include "arith.h" /* definition arith */
- #include "label.h" /* definition label */
- #include "expr.h"
- #include "idf.h"
- #include "def.h"
- #include "code.h" /* RVAL etc */
- #include "LLlex.h"
- #include "Lpars.h"
- #include "stack.h"
- #include "type.h"
- #include "level.h"
- #include "nofloat.h"
- #include "l_lint.h"
- #include "l_state.h"
- #include "l_outdef.h"
- extern char options[128];
- extern char *symbol2str();
- struct expr_state *lint_expr();
- lint_init()
- {
- /* Allocate some memory for the global stack_bottom
- * and some other initializations
- */
- extern struct lint_stack_entry stack_bottom;
- stack_bottom.ls_current = new_state();
- }
- pre_lint_expr(expr, val, used)
- struct expr *expr;
- {
- /* Introduced to dispose the returned expression states */
- register struct expr_state *esp;
- esp = lint_expr(expr, val, used);
- 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);
- }
- }
- struct expr_state *
- lint_expr(expr, val, used)
- register struct expr *expr;
- {
- /* Main function to process an expression tree.
- * It returns a structure containing information about which variables
- * are set and which are used in the expression.
- * In addition it sets 'used' and 'set' fields of the corresponding
- * variables in the current state.
- * If the value of an operation without side-effects is not used,
- * a warning is given.
- */
- struct expr_state *esp1 = 0, *esp2 = 0;
- if (used == IGNORED) {
- expr_ignored(expr);
- }
- switch (expr->ex_class) {
- case Value:
- switch (expr->VL_CLASS) {
- case Const:
- case Label:
- return(0);
- case Name:
- {
- register struct idf *idf = expr->VL_IDF;
- 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) {
- change_state(idf, USED);
- add_expr_state(expr->EX_VALUE, USED, &esp1);
- }
- return(esp1);
- }
- default:
- crash("(lint_expr) bad value class\n");
- /* NOTREACHED */
- }
- case Oper:
- {
- register int oper = expr->OP_OPER;
- register struct expr *left = expr->OP_LEFT;
- register struct expr *right = expr->OP_RIGHT;
- switch (oper) {
- case '=':
- case PLUSAB:
- case MINAB:
- case TIMESAB:
- case DIVAB:
- case MODAB:
- case LEFTAB:
- case RIGHTAB:
- case ANDAB:
- case XORAB:
- case ORAB:
- lint_conversion(oper, right->ex_type, left->ex_type);
- /* 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);
- }
- 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);
- 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);
- 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);
- case '(':
- if (right != 0) {
- /* function call with parameters */
- register struct expr *ex = right;
- while ( ex->ex_class == Oper
- && ex->OP_OPER == PARCOMMA
- ) {
- esp2 = lint_expr(ex->OP_RIGHT, RVAL,
- USED);
- check_and_merge(&esp1, esp2, oper);
- ex = ex->OP_LEFT;
- }
- esp2 = lint_expr(ex, RVAL, USED);
- check_and_merge(&esp1, esp2, oper);
- }
- if ( left->ex_class == Value
- && left->VL_CLASS == Name
- ) {
- fill_outcall(expr,
- expr->ex_type->tp_fund == VOID ?
- VOIDED : used
- );
- outcall();
- left->VL_IDF->id_def->df_used = 1;
- }
- else {
- esp2 = lint_expr(left, val, USED);
- check_and_merge(&esp1, esp2, oper);
- }
- return(esp1);
- case '.':
- return(lint_expr(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);
- case INT2INT:
- case INT2FLOAT:
- case FLOAT2INT:
- case FLOAT2FLOAT:
- lint_conversion(oper, right->ex_type, left->ex_type);
- return(lint_expr(right, RVAL, USED));
- case '<':
- case '>':
- case LESSEQ:
- case GREATEREQ:
- case EQUAL:
- case NOTEQUAL:
- lint_relop(left, right, oper);
- lint_relop(right, left,
- oper == '<' ? '>' :
- oper == '>' ? '<' :
- oper == LESSEQ ? GREATEREQ :
- oper == GREATEREQ ? LESSEQ :
- oper
- );
- /*FALLTHROUGH*/
- case '+':
- case '/':
- case '%':
- case ',':
- case LEFT:
- case RIGHT:
- case '&':
- case '|':
- case '^':
- case OR:
- case AND:
- esp1 = lint_expr(left, RVAL,
- oper == ',' ? IGNORED : USED);
- esp2 = lint_expr(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);
- default:
- return(0); /* for initcomma */
- }
- }
- default:
- return(0);
- }
- }
- expr_ignored(expr)
- struct expr *expr;
- {
- switch (expr->ex_class) {
- case Oper:
- switch (expr->OP_OPER) {
- case '=':
- case TIMESAB:
- case DIVAB:
- case MODAB:
- case LEFTAB:
- case RIGHTAB:
- case ANDAB:
- case XORAB:
- case ORAB:
- case AND: /* doubtful but useful */
- case OR: /* doubtful but useful */
- case '(':
- case '?':
- case ',':
- break;
- case PLUSAB:
- case MINAB:
- case POSTINCR:
- case POSTDECR:
- case PLUSPLUS:
- case MINMIN:
- /* may hide the operator * */
- if ( /* operation on a pointer */
- expr->OP_TYPE->tp_fund == POINTER
- && /* the result is dereferenced, e.g. *p++; */
- expr->ex_type == expr->OP_TYPE->tp_up
- ) {
- hwarning("result of * ignored");
- }
- break;
- default:
- hwarning("result of %s ignored",
- symbol2str(expr->OP_OPER));
- break;
- }
- break;
- case Value:
- hwarning("identifier as statement");
- break;
- case String:
- case Float:
- hwarning("constant as statement");
- break;
- }
- }
- #endif LINT
|