home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 300-399 / ff314.lha / zc / zc.lzh / Examples / Stdio / CCheck / CCheck.c < prev    next >
C/C++ Source or Header  |  1988-07-17  |  22KB  |  868 lines

  1. /*
  2.  * CCHECK.C -- Amiga Lattice C version 4/8/86
  3.  *
  4.  *
  5.  * Copyright: The Regents of the University of California
  6.  *   [Note - since Steve Draper distributed cchk.c over
  7.  *    Usenet, I assume it's effectively in the public
  8.  *    domain. JCM
  9.  *
  10.  * Title:  ccheck
  11.  *
  12.  * Purpose: To find and report all badly matched openers and
  13.  *   closers plus assignment/equality confusions
  14.  *   in a c source file.
  15.  *
  16.  * Author:  Steve Draper, expanding cnest by Tom Anderson
  17.  *
  18.  * Usage:  ccheck [-q] [-v] <filename1> <filename2> ...
  19.  *
  20.  * History (in reverse order to minimize reading time for updates):
  21.  *
  22.  *   April 8, 1986  Converted to Amiga Lattice C from from butchered text
  23.  *                  file.  If any one can supply me with the original source
  24.  *                  I would appreciate it.  IF-ELSE check seems flaky.
  25.  *  
  26.  *                           Thom Althoff (BIX althoff)
  27.  *                       c/o American Broadcasting Companies
  28.  *                           30 W. 67th St Video Tape Tech Support 
  29.  *                           Floor B1
  30.  *                           New York City, N.Y. 10023
  31.  *
  32.  *   June 18, 1985  Converted to Aztec C - removed BDS C code  -  Rick Moore
  33.  *
  34.  *   January 9, 1983  Single BDS/UNIX source created
  35.  *      as CCHECK.C  -- Jeff Martin
  36.  *
  37.  *   December 29, 1982 Adapted for BDS C --
  38.  *       Jeff Martin at home.
  39.  *
  40.  *   December 20, 1982 Converted to cchk --
  41.  *       Steve Draper at UCSD
  42.  *
  43.  *   December 9, 1982 Jeffrey Mogul at Stanford
  44.  *    - checks for unclosed comment at end of file.
  45.  *
  46.  *   December 3, 1982 creation date --
  47.  *      Tom Anderson at microsof!fluke
  48.  */
  49.  
  50. #include <stdio.h>
  51. #include <ctype.h>
  52.  
  53. #define TRUE 1
  54. #define FALSE 0
  55. #define SPACE 32
  56.  
  57. #define BRACE 1
  58. #define SQBRAK  2
  59. #define PAREN 3
  60. #define IF 4
  61. #define IFCOND 5
  62. #define WHLCOND 6
  63. #define THEN 7
  64. #define ELSE 8
  65.  
  66. #define STACKSIZ 64
  67.  
  68. struct brak
  69. {
  70.     int type, b_indent, b_ln;
  71. } stack[STACKSIZ];
  72.  
  73. #define rmbrak(N) (top -= N, stackc -= N)
  74. #define myungetc(C)  ungetc(((C) == '\n' ? SPACE : (C)), infile)
  75.  
  76. #define VFLAG "-v"
  77. #define QFLAG "-q"
  78. #define SFLAG "-s"
  79.  
  80. int firsttime; /* This was a static in mygetchar() */
  81.  
  82. int mygetchar(), pr();
  83. void checkelse(), newbrak(), checkcloser(), prtype();
  84.  
  85. FILE *infile;
  86. int ln, indent, commindent, stackc, commln;
  87. int singlequoterr, oddsinglequote, bracecnt, parencnt, sqbrakcnt;
  88. int errstatus, wstatus;
  89. int errnmb, wnmb;
  90. int verbose;
  91. char *filename;
  92. struct brak *top;
  93.  
  94. main(argc, argv)
  95. unsigned argc ;
  96. char *argv[] ;
  97. {
  98.     register int c ;
  99.     int i;
  100.     int doubleqflag;
  101.     unsigned file_index;
  102.  
  103.     wnmb = 0;
  104.     verbose = 0;
  105.     file_index = 1;
  106.  
  107.     while (argc > 1  &&  argv[file_index][0] == '-')
  108.        {
  109.         if (strcmp(argv[file_index], VFLAG) == 0)
  110.             verbose++;
  111.         if (strcmp(argv[file_index], QFLAG) == 0)
  112.             wnmb = -2;
  113.         if (strcmp(argv[file_index], SFLAG) == 0)
  114.             wnmb = -2;
  115.         file_index++;
  116.         argc--;
  117.        }
  118.  
  119.     do
  120.      {
  121.         /* INIT for each file */
  122.         firsttime = 1;
  123.         doubleqflag = 0;
  124.         errstatus = wstatus = 0;
  125.         ln = 1;
  126.         indent = 0;
  127.         commindent = 0;
  128.         singlequoterr = oddsinglequote = parencnt = sqbrakcnt = bracecnt = 0;
  129.         errnmb = 0;
  130.         if (wnmb > -2)
  131.             wnmb = 0;
  132.         newbrak(0);
  133.  
  134.         if (argc == 1)
  135.           {
  136.             infile = stdin;
  137.             filename = NULL;
  138.            }
  139.         else
  140.          {
  141.             if ((infile = fopen(argv[file_index], "r")) == (FILE * ) NULL)
  142.             {
  143.                 fprintf(stdout, "%s: Can't access %s\n",argv[0],argv[file_index]);
  144.                 continue;
  145.             }
  146.             filename = argv[file_index];
  147.          }
  148.  
  149.         while ( ( c = mygetchar()) !=  EOF )
  150.            {
  151.             if (verbose == 2)
  152.                {
  153.                 for (i = stackc; i > 0; i--)
  154.                   {
  155.                     printf("%c %d: type ", c, i);
  156.                     prtype(stack[i].type);
  157.                     printf(", indent %d, line %d.\n",stack[i].b_indent,stack[i].b_ln);
  158.                   }
  159.                }
  160.  
  161.             switch (c)
  162.             {
  163.             case ';':
  164.                 ungetc(SPACE, infile);
  165.                 while (top->type == ELSE)
  166.                     rmbrak(1);
  167.                 if (top->type == THEN)
  168.                 {
  169.                     rmbrak(1);
  170.                     checkelse();
  171.                 }
  172.                 break;
  173.  
  174.             case '!':
  175.             case '>':
  176.             case '<':
  177.                 /* swallow legit. '=' chars */
  178.                 c = mygetchar();
  179.                 if (c != '=')
  180.                     myungetc(c);
  181.                 break;
  182.  
  183.             case '=':
  184.                 if ((top - 1)->type == IFCOND  ||  (top - 1)->type == WHLCOND)
  185.                    {
  186.                     c = mygetchar();
  187.                     if (c != '=')
  188.                       {
  189.                         myungetc(c);
  190.                         if (pr(1))
  191.                             printf("Assignment instead of equals in conditional,%d\n", ln);
  192.                     }
  193.                 }
  194.                 break;
  195.  
  196.             case '\n':
  197.             case SPACE:
  198.                 c = mygetchar();
  199.                 switch (c) {
  200.                 case 'i':
  201.                     /* if */
  202.                     c = mygetchar();
  203.                     if (c == 'f' && !isalpha(c = fgetc(infile)) && !isdigit(c))
  204.                       {
  205.                         ungetc(c, infile);
  206.                         newbrak(IF);
  207.                         while ((c = mygetchar()) == SPACE ||  c == '\n');
  208.                         if (c != '(')
  209.                         {
  210.                             if (pr(1))
  211.                                 printf("Bad if (no condition) line %d.\n",ln);
  212.                             rmbrak(1);
  213.                         }
  214.                         else
  215.                             newbrak(IFCOND);
  216.                             myungetc(c);
  217.                     }
  218.                         else
  219.                         myungetc(c);
  220.                     break;
  221.                 case 'w':
  222.                     /* while */
  223.                     if ((c = mygetchar()) == 'h'
  224.                       &&  (c = mygetchar()) == 'i'
  225.                       &&  (c = mygetchar()) == 'l'
  226.                       &&  (c = mygetchar()) == 'e'
  227.                       &&  !isalpha(c = fgetc(infile))  &&  !isdigit(c))
  228.                       {
  229.                         ungetc(c, infile);
  230.                         while ((c = mygetchar()) == SPACE ||  c == '\n');
  231.                         if (c != '(')
  232.                          {
  233.                             if (pr(1))
  234.                                 printf("Bad while (no condition) line %d.\n",ln);
  235.                         }
  236.                         else
  237.                             newbrak(WHLCOND);
  238.                             myungetc(c);
  239.                     }
  240.                     else
  241.                         myungetc(c);
  242.                     break;
  243.                 case 'e':
  244.                     /* else */
  245.                     myungetc(c);
  246.                     checkelse();
  247.                     break;
  248.  
  249.                 default:
  250.                     myungetc(c);
  251.                     break;
  252.                 }
  253.                 break;
  254.  
  255.             case '*':
  256.                 /* close comment ? */
  257.                 c = mygetchar();
  258.                 if (c != '/')
  259.                 {
  260.                     myungetc(c);
  261.                     break;
  262.                 }
  263.  
  264.                 if (pr(1))
  265.                     printf("Line %d: Comment close without open, indent %d\n",ln, indent);
  266.  
  267.                 break;
  268.  
  269.             case '\'':
  270.                 if ((c = fgetc(infile)) != '\\')
  271.                 {
  272.                     if (c == '\''  ||  (c = fgetc(infile)) != '\'')
  273.                     {
  274.                         if (pr(1))
  275.                             printf("Bad character constant line %d\n", ln);
  276.                         singlequoterr = 1;
  277.                     }
  278.                 }
  279.                 else
  280.                    if (!isdigit(c = fgetc(infile)))
  281.                    {
  282.                     if ((c = fgetc(infile)) != '\'')
  283.                        {
  284.                         if (pr(1))
  285.                             printf("Bad character constant with \\ line %d\n",ln);
  286.                        }
  287.                    } 
  288.                 else
  289.                    {
  290.                     if (isdigit(c = fgetc(infile)))
  291.                         if (isdigit(c = fgetc(infile)))
  292.                             c = fgetc(infile);
  293.                     if (c != '\'')
  294.                         if (pr(1))
  295.                             printf("Bad character constant with \\0 line %d\n",ln);
  296.                 }
  297.  
  298.                 if (c != '\'')
  299.                   {
  300.                     ungetc(c, infile);
  301.                     oddsinglequote = !oddsinglequote;
  302.                     singlequoterr = 1;
  303.                   }
  304.                 break;
  305.  
  306.             case '"':
  307.                 do
  308.                 {
  309.                     c = fgetc(infile);
  310.                     if (c == EOF)
  311.                     {
  312.                         if (pr(2))
  313.                             printf("Error: '\"' quoted string not ended on line %d\n",ln);
  314.                             break;
  315.                     }
  316.                     else
  317.                     if (c == '\n')
  318.                     {
  319.                         if (doubleqflag == 0)
  320.                             if (pr(0))
  321.                                 printf("Warning: '\"' quoted string not ended on line %d",ln);
  322.                         doubleqflag = 1;
  323.                         ln++;
  324.                     }
  325.                     else
  326.                     if (c == '\\')
  327.                       {
  328.                         c = SPACE;
  329.                         fgetc(infile);
  330.                       }
  331.                 }
  332.                 while (c != '"');
  333.                 doubleqflag = 0;
  334.                 break;
  335.  
  336.             case '{':
  337.                 if (stackc  &&  indent < top->b_indent)
  338.                     if (pr(0))
  339.                         printf("Indent jumps backwards line %d.\n", ln);
  340.                 newbrak(BRACE);
  341.                 break;
  342.  
  343.             case '}':
  344.                 checkcloser(BRACE);
  345.                 while (top->type == ELSE)
  346.                     rmbrak(1);
  347.                 if (top->type == THEN)
  348.                 {
  349.                     rmbrak(1);
  350.                     checkelse();
  351.                 }
  352.                 break;
  353.  
  354.             case '(':
  355.                 if (stackc  &&  indent < top->b_indent)
  356.                     if (pr(0))
  357.                         printf("Indent jumps backwards line %d.\n", ln);
  358.                 newbrak(PAREN);
  359.                 break;
  360.  
  361.             case ')':
  362.                 checkcloser(PAREN);
  363.                 if (top->type == IFCOND)
  364.                 {
  365.                     rmbrak(1);
  366.                     newbrak(THEN);
  367.                 }
  368.                 else
  369.                 if (top->type == WHLCOND)
  370.                     rmbrak(1);
  371.                 break;
  372.  
  373.             case '[':
  374.                 if (stackc  &&   indent < top->b_indent)
  375.                     if (pr(0))
  376.                         printf("Indent jumps backwards line %d.\n", ln);
  377.                 newbrak(SQBRAK);
  378.                 break;
  379.  
  380.             case ']':
  381.                 checkcloser(SQBRAK);
  382.                 break;
  383.  
  384.             default:
  385.                 break;
  386.  
  387.             }
  388.         }
  389.  
  390.         fclose(infile);
  391.  
  392.         while (stackc > 0)
  393.         {
  394.             pr(2);
  395.             fputs("Unclosed brak at EOF: ", stdout);
  396.             prtype(top->type);
  397.             printf(" opened on line %d.\n", top->b_ln);
  398.             switch (top->type)
  399.             {
  400.             case BRACE:
  401.                 bracecnt++;
  402.                 break;
  403.             case SQBRAK:
  404.                 sqbrakcnt++;
  405.                 break;
  406.             case PAREN:
  407.                 parencnt++;
  408.                 break;
  409.             default:
  410.                 break;
  411.             }
  412.             rmbrak(1);
  413.         }
  414.  
  415.         if ((i = (oddsinglequote || bracecnt || sqbrakcnt || parencnt)) || errstatus)
  416.         {
  417.             pr(2);
  418.             printf("Summary:\n");
  419.         }
  420.         else
  421.         {
  422.             if (filename != NULL)
  423.             {
  424.                 fputs(filename, stdout);
  425.                 fputs(": ", stdout);
  426.             }
  427.             printf(" OK\n");
  428.         }
  429.         if (oddsinglequote)
  430.             printf("\tOdd number of single quotes.\n");
  431.         if (bracecnt)
  432.             printf("\t%d too few %s braces.\n", abs(bracecnt), (bracecnt >
  433.               0 ? "closing" : "opening"));
  434.         if (sqbrakcnt)
  435.             printf("\t%d too few %s square brackets.\n", abs(sqbrakcnt),(sqbrakcnt
  436.               > 0 ? "closing" : "opening"));
  437.         if (parencnt)
  438.             printf("\t%d too few %s parentheses.\n", abs(parencnt), (parencnt
  439.               > 0 ? "closing" : "opening"));
  440.         if (errstatus && !i)
  441.             printf("\tPossible error(s), but no net delimiter imbalance.\n");
  442.         putchar('\n');
  443.     }
  444.     while (++file_index < argc);
  445.  
  446.     exit(errstatus ? 2 : wstatus);
  447. }
  448.  
  449. int mygetchar()
  450. {
  451.     register int c;
  452.  
  453.     c = fgetc(infile);
  454.  
  455.     /*
  456.     if (c == ';') {
  457.  ungetc(SPACE, infile);
  458.  return(';');
  459.     }
  460.     */
  461.     if (c == '/') {    /* open comment ? */
  462.         c = fgetc(infile);
  463.         if (c != '*')
  464.         {
  465.             ungetc(c, infile);
  466.             return('/');
  467.         }
  468.         commln = ln;
  469.         commindent = indent;
  470.  
  471.         while (1)
  472.         {
  473.             c = fgetc(infile);
  474.  
  475.             if (c == EOF)
  476.             {   /* last comment never ended */
  477.                 if (pr(2))
  478.                     printf("Comment opened line %d unclosed by end of file.\n",commln);
  479.                 break; /* Get out of this loop! */
  480.             }
  481.             else
  482.             if (c == '/') {  /* nested comment ? */
  483.                 if ((c = fgetc(infile)) == '*')
  484.                 {
  485.                     if (pr(0))
  486.                         fprintf(stdout,
  487.                           "Nested comment: line %d, indent %d.  First open: line %d indent %d\n",
  488.                           ln, indent, commln, commindent);
  489.                 }
  490.                 else
  491.                     ungetc(c, infile);
  492.             } else if (c == '*') {  /* end comment ? */
  493.                 if ((c = fgetc(infile)) == '/')
  494.                 {
  495.                     if (indent != commindent  &&  indent - 1 != commindent)
  496.                         if (pr(0))
  497.                             printf("Indent of comment close doesn't match open: lines %d, %d indents %d, %d\n",
  498.                                      commln, ln, commindent, indent);
  499.  
  500.                     break;    /* only exit from loop, except EOF */
  501.                 }
  502.                 else
  503.                     ungetc(c, infile);
  504.             }
  505.             else
  506.             if (c == '\n')
  507.             {
  508.                 do
  509.                 {                  
  510.                   if (c == SPACE)
  511.                         indent++;
  512.                     else
  513.                     if (c == '\t')                    
  514.                         indent = ((indent + 8) / 8) * 8;
  515.                     else if (c == '\n')
  516.                     {
  517.                         ln++;
  518.                         indent = 0;
  519.                     }
  520.                 }
  521.                 while (isspace(c = fgetc(infile)));
  522.                 ungetc(c, infile);
  523.             }
  524.         }
  525.         return(SPACE);
  526.  
  527.     }
  528.  
  529.     if (c == '\n'  ||  firsttime == 1)
  530.     {
  531.         firsttime = 0;
  532. lf:
  533.         while (1)
  534.         {
  535.             if (c == SPACE)
  536.                 indent++;
  537.             else if (c == '\t')
  538.                 indent = ((indent + 8) / 8) * 8;
  539.             else if (c == '\n')
  540.             {
  541.                 ln++;
  542.                 indent = 0;
  543.                 singlequoterr = 0;
  544.             } else
  545.             {
  546.                 ungetc(c, infile);
  547.                 return('\n');
  548.                 /*NOTREACHED*/
  549.                 break;
  550.             }
  551.             c = fgetc(infile);
  552.         }
  553.     }
  554.  
  555.     if (c == SPACE  ||  c == '\t')
  556.     {
  557.         do
  558.         
  559.             c = fgetc(infile);
  560.         while (c == SPACE  ||  c == '\t');
  561.         if (c != '\n')
  562.         {
  563.             ungetc(c, infile);
  564.             return(SPACE);
  565.         }
  566.         else
  567.             goto lf;
  568.     }
  569.     return(c);
  570. }
  571.  
  572. /*
  573.  * administer count of error msgs. and suppress if too many
  574.  * administer the status var.s
  575.  * prepend file name to msg.
  576.  * flag error msg.s (not warnings) with '*'
  577.  */
  578. int pr(error)
  579. int error;
  580. {
  581.     int i;
  582.  
  583.     if (singlequoterr)
  584.         return(0);
  585.  
  586.     if (verbose)
  587.       {
  588.         for (i = stackc; i > 0; i--)
  589.           {
  590.             printf("%d: type ", i);
  591.             prtype(stack[i].type);
  592.             printf(", indent %d, line %d.\n", stack[i].b_indent, stack[i].b_ln);
  593.           }
  594.       }
  595.  
  596.     if (error == 2)
  597.       {
  598.         errnmb = 0;
  599.         errstatus = 1;
  600.       }
  601.     else
  602.     
  603.     if (error)
  604.        {
  605.         errstatus = 1;
  606.         if (errnmb < 0)
  607.             return(0);
  608.             
  609.         else
  610.         if (errnmb >= 9)
  611.           {
  612.             errnmb = -1;
  613.             printf("Other error messages being suppressed.\n");
  614.             return(0);
  615.           }
  616.         }
  617.     else
  618.     {
  619.         wstatus = 1;
  620.         if (wnmb < 0)
  621.             return(0);
  622.         else if (errnmb + wnmb >= 9)
  623.           {
  624.             wnmb = -1;
  625.             puts("Further warning messages being suppressed.\n");
  626.             return(0);
  627.           }
  628.      }
  629.  
  630.     if (filename != NULL)
  631.       {
  632.         fputs(filename, stdout);
  633.         fputs(": ", stdout);
  634.       }
  635.     if (error)
  636.         putchar('*');
  637.     if (error)
  638.         errnmb++;
  639.     else
  640.         wnmb++;
  641.     return(1);
  642. }
  643.  
  644. void newbrak(newtype)
  645. int newtype;
  646. {
  647.     if (newtype == 0)
  648.       {
  649.         top = stack;
  650.         stackc = 0;
  651.       }
  652.     else
  653.       {
  654.         top++;
  655.         stackc++;
  656.       }
  657.       
  658.     if (stackc >= STACKSIZ)
  659.        {
  660.         if (pr(2))
  661.          {
  662.            printf("***stack overflow, line %d.\n", ln);
  663.          }  
  664.         exit(3);
  665.        }
  666.  
  667.     top->type = newtype;
  668.     top->b_indent = indent;
  669.     top->b_ln = ln;
  670.  
  671. }
  672.  
  673. void prtype(typ)
  674. int typ;
  675. {
  676.     switch (typ)
  677.     {
  678.     case BRACE:
  679.         putchar('}');
  680.         break;
  681.     case PAREN:
  682.         putchar(')');
  683.         break;
  684.     case SQBRAK:
  685.         putchar(']');
  686.         break;
  687.     case IF:
  688.         fputs("if", stdout);
  689.         break;
  690.     case IFCOND:
  691.         fputs("if-condition", stdout);
  692.         break;
  693.     case THEN:
  694.         fputs("then", stdout);
  695.         break;
  696.     case ELSE:
  697.         fputs("else", stdout);
  698.         break;
  699.     case WHLCOND:
  700.         fputs("while-condition", stdout);
  701.         break;
  702.     default:
  703.         fputs("'NULL'", stdout);
  704.         break;
  705.     }
  706. }
  707.  
  708. void checkcloser(typ)
  709. int typ;
  710. {
  711.     int i, found;
  712.  
  713.     i = found = 0;
  714.     if (typ == top->type  &&  top->b_indent == indent)
  715.     {
  716.         rmbrak(1);
  717.         return;
  718.     }
  719.     
  720.     while (!found  &&  ++i < stackc  &&  indent <= (top - i)->b_indent)
  721.         if (typ == (top - i)->type  &&  (top - i)->b_indent == indent)
  722.             found = 1;
  723.  
  724.     if (found)
  725.     {
  726.         if (pr(1))
  727.             printf("Missing closer%s detected line %d:\n", (i > 1 ? "s" :
  728.               ""), ln);
  729.         while (i--)
  730.         {
  731.             if (pr(1))
  732.             {
  733.                 fputs("\tMissing closing ", stdout);
  734.                 prtype(top->type);
  735.                 printf(" opened line %d.\n", top->b_ln);
  736.             }
  737.             switch (top->type)
  738.             {
  739.             case BRACE:
  740.                 bracecnt++;
  741.                 break;
  742.             case SQBRAK:
  743.                 sqbrakcnt++;
  744.                 break;
  745.             case PAREN:
  746.                 parencnt++;
  747.                 break;
  748.             default:
  749.                 break;
  750.             }
  751.             rmbrak(1);
  752.         }
  753.         rmbrak(1); /* the matching brak */
  754.     }
  755.     else
  756.     if (typ == top->type)
  757.     {
  758.         if (indent != top->b_indent)
  759.         {
  760.             if (pr(0)) {
  761.                 fputs("Mismatched indent on closing ", stdout);
  762.                 prtype(typ);
  763.                 printf(" lines %d, %d; indents %d, %d.\n",
  764.                   top->b_ln, ln, top->b_indent, indent);
  765.             }
  766.         }
  767.         rmbrak(1);
  768.     }
  769.       else
  770.       {
  771.         switch (typ)
  772.         {
  773.         case BRACE:
  774.             bracecnt--;
  775.             break;
  776.             case SQBRAK:
  777.             sqbrakcnt--;
  778.             break;
  779.         case PAREN:
  780.             parencnt--;
  781.             break;
  782.         default:
  783.             break;
  784.         }
  785.  
  786.         if (pr(1))
  787.         {
  788.             fputs("Muddle detected at unmatched closing ", stdout);
  789.             prtype(typ);
  790.             printf(" line %d.\n", ln);
  791.         }
  792.     }
  793. }
  794.  
  795. /*
  796.  * removes IF from stack
  797.  * checks else's indent
  798.  */
  799. void checkelse()
  800. {
  801.     int c;
  802.  
  803.     while ((c = mygetchar()) == SPACE  || c == '\n');
  804.     if (c == 'e' &&  (c = mygetchar()) == 'l' &&  (c = mygetchar()) == 's'
  805.       &&  (c = mygetchar()) == 'e' &&  !isalpha(c = fgetc(infile)) 
  806.       &&  !isdigit(c))
  807.       {
  808.         ungetc(c, infile);
  809.         if (top->type == THEN)
  810.             rmbrak(1);
  811.         if (top->type != IF)
  812.         {
  813.             if (pr(1))
  814.                 printf("Else with no if line %d.\n", ln);
  815.         }
  816.           else
  817.           if (indent + 2 < top->b_indent)
  818.           {
  819.             if (pr(1))
  820.                 printf("Dangling else -- bound to wrong if?  \"if\" line %d, \"else\" line %d\n",top->b_ln, ln);
  821.           }
  822.           else
  823.           if (indent != top->b_indent)
  824.           {
  825.             if (pr(0))
  826.             {
  827.                 fputs("Wrong indent for else", stdout);
  828.                 if (indent - 2 >  top->b_indent)
  829.                     fputs(" missing if?", stdout);
  830.                 printf(".  \"if\" line %d, \"else\" line %d.\n", top->b_ln,ln);
  831.             }
  832.         }
  833.  
  834.         if (top->type == IF)
  835.             rmbrak(1);
  836.         newbrak(ELSE);
  837.     }
  838.     else
  839.     {
  840.         myungetc(c);
  841.         ungetc(SPACE, infile);  /* BUG?? */
  842.         /* no else so terminate the IF */
  843.         if (top->type == IF)
  844.         {
  845.             rmbrak(1);
  846.             while (top->type == ELSE)
  847.                 rmbrak(1);
  848.             if (top->type == THEN)
  849.             {
  850.                 rmbrak(1);
  851.                 checkelse();
  852.             }
  853.         }
  854.     }
  855. }
  856.  
  857. /*  This function is included because Aztec C does not include an "abs"
  858.     function.  If your library contains this function, this code can be    
  859.     deleted.
  860. */
  861. int abs(i)
  862. {
  863.     int c;
  864.  
  865.     return((i < 0) ? -i : i);
  866. }
  867.  
  868.