O que acontece quando você precisa avaliar uma expressão e não quer errar
Eu trabalhei com parsing de expressões em sistemas críticos e vou explicar de forma direta como isso funciona na prática. Você provavelmente já se deparou com uma expressão do tipo 3 + 5 * 2 e ficou na dúvida se o resultado é 16 ou 13. A resposta correta é 13, mas entender o porquê exige saber sobre precedência de operadores e associatividade. A precedência define a ordem em que os operadores são avaliados. Multiplicação e divisão vêm antes de adição e subtração. Isso é regra padrão na maioria das linguagens e calculadoras. Quando dois operadores têm a mesma precedência, entra a associatividade. A maioria dos operadores aritméticos é associativa à esquerda, o que significa que a expressão é avaliada da esquerda para a direita.
qual o resultado da expressão
Para responder essa pergunta corretamente, o processo básico envolve três etapas: identificar os operadores e seus níveis de precedência, aplicar a associatividade quando houver empate, e executar as operações na ordem determinada. Vou dar um exemplo mais complexo. Considere a expressão 10 - 3 + 2 * 4 / 2. Primeiro, identificamos que multiplicação e divisão têm precedência maior que subtração e adição. Dentro do grupo de maior precedência, temos 2 * 4 / 2, que avaliada da esquerda para a direita resulta em 8 / 2 = 4. Depois, fazemos 10 - 3 + 4, que também é avaliada da esquerda para a direita: 10 - 3 = 7, depois 7 + 4 = 11. O resultado final é 11. Na prática, eu construí um analisador sintático recursivo (recursive descent parser) para um sistema de cálculo financeiro que precisava avaliar expressões complexas com funções customizadas. O problema é que diferentes engines de cálculo tratam operadores de forma distinta. Eu tive um bug difícil de rastrear onde uma planilha gerava resultados diferentes de um script Python para a mesma expressão. A diferença estava em como cada um lidava com operador unário negativo em potências. A expressão -3 ^ 2 retorna -9 no Python (porque -3 é tratado como unary minos aplicado após a exponenciação), mas a maioria das calculadoras e do Excel devolve 9 (tratando -3 como um número negativo elevado ao quadrado). Isso causa problemas sérios quando você migra modelos financeiros entre plataformas.
Um ponto que poucos mencionam: a associatividade à direita existe e é importante. Operadores como exponenciação, atribuição e alguns operadores ternários são associativos à direita. Isso significa que a ^ b ^ c é avaliado como a ^ (b ^ c), e não (a ^ b) ^ c. Em notação reversa polonesa (RPN), usado em calculadoras Hewlett-Packard e na linguagem Forth, a ordem dos operadores elimina completamente a ambiguidade de precedência. A expressão 3 5 2 * + em RPN equivale exatamente a 3 + (5 * 2). Não há como confundir. Se você está desenvolvendo software que precisa avaliar expressões dinamicamente, evite usar eval() do JavaScript ou equivalentes em outras linguuras sem sanitização prévia. Isso abre brechas de segurança sérias. Em vez disso, use bibliotecas dedicadas como math.js, expr-eval ou ANTLR. A math.js, por exemplo, permite definir precedência customizada e tipos de dados como frações e números complexos sem perda de precisão.
👉 Clique no botão abaixo para saber mais sobre o assunto!
Uma armadilha comum: operadores de comparação em expressões encadeadas. A expressão 0 < x 10 funciona como esperado em Python, retornando verdadeiro quando x está entre 0 e 10. Em JavaScript, C++ e Java, essa mesma expressão é avaliada como (0 < x) 10, onde o resultado da primeira comparação (true ou false) é convertido para 1 ou 0, e então comparado com 10. Isso sempre retorna true para valores de x maiores que 0, porque tanto 1 quanto 0 são menores que 10. Se você escrever código multiplataforma, essa diferença vai te pegar. Outro detalhe prático que custa horas de debugging: operadores bitwise versus lógicos. Em muitas linguagens, & é bitwise e && é lógico. Mas em Python não existe operador bitwise lógico. Se você colocar um único & em uma condição if, ele opera bit a bit em vez de fazer avaliação curta (short-circuit evaluation). Isso pode causar erros de segmentation fault ao acessar elementos de arrays dentro de condições que nunca deveriam ser avaliadas.
Quando as expressões não funcionam como você espera
Tipos de dados misturados mudam o comportamento da avaliação. Em C e C++, 5 / 2 retorna 2 (divisão inteira), mas 5.0 / 2 retorna 2.5. No Python 3, 5 / 2 já retorna 2.5 automaticamente, e 5 // 2 é usado para divisão inteira. A inconsistência entre linguagens aqui é proposital, mas gera bugs silenciosos quando você assume que o comportamento é universal. Arredondamento de ponto flutuante é outro campo minado. Expressões como 0.1 + 0.2 == 0.3 retornam false em praticamente todas as linguagens devido à representação binária imprecisa de frações decimais. Se seu sistema precisa de comparação exata, use casas decimais fixas ou bibliotecas como decimal em Python ou BigDecimal em Java.
O trade-off é que expressões literais em código são fáceis de ler mas difíceis de manter quando os requisitos mudam. Planilhas eletrônicas e query languages oferecem flexibilidade, mas perdem tipagem estática e detecção de erros em tempo de compilação. A escolha depende do contexto. Para cálculos acadêmicos ou protótipos rápidos, expressões texto bastam. Para sistemas de produção com alto volume, considere gerar árvores de expressão (expression trees) e compilá-las. Se você precisa apenas testar rapidamente o resultado de uma expressão, ferramentas online como WolframAlpha ou o terminal do Python com o shell interativo resolvem em segundos. Para incorporar avaliação de expressões em um projeto, a biblioteca exprtk (C++) ou antlr4 com templates de árvore são escolhas sólidas e amplamente usadas na indústria.