web-dev-qa-db-fra.com

Quels langages de programmation sont sans contexte?

Ou, pour être un peu plus précis: quels langages de programmation sont définis par une grammaire sans contexte?

D'après ce que je comprends, le C++ n'est pas sans contexte en raison de choses comme les macros et les modèles. Mon instinct me dit que les langages fonctionnels peuvent être sans contexte, mais je n'ai aucune donnée solide pour le sauvegarder.

Représentant supplémentaire pour des exemples concis :-)

57
n3rd

L'ensemble de programmes dont la syntaxe est correcte est sans contexte pour presque toutes les langues.

L'ensemble des programmes qui compilent n'est pas sans contexte pour presque tous les langages. Par exemple, si l'ensemble de tous les programmes C de compilation était sans contexte, alors en se croisant avec un langage régulier (également appelé regex), l'ensemble de tous les programmes C de compilation qui correspondent

^int main\(void\) { int a+; a+ = a+; return 0; }$

serait sans contexte, mais c'est clairement isomorphe au langage a ^ kba ^ kba ^ k, qui est bien connu pas pour être sans contexte.

34
Dave

Quels langages de programmation sont sans contexte? [...]

Mon instinct me dit que les langages fonctionnels peuvent être sans contexte [...]

La version courte: Il n'y a pratiquement aucun langage de programmation dans le monde réel qui soit sans contexte dans quelque sens que ce soit du mot. Qu'une langue soit ou non sans contexte n'a rien à voir avec sa fonctionnalité. Il s'agit simplement de la complexité des règles et des fonctionnalités du langage à analyser.

Voici un CFG pour le langage impératifBrainfuck :

Program → Instr Program | ε
Instr → '+' | '-' | '>' | '<' | ',' | '.' | '[' Program ']'

Et voici un CFG pour la fonctionnellecalcul combinateur SKI :

Program → E
E → 'S' E E E
E → 'K' E E
E → 'I'
E → '(' E ')'

Ces CFG reconnaissent tous programmes valides des deux langages parce qu'ils sont si simples.


La version plus longue: Habituellement, les grammaires sans contexte (CFG) ne sont utilisées que pour grosso modo spécifier la syntaxe d'un Langue. Il faut distinguer programmes syntaxiquement corrects et programmes qui compilent. Le plus souvent, les compilateurs divisent l'analyse du langage en analyse syntaxique qui construit et vérifie la structure générale d'un morceau de code, et analyse sémantique qui vérifie le signifiant du programme.

Si par "langage sans contexte" vous entendez " ... pour lequel tous les programmes compilent ", alors la réponse est: pratiquement aucun. Les langages qui correspondent à ce projet de loi n'ont guère de règles ou de fonctionnalités compliquées, telles que l'existence de variables, la sensibilité aux espaces, un système de types ou tout autre contexte: Informations définies à un endroit et sur lesquelles s'appuie un autre.

Si, par contre, "langage sans contexte" signifie seulement " ... pour lequel tous les programmes passent l'analyse syntaxique ", la réponse est une question de la complexité de la syntaxe seule. Il existe de nombreuses fonctionnalités syntaxiques difficiles ou impossibles à décrire avec un CFG seul. Certains de ces problèmes sont surmontés en ajoutant un état supplémentaire aux analyseurs pour garder une trace des compteurs, des tables de recherche, etc.

Exemples de fonctionnalités syntaxiques impossibles à exprimer avec un CFG:

  • Les langages sensibles à l'indentation et aux espaces blancs comme Python et Haskell. Le suivi des niveaux d'indentation imbriqués arbitrairement est essentiellement sensible au contexte et nécessite des compteurs séparés pour le niveau d'indentation; les deux combien d'espaces sont utilisés pour chaque niveau et combien il y a de niveaux.

    Autoriser uniquement un niveau d'indentation fixe en utilisant une quantité fixe d'espaces fonctionnerait en dupliquant la grammaire pour chaque niveau d'indentation, mais en pratique, cela n'est pas pratique.

  • Le C Typedef Parsing Problem dit que les programmes C sont ambigus pendant l'analyse lexicale car il ne peut pas savoir à partir de la grammaire seule si quelque chose est un identifiant régulier ou un alias typedef pour un type existant.

    L'exemple est:

      typedef int my_int;
      my_int x;
    

    Au point-virgule, l'environnement de type doit être mis à jour avec une entrée pour my_int. Mais si le lexer a déjà anticipé my_int, il l'aura lexé comme un identifiant plutôt qu'un nom de type.

  • Langages basés sur des macros et des modèles comme LISP, C++, Template Haskell, Nim, etc. Comme la syntaxe change au fur et à mesure de son analyse, une solution consiste à transformer l'analyseur en un programme auto-modifiable. Voir aussi " Le C++ est-il sans contexte ou sensible au contexte? "

  • Souvent, la priorité et l'associativité des opérateurs ne sont pas exprimées directement dans les CFG, même si elles est possible. Par exemple, un CFG pour une petite grammaire d'expression où ^ lie plus étroitement que ×, et × lie plus étroitement que +, pourrait ressembler à ceci:

    E → E ^ E
    E → E × E
    E → E + E
    E → (E)
    E → num
    

    Ce CFG est ambig , cependant, et est souvent accompagné d'un table de préséance/associativité disant par ex. que ^ lie le plus étroitement, × lie plus étroitement que +, que ^ est associatif à droite, et que × et + sont associatifs à gauche.

    La préséance et l'associativité peuvent être codées dans un CFG d'une manière mécanique de sorte qu'elle soit sans ambiguïté et ne produise que des arbres de syntaxe où les opérateurs se comportent correctement. Un exemple de ceci pour la grammaire ci-dessus:

    E₀ → EA E₁
    EA → E₁ + EA
    EA → ε
    E₁ → EM E₂
    EM → E₂ × EM
    EM → ε
    E₂ → E₃ EP
    EP → ^ E₃ EP
    E₃ → num
    E₃ → (E₀)
    

    Mais les tables CFG ambiguës + les tables de préséance/associativité sont courantes car elles sont plus lisibles et parce que différents types de analyseur LR les bibliothèques génératrices peuvent produire des analyseurs plus efficaces en éliminant les conflits de décalage/réduisant les conflits au lieu de traiter une grammaire transformée sans ambiguïté d'une plus grande taille.

