108 votes

Quelle est la différence entre un arbre syntaxique abstrait et un arbre syntaxique concret ?

J'ai lu quelques articles sur le fonctionnement des interpréteurs et des compilateurs, et la différence entre un AST et un CST est l'un des points sur lesquels je m'interroge. Si j'ai bien compris, l'analyseur syntaxique crée un CST, le transmet à l'analyseur sémantique qui le transforme en un AST. Cependant, je crois comprendre que l'analyseur sémantique s'assure simplement que les règles sont respectées. Je ne comprends pas vraiment pourquoi il apporterait des modifications pour le rendre abstrait plutôt que concret.

Y a-t-il quelque chose qui m'échappe dans l'analyseur sémantique, ou la différence entre une AST et une CST est-elle quelque peu artificielle ?

81voto

Michael Ekstrand Points 12849

Un arbre syntaxique concret représente le texte source exactement sous sa forme analysée. En général, il se conforme à la grammaire sans contexte définissant le langage source.

Cependant, la grammaire et l'arbre concrets comportent beaucoup de choses qui sont nécessaires pour rendre le texte source analysable sans ambiguïté, mais qui ne contribuent pas à la signification réelle. Par exemple, pour implémenter la précédence des opérateurs, votre GFC a généralement plusieurs niveaux de composants d'expression (terme, facteur, etc.), avec les opérateurs qui les relient aux différents niveaux (vous ajoutez des termes pour obtenir des expressions, les termes sont composés de facteurs éventuellement multipliés, etc.) Pour interpréter ou compiler le langage, cependant, vous n'avez pas besoin de cela ; vous avez juste besoin de nœuds d'expression qui ont des opérateurs et des opérandes. L'arbre syntaxique abstrait est le résultat de la simplification de l'arbre syntaxique concret jusqu'aux éléments réellement nécessaires pour représenter la signification du programme. Cet arbre a une définition beaucoup plus simple et est donc plus facile à traiter dans les étapes ultérieures de l'exécution.

En général, il n'est pas nécessaire de construire un arbre syntaxique concret. Les routines d'action de votre grammaire YACC (ou Antlr, ou Menhir, ou autre...) peuvent directement construire l'arbre syntaxique abstrait, de sorte que l'arbre syntaxique concret n'existe que comme une entité conceptuelle représentant la structure d'analyse de votre texte source.

4 votes

Supplément : l'interpréteur Python construit d'abord une CST et la convertit ensuite en AST.

0 votes

Est-il correct de dire que le changement principal (ou un changement principal) en passant de la CST -> AST est que les symboles sont remplacés par leurs référents ? (En gardant à l'esprit que la CST peut ne pas être construite en pratique).

2 votes

@EricAuld C'est un changement significatif ; l'AST est souvent beaucoup plus simple aussi (par exemple, les structures de regroupement comme les parenthèses sont abandonnées dans la traduction CST -> AST, parce que le regroupement est implicite dans la structure AST ; ce ne sont que des instructions sur la façon de construire un arbre correct à partir du texte source).

41voto

Ira Baxter Points 48153

A arbre syntaxique concret correspond à ce que les règles de grammaire disent être la syntaxe. Le but de la arbre syntaxique abstrait est d'avoir une représentation "simple" de ce qui est essentiel dans "l'arbre syntaxique".

La valeur réelle de l'AST, selon moi, est qu'elle est plus petit que le CST, et prend donc moins de temps à traiter. (Vous pourriez dire, qui s'en soucie ? Mais je travaille avec un outil où nous avons des dizaines de millions de nœuds en direct en même temps).

La plupart des générateurs d'analyseurs syntaxiques qui prennent en charge la construction d'arbres syntaxiques insistent pour que vous spécifiiez personnellement la manière dont ils sont construits, en partant du principe que les nœuds de votre arbre seront plus "simples" que la CST (et en cela, ils ont généralement raison, car les programmeurs sont plutôt paresseux). On peut soutenir que cela signifie que vous devez coder moins de fonctions de visiteur d'arbre, et cela est également valable, dans la mesure où cela minimise l'énergie d'ingénierie. Lorsque vous avez 3500 règles (par exemple, pour COBOL), cela compte. Et cette "simplicité" conduit à la bonne propriété de "petitesse".

Mais le fait d'avoir de tels AST crée un problème qui n'existait pas : il ne correspond pas à la grammaire, et maintenant vous devez suivre mentalement les deux. Et quand il y a 1500 nœuds AST pour une grammaire de 3500 règles, cela compte beaucoup. Et si la grammaire évolue (c'est toujours le cas !), vous avez maintenant deux ensembles géants de choses à garder en synchronisation.

Une autre solution est de laisser l'analyseur syntaxique construire simplement les noeuds CST pour vous et de n'utiliser que ceux-ci. C'est un avantage énorme lors de la construction des grammaires : il n'y a pas besoin d'inventer 1500 nœuds AST spéciaux pour modéliser 3500 règles de grammaire. Il suffit de penser que l'arbre est isomorphe à la grammaire. Du point de vue de l'ingénieur grammairien, c'est complètement inutile, ce qui lui permet de se concentrer sur l'obtention d'une grammaire correcte et de la modifier à sa guise. On peut dire que vous devez écrire plus de règles pour les visiteurs de nœuds, mais cela peut être géré. Nous y reviendrons plus tard.

Ce que nous faisons avec le Boîte à outils de réingénierie du logiciel DMS consiste à construire automatiquement un CST sur la base des résultats d'un processus d'analyse syntaxique (GLR). DMS construit ensuite automatiquement une CST "compressée" pour des raisons d'efficacité de l'espace, en éliminant les terminaux non porteurs de valeur (mots-clés, ponctuation), les productions unaires sémantiquement inutiles, et en formant des listes directement indexables pour les paires de règles de grammaire qui sont semblables à des listes :

    L = e ;
    L = L e ;
    L2 = e2 ;
    L2 = L2  ','  e2 ;

et une grande variété de variations de ces formes. Vous pensez en termes de règles de grammaire et de CST virtuelle ; l'outil fonctionne sur la représentation compressée. Facile pour votre cerveau, plus rapide/plus petit au moment de l'exécution.

De façon remarquable, la CST compressée construite de cette façon ressemble beaucoup à une AST que vous auriez pu concevoir à la main (voir le lien à la fin pour des exemples). En particulier, la CST compressée ne comporte aucun nœud qui ne soit qu'une syntaxe concrète. Il y a quelques petites maladresses : par exemple, alors que les nœuds concrets pour '(' et ')' que l'on trouve classiquement dans les sous-programmes d'expression ne sont pas dans l'arbre, un " nœud de parenthèses " est présent. fait apparaissent dans la CST compressée et doivent être traitées. Une véritable AST n'aurait pas cela. Cela semble être un prix assez faible à payer pour la commodité de ne pas avoir à spécifier la construction AST, jamais. Et la documentation de l'arbre est toujours disponible et correcte : la grammaire es la documentation.

Comment éviter les "visiteurs supplémentaires" ? Nous ne le faisons pas entièrement, mais DMS fournit une bibliothèque AST qui parcourt l'AST et gère les différences entre la CST et l'AST de manière transparente. DMS offre également un évaluateur de "grammaire d'attributs" (AGE), qui est une méthode pour passer les valeurs calculées d'un nœud vers le haut et vers le bas de l'arbre ; l'AGE gère tous les problèmes de représentation de l'arbre et l'ingénieur outil ne se soucie donc que d'écrire des calculs efficaces directement sur les règles de grammaire elles-mêmes. Enfin, DMS fournit également des modèles de "syntaxe de surface", qui permettent d'utiliser des fragments de code de la grammaire pour trouver des types spécifiques de sous-arbres, sans connaître la plupart des types de nœuds impliqués.

Une des autres réponses observe que si vous voulez construire des outils qui peuvent régénérer les sources, votre AST devra correspondre à la CST. Ce n'est pas vraiment exact, mais il est beaucoup plus facile de régénérer la source si vous avez des nœuds CST. DMS génère la plupart des prettyprinter automatiquement parce qu'il a accès aux deux :-}

En résumé : AST sont bons pour les petits, à la fois phyisque et conceptuel. La construction automatisée d'AST à partir de la CST fournit les deux, et vous permet d'éviter le problème du suivi de deux ensembles différents.

EDIT mars 2015 : Lien vers des exemples de CST vs. "AST" construits de cette manière

35voto

Guy Coder Points 3526

Ceci est basé sur le Évaluateur d'expression grammaire de Terrence Parr.

La grammaire pour cet exemple :

grammar Expr002;

options 
{
    output=AST;
    ASTLabelType=CommonTree; // type of $stat.tree ref etc...
}

prog    :   ( stat )+ ;

stat    :   expr NEWLINE        -> expr
        |   ID '=' expr NEWLINE -> ^('=' ID expr)
        |   NEWLINE             ->
        ;

expr    :   multExpr (( '+'^ | '-'^ ) multExpr)*
        ; 

multExpr
        :   atom ('*'^ atom)*
        ; 

atom    :   INT 
        |   ID
        |   '('! expr ')'!
        ;

ID      : ('a'..'z' | 'A'..'Z' )+ ;
INT     : '0'..'9'+ ;
NEWLINE : '\r'? '\n' ;
WS      : ( ' ' | '\t' )+ { skip(); } ;

Entrée

x=1
y=2
3*(x+y)

Arbre d'analyse

L'arbre d'analyse est une représentation concrète de l'entrée. L'arbre d'analyse retient toutes les informations de l'entrée. Les cases vides représentent les espaces blancs, c'est-à-dire les fins de ligne.

Parse Tree

AST

L'AST est une représentation abstraite de l'entrée. Notez que les parens ne sont pas présents dans l'AST car les associations sont dérivables de la structure de l'arbre.

AST

EDIT

Pour une explication plus approfondie, voir Compilateurs et générateurs de compilateurs pg. 23

21voto

Jonathan Feinberg Points 24791

Cet article de blog peut être utile.

Il me semble que l'AST "jette" beaucoup d'informations grammaticales/structurelles intermédiaires qui ne contribueraient pas à la sémantique. Par exemple, vous ne vous souciez pas de savoir si 3 est un atome, un terme, un facteur ou un ..... Vous vous souciez seulement du fait que c'est 3 lorsque vous implémentez l'expression d'exponentiation ou autre.

11voto

Pascal Cuoq Points 39606

En arbre syntaxique concret suit les règles de la grammaire de la langue. Dans la grammaire, les "listes d'expressions" sont généralement définies par deux règles

  • expression_list peut être : expression
  • expression_list peut être : expression, expression_list

Suivies à la lettre, ces deux règles donnent une forme de peigne à toute liste d'expressions qui apparaît dans le programme.

En arbre syntaxique abstrait est sous la forme qui convient pour une manipulation ultérieure. Elle représente les choses d'une manière qui a du sens pour quelqu'un qui comprend la signification des programmes, et pas seulement la manière dont ils sont écrits. La liste d'expressions ci-dessus, qui peut être la liste des arguments d'une fonction, peut être représentée de manière pratique comme un vecteur d'expressions, car il est préférable pour l'analyse statique d'avoir le nombre total d'expressions explicitement disponible et de pouvoir accéder à chaque expression par son index.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X