IFT313 Introduction aux langages formels Froduald Kabanza Département d’informatique Université de Sherbrooke planiart.usherbrooke.ca/kabanza/cours/ift313 Expressions régulières
Sujets couverts Rôle de l’analyseur lexical Langages réguliers Expressions régulières IFT313 © Froduald Kabanza
Objectifs Savoir ce qu’un langage régulier. Être capable d’écrire une expression régulière décrivant un langage donné. Être capable de faire une recherche dans un fichier texte en utilisant grep. Être capable d’écrire un programme cherchant des patterns dans un fichier texte avec regex. IFT313 © Froduald Kabanza
Rôle de l’analyseur lexical Nous avons vu que la phase “analyse” d’un compilateur comprend: L’analyse lexicale : diviser le code source en une suite d’unités lexicales (tokens). L’analyse syntaxique : analyser la structure grammaticale du code source (de la suite de tokens) Analyse sémantique : déterminer le sens du code source. IFT313 © Froduald Kabanza
Rôle de l’analyseur lexical L’analyseur lexical lit une séquence de caractères et produit une séquence de tokens. En même temps, l’analyseur lexical produit une table de symboles. token Code source Analyseur lexical Analyseur syntaxique next token Table de symboles Analyseur sémantique Code cible IFT313 © Froduald Kabanza
Qu’est-ce qu’une unité lexicale (token) ? Un token (unité lexicale) est une séquence de caractères pouvant être traitée comme une unité dans la grammaire d’un langage de programmation. Exemples: Type de token Séquence de caractères ID x, rate, position NUM 60, 10 REAL 60.0 IF if WHILE while SEMI ; LPAREN ( RPAREN ) ASSIGN = IFT313 © Froduald Kabanza
Qu’est-ce qu’une unité lexicale (token) ? Les tokens comme IF, WHILE sont des mots-clés. Les mots-clés sont souvent réservés. Les tokens d’un langage de programmation incluent les identificateurs, les mots-clés, les nombres et les séparateurs ou terminaisons d’instructions (par exemple, ; /*) Les tokens sont les symboles terminaux d’une grammaire d’une langage de programmation. En général, un analyseur lexical ignore les espaces blancs (espaces, sauts de lignes et tabulation) entre les tokens et les commentaires. IFT313 © Froduald Kabanza
Chaîne de caractères unités lexicales int a = 34; // commentaire double /* commentaire */ b= 34.3900f; <INT_DECLARATION> { ligne=1, pos=1} <IDENTIFICATEUR> { ligne=1, pos=5, name=a} <ASSIGN> { ligne=1, pos=7} <INTEGER> { ligne=1, pos=9, value=34} <DOUBLE_DECLAR> { ligne=2, pos=12} <IDENTIFICATEUR> { ligne=2, pos=25, value=b} <ASSING> { ligne=2, pos=26} <DOUBLE> { ligne=2, pos=30, value=34.39} IFT313 © Froduald Kabanza
Qu’est-ce qu’une unité lexicale (token) ? Nous allons spécifier les tokens d’un langage de programmation en utilisant une notation formelle appelée le langage des expressions régulières. Nous allons implémenter les analyseurs lexicaux qui reconnaissent de tels tokens en utilisant des outils formels appelés automates (à états) finis. La théorie des langages réguliers nous permettra d’établir une correspondance entre les deux formalismes. IFT313 © Froduald Kabanza
Langages Le code source est une séquence de caractères (symboles), y compris les espaces, tabulations, sauts de lignes, etc. L’ensemble de tous les caractères possibles (symboles) est appelé un alphabet. Un langage est un ensemble de mots ou chaînes de caractères (possiblement infini) formé à partir d’un alphabet, selon une syntaxe bien précise. IFT313 © Froduald Kabanza
Opérations sur les langages Il y a plusieurs opérations qu’on peut effectuer avec les langages. Soit L et M deux langages. L U M = {s | s is in L or s is in M} union L = {s | s is not in L } complément LM= {s | s= s’s” for s’ in L and s” in M } concaténation L* = {s | s’s’’ for s’ and s’’ in L U {ε}} Étoile (ou fermeture) de Kleen (ε représente la chaîne vide ‘’). L+ = LL* Une ou plusieurs répétitions de L … IFT313 © Froduald Kabanza
Exemples d’opérations sur les langages Soit L = {A,B, … , Z, a,b,…,z} Soit D = {0,1,…,9} Alors L* est l’ensemble des mots formé de lettres, y compris la chaîne vide ε (aussi noté ‘’). L(L U D)* est l’ensemble de chaînes alphanumériques commençant par une lettre. DD* est l’ensemble des entiers positifs. IFT313 © Froduald Kabanza
C’est quoi un langage régulier ? Un langage régulier est un langage défini sur un alphabet fini en utilisant les opérations précédentes: union, concaténation, complément et fermeture de Kleen. Nous verrons bientôt d’autres définitions équivalentes : Un langage régulier est celui défini par une expression régulière. Un langage régulier est celui accepté par un automate fini. Un langage régulier est celui généré par une grammaire régulière. IFT313 © Froduald Kabanza
Expression régulières L’ensemble de tokens d’un langage de programmation est un langage régulier. Pour le spécifier à un générateur d’analyseurs lexicaux, comme JFLEX, on utilise une notation d’expressions régulières. Chaque expression régulière r dénote un langage régulier L(r) , selon les règles suivantes : IFT313 © Froduald Kabanza
Expression régulières ε (ou ‘’) : L’expression régulière ε représente le langage {ε} (ou {‘’}) symbole (caractère) : Pour chaque symbole (caractère) a dans l’alphabet, l’expression régulière a représente le langage {a}, c-à-d., le langage contenant juste le mot a. Étant donnés les expressions régulières r et s représentant, respectivement, les langages L(r) et L(s) : r|s (alternation) est une expression régulière représentant L(r) U L(s). rs (concaténation) est une expression régulière représentant L(r)L(s). r* (zéro ou plusieurs répétitions) représente (L(r))*. (r) est une expression régulière représentant L(r). IFT313 © Froduald Kabanza
Exemples expressions régulières ((a|b)a)* spécifie le langage { ‘’, aa, ba, aaaa, baaa, aaba, baba, aaaaaaa, …} (0|1)*0 spécifies l’ensemble de nombres binaires qui sont des multiples de 2. IFT313 © Froduald Kabanza
Autres notations d’expressions régulières r+ ≡ rr* r? ≡ r| ε [a b c] ≡ (a|b|c) [a-g] ≡ a|b|…|f|g [^s] ≡ complément de l’ensemble ^ ≡ début de ligne $ ≡ fin de ligne “ab” ≡ la chaîne ab . ≡ N’importe quelle caractère sauf ‘\n’ [a-zA-Z][a-zA-Z0-9]* : chaîne alphanumérique commençant par une lettre. [0-9]+ : un nombre entier positif. Examples IFT313 © Froduald Kabanza
Outils utilisant des expressions régulières grep regex (devoir 1) JFLEX (devoir 2) IFT313 © Froduald Kabanza
Exemple de spécification pour JFLEX Une spécification typique de JFLEX décrit des expressions régulières annotées de code Java pour traiter et renvoyer le token au parser. IFT313 © Froduald Kabanza
Résumé Nous utiliserons des expressions régulières pour décrire les tokens du langages que nous voulons analyser, compiler, traduire ou traiter autrement. Pour la tâche de reconnaissance de tokens, les expressions régulières sont très appropriées. Elles décrivent “ce qu’il faut reconnaître” pour isoler un token, plutôt que “comment” les reconnaître. Toutefois, pour que le scanner puisse effectivement reconnaître les tokens, nous avons besoin d’un outil formel procédural, pouvant être implémenté comme un programme. Pour cela, nous utiliserons les automates à états finis. Les expressions régulières sont aussi utiles pour faire une recherche dans un fichier de texte, avec des outils tels que grep et regex et des éditeurs tels que emacs. IFT313 © Froduald Kabanza