[net.micro.apple] LL

bbanerje@sjuvax.UUCP (B. Banerjee) (05/15/84)

This is a followup to two articles actually.  As this discussion
is leaving the original topic (availability of a C compiler for
apple) and is going into issues which are of further interest to
net.lang only, I am cross posting this to that newsgroup.  Anyone 
following up on this should remove net.micro.apple from the list
of newsgroups.

The two articles in question are (partially) reproduced below...

>> In response to "why would anyone want to write a recursive descent
>> parser"
>> Okay, well gee, as i understand it, as told to me by the gentleman in
>> hawaii, the ll(1) parse tables are not easy to fill in.
>> I suppose you should ask Per Brinch Hansen or
>> Hoare, why they recommend recursive descent for 
>> micro computers.
>> 
>> It seems that the only feasible way to write a parser for
>> a MICRO-COMPUTER is to use recursive descent. This saves
>> the time that would be spent figuring out the parse tables
>> for ll(1). Also, there are a zillion states for even a moderate
>> sized language.
>> 

Also ...

>> If you have access to a parser generator such as yacc, use it and don't
>> worry about what kind of parser it generates.
>> 
>> Yacc happens to generate an LALR(1) parser.  A book on my shelf claims
>> that an LALR(1) parser table for Algol 60 occupies less than 3000 bytes.
>> I would guess that an LL(1) parser table would be about the same size.
>> 
>> A true recursive descent parser is just an LL(1) parser in which the
>> parser table is encoded procedurally.  I would expect table-driven LL(1)
>> parsers to be more compact than recursive descent parsers.
>> 
>> If you don't have access to a parser generator, use table-driven LL(1)
>> or recursive descent.  Just be careful as you transform the grammar into
>> LL(1) form.  Consult a good textbook on compiler construction such as
>> Aho & Ullman or Hunter.

Regarding the second article.  LALR parsers are incredibly difficult
to write by hand.  Try and write a table for the 5 line grammar in
Aho and Ullman.  I don't have it handy, so I can't refer you to a page
number.  However, it is in the section on writing LALR grammars
(what else).

Now, the first article was a followup to one of mine advocating
table driven LL(1) over recursive descent.  The points raised (in
order) are -

1.	Recursive descent is easier to write than table driven
	LL(1)

This is probably true.  However LL(1) tables are by no means
difficult to write.  An algorithm suitable for machine encoding
(very easily) can be found in the book by Rosencrantz, Lewis
& Stearns.  It can be done by hand quite easily.  Also, with
a little bit of effort, one can rewrite an LL(1) grammar as a
Q grammar (Non terminals directly derive either null, or a
right hand side that begins with a terminal).  Finding the 
selection sets for Q grammars is a relatively trivial operation.

2.	Recursive descent is more "naturally" suited to micro-
	computers.

This, I don't buy.  With a micro, you usually have memory
constraints.  Recursive descent automatically requires use of
a higher level language supporting recursion.  It also requires
that you add in the overhead for recursion.  Table driven LL(1)
is likely to be *much* smaller.  The driver for this is also
relatively simple, and could be written in assembler (far more
easily than that for a recursive descent parser).  A further
advantage is that changes to the grammar only require changes to
the table.  I submit that this is "better" (subjective) than
recoding as must be done with a recursive descent parser.

LL(1) parsers (in general) also have the "prefix property" of
catching an error as soon as it occurs, rather than at some
later stage.  LALR parsers don't.

An ambiguous operator precedence grammar is probably better
for parsing expressions.

Regards,
-- 
				Binayak Banerjee
		{allegra | astrovax | bpa | burdvax}!sjuvax!bbanerje
P.S.
	Send Flames, I love mail.

rpw3@fortune.UUCP (05/16/84)

#R:sdccs7:-121900:fortune:22000002:000:1080
fortune!rpw3    May 15 17:03:00 1984

It also happens to be the case that IF the grammar is LL(1) or even
reasonably close, a recursive-descent parser is:

	1. Fast

	2. Easy to write, understand, and maintain

	3. Easy to embed semantics (and other misc. functions) at
	   the right point

	4. Capable of acceptable error-handling (assuming you want to
	   detect erros, not "fix" them)
	
	5. It mixes well with other parsing techniques which may want to
	   be used in parts of the language that may not be strictly LL(1).

The BLISS family of languages/compilers all (to my knowledge) use
recursive-descent for declarations and control structures, and
operator-precedence for expressions. They are also some of the
best optimizing compilers ever built. (It's not a complete non-sequitor,
as the common sub-expression recognition was done during syntax analysis.)
See Wulf, et. al., "The Design of an Optimizing Compiler" (Addison-Wesley).

