|
Publicité ' | ||||||||||||||||||||||||
|
|
#1 | ||||
![]() ![]() Inscription : juin 2006 Messages : 6 935 ![]() |
Bonjour,
Pour le deuxième défi, l'équipe de developpez.com vous propose un challenge un peu plus délicat que le précédent. Challenge : Le but est de réaliser un interpréteur d'expression mathématiques. Il y aura en entrée du programme (ou de la fonction) soit une chaine de caractères, soit un fichier. En sortie, il y aura le résultat de l'évaluation de l'expression arithmétique. Si une erreur de syntaxe est détectée, un message d'erreur pourra s'afficher. La grammaire (que nous n'allons pas décrire) sera celle des expressions arithmétiques parenthésées avec les 4 opérateurs +, -, * et /, et pouvant comprendre les fonctions : sin et cos. Les nombres pourront être des entiers (0, 1, -1), ou des flottants (0.01, -9.78) que vous pourrez limiter à deux décimales après la virgule (et séparé par un .) Par exemple, votre programme pourra évaluer des expressions comme : Code :
Et éventuellement émettre un message de division par 0 dans le cas d'une expression comme : Modification : Le programme peut fonctionner ou donner une erreur de syntaxe dans ces cas comme : Les règles Il n'y a pas de règle particulière (évidemment, il faut que la solution proposée fonctionne). Vous pouvez proposer des solutions aussi bien dans des langages fonctionnels (caml, haskell, scheme, lisp...) qu'impératif. Le public pourra ainsi juger du code suivant divers critères :
Attention, nous interdisons toutefois l'utilisation d'un évaluateur d'expressions mathématiques "tout prêt", le but étant quand même de montrer à quoi ressemble un "micro-interprète". Ainsi, nous refuserons des propositions du style suivant : Code perl :
Par ailleurs, nous apprécierions quelques remarques sur le fonctionnement de votre programme, comme le nombre de passes nécessaires pour traiter un fichier, éventuellement les complexités spatiales et temporelles, etc. Le public pourra également juger les différences entre une solution fonctionnelle et une solution impérative. Il lui sera ainsi plus facile de voir, pour un même problème, les différences entre divers paradigmes. A vos claviers de votre participation.
__________________
Je ne répondrai à aucune question technique en privé |
||||
|
|
00
|
|
|
#2 | ||
|
Expert Confirmé Sénior
![]() ![]() ![]() Inscription : novembre 2005 Messages : 4 970 ![]() |
Rien que pour m'amuser:
Code c :
Note que j'accepte: avec la signification evidente.
__________________
Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça. |
||
|
|
00
|
|
|
#3 |
![]() ![]() Inscription : juin 2006 Messages : 6 935 ![]() |
Rapide
Je pensais que les solutions en C ou en C++ auraient tendance à utiliser des outils comme lex/yacc.
__________________
Je ne répondrai à aucune question technique en privé |
|
|
00
|
|
|
#4 | ||
|
Expert Confirmé Sénior
![]() ![]() ![]() Inscription : novembre 2005 Messages : 4 970 ![]() |
Citation:
J'ai juste eu a ajouter sin/cos. Citation:
__________________
Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça. |
||
|
|
00
|
|
|
#5 | |||||||||
|
Membre Expert
![]() Inscription : mars 2002 Messages : 962 ![]() |
Code lexer.fsl :
Code parser.fsy :
Code eval.fs :
Citation:
Dans mon code, il suffit d'ajouter une ligne pour gérer une nouvelle fonction ou un nouvel opérateur, par exemple : "| "abs" { FCT abs }". Et pareil, les expressions suivantes sont acceptées : Code :
|
|||||||||
|
|
00
|
|
|
#6 | ||||||||
![]() ![]() ![]() Nicolas ValléeIngénieur d'études Inscription : décembre 2005 Messages : 9 961 ![]() |
j'avais une version ocaml avec lex et yacc, puis interprétation (donc 3 passes)... mais LLB vient d'en donner la solution optimisée "calcul en 2 passes"
Code lexer.mll :
Code parser.mly :
Code main.ml :
Code ast.mli :
là, on peut vraiment parler d'overkill... car il s'agit d'un interprète pour une machine virtuelle "quelconque" je reviendrais
|
||||||||
|
|
00
|
|
|
#7 |
|
Expert Confirmé Sénior
![]() Inscription : janvier 2007 Messages : 9 569 ![]() |
questions :
__________________
"Un homme sage ne croit que la moitié de ce qu’il lit. Plus sage encore, il sait laquelle". Consultant indépendant. Architecture systèmes complexes. Programmation grosses applications critiques. Ergonomie. C, Fortran, XWindow/Motif, Java Je ne réponds pas aux MP techniques |
|
|
00
|
|
|
#8 | |
![]() ![]() ![]() Nicolas ValléeIngénieur d'études Inscription : décembre 2005 Messages : 9 961 ![]() |
Citation:
2 chiffres après la virgule... pour les erreurs d'arrondis (on ne sait jamais... certains voudront peut-être implanter un calcul de cos récursif avec une précision via un seuil pas de vecteurs... exact pas de problèmes d'unités puisque c'est des maths (mais en maths 1+cos n'existe pas... attention )
|
|
|
|
00
|
|
|
#9 | |||
|
Expert Confirmé Sénior
![]() ![]() ![]() Inscription : novembre 2005 Messages : 4 970 ![]() |
Citation:
Dans le meme esprit, le projet GCC a reecrit ses parseurs bisons pour le C et pour le C++ de bison a l'utilisation de parseurs ecrits a la main. Et B. Stroustrup a declare qu'une de ses plus grosses erreurs avait ete de se laisser convaincre d'utiliser yacc lors d'une reecriture de CFront. Les generateurs sont utiles tout compte fait sur une classe de langage de complexite moyenne. Les frontieres exactes vont dependre de la familiarite avec les outils et les techniques, de la volatilite de la grammaire et de la capacite a contraindre celle-ci a ce qui passe bien sur le generateur utilise. Citation:
__________________
Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça. |
|||
|
|
00
|
|
|
#10 | |
![]() ![]() Inscription : juin 2006 Messages : 6 935 ![]() |
Citation:
D'ailleurs au passage, il y a le même problème pour les entiers normaux,du style : 100000000000000000000000000000000 qui risque de poser problème
__________________
Je ne répondrai à aucune question technique en privé |
|
|
|
00
|
|
|
#11 |
![]() ![]() Inscription : juin 2006 Messages : 6 935 ![]() |
Vu que presque tout le monde a accepté les expressions du type : 1--1 ou cos 1. J'ai laissé le choix à la personne d'évaluer ces expressions ou de les considérer comme des erreurs syntaxiques.
__________________
Je ne répondrai à aucune question technique en privé |
|
|
00
|
|
|
#12 | |
|
Membre Expert
![]() ![]() Inscription : septembre 2006 Messages : 1 036 ![]() |
Citation:
|
|
|
|
00
|
|
|
#13 | |
![]() ![]() ![]() Nicolas ValléeIngénieur d'études Inscription : décembre 2005 Messages : 9 961 ![]() |
Citation:
lex -> 1 passe yacc -> 1 passe interprète -> 1 passe au passage, avec le packrat, on fait l'équivalent de lex+yacc en une passe seulement... modulo une compensation d'un cout temporel en cout mémoire |
|
|
|
00
|
|
|
#14 |
|
Membre Expert
![]() ![]() Inscription : septembre 2006 Messages : 1 036 ![]() |
Ca fait deux passes... à chaque fois que yacc a besoin d'un léxème, yacc appelle la fonction qui lui donne le prochain léxème : c'est pas comme si on construisait la liste de tous les léxèmes, puis que yacc parsait le tout pour construire l'arbre de syntaxe... et pas besoin de packrat pour faire lex + yacc en une seule passe : c'est déjà comme ça.
|
|
|
00
|
|
|
#15 | |
![]() ![]() ![]() Nicolas ValléeIngénieur d'études Inscription : décembre 2005 Messages : 9 961 ![]() |
Citation:
ce n'est pas parce qu'on peut faire les deux passes presque simultanément, qu'il ne s'agit pas de deux passes... donc je maintiens ce que j'ai dit par ailleurs, le packrat apporte réellement un gain de vitesse sur le parsage, mais au prix d'un coût "transféré" sur la complexité spatiale |
|
|
|
00
|
|
|
#16 | ||
|
Membre Expert
![]() Inscription : avril 2007 Messages : 829 ![]() |
Une version différente, qui utilise (détourne) les facilités de créations de grammaires de Camlp4 :
Code :
$ ocamlc -c -I +camlp4 -pp camlp4of maths.ml Exemple : $ camlp4o ./maths.cmo -str '1 + 2 * cos sin 0' 3. |
||
|
|
00
|
|
|
#17 | ||||
|
Expert Confirmé Sénior
![]() ![]() |
Avec Parsec en Haskell, Parsec.Expr est particulièrement utile dans ce cas, faisant tout le travail de gestion des priorités pour nous, les seuls points un peu plus délicat sont la gestion des espaces et du (-) préfixe.
En deux modules (soyons propre Code :
Code :
Jedaï |
||||
|
|
00
|
|
|
#18 | ||
|
Membre Expert
![]() Inscription : mars 2002 Messages : 962 ![]() |
Et voici la version avec FParsec, l'adaptation de Parsec pour F#. La logique est la même, on utilise des monades, là aussi. Une différence quand même : Parsec.Expr n'est pas implémenté dans FParsec.
Code F# :
Et par rapport à la version fslex/fsyacc, on gagne des messages d'erreurs plus explicites. Edit : Merci Alex. |
||
|
|
00
|
|
|
#19 | |||
|
Invité(e)
![]() Messages : n/a ![]() |
Citation:
|
|||
00
|
|
|
#20 | ||
|
Futur Membre du Club
![]() Inscription : février 2008 Messages : 75 ![]() |
Bonjour
Ça y est, mon interpréteur est fin prêt ! Il a été fait à la base en Caml Light mais je le donne ici en syntaxe OCaml. Je ne me sers de plus d'aucun module externe genre ocamllex et ocamlyacc, c'est le programme qui fait tout. Comme la plupart des autres programmes, j'accepte les expressions du type 1--1, ou encore ---1-+cossin--sin-cossin-(sin1-sin-1) ![]() Je ne me suis pas fixé de limites pour les flottants, donc il peut y avoir des petites erreurs d'arrondi. Ensuite (mais j'ai pas fait exprès Voilà, j'ai essayé de commenter pas mal le code, mais si vous avez des questions , des remarques, ou si vous trouvez une erreur, n'hésitez pas Code :
Fractal |
||
|
|
00
|
Copyright © 2000-2013 - www.developpez.com