Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Atelier] P'tit langage

Craque ton slip !

Anonyme
    6 mai 2009 à 12:29:08

    Ah mince j'ai mal compris la phrase, désolé :-° . J'avais compris "les flottants ne sont pas un sous-ensemble de R car l'infini ne fait pas partie des flottants", alors qu'il fallait comprendre le contraire.
    • Partager sur Facebook
    • Partager sur Twitter
      6 mai 2009 à 21:23:30

      Cacophrene, je sais bien que l'addition et la multiplication son théoriquement commutatives, quand je fais 2.345 * 3.354 je me suis jamais dit "oulà attention au sens, c'est pas pareil si j'inverse" :-°

      Le truc, c'est que vu la représentation mémoire chelou des flottants, c'était possible que la multiplication devienne non-commutative.
      Maintenant, si l'autre avec ses affirmations qui nous font nous disputer voulait bien venir nous expliquer s'il s'est trompé ou pas, ça éviterait que Ppjet6 sorte le bazooka :-°
      • Partager sur Facebook
      • Partager sur Twitter
        7 mai 2009 à 0:25:23

        La première chose à voir c'est que quand on fait a * b (par exemple), il y a trois erreurs qui rentrent en jeu. Les deux erreurs faites en traduisant a et b en flottants, et l'erreur du calcul. Donc si "a * b" tout seul est commutatif, dès qu'on fait plus d'opérations, ce n'est plus vrai, parce que les erreurs réalisées au niveau des calculs intermédiaires ne sont pas équivalentes.

        Plus de détails voudrait dire de l'analyse numérique pas drôle, et c'est pas drôle.
        • Partager sur Facebook
        • Partager sur Twitter
          7 mai 2009 à 9:53:14

          Ben effectivement, j'ai vérifié Ppjet6 a raison, dans la norme l'addition et la multiplication sont commutatives mais pas associatives. Je m'étais trompé en lisant des histoires de bugs liées aux optimisations trop agressive du calcul des compilateurs.

          Je suis pas venu en reparler ici parce que j'ai jugé que c'était pas un sujet important et légèrement off-topic. Le sort en a décidé autrement.

          Par ailleurs, Cacophrène, tes histoires de "sous-ensemble de ..." ne sont pas très convaincantes puisque les opérations sur les flottants ne sont pas les opérations usuelles dans R (typiquement 0.1 + 0.2 ne fait pas 0.3).

          Effectivement, c'est un sujet vachement pas drôle. Encore plus sordide que les histoires d'overflow.
          • Partager sur Facebook
          • Partager sur Twitter
            7 mai 2009 à 14:15:12

            Salut !

            Citation : bluestorm

            Par ailleurs, Cacophrène, tes histoires de "sous-ensemble de ..." ne sont pas très convaincantes puisque les opérations sur les flottants ne sont pas les opérations usuelles dans R (typiquement 0.1 + 0.2 ne fait pas 0.3).


            Ce ne sont pas « mes histoires ». Il suffit de travailler à epsilon_float près (plus simplement encore : arrondir à un certain nombre de décimales) pour éviter les erreurs d'arrondis et autres joyeusetés liées à la représentation interne des flottants. Moyennant cette précaution, on retombe peu ou prou sur les opérations dans R. Je maintiens que l'approximation n'est pas si mauvaise que ça.

            Toutefois, si réserve il y a, elle concerne plutôt le fait que ce n'est pas du tout R mais bel et bien Q dont les flottants sont un sous-ensemble approximatif. Aucun nombre irrationnel ne peut être représenté correctement par un flottant. Mais là encore l'erreur d'approximation est-elle si importante qu'elle fasse rejeter l'analogie sans hésiter ? Je ne le crois pas.

            Citation : bluestorm

            Effectivement, c'est un sujet vachement pas drôle. Encore plus sordide que les histoires d'overflow.


            Sordide ou pas, c'est un point crucial dans la mesure où beaucoup de débutants sont tentés de faire des boucles avec des tests d'égalité sur les flottants comme condition d'arrêt (et aucune raison évidente ne peut leur révéler le risque que cela comporte). Cec dit, je suis bien d'accord pour dire qu'il est déplaisant d'être sans cesse rappelé à la dure réalité de la "représentation interne qui fait ceci quand je pense qu'elle fait cela". Sans parler des optimisations que tu évoques, qui compliquent encore la chose... :p

            Cordialement,
            Cacophrène
            • Partager sur Facebook
            • Partager sur Twitter
              7 mai 2009 à 18:39:16

              Ci ça intéresse des gens, j'ai créé un topic à part pour discuter du sujet. J'aimerais bien revenir à nos moutons par ici, mais je suis un peu découragé et vachement occupé dans l'immédiat.
              • Partager sur Facebook
              • Partager sur Twitter
                8 mai 2009 à 0:28:32

                Je suis pour ma part en train de bosser sur un interpréteur en C... mais c'est sur ce genre de choses qu'on voit que ce langage (le C) est rigide :/
                • Partager sur Facebook
                • Partager sur Twitter
                  10 mai 2009 à 15:49:49

                  Bonjour,

                  - J'ai recodé en partie mon truc en améliorant la structure (je me suis basé sur le code de bluestorm pour les types).
                  - J'ai rajouté une vrai gestion des erreurs, à la ligne et au caractère près.
                  - J'ai utilisé les Hashtbl pour la gestion des variables et des fonctions.
                  - Enfin, j'ai rajouté la syntaxe pour les fonctions, mais elles ne sont pas encore typées (c'est la prochaine étape).

                  Mon code est maintenant ici : http://code.google.com/p/slical/source/browse/#svn/trunk (en plus comme ça, vous avez la coloration).
                  N'ayez pas peur du nombre de fichier, y'en a qui contiennent presque rien.
                  Pour compiler : ocamlbuild calc.native si vous voulez le top-level, ou ocamlbuild slical.native pour l'interpreteur de fichiers.

                  Exemple de code :
                  # (define (f a) (if (= a 0) 1 (* a (f (- a 1)))))
                  # (print (string (f 5)))
                  120.#


                  Voilà voilou.

                  PS : N'hésitez pas à critiquer mon code, ça me serait extrêmement bénéfique.
                  • Partager sur Facebook
                  • Partager sur Twitter
                  Anonyme
                    10 mai 2009 à 16:19:53

                    Voilà la nouvelle version de mon interpréteur. J'ai essayé de corriger tout ce dont bluestorm a parlé, et j'ai fait un refactoring majeur. Enjoy!

                    #!/usr/bin/perl -l
                    
                    use strict;
                    use warnings;
                    my (%vars, %funcs);
                    
                    # Evaluate the sexp
                    # Apply the first argument to the tail
                    sub sexp {
                        my ($hd, @tl) = @_;
                        if (exists $funcs{$hd}) {
                            $funcs{$hd}->(@tl);
                        } else {
                            die "Unknown function `$hd'";
                        }
                    }
                    # Either evaluate the sexp or returns the direct value
                    sub comp {
                        my $val = shift;
                        if (ref $val eq 'ARRAY') {
                            sexp(@$val)
                        } elsif ($val =~ /^\d+$/) {
                            int $val
                        } elsif (exists $vars{$val}) {
                            $vars{$val}
                        } else {
                            die "Unknow variable `$val'"
                        }
                    }
                    
                    # Variable definition
                    $funcs{define} = sub {
                        my ($name, $val) = @_;
                        die "Bad variable name: `$name'" unless $name =~ /^[a-z]\w*$/;
                        die "Variable already defined: `$name'" if exists $vars{$name};
                        $val = comp($val);
                        $vars{$name} = $val;
                        return "$name => $val";
                    };
                    
                    # Basic binary ops
                    sub basic_binop {
                        my $op = shift;
                        $funcs{$op} = sub {
                            my ($a, $b) = @_;
                            $a = comp($a); $b = comp($b);
                            eval qq{$a $op $b};
                        };
                    }
                    basic_binop $_ for qw{+ - * / < > <= >=};
                    
                    # Booleans & branching
                    $funcs{not}  = sub { not(comp(shift)) };
                    $funcs{and}  = sub { comp(shift) and comp(shift) };
                    $funcs{or}   = sub { comp(shift) or  comp(shift) };
                    $funcs{if}   = sub {
                        my ($cond, $a, $b) = @_;
                        comp($cond) ? comp($a) : comp($b);
                    };
                    # Imperative tasks
                    $funcs{set} = sub {
                        my ($n, $v) = @_;
                        die "Unknow variable: `$n'" unless exists $vars{$n};
                        $vars{$n} = comp($v);
                    };
                    $funcs{begin} = sub { comp($_) for @_ };
                    $funcs{while} = sub {
                        my ($cond, $block) = @_;
                        comp($block) while comp($cond);
                    };
                    
                    # The "parsing"
                    # Produces arrays like ['+', '1', '2', '3'] from '(+ 1 2 3)'
                    my $txt = join '', <>;
                    $txt =~ y/()/[]/;
                    $txt =~ s/\s+/,/g;
                    $txt =~ s/([^\[\],]+)/'$1'/g;
                    my @code = eval $txt;
                    
                    # Main
                    print comp $_ for @code;
                    


                    Prochainement dans Pokémon : une version Perl 6 (si j'arrive à me passer de s///, Rakudo gère pas encore hélas :( ).
                    • Partager sur Facebook
                    • Partager sur Twitter
                      3 juillet 2009 à 11:25:01

                      Bonjour tout le monde !

                      J'ai moi aussi essayé de coder un p'tit langage. Je ne sais pas s'il fonctionne, l'interpréteur semble sauter une étape.

                      Voilà le code de l'interpréteur :

                      main.cpp

                      #include "interpreteur.h"
                      
                      int main(int argc,char *argv[])
                      {
                          Interpreteur lecteur(argv[1]);
                      
                      	lecteur.exec();
                      	return 0;
                      }
                      


                      interpreteur.h

                      #ifndef DEF_INTERPRETEUR
                      #define DEF_INTERPRETEUR
                      
                      #include <iostream>
                      #include <cstdlib>
                      #include <string>
                      #include <vector>
                      #include <fstream>
                      
                      class Interpreteur
                      {
                          public:
                              Interpreteur(std::string argv);
                              ~Interpreteur();
                      
                              int exec();
                      
                          protected:
                              void analyser(std::string analyze);
                      
                              std::string code;
                              std::ifstream file;
                      };
                      
                      #endif
                      


                      interpreteur.cpp

                      #include "interpreteur.h"
                      
                      using namespace std;
                      
                      Interpreteur::Interpreteur(string argv)
                      {
                          if(!argv.find(".jkc",0))
                              cerr << "L'extension n'est pas supportee!";
                      
                          file.open(argv.c_str(),ios::in);
                      
                          if(file)
                          {
                              while(getline(file,code))
                              {
                                  cout << "Chargement du code..." << endl;
                                  system("CLS");
                              }
                      
                              if(!code.empty())
                              {
                                  cout << "Chargement du code fini !" << endl;
                                  system("PAUSE");
                                  system("CLS");
                              }
                              else
                              {
                                  cerr << "Le code est introuvable";
                              }
                          }
                          else if(!file)
                          {
                              cerr << "Le fichier specifie n'existe pas." << endl;
                          }
                      }
                      
                      Interpreteur::~Interpreteur()
                      {
                          file.close();
                      }
                      
                      int Interpreteur::exec()
                      {
                          if(code.empty())
                          {
                              cerr << "Le code est introuvable." << endl;
                              system("PAUSE");
                              return 1;
                          }
                      
                          int pos = 0;
                          string::size_type fin;
                          string analyze;
                      
                          while(pos <= code.size())
                          {
                              fin = code.find(";",pos);
                              analyze = code.substr(pos,fin);
                      
                              analyser(analyze);
                      
                              pos = fin + 1;
                          }
                      
                          system("PAUSE");
                          return 0;
                      }
                      
                      void Interpreteur::analyser(string analyze)
                      {
                          string::size_type place_num1 = analyze.find_first_of("%ld",0);
                          string::size_type place_num2 = analyze.find("%ld",place_num1 + 1);
                      
                          long num1 = analyze.at(place_num1);
                          long num2 = analyze.at(place_num2);
                      
                          if(string::size_type output = analyze.find("output",0,6))
                          {
                              string::size_type begin = analyze.find_first_of("\"",output + 1);
                              string::size_type end = analyze.find("\"",begin + 1);
                      
                              if(begin != string::npos && end != string::npos)
                              {
                                  cout << analyze.substr(begin + 1,end - 1);
                              }
                      
                              else
                              {
                                  if(string::size_type ope = analyze.find("+",output + 1,analyze.size()))
                                  {
                                      cout << num1 + num2;
                                  }
                      
                                  if(string::size_type ope = analyze.find("-",output + 1,analyze.size()))
                                  {
                                      cout << num1 - num2;
                                  }
                      
                                  if(string::size_type ope = analyze.find("*",output + 1,analyze.size()))
                                  {
                                      cout << num1 * num2;
                                  }
                      
                                  if(string::size_type ope = analyze.find("/",output + 1,analyze.size()))
                                  {
                                      cout << num1 / num2;
                                  }
                      
                                  if(string::size_type ope = analyze.find("%",output + 1,analyze.size()))
                                  {
                                      cout << num1 % num2;
                                  }
                              }
                          }
                      }
                      


                      Voilà aussi un code test :

                      output 45 + 58;


                      La syntaxe est basée sur le code des fichiers .cfg utilisés pour les scripts JK2 et JK3.

                      Vous allez sûrement me reprocher :

                      Les inclusions inutiles : C'est pour quand j'en aurai besoin (si elles sont effectivement inutiles, je les enlèverai).
                      Les noms de variables à l'arrache : c'est tout moi :ange:

                      Le problème en lui même :
                      Je lance un fichier .jkc avec p'tit langage (c'est le nom de l'interpréteur), il charge le code et me dit "Chargement du code fini !". Ensuite, j'appuie sur un bouton comme demandé, et le programme se ferme.

                      Voilà, si quelqu'un pense avoir trouver la solution du problème, qu'il me le dise.

                      Merci d'avoir lu ce roman d'horreur.
                      • Partager sur Facebook
                      • Partager sur Twitter
                        3 juillet 2009 à 14:27:07

                        C'est pas le bon endroit pour poster. Si ta un problème, crée un nouveau post.
                        • Partager sur Facebook
                        • Partager sur Twitter
                          4 juillet 2009 à 0:34:14

                          Bon, comme j'avais déjà réalisé un petit interprète pour un autre langage, je propose ici mon code interprétant un début de P'tit langage. Le code est en OCaml, car personnellement, je trouve qu'OCaml est particulièrement bien adapté pour ce genre de programme. Le code utilise l'extension offerte par camlp4 pour les stream, que j'utilise dans l'analyse syntaxique.

                          L'analyse lexicale utilise Genlex, un module de la bibliothèque standard. Genlex est pratique pour faire de petites choses, mais ça devient vite limité. Quelques défauts (ou pas) notables : gestion bizarre du moins binaire et du moins unaire, "(*" considéré quoiqu'il arrive comme un début de commentaire, etc. Justement, le "(*" peut poser problème, voilà pourquoi les expressions telles "(* i j)" doivent être écrites "( * i j)" (avec un espace entre '(' et '*'). Autrement, je trouve ce module pratique et il est largement suffisant autant pour la spécialisation des unités lexicales que pour l'analyse lexicale en ce qui concerne le P'tit langage.

                          Il n'y a pas de type. En effet, il s'agit là d'une première version, une version "basique", et intégrer les types n'est pas une chose aisée, je compte éventuellement le faire dans une éventuelle deuxième version. Nous travaillons exclusivement sur le type int (les entiers).

                          Au lieu d'énumérer ce que ce code ne gère pas, je préfère énumérer ce qu'il gère : la définition de variable, les conditions if, les boucles while, set, l'affichage avec un "mot-clef" print et la suite d'instructions avec begin .. end. Il est possible que j'ajoute la gestion des fonctions dans une version ultérieure.

                          Pour être un peu plus au clair avec la syntaxe, je l'ai défini à l'aide de la grammaire suivante :

                          instrs -> ( instr ) instrs
                                  | RIEN
                          
                           instr -> define ident expr
                                  | if expr ( instr ) ( instr )
                                  | while expr ( instr )
                                  | set ident expr
                                  | Print of expr
                                  | begin instrs end
                          
                            expr -> int_value
                                  | ident
                                  | ( operator expr expr )


                          Voici le code (légèrement commenté) :

                          (* Définition de l'arbre abstrait *)
                          
                          type instrs =
                          | Instrs of instr * instrs
                          | Lf
                           and instr =
                          | Define of string * expr
                          | If of expr * instr * instr
                          | While of expr * instr
                          | Set of string * expr
                          | Print of expr
                          | Begin of instrs
                           and expr =
                          | PLInt of int
                          | PLId of string
                          | Op of string * expr * expr
                          
                          (* Analyse lexicale *)
                          
                          open Genlex
                          
                          let analex = function
                          | "" -> failwith "Error in [analex] : Void src"
                          | str -> let kwd = ["("; ")"; "define"; "if"; "while"; "set"; "begin"; "end"; "print";
                                              "+"; "-"; "**"; "/"; "*"; "<="; "<>"; ">="; ">"; "="; "<"; "and"; "or"]
                            in make_lexer kwd (Stream.of_string str)
                            
                          (* Analyse syntaxique *)
                          
                          let anasyn stm =
                          
                            let is_op = function
                            | ("+"| "-"| "**"| "/"| "*"| "<="| "<>"| ">="| ">"| "="| "<"| "and"| "or") -> true
                            | _ -> false
                            
                            in let rec instrs = parser
                            | [< 'Kwd "("; i = instr; 'Kwd ")"; is = instrs >] -> Instrs (i, is)
                            | [< >] -> Lf
                            
                             and instr = parser
                            | [< 'Kwd "define"; 'Ident n; e = expr >] -> Define (n, e)
                            | [< 'Kwd "if"; e = expr; 'Kwd "("; i1 = instr; 'Kwd ")"; 'Kwd "("; i2 = instr; 'Kwd ")" >] -> If (e, i1, i2)
                            | [< 'Kwd "while"; e = expr; 'Kwd "("; i = instr; 'Kwd ")" >] -> While (e, i)
                            | [< 'Kwd "set"; 'Ident n; e = expr >] -> Set (n, e)
                            | [< 'Kwd "print"; e = expr >] -> Print e
                            | [< 'Kwd "begin"; is = instrs; 'Kwd "end" >] -> Begin is
                            | [< >] -> failwith "Error in [instr] : no match case"
                            
                             and expr = parser
                            | [< 'Int i >] -> PLInt i
                            | [< 'Ident n >] -> PLId n
                            | [< 'Kwd "("; 'Kwd op when is_op op; e1 = expr; e2 = expr; 'Kwd ")" >] -> Op (op, e1, e2)
                            | [< >] -> failwith "Error in [expr] : no match case"
                            
                            in instrs stm
                            
                          (* Evaluation *)
                          
                          let eval ast tbl =
                          
                            let bool_of_int = function
                            | 0 -> false
                            | _ -> true
                            
                            in let int_of_bool = function
                            | true -> 1
                            | false -> 0
                            
                            in let rec eval_instrs = function
                            | Instrs (i, is) -> eval_instr i; eval_instrs is
                            | Lf -> ()
                            
                             and eval_instr = function
                            | Define (n, e) -> Hashtbl.add tbl n (eval_expr e)
                            | If (e, i1, i2) -> if bool_of_int (eval_expr e) then eval_instr i1 else eval_instr i2
                            | While (e, i) -> while bool_of_int (eval_expr e) do eval_instr i done
                            | Print e -> print_int (eval_expr e); print_newline ()
                            | Set (n, e) ->
                              if Hashtbl.mem tbl n then
                                Hashtbl.replace tbl n (eval_expr e)
                              else failwith ("Error in [eval_instr] : " ^ n ^ " undefined")
                            | Begin is -> eval_instrs is
                            
                             and eval_expr = function
                            | PLInt i -> i
                            | PLId n ->
                              if Hashtbl.mem tbl n then
                                Hashtbl.find tbl n
                              else failwith ("Error in [eval_expr] : " ^ n ^ " undefined")
                            | Op (op, e1, e2) ->
                              let a, b = eval_expr e1, eval_expr e2
                              in ( match op with
                              | "+" -> a + b
                              | "-" -> a - b
                              | "**" -> int_of_float ( float_of_int a ** float_of_int b )
                              | "/" -> a / b
                              | "*" -> a * b
                              | "<=" -> int_of_bool ( a <= b)
                              | "<>" -> int_of_bool ( a <> b)
                              | ">=" -> int_of_bool ( a >= b)
                              | ">" -> int_of_bool ( a > b)
                              | "=" -> int_of_bool ( a = b)
                              | "<" -> int_of_bool ( a < b)
                              | "and" -> int_of_bool ( bool_of_int a && bool_of_int b)
                              | "or" -> int_of_bool ( bool_of_int a || bool_of_int b)
                              | _ -> failwith "Error in [eval_expr] : no match case" )
                          	
                            in eval_instrs ast
                             
                          (* Pour tester *)
                          
                          let plang () =
                            let read_bloc () =
                              let rec read acc = match read_line () with
                              | ";;" -> acc
                              | s -> read (s :: acc)
                              in String.concat " " (List.rev (read []))
                            in let src = read_bloc ()
                            in eval (anasyn (analex src)) (Hashtbl.create 1)
                          


                          Et voila un petit essai :

                          # plang ();;
                          (define a 5)
                          (while a
                            (begin
                              (print a)
                              (set a (- a 1))
                             end)
                          )
                          ;;
                          5
                          4
                          3
                          2
                          1
                          - : unit = ()
                          
                          • Partager sur Facebook
                          • Partager sur Twitter
                            7 août 2009 à 22:05:29

                            Chem ton code n' est pas portable;
                            system("CLS"); // fonctionne uniquement sur windows
                            Bonne chance à tous
                            • Partager sur Facebook
                            • Partager sur Twitter
                            Anonyme
                              22 août 2009 à 18:08:17

                              Bonjour,

                              Mon langage est très très rudimentaire pour le moment, mais j'ai décidé de faire une base et d'ajouter des fonctionnalités plus tard.
                              J'ai choisis de faire un langage à structure de blocs pour permettre (plus tard) l'implémentation des portés pour les variables et pour la lisibilité du code.

                              Exemple de code :

                              Citation : P'tit langage

                              [
                              (let a 5)
                              (print a)
                              [
                              (let b 10)
                              (print b)
                              ]
                              ]



                              Ensuite, le code : ici

                              Je viens demander des critiques et suggestions sur le code bien entendu mais aussi des renseignements sur comment implémenter les portés et le typage.

                              Pour les portés, j'ai pensé à créer une table (Hashtbl) à chaque fois que je rencontre un symbole "[" et de la détruire à chaque symbole "]".
                              Ainsi, je pourrai former une pile de tables et les utiliser dans leurs blocs respectifs. Je sais que c'est la bonne méthode, cependant elle me parait légèrement compliqué à mettre en oeuvre :-° .

                              Pour le typage, je n'ai aucune idée de comment procéder.

                              Merci d'avance.
                              • Partager sur Facebook
                              • Partager sur Twitter
                                22 août 2009 à 18:13:45

                                Citation

                                J'ai choisis de faire un langage à structure de blocs pour permettre (plus tard) l'implémentation des portés pour les variables et pour la lisibilité du code.


                                Comment ça ? Il n'y a pas besoin de blocs pour avoir de la portée des variables. Et tu codes en OCaml (donc tu dois trouver ça un poil lisible) qui n'a pas de blocs.

                                Je crois que tu trompes sur ce qu'est la portée, et l'intérêt des blocs. Je pense que tu devrais commencer par faire quelque chose de simple comme les premières "couches" que j'ai proposées, avant de prendre des libertés. En particulier, la partie "déclarations locales de valeurs" est la plus importante pour la question de la portée, et si tu ne trouves pas comment faire tu peux te référer aux codes existants sur la question.


                                Edit :
                                Plutôt qu'une Hashtable, tu ferais mieux d'utiliser une simple liste associative :
                                - List.mem_assoc pour voir si un binding existe ;
                                - List.assoc pour y accéder ;
                                - (identifiant, valeur) :: ancien_environnement pour ajouter un binding à ton environnement.

                                Ce n'est pas la structure la plus performante mais elle te permet de te concentrer sur la conception et le fonctionnement du truc. Tu pourras t'occuper des performances plus tard, ou pas du tout, ce n'est pas la partie la plus importante de l'atelier.
                                • Partager sur Facebook
                                • Partager sur Twitter
                                Anonyme
                                  22 août 2009 à 18:20:50

                                  En fait, les blocs permettent de ne pas avoir à créer un autre mot clé.
                                  Dès que j'entre dans un bloc, je sais déjà que toutes les variables déclarées dans ce bloc pourront être utilisées uniquement dans ce bloc.

                                  Par contre, les variables déclarées dans un bloc A peuvent être utilisées dans un sous-bloc B de A

                                  Je ne sais pas si c'est très clair :-° .

                                  En tout cas, merci pour ces explications.
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    22 août 2009 à 18:25:28

                                    C'est clair mais ça ne sert à rien puisque ma proposition de "let" local dans le sujet fait exactement ça : tu as accès à la variable bindée dans tout le reste de l'expression (ce que tu vois comme les "sous-blocs") et ni "avant" ni "après". Tu peux voir ça comme des blocs à une seule variable (comme le "let .. in .." de OCaml), sachant que tu peux dans un second temps permettre les déclarations simultanées dans un seul 'let' comme le propose le sujet.

                                    En bref, si t'es pas trop sûr de toi, essaie de pas trop t'écarter du sujet, c'est un terrain à peu prêt sûr qui a été étudié pour présenter tous ces problèmes de manière progressive.

                                    Je n'ai pas encore regardé ton code, j'essaierai de le faire.
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                    Anonyme
                                      22 août 2009 à 18:27:51

                                      D'accord, je comprend mieux.
                                      Je voulais "simplifier" la démarche mais, en effet, ça complique inutilement les choses.

                                      Je vais m'en tenir au programme pour le moment.

                                      Merci.

                                      Edit : Version du code sans les blocs, juste avec les opérations arithmétiques, la déclaration de variable et un opérateur print : code
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        23 septembre 2009 à 0:48:37

                                        Salut,

                                        Je ressuscite le topic, parce que ça manque un peu de python dans le coin ! Ah oui et puis aussi, c'est intéressant comme atelier...

                                        Je préfère prévenir, c'est beaucoup plus volumineux que les codes Ocaml, d'une part parce que tout est fait à la main (y compris le lexer, les Genlex et consort c'est de la triche :-° ), et d'autre part parce que plutôt que d'interpréter directement le code, j'ai préféré construire un arbre syntaxique, et ensuite l'évaluer. L'avantage c'est que ça permet d'étendre le langage rapidement, et puis si je suis vraiment motivé (comprendre : j'ai rien à foutre de mes journées), ça peut constituer le front-end d'un compilateur.

                                        Voilà où le projet en est : on a
                                        • les opérateurs arithmétiques + - * / ;
                                        • les opérateurs de comparaison < <= > >= = <> ;
                                        • les définitions de variables avec (define the_answer 42);
                                        • les structures if-then-else avec (if ga then bu else zo);
                                        • une gestion à peu près correcte des erreurs (avec un affichage de où-c'est-qu'-ça-a-foiré™).

                                        Il n'existe que deux types d'instructions (statement dans le code): les définitions de variables avec define et le reste; toutes les instructions autres que les define renvoient une valeur (y compris les if-then-else, ça change agréablement du comportement de python), les définitions ne renvoient rien (enfin, qui dit rien en Python dit None).

                                        L'évaluation est paresseuse (enfin, si je me plante pas sur ce que c'est qu'une évaluation paresseuse). On peut donc écrire (define y x) (define x 3) (y) et paf, ça fait des chocapics renvoie 3.

                                        Voilà la grammaire du machin :
                                        program         ::= statement_list
                                        
                                        statement_list  ::= "(" statement ")" statement_list
                                                         |  NOTHING
                                        
                                        statement       ::= assign_stmt
                                                         |  expr_stmt
                                        
                                        assign_stmt     ::= "define" ID expr_stmt
                                        
                                        expr_stmt       ::= "if" atom "then" atom "else" atom
                                                         |  OP atom_list
                                                         |  atom
                                        
                                        atom_list       ::= atom atom_list
                                                         |  NOTHING
                                        
                                        atom            ::= NUM
                                                        ::= ID
                                                         |  "(" expr_stmt ")"


                                        et voilà les 4 fichiers que sont le module des erreurs :
                                        #!/usr/bin/env python
                                        # coding: utf-8
                                        
                                        
                                        # -- Lexical errors
                                        
                                        
                                        class PLLexicalError(Exception):
                                            def __init__(self, value, start_pos, end_pos):
                                                self.value = value
                                                self.start_pos = start_pos
                                                self.end_pos = end_pos
                                        
                                        
                                        class UnknownOpError(PLLexicalError):
                                            def __str__(self):
                                                return "Unknown operator '" + str(self.value) + "'"
                                        
                                        
                                        class IllicitCharError(PLLexicalError):
                                            def __str__(self):
                                                return "Illicit character '" + str(self.value) + "'"
                                        
                                        
                                        # -- Syntax errors
                                        
                                        
                                        class PLSyntaxError(Exception):
                                            def __init__(self, msg=""):
                                                self.msg = msg
                                        
                                            def __str__(self):
                                                return self.msg
                                        
                                        
                                        class UnknownIdError(PLSyntaxError):
                                            def __init__(self, name):
                                                self.name = name
                                        
                                            def __str__(self):
                                                return "Unknown identifier '" + self.name + "'"
                                        

                                        le module du lexer :
                                        #!/usr/bin/env python
                                        # coding: utf-8
                                        
                                        import string
                                        
                                        from error import *
                                        
                                        # Some utility lists
                                        _end_char = '\0'
                                        _digits = list(string.digits)
                                        _letters = list(string.letters)
                                        _whitespace = list(string.whitespace)
                                        _opchars = ['+', '-', '*', '/', '<', '>', '=',]
                                        
                                        
                                        # The token types
                                        ID = 'an identifier'
                                        KEYWD = 'a keyword'
                                        NUM = 'a number'
                                        OP = 'an operator'
                                        LPAREN = 'a left parenthesis'
                                        RPAREN = 'a right parenthesis'
                                        END = 'the end'
                                        
                                        class Lexer:
                                            def __init__(self, input="", keywords=[], operators=['+', '-', '*', '/']):
                                                self.keywords = keywords
                                                self.operators = operators
                                                self.set_input(input)
                                        
                                            def set_input(self, input):
                                                self.pos = 0
                                                self.start_pos = 0
                                                self.pos_max = len(input)
                                                self.input = input + _end_char
                                                self.current_token = self.read_next_token()
                                        
                                            # Return the token being read and scan the next.
                                            def get_token(self):
                                                current_token = self.current_token
                                                self.current_token = self.read_next_token()
                                                return current_token
                                        
                                            # Return the token being read without scanning the next. That is, several
                                            # successive calls to 'peek()' will give the same result, while successive
                                            # calls to 'get_token()' would give three different results (the three next
                                            # tokens).
                                            def peek(self):
                                                return self.current_token
                                        
                                            # Scan the next token and return it.
                                            def read_next_token(self):
                                                self.last_start_pos = self.start_pos
                                                self.last_pos = self.pos
                                        
                                                # Skip _whitespace
                                                while self.input[self.pos] in _whitespace:
                                                    self.pos += 1
                                        
                                                # Remember the start position of the token being read for debugging
                                                self.start_pos = self.pos
                                                cur_char = self.input[self.pos] # The current characterbeing read
                                        
                                                # If we are reading an identifier or a keyword
                                                if cur_char in _letters:
                                                    result = ''
                                                    while self.input[self.pos] in _letters + _digits + ['_']:
                                                        result += self.input[self.pos]
                                                        self.pos += 1
                                                    
                                                    # Check whether what was read is a keyword
                                                    if result in self.keywords:
                                                        return Token(KEYWD, result)
                                                    else:
                                                        return Token(ID, result)
                                        
                                                # If we are reading a number (positive or negative)
                                                elif cur_char in _digits + ['-', '+']:
                                                    result = ''
                                                    
                                                    # We first have to check that if we read a '+' or '-', it is
                                                    # followed by a digit to ensure it was a unary operator and not a
                                                    # binary one
                                                    if cur_char in ['+', '-'] and not self.input[self.pos+1] in _digits:
                                                        self.pos += 1
                                                        return Token(OP, cur_char)
                                                    else:
                                                        result += cur_char
                                                        self.pos += 1
                                        
                                                    while self.input[self.pos] in _digits:
                                                        result += self.input[self.pos]
                                                        self.pos += 1
                                        
                                                    return Token(NUM, int(result))
                                        
                                                # If we are reading an operator
                                                elif cur_char in _opchars:
                                                    result = ''
                                                    while self.input[self.pos] in _opchars:
                                                        result += self.input[self.pos]
                                                        self.pos += 1
                                        
                                                    if result in self.operators:
                                                        return Token(OP, result)
                                                    else:
                                                        raise UnknownOpError(result, self.start_pos, self.pos)
                                        
                                                # Parentheses
                                                elif cur_char == '(':
                                                    self.pos += 1
                                                    return Token(LPAREN)
                                                elif cur_char == ')':
                                                    self.pos += 1
                                                    return Token(RPAREN)
                                                        
                                                # The end of the input
                                                elif cur_char == _end_char:
                                                    return Token(END)
                                                
                                                # Woops, that's not legal
                                                else:
                                                    raise IllicitCharError(cur_char, self.start_pos, self.pos)
                                        
                                        
                                        class Token:
                                            def __init__(self, type, value=None):
                                                self.type = type
                                                self.value = value
                                        

                                        le module des arbres syntaxiques :
                                        #!/usr/bin/env python
                                        # coding: utf-8
                                        
                                        from error import *
                                        
                                        # Map an operator name to a function
                                        op_dict = {
                                                '+':    lambda x,y: x + y,
                                                '-':    lambda x,y: x - y,
                                                '*':    lambda x,y: x * y,
                                                '/':    lambda x,y: x / y,
                                                '<':    lambda x,y: x < y,
                                                '<=':   lambda x,y: x <= y,
                                                '>':    lambda x,y: x > y,
                                                '>=':   lambda x,y: x >= y,
                                                '=':    lambda x,y: x == y,
                                                '<>':   lambda x,y: x != y
                                                }
                                        
                                        # A generic syntax tree node.
                                        # The __str__ part is there for debugging purposes.
                                        class PLNode():
                                            def __str__(self):
                                                return '<(%s)>' % self.__class__.__name__
                                        
                                        
                                        class AssignStmt(PLNode):
                                            def __init__(self, target, ast, context):
                                                self.target = target
                                                self.ast = ast
                                                self.context = context
                                        
                                            def eval(self):
                                                self.context.assign(target=self.target, ast=self.ast)
                                        
                                        
                                        class IfThenElse(PLNode):
                                            def __init__(self, condition, then_block, else_block):
                                                self.condition = condition
                                                self.then_block = then_block
                                                self.else_block = else_block
                                        
                                            def eval(self):
                                                if self.condition.eval():
                                                    return self.then_block.eval()
                                                else:
                                                    return self.else_block.eval()
                                        
                                        
                                        class Id(PLNode):
                                            def __init__(self, name, context):
                                                self.name = name
                                                self.context = context
                                        
                                            def eval(self):
                                                return self.context.fetch(target=self.name)
                                        
                                        
                                        class Op(PLNode):
                                        
                                            def __init__(self, name, operands):
                                                self.name = name
                                                self.operands = operands
                                        
                                            def eval(self):
                                                if len(self.operands) != 2:
                                                    msg = "Wrong number of arguments. Operator " + self.name +\
                                                    " expected 2 arguments but got %d" % len(self.operands)
                                                    raise PLSyntaxError(msg)
                                                func = op_dict[self.name]
                                                arg1 = self.operands[0].eval()
                                                arg2 = self.operands[1].eval()
                                                return func(arg1, arg2)
                                        
                                        
                                        class Atom(PLNode):
                                            def __init__(self, value):
                                                self.value = value
                                        
                                            def eval(self):
                                                return self.value
                                        
                                        class Num(Atom): pass
                                        

                                        et le module du parser proprement dit :
                                        #!/usr/bin/env python
                                        # coding: utf-8
                                        
                                        import sys
                                        
                                        from lex import *
                                        from ast import *
                                        from error import *
                                        
                                        
                                        # For debugging only. When 'pass' is replaced by 'print msg', it prints the
                                        # list of the names of the productions that are matched.
                                        def dump(msg):
                                            pass
                                        
                                        
                                        class Parser:
                                            def __init__(self, keywords=[], operators=['+','-','*','/']):
                                                self.input = input
                                                self.lexer = Lexer(keywords=keywords, operators=operators)
                                                self.global_context = Context(father=None)
                                                self.results = None
                                            
                                            # Parse the input into an abstract syntax tree
                                            def parse(self, input=""):
                                                self.input = input
                                                try:
                                                    self.lexer.set_input(self.input)
                                                    self.results = self.statement_list
                                                except PLLexicalError as e:
                                                    print "(!) Lexical error (%d-%d): %s." \
                                                            % (self.lexer.last_start_pos, self.lexer.last_pos, e)
                                                except PLSyntaxError as e:
                                                    print "(!) Syntax error (%d-%d): %s." \
                                                            % (self.lexer.last_start_pos, self.lexer.last_pos, e)
                                                except: raise
                                        
                                            def report_error(self, name_error, msg_error):
                                                start = self.lexer.last_start_pos
                                                stop = self.lexer.last_pos - 1
                                                print "(!) %s:" % (name_error)
                                                print "    %s" % self.input
                                                print "    %s^%s" % (" " * (start), "^" * (stop-start))
                                                print "    %s." % msg_error
                                        
                                            # A generator that returns the evaluations of the successive statements
                                            def eval(self):
                                                try:
                                                    for result in self.results():
                                                        yield result
                                                except PLSyntaxError as e:
                                                    self.report_error("Syntax error", e)
                                                except: raise
                                        
                                            # Check that the current token is of the expected type. If it is, return
                                            # the value of the token; if a value was provided, check that the value of
                                            # the token is what we expected.
                                            def match(self, expected_type, expected_value=None):
                                                token = self.lexer.get_token()
                                                if token.type == expected_type:
                                                    if expected_value == None or \
                                                        (expected_value != None and token.value == expected_value):
                                                        return token.value
                                                    else:
                                                        raise PLSyntaxError("I expected '%s' but got '%s'" %
                                                                (expected_value, token.value))
                                                else:
                                                    raise PLSyntaxError("I expected %s but got %s" % 
                                                            (expected_type, token.type))
                                        
                                            # -- The functions correponding to productions in the grammar
                                                
                                            def statement_list(self):
                                                dump('statement_list')
                                                while self.lexer.peek().type == LPAREN:
                                                    self.lexer.get_token()
                                                    statement = self.statement()
                                                    self.match(RPAREN)
                                                    yield statement.eval()
                                        
                                            def statement(self):
                                                dump('statement')
                                                token = self.lexer.peek()
                                                
                                                # assign_stmt
                                                if token.type == KEYWD and token.value == "define":
                                                    self.match(KEYWD)
                                                    dump('assign_stmt')
                                                    target = self.match(ID)
                                                    ast = self.atom()
                                                    return AssignStmt(target=target, ast=ast,
                                                            context=self.global_context)
                                        
                                                # expr_stmt
                                                else: return self.expr_stmt()
                                        
                                            def expr_stmt(self):
                                                dump('expr_stmt')
                                                token = self.lexer.peek()
                                                
                                                # if-then-else expression
                                                if token.type == KEYWD and token.value == "if":
                                                    dump('if_stmt')
                                                    self.match(KEYWD)
                                                    condition = self.atom()
                                                    self.match(KEYWD, "then")
                                                    then_block = self.expr_stmt()
                                                    self.match(KEYWD, "else")
                                                    else_block = self.expr_stmt()
                                                    return IfThenElse(condition=condition, then_block=then_block,
                                                            else_block=else_block)
                                                
                                                # An operation
                                                if token.type == OP:
                                                    operator = self.match(OP)
                                                    operands = self.atom_list()
                                                    return Op(name=operator, operands=operands)
                                                    
                                                # atom
                                                else: return self.atom()
                                        
                                            def atom_list(self):
                                                dump('atom_list')
                                                atoms = []
                                        
                                                # Get as much atoms as possible
                                                while self.lexer.peek().type in [NUM, ID, LPAREN]:
                                                    atoms.append(self.atom())
                                        
                                                return atoms
                                        
                                            def atom(self):
                                                dump('atom')
                                                token = self.lexer.get_token()
                                                dump(token.type)
                                        
                                                # A number
                                                if token.type == NUM:
                                                    return Num(value=token.value)
                                                
                                                # An identifier
                                                elif token.type == ID:
                                                    return Id(name=token.value, context=self.global_context)
                                        
                                                # ( expr_stmt )
                                                elif token.type == LPAREN:
                                                    result = self.expr_stmt()
                                                    self.match(RPAREN)
                                                    return result
                                        
                                                else:
                                                    raise PLSyntaxError("I did not expect %s" % token.type)
                                        
                                        
                                        # A context acts as a dictionary that maps an identifier to a syntax tree. Not
                                        # that useful for now, but it will be when the keyword 'let' is introduced.
                                        class Context():
                                        
                                            def __init__(self, father):
                                                # 'father' is the context of which 'self' is a sub-context; that is,
                                                # the father is a broader context.
                                                # father == None for the global context
                                                self.father = father
                                                
                                        
                                            # Assign a syntax tree to a name
                                            def assign(self, target, ast):
                                                return setattr(self, target, ast)
                                        
                                            # Get the tree associated to a name, searching from the current context
                                            # outwards
                                            def fetch(self, target):
                                                if hasattr(self, target):   # If the name is defined in this context
                                                    return getattr(self, target).eval()
                                                elif self.father != None:   # If this is not the global context
                                                    return self.father.fetch(target)
                                                else:               
                                                    raise UnknownIdError(target)
                                        
                                        # A very simple interface: the string that the parser should parse is given as
                                        # a command line argument.
                                        if __name__ == '__main__':
                                            try:
                                                parser = Parser(
                                                        keywords=['define', 'if', 'then', 'else'],
                                                        operators=['+', '-', '*', '/', '<', '<=', '>', '>=', '=', '<>']
                                                        )
                                                parser.parse(input=' '.join(sys.argv[1:]))
                                                for result in parser.eval():
                                                    print ":", result
                                            except PLSyntaxError as e: exit()
                                            except: raise
                                        


                                        Voili voilou.

                                        PS : un petit code de test:
                                        $ ./parse.py "(define y (/ x 10)) (define x (- 0 -20)) (if 0 then (+ x (* y 2)) else (+ (* x y) 2))"
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          23 septembre 2009 à 7:41:10

                                          Merci pour le code, c'est pas inintéressant. En particulier, soit je n'ai pas fait attention les autres fois, soit tu es la première personne à avoir fait un vrai AST à la manière POO, avec la fonction "eval" morcelée dans chaque classe.

                                          Citation

                                          L'évaluation est paresseuse (enfin, si je me plante pas sur ce que c'est qu'une évaluation paresseuse). On peut donc écrire (define y x) (define x 3) (y) et paf, ça fait des chocapics renvoie 3.



                                          Ça ne serait pas une évaluation paresseuse, mais éventuellement une portée dynamique. En fait à lire le code j'ai l'impression que tu fais aussi l'évaluation paresseuse, vu que tu associes aux identifiants le bout d'AST correspondant, sans l'évaluer, et que tu évalues au fetch.

                                          Je ne suis pas tout à fait convaincu par ton modèle de gestion des environnements. L'utilisation d'une liste chaînée de contexte te permettra effectivement de gérer les contextes locaux, mais ta méthode "par blocs" me paraît franchement funky et je m'attends à ce qu'elle produise des comportements inattendus pour le programmeur qui l'utilise, voire des bugs : tu as un mélange de portée dynamique (la suite du code peut modifier le contexte du code actuel par effet de bord) et statique (le contexte d'un identifiant est capturé statiquement pendant le parsing) et ça risque de foirer quelque part.
                                          À ta place je ferais quelque chose tout-statique, comme c'est la norme dans les langages d'aujourd'hui ; tu peux aussi faire des essais de choses plus bizarres, mais c'est mieux quand ça reste cohérent dans l'ensemble.
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            23 septembre 2009 à 12:32:50

                                            Merci pour ta réponse très intéressante.

                                            Donc l'évaluation est paresseuse, puisque comme tu le dis, si on n'a jamais besoin de calculer x, le bout d'ast qui lui a été associé ne sera jamais évalué.

                                            Pour l'histoire des contextes, je suis pas sûr de trop comprendre... D'une part je sais pas ce que t'appelles la méthode "par blocs". En fait j'ai l'impression que justement je fais déjà tout en statique. D'autant plus que dans l'état actuel des choses, les seuls effets de bord qui existent sont les defines, et qu'ils ne sont pas autorisés dans une expression.
                                            On peut écrire
                                            (define x 1)
                                            (define x (if (= x 1) then 0 else 1))
                                            mais pas
                                            (define x 1)
                                            (if (= x 1) then (define x 0) else (define x 1))
                                            Donc le seul contexte qu'un define peut modifier, c'est le contexte global.

                                            Soi ça, sois j'ai pas compris de quoi tu parlais. o_O
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              23 septembre 2009 à 14:10:57

                                              Citation : bluestorm

                                              En particulier, soit je n'ai pas fait attention les autres fois, soit tu es la première personne à avoir fait un vrai AST à la manière POO, avec la fonction "eval" morcelée dans chaque classe.



                                              Euh, quasiment tout le monde s'est servi d'un "vrai" Ast (je suppose que tu faisais le lien avec les constructions implicites (en mémoire) d'arbres). Puis juste pour préciser un peu le "à la manière POO", il a deux manières de gérer les actions pour chaque type d'objet : par phase ou par classe. L'idée générale "par phase" est d'avoir une fonction qui traite l'ensemble des cas. L'autre méthode, c'est d'avoir une fonction par cas, intelligemment greffée à la définition du type de l'objet concerné elle-même. Les deux techniques possèdent leurs avantages et leurs défauts, mais ce n'est pas parce que ça fait plus "OO" que c'est mieux.
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                24 septembre 2009 à 12:14:04

                                                Bad_Wolf > effectivement seul le contexte global est concerné, mais au niveau global ça reste du binding dyamique : si tu écris une valeur, elle n'est pas fixée au moment de sa définition, ou de sa première utilisation, mais peut toujours évoluer dans le temps, implicitement, selon les bindings suivant qui ont lieu au toplevel :
                                                define x 3) (define y (= x 3)) (y) (define x 4) (y) renvoie : True : False.

                                                Au niveau sémantique, cela correspond à l'utilisation de variables modifiables utilisables à valeur d'erreur par défaut, pour lesquelles les "define" correspondent à des affectations. Ça a du sens, mais ce n'est pas celui qu'on attend en général, et intuitivement ce n'est pas très cohérent avec le comportement "statique" qu'aura sans doute la résolution des bindings locaux quand tu les auras implémentés.


                                                shareman > j'ai parlé de "vrai AST à la manière POO". Après une relecture rapide des codes du topic, j'ai peut-être manqué quelque chose mais il me semble qu'aucun code déjà proposé ne le fait. J'ai donc signalé que c'était intéressant, puisqu'on n'en avait pas encore d'exemple jusqu'à présent.
                                                Je n'ai pas dit que c'était "mieux", et effectivement un pattern Visitor pourrait être intéressant ici (puisque les opérations sont plus complexes que les données, il est bon de les regrouper), mais je pense que tu n'as juste pas très bien compris ce que je voulais dire.
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  24 septembre 2009 à 18:51:49

                                                  Ah ok, je vois ce que tu veux dire.
                                                  Ouais, effectivement, c'est un peu bizarre. Il vaudrait mieux que je stocke l'arbre en mémoire et que je lui colle des étiquettes. À chaque (define x blabla) j'enlève l'étiquette x de là où elle était, j'enregistre un nouvel arbre blabla et je lui colle une étiquette x.

                                                  En plus comme ça, le jour où x et y pointent sur le même ast, si on a besoin de x on évalue l'ast, et si après on a besoin de y, l'ast est déjà évalué. Pas besoin de se taper 150 fois l'évaluation du même arbre.
                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                    20 décembre 2009 à 22:16:39

                                                    Salut,

                                                    Je déterre le topic pour proposer mon interpréteur en C. Plus par défi que pour autre chose. Je n'ai utilisé aucun module externe, tout codé à la main, ce qui explique en partie la taille imposante du code.
                                                    J'espère que mon code ne comporte pas de fuite de mémoire, c'est pas évident à gérer en manipulant beaucoup de structure.

                                                    Sinon ma version gère la définition de variable, les modifications (utiliser set est équivalent à utiliser define dans mon langage), les suites d'expressions, les boucles, les conditions (avec opérateur and / or / not). J'ai aussi intégré une fonction print. Dans mon langage, tout est expression (y compris les conditions et les boucles). Pour ces dernières, la valeur de l'expression est la valeur de la dernière expression exécuter. On peut donc écrire des choses du genre : (+ 5 (if 0 1 2)) qui renverra 7. J'ai aussi différencié les opérateurs unaire et binaire moins. Pour l'opérateur unaire, il faut utiliser l'opérateur ~.
                                                    Je coderai surement plus tard la gestion des fonctions. Je n'ai aussi aucune gestion des erreurs pour le moment (à part un message que on tente d'utiliser une variable non définie)

                                                    Voici la bête :

                                                    Une gestion d'arbre binaire pour stocker des données comme les différentes variables. Une simple liste aurait pu suffir, mais c'était moins intéressant à coder et aussi moins efficace.

                                                    #ifndef DATA_TREE_H
                                                    #define DATA_TREE_H
                                                    
                                                    typedef struct data_tree data_tree;
                                                    struct data_tree
                                                    {
                                                      char *id;
                                                      int val;
                                                      data_tree * left;
                                                      data_tree * right;
                                                    };
                                                    
                                                    data_tree * dt_add (data_tree * dt, char *ident, int value);
                                                    int dt_search (data_tree * dt, char *ident, int *error);
                                                    void dt_delete (data_tree ** dt);
                                                    
                                                    #endif
                                                    


                                                    #include <stdlib.h>
                                                    #include <string.h>
                                                    #include "data-tree.h"
                                                    
                                                    #include "stdio.h"
                                                    
                                                    data_tree *
                                                    dt_add (data_tree * dt, char *ident, int value)
                                                    {
                                                      if (dt == NULL)
                                                        {
                                                          data_tree *d = malloc (sizeof (data_tree));
                                                          d->left = NULL;
                                                          d->right = NULL;
                                                          d->id = malloc (strlen(ident) * sizeof(char));
                                                          strcpy(d->id, ident);
                                                          d->val = value;
                                                          return d;
                                                        }
                                                      if (strcmp (dt->id, ident) == 0)
                                                        dt->val = value;
                                                      else if (strcmp (dt->id, ident) > 0)
                                                        dt = dt_add (dt->left, ident, value);
                                                      else
                                                        dt = dt_add (dt->right, ident, value);
                                                    
                                                      return dt;
                                                    }
                                                    
                                                    int
                                                    dt_search (data_tree * dt, char *ident, int *error)
                                                    {
                                                      *error = 1;
                                                      if (dt == NULL)
                                                        return -1;
                                                      
                                                      if (strcmp (dt->id, ident) == 0)
                                                        {
                                                          *error = 0;
                                                          return dt->val;
                                                        }
                                                      else if (strcmp (dt->id, ident) > 0)
                                                        {
                                                          int nb = dt_search (dt->left, ident, error);
                                                          if (*error = 0)
                                                    	return nb;
                                                        }
                                                      else
                                                        {
                                                          int nb = dt_search (dt->right, ident, error);
                                                          if (*error = 0)
                                                    	return nb;
                                                    
                                                          return 0;
                                                        }
                                                    }
                                                    
                                                    void
                                                    dt_delete (data_tree ** dt)
                                                    {
                                                      if (*dt == NULL)
                                                    	  return;
                                                      if ((*dt)->left != NULL)
                                                        dt_delete (&((*dt)->left));
                                                      if ((*dt)->right != NULL)
                                                        dt_delete (&((*dt)->right));
                                                      free((*dt)->id);
                                                      free (*dt);
                                                    }
                                                    


                                                    Le lexer, il comporte des défauts, par exemple, on peut pas mettre de chiffres dans le nom des variables. J'ai aussi codé une fonction pour voir la sortie du lexer.

                                                    #ifndef LEXER_H
                                                    #define LEXER_H
                                                    
                                                    #define MAX_DIGIT 40
                                                    #define MAX_ALPHA 40
                                                    
                                                    enum
                                                    { INT, KWD, IDENT };
                                                    
                                                    typedef struct token token;
                                                    struct token
                                                    {
                                                      token *next;
                                                      void *data;
                                                      int type;
                                                    };
                                                    
                                                    token *gen_lexer (char *str, char *kwd[], int nb_kwd);
                                                    void next_token (token ** t);
                                                    void print_all_token (token *t);
                                                    
                                                    #endif
                                                    


                                                    #include <stdlib.h>
                                                    #include <string.h>
                                                    #include <ctype.h>
                                                    #include "lexer.h"
                                                    
                                                    void
                                                    print_all_token (token * t)
                                                    {
                                                      if (t == NULL)
                                                        {
                                                          printf ("\n");
                                                          return;
                                                        }
                                                    
                                                      printf (" - ");
                                                      if (t->type == INT)
                                                        printf ("(INT : %d)", *((int *) t->data));
                                                      else if (t->type == KWD)
                                                        printf ("(KWD : %s)", (char *) t->data);
                                                      else
                                                        printf ("(IDENT : %s)", (char *) t->data);
                                                    
                                                      t = t->next;
                                                      print_all_token (t);
                                                    }
                                                    
                                                    int is_not_end (char t)
                                                    {
                                                    	return t != ' ' && t != '\n' && t != '\0';
                                                    }
                                                    
                                                    void
                                                    del_space (char **str)
                                                    {
                                                      while (**str == ' ' || **str == '\n' || **str == '\t')
                                                        (*str)++;
                                                    }
                                                    
                                                    token *
                                                    digit (char **str)
                                                    {
                                                      token *tok = malloc (sizeof (token));
                                                    
                                                      char tmp[MAX_DIGIT];
                                                      int i;
                                                      int *nb = malloc (sizeof (int));
                                                    
                                                      for (i = 0; i < MAX_DIGIT && isdigit (**str); i++, (*str)++)
                                                        tmp[i] = **str;
                                                    
                                                      *nb = atoi (tmp);
                                                      tok->data = nb;
                                                      tok->type = INT;
                                                    
                                                      return tok;
                                                    }
                                                    
                                                    token *
                                                    string (char **str, char *kwd[], int nb_kwd)
                                                    {
                                                      token *tok = malloc (sizeof (token));
                                                    
                                                      char tmp[MAX_ALPHA];
                                                      char *data = NULL;
                                                      int i;
                                                      int boo = 1;
                                                    
                                                      for (i = 0; i < MAX_ALPHA && is_not_end(**str); i++, (*str)++)
                                                      {
                                                       if (i > 0 && (isdigit(**str) || *(*str-1) == '(' || **str == ')'))
                                                    	   break;
                                                       else
                                                        	tmp[i] = **str;
                                                      }
                                                      tmp[i] = '\0';
                                                    
                                                      data = malloc (i * sizeof (char));
                                                      strcpy (data, tmp);
                                                      tok->data = data;
                                                    
                                                      for (i = 0; i < nb_kwd && boo; i++)
                                                        if (strcmp (data, kwd[i]) == 0)
                                                          boo = 0;
                                                    
                                                      if (boo == 1)
                                                        tok->type = IDENT;
                                                      else
                                                        tok->type = KWD;
                                                    
                                                      return tok;
                                                    }
                                                    
                                                    token *
                                                    gen_lexer (char *str, char *kwd[], int nb_kwd)
                                                    {
                                                      if (*str == '\0')
                                                        return NULL;
                                                    
                                                      token *tok = NULL;
                                                      del_space (&str);
                                                    
                                                      if (isdigit (*str))
                                                        tok = digit (&str);
                                                      else
                                                        tok = string (&str, kwd, nb_kwd);
                                                     
                                                      tok->next = gen_lexer (str, kwd, nb_kwd);
                                                      return tok;
                                                    }
                                                    
                                                    void
                                                    next_token (token ** t)
                                                    {
                                                      if (*t == NULL)
                                                        return;
                                                      token *next = (*t)->next;
                                                    
                                                      free ((*t)->data);
                                                      free (*t);
                                                      (*t) = next;
                                                    }
                                                    


                                                    Le parser, avec l'AST :

                                                    #ifndef PARSER_H
                                                    #define PARSER_H
                                                    
                                                    #include "lexer.h"
                                                    
                                                    enum e_expr
                                                    { Int, Ident, Bin_Op, Un_Op, Define, If, Begin, While, Print};
                                                    
                                                    enum e_bin_op
                                                    { Add, Sub, Mul, Div, Equ, Dif, Sup, Low, E_Sup, E_Low, And, Or };
                                                    
                                                    enum e_un_op
                                                    { Not, Opp };
                                                    
                                                    typedef struct s_bin_op s_bin_op;
                                                    struct s_bin_op
                                                    {
                                                      enum e_bin_op type_op;
                                                      void *expr1;
                                                      void *expr2;
                                                    };
                                                    
                                                    typedef struct s_un_op s_un_op;
                                                    struct s_un_op
                                                    {
                                                      enum e_un_op type_op;
                                                      void *expr;
                                                    };
                                                    
                                                    typedef struct s_define s_define;
                                                    struct s_define
                                                    {
                                                      char *id;
                                                      void *expr_var;
                                                    };
                                                    
                                                    typedef struct s_if s_if;
                                                    struct s_if
                                                    {
                                                      void *expr_bool;
                                                      void *expr_then;
                                                      void *expr_else;
                                                    };
                                                    
                                                    typedef struct s_while s_while;
                                                    struct s_while
                                                    {
                                                      void *expr_bool;
                                                      void *expr_then;
                                                    };
                                                    
                                                    typedef struct s_begin s_begin;
                                                    struct s_begin
                                                    {
                                                      void * seq;
                                                    };
                                                    
                                                    typedef struct s_print s_print;
                                                    struct s_print
                                                    {
                                                      void * expr;
                                                    };
                                                    
                                                    typedef union u_expr u_expr;
                                                    union u_expr
                                                    {
                                                      int nb;
                                                      char *id;
                                                      s_bin_op expr_bin_op;
                                                      s_un_op expr_un_op;
                                                      s_define expr_define;
                                                      s_if expr_if;
                                                      s_begin expr_begin;
                                                      s_while expr_while;
                                                      s_print expr_print;
                                                    };
                                                    
                                                    typedef struct s_expr s_expr;
                                                    struct s_expr
                                                    {
                                                      enum e_expr type_expr;
                                                      u_expr expr;
                                                    };
                                                    
                                                    typedef struct s_seq s_seq;
                                                    struct s_seq
                                                    {
                                                      s_expr * expr;
                                                      s_seq * next;
                                                    };
                                                     
                                                    s_expr *parse_expr (token ** tok);
                                                    s_seq *parse_seq (token ** tok);
                                                    
                                                    #endif
                                                    


                                                    #include <stdlib.h>
                                                    #include <string.h>
                                                    #include "parser.h"
                                                    #include "lexer.h"
                                                    
                                                    int
                                                    is_bin_op (char *op)
                                                    {
                                                      return strcmp (op, "+") == 0 ||
                                                        strcmp (op, "*") == 0 || strcmp (op, "/") == 0 || strcmp (op, "-") == 0 ||
                                                        strcmp (op, "=") == 0 || strcmp (op, ">=") == 0 || strcmp (op, "<=") == 0
                                                        || strcmp (op, "<") == 0 || strcmp (op, ">") == 0
                                                        || strcmp (op, "<>") == 0 || strcmp (op, "and") == 0
                                                        || strcmp (op, "or") == 0;
                                                    }
                                                    
                                                    int
                                                    is_un_op (char *op)
                                                    {
                                                      return strcmp (op, "!") == 0 || strcmp (op, "~") == 0;
                                                    }
                                                    
                                                    enum e_bin_op
                                                    char_to_bin_op (char *op)
                                                    {
                                                      if (strcmp (op, "*") == 0)
                                                        return Mul;
                                                      else if (strcmp (op, "/") == 0)
                                                        return Div;
                                                      else if (strcmp (op, "+") == 0)
                                                        return Add;
                                                      else if (strcmp (op, "-") == 0)
                                                        return Sub;
                                                      else if (strcmp (op, "=") == 0)
                                                        return Equ;
                                                      else if (strcmp (op, "<>") == 0)
                                                        return Dif;
                                                      else if (strcmp (op, ">") == 0)
                                                        return Sup;
                                                      else if (strcmp (op, "<") == 0)
                                                        return Low;
                                                      else if (strcmp (op, ">=") == 0)
                                                        return E_Sup;
                                                      else if (strcmp (op, "=<") == 0)
                                                        return E_Low;
                                                      else if (strcmp (op, "and") == 0)
                                                        return And;
                                                      else if (strcmp (op, "or") == 0)
                                                        return Or;
                                                    }
                                                    
                                                    enum e_un_op
                                                    char_to_un_op (char *op)
                                                    {
                                                      if (strcmp (op, "!") == 0)
                                                        return Not;
                                                      else if (strcmp (op, "~") == 0)
                                                        return Opp;
                                                    }
                                                    
                                                    
                                                    s_expr *
                                                    parse_expr (token ** tok)
                                                    {
                                                      if (*tok == NULL)
                                                      {
                                                       return NULL;
                                                      }
                                                    
                                                      s_expr *e = malloc (sizeof (s_expr));
                                                      if ((*tok)->type == INT)
                                                        {
                                                          e->type_expr = Int;
                                                          e->expr.nb = *((int *) (*tok)->data);
                                                          next_token (tok);
                                                        }
                                                      else if ((*tok)->type == IDENT)
                                                        {
                                                          e->type_expr = Ident;
                                                          char *ident = (char *) ((*tok)->data);
                                                          e->expr.id = malloc (strlen (ident) * sizeof (char));
                                                          strcpy (e->expr.id, ident);
                                                          next_token (tok);
                                                        }
                                                    
                                                      else if ((*tok)->type == KWD
                                                    	   && (strcmp ("define", (char *) ((*tok)->data)) == 0 ||
                                                    	       strcmp ("set", (char *) ((*tok)->data)) == 0))
                                                        {
                                                          e->type_expr = Define;
                                                    
                                                          next_token (tok);
                                                          char *ident = (char *) ((*tok)->data);
                                                          e->expr.expr_define.id = malloc (strlen (ident) * sizeof (char));
                                                          strcpy (e->expr.expr_define.id, ident);
                                                    
                                                          next_token (tok);
                                                          e->expr.expr_define.expr_var = parse_expr (tok);
                                                        }
                                                      else if ((*tok)->type == KWD && is_bin_op ((*tok)->data))
                                                        {
                                                          e->type_expr = Bin_Op;
                                                          e->expr.expr_bin_op.type_op = char_to_bin_op ((char *) ((*tok)->data));
                                                          next_token (tok);
                                                          e->expr.expr_bin_op.expr1 = parse_expr (tok);
                                                          e->expr.expr_bin_op.expr2 = parse_expr (tok);
                                                        }
                                                      else if ((*tok)->type == KWD && is_un_op ((*tok)->data))
                                                        {
                                                          e->type_expr = Un_Op;
                                                          e->expr.expr_un_op.type_op = char_to_un_op ((char *) ((*tok)->data));
                                                          next_token (tok);
                                                          e->expr.expr_un_op.expr = parse_expr (tok);
                                                        }
                                                      else if ((*tok)->type == KWD && strcmp ("(", (char *) ((*tok)->data)) == 0)
                                                        {
                                                          next_token (tok);
                                                          e = parse_expr (tok);
                                                          next_token (tok);
                                                        }
                                                      else if ((*tok)->type == KWD && strcmp ("if", (char *) ((*tok)->data)) == 0)
                                                        {
                                                          e->type_expr = If;
                                                          next_token (tok);
                                                          e->expr.expr_if.expr_bool = parse_expr (tok);
                                                          e->expr.expr_if.expr_then = parse_expr (tok);
                                                          e->expr.expr_if.expr_else = parse_expr (tok);
                                                        }
                                                      else if ((*tok)->type == KWD && strcmp ("while", (char *) ((*tok)->data)) == 0)
                                                        {
                                                          e->type_expr = While;
                                                          next_token (tok);
                                                          e->expr.expr_while.expr_bool = parse_expr (tok);
                                                          e->expr.expr_while.expr_then = parse_expr (tok);
                                                        }
                                                      else if ((*tok)->type == KWD && strcmp("begin", (char *) ((*tok)->data)) == 0)
                                                      {
                                                        e->type_expr = Begin;
                                                        next_token (tok);
                                                        e->expr.expr_begin.seq = parse_seq (tok);
                                                      }
                                                      else if ((*tok)->type == KWD && strcmp("print", (char *) ((*tok)->data)) == 0)
                                                      {
                                                        e->type_expr = Print;
                                                        next_token (tok);
                                                        e->expr.expr_print.expr = parse_expr (tok);
                                                      }
                                                      else
                                                      {
                                                        free(e);
                                                        e = NULL;
                                                      }
                                                      return e;
                                                    }
                                                    
                                                    s_seq * 
                                                    parse_seq (token ** tok)
                                                    {
                                                      s_seq *s = malloc(sizeof (s_seq));
                                                      s->expr = parse_expr (tok);
                                                      if (s->expr == NULL)
                                                      {
                                                        free (s);
                                                        s = NULL;
                                                      }
                                                      else
                                                        s->next = parse_seq (tok);
                                                      return s;
                                                    }
                                                    


                                                    Le code pour l'évaluation de l'arbre :
                                                    #include <stdlib.h>
                                                    #include <stdio.h>
                                                    #include "exec.h"
                                                    
                                                    void delete_seq (s_seq ** s);
                                                    
                                                    void
                                                    delete_expr (s_expr ** e)
                                                    {
                                                      if ((*e)->type_expr == Ident)
                                                        free ((*e)->expr.id);
                                                      else if ((*e)->type_expr == Define)
                                                      {
                                                        
                                                        free ((*e)->expr.expr_define.id);
                                                        delete_expr ((s_expr **) &((*e)->expr.expr_define.expr_var));
                                                      }
                                                      else if ((*e)->type_expr == Bin_Op)
                                                      {
                                                        delete_expr ((s_expr **) &((*e)->expr.expr_bin_op.expr1));
                                                        delete_expr ((s_expr **) &((*e)->expr.expr_bin_op.expr2));
                                                      }
                                                      else if ((*e)->type_expr == Un_Op)
                                                        delete_expr ((s_expr **) &((*e)->expr.expr_un_op.expr));
                                                      else if ((*e)->type_expr == If)
                                                      {
                                                        delete_expr ((s_expr **) &((*e)->expr.expr_if.expr_bool));
                                                        delete_expr ((s_expr **) &((*e)->expr.expr_if.expr_then));
                                                        delete_expr ((s_expr **) &((*e)->expr.expr_if.expr_else));
                                                      }
                                                      else if ((*e)->type_expr == While)
                                                      {
                                                        delete_expr ((s_expr **) &((*e)->expr.expr_while.expr_bool));
                                                        delete_expr ((s_expr **) &((*e)->expr.expr_while.expr_then));
                                                      }
                                                      else if ((*e)->type_expr == Print)
                                                        delete_expr ((s_expr **) &((*e)->expr.expr_print.expr));
                                                      else if ((*e)->type_expr == Begin)
                                                        delete_seq ((s_seq **) &((*e)->expr.expr_begin.seq));
                                                    
                                                      free (*e);
                                                    }
                                                    
                                                    void
                                                    delete_seq (s_seq ** s)
                                                    {
                                                      if (*s == NULL)
                                                       return;
                                                      delete_expr ((s_expr **) &((*s)->expr));
                                                      delete_seq ((s_seq **) &((*s)->next));
                                                      free(*s);
                                                    }
                                                    
                                                    int
                                                    exec_bin_op (enum e_bin_op op, int a, int b)
                                                    {
                                                      if (op == Add)
                                                        return a + b;
                                                      else if (op == Sub)
                                                        return a - b;
                                                      else if (op == Mul)
                                                        return a * b;
                                                      else if (op == Div)
                                                        return a / b;
                                                      else if (op == Equ)
                                                        return a == b;
                                                      else if (op == E_Sup)
                                                        return a >= b;
                                                      else if (op == E_Low)
                                                        return a <= b;
                                                      else if (op == Dif)
                                                        return a != b;
                                                      else if (op == Sup)
                                                        return a > b;
                                                      else if (op == Low)
                                                        return a < b;
                                                      else if (op == And)
                                                        return a && b;
                                                      else if (op == Or)
                                                        return a || b;
                                                    }
                                                    
                                                    int
                                                    exec_un_op (enum e_un_op op, int a)
                                                    {
                                                      if (op == Not)
                                                        return !a;
                                                      if (op == Opp)
                                                        return -a;
                                                    }
                                                    
                                                    int
                                                    exec_expr (s_expr * e, data_tree ** dt)
                                                    {
                                                      int nb;
                                                      if (e->type_expr == Int)
                                                        nb = e->expr.nb;
                                                      else if (e->type_expr == Bin_Op)
                                                        {
                                                          enum e_bin_op op = e->expr.expr_bin_op.type_op;
                                                          int nb1 = exec_expr ((s_expr *) e->expr.expr_bin_op.expr1, dt);
                                                          int nb2 = exec_expr ((s_expr *) e->expr.expr_bin_op.expr2, dt);
                                                    
                                                          nb = exec_bin_op (op, nb1, nb2);
                                                        }
                                                      else if (e->type_expr == Un_Op)
                                                      { 
                                                    	  enum e_un_op op = e->expr.expr_un_op.type_op;
                                                    	  int nb1 = exec_expr ((s_expr *) e->expr.expr_un_op.expr, dt);
                                                    
                                                    	  nb = exec_un_op (op, nb1);
                                                      }
                                                      else if (e->type_expr == Ident)
                                                        {
                                                          int error;
                                                          nb = dt_search (*dt, e->expr.id, &error);
                                                          if (error == 1)
                                                    	printf ("ERROR :- no var named %s\n", e->expr.id);
                                                        }
                                                      else if (e->type_expr == Define)
                                                        {
                                                          nb = exec_expr ((e->expr.expr_define.expr_var), dt);
                                                          *dt = dt_add (*dt, e->expr.expr_define.id, nb);
                                                        }
                                                      else if (e->type_expr == If)
                                                        {
                                                          if (exec_expr ((s_expr *) (e->expr.expr_if.expr_bool), dt))
                                                    	nb = exec_expr ((s_expr *) (e->expr.expr_if.expr_then), dt);
                                                          else
                                                    	nb = exec_expr ((s_expr *) (e->expr.expr_if.expr_else), dt);
                                                        }
                                                      else if (e->type_expr == Begin)
                                                        nb = exec_seq((s_seq *) e->expr.expr_begin.seq, dt);
                                                      else if (e->type_expr == While)
                                                        { 
                                                          nb = 0;
                                                          while (exec_expr (e->expr.expr_while.expr_bool, dt))
                                                    	nb = exec_expr (e->expr.expr_while.expr_then, dt);
                                                        }
                                                      else if (e->type_expr == Print)
                                                       {
                                                        nb = exec_expr((s_expr *) (e->expr.expr_print.expr), dt);
                                                        printf("%d\n", nb);
                                                       }
                                                      
                                                    
                                                      return nb;
                                                    }
                                                    
                                                    int 
                                                    exec_seq (s_seq * s, data_tree ** dt)
                                                    {
                                                      int nb = exec_expr(s->expr, dt);
                                                      if (s->next != NULL)
                                                      	nb = exec_seq (s->next, dt);
                                                      return nb;
                                                    }
                                                    


                                                    Et le main.c comportant la fonction de saisie qui n'est totalement pas sécurisée (mais pas le but ici) :D

                                                    #include <stdio.h>
                                                    #include <stdlib.h>
                                                    #include <string.h>
                                                    #include "lexer.h"
                                                    #include "parser.h"
                                                    #include "exec.h"
                                                    
                                                    #define MAX_INPUT 200
                                                    
                                                    void read (char * t)
                                                    {
                                                      int i;
                                                      int nb_pth = 1;
                                                      t[0] = fgetc(stdin); 
                                                    
                                                      for (i = 1; i < MAX_INPUT-1 && nb_pth > 0; i++)
                                                      {
                                                        t[i] = fgetc(stdin);	  
                                                        if (t[i] == '(')
                                                    	nb_pth++;
                                                        else if (t[i] == ')')
                                                    	nb_pth--;
                                                      }
                                                      fgetc(stdin); 
                                                      t[i] = '\0';  
                                                    }
                                                    
                                                    int
                                                    main (void)
                                                    {
                                                      char *kwd[] = { "+", "-", "/", "*", "~", "(", ")", "define", "set",  "if",
                                                    	  "and", "or", "=", ">=", "<=", "<", ">", "<>", "!", 
                                                    	  "print", "begin", "while"};
                                                      data_tree * dt = NULL;
                                                    
                                                      while (1)
                                                      {
                                                        char str[MAX_INPUT] = {0};
                                                        read(str);
                                                        if (strcmp(str, "(end)") == 0)
                                                    	    break;
                                                    
                                                        token *lex = gen_lexer (str, kwd, 22);
                                                       print_all_token (lex);
                                                        s_seq *seq = parse_seq (&lex);
                                                       printf (" - Result :- %d\n", exec_seq (seq, &dt));
                                                        delete_seq (&seq);
                                                      }
                                                    
                                                      dt_delete(&dt);
                                                      return 1;
                                                    }
                                                    


                                                    Petit exemple :
                                                    [ker@ker-laptop PtitLangage]$ ./test
                                                    (define boo (+ 7 ~3))
                                                     - Result :- 4
                                                    (while (> boo 1)       
                                                            (begin
                                                                    (print boo)
                                                                    (set boo (- boo 1))
                                                            )
                                                    )
                                                    4
                                                    3
                                                    2
                                                     - Result :- 1
                                                    (if (! (<> boo 0)) (set boo 1) (set boo 2))
                                                     - Result :- 2
                                                    
                                                    (end)


                                                    Pour quitter la boucle d'interaction j'ai défini le mot clef (end).
                                                    J'attends toutes les critiques que ce soit sur la fond ou la forme du code. Ça faisait un bail que je n'avais pas codé en C donc j'ai peut-être oublié de bonne habitude.

                                                    Tchao !
                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                    Anonyme
                                                      23 décembre 2009 à 18:24:09

                                                      Bonjour.
                                                      J'ai lu le premier post et ce langage de programation est terriblement alambiqué.
                                                      Pour une pauvre addition on n'écris pas 2+2 mais (+2 2).
                                                      Permettez moi de dire que ça n'a pas de sens, compliquer ce qui est simple rend impossible ce qui est compliqué...

                                                      Après je ne sais pas si ce langage est destiné à tout le monde ou à de rares initiés...

                                                      Cordialement
                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                        23 décembre 2009 à 18:38:46

                                                        Citation : bluestorm

                                                        Mais ici on s'intéresse aux concepts, et pas à la syntaxe ; pour éviter que vous perdiez trop de temps avec ça, on a choisi une syntaxe pour vous. Elle est très simple (sans doute la plus simple possible) et mettra tout le monde sur un pied d'égalité.

                                                        De plus, vous pourrez réutiliser pour l'analyse syntaxique les connaissances et le code accumulés par l'atelier Calculatrice(s), donc ça ne devrait pas être un problème. Ne vous focalisez pas sur l'emballage, c'est le goût qui nous intéresse !


                                                        Le langage n'est pas une fin en soi. Relis le premier post pour te convaincre de l'interêt du topic.
                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                        Anonyme
                                                          23 décembre 2009 à 18:50:09

                                                          ok ok alors la syntaxe choisie ici n'est pas formidable et le peu de lisibilité qu'elle offre m'a découragé de lire plus d'un message.

                                                          J'espère que vous trouverez ce que vous cherchez.

                                                          Cordialement
                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                          Anonyme
                                                            23 décembre 2009 à 18:53:15

                                                            o_O

                                                            Tu n'as pas du tout comprendre du but de ce topic.
                                                            • Partager sur Facebook
                                                            • Partager sur Twitter
                                                              24 décembre 2009 à 0:41:05

                                                              Citation : juliusII

                                                              J'ai lu le premier post et ce langage de programation est terriblement alambiqué.
                                                              Pour une pauvre addition on n'écris pas 2+2 mais (+2 2).
                                                              Permettez moi de dire que ça n'a pas de sens, compliquer ce qui est simple rend impossible ce qui est compliqué...

                                                              Après je ne sais pas si ce langage est destiné à tout le monde ou à de rares initiés...


                                                              "Compliquer". On ne peut pas dire que (+2 2) soit plus compliqué que 2+2. L'expression ne prend juste pas la forme habituellement utilisée, la forme naïve, c'est à dire la notation infixée. Ce n'est pas plus compliqué, c'est juste moins habituel. Et au contraire, en fonction de la méthode d'analyse syntaxique choisie (naïvement une analyse par descente récursive), l'implémentation de cette dernière est plus simple.

                                                              Le terme "compliquer" est donc faux, puisque ce qui nous intéresse ici est la construction de l'interpréteur et cette dernière est plus simple en prenant la syntaxe (+2 2). Pour t'en convaincre : la notation infixée peut être décrite avec une grammaire de la forme "expr -> expr opérateur terme", qui ne se prête à l'analyse par descente récursive qu'après modification (pour supprimer la récursivité à gauche). Au contraire, la notation préfixée est de la forme "expr -> opérateur term ..". La partie de l'analyseur syntaxique gérant cette production est enfantine à coder (si besoin d'un exemple pour se lancer, ici par exemple).

                                                              Ensuite, je ne vois pas pourquoi tu dis "ce langage est destiné". Ce langage n'est pas ici sur ce topic pour être utilisé, ou pour être appris (même si ça ne serait pas un soucis). Son lexique, sa syntaxe et sa sémantique servent juste de référence pour la construction d'un petit interpréteur (ou partie frontale de compilateur, tiens). C'est purement pédagogique.
                                                              • Partager sur Facebook
                                                              • Partager sur Twitter

                                                              [Atelier] P'tit langage

                                                              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                              × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                              • Editeur
                                                              • Markdown