Como funciona o tradutor do Pyrtugues por dentro
Tempo de leitura: ~6 minutos
No meu primeiro post eu apresentei o Pyrtugues: uma linguagem de programação em português que traduz código para Python real. Muita gente perguntou como isso funciona por dentro.
Esse post responde. Vou mostrar os desafios técnicos de traduzir código entre linguagens e como resolvi cada um.
Se você nunca escreveu um tradutor, esse post é pra você. Se já escreveu, talvez encontre algo interessante.
O problema básico
Traduzir mostrar("Olá") para print("Olá") parece simples. E é — se você só tem uma linha.
O problema começa quando o código tem strings, comentários e f-strings. Veja esse exemplo:
nome = "Maria e João"
mostrar(f"Olá, {nome}!")
# Isso é um comentário com se, senão, mostrar
Se você fizer uma tradução ingênua (substituir toda palavra-chave), o resultado vira uma bagunça:
nome = "Maria and João" # ❌ ERRADO - "e" virou "and"
print(f"Olá, {nome}!") # ✅ Ok
# Isso é um comentário com if, else, print # ❌ ERRADO
Três problemas apareceram:
- O "e" dentro da string virou "and"
- O comentário foi traduzido
- O Python não entende isso
A solução: proteger strings antes de traduzir
A primeira coisa que o tradutor faz é esconder todas as strings e comentários antes de mexer no código. Uso um scanner que percorre caractere por caractere:
def proteger_strings_e_comentarios(codigo):
blocos = []
resultado = []
i = 0
while i < len(codigo):
# Comentário: protege tudo depois de #
if codigo[i] == "#":
inicio = i
while i < len(codigo) and codigo[i] != "\n":
i += 1
resultado.append(guardar(codigo[inicio:i]))
continue
# String: protege tudo entre aspas
if codigo[i] in '"\'':
# ... lógica de detecção ...
resultado.append(guardar(codigo[inicio:i]))
continue
resultado.append(codigo[i])
i += 1
return "".join(resultado), blocos
Cada string/comentário vira um placeholder único tipo __PYRT_STR_0__. Depois o tradutor roda em paz, e no final os placeholders são restaurados.
Resultado: as strings ficam intocadas. ✅
O caso mais difícil: f-strings
F-strings são strings especiais que contêm expressões Python dentro de chaves:
mostrar(f"Olá, {nome}! Você tem {idade mais 1} anos.")
O tradutor precisa:
-
Não traduzir o texto normal da f-string (
"Olá, ...") -
Traduzir as expressões dentro das chaves (
{idade mais 1}→{idade + 1})
A solução é processar cada f-string separadamente, identificando onde começa e termina cada {...}:
def _traduzir_fstring(match):
texto = match.group(0)
# ... encontrar prefixo e aspas ...
corpo = texto[...]
partes = []
i = 0
while i < len(corpo):
if corpo[i] == '{':
# Encontrar o } correspondente
profundidade = 1
j = i + 1
while j < len(corpo) and profundidade:
if corpo[j] == '{': profundidade += 1
elif corpo[j] == '}': profundidade -= 1
j += 1
# Traduzir a expressão interna
expr = corpo[i+1:j-1]
partes.append('{' + traduzir_expressao(expr) + '}')
i = j
else:
partes.append(corpo[i])
i += 1
return prefixo + quote + ''.join(partes) + quote
Isso funciona mesmo com f-strings aninhadas ou expressões complexas como {minha_lista[0] mais 10}.
O truque das palavras contextuais
Palavras como se, em, e, ou são ambíguas. Podem ser:
- Palavra-chave (
se idade > 10:) - Nome de variável (
se = 10) - Parte de outra palavra (
sete,sempre,tema)
Uso regex com contexto específico pra cada caso:
se só traduz no início de linha
# Só vira "if" se for início de uma condição
resultado = re.sub(
r'^(\s*)se(?=\s+.+:)', # início + indentação + se + expressão + :
r'\1if',
resultado,
flags=re.MULTILINE
)
Isso garante que se idade > 10: vira if idade > 10:, mas se = 10 continua sendo variável.
em só traduz em loops
# Só vira "in" em "for x em y"
resultado = re.sub(
r'\bfor\s+(\w+)\s+em\b',
r'for \1 in',
resultado
)
e / ou só entre expressões
# Só vira "and" / "or" entre duas expressões
resultado = re.sub(
r'([a-zA-Z0-9_\)\]]+)\s+e\s+([a-zA-Z0-9_\(\[\{])',
r'\1 and \2',
resultado
)
Isso evita que "bom dia e boa tarde" vire "bom dia and boa tarde".
Métodos: só depois do ponto
Em Python, métodos são chamados depois de um ponto:
texto.upper()
lista.append("item")
Em Pyrtugues, usamos palavras em português nos mesmos lugares:
texto.maiúsculas()
lista.adicionar("item")
A tradução usa lookbehind pra garantir que só traduz depois do ponto:
# (?<=\.) significa "precedido por ."
resultado = re.sub(
rf'(?<=\.)\s*{palavra}(?=\s*\()',
traducao,
resultado
)
Isso evita que uma variável chamada maiúsculas seja traduzida por engano.
O resultado final
O tradutor completo faz isso em sequência:
1. Proteger strings e comentários → __PYRT_STR_0__, __PYRT_STR_1__...
2. Traduzir expressões dentro de f-strings
3. Traduzir palavras-chave com contexto (se, em, e, ou)
4. Traduzir métodos (só depois do ponto)
5. Traduzir operadores (mais, menos, vezes)
6. Restaurar strings e comentários
7. Retornar código Python
Linha 1 do Pyrtugues:
se idade maior que 10:
mostrar("Olá!")
Linha 1 do Python gerado:
if idade > 10:
print("Olá!")
E funciona com código complexo:
função calcular_media(notas):
soma = 0
para nota em notas:
soma = soma mais nota
retornar soma dividido por tamanho(notas)
nomes = ["Ana e Maria", "João e Pedro"]
para nome em nomes:
mostrar(f"Processando: {nome}")
Vira:
def calcular_media(notas):
soma = 0
for nota in notas:
soma = soma + nota
return soma / len(notas)
nomes = ["Ana e Maria", "João e Pedro"]
for nome in nomes:
print(f"Processando: {nome}")
Os "e" dentro das strings ficam preservados. ✅
O que aprendi nesse projeto
Fazer um tradutor parece simples até você tentar. Aprendi três lições:
- Contexto é tudo. Substituir palavra por palavra não funciona. Precisa entender onde cada uma está.
- Strings são sagradas. Proteja antes de qualquer coisa.
- Teste com código real. Bug só aparece quando você tenta casos extremos.
O código completo tá no GitHub. Se você quiser contribuir com melhorias no tradutor, abre uma issue ou manda PR.
Vem testar
O Pyrtugues tá disponível em:
- 🌐 Site oficial: pyrtugues.pages.dev
- 💻 Editor Web: pyrtugues-editor.pages.dev
- 🐙 GitHub: github.com/pyrtugues
Ficou alguma dúvida sobre o tradutor? Quer saber mais sobre alguma parte específica? Comenta aqui embaixo que eu respondo!
📚 Posts anteriores
Pyrtugues — Programação em português. Lógica de Python. Uma ponte para aprender.
Criado por Vinicius Caracciolo (12 anos)
Top comments (0)