Quelqu'un peut-il me donner un exemple simple d'analyse syntaxique LL par rapport à l'analyse syntaxique LR?
À un niveau élevé, la différence entre l'analyse syntaxique LL et l'analyse syntaxique LR est que les analyseurs syntaxiques LL commencent au symbole de début et tentent d'appliquer des productions pour atteindre la chaîne cible, tandis que les analyseurs syntaxiques LR commencent à la chaîne cible et tentent de revenir au début. symbole.
Une analyse LL est une dérivation de gauche à droite. C'est-à-dire que nous considérons les symboles d'entrée de gauche à droite et essayons de construire une dérivation la plus à gauche. Ceci est fait en commençant par le symbole de début et en développant de manière répétée le non-terminal le plus à gauche jusqu'à ce que nous arrivions à la chaîne cible. Une analyse LR est une dérivation de gauche à droite, la plus à droite, ce qui signifie que nous balayons de gauche à droite et essayons de construire une dérivation la plus à droite. L'analyseur sélectionne en permanence une sous-chaîne de l'entrée et tente de l'inverser en non-terminal.
Lors d'une analyse LL, l'analyseur choisit en permanence entre deux actions:
A titre d'exemple, étant donné cette grammaire:
int
Puis, étant donné la chaîne int + int + int
_, un analyseur LL (2) (qui utilise deux jetons de lookahead) analysera la chaîne comme suit:
Production Input Action
---------------------------------------------------------
S int + int + int Predict S -> E
E int + int + int Predict E -> T + E
T + E int + int + int Predict T -> int
int + E int + int + int Match int
+ E + int + int Match +
E int + int Predict E -> T + E
T + E int + int Predict T -> int
int + E int + int Match int
+ E + int Match +
E int Predict E -> T
T int Predict T -> int
int int Match int
Accept
Notez qu'à chaque étape, nous examinons le symbole le plus à gauche de notre production. Si c'est un terminal, nous l'assortissons, et s'il s'agit d'un terminal, nous prédisons ce que cela va devenir en choisissant l'une des règles.
Dans un analyseur syntaxique LR, il existe deux actions:
Par exemple, un analyseur syntaxique LR (1) (avec un jeton de lookahead) peut analyser la même chaîne de la manière suivante:
Workspace Input Action
---------------------------------------------------------
int + int + int Shift
int + int + int Reduce T -> int
T + int + int Shift
T + int + int Shift
T + int + int Reduce T -> int
T + T + int Shift
T + T + int Shift
T + T + int Reduce T -> int
T + T + T Reduce E -> T
T + T + E Reduce E -> T + E
T + E Reduce E -> T + E
E Reduce S -> E
S Accept
Les deux algorithmes d'analyse que vous avez mentionnés (LL et LR) sont connus pour avoir des caractéristiques différentes. Les analyseurs syntaxiques LL ont tendance à être plus faciles à écrire à la main, mais ils sont moins puissants que les analyseurs syntaxiques LR et acceptent un ensemble de grammaires beaucoup plus petit que celui utilisé par les analyseurs syntaxiques LR. Les analyseurs syntaxiques LR sont proposés dans de nombreuses versions (LR (0), SLR (1), LALR (1), LR (1), IELR (1), GLR (0), etc.) et sont beaucoup plus puissants. Ils ont également tendance à être beaucoup plus complexes et sont presque toujours générés par des outils tels que yacc
ou bison
. Les analyseurs syntaxiques LL sont également proposés dans de nombreuses versions (y compris LL (*), qui est utilisé par l’outil ANTLR
), bien que, dans la pratique, LL (1) soit le plus largement utilisé.
Si vous souhaitez en savoir plus sur l’analyse syntaxique de LL et de LR, je viens tout juste de terminer l’enseignement d’un cours de compilation et j’ai des fiches et des diapositives sur l’analyse syntaxique sur le site Web du cours. Je serais ravi de vous en dire plus si vous pensez que cela serait utile.
Josh Haberman dans son article LL et LR Parsing Demystified affirme que l'analyse de LL correspond directement à notation polonaise , alors que LR correspond à notation polonaise inversée . La différence entre PN et RPN est l’ordre de traverser l’arbre binaire de l’équation:
+ 1 * 2 3 // Polish (prefix) expression; pre-order traversal.
1 2 3 * + // Reverse Polish (postfix) expression; post-order traversal.
Selon Haberman, cela illustre la principale différence entre les analyseurs syntaxiques LL et LR:
La différence principale entre le fonctionnement des analyseurs syntaxiques LL et LR réside dans le fait qu’un analyseur syntaxique LL génère une traversée de pré-ordre de l’arbre d’analyse syntaxique et qu’un analyseur LR délivre une traversée de post-ordre.
Pour des explications détaillées, des exemples et des conclusions, consultez Haberman article .
La LR utilise une approche descendante, tandis que la LR utilise une approche ascendante.
Si vous analysez une langue de programmation:
L'analyse de LL est handicapée par rapport à la LR. Voici une grammaire cauchemardesque pour un générateur d'analyseur syntaxique LL:
Goal -> (FunctionDef | FunctionDecl)* <eof>
FunctionDef -> TypeSpec FuncName '(' [Arg/','+] ')' '{' '}'
FunctionDecl -> TypeSpec FuncName '(' [Arg/','+] ')' ';'
TypeSpec -> int
-> char '*' '*'
-> long
-> short
FuncName -> IDENTIFIER
Arg -> TypeSpec ArgName
ArgName -> IDENTIFIER
Un FunctionDef ressemble exactement à un FunctionDecl jusqu'à ce que le ';' ou '{' est rencontré.
Un analyseur LL ne peut pas gérer deux règles en même temps, il doit donc choisir FunctionDef ou FunctionDecl. Mais pour savoir ce qui est correct, il faut rechercher un ';' ou '{'. Au moment de l’analyse grammaticale, le lookahead (k) apparaît infini. Au moment de l'analyse, il est fini, mais peut être volumineux.
Un analyseur syntaxique LR n'a pas besoin de regarder en avance, car il peut gérer deux règles en même temps. Ainsi, les générateurs d’analyseurs LALR (1) peuvent gérer cette grammaire avec facilité.
Étant donné le code d'entrée:
int main (int na, char** arg);
int main (int na, char** arg)
{
}
Un analyseur syntaxique LR peut analyser le
int main (int na, char** arg)
sans se soucier de savoir quelle règle est reconnue jusqu'à ce qu'elle rencontre un ';' ou un '{'.
Un analyseur syntaxique LL se bloque au niveau de 'int' car il doit savoir quelle règle est reconnue. Par conséquent, il doit rechercher un ';' ou '{'.
L'autre cauchemar pour les analyseurs syntaxiques LL est la récursion dans une grammaire. La récursion gauche est une chose normale dans les grammaires, pas de problème pour un générateur d'analyseur syntaxique LR, mais LL ne peut pas la gérer.
Vous devez donc écrire vos grammaires de manière non naturelle avec LL.
Exemple de dérivation la plus à gauche: Une grammaire G sans contexte a les productions
z → xXY (règle: 1) X → Ybx (règle: 2) Y → bY (règle: 3) Y → c (règle: 4)
Calculez la chaîne w = 'xcbxbc' avec la dérivation la plus à gauche.
z ⇒ xXY (règle: 1) ⇒ xYbxY (règle: 2) ⇒ xcbxY (règle: 4) ⇒ xcbxbY (règle: 3) ⇒ xcbxbc (règle: 4)
Exemple de dérivation la plus à droite: K → aKK (règle: 1) A → b (règle: 2)
Calculez la chaîne w = ‘aababbb’ avec la dérivation la plus à droite.
K ⇒ aKK (règle: 1) ⇒ aKb (règle: 2) ⇒ aaKKb (règle: 1) ⇒ aaKaKKb (règle: 1) ⇒ aaKaKbb (règle: 2) ⇒ aaKabbb (règle: 2) ⇒ aababbb (règle: 2)