Equation: 1+x^2*((1+y)*3)+5*(4+(4+3)) + / \__________________ 1 + __________/ \ * 5 __/ \__ 5 ^ + / \ / \__ x 2 3 * / \ y 3 Equation: ((4+c)*y)^(4+2)/5-s^200 - __/ \__ / ^ __/ \ / \ ^ 5 s 2 ______/ \ 0 + 6 0 __/ \__ * * / \ / \ 4 y c y Equation: 2+2 4 ##```## use strict; use warnings; use Data::Dumper; my %ops = ( '+' => sub { \$_[0] + \$_[1] }, '-' => sub { \$_[0] - \$_[1] }, '*' => sub { \$_[0] * \$_[1] }, '/' => sub { \$_[1] or die "Division by zero.\n"; \$_[0] / \$_[1] }, '^' => sub { \$_[0] ** \$_[1] }, ); my @ops = ( '^', '*', '/', '+', '-' ); my @parens = ( '(', ')' ); my @operands = ( '\d+', '\w+' ); my \$tokre = join "|", @operands, map { "\Q\$_\E" } @ops, @parens ; sub reduce_parens { my \$tokens = shift; my @temp; while( @\$tokens ) { my \$tok = shift @\$tokens; if( \$tok eq '(' ) { push @temp, [ reduce_parens( \$tokens ) ]; next; } return @temp if \$tok eq ')'; push @temp, \$tok; } return @temp; } sub reduce_ops { my( \$tokens, \$op ) = @_; my @temp; while( @\$tokens ) { my \$tok = shift @\$tokens; if( ref( \$tok ) ) { push @temp, [ reduce_ops( \$tok, \$op ) ]; next; } if ( \$tok eq \$op ) { my \$left = [ @temp ]; my \$right = [ reduce_ops( \$tokens, \$op) ]; return ( 1==@\$left?\$\$left[0]:\$left, \$op, 1==@\$right?\$\$right[0]:\$right ); } push @temp, \$tok; } return @temp; } sub distributivity { my \$tokens = shift; if( ref(\$tokens) && \$\$tokens[1] =~ /^(\*|\/)\$/ ) { if( ref( \$\$tokens[0] ) && \$\$tokens[0]->[1] =~ /^(\-|\+)\$/ ) { my \$mult = \$\$tokens[1]; \$\$tokens[1] = \$\$tokens[0]->[1]; my \$left = \$\$tokens[0]->[0]; my \$right = \$\$tokens[0]->[2]; \$\$tokens[0] = [ \$left, \$mult, \$\$tokens[2] ]; \$\$tokens[2] = [ \$right, \$mult, \$\$tokens[2] ]; } elsif( ref( \$\$tokens[2] ) && \$\$tokens[2]->[1] =~ /^(\-|\+)\$/ ) { my \$mult = \$\$tokens[1]; \$\$tokens[1] = \$\$tokens[2]->[1]; my \$left = \$\$tokens[2]->[0]; my \$right = \$\$tokens[2]->[2]; \$\$tokens[2] = [ \$\$tokens[0], \$mult, \$right ]; \$\$tokens[0] = [ \$\$tokens[0], \$mult, \$left ]; } } ref( \$\$tokens[\$_] ) and distributivity( \$\$tokens[\$_] ) for 0,2; } sub reduce_literals { my \$tokens = shift; ref \$\$tokens[\$_] and \$\$tokens[\$_] = reduce_literals( \$\$tokens[\$_] ) for 0, 2; if( !ref(\$\$tokens[0]) && !ref(\$\$tokens[1]) && (\$\$tokens[0] !~ /\D/) && (\$\$tokens[2] !~ /\D/) ) { return \$ops{\$\$tokens[1]}->( \$\$tokens[0], \$\$tokens[2] ); } return \$tokens; } sub parse_equation { my \$eq = shift; my \$tokens = [ \$eq =~ /(\$tokre)/g ]; @\$tokens = reduce_parens \$tokens; @\$tokens = reduce_ops \$tokens, \$_ for reverse @ops; distributivity \$tokens; \$tokens = reduce_literals \$tokens; # print Dumper \@tokens; return \$tokens; } sub prepare { my( \$subtree, \$level, \$col, \$graph ) = @_; my \$lcol = 0; if( ref(\$subtree) ) { \$lcol = prepare( \$subtree->[0], \$level+2, \$col, \$graph ); # parse left side of tree, keep top position \$lcol and \$graph->[\$level]->[\$_] = '_' for \$lcol..\$\$col-1; # draw horizontal line \$graph->[\$level]->[\$\$col++] = '/'; \$graph->[\$level-1]->[\$\$col++] = \$subtree->[1]; \$lcol = \$\$col; # new root of the tree \$graph->[\$level]->[\$\$col++] = '\\'; my \$rcol = prepare( \$subtree->[2], \$level+2, \$col, \$graph ); # parse right side of the tree, keep its top position \$rcol and \$graph->[\$level]->[\$_] = '_' for \$lcol+1..\$rcol-2; # draw horizontal line } else { \$graph->[\$level++ -1]->[\$\$col] = \$_ for split //, \$subtree; # leaf \$\$col++; } return \$lcol; # return column of root } sub printTree { my \$root = shift; my @graph; my \$col = 1; prepare( \$root, 1, \\$col, \@graph ); for my \$row ( @graph ) { print \$_ // ' ' for @\$row; print "\n"; } } for( ){ print "\nEquation: \$_\n"; printTree parse_equation( \$_ ); } __DATA__ 1+x^2*((1+y)*3)+5*(4+(4+3)) ((4+c)*y)^(4+2)/5-s^200 2+2 ```