Has anyone implemented BASIC in Python?

Michael J. Fromberger Michael.J.Fromberger at Clothing.Dartmouth.EDU
Wed Aug 25 00:37:59 EDT 2004


In article <285ni0hmusfgqslj9gnhhimvanr2jh0be3 at 4ax.com>,
 Andrea Griffini <agriff at tin.it> wrote:

> On Mon, 23 Aug 2004 11:10:53 -0400, "Michael J. Fromberger"
> <Michael.J.Fromberger at Clothing.Dartmouth.EDU> wrote:
> 
> >when you are dealing with a more complex general-purpose language, and 
> >one whose grammar needs to evolve over time, then I think a 
> >parser-generator is a much better solution by far.
> 
> Like I said before may be it's me... but I see the grammar definition 
> and the sparse collection of C code snippets required to use yacc & 
> friends harder to understand than a recursive descending parser.

Admittedly, YACC and Bison have a somewhat steep initial learning curve.  
However, in terms of long-term maintainability, that learning curve is 
well worth the trouble for non-trivial language projects.  By combining 
the context-free grammar with associated semantic information (the 
so-called "sparse collection of C code snippets" you mention above), and 
allowing the tool to generate your parser code, you are much more likely 
to get a parser you can actually argue is correct.

Correct code may not be fashionable, but it is certainly much more 
maintainable than incorrect code, or code whose correctness cannot 
easily be determined.  The usual response:  "It's worked fine so far!" 
does not cut much ice when you're writing something important, as I am 
sure you know!

> for me, shift-reduce parser are beyond the ROI point.

Ah, well.  Suit yourself.  :)  In my opinion, that's equivalent to a 
builder saying, "Power tools do not have good return-on-investment over 
doing all our cutting, fitting, and joining using hand tools."  But, 
perhaps if you only ever need to work with simple grammars, that might 
be true for your own needs.

> >The chief trouble in maintaining a hand-written recursive descent parser 
> >is that the grammar for the input language is hidden inside the 
> >implementation.
> 
> Normally the grammar is documented ALSO elsewhere in a very
> human readable form.

Of course -- but how do you know your human-readable documentation has 
any necessary correlation with the actions of the parser?  With a hand 
coded parser, you basically have nothing but the author's hopeful 
assurance.  Automatically generated parsers are generated directly from 
an EBNF analogue of the grammar (e.g., YACC input), which means you can 
be sure the parser matches the grammar, unless there's a bug in the 
parser generator, and the latter is S.E.P.

And, heck, if you don't like bottom-up shift-reduce parsers of the LR(k) 
family, there are even parser-generators that generate top-down 
predictive parsers of various stripes (e.g., ANTLR), that are reputed to 
work well for many common tasks.

> >Also, error-handling is tricky in recursive descent, because 
> >much of the parser's state is implicit in stack frames that must be 
> >correctly unwound when an error forces you to bail out.  
> 
> Here is an excerpt of a parser I wrote about a dozen years ago
> in C. [...]
> 
>       case -RW_IF :
> 	  SkipToken();
> 	  c=ParseExpr();
> 	  if (!ParseError && NextIs(-RW_THEN))
> 	    { t=ParseStat();
> 	      if (!ParseError)
> 		{ if (CurToken==-RW_ELSE)
> 		    { SkipToken(); e=ParseStat(); }
> 		  else
> 		    e=NULL;
> 		  r=NewIf(c,t,e);
> 		}
> 	      else
> 		{ Deref(t); Deref(c); }
> 	    }
> 	  else
> 	    Deref(c);
> 	  break;
> 
> This is the case for parsing IF-THEN-ELSE statement.

If you'll forgive me for being a bit harsh, I find this code practically 
unreadable.  You've got at least three layers of nested error-handling 
here, just to make sure your dereferences all happen in the correct 
order.  Having to explicitly check error codes like this, and manually 
handle memory, is PRECISELY the reason why I argued that error-handling 
is tricky in recursive descent.  If you handed me this code and asked me 
to find a problem in it, I'd probably tear all my hair out.

Does that mean you shouldn't use recursive descent?  Of course not!  The 
technique is clever, and has its place.  But this example could have 
been so much nicer, even just using a table-driven top-down predictive 
parser, rather than an explicitly recursive one.

> Of course this is just my personal view, based on the experience
> I had on the few languages I implemented. For example I never
> dared to write a parser for C++

Yeah.  Well, C++ is pretty awful to parse, no matter WHAT type of 
algorithm you want to use.  I won't dispute that at all. :)

> PS: Ok ok ok... I'll give shift-reduce parser and their tools
>     another look. May be it's just my laziness that is showing up and 
>     my brain that tries to find excuses for justifying it.

I think that, in the long run, you will probably find your efforts well 
rewarded.  I didn't intend to become the advocate for automatic parser 
generators, but I do think that someone just starting out should be 
aware that recursive descent is not always the best solution.

-M

-- 
Michael J. Fromberger             | Lecturer, Dept. of Computer Science
http://www.dartmouth.edu/~sting/  | Dartmouth College, Hanover, NH, USA



More information about the Python-list mailing list