¿Cuál es la regla de Yacc / Bison para la aritmética de BNF?

Puede encontrar reglas estándar para la aritmética en la sintaxis de muchos lenguajes de programación. Por ejemplo, el manual de bison Bison 3.0.4 tiene la siguiente definición de regla

exp: NUM {$$ = $ 1; }
El | exp ‘+’ exp {$$ = $ 1 + $ 3; }
El | exp ‘-‘ exp {$$ = $ 1 – $ 3; }
El | exp ‘*’ exp {$$ = $ 1 * $ 3; }
El | exp ‘/’ exp {$$ = $ 1 / $ 3; }
El | ‘-‘ exp% prec NEG {$$ = – $ 2; }
El | exp ‘^’ exp {$$ = pow ($ 1, $ 3); }
El | ‘(‘ exp ‘)’ {$$ = $ 2; }
;

que incluyen las reglas estándar más la acción de análisis. Las expresiones matemáticas son un poco complicadas en su interpretación, ya que debe considerar el concepto de precedencia y la asociatividad del operador. Con prioridad, la multiplicación y la división deben evaluarse antes de la suma y la resta, por lo que 2 + 3 * 4 se evalúa como 2+ (3 * 4) no (2 + 3) * 4. Con asociatividad especifica si 2-3-4 se evalúa como (2-3) -4, asociativo a la izquierda, o 2- (3-4), asociativo a la derecha. +, -, *, / son todos asociativos a la izquierda pero la exponenciación es asociativa a la derecha y en C asignación = es asociativa a la derecha, por lo que a = b = c se interpreta como a = (b = c).

Bison agrega algunos bits de sintaxis especiales que no son BNF para permitir esto

% token NUM
Queda% ‘-‘ ‘+’
%izquierda ‘*’ ‘/’
% de precedencia NEG / * negación – unario menos * /
% correcto ‘^’ / * exponenciación * /

Para agregar variables y funciones necesita un par de bits adicionales.

% define api.value.type union / * Genera YYSTYPE a partir de estos tipos: * /
% token NUM / * Número simple de doble precisión. * /
% token VAR FNCT / * Puntero de la tabla de símbolos: variable y función. * /
% type exp

y las reglas gramaticales.

Exp:
NUM {$$ = $ 1; }
El | VAR {$$ = $ 1-> value.var; }
El | VAR ‘=’ exp {$$ = $ 3; $ 1-> value.var = $ 3; }
El | FNCT ‘(‘ exp ‘)’ {$$ = (* ($ 1-> value.fnctptr)) ($ 3); }
El | exp ‘+’ exp {$$ = $ 1 + $ 3; }


Muchos autores dividen la regla individual en varios pasos; consulte, por ejemplo, yacc java Grammar, cuyo segmento modificado es

Expresión multiplicativa
: UnaryExpression
El | MultiplicativeExpression ‘*’ UnaryExpression
El | MultiplicativeExpression ‘/’ UnaryExpression
El | MultiplicativeExpression ‘%’ UnaryExpression
;
Expresión aditiva
: Expresión Multiplicativa
El | AdditiveExpression ‘+’ MultiplicativeExpression
El | AdditiveExpression ‘-‘ Expresión multiplicativa
;

Si realmente quiere profundizar en esto, puede ver la especificación real de las expresiones en Java Capítulo 15. Expresiones.

Una página bastante bonita es http://math.purduecal.edu/~rlkra… que tiene diez gramáticas diferentes para analizar la aritmética.

Analizar la aritmética es un trabajo bastante complicado, debe preocuparse por los diferentes operadores asociativos izquierdo y derecho, y la prioridad. En mi código ya no confío en el uso de generadores de analizadores que funcionan desde la sintaxis BNF o EBNF. En cambio, escribo mi propio analizador de precedencia de operadores construido sobre el algoritmo Shunting-yard. He encontrado que esto es más fácil de controlar y extender.