- 论坛徽章:
- 95
|
回复 12# yuanquan08
添加对 not 的支持:
- #!/usr/bin/perl
- use strict;
- use warnings;
- use feature "switch";
- use Data::Dumper;
- my @tokens;
- my %operators = (
- 'interact' => 1,
- 'inside' => 1,
- 'or' => 1,
- 'not' => 1,
- );
- while (my $exp = <DATA>) {
- @tokens = map { $_ ? $_ : () } split(/\s*([\(\)])\s*|\s+/, $exp);
- my $syn_tree = parser();
- print $exp;
- print Dumper($syn_tree), "\n";
- print Dumper(evaluate($syn_tree)), "\n";
- }
- sub evaluate {
- my $tree = shift;
- if (ref($tree) ne "HASH") {
- return ($tree);
- }
- given ($tree->{op}) {
- when (/or/) {
- return (evaluate($tree->{left}), evaluate($tree->{right}));
- }
- when (/not .+/) {
- return (evaluate($tree->{left}));
- }
- when (/interact|inside/) {
- my @left = evaluate($tree->{left});
- my @right = evaluate($tree->{right});
- my @result;
- foreach my $l (@left) {
- foreach my $r (@right) {
- push @result, "${l}_${r}";
- }
- }
- return @result;
- }
- }
- }
- sub parser {
- my ($left, $op, $right);
- while (@tokens) {
- my $token = shift @tokens;
- given ($token) {
- when (is_variable($token)) {
- if (not $left) {
- $left = $token;
- } elsif ($left and $op) {
- my $node = node($op, $left, $token);
- if (@tokens) {
- if ($tokens[0] =~ /\)/) {
- $right = $token;
- } else {
- $left = $node;
- $op = undef;
- }
- } else {
- return $node;
- }
- } else {
- die "Syntax error!";
- }
- }
- when (is_operator($token)) {
- if ($token =~ /not/) {
- if (@tokens and is_operator($tokens[0])) {
- $token = join(' ', $token, shift @tokens);
- } else {
- die "Syntax error!";
- }
- }
- if ($left) {
- $op = $token;
- } else {
- die "Syntax error!";
- }
- }
- when (/\(/) {
- if (not $left) {
- $left = parser();
- if (not @tokens) {
- return $left;
- }
- } elsif ($left and $op) {
- return node($op, $left, parser());
- } else {
- die "Syntax error!";
- }
- }
- when (/\)/) {
- if ($right) {
- return node($op, $left, $right);
- } elsif ($left and not $op) {
- return $left;
- }
- else {
- die "Syntax error!";
- }
- }
- }
- }
- }
- sub is_variable {
- my $token = shift;
- $token =~ /[[:upper:]]/;
- }
- sub is_operator {
- my $token = shift;
- $operators{$token};
- }
- sub node {
- my ($op, $left, $right) = @_;
- return {
- 'left' => $left,
- 'op' => $op,
- 'right' => $right,
- };
- }
- __DATA__
- A or B
- A or B or C
- (A or B)
- ((A or B) or C)
- (A or (B or C))
- (A not inside B)
- (A interact ((B or C) or (((D inside E) or F) inside G)))
- (A interact ((B or C) or (((D inside E) or F) not inside G)))
复制代码 |
|