[net.lang] Comments on this program please...

david@ukma.UUCP (David Herron, NPR Lover) (11/23/85)

Everybody I've shown this program to has *groaned* and complained
about what a nasssty program it was...  This program was written
to help decode a bitnet routing table that I had been netcopy'd
to me and didn't get translated into ascii.  So after running dd
over it, the line markers had disappeared into never never land.
But from looking real closely at the file I could see that each
line was supposed to start with ROUTE.....  thus this program:

I think it's *cute*!





#include <stdio.h>

main()
{
	register int r, o, u, t, e;

	while ((r = getchar()) != EOF) {
		if (r == 'R')
			if ((o = getchar()) == 'O')
				if ((u = getchar()) == 'U')
					if ((t = getchar()) == 'T')
						if ((e = getchar()) == 'E')
							printf("\nROUTE");
						else
							printf("ROUT%c", e);
					else
						printf("ROU%c", t);
				else
					printf("RO%c", u);
			else
				printf("R%c", o);
		else
			putchar(r);
	}
	putchar('\n');
}
-- 
David Herron,  cbosgd!ukma!david, david@UKMA.BITNET.

Experience is something you don't get until just after you need it.

jimc@ucla-cs.UUCP (12/03/85)

In article <2389@ukma.UUCP> david@ukma.UUCP (David Herron, NPR Lover) writes:
>Everybody I've shown this program to has *groaned* ...
>I think it's *cute*!
>#include <stdio.h>
>main()
>{
>	register int r, o, u, t, e;
>	while ((r = getchar()) != EOF) {
>		if (r == 'R')
>			if ((o = getchar()) == 'O')
>				if ((u = getchar()) == 'U')
>					if ((t = getchar()) == 'T')
>						if ((e = getchar()) == 'E')
>							printf("\nROUTE");
>						else
>							printf("ROUT%c", e);
>					else
>						printf("ROU%c", t);
>				else
>					printf("RO%c", u);
>			else
>				printf("R%c", o);
>		else
>			putchar(r);
>	}
>	putchar('\n');
>}
Yes, indeed, the above program is aesthetically disgusting.  But what is
wrong with it in practice?  1.  It works only for that one pattern (not 
that files are often wiped like that, but let's keep our standards
up).  2.  The multiple if's and library calls can get lengthy on some mach-
ines.  3.  Using printf is expensive when you just want to concatenate
strings on the way out.  Here is a looping version.  Isn't this one just
as cute?

#include <stdio.h>
main(an, av)
  int an;
  char *av[];           /*When the pattern av[1] is found in stdin, a new-
                         *line is put in front of it, the result going to
                         *stdout. */
{
  register char c, *p, *r;
  if (an < 2) {puts("Usage: gorf pattern"); exit(1);}  /*Idiotproof*/
  for (p = av[1]; ; ) {
    c = getchar();
    if (c == *p && c != '\0') {  /*Char does match pattern (last term is
                         *nitpick overkill since \0 unlikely in text).
                         *Note, EOF doesn't match pattern.*/
      if (*++p == '\0') putchar('\n'); /*Found whole pattern, write new-
                         *line before it.  Pattern dumped on next char.*/
    } else {            /*Char. doesn't match pattern*/
      for (r = av[1]; r < p; ) putchar(*r++);  /*Dump portion of pattern,
                             *if any, that was matched*/
      if (c == EOF) break;
      putchar(c);       /*After which, write non-matching char.*/
      p = av[1];        /*Again start looking for pattern*/
    }
  }
}
(Bug: if the pattern is ROUTE and the text is ROUROUTE, the pattern will
be missed.  This is an easy fix.  But if the pattern is TINTINABULATION
and the text is TINTINTINABULATION, even with the above fix the pattern
will be missed.  It could be seen only with long and expensive pattern
checking -- or does someone see a smart way to do it?

ken@rochester.UUCP (Ipse dixit) (12/04/85)

In article <7839@ucla-cs.ARPA> jimc@ucla-cs.UUCP (Jim Carter) writes:
>(Bug: if the pattern is ROUTE and the text is ROUROUTE, the pattern will
>be missed.  This is an easy fix.  But if the pattern is TINTINABULATION
>and the text is TINTINTINABULATION, even with the above fix the pattern
>will be missed.  It could be seen only with long and expensive pattern
>checking -- or does someone see a smart way to do it?

Yes, in the chapter on string matching in Design and Analysis of Computer
Algorithms (Aho, Hopcroft and Ullman?) you can see how to construct a
finite state machine to recognize a substring anywhere in the input
word. Basically, when a failure to match occurs, the machine goes back
to the last state which it could be in. In your second example, when
it fails to match the third T it goes back to the state it would have
been in after seeing TINT. All the states can be computed in advance and the
algorithm runs in linear time.

	Ken
-- 
UUCP: ..!{allegra,decvax,seismo}!rochester!ken ARPA: ken@rochester.arpa
USnail:	Dept. of Comp. Sci., U. of Rochester, NY 14627. Voice: Ken!

abh6509@ritcv.UUCP (A. hudson) (12/04/85)

That program looks like it should first be modelled with a finite
state diagram. A few theoretical considerations will quickly show
if you are testing for impossible conditions or have redundant
code. Or if a group of IF's are clumsily arranged, always testing
true and therefore unnecesary. 

If that BITNET routine function exhibited none of those maladies
then your cryptic style is functionally justified. Providing
no one has to understand it or modify it later on.


				Andrew Hudson

avg@diablo.ARPA (12/05/85)

In article <7839@ucla-cs.ARPA> jimc@ucla-cs.UUCP (Jim Carter) 
commented on:
>>#include <stdio.h>
>>main()
>>{
>>	register int r, o, u, t, e;
>>	while ((r = getchar()) != EOF) {
>>		if (r == 'R')
>>			if ((o = getchar()) == 'O')
>>				if ((u = getchar()) == 'U')
>>					if ((t = getchar()) == 'T')
>>						if ((e = getchar()) == 'E')
>>							printf("\nROUTE");
>>						else
>>							printf("ROUT%c", e);
>>					else
>>						printf("ROU%c", t);
>>				else
>>					printf("RO%c", u);
>>			else
>>				printf("R%c", o);
>>		else
>>			putchar(r);
>>	}
>>	putchar('\n');
>>}
and submitted his own "improvement".  My question is, "What is the original
program supposed to do?"  Judging from Jim's comments, he believes that
input ROUROUTE should produce output ROU\nROUTE\n.  It doesn't.
However, input ROUXROUTE produces ROUX\nROUTE\n.  So perhaps the answer to
"What's wrong with this program?" is "It doesn't meet specs."

On a very simple style level, what's wrong is that it uses nested if's
when it could use if ... else if ... else if ...

The following version corrects both complaints.
The technique of getting the first char before the loop is called
"priming", and has wide applicability.

#include <stdio.h>
main()
{
	register int r, o, u, t, e;
	r = getchar();
	while (r != EOF) {
		if                  (r != 'R') { putchar(r); r = getchar(); }
		else if ((o = getchar()) != 'O') { printf("R");  r = o; }
		else if ((u = getchar()) != 'U') { printf("RO");  r = u; }
		else if ((t = getchar()) != 'T') { printf("ROU");  r = t; }
		else if ((e = getchar()) != 'E') { printf("ROUT");  r = e; }
		else { printf("\nROUTE");  r = getchar(); }
	}
	putchar('\n');
}

Not to pick on Jim C., but I don't see how his program, or any other
program that is mainly explanatory comments, can be considered "cute."