| Language-MPI documentation | Contained in the Language-MPI distribution. |
Language::MPI - 2008.0217 Message Parsing Interpreter
Processor for the Message Parsing Interpreter text composition language, based on the MPI found in MU* online environments, adapted for more general semantics.
http://en.wikipedia.org/wiki/Message_Parsing_Interpreter
use Language::MPI;
$node = new Language::MPI($noderef);
$node->setvar("varname", "varval");
$results = $node->parse("tick {set:varname,{time:}} tock");
$val = $node->readvar("varname");
MPI assumes an operating environment consisting of a set of nodes each of which has a set of named properties. How these nodes and properties are stored and structured is up to the application except that:
MPI, in the interest of more general usage, expects some support subroutines to be supplied by app to access nodes and properties. Should any of these not be supplied, errors are trapped to prevent crashing. Functions not needing these should still work properly. Should the application designer wish, app data to be passed to these callbacks may be set into and read from the object by the setvar() and readvar() methods.
$thisnode is a noderef. $pattern is a string pattern used to specify which nodes 'neighboring' the current node are of interest. returns list of noderefs;
$propname is the string name of a property. returns propval;
$propat is a string specifier to a property directory or a subset of properties. returns list of propnames;
perl Makefile.PL make make install
Or simply copy the MPI.pm file to Language/ under the perl modules directory. README and the man file for this package exist as pod data in MPI.pm.
Some MPI standard functions incomplete or unimplimented. Testing incomplete.
This code developed using perl 5.8.8. Might work with perl 5.6.0 or older with proper libraries. Uses strict and warning.
Copyright (c)2007 Peter Hanely. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Create new MPI object.
Sets a variable in the mpi object to a scalar value.
Reads a scalar value from the mpi object
Processes a string for MPI codes
| Language-MPI documentation | Contained in the Language-MPI distribution. |
# MPI.pm
use strict; use warnings; # warning good for debug, but produce noise from good code no warnings qw(uninitialized); #use Carp; package Language::MPI; our ($VERSION, @ISA, @EXPORT_OK, $perl_list); #use vars qw($VERSION, @ISA, @EXPORT_OK, $perl_list); BEGIN { require Exporter; our ($VERSION, @ISA, @EXPORT_OK); @ISA = qw(Exporter); @EXPORT_OK = qw(parse setvar readvar simp_functions); $VERSION = "2008.0217"; } # control functions alter execution of their parameters, # and thus parse their own parameters. my %ctrl_functions = ( 'debug' => \&func_debug, 'debugif' => \&func_debugif, 'filter' => \&func_filter, 'fold' => \&func_fold, 'for' => \&func_for, 'foreach' => \&func_foreach, # 'func' => \&func_func, 'if' => \&func_if, 'lit' => \&func_lit, 'lsort' => \&func_lsort, 'neighbors' => \&func_neighbors, 'parse' => \&func_parse, 'while' => \&func_while, 'with' => \&func_with ); # simple functions have their parameters parsed by calling code. my %simp_functions = ( 'abs' => \&func_abs, 'add' => \&func_add, 'and' => \&func_and, 'attr' => \&func_attr, 'convsecs' => \&func_convsecs, 'convtime' => \&func_convtime, 'count' => \&func_count, 'date' => \&func_date, 'debug' => \&func_debug, 'debugif' => \&func_debugif, 'dec' => \&func_dec, 'default' => \&func_default, 'delprop' => \&func_delprop, 'dice' => \&func_dice, 'dist' => \&func_dist, 'div' => \&func_div, 'eq' => \&func_eq, 'escape' => \&func_escape, 'eval' => \&func_eval, 'exec' => \&func_exec, 'filter' => \&func_filter, 'fold' => \&func_fold, 'for' => \&func_for, 'foreach' => \&func_foreach, 'ftime' => \&func_ftime, 'fullname' => \&func_fullname, 'func' => \&func_func, 'ge' => \&func_ge, 'gt' => \&func_gt, 'if' => \&func_if, 'inc' => \&func_inc, 'index' => \&func_index, 'instr' => \&func_instr, 'isnum' => \&func_isnum, 'lcommon' => \&func_lcommon, 'le' => \&func_le, 'list' => \&func_list, 'listprops' => \&func_listprops, 'lit' => \&func_lit, 'lmember' => \&func_lmember, 'lrand' => \&func_lrand, 'lremove' => \&func_lremove, 'lsort' => \&func_lsort, 'lt' => \&func_lt, 'ltimestr' => \&func_ltimestr, 'lunion' => \&func_lunion, 'lunique' => \&func_lunique, 'max' => \&func_max, 'midstr' => \&func_midstr, 'min' => \&func_min, 'mklist' => \&func_mklist, 'mod' => \&func_mod, 'mult' => \&func_mult, 'name' => \&func_name, 'ne' => \&func_ne, 'neighbors2' => \&func_neighbors2, 'nl' => \&func_nl, 'not' => \&func_not, 'null' => \&func_null, 'or' => \&func_or, 'parse' => \&func_parse, 'prop' => \&func_prop, 'rand' => \&func_rand, 'secs' => \&func_secs, 'select' => \&func_select, 'set' => \&func_set, 'sign' => \&func_sign, 'smatch' => \&func_smatch, 'stimestr' => \&func_stimestr, 'store' => \&func_store, 'strip' => \&func_strip, 'strlen' => \&func_strlen, 'sublist' => \&func_sublist, 'subst' => \&func_subst, 'subt' => \&func_subt, 'time' => \&func_time, 'timestr' => \&func_timestr, 'timesub' => \&func_timesub, 'tolower' => \&func_tolower, 'toupper' => \&func_toupper, 'tzoffset' => \&func_tzoffset, 'v' => \&func_v, 'version' => \&func_version, 'while' => \&func_while, 'with' => \&func_with, 'xor' => \&func_xor );
sub func_abs { my ($this, $val) = @_; abs $val->[0]; }
sub func_add { my ($this, $val) = @_; my ($num, $tot); foreach $num (@$val) { $tot += $num; } $tot; }
sub func_and { my ($this, $val) = @_; my ($num, $tot); $tot = 1; foreach $num (@$val) { #$tot &&= $num; if (!$num) { $tot = 0; } } $tot; }
sub func_attr { my ($this, $val) = @_; #stub $$val[-1]; } sub func_convsecs { my ($this, $val) = @_; } sub func_convtime { my ($this, $val) = @_; }
sub func_count { my ($this, $val) = @_; my (@arry); @arry = &unpack_list($val->[0]); return (scalar (@arry)); }
sub func_date { my ($sec, $min, $hour, $mday, $mon, $year) = gmtime (time()); if ($year < 1000) { $year += 1900; } $mon++; "$mon/$mday/$year"; } sub func_debug { } sub func_debugif { }
sub func_dec { my ($this, $val) = @_; my ($var, $inc) = @$val; $inc = $inc || 1; $this->{$var} -= $inc; }
sub func_default { my ($this, $val) = @_; my ($indx) = 0; while (($indx < @$val) && !($val->[$indx])) { $indx ++ } if ($indx < @$val) { $val->[$indx]; } else { ""; } }
sub func_delprop { my ($this, $val) = @_; my ($prop, $obj) = @$val; $obj = $obj || $this->{'_node'}; if (defined &mpi_propset) { eval (&mpi_propset($obj, $prop, "", $this)); } }
sub func_dice { my ($this, $val) = @_; my ($range, $count, $bonus) = @$val; my ($indx, $tot); if ($count <= 0) { $count = 1; } for ($indx = 0; $indx < $count; $indx ++) { $tot += int(rand($range)+1); } $tot+$bonus; }
sub func_dist { my ($this, $val) = @_; my ($x1, $y1, $z1, $x2, $y2, $z2) = @$val; if (@$val == 4) { ($x2, $y2) = ($z1, $x2); } my ($dx, $dy, $dz) = ($x2-$x1, $y2-$y1, $z2-$z1); sqrt($dx*$dx + $dy*$dy + $dz*$dz); }
sub func_div { my ($this, $val) = @_; int($val->[0]/$val->[1]); }
sub func_eq { my ($this, $val) = @_; $val->[0] eq $val->[1]; } sub func_escape { }
sub func_eval { my ($this, $val) = @_; my ($tot, $param); foreach $param(@$val) { $tot .= &parse($this, $param); } $tot; }
sub func_exec { my ($this, $val) = @_; my ($prop, $obj) = @$val; my ($tmp) = ""; my ($propval) = eval {&mpi_prop($obj || $this->{'_node'}, $prop, $this)}; if ($propval) { $tmp = &parse($this, $propval) || "" }; $tmp; } sub func_filter { } sub func_fold { }
# control function, parses its own parameters sub func_for { my ($this, $params) = @_; my ($varname,$start,$end,$increment,$command, $result, $results); ($varname, $params) = &parse_parameter($this, $params); ($start, $params) = &parse_parameter($this, $params); ($end, $params) = &parse_parameter($this, $params); ($increment, $command) = &parse_parameter($this, $params); $this->{$varname} = $start; if ($increment > 0) { while ($this->{$varname} <= $end) { ($result, $params) = &parse_parameters($this, $command); $results .= join '', @$result; $this->{$varname} += $increment; } } elsif ($increment < 0) { while ($this->{$varname} <= $end) { ($result, $params) = &parse_parameters($this, $command); $results .= join '', @$result; $this->{$varname} += $increment; } } else # sanity case { ($result, $params) = &parse_parameters($this, $command); $results .= join '', @$result; } ($results, $params); }
sub func_foreach { my ($this, $params) = @_; my ($varname,$list,$expr,$sep, @list, $val, $res, $result); ($varname, $params) = &parse_parameter($this, $params); ($list, $expr) = &parse_parameter($this, $params); ($params) = &skip_param($this, $expr); #$sep = $sep || "\n"; @list = unpack_list($list, $sep); foreach $val(@list) { $this->{$varname} = $val; ($res) = &parse_parameter($this, $expr); $result .= $res; } ($res, $params); } sub func_ftime { } sub func_fullname { }
sub func_func { my ($this, $val) = @_; my ($func, $vars, $code) = @$val; $this->{"_f_$func"} = $code; $this->{"_f_$func v"} = $vars; "$func, $vars, $code"; }
sub func_ge { my ($this, $val) = @_; $val->[0] >= $val->[1]; }
sub func_gt { my ($this, $val) = @_; $val->[0] > $val->[1]; }
sub func_if { my ($this, $params) = @_; my ($check, $ret); ($check, $params) = &parse_parameter($this, $params); if ($check) { ($ret, $params) = &parse_parameter($this, $params); ($params) = &skip_param($this, $params); } else { ($params) = &skip_param($this, $params); ($ret, $params) = &parse_parameter($this, $params); } $ret; }
sub func_inc { my ($this, $val) = @_; my ($var, $inc) = @$val; $inc = $inc || 1; $this->{$var} += $inc; }
sub func_index { my ($this, $val) = @_; my ($prop, $obj) = @$val; $obj = $obj || $this->{"_node"}; $prop = eval {&mpi_prop($obj, $prop, $this)}; if ($prop) { eval {&mpi_prop($obj, $prop, $this)} || ""; } }
sub func_instr { my ($this, $val) = @_; my ($str1, $str2) = @$val; index($str1, $str2) + 1; } sub func_isnum { my ($this, $val) = @_; my ($num) = @$val; if (!$num) { $num = '0e0'; } $num; }
sub func_lcommon { my ($this, $val) = @_; my ($l1, $l2) = @$val; my (%h, $i, @res); foreach $i(&unpack_list($l1)) { $h{$i} = 1; } foreach $i(&unpack_list($l2)) { if ($h{$i}) { push @res, $i; undef $h{$i}; # remove duplicates. } } &pack_list(@res); }
sub func_le { my ($this, $val) = @_; $val->[0] <= $val->[1]; }
sub func_list { my ($this, $val) = @_; my ($list, $obj) = @$val; my (@list, $i); $obj = $obj || $this->{"_node"}; foreach $i(eval{&mpi_props($obj, $list, $this)}) { push @list, eval(&mpi_prop($obj, $i, $this)); } &pack_list(@list); }
sub func_listprops { my ($this, $val) = @_; my ($list, $obj) = @$val; $obj = $obj || $this->{"_node"}; &pack_list(eval{&mpi_props($obj, $list, $this)}); }
sub func_lit { my ($this, $param) = @_; my ($lit); ($param, $lit) = &skip_parameters($this, $param); $lit; }
sub func_lmember { my ($this, $val) = @_; my ($list, $item, $del) = @$val; my ($i, @list); @list = &unpack_list($list, $del); for ($i = 0; $i < @list && $list[$i] ne $item; $i++) { } if ($list[$i] eq $item) { return $i+1; } 0; }
sub func_lrand { my ($this, $val) = @_; my ($list, $del) = @$val; my ($i, @list); @list = &unpack_list($list, $del); $list[int(rand @list)]; }
sub func_lremove { my ($this, $val) = @_; my ($l1, $l2) = @$val; my (%h, $i, @res); foreach $i(&unpack_list($l1)) { $h{$i} = 1; } foreach $i(&unpack_list($l2)) { if (!$h{$i}) { push @res, $i; $h{$i} = 1; # remove duplicates. } } &pack_list(@res); } sub func_lsort { my ($this, $params) = @_; my ($list, @list, $var1, $var2, $code); ($list, $params) = &parse_parameter($this, $params); # do fancy sort later &pack_list(sort &unpack_list($list)); }
sub func_lt { my ($this, $val) = @_; $val->[0] < $val->[1]; } sub func_ltimestr { }
sub func_lunion { my ($this, $val) = @_; my ($l1, $l2) = @$val; my (%h, $i); foreach $i(&unpack_list($l1)) { $h{$i} = 1; } foreach $i(&unpack_list($l2)) { $h{$i} = 1; } &pack_list(keys %h); }
sub func_lunique { my ($this, $val) = @_; my ($l1, $l2) = @$val; my (%h, $i, @res); foreach $i(&unpack_list($l1)) { if (!$h{$i}) { $h{$i} = 1; push @res,$i; } } &pack_list(@res); }
sub func_max { my ($this, $val) = @_; my ($tot, $var); $tot = $val->[0]; foreach $var(@$val) { if ($tot > $var) { $tot = $var; } } $tot; }
sub func_midstr { my ($this, $val) = @_; my ($str, $pos1, $pos2); substr ($str, $pos1, $pos2); }
sub func_min { my ($this, $val) = @_; my ($tot, $var); $tot = $val->[0]; foreach $var(@$val) { if ($tot > $var) { $tot = $var; } } $tot; }
sub func_mklist { my ($this, $val) = @_; #join "\n", @$val; &pack_list(&unpack_list($val)); }
sub func_mod { my ($this, $val) = @_; $val->[0] % $val->[1]; }
sub func_mult { my ($this, $val) = @_; my ($num, $tot); $tot = 1; foreach $num (@$val) { $tot *= $num; } $tot; } sub func_name { }
sub func_ne { my ($this, $val) = @_; $val->[0] ne $val->[1]; }
sub func_neighbors { my ($this, $params) = @_; my ($varname,$pattern,$expr, @list, $val, $res, $result); ($varname, $params) = &parse_parameter($this, $params); ($pattern, $expr) = &parse_parameter($this, $params); @list = eval {&mpi_neighbors($this->{'_node'}, $pattern, $this)}; foreach $val(@list) { $this->{$varname} = $val; ($res, $params) = &parse_parameter($this, $expr); $result .= $res; } if (@list == 0) { $res = ""; $params = &skip_parameters($this, $expr); $params =~ /^\}(.*)/; $params = $! || $params; } ($res, $params); }
sub func_neighbors2 { my ($this, $params) = @_; my ($pattern) = @$params; &pack_list(eval {&mpi_neighbors($this->{'_node'}, $pattern, $this)}); }
sub func_nl { "\n"; }
sub func_not { my ($this, $val) = @_; !($val->[0]); }
sub func_null { ""; }
sub func_or { my ($this, $val) = @_; my ($num, $tot); foreach $num (@$val) { #$tot ||= $num; if (!$num) { $tot = 0; } } $tot; } sub func_parse { }
sub func_prop { my ($this, $val) = @_; my ($prop, $obj) = @$val; $obj = $obj || $this->{"_node"}; eval {&mpi_prop($obj, $prop, $this)} || ""; }
sub func_rand { my ($this, $val) = @_; my ($list, $obj) = @$val; my (@list, $i); $obj = $obj || $this->{"_node"}; @list = eval{&mpi_props($obj, $list, $this)}; eval(&mpi_prop($obj, $list[int(rand @list)], $this)); }
sub func_secs { time(); } sub func_select { }
sub func_set { my ($this, $val) = @_; my ($var, $v) = @$val; if ($var =~ /^[a..zA..Z]/) # some vars are reserved for engine use { $this->{$var} = $v; } }
sub func_sign { my ($this, $val) = @_; $val->[0] <=> 0; }
sub func_smatch { my ($this, $val) = @_; my ($str, $pat) = @$val; $str =~ /($pat)/; $1 } sub func_stimestr { }
sub func_store { my ($this, $val) = @_; my ($str, $prop, $obj) = @$val; $obj = $obj || $this->{'_node'}; eval {&mpi_propset($obj, $prop, $str, $this)} || ""; }
sub func_strip { my ($this, $val) = @_; chomp $val->[0]; $val->[0] =~ s/^\s*//; $val->[0] =~ s/\s*$//; $val->[0]; }
sub func_strlen { my ($this, $val) = @_; length $val->[0]; }
sub func_sublist { my ($this, $val) = @_; my ($list, $pos1, $pos2, $sep) = @$val; my @list = &unpack_list($list, $sep); if (!defined($pos2)) { $pos2 = @list; } &pack_list( splice( @list, $pos1+1, $pos2-$pos1) ); }
sub func_subst { my ($this, $val) = @_; my ($str, $old, $new) = @$val; $str =~ s/$old/$new/g; $str; }
sub func_subt { my ($this, $val) = @_; my ($num, $tot); $tot = shift @$val; foreach $num (@$val) { $tot -= $num; } $tot; }
sub func_time { my ($sec, $min, $hour, $mday, $mon, $year) = gmtime(time()); if ($year < 1000) { $year += 1900; } "$hour:$min:$sec"; } sub func_timestr { } sub func_timesub { }
sub func_tolower { my ($this, $val) = @_; lc $val->[0]; }
sub func_toupper { my ($this, $val) = @_; uc $val->[0]; } sub func_tzoffset { }
sub func_v { my ($this, $val) = @_; $this->{$val->[0]}; }
sub func_version { $VERSION; }
sub chk_cond { my ($this, $cond) = @_; my ($res) = &parse_parameter($this, $cond); # debug # print "cond $res -- "; $res; } sub func_while { my ($this, $params) = @_; my ($go,$cond,$expr,$sep, $val, $res, $result, %save, $maxloop); $cond = $params; ($expr) = &skip_param($this, $params); ($params) = &skip_param($this, $expr); $maxloop = 255; #sanity while (&chk_cond($this, $cond) && ($maxloop >= 0)) { ($res, $params) = &parse_parameter($this, $expr); $result .= $res; $maxloop --; } ($result, $params); }
sub func_with { my ($this, $params) = @_; my ($varname,$expr,$val, $res, %save); ($varname, $expr) = &parse_parameter($this, $params); foreach $val(split /:/, $varname) { $save{$val} = $this->{$val}; $this->{$val} = ''; # a 'null' that isn't undef } ($res, $params) = &parse_parameter($this, $expr); foreach $val(split /:/, $varname) { $this->{$val} = $save{$val}; } ($res, $params); }
sub func_xor { my ($this, $val) = @_; my ($num, $tot); $tot = shift @$val; foreach $num (@$val) { $tot = ($tot xor $num); } $tot; } # ==================================================== # core routines # ====================================================
sub new { my ($class, $node) = @_; my (%this); $this{'_node'} = $node; bless \%this, $class; }
sub setvar { my ($this, $var, $val) = @_; $this->{$var} = $val; }
sub readvar { my ($this, $var) = @_; $this->{$var}; } # unpack a list in either MPI \n delimited string or perl list ref sub unpack_list { my ($list, $sep) = @_; my (@list); if (ref $list) { @list = @$list; } else { $sep = $sep || "\n"; @list = split "\n", $list; } @list; } sub pack_list { if ($perl_list) {return \@_} else { join "\n", @_; } } # parse 1 parameter, which may contain a mix of plain text and MPI functions sub parse_parameter { my ($this, $text) = @_; my ($result, $prefix, $remainder, $match, $value); $result = ""; # find start of MPI function or terminating comma while ($text =~ /(,|\}|\{\w+:?)/ ) { $match = $1; # terminating comma or '}', split remaining text into result and remainder if ($match =~ /(,|\})/) { ($prefix, $remainder) = split $match, $text, 2; $result .= $prefix; return ($result, $remainder, $match); } # mpi function, evaluate elsif ($match =~ /\{(\w+)/ ) { ($prefix, $remainder) = split $match, $text, 2; $result .= $prefix; ($value, $remainder) = &eval_mpi($this, $1, $remainder); #if (! defined($value)) #{ "catch"; } $result .= $value; $text = $remainder; } } # nothing left to parse ($result.$text, '', ''); } # skip a parameter sub skip_param { my ($this, $text) = @_; my ($match, $prefix, $remainder); while ($text =~ /(,|\}|\{\w+:?)/ ) { $match = $1; # terminating comma or }, split remaining text into result and remainder if ($match =~ /([,\}])/) { ($prefix, $remainder) = split $1, $text, 2; return ($remainder, $match); } # mpi function, recurse in and skip elsif ($match =~ /\{(\w+)/ ) { ($prefix, $remainder) = split $match, $text, 2; ($remainder) = &skip_parameters($this, $remainder); $text = $remainder; } } # nothing left to parse (''); } # skip all remaining parameters sub skip_parameters { my ($this, $text) = @_; my ($match, $prefix, $prefix1, $remainder); while ($text =~ /(\}|\{\w+:?)/ ) { $match = $1; # terminating }, split remaining text into result and remainder if ($match =~ /([\}])/) { ($prefix, $remainder) = split $1, $text, 2; $prefix1 .= $prefix; return ($remainder, $prefix1, $1); } # mpi function, recurse in and skip elsif ($match =~ /\{(\w+)/ ) { ($prefix, $remainder) = split $match, $text, 2; $prefix1 .= $prefix.$match; ($remainder, $prefix, $match) = &skip_parameters($this, $remainder); $prefix1 .= $prefix.$match; $text = $remainder; } } # nothing left to parse (''); } # parse all parameters for the current function sub parse_parameters { my ($this, $text) = @_; my @params; my ($result, $term); $term = "zz"; while ($term =~ /[^\}]/) { ($result, $text, $term) = &parse_parameter($this, $text); push @params, $result; } (\@params, $text); } # evaluate 1 MPI function sub eval_mpi { my ($this, $function, $text) = @_; my ($result, $remainder, $params); $function = lc $function; $result = ""; # if function is in control function list, pass raw text and let function parse. if ($ctrl_functions{$function}) { ($result, $remainder) = &{$ctrl_functions{$function}}($this, $text); } # parse parameters and pass results to function. elsif ($simp_functions{$function}) { ($params, $remainder) = &parse_parameters($this, $text); ($result) = &{$simp_functions{$function}}($this, $params); } # else concat parameters elsif ($this->{"_f_$function"}) { my (@vars, $var, $i, %save); ($params, $remainder) = &parse_parameters($this, $text); @vars = split /:/, $this->{"_f_$function v"}; for ($i = 0; $i < @vars; $i++) { $var = $vars[$i]; $save{$var} = $this->{$var}; $this->{$var} = $params->[$i]; } $result = &parse($this, $this->{"_f_$function"}); foreach $var(split /:/, $this->{"_f_$function v"}) { $this->{$var} = $save{$var}; } } else { ($params, $remainder) = &parse_parameters($this, $text); $result = join (',', @$params); } ($result, $remainder); }
# parse a text block. simular to parse_parameter, except not terminating at ',' sub parse { my ($this, $text) = @_; my ($result, $value, $term); # while we have unprocessed text # find MPI, if any. # preceeding text copied to result. # MPI evaluated and retuned values added to result. $term = "zz"; # meaningless except not null while ($term) { ($value, $text, $term) = &parse_parameter($this, $text); $result .= $value.$term; } $result; } 1; __END__ use Language::MPI; # dummy test callbacks package Language::MPI; sub mpi_neighbors { my ($thisnode, $pattern) = @_; "neighbors:$thisnode,$pattern"; } sub mpi_prop { my ($thisnode, $propname) = @_; "$thisnode/$propname"; } sub mpi_props { my ($thisnode, $proppat) = @_; ("propa", "propb", "propc"); } sub mpi_propset { my ($thisnode, $propname, $val) = @_; "$thisnode,$propname,$val"; } package main; $mpi = new Language::MPI('dummy node'); @tests = ( 'plain text, no MPI', '{toupper:lower to upper}', '1+2 = {add:1,2} = 2+1', '{tolower:{toupper:lower to upper to lower}}', '{for:i,1,4,1,{v:i} }', '{abs:-2}', '{add:1,2,3}', '{and:2,4,6}', '{attr:attribute...,text}', '{mklist:list,items}', '{set:list,{mklist:list,items}}', '{count:{v:list}', '{date:}', '{set:var,1}', '{v:var}', '{dec:var,2}', '{inc:var,4}', '{default:1,2}', '{dice:6,3,2}', '{dist:3,4}', '{div:81,9,3}', '{eq:var1,var1}', '{eval:vars...}', '{foreach:var,{v:list},:{v:var}:}', '{ge:2,2}', '{gt:2,1}', '{if:true,true statement,false statement}', '{insrt:string1,ing}', '{lcommon:{v:list},{mklist:items}}', '{le:1,2}', '{lmember:{v:list},items}', '{lit:{a:dummy,mpi}}', '{max:1,2,3}', '{min:1,2,3}', '{mod:9,4}', '{mult:2,4,8}', '{ne:var1,var2}', '::{nl:}::', '{not:true}', '{null:a big statement to execute but not keep a value from...}', '{or:1,2,0}', '{secs:}', '{sign:-100}', '{smatch:string,ing}', '{strip: string }', '{strlen:string}', '{subst:string,ing,ung}', '{subt:100,50,25}', '{time:}', '{version:}', '{set:var,3}', '{while:{v:var},{v:var}>>{dec:var,1}:}', '{with:var,{v:var}}', '{xor:1,1,1}', 'The following are dummy without support functions', '{delprop:var,obj}', '{exec:prop,node}', '{index:prop,obj}', '{list:props,obj}', '{listprops:props,obj}', '{neighbors:varname,pattern,{v:varname}}', '{prop:property,node}', '{store:val,property,node}', ); foreach $test (@tests) { print "test: $test\n"; $result = $mpi->parse($test); print "result: [[$result]]\n\n"; } #Makefile.pl use ExtUtils::MakeMaker; WriteMakefile ( NAME => 'Language::MPI', VERSION_FROM => 'lib/Language/MPI.pm' ); __END__ MANIFEST Makefile.pl README lib/Language/MPI.pm __END__ additional notes: perldoc ExtUtils::MakeMaker::Tutorial #abs add and attr convsecs convtime #count date debug debugif dec default #delprop dice dist div eq escape #eval exec filter fold #ftime fullname ge gt #inc index instr isnum lcommon le #list listprops lmember lrand lremove #lsort lt ltimestr lunion lunique max #midstr min mklist mod mult name #ne nl not null or parse #prop rand secs select set sign #smatch stimestr store strip strlen sublist #subst subt time timestr timesub tolower #toupper tzoffset v version xor