En la teoría del lenguaje de programación , la asociatividad de un operador es una propiedad que determina cómo se agrupan los operadores de la misma precedencia en ausencia de paréntesis . Si un operando está precedido y seguido por operadores (por ejemplo, ^ 3 ^
), y esos operadores tienen la misma precedencia, entonces el operando puede usarse como entrada para dos operaciones diferentes (es decir, las dos operaciones indicadas por los dos operadores). La elección de a qué operaciones aplicar el operando está determinada por la asociatividad de los operadores. Los operadores pueden ser asociativos (lo que significa que las operaciones se pueden agrupar arbitrariamente), asociativos por la izquierda (lo que significa que las operaciones se agrupan desde la izquierda), asociativos por la derecha (lo que significa que las operaciones se agrupan desde la derecha) o no asociativos (lo que significa que las operaciones no se pueden agrupar desde la derecha). encadenados, a menudo porque el tipo de salida es incompatible con los tipos de entrada). La asociatividad y precedencia de un operador es parte de la definición del lenguaje de programación; Diferentes lenguajes de programación pueden tener diferente asociatividad y precedencia para el mismo tipo de operador.
Considere la expresión a ~ b ~ c
. Si el operador ~
ha abandonado la asociatividad, esta expresión se interpretaría como (a ~ b) ~ c
. Si el operador tiene asociatividad correcta, la expresión se interpretaría como a ~ (b ~ c)
. Si el operador no es asociativo, la expresión podría ser un error de sintaxis o podría tener algún significado especial. Algunos operadores matemáticos tienen asociatividad inherente. Por ejemplo, la resta y la división, tal como se usan en la notación matemática convencional, son inherentemente asociativas por la izquierda. La suma y la multiplicación, por el contrario, son asociativas tanto de izquierda como de derecha. (p.ej (a * b) * c = a * (b * c)
).
Muchos manuales de lenguajes de programación proporcionan una tabla de precedencia y asociatividad de operadores; consulte, por ejemplo, la tabla para C y C++ .
El concepto de asociatividad notacional descrito aquí está relacionado con la asociatividad matemática, pero es diferente de ella . Una operación que es matemáticamente asociativa, por definición, no requiere asociatividad notacional. (Por ejemplo, la suma tiene la propiedad asociativa, por lo tanto no tiene que ser asociativa por la izquierda ni por la derecha). Sin embargo, una operación que no es matemáticamente asociativa debe ser notacionalmente por la izquierda, por la derecha o no asociativa. (Por ejemplo, la resta no tiene la propiedad asociativa, por lo tanto debe tener asociatividad notacional).
La asociatividad sólo es necesaria cuando los operadores de una expresión tienen la misma precedencia. Generalmente +
y -
tienen la misma precedencia. Considere la expresión 7 - 4 + 2
. El resultado podría ser cualquiera (7 - 4) + 2 = 5
o 7 - (4 + 2) = 1
. El primer resultado corresponde al caso en que +
y -
son asociativos por izquierda, el segundo al caso en que +
y -
son asociativos por derecha.
Para reflejar el uso normal, los operadores de suma , resta , multiplicación y división suelen ser asociativos por la izquierda, [1] [2] [3] [4] [5] mientras que para un operador de exponenciación (si está presente) [6] y No existe un acuerdo general sobre los operadores de flecha hacia arriba de Knuth . Todos los operadores de asignación suelen ser asociativos por la derecha. Para evitar casos en los que los operandos se asocien con dos operadores, o con ningún operador, los operadores con la misma precedencia deben tener la misma asociatividad.
Considere la expresión 5^4^3^2
, en la que ^
se considera un operador de exponenciación asociativo derecho. Un analizador que lea los tokens de izquierda a derecha aplicaría la regla de asociatividad a una rama, debido a la asociatividad derecha de ^
, de la siguiente manera:
5
Se lee el término .^
Se lee no terminal . Nodo: " 5^
".4
Se lee el término . Nodo: " 5^4
".^
, lo que activa la regla de asociatividad por la derecha. La asociatividad decide el nodo: " 5^(4^
".3
Se lee el término . Nodo: " 5^(4^3
".^
, lo que desencadena la reaplicación de la regla de asociatividad por la derecha. Nodo " 5^(4^(3^
".2
Se lee el término . Nodo " 5^(4^(3^2
".5^(4^(3^2))
".Luego, esto se puede evaluar primero en profundidad, comenzando en el nodo superior (el primero ^
):
^
expresión.^
.^
.Una evaluación asociativa por la izquierda habría dado como resultado el árbol de análisis ((5^4)^3)^2
y el resultado completamente diferente (625 3 ) 2 = 244,140,625 2 ≈5,960 4645 × 10 16 .
En muchos lenguajes de programación imperativos , el operador de asignación se define como asociativo por la derecha y la asignación se define como una expresión (que se evalúa como un valor), no solo una declaración. Esto permite la asignación encadenada utilizando el valor de una expresión de asignación como operando derecho de la siguiente expresión de asignación.
En C , la asignación a = b
es una expresión que se evalúa con el mismo valor que la expresión b
convertida al tipo de a
, con el efecto secundario de almacenar el valor R de b
en el valor L de a
. [a] Por lo tanto la expresión a = (b = c)
puede interpretarse como b = c; a = b;
. La expresión alternativa (a = b) = c
genera un error porque a = b
no es una expresión de valor L, es decir, tiene un valor R pero no un valor L donde almacenar el valor R de c
. La asociatividad derecha del =
operador permite que expresiones como a = b = c
se interpreten como a = (b = c)
.
En C++ , la asignación a = b
es una expresión que se evalúa con el mismo valor que la expresión a
, con el efecto secundario de almacenar el valor R de b
en el valor L de a
. Por lo tanto, la expresión a = (b = c)
todavía puede interpretarse como b = c; a = b;
. Y la expresión alternativa (a = b) = c
se puede interpretar como a = b; a = c;
en lugar de generar un error. La asociatividad derecha del =
operador permite que expresiones como a = b = c
se interpreten como a = (b = c)
.
Los operadores no asociativos son operadores que no tienen un comportamiento definido cuando se usan en secuencia en una expresión. En Prolog, el operador infijo no:-
es asociativo porque construcciones como " " constituyen errores de sintaxis.a :- b :- c
Otra posibilidad es que las secuencias de ciertos operadores se interpreten de alguna otra manera, lo que no puede expresarse como asociatividad. Esto generalmente significa que sintácticamente existe una regla especial para las secuencias de estas operaciones y semánticamente el comportamiento es diferente. Un buen ejemplo es Python , que tiene varias construcciones de este tipo. [7] Dado que las asignaciones son declaraciones, no operaciones, el operador de asignación no tiene un valor y no es asociativo. En cambio, la asignación encadenada se implementa al tener una regla gramatical para secuencias de asignaciones a = b = c
, que luego se asignan de izquierda a derecha. Además, las combinaciones de asignación y asignación aumentada, como a = b += c
no son legales en Python, aunque sí lo son en C. Otro ejemplo son los operadores de comparación, como >
, ==
y <=
. Una comparación encadenada como a < b < c
se interpreta como (a < b) and (b < c)
no equivalente a ni (a < b) < c
a ni a a < (b < c)
. [8]
a = b
es una expresión pero a = b;
es una declaración.