Visualizando a AST de um programa C com o Psyche-C

Psyche C

O Psyche-C é um frontend de compilador para a linguagem C. Uma diferença fundamental entre ele e o Clang é que no Psyche-C existe uma separação clara e modular entre as fases de análise sintática e análise semântica. Além disso, o Psyche-C conta com um notável mecanismo de inferência de tipos, sobre o qual já escrevi aqui no Embarcados.

Atualmente o projeto passa por uma grande reformulação; como parte dela, seu parser foi reescrito praticamente do zero (inclusive, na semana passada eu publiquei um programa de Bug Bounty, no valor de R$ 100,00, para quem encontrar erros nesse componente — até o momento, há 5 recompensas ainda disponíveis), de maneira a produzir uma AST que se assemelha àquela do Clang. A API geral do Psyche-C também foi reformulada, tendo como inspiração a API do Roslyn, o compilador de .NET.

Neste artigo, mostro como visualizar a AST do Psyche-C — irei também compará-la brevemente com a AST do Clang. Considere o programa test.c abaixo.

Para produzir e visualizar a AST de um programa com o Psyche-C, o driver cnippet deve ser invocado com a opção --C-dump-AST.

astpsyche
AST produzida pelo Psyche-C.

Já a AST produzida pelo Clang para o mesmo programa test.c é a seguinte.

astclang
AST produzida pelo Clang.

Além das cores e da decoração extra, quais são as principais diferenças entre elas?

  • A AST do Psyche-C é mais próxima da gramática de C. Por exemplo, na AST do Clang os declarators não aparecem, pois eles são absorvidos pela declaration que os contém. Se essa característica é boa ou ruim, dependerá de aplicação em questão. Para fins de análise estática, considero esse refinamento sintático da AST do Psyche-C como uma vantagem.

Isso não quer dizer que todo nodo da AST deve corresponder a um terminal da gramática. Senão, acabaríamos com uma árvore de sintaxe bastante concreta, ao invés uma árvore de sintaxe abstrata. Uma AST inteligível deve conter a “medida certa” de semântica da linguagem. (Por exemplo, a AST do antigo parser do Psyche-C era muito orientada/focada no aspecto gramatical.)

Indo um pouco além, considere este snippet de test.c:

No AST do Clang, ele é representado por um VarDecl e um FunctionDecl; ambos os nodos herdam de DeclaratorDecl (ou seja, uma declaration que vem de um declarator). Porém, sendo razoavelmente pedante, essa representação não é totalmente correta, dado que há uma única declaration — tal que se inicia com int termina com ; — neste trecho do programa.

No Psyche-C, eu optei por uma representação mais rigorosa na AST:

  • Um nodo VariableAndOrFunctionDeclaration é criado (assim como no Clang, este nodo herda de DeclaratorDeclaration), mas ele tem dois nodos filhos: um IdentifierDeclarator, designando objeto de tipo int, e um FunctionDeclarator, designando uma função cujo tipo de retorno é int. Outra vantagem dessa é que ela torna o AST do Psyche-C precisa/acurada para fins de reescrita (i.e., unparsing).

Em geral, o “espírito” de design do AST do Psyche-C é mais alinhado com o Roslyn. Embora, como Psyche-C é um frontend para C, seus nodos serão, obviamente, semelhantes àqueles da AST do Clang.

Para encerrar, deixo uma versão C# de test.c (bem, na verdade test.cs), junto com sua AST para que possam realizar uma comparação mais superficial.

astroslyn
Screenshot from SharpLab.

Saiba mais

Programando em C com inferência de tipos usando PsycheC

Objetos em Linguagem C

Orientação a objeto em C: Encapsulamento com estruturas opacas

Ponteiro em C: Polimorfismo

Website | Veja + conteúdo
Sem licença Creative Commons

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Comentários:
Notificações
Notificar
guest
0 Comentários
Inline Feedbacks
View all comments
Talvez você goste:

Séries

Menu

WEBINAR

Inteligência Artificial na Borda

DATA: 29/06 às 15:00h