En la teoría de lenguajes 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 es precedido y seguido por operadores (por ejemplo, ^ 3 ^
), y esos operadores tienen igual 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 encadenar, a menudo porque el tipo de salida es incompatible con los tipos de entrada). La asociatividad y la precedencia de un operador son parte de la definición del lenguaje de programación; diferentes lenguajes de programación pueden tener diferentes asociatividades y precedencias para el mismo tipo de operador.
Considere la expresión a ~ b ~ c
. Si el operador ~
tiene asociatividad por la izquierda, esta expresión se interpretaría como (a ~ b) ~ c
. Si el operador tiene asociatividad por la derecha, 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 por la izquierda como por la 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 que se describe 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 o por la derecha). Sin embargo, una operación que no es matemáticamente asociativa debe ser asociativa por la izquierda, por la derecha o no asociativa por la notacional. (Por ejemplo, la resta no tiene la propiedad asociativa, por lo tanto, debe tener asociatividad notacional).
La asociatividad solo es necesaria cuando los operadores de una expresión tienen la misma precedencia. Por lo general +
, y -
tienen la misma precedencia. Considere la expresión 7 - 4 + 2
. El resultado podría ser (7 - 4) + 2 = 5
o 7 - (4 + 2) = 1
. El primer resultado corresponde al caso cuando +
y -
son asociativos por la izquierda, el segundo al caso cuando +
y -
son asociativos por la 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] mientras que para un operador de exponenciación (si está presente) [4] [ se necesita una mejor fuente ] no hay un acuerdo general. 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 en absoluto, los operadores con la misma precedencia deben tener la misma asociatividad.
Consideremos la expresión 5^4^3^2
, en la que ^
se toma como un operador de exponenciación asociativo por la derecha. Un analizador que lea los tokens de izquierda a derecha aplicaría la regla de asociatividad a una rama, debido a la asociatividad por la derecha de ^
, de la siguiente manera:
5
se lee.^
. Nodo: " 5^
".4
Se lee el término . Nodo: " 5^4
".^
, lo que activa la regla de asociatividad derecha. La asociatividad decide el nodo: " 5^(4^
".3
Se lee el término . Nodo: " 5^(4^3
".^
, lo que activa la reaplicación de la regla de asociatividad derecha. Nodo " 5^(4^(3^
".2
Se lee el término . Nodo " 5^(4^(3^2
".5^(4^(3^2))
".Esto se puede evaluar 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 imperativa , el operador de asignación se define como asociativo por la derecha y la asignación se define como una expresión (que evalúa como un valor), no solo como una declaración. Esto permite la asignación encadenada al utilizar el valor de una expresión de asignación como el operando derecho de la siguiente expresión de asignación.
En C , la asignación a = b
es una expresión que evalúa 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)
se puede interpretar 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 evalúa 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 se puede interpretar 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 utilizan en secuencia en una expresión. En Prolog, el operador infijo no :-
es asociativo porque construcciones como " a :- b :- c
" constituyen errores de sintaxis.
Otra posibilidad es que las secuencias de ciertos operadores se interpreten de alguna otra manera, que no se puede expresar como asociatividad. Esto generalmente significa que sintácticamente, hay una regla especial para las secuencias de estas operaciones, y semánticamente el comportamiento es diferente. Un buen ejemplo está en Python , que tiene varias construcciones de este tipo. [5] Dado que las asignaciones son declaraciones, no operaciones, el operador de asignación no tiene un valor y no es asociativo. La asignación encadenada se implementa en cambio 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 es equivalente a ni (a < b) < c
a a < (b < c)
. [6]
a = b
es una expresión pero a = b;
es una declaración.