

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!

