#ifdef LINT
#include <alloc.h> /* for st_free */
+#include "interface.h"
#include "assert.h"
#include "arith.h" /* definition arith */
#include "label.h" /* definition label */
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;
p1 = *espp;
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
#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 */
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()
{
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
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:
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);
+ }
+ if (val == RVAL && expr->ex_lvalue == 0) {
+ /* address of identifier used */
+ add_expr_state(expr->EX_VALUE, REFERRED, &esp);
}
- return esp1;
+ return esp;
}
default:
}
}
-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:
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);
- }
- 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);
+ /* 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);
}
- 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);
+ esp_l = expr2state(left, RVAL, USED);
+
+ /* set resulting variable, if any */
+ if (ISNAME(left)) {
+ change_state(left->VL_IDF, SET);
+ add_expr_state(left->EX_VALUE, SET, &esp_l);
}
- 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;
+ 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) {
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
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:
oper == GREATEREQ ? LESSEQ :
oper
);
- /*FALLTHROUGH*/
+ goto dyadic;
+
+ /* dyadic operators */
+ dyadic:
case '+':
case '/':
case '%':
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;
{
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++; */
}
}
+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
#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"
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;
-
-static print_autos();
+PRIVATE int brace_count;
+PRIVATE struct brace brace_bottom;
+PRIVATE struct brace *top_br = &brace_bottom;
+
+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()
{
end_brace(stl);
}
+PRIVATE
end_brace(stl)
struct stack_level *stl;
{
free_brace(br);
}
+PRIVATE
lint_1_local(idf, def)
struct idf *idf;
struct def *def;
}
}
+PRIVATE
lint_1_global(idf, def)
struct idf *idf;
struct def *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.
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;
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 */
- if (!a->ad_set) {
- warning("%s%s uninitialized", idf->id_text,
- (a->ad_maybe_set ? " possibly" : "")
- );
- a->ad_maybe_set = 0;
- a->ad_set = 1; /* one warning */
+ break;
+ case USED:
+ if (!a->ad_set) {
+ warning("%s%s uninitialized", idf->id_text,
+ (a->ad_maybe_set ? " possibly" : "")
+ );
+ a->ad_maybe_set = 0;
+ a->ad_set = 1; /* one warning */
+ }
+ a->ad_used = 1;
+ break;
}
- a->ad_used = 1;
}
extern struct stack_level *local_level;
}
}
+PRIVATE
check_autos()
{
/* Before leaving a block remove the auto_defs of the automatic
}
}
-struct auto_def *
+PRIVATE struct auto_def *
copy_st_auto_list(from_al, lvl)
struct auto_def *from_al;
{
return start;
}
+PRIVATE
free_st_auto_list(au)
register struct auto_def *au;
{
}
}
-struct state *
+PRIVATE struct state *
copy_state(from_st, lvl)
struct state *from_st;
{
return st;
}
-static
+PRIVATE
Free_state(stp)
struct state **stp;
{
*stp = 0;
}
+PRIVATE
remove_settings(state, lvl)
struct state *state;
{
#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;
return a;
}
+PRIVATE
merge_states(st1, st2, lvl, mode)
struct state *st1, *st2;
int 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;
return 0;
}
-struct lint_stack_entry *
+PRIVATE struct lint_stack_entry *
find_wdfc()
{
register struct lint_stack_entry *lse = top_ls;
return 0;
}
-struct lint_stack_entry *
+PRIVATE struct lint_stack_entry *
find_cs()
{
register struct lint_stack_entry *lse = top_ls;
}
}
+PRIVATE
cont_break_merge(lse)
struct lint_stack_entry *lse;
{
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;
}
}
}
+PRIVATE
lint_push(lse)
struct lint_stack_entry *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()
print(" |--------------\n\n");
}
-static
print_autos(a)
register struct auto_def *a;
{
}
print("\n");
}
+#endif DEBUG
+
#endif LINT