web-dev-qa-db-fra.com

Quelle est la différence entre un arbre de syntaxe abstraite et un arbre de syntaxe concrète?

J'ai lu un peu sur le fonctionnement des interprètes/compilateurs, et l'un des domaines dans lequel je suis confus est la différence entre un AST et un CST. D'après ce que je comprends, l'analyseur crée un CST et le remet à l'analyseur sémantique qui le transforme en AST. Cependant, ma compréhension est que l'analyseur sémantique s'assure simplement que les règles sont suivies. Je ne comprends pas vraiment pourquoi cela apporterait des changements pour le rendre abstrait plutôt que concret.

Y a-t-il quelque chose qui me manque dans l'analyseur sémantique ou la différence entre un AST et le CST est-elle quelque peu artificielle?

67
Jason Baker

Une arborescence de syntaxe concrète représente le texte source exactement sous forme analysée. En général, il est conforme à la grammaire sans contexte définissant la langue source.

Cependant, la grammaire concrète et l’arbre comportent beaucoup de choses nécessaires pour rendre le texte source analysable sans ambiguïté, mais ne contribuent pas à la signification réelle. Par exemple, pour implémenter la priorité des opérateurs, votre CFG comporte généralement plusieurs niveaux de composants d’expression (terme, facteur, etc.), les opérateurs les connectant à différents niveaux (vous ajoutez des termes pour obtenir des expressions, les termes étant composés de facteurs éventuellement multipliés , etc.). Cependant, pour interpréter ou compiler le langage, vous n'en avez pas besoin. vous avez juste besoin de nœuds d'expression qui ont des opérateurs et des opérandes. L’arbre de syntaxe abstraite est le résultat de la simplification de l’arbre de syntaxe concret jusqu’à ce qu’il faut réellement pour représenter le sens du programme. Cette arborescence a une définition beaucoup plus simple et est donc plus facile à traiter dans les étapes ultérieures de l’exécution.

Généralement, vous n'avez pas besoin de créer un arbre de syntaxe concret. Les routines d'action de votre grammaire YACC (ou Antlr, ou Menhir, ou autre) peuvent directement construire l'arbre de syntaxe abstraite. L'arbre de syntaxe concrète n'existe donc qu'en tant qu'entité conceptuelle représentant la structure d'analyse de votre texte source.

50
Michael Ekstrand

Un arbre de syntaxe concret correspond à ce que les règles de grammaire disent est la syntaxe. Le but de l’arbre de syntaxe abstract est d’avoir une représentation "simple" de ce qui est essentiel dans "l’arbre de syntaxe".

Une valeur réelle dans le AST IMHO est qu'il 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 vivent à la fois!).

La plupart des générateurs d’analyseurs prenant en charge la création d’arbres de syntaxe insistent pour que vous précisiez personnellement comment ils sont construits, en supposant que vos noeuds d’arbres seront "plus simples" que le CST (et qu’ils ont généralement raison, car les programmeurs sont jolis paresseux). On peut dire que cela signifie que vous devez coder moins de fonctions de visiteur dans les arbres, ce qui est également précieux, car cela minimise l'énergie utilisée par l'ingénierie. Lorsque vous avez 3500 règles (par exemple, pour COBOL), cela est important. Et cette "simplicité" conduit à la bonne propriété de "petitesse".

Mais avoir de tels AST crée un problème qui n'existait pas: cela ne correspond pas à la grammaire, et maintenant vous devez suivre mentalement les deux. Et quand il y a 1500 AST nœuds pour une grammaire de règles 3 500, cela compte beaucoup. Et si la grammaire évolue (ils le font toujours!), Vous avez maintenant deux ensembles de choses gigantesques à synchroniser.

Une autre solution consiste à laisser l’analyseur construire simplement des nœuds CST pour vous et à les utiliser. Ceci est un énorme avantage lors de la construction des grammaires: il n’est pas nécessaire d’inventer 1 500 nœuds spéciaux AST pour modéliser 3 500 règles de grammaire. Il suffit de penser à l’arbre qui est isomorphe à la grammaire. Du point de vue de l'ingénieur en grammaire, cela est totalement sans cerveau, ce qui lui permet de se concentrer sur la correction de la grammaire et de la modifier à sa guise. On peut soutenir que vous devez écrire plus de règles de visiteur de noeud, mais cela peut être géré. Plus sur cela plus tard.

Ce que nous faisons avec DMS Software Reengineering Toolkit consiste à créer automatiquement un fichier CST basé sur les résultats d’un processus d’analyse (GLR). DMS construit ensuite automatiquement un CST "compressé" pour des raisons d'efficacité d'espace en éliminant les terminaux non porteurs de valeur (mots-clés, ponctuation), les productions unaires sémantiquement inutiles et en formant des listes pour les paires de règles de grammaire telles que:

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

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

Remarquablement, le CST compressé construit de cette façon ressemble beaucoup à un AST que vous auriez peut-être conçu à la main (voir le lien à la fin des exemples). En particulier, le fichier CST compressé ne contient pas de nœuds qui ne soient que de la syntaxe concrète . Il existe des petits défauts d'inconvénients: par exemple, les nœuds concrets de '(' et ')' classiquement trouvés dans les sous-grammes d'expression ne sont pas l’arbre, un "noeud de parenthèses" fait apparaît dans le fichier CST compressé et doit être traité. Un vrai AST n'aurait pas cela. Cela semble être un assez petit prix à 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 est la documentation.

Comment pouvons-nous éviter les "visiteurs supplémentaires"? Nous ne le faisons pas entièrement, mais DMS fournit une bibliothèque AST qui parcourt le AST et gère les différences entre le CST et le AST de manière transparente. DMS propose également un évaluateur "AGE" ("Grammaire d'attribut"), méthode permettant de transmettre des valeurs calculées sous forme de nœuds en haut et en bas de l'arbre. AGE gère tous les problèmes de représentation de l'arborescence et l'ingénieur en outils ne se préoccupe que d'écrire des calculs de manière efficace directement sur les règles de grammaire elles-mêmes. Enfin, DMS fournit également des modèles de "syntaxe de surface", qui permettent aux fragments de code de la grammaire de rechercher des types spécifiques de sous-arbres, sans connaître la plupart des types de nœuds impliqués.

Une des autres réponses indique que si vous souhaitez créer des outils pouvant régénérer le code source, votre AST devra correspondre au CST. Ce n'est pas vraiment vrai, 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 de la jolie imprimante automatiquement car il a accès aux deux: -}

En bout de ligne: les AST sont utiles pour les petites entreprises, à la fois physiques et conceptuelles. La construction AST automatisée à partir du CST fournit les deux et vous évite le problème du suivi de deux ensembles différents.

EDIT Mars 2015: Lien vers des exemples de CST contre "AST" construit de cette façon

28
Ira Baxter

Cet article de blog peut être utile.

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

18
Jonathan Feinberg

Ceci est basé sur le Expression Evaluator grammaire de Terrence Parr.

La grammaire de 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(); } ;

Contribution

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 conserve toutes les informations de l'entrée. Les cases vides représentent les espaces, c’est-à-dire la fin de la ligne.

Parse Tree

AST

Le AST est une représentation abstraite de l'entrée. Notez que les parens ne sont pas présents dans AST car les associations peuvent être dérivées de la structure arborescente. 

AST

MODIFIER

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

14
Guy Coder

L'arbre de syntaxe concrete suit les règles de la grammaire du langage. Dans la grammaire, les "listes d'expressions" sont généralement définies avec deux règles 

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

Suivi à la lettre, ces deux règles donnent une forme de peigne à toute liste d’expressions apparaissant dans le programme.

L'arbre de syntaxe abstract se présente sous la forme qui convient à une manipulation ultérieure. Il représente les choses d'une manière qui a du sens pour quelqu'un qui comprend le sens des programmes, et pas seulement la façon dont elles sont écrites. 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 que l’analyse statique ait le nombre total d’expressions explicitement disponible et puisse accéder à chaque expression par son indice.

9
Pascal Cuoq

C'est une différence qui ne fait pas de différence.

Un AST est généralement expliqué comme un moyen d'approcher la sémantique d'une expression de langage de programmation en jetant le contenu lexical. Par exemple, dans une grammaire sans contexte, vous pourriez écrire la règle EBNF suivante

term: atom (('*' | '/') term )*

alors que dans le cas AST vous n'utilisez que mul_rule et div_rule qui exprime les opérations arithmétiques appropriées. 

Ces règles ne peuvent-elles pas être introduites dans la grammaire en premier lieu? Bien sûr. Vous pouvez réécrire la règle compacte et abstract ci-dessus en la décomposant en une règle plus concrète utilisée pour imiter les nœuds AST mentionnés:

term: mul_rule | div_rule
mul_rule: atom ('*' term)*
div_rule: atom ('/' term)*

Maintenant, quand vous pensez en termes d’analyse descendante, la seconde term introduit un PREMIER/PREMIER conflit entre mul_rule et div_rule Quelque chose qu'un analyseur LL (1) ne peut pas traiter. La première forme de règle était la version factorisée de gauche de la seconde qui éliminait effectivement la structure. Vous devez payer un prix pour utiliser LL (1) ici.

Les AST sont donc un complément ad hoc utilisé pour remédier aux carences des grammaires et des analyseurs syntaxiques. La transformation CST -> AST est une opération de refactoring. Personne ne s'est jamais inquiété lorsqu'une virgule ou deux points supplémentaires sont stockés dans l'arbre de syntaxe. Certains auteurs les adaptent au contraire dans les AST car ils préfèrent utiliser des AST pour effectuer des refactorings au lieu de conserver plusieurs arbres en même temps ou écrire un moteur d'inférence supplémentaire. Les programmeurs sont paresseux pour de bonnes raisons. En fait, ils stockent même les informations de ligne et de colonne recueillies par analyse lexicale dans les AST pour signaler les erreurs. Très abstrait en effet.

1
Kay Schluehr

L'arbre de syntaxe concret contient toutes les informations telles que les parenthèses superflues, les espaces et les commentaires, l'arbre de syntaxe abstrait s'abstenant de cette information.

NB: Assez drôle, lorsque vous implémentez un moteur de refactoring, votre AST contiendra à nouveau toutes les informations concrètes, mais vous continuerez à le désigner comme un AST car il est devenu le terme standard le champ (on pourrait donc dire qu’il a depuis longtemps perdu son sens originel).

1
akuhn

Simplement, AST ne contient que la sémantique du code, Parse tree/CST inclut également des informations sur la manière dont le code a été écrit.

0
mym