Viewing file: soen229/math.pl | Back to directory listing
Author: Loren Segal | Last modified: February 20 2006 07:00 pm | Download

#!/usr/bin/perl -w
# @ Author: Loren Segal 
# @ Date: March 2005
#
use strict;	# strict programming style
 
###
## GLOBAL VARIABLES
###
my(%SYMTAB);       		# Global Symbol Table
my $NUMBER = qr/\d+(?:\.\d+)?/;	# global number match
 
sub init_symtable($);
sub load_symtable();
sub lex($);
sub do_op($$);
sub main();
 
###
## START OF PROGRAM
###
main();				# call main()
## end of program
 
####
### SYMBOL TABLE FUNCTIONS
####
 
sub init_symtable($)
{
	open(SYMTAB, $_[0]) or die("% Error: could not open file '$_[0]': $!\n");
}
 
sub load_symtable()
{
	local $_;
	for (<SYMTAB>) { $SYMTAB{$1} = $2 if (m/^\s*(\w+):.*\svalue=($NUMBER)/); }
	close(SYMTAB);
}
 
###
## MATH PARSING FUNCTIONS
###
 
## Function: lex(EXPR)
#
## Description: Does order of operations on the following EXPR, expanding each set of brackets
#		from inside out.
#
sub lex($) {
	local ($_) = @_;
	my $name;
	# Expand all identifiers
	for $name (sort keys %SYMTAB) { s/\b$name\b/$SYMTAB{$name}/g; }
	while (m/\(([^(]+)\)/) {
		my $ans = $1;
		$ans = do_op($ans, '^');	# Do exponents (not required)
		$ans = do_op($ans, '*');	# Do multiplication
		$ans = do_op($ans, '/');	# Do division
		$ans = do_op($ans, '%');	# Do modular division (not required)
		$ans = do_op($ans, '+');	# Do addition
		$ans = do_op($ans, '-');	# Do subtraction
		s/\([^(]+\)/$ans/;		# Expand the bracket into the answer
	}
	return "Syntax error." if (!m/^$NUMBER$/);
	return $_;
}
 
## Function: do_op(EXPR, OPERAND)
#
## Description: Searches through EXPR for a NUMBER followed by OPERAND followed by NUMBER and expands
#		it into its mathematical value. Continues until no matches are found for the OPERAND.
#		
sub do_op($$) {
	local $_ = shift(@_);
	my($op) = @_;
	my $re = qr/\b($NUMBER)\Q$op\E($NUMBER)\b/;
	while (m/$re/) {
		my $ans = eval("$1 $op $2");
		s/$re/$ans/;
	}
	return $_;
}
 
## Function: main()
#
## Description: main program function
#
sub main() {
	init_symtable("symbolfile.txt");	# initiate symbol table, hardcoded location
	load_symtable();			# load keyval pairs into table
	local $_ = <STDIN>;			# get mathematical input
	s/\s*//g;				# remove ALL spaces
	s/(.+)/($1)/;				# wrap the line in brackets ()
	$_ = lex($_);				# call the math function
	print "Answer: $_\n";			# print the answer
}