En este punto debo decir que no he podido reproducir el comportamiento
de las directivas <error:>
y <warning:>
tal y como las describe
Conway en el manual de Regexp::Grammars.
El siguiente ejemplo ilustra un conjunto de técnicas de gestión de errores que son independientes del soprote dado por Regexp::Grammars.
Se trata de la misma calculadora explicada en la sección 3.10.18.
pl@nereida:~/Lregexpgrammars/demo/calculator$ cat -n calculatorwitherrmanagement.pl 1 #!/usr/bin/env perl5.10.1 2 use strict; 3 use warnings; 4 use 5.010; 5 use Lingua::EN::Inflect qw(PL); 6 use Scalar::Util qw{blessed}; 7 8 my $rbb = do { 9 my ($warnings, $errors); # closure 10 sub warnings { $warnings } # accessor 11 sub errors { $errors } # accessor 12 13 use Regexp::Grammars; 14 qr{ 15 (?{ 16 $warnings = 0; 17 $errors = 0; 18 }) 19 \A<expr> 20 (?: \z 21 | 22 (.*) (?{ 23 # Accept the string but emit a warning 24 $warnings++; 25 local our $expr = \$MATCH{expr}{''}; 26 local our $endlegal = length($$expr) > 4? "... ".substr($$expr, -4) : $$expr; 27 warn "Warning: Unexpected '". substr($^N, 0, 10)."' after '$endlegal'\n"; 28 }) 29 ) 30 31 <objrule: expr> <[operands=term]> ** <[operators=addop]> 32 33 <objrule: term> <[operands=uneg]> ** <[operators=mulop]> 34 35 <objrule: uneg> <[operators=minus]>* <[operands=power]> 36 37 <objrule: power> <[operands=factorial]> ** <[operators=powerop]> 38 39 <objrule: factorial> <[operands=factor]> <[operators=(!)]>* 40 41 <objrule: factor> (<val=([+-]?\d+(?:\.\d*)?)>) 42 | \( <MATCH=expr> \) 43 | ([^-+(0-9]+) (?{ 44 # is + and not * to avoid infinite recursion 45 warn "Error: expecting a number or a open parenthesis, found: '". substr($^N, 0, 10)."'\n"; 46 $warnings++; 47 $errors++; 48 }) <MATCH=factor> 49 50 <token: addop> [+-] 51 52 <token: mulop> [*/] 53 54 <token: powerop> \*\*|\^ 55 56 <token: minus> - <MATCH=(?{ 'NEG' })> 57 58 }x; 59 }; 60 61 sub test_calc { 62 my $prompt = shift; 63 64 print $prompt; 65 while (my $input = <>) { 66 chomp($input); 67 68 local %/; 69 $input =~ m{$rbb}; 70 71 say warnings." ".PL('warning',warnings) if warnings; 72 say errors." ".PL('error',errors) if errors; 73 74 my $tree = $/{expr}; 75 if (blessed($tree)) { 76 do "PostfixCalc.pm"; 77 say "postfix: ".$tree->ceval; 78 79 do "EvalCalc.pm"; 80 say "result: ".$tree->ceval; 81 } 82 print $prompt; 83 } 84 say "Bye!" 85 } 86 87 ########## main 88 test_calc( 89 'Parsing infix arithmetic expressions (CTRL-D to end in unix) ', 90 );
Veamos algunas ejecuciones que incluyen entradas erróneas:
pl@nereida:~/Lregexpgrammars/demo/calculator$ ./calculatorwitherrmanagement.pl Parsing infix arithmetic expressions (CTRL-D to end in unix) 2+3 postfix: 2 3 + result: 5 Parsing infix arithmetic expressions (CTRL-D to end in unix) 2*(3+#) Error: expecting a number or a open parenthesis, found: '#)' Error: expecting a number or a open parenthesis, found: '#' Error: expecting a number or a open parenthesis, found: ')' Warning: Unexpected '*(3+#)' after '2' 4 warnings 3 errors postfix: 2 result: 2 Parsing infix arithmetic expressions (CTRL-D to end in unix) 2+#*4 Error: expecting a number or a open parenthesis, found: '#*' 1 warning 1 error postfix: 2 4 + result: 6 Parsing infix arithmetic expressions (CTRL-D to end in unix) Bye!Obsérvese los mensajes de error repetidos para la entrada
2*(3+#)
. Ellos son debidos a los reiterados intentos de
casar <factor>
en la regla de recuperación de errores:
41 <objrule: factor> (<val=([+-]?\d+(?:\.\d*)?)>) 42 | \( <MATCH=expr> \) 43 | ([^-+(0-9]+) (?{ 44 # is + and not * to avoid infinite recursion 45 warn "Error: expecting a number or a open parenthesis, found: '". substr($^N, 0, 10)."'\n"; 46 $warnings++; 47 $errors++; 48 }) <MATCH=factor>en este caso resulta imposible encontrar un factor. Se puede cambiar la conducta indicando un
(* COMMIT)
antes de la
llamada a <MATCH=factor>
:
41 <objrule: factor> (<val=([+-]?\d+(?:\.\d*)?)>) 42 | \( <MATCH=expr> \) 43 | ([^-+(0-9]+) (?{ 44 # is + and not * to avoid infinite recursion 45 warn "Error: expecting a number or a open parenthesis, found: '". substr($^N, 0, 10)."'\n"; 46 $warnings++; 47 $errors++; 48 }) (*COMMIT) <MATCH=factor>
en este caso la conducta es abandonar en el caso de que no se pueda encontrar un <factor>
:
pl@nereida:~/Lregexpgrammars/demo/calculator$ ./calculatorwitherrmanagement.pl Parsing infix arithmetic expressions (CTRL-D to end in unix) 2*(3+#) Error: expecting a number or a open parenthesis, found: '#)' 1 warning 1 error Parsing infix arithmetic expressions (CTRL-D to end in unix) 2*3 postfix: 2 3 * result: 6 Parsing infix arithmetic expressions (CTRL-D to end in unix) @ Error: expecting a number or a open parenthesis, found: '@' 1 warning 1 error Parsing infix arithmetic expressions (CTRL-D to end in unix) Bye!