Quando C++ não é apenas uma linguagem, mas um construtor de linguagens
\n\nImagine que você está escrevendo um sistema complexo de controle de um robô manipulador. Todos os dias você digita comandos repetitivos: "girar servo motor em 30 graus", "agarrar peça", "mover para o ponto X:100 Y:200". O código em C++ puro se transforma em uma interminável sequência de chamadas de funções e loops. E se você pudesse escrever um comando diretamente como em linguagem humana: move arm to (100, 200) at speed 50? E que isso fosse código C++ real e compilável?
Isso não é ficção científica. Isso é DSL (Domain-Specific Language), ou linguagem específica de domínio. Em C++, você pode criar sua própria minilinguagem que descreve perfeitamente as tarefas do seu domínio. Neste artigo, não vamos apenas falar sobre teoria — vamos escrever uma DSL real em C++ do zero, abordar duas abordagens (interna e externa) e mostrar como isso pode acelerar o desenvolvimento em 5 a 10 vezes.
\n\nBem-vindo ao mundo onde o programador se torna um linguista e o compilador, seu tradutor.
\n\nO que é DSL e por que você precisa dela?
\n\nLinguagem Específica de Domínio (DSL) é uma linguagem de programação criada para resolver problemas de uma área específica. Ao contrário de uma linguagem de propósito geral (C++, Python, Java), a DSL é altamente especializada. Exemplos que você certamente conhece: SQL (para bancos de dados), Regex (para busca de padrões), HTML (para marcação de páginas web).
\n\nMas por que criar sua própria DSL em C++? Três razões principais:
\n- \n
- Legibilidade do código. Seu código se torna semelhante a uma especificação técnica. Pode ser lido e modificado não apenas por programadores, mas também por engenheiros, matemáticos, designers. \n
- Velocidade de desenvolvimento. Em vez de 20 linhas de código padrão, uma linha em DSL. \n
- Segurança. A DSL não permite escrever um comando sintaticamente incorreto para o seu sistema. Erros são detectados em tempo de compilação. \n
C++ é ideal para criar DSLs graças ao seu poderoso sistema de templates (metaprogramação com templates), sobrecarga de operadores e macros. Você pode criar uma DSL que executa tão rápido quanto o código C++ comum, porque ela é incorporada diretamente ao compilador.
\n\nDois mundos: Internal DSL vs External DSL
\n\nAntes de escrever código, vamos escolher a abordagem. Existem dois tipos de DSL para C++:
\n\nInternal DSL (DSL embutido)
\nVocê não escreve um novo analisador sintático. Você usa a sintaxe do C++ — sobrecarga de operadores, encadeamento de chamadas, lambdas — para criar uma "linguagem dentro da linguagem". Esta é a abordagem mais popular em C++. Exemplo: a biblioteca Boost.Spirit ou Eigen para álgebra linear, onde você escreve v = (3.0 * m1 + m2) * m3; — parece uma DSL matemática, mas é C++ puro.
External DSL (DSL externo)
\nVocê inventa sua própria sintaxe do zero, escreve um analisador sintático (ou usa um gerador de analisadores como ANTLR, Flex/Bison) e depois o traduz para código C++. É mais complexo, mas oferece total liberdade. Por exemplo, você pode escrever um script em sua própria linguagem, e o programa em C++ o executará.
\n\nNeste artigo, faremos ambas as variantes. Começaremos com a mais simples — a DSL interna.
\n\nPrática 1: Criando uma Internal DSL para configuração de robô
\n\nSuponha que estamos escrevendo uma biblioteca para controle de um robô. Precisamos definir uma sequência de ações. O código normal seria assim:
\n\nRobot robot;\nrobot.connect("COM3");\nrobot.setSpeed(50);\nrobot.moveTo(100, 200);\nrobot.grip(true);\nrobot.moveTo(300, 400);\nrobot.grip(false);\n\n\nFunciona, mas é entediante. Vamos transformar isso em uma DSL, usando encadeamento de métodos e sobrecarga de operadores. Queremos escrever assim:
\n\nRobot robot;\nrobot << connect("COM3") << speed(50)\n << move(100, 200) << grip(on)\n << move(300, 400) << grip(off);\n\n\nComo implementar isso? Usamos o padrão "Builder" e a sobrecarga do operador <<
Blogs
Book Recommendations
Leia também