#!/usr/bin/perl
#####
# from http://www.adp-gmbh.ch/perl/rec_descent.html
#
# As Josh pointed out, the original failed to do
# what was expected with "x=0; x=x+1".
#
# This one does better.
# The "statements" rule is like statement(s) but with optional ; between.
# The result in statements is an array ref [statement1, statement2, ...]
# from which we pop off last entry.
#
###############
use strict;
use warnings;

use Parse::RecDescent;

my $grammar = q {
                                         { my %vars }
start:          statements		 { pop @{$item[1]} }

statements:     statement(s /;/)

statement:      variable '=' statement   { $vars{$item[1]} = $item[3] }
              | expression               

expression:     term '+' expression      { $item[1] + $item[3] }
              | term '-' expression      { $item[1] - $item[3] }
              | term			 

term:           factor '*' term          { $item[1] * $item[3] }
              | factor '/' term          { $item[1] / $item[3] }
              | factor			 

factor:         number
              | variable                 { $vars{$item[1]} ||= 0 }
              | '+' factor               { $item[2] }
              | '-' factor               { -1 * $item[2] }
              | '(' statement ')'        { $item[2] }

number:         /\d+/                    

variable:       /[a-z]+/i

};

my $parser = Parse::RecDescent->new($grammar);

my @text = ( "three=3;six=2*three;eight=three+5;2+eight*six+50",
	     "x",
	     "x+1",
	     "x=0; x+1",
	     "x=0; x=x+1",
	     "x=0; x=x+1; x",
	     "x=0; x=x+1; x+1",
	    );
for my $text (@text){
  my $result = $parser->start($text);
  print "result of '$text' is $result .\n";
  # use Data::Dumper;
  # print Dumper($result);
}