Rob Warnock

UUCP:	{ihnp4,ucbvax!amd70,hpda,harpo,sri-unix,allegra}!fortune!rpw3
DDD:	(415)595-8444
USPS:	Fortune Systems Corp, 101 Twin Dolphin Drive, Redwood City, CA 94065

rpw3@fortune.UUCP (05/16/84)

#R:sdccs7:-121900:fortune:22000003:000:1135
fortune!rpw3    May 15 17:12:00 1984

It also happens to be the case that IF the grammar is LL(1) or even
reasonably close, a recursive-descent parser is:

	1. Fast

	2. Easy to write, understand, and maintain

	3. Easy to embed semantics (and other misc. functions) at
	   the right point

	4. Capable of acceptable error-handling (assuming you want to
	   detect errors, not "fix" them)
	
	5. It mixes well with other parsing techniques which may want to
	   be used in parts of the language that may not be strictly LL(1),
	   or where other techniques may be more convenient.

The BLISS family of languages/compilers all (to my knowledge) use
recursive-descent for declarations and control structures, and
operator-precedence for expressions. They are also some of the
best optimizing compilers ever built. (It's not a complete non-sequitor,
as the common sub-expression recognition was done during syntax analysis.)
See Wulf, et. al., "The Design of an Optimizing Compiler" (Addison-Wesley).

Rob Warnock

UUCP:	{ihnp4,ucbvax!amd70,hpda,harpo,sri-unix,allegra}!fortune!rpw3
DDD:	(415)595-8444
USPS:	Fortune Systems Corp, 101 Twin Dolphin Drive, Redwood City, CA 94065

ee163ahp@sdccs7.UUCP (GALACTUS) (05/16/84)

In response to "why would anyone want to write a recursive descent
parser"
Okay, well gee, as i understand it, as told to me by the gentleman in
hawaii, the ll(1) parse tables are not easy to fill in.
I suppose you should ask Per Brinch Hansen or
Hoare, why they recommend recursive descent for 
micro computers.

It seems that the only feasible way to write a parser for
a MICRO-COMPUTER is to use recursive descent. This saves
the time that would be spent figuring out the parse tables
for ll(1). Also, there are a zillion states for even a moderate
sized language.

Nick.
.

henry@utzoo.UUCP (Henry Spencer) (05/17/84)

Rob Warnock says, in part:

   It also happens to be the case that IF the grammar is LL(1) or even
   reasonably close, a recursive-descent parser is:

	...

	4. Capable of acceptable error-handling (assuming you want to
	   detect errors, not "fix" them)
	
This is actually an understatement.  Error-handling is much easier in
recursive-descent/LL(1) than in LALR systems like yacc.  It is possible
to build an error-handling module which fits between the parser and the
scanner which does all the work.  The parser has to be specific about
what it wants -- this just means a slightly unusual-looking "scanner"
interface for the parser -- but the parser then sees a syntactically-
correct program regardless of what the user feeds in.  The key feature
of top-down parsing, for this and other purposes, is that the software
"knows what it wants":  it has a fairly specific idea of what sort of
input it's expecting at a given instant, and can take intelligent action
if there is a mismatch.  Bottom-up methods like yacc don't give you this
sort of detailed context to work in, which is why error repair is such
a headache for them.

The above is not theory; such an error-repair system was built here at
U of T years ago for the SP/k compiler, and several similar things for
other languages have been done since.  It really works well.
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

lowry@fortune.UUCP (05/24/84)

Regarding the comment that recursive desecent "automatically"
requires the use of a hiagher level langauge---not true.  If
you manage your own stack of local variables, you can do it
in assembly language.  I know; I did it once.  On an apple, no less.

nessus@mit-eddie.UUCP (Doug Alan) (06/06/84)

>	From: henry@utzoo.UUCP
>	This is actually an understatement.  Error-handling is much
>	easier in recursive-descent/LL(1) than in LALR systems like
>	yacc.

I find this extremely hard to believe.  It is amazingly easy to write a
very good error recovery system for an LALR parser.  In fact, I was able
to write an error recovery system for an LALR Modula 2 parser in less
than a day.  And not only that, it worked much better than the error
recovery in any other compiler I've ever seen.  How much easier can you
get?

What makes it so easy to do good and easy error recovery systems for
LALR parsers is that you have the parse stack directly available to you
and you can copy it and fiddle with it until you get something that
works.  You can't do this with a recursive decent parser.  Though,  of
course, there are ways of doing error recovery with a recursive decent
parser, I can't imagine that any of them are easier.
-- 
				-Doug Alan
				 mit-eddie!nessus
				 Nessus@MIT-MC

				"What does 'I' mean"?