Annonce

Réduire
Aucune annonce.

La création de langage - Introduction

Réduire
X
 
  • Filtre
  • Heure
  • Afficher
Tout nettoyer
nouveaux messages

  • Tutoriel La création de langage - Introduction

    Introduction

    La création et l'analyse formelle de langages est une vaste branche de la programmation informatique et bien que de solides connaissances en programmation et une bonne expérience dans différents langages soient indispensables pour appréhender au mieux cette discipline, je me propose aujourd'hui de rédiger une série d'article sur les différentes étapes de création d'un langage. Le but de ces articles sera de familiariser le lecteur avec une vision très théorique et abstraite des langages qu'il utilise afin d'élargir ses possibilités en terme de réflexion et de mise au point d'algorithmes complexes.
    Nous travaillerons en deux temps : la théorie et la pratique. Dans un premier temps, les nouveaux concepts seront expliqués et la thèse développée de manière abstraite et très précise. Le but sera de faire connaître le côté théorique de manière générique afin de pouvoir transposer le contenu du cours vers un exercice autre que le TP de la deuxième partie. Dans un deuxième temps, nous appliquerons le cours précédemment acquis par la création d'un petit langage de script qui pourra, par la suite, être utilisé par le lecteur dans ses propres programmes. Je tiens tout d'abord à préciser que les algorithmes utilisés pour le TP ne seront pas ou peu optimisés et leur code se voudra clair pour le lecteur.

    Une fois le cours terminé, le lecteur aura un interpréteur pour le langage de script suivant :

    Code:
    def prog = "cat"
    
    if args <> []
      def file = args !! 1
      exec prog, [file]
    else
      print "You need a file to cat."
    end
    HackScript - Le langage de script de l'académie

    Tout au long du cours, le lecteur aura l'occasion d'écrire un interpréteur pour le langage de script défini plus bas. Afin d'assurer la plus grande cohérence entre le cours et le TP, je décrirai personnellement les spécifications du langage, amenant ainsi tous les lecteurs à pouvoir travailler autour d'un seul et même langage. Ce cours étant rédigé pour hackademics, j'ai trouvé de bon ton de nommer le langage en question "HackScript". Ce sera un langage impératif de haut niveau à typage dynamique (termes expliqués plus tard) supportant trois types de données simples : le vide, l'entier et le caractère et un type de données complexe : la liste chaînée.

    La syntaxe du HS (HackScript) est simple et essentiellement basée sur le Ruby. L'indentation est très fortement conseillée, mais contrairement au Python, elle sera loin d'être obligatoire. On trouvera 3 niveaux hiérarchiques de constructions syntaxiques :
    • la directive
    • l'instruction
    • l'expression


    Parmi les directives, nous trouverons les instructions, les définitions de fonctions et les directives de préprocesseur. Les instructions représenteront les blocs, les boucles, les conditions et les macros secondaires. Les expressions seront quant à elles des calculs (numériques ou sur des listes, appel de fonctions...).

    La syntaxe d'un bloc est simple, il constitué d'un en-tête, d'une séquence d'instructions et du mot-clé "end", exemple :

    Code:
    while var == 1
    	foo("bonjour")
    	bar(1, 2)
    	
    	var = baz(1, 2, 3)
    end
    Le dernier point me paraissant assez important reste ce que j'ai appelé les "macros secondaires" qui, contrairement aux macros de préprocesseur, sont interprétées pendant l'éxecution. Au risque de ne pas être original, je n'en ai pensé que quatre :
    • print (affiche le contenu d'une variable)
    • read (lit une entrée clavier et la stocke dans une variable sous forme de chaîne de caractère)
    • return (permet le retour d'une valeur dans une fonction)
    • exec (permet d'exécuter un autre programme)


    Le fait que le retour de read soit une chaîne de caractère et rien d'autre permet une bien plus grande stabilité du code et éviter toute ambiguité quant au type de la variable après sa lecture. Pour pouvoir lire des entiers, nous créerons une fonction qui utilisera read et se chargera de convertir les données contenues dans la chaîne en le type désiré.
    La macro secondaire return sera bien particulière puisque celle-ci ne pourra être utilisée que dans une fonction. Une fonction n'ayant pas de return explicite renverra un unit (unit = variable de type vide) implicitement. Ainsi le code suivant est valide :

    Code:
    fun test():
    	print "bonjour"
    end
    
    def i = 0 # i :: Int
    def u = test() # u :: Unit
    
    def ti = [ 0 ; 1 ; 2 ] # ti :: [Int]
    def s = "" # s :: [Char]
    Afin de profiter du shebang (sous Linux), nous utiliserons les # comme balise de commentaire. Nous verrons au cours de notre étude que nous ne limiterons pas à ça et qu'une multitude de types de commentaires différents peuvent être implémentés de manière très simple et réutilisable.

    Conclusion

    Après une brève description de notre projet, je vais conclure sur quelques détails qui me paraissent importants. Tout d'abord, je ne donnerai que des morceaux de code, aucun code complet ne sera donné dans le cours, ce projet est à but éducatif et comprendre ce qui y sera dit est d'une importance capitale. Je tenterai de créer un interpréteur "officiel" pour que chacun sur le forum puisse profiter pleinement des résultats du projet en suivant le cours à son rythme, je recommande cependant de ne pas trop compter sur les sources que je distribuerai pour avancer dans le cours, le code que je mettrai sera le plus performant possible et non voué à être support du cours. Je ne saurais trop recommander de pratiquer et ce, pour des projets autre que HackScript, le but est d'acquérir la maîtrise des concepts exposés et non de réussir le TP.
    Je tiens par ailleurs à dire que je vais rédiger ce cours dans mon temps libre, malgré un emploi du temps assez chargé et qu'en plus je vais écrire beaucoup de code sur ce projet, c'est pourquoi je demanderai indulgence quant au temps que prendra un article à paraître. Je jure cependant que je garderai la plus grande qualité qu'il m'est possible de fournir dans l'écriture de mes articles.

    Sur ces quelques mots, je vous laisse la parole et suis tout ouïe des commentaires que vous émettrez.
    Bisou,

    Docteur Lalla.
    Y a deux ailes au cul de Lalla, sinon ça peut pas voler.

  • #2
    Quelle belle initiative Remarquable. Mes félicitations.

    Le fait de créer un langage "en temps réel" (qui plus est pour hackademics ) permettra, j'en suis sûr, à tous et à toutes de comprendre le mécanisme de création d'un nouveau langage.

    J'ai pour toi quelques questions et quelques demandes/propositions :

    - tout d'abord, HackScript qui donne HS, bon... nous dénommons le forum hackademics : "HK", ainsi, "HKS" me parait plus approprié !
    - peut-on proposer quelques idées pour la construction de la syntaxe ?
    - fortement basé sur Ruby, pourquoi ?

    J'ai envie de lire la suite dès ce soir

    Un +20 pour l'initiative
    sigpic

    Cyprium Download Link

    Plus j'étudie plus j'me rends compte que je n'sais rien.

    †|

    Commentaire


    • #3
      Pour l'abréviation, je suis pas à ça près, faites comme vous le sentez, le langage s'appellera HackScript et ses surnoms n'ont rien d'officiel, donc amusez vous.
      Pour ce qui est de la syntaxe, je préfèrerais une syntaxe officielle, définie par votre serviteur à l'égo surdimensionné. En revanche, comme la structure de mes prochains articles le suggère, rien ne vous empêche de partir dans des délires et de créer votre propre langage à la place du HKS et même, je vous y encourage vivement ! La principale raison pour laquelle j'aimerais éviter de brider la syntaxe est que j'essaie garder un langage cohérent et fiable. Le but étant (surtout d'après ma philosophie ^^) d'avoir une syntaxe presque unique pour chaque construction du langage. J'illustrerais volontiers mon propos par la fonction suivante :

      Code:
      def read_int():
      	def str = read ()
      	def result = 0
      	def neg = 1
      	
      	if str !! 0 == '-'
      		neg = -1
      		str = ~str
      	end
      	
      	while str <> []
      		if str !! 0 >= '0' and str !! 0 <= '9'
      			result = result * 10 + str !! 0 - 48
      			
      			str = ~str
      		else
      			str = []
      		end
      	end
      	
      	result = result * neg
      	return result
      end
      On reconnait sans peine une structure uniforme des blocs de la forme :

      nomdubloc parametre
      instr
      instr
      instr
      end

      C'est d'ailleurs la raison pour laquelle j'hésite à enlever les ':' à la fin du prototype des fonctions. D'un côté je trouve ça joli et ça donne un côté unique la définition de fonction, mais ça a aussi le malheur de casser l'unicité de la syntaxe. Pour rester sur la structure des blocs, c'est cette structure qui s'inspire de Ruby, rien d'autre, pas d'objet (coton à implémenter ça).

      Si tu veux en lire plus dès maintenant, je peux te conseiller "L'atelier P'tit Langage" sur le site du zéro qui m'a permis de démarrer dans cette discipline.
      Y a deux ailes au cul de Lalla, sinon ça peut pas voler.

      Commentaire


      • #4
        Bonjour Docteur Lalla.
        Ton sujet m'intéresse beaucoup !!!
        Je développe actuellement une nouvelle forme de programmation, mais un problème se pose : je n'arrive pas à calculer une chaîne mathématique contenant des priorités de calcules "(2*(6/2+1))". Sachant que le code source doit s'exécuter par l'intermédiaire de python, l'algorithme brut d'interprétation me manque.

        Aurais-tu une idée ?
        Vaut-il mieux lire la chaîne de gauche à droite ou de lire parenthèse par parenthèse ?
        Le problème est plus complexe qu'en apparence ...
        Dernière modification par Yarflam, 12 février 2013, 17h48.
        ~ Yarflam ~

        ❉ L'Univers se dirige vers son ultime perfection ❉

        Commentaire


        • #5
          Bonsoir !

          Tu touches là un problème que je comptais développer plus tard qu'on appelle "la récursivité à gauche". En fait, si tu écris une BNF naïve de ton langage, tu auras ça :

          Code:
          expr ::= leaf
          leaf ::= number
                 | reference (= 'x' ou 'bonsoir')
                 | (term)
          
          term ::= term + term
                 | term - term
                 | factor
          
          factor ::= factor * factor
                   | factor / factor
                   | leaf
          Comme tu peux le constater, si tu essaies de lire un terme ou un facteur, la première chose que tu vas trouver, c'est un sous-terme (ou un sous-facteur). Tu le lis, tu te retrouves dans la même situation... à l'infini. C'est le problème de la récursivité à gauche, tu ne peux pas faire d'analyse descendante (qui est l'analyse la plus simple à faire à la main).
          Dans le but d'améliorer la situation, on va devoir changer cette BNF et créer quelque chose de ce style :

          Code:
          expr ::= leaf
          leaf ::= number
                 | reference (= 'x' ou 'bonsoir')
                 | (term)
          
          term ::= factor term_aux
                 | factor
          
          term_aux ::= + term_aux
                     | - term_aux
                     | void
          
          term ::= factor term_aux
                 | factor
          
          term_aux ::= + term_aux
                     | - term_aux
                     | void
          
          factor ::= leaf factor_aux
                   | leaf
          
          factor_aux ::= + factor_aux
                     | - factor_aux
                     | void
          Tu peux maintenant faire une belle LL(1). (Je te laisse le soin de trouver toi-même l'algorithme, sachant que tu peux sereinement suivre scrupuleusement la BNF indiquée)
          Y a deux ailes au cul de Lalla, sinon ça peut pas voler.

          Commentaire


          • #6
            Merci beaucoup !!!
            Je vais étudier ton code BNF plus en détail, vu que je n'avais jamais croisé ce type de notation.
            En tout cas la logique je l'ai comprise. Ça va m'aider !
            ~ Yarflam ~

            ❉ L'Univers se dirige vers son ultime perfection ❉

            Commentaire


            • #7
              J'ai réussi ! ... à réinventer la calculette !
              http://pastebin.com/6VaGN8BN
              Tu vas me dire si ça colle avec ton code BNF. Au final, j'ai suivi uniquement ta logique ...

              Maintenant en avant pour ma programmation ...
              Dernière modification par Yarflam, 14 février 2013, 18h56.
              ~ Yarflam ~

              ❉ L'Univers se dirige vers son ultime perfection ❉

              Commentaire


              • #8
                Oh pitié !

                Juste non quoi ! Coupe chaque partie de ton algorithme en fonctions, pour chaque règle de la BNF, tu dois avoir une (ou plusieurs) fonction la mettant en oeuvre. Déjà de ce côté tu gagnes en clarté et surtout en flexibilité !

                Qui plus est, ton lexer est une horreur sans nom. Regarde le premier article que j'ai rédigé sur le lexique dans les langages de programmation, ça te laissera une idée de ce dont je parle.

                Je suis désolé de te dire ça aussi brutalement, mais voilà. Certes, ça fonctionne ; mais non, ce n'est pas beau, ce n'est pas réussi ! Le principal problème est un manque flagrant d'organisation du code.

                Bisou quand même !
                Y a deux ailes au cul de Lalla, sinon ça peut pas voler.

                Commentaire


                • #9
                  Oui, c'est très moche ! Généralement tout mes essais ressemblent à "ça".
                  Promis je l'améliorerai. (Vu que d'un autre côté j'ai pas trop le choix pour continuer ...)

                  Merci pour ton coup de pouce Docteur Lalla !
                  Ça m'a bien aidé.
                  ~ Yarflam ~

                  ❉ L'Univers se dirige vers son ultime perfection ❉

                  Commentaire


                  • #10
                    Un cours sur le développement d'un interpréteur pour un petit langage de programmation, par les gens qui ont fait l'atelier P'tit langage dont tu parlais.

                    Commentaire


                    • #11
                      Bonjour !

                      Je connais PM, et je connais aussi ce cours. D'ailleurs, ce n'est pas du tout la même approche que celui que je vais rédiger. Le but du cours de PM est d'arriver au langage en utilisant des outils spécialisés, le mien est de tout refaire à la main dans le but de comprendre comment ça fonctionne derrière, le langage final important peu.

                      Je recommande cependant la lecture de ce cours à qui est plus intéressé par le résultat que la démarche.
                      Y a deux ailes au cul de Lalla, sinon ça peut pas voler.

                      Commentaire

                      Chargement...
                      X