En théorie, tous les ensembles finis de chaînes sont des langages réguliers, et donc tous les programmes légaux de taille limitée sont réguliers. Puisque les langages normaux sont un sous-ensemble de langages sans contexte, tous les programmes de taille limitée sont sans contexte. L'argument continue,

Bien que l'on puisse affirmer que ce serait une limitation acceptable pour un langage de n'autoriser que des programmes de moins d'un million de lignes, il n'est pas pratique de décrire un langage de programmation comme un langage régulier: la description serait beaucoup trop longue.
- Torben Morgensen's Bases de la conception de compilateurs, ch. 2.10.2

Il en va de même pour les CFG. Pour répondre un peu différemment à votre sous-question,

Quels langages de programmation sont définis par une grammaire sans contexte?

La plupart des langages de programmation du monde réel sont définis par leurs implémentations, et la plupart des analyseurs pour les langages de programmation du monde réel sont soit écrits à la main, soit utilisent un générateur d'analyseurs qui étend l'analyse sans contexte. Il n'est malheureusement pas si courant de trouver un CFG exact pour votre langue préférée. Lorsque vous le faites, c'est généralement sous forme Backus-Naur (BNF), ou dans une spécification d'analyseur qui n'est probablement pas purement sans contexte.

Exemples de spécifications grammaticales de la nature:

41
Simon Shine

Selon la façon dont vous comprenez la question, la réponse change. Mais IMNSHO, la bonne réponse est que tous les langages de programmation modernes sont en fait sensibles au contexte. Par exemple, il n'y a pas de grammaire sans contexte qui n'accepte que les programmes C syntaxiquement corrects. Les personnes qui pointent vers les grammaires libres de contexte yacc/bison pour C manquent le point.

8
starflyer

Pour prendre l'exemple le plus dramatique d'une grammaire non sans contexte, la grammaire de Perl est, d'après ce que je comprends, turing-complete .

3
Devin Jeanpierre

Si je comprends votre question, vous recherchez des langages de programmation qui peuvent être décrits par des grammaires sans contexte (cfg) afin que le cfg génère tous les programmes valides et uniquement les programmes valides.

Je crois que la plupart (sinon tous) les langages de programmation modernes ne sont donc pas sans contexte. Par exemple, une fois que vous avez des types définis par l'utilisateur (très courants dans les langues modernes), vous êtes automatiquement sensible au contexte.

Il existe une différence entre la vérification de la syntaxe et la vérification de l'exactitude sémantique d'un programme. La vérification de la syntaxe est sans contexte, alors que la vérification de l'exactitude sémantique ne l'est pas (encore une fois, dans la plupart des langages).

Cela ne signifie pas pour autant qu’un tel langage ne peut pas exister. Untyped lambda calculus , par exemple, peut être décrit en utilisant une grammaire sans contexte, et est, bien sûr, Turing complet.

3
Ginandi

VHDL est quelque peu sensible au contexte:

VHDL est sensible au contexte d'une manière moyenne. Considérez cette déclaration dans un processus:

jinx := foo(1);

Eh bien, en fonction des objets définis dans la portée du processus (et de ses étendues englobantes), cela peut être soit:

  • Un appel de fonction
  • Indexer un tableau
  • Indexation d'un tableau renvoyé par un appel de fonction sans paramètre

Pour analyser cela correctement, un analyseur doit transporter une table de symboles hiérarchique (avec des étendues englobantes), et le fichier actuel n'est même pas suffisant. foo peut être une fonction définie dans un package. Ainsi, l'analyseur doit d'abord analyser les packages importés par le fichier qu'il analyse et déterminer les symboles qui y sont définis.

C'est juste un exemple. Le système de type/sous-type VHDL est un désordre tout aussi sensible au contexte qui est très difficile à analyser.

(Eli Bendersky, "L'analyse VHDL est [très] difficile" , 2009)

2
Graham Gimbert

La plupart des langages de programmation modernes ne sont pas des langages sans contexte. Pour preuve, si je plonge dans la racine de CFL sa machine correspondante PDA ne peut pas traiter les correspondances de chaînes comme {ww | w is a string}. Donc, la plupart des langages de programmation l'exigent.

Exemple:

int fa; // w
fa=1; // ww as parser treat it like this
2
P.R.

Je pense que Haskell et ML supportent sans contexte. Voir ceci lien pour Haskell.

1
RoboAlex