]> thyrsus.com Git - cupl.git/commitdiff
Sanity checks passed.
authorEric S. Raymond <esr@thyrsus.com>
Thu, 3 Nov 1994 05:28:48 +0000 (05:28 +0000)
committerEric S. Raymond <esr@thyrsus.com>
Thu, 3 Nov 1994 05:28:48 +0000 (05:28 +0000)
Makefile
cupl.y
interpret.c

index e030fd80135c70e04379ae6e44b186571cdd3730..c13bd38af91ccc1f9e4e885f99d015b36b2bf1cb 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -21,6 +21,7 @@ grammar.c tokens.h y.output: cupl.y
        mv y.tab.c grammar.c
        mv y.tab.h tokens.h
 
+grammar.o: grammar.c cupl.h
 tokdump.o: tokdump.c toktab.h
 lexer.o: lexer.c tokens.h cupl.h
 interpret.o: interpret.c tokens.h cupl.h
diff --git a/cupl.y b/cupl.y
index 742086e60617f687a3c5084c2959c7b62c8550a0..80dabe7cd8ead0972dba4913bbf52e45da4b6249 100644 (file)
--- a/cupl.y
+++ b/cupl.y
@@ -73,6 +73,8 @@ author first.
 %token IFELSE
 %token DIMENSION
 %token ISLICE JSLICE
+%token ITERATE
+%token FROM
 
 %type <node> prog command cond simple guard perform iter expr rel alloc subscr
 %type <node> datal ditem expl readl writel witem allocl varlist minl maxl
@@ -116,15 +118,15 @@ datal     :    ditem ',' datal            {$$ = cons(DATALIST, $1, $3);}
        ;
 
 perform        :    PERFORM IDENTIFIER
-               {$$ = cons(PERFORM, NULLNODE,  $2);}
+               {$$ = cons(PERFORM, $2, NULLNODE);}
        |    PERFORM IDENTIFIER expr TIMES
-               {$$ = cons(TIMES,   $3, $2);}
+               {$$ = cons(TIMES,   $2, $3);}
        |    PERFORM IDENTIFIER WHILE guard
-               {$$ = cons(WHILE,   $4, $2);}
+               {$$ = cons(WHILE,   $2, $4);}
        |    PERFORM IDENTIFIER FOR IDENTIFIER '=' expl
-               {$$ = cons(FOR, $2, cons('=', $4, $6));}
+               {$$ = cons(FOR,     $2, cons('=', $4, $6));}
        |    PERFORM IDENTIFIER FOR IDENTIFIER '=' expr iter
-               {$$ = cons(FOR, $2, cons(FOR, $4, cons(FOR, $6, $7)));}
+               {$$ = cons(FOR,     $2, cons(ITERATE, $4, cons(FROM, $6, $7)));}
        ;
 
 iter   :    TO expr BY expr            {$$ = cons(TO, $2, $4);}
index 1ffb8d9a7fcb84ac5db8258f10dab4331bbe28c3..56bc18bfb221dbd5c719a0a555a209b121c03bcc 100644 (file)
@@ -3,7 +3,26 @@
 #include "cupl.h"
 #include "tokens.h"
 
+/*
+ * Define token classes for consistency checks here.  The theory is
+ * that by separating this from the tree-traversal machinery below, we
+ * may be able to parametrize for different source languages someday.
+ */
+/* does the node represent an atom? */
 #define ATOMIC(n)      ((n) == IDENTIFIER || (n) == NUMBER || (n) == STRING)
+/* does the node reference a label? */
+#define LABELREF(n)    ((n) == GO || (n) == OG || (n) == PERFORM \
+                        || (n) == TIMES || (n) == WHILE || (n) == FOR)
+/* does the node set a variable? */
+#define VARSET(n)      ((n) == LET || (n) == READ || (n) == ITERATE)
+/* does the (non-VARSET) node refer to its left operand? */ 
+#define LEFTREF(n)     ((n) != FOR && (n) != GO && (n) != OG && (n) != LABEL \
+                               && (n) != ALLOCATE && (n) != WATCH \
+                               && (n) != ITERATE && (n) != FROM \
+                               && (n) != LABEL && (n) != TIMES \
+                               && (n) != WHILE)
+/* does the (non-VARSET) node refer to its right operand? */
+#define RIGHTREF(n)    ((n) != PERFORM)
 
 /* this structure represents a CUPL value */
 typedef struct
@@ -66,6 +85,18 @@ static void prettyprint(node *tree, int indent)
 }
 #endif /* PARSEDEBUG */
 
+static void warn(char *msg, ...)
+/* warn of an error and die */
+{
+    va_list    args;
+
+    va_start(args, msg);
+    vfprintf(stderr, msg, args);
+    va_end(args);
+
+    exit(1);
+}
+
 static void die(char *msg, ...)
 /* complain of a fatal error and die */
 {
@@ -78,16 +109,53 @@ static void die(char *msg, ...)
     exit(1);
 }
 
-static bool r_mark_labels(node *tree)
+static bool r_mark_labels(node *tp)
 /* record label references */
 {
-    /* mark label definitions */
-    if (tree->type == STATEMENT && tree->u.n.left->type == LABEL)
-       tree->u.n.left->u.n.left->syminf->labeldef++;
+    /* count label definitions */
+    if (tp->type == LABEL)
+       tp->u.n.left->syminf->labeldef++;
+
+    /* count label references */
+    if (LABELREF(tp->type))
+       if (tp->u.n.left && tp->u.n.left->type == IDENTIFIER)
+           tp->u.n.left->syminf->labelref++;
+       else if (tp->u.n.right && tp->u.n.right->type == IDENTIFIER)
+           tp->u.n.right->syminf->labelref++;
 
-    /* mark label references */
-    if (tree->type == GO || tree->type == OG || tree->type == PERFORM)
-       tree->u.n.left->syminf->labelref++;
+    /* count identifier assignments */
+    if (VARSET(tp->type))
+    {
+       if (tp->u.n.left->type == IDENTIFIER)
+       {
+#ifdef ODEBUG
+           (void) printf("left  operand %8s of %8s assigned\n",
+                         tp->u.n.left->u.string, tokdump(tp->type));
+#endif /* ODEBUG */
+           tp->u.n.left->syminf->assigned++;
+       }
+    }
+    else if (!ATOMIC(tp->type))
+    {
+       if (tp->u.n.left && tp->u.n.left->type == IDENTIFIER && LEFTREF(tp->type))
+       {
+#ifdef ODEBUG
+           (void) printf("left  operand %8s of %8s used\n",
+                         tp->u.n.left->u.string, tokdump(tp->type));
+#endif /* ODEBUG */
+           tp->u.n.left->syminf->used++;
+       }
+       
+
+       if (tp->u.n.right && tp->u.n.right->type == IDENTIFIER && RIGHTREF(tp->type))
+       {
+#ifdef ODEBUG
+           (void) printf("right operand %8s of %8s used\n",
+                         tp->u.n.right->u.string, tokdump(tp->type));
+#endif /* ODEBUG */
+           tp->u.n.right->syminf->used++;
+       }
+    }
 
     return(TRUE);
 }
@@ -118,7 +186,7 @@ static bool check_errors(node *tree)
     /* simple sanity check */
     for (n = tree; n; n = n->u.n.right)
        if (n->type != STATEMENT)
-           die("cupl: internal error: non-STATEMENT at top level");
+           die("internal error: non-STATEMENT at top level");
 
     /* make backpointers */
     for_symbols(lp)
@@ -127,12 +195,20 @@ static bool check_errors(node *tree)
     /* mark labels */
     recursive_apply(tree, r_mark_labels);
 
-    /* check for label consistency */
+    /* check for label/variable consistency */
     for_symbols(lp)
        if (lp->labelref && !lp->labeldef)
-           die("cupl: label %s referenced but not defined\n", lp->node->u.string);
+           die("label %s used but not defined\n", lp->node->u.string);
+       else if ((lp->labelref || lp->labeldef) && (lp->assigned || lp->used))
+           die("%s used as both variable and label\n");
+       else if (!lp->labelref && lp->labeldef)
+           warn("label %s defined but never used\n", lp->node->u.string);
+        else if (lp->used && !lp->assigned)
+           warn("variable %s used but not set\n", lp->node->u.string);
+        else if (!lp->used && lp->assigned)
+           warn("variable %s set but not used\n", lp->node->u.string);
 
-    /* report on the number of labels */
+    /* describe all labels and variables */
     if (verbose >= DEBUG_CHECKDUMP)
     {
        int             nlabels = 0;
@@ -148,10 +224,17 @@ static bool check_errors(node *tree)
            (void) printf("Labels:\n");
            for_symbols(lp)
                if (lp->labeldef)
-                   (void) printf("    %s (%d references)\n",
-                                 lp->node->u.string,
+                   (void) printf("    %8s: %d reference(s)\n",
+                                 lp->node->u.string, 
                                  lp->labelref);
        }
+
+       /* static counts for variables */
+       (void) printf("Variables:\n");
+       for_symbols(lp)
+           if (!lp->labeldef)
+               (void) printf("    %8s: %d assignments, %d reference(s)\n",
+                             lp->node->u.string, lp->assigned, lp->used);
     }
 }
 
@@ -159,7 +242,7 @@ void interpret(node *tree)
 /* interpret a program parse tree */
 {
 #ifdef PARSEDEBUG
-    if (verbose > DEBUG_PARSEDUMP)
+    if (verbose >= DEBUG_PARSEDUMP)
        prettyprint(tree, 0);
 #endif /* PARSEDEBUG */