El ejemplo más común, y tal vez el más acertado para aprender sobre el tema es al utilizar operaciones aritméticas, como en la siguiente gramática (escrita para Irony):
/* Terminales */
RegexBasedTerminal mas = new RegexBasedTerminal("suma", "[+]");
RegexBasedTerminal menos = new RegexBasedTerminal("resta", "[-]");
RegexBasedTerminal por = new RegexBasedTerminal("multiplicacion","[*]");
RegexBasedTerminal div = new RegexBasedTerminal("division", "[/]");
RegexBasedTerminal mod = new RegexBasedTerminal("mod", "[%]");
RegexBasedTerminal neg = new RegexBasedTerminal("mod", "[~]");
VALOR.Rule
= VALOR + por + VALOR
| VALOR + div + VALOR
| VALOR + mod + VALOR
| VALOR + exp + VALOR
| VALOR + mas + VALOR
| VALOR + menos + VALOR
| id
| entero
| neg + VALOR ;
El problema con esta gramática es que el árbol se puede generar de varias formas para la misma entrada (la gramática tiene ambigüedad) por lo que para la entrada:
1 + 2 * 3 - 4 % ~5
Se puede generar el árbol:
El cual ejecutando realizaría como resultado:
((((1+2) * 3) - 4) % ~5) = 0
Para lo cual escribimos la precedencia de operadores:
/* Precedencia */
RegisterOperators(1, smas, smenos);
RegisterOperators(2, spor, sdiv, mod);
RegisterOperators(3, Associativity.Left, neg);
Lo cual nos generaría un árbol que si da el resultado esperado:
((1 +( 2 * 3)) - (4 % (~5)))
Como es de notar se puede establecer que un signo tenga asociatividad por la izquierda o por la derecha, de la siguiente forma:
((((1+2) * 3) - 4) % ~5) = 0
Para lo cual escribimos la precedencia de operadores:
/* Precedencia */
RegisterOperators(1, smas, smenos);
RegisterOperators(2, spor, sdiv, mod);
RegisterOperators(3, Associativity.Left, neg);
((1 +( 2 * 3)) - (4 % (~5)))
Como es de notar se puede establecer que un signo tenga asociatividad por la izquierda o por la derecha, de la siguiente forma:
RegisterOperators(3, Associativity.Left, neg);
RegisterOperators(3, Associativity.Right, neg);
Y de esta forma establecemos prioridades y precedencia en Irony .net...
No hay comentarios:
Publicar un comentario