diff options
-rw-r--r-- | tp2-files/Calculatrice-final.jj | 34 | ||||
-rw-r--r-- | tp2.tex | 170 |
2 files changed, 118 insertions, 86 deletions
diff --git a/tp2-files/Calculatrice-final.jj b/tp2-files/Calculatrice-final.jj index 9a03f39..889659c 100644 --- a/tp2-files/Calculatrice-final.jj +++ b/tp2-files/Calculatrice-final.jj @@ -37,47 +37,47 @@ void boucle(): } // Expression (axiome de la grammaire de la calculatrice) -// expression → terme ( "+" terme | "-" terme )* +// expression → term ( "+" term | "-" term )* double expression(): { double a,b; } { - a=terme() + a=term() ( - "+" b=terme() { a += b; } - | "-" b=terme() { a -= b; } + "+" b=term() { a += b; } + | "-" b=term() { a -= b; } )* { return a; } } // Terme d'une somme ou différence -// terme → unaire ( "*" unaire | "/" unaire )* -double terme(): +// term → factor ( "*" factor | "/" factor )* +double term(): { double a,b; } { - a=unaire() + a=factor() ( - "*" b=unaire() { a *= b; } - | "/" b=unaire() { a /= b; } + "*" b=factor() { a *= b; } + | "/" b=factor() { a /= b; } )* { return a; } } // Gestion du "+" et "−" unaires -// unaire → puissance | "+" puissance | "-" puissance -double unaire(): +// factor → power | "+" power | "-" power +double factor(): { double a; } { - a=puissance() { return a; } -| "+" a=puissance() { return a; } -| "-" a=puissance() { return -a; } + a=power() { return a; } +| "+" a=power() { return a; } +| "-" a=power() { return -a; } } // Opération puissance (associative à droite) -// puissance → element ( "^" unaire )? -double puissance(): +// power → element ( "^" factor )? +double power(): { double a,b; } { a=element() ( - "^" b=unaire() { a = Math.pow(a,b); } + "^" b=factor() { a = Math.pow(a,b); } )? { return a; } } @@ -138,11 +138,23 @@ Initialement, la grammaire de la calculatrice définie dans ){*}\\ \mathit{element} & \rightarrow \mathit{Number}\\ \mathit{Number} & \rightarrow -[\ldquote\mathtt{0}\rdquote\endash\ldquote\mathtt{9}\rdquote]{+} \; -(\ldquote\mathtt{.}\rdquote \; -[\ldquote\mathtt{0}\rdquote\endash\ldquote\mathtt{9}\rdquote]*)?\\ +[\ldquote\texttt{0}\rdquote\endash\ldquote\texttt{9}\rdquote]{+} \; +(\ldquote\texttt{.}\rdquote \; +[\ldquote\texttt{0}\rdquote\endash\ldquote\texttt{9}\rdquote]*)?\\ \end{aligned} \] +Il s'agit d'une grammaire « étendue » au sens où le membre de droite +des règles de production autorise l'utilisation des métacaractères +« ${*}$ », « ${+}$ » et « ${?}$ » des expressions rationnelles — pour +désigner respectivement un nombre quelconque de répétitions, au moins +une répétition, ou un groupe facultatif. En principe, on pourrait +éliminer l'utilisation de ces métacaractères en s'inspirant de la +manière dont on démontre que tout langage rationnel est algébrique +(par exemple $X\rightarrow Y{*}$ peut être remplacé par $X\rightarrow +\varepsilon\,|\,YX$), mais l'analyseur LL de JavaCC ne sera pas +forcément capable de gérer la grammaire ainsi transformée, donc il est +préférable d'utiliser les métacaractères lorsque c'est possible. + Le code important se situe dans \texttt{Calculatrice.jj} au niveau de la ligne \texttt{double expression():} ; le bloc qui suit définit la production $\mathit{expression}$ ainsi que le code à exécuter quand @@ -154,11 +166,11 @@ elle est rencontrée. la calculatrice ? Pourquoi ? Modifier la grammaire pour avoir une priorité correcte des opérations -(\texttt{*} et \texttt{/} doivent être prioritaires sur -\texttt{+} et \texttt{-}, et en particulier \texttt{3+4*5} doit -renvoyer $23$). Pour cela, on peut par exemple introduire un nouveau -nonterminal $\mathit{terme}$ représentant un terme d'une somme ou -différence, et qui est lui-même formé de produits ou quotients. +(\texttt{*} et \texttt{/} doivent être prioritaires sur \texttt{+} et +\texttt{-}, et en particulier \texttt{3+4*5} doit +renvoyer \texttt{23.0}). Pour cela, on peut par exemple introduire un +nouveau nonterminal $\mathit{term}$ représentant un terme d'une somme +ou différence, et qui est lui-même formé de produits ou quotients. Tester la calculatrice ainsi modifiée. \begin{corrige} @@ -173,17 +185,17 @@ Pour corriger ce problème, on va modifier la grammaire de la manière suivante : \[ \begin{aligned} -\mathit{expression} & \rightarrow \mathit{terme} \; -( \ldquote\hbox{\texttt{+}}\rdquote \mathit{terme} -\,|\, \ldquote\hbox{\texttt{-}}\rdquote \mathit{terme}){*}\\ -\mathit{terme} & \rightarrow \mathit{element} \; +\mathit{expression} & \rightarrow \mathit{term} \; +( \ldquote\hbox{\texttt{+}}\rdquote \mathit{term} +\,|\, \ldquote\hbox{\texttt{-}}\rdquote \mathit{term}){*}\\ +\mathit{term} & \rightarrow \mathit{element} \; (\ldquote\hbox{\texttt{*}}\rdquote \mathit{element} \,|\, \ldquote\hbox{\texttt{/}}\rdquote \mathit{element} ){*}\\ \end{aligned} \] (le reste est inchangé) : ceci forcera l'arbre d'analyse de -\texttt{3+4*5} à comporter deux $\mathit{terme}$, en l'occurrence +\texttt{3+4*5} à comporter deux $\mathit{term}$, en l'occurrence \texttt{3} et \texttt{4*5}, qui s'évalueront dans les bonnes valeurs. Voici à quoi peut ressembler le code JavaCC modifié pour refléter la @@ -192,14 +204,14 @@ grammaire en question : double expression(): { double a,b; } { - a=terme() + a=term() ( - "+" b=terme() { a += b; } - | "-" b=terme() { a -= b; } + "+" b=term() { a += b; } + | "-" b=term() { a -= b; } )* { return a; } } -double terme(): +double term(): { double a,b; } { a=element() @@ -217,7 +229,7 @@ quand on lui demande de calculer \texttt{3+4*5}. (2) La calculatrice ne gère pas les parenthèses : ajouter cette fonctionnalité et tester. Par exemple, \texttt{(3+5)/(2*2)} doit -revoyer $2$. Pour cela, on pourra ajouter une nouvelle production +renvoyer \texttt{2.0}. Pour cela, on pourra ajouter une nouvelle production pour $\mathit{element}$ correspondant à une $\mathit{expression}$ entourée de parenthèses. @@ -247,40 +259,40 @@ contente d'ajouter une deuxième production). (3) La calculatrice ne gère pas le $-$ unaire (pour indiquer l'opposé d'un nombre) : ajouter cette fonctionnalité et tester. Par exemple, -\texttt{-3*-6} doit renvoyer $18$, et \texttt{-1-2} doit -renvoyer $-3$. Vérifier que le moins unaire marche aussi devant les -parenthèses (\texttt{-(2+3)} doit renvoyer $-5$). On pourra aussi -ajouter le $+$ unaire (qui ne change pas le nombre). Pour cela, on -pourra introduire un nouveau nonterminal $\mathit{unaire}$ -représentant un élément éventuellement précédé d'un $-$ (ou d'un $+$) -unaire. +\texttt{-3*-6} doit renvoyer \texttt{18.0}, et \texttt{-1-2} doit +renvoyer \texttt{-3.0}. On veut que le moins unaire marche aussi +devant les parenthèses : par exemple, \texttt{-(2+3)} doit +renvoyer \texttt{-5.0}. On pourra aussi ajouter le $+$ unaire (qui ne +change pas le nombre). Pour cela, on pourra introduire un nouveau +nonterminal $\mathit{factor}$ représentant un élément éventuellement +précédé d'un $-$ (ou d'un $+$) unaire. \begin{corrige} On modifie la grammaire comme suit : \[ \begin{aligned} -\mathit{terme} & \rightarrow \mathit{unaire} \; -(\ldquote\hbox{\texttt{*}}\rdquote \mathit{unaire} -\,|\, \ldquote\hbox{\texttt{/}}\rdquote \mathit{unaire} +\mathit{term} & \rightarrow \mathit{factor} \; +(\ldquote\hbox{\texttt{*}}\rdquote \mathit{factor} +\,|\, \ldquote\hbox{\texttt{/}}\rdquote \mathit{factor} ){*}\\ -\mathit{unaire} & \rightarrow \mathit{element} \; +\mathit{factor} & \rightarrow \mathit{element} \; \,|\, \ldquote\hbox{\texttt{+}}\rdquote \mathit{element} \,|\, \ldquote\hbox{\texttt{-}}\rdquote \mathit{element}\\ \end{aligned} \] et le code JavaCC correspondant pourrait être : \begin{verbatim} -double terme(): +double term(): { double a,b; } { - a=unaire() + a=factor() ( - "*" b=unaire() { a *= b; } - | "/" b=unaire() { a /= b; } + "*" b=factor() { a *= b; } + | "/" b=factor() { a /= b; } )* { return a; } } -double unaire(): +double factor(): { double a; } { a=element() { return a; } @@ -290,7 +302,7 @@ double unaire(): \end{verbatim} (Plusieurs variations sont possibles : par exemple, si on fait suivre -le \texttt{-} unaire d'un $\mathit{unaire}$ au lieu d'un +le \texttt{-} unaire d'un $\mathit{factor}$ au lieu d'un $\mathit{element}$, cela permet d'autoriser \texttt{-{}-3} comme façon d'écrire \texttt{+3}.) \end{corrige} @@ -306,78 +318,98 @@ veut qu'elle soit associative \emph{à droite}, c'est-à-dire par exemple que \texttt{2\char"5E\relax 3\char"5E\relax 2} doit calculer $2^{3^2} = 2^9 = 512$. +On pourra pour cela introduire un nouveau nonterminal $\mathit{power}$ +représentant un $\mathit{element}$ suivi facultativement d'un +\texttt{\char"5E} et d'un nouveau $\mathit{power}$. + La méthode Java permettant de calculer $a^b$ s'écrit \texttt{Math.pow(a,b)}. Tester notamment les calculs suivants : $\hbox{\texttt{2\char"5E\relax - 3\char"5E\relax 2}} \rightsquigarrow 512$ ; -$\hbox{\texttt{-1\char"5E\relax 2}} \rightsquigarrow -1$ ; -$\hbox{\texttt{(-1)\char"5E\relax 2}} \rightsquigarrow 1$ ; -$\hbox{\texttt{2\char"5E\relax -1}} \rightsquigarrow 0.5$ ; -$\hbox{\texttt{2*3\char"5E\relax 2*3}} \rightsquigarrow 54$. + 3\char"5E\relax 2}} \rightsquigarrow \texttt{512.0}$ ; +$\hbox{\texttt{-1\char"5E\relax 2}} \rightsquigarrow \texttt{-1.0}$ ; +$\hbox{\texttt{(-1)\char"5E\relax 2}} \rightsquigarrow \texttt{1.0}$ ; +$\hbox{\texttt{(2+3)\char"5E\relax 2}} \rightsquigarrow \texttt{25.0}$ ; +$\hbox{\texttt{2\char"5E\relax -1}} \rightsquigarrow \texttt{0.5}$ ; +$\hbox{\texttt{2*3\char"5E\relax 2*3}} \rightsquigarrow \texttt{54.0}$. \begin{corrige} Pour obtenir l'associativité \emph{à droite}, on va définir un -nonterminal $\mathit{puissance}$ pour lequel on va définir une -production faisant qu'une $\mathit{puissance}$ peut s'analyser comme +nonterminal $\mathit{power}$ pour lequel on va définir une +production faisant qu'une $\mathit{power}$ peut s'analyser comme un $\mathit{element}$ suivi d'un ``$\texttt{\char"5E}$'' suivi -facultativement d'une nouvelle $\mathit{puissance}$, c'est-à-dire +facultativement d'une nouvelle $\mathit{power}$, c'est-à-dire qu'on modifie la grammaire ainsi : \[ \begin{aligned} -\mathit{unaire} & \rightarrow \mathit{puissance} \; -\,|\, \ldquote\hbox{\texttt{+}}\rdquote \mathit{puissance} -\,|\, \ldquote\hbox{\texttt{-}}\rdquote \mathit{puissance}\\ -\mathit{puissance} & \rightarrow \mathit{element} -( \ldquote\hbox{\texttt{\char"5E}}\rdquote \mathit{unaire} +\mathit{factor} & \rightarrow \mathit{power} \; +\,|\, \ldquote\hbox{\texttt{+}}\rdquote \mathit{power} +\,|\, \ldquote\hbox{\texttt{-}}\rdquote \mathit{power}\\ +\mathit{power} & \rightarrow \mathit{element} +( \ldquote\hbox{\texttt{\char"5E}}\rdquote \mathit{factor} ){?}\\ \end{aligned} \] avec le code JavaCC suivant : \begin{verbatim} -double unaire(): +double factor(): { double a; } { - a=puissance() { return a; } -| "+" a=puissance() { return a; } -| "-" a=puissance() { return -a; } + a=power() { return a; } +| "+" a=power() { return a; } +| "-" a=power() { return -a; } } -double puissance(): +double power(): { double a,b; } { a=element() ( - "^" b=unaire() { a = Math.pow(a,b); } + "^" b=factor() { a = Math.pow(a,b); } )? { return a; } } \end{verbatim} +Remarquez l'utilisation du métacaractère « $?$ » pour marquer le +caractère facultatif de la partie +$\ldquote\hbox{\texttt{\char"5E}}\rdquote \mathit{factor}$ ; on aurait +pu tenter d'écrire la règle sous la forme $\mathit{power} \rightarrow +\mathit{element} \;|\; \mathit{element} +\ldquote\hbox{\texttt{\char"5E}}\rdquote \mathit{factor}$ pour un code +JavaCC qui ressemblerait à « \texttt{\{ a=element() \{ return a; \} + |\penalty-100\hskip.5emplus1em a=element() "\char"5E" b=factor() + \{ return Math.pow(a,b); \} \}} », mais ce code fait échouer +JavaCC car au moment où il reconnaît le nonterminal +$\mathit{element}$, l'analyseur ne peut pas encore savoir dans quelle +branche de l'alternative il sera. + +\smallbreak + Voici la grammaire finale : \[ \begin{aligned} -\mathit{expression} & \rightarrow \mathit{terme} \; -( \ldquote\hbox{\texttt{+}}\rdquote \mathit{terme} -\,|\, \ldquote\hbox{\texttt{-}}\rdquote \mathit{terme}){*}\\ -\mathit{terme} & \rightarrow \mathit{unaire} \; -(\ldquote\hbox{\texttt{*}}\rdquote \mathit{unaire} -\,|\, \ldquote\hbox{\texttt{/}}\rdquote \mathit{unaire} +\mathit{expression} & \rightarrow \mathit{term} \; +( \ldquote\hbox{\texttt{+}}\rdquote \mathit{term} +\,|\, \ldquote\hbox{\texttt{-}}\rdquote \mathit{term}){*}\\ +\mathit{term} & \rightarrow \mathit{factor} \; +(\ldquote\hbox{\texttt{*}}\rdquote \mathit{factor} +\,|\, \ldquote\hbox{\texttt{/}}\rdquote \mathit{factor} ){*}\\ -\mathit{unaire} & \rightarrow \mathit{puissance} \; -\,|\, \ldquote\hbox{\texttt{+}}\rdquote \mathit{puissance} -\,|\, \ldquote\hbox{\texttt{-}}\rdquote \mathit{puissance}\\ -\mathit{puissance} & \rightarrow \mathit{element} -( \ldquote\hbox{\texttt{\char"5E}}\rdquote \mathit{unaire} +\mathit{factor} & \rightarrow \mathit{power} \; +\,|\, \ldquote\hbox{\texttt{+}}\rdquote \mathit{power} +\,|\, \ldquote\hbox{\texttt{-}}\rdquote \mathit{power}\\ +\mathit{power} & \rightarrow \mathit{element} +( \ldquote\hbox{\texttt{\char"5E}}\rdquote \mathit{factor} ){?}\\ \mathit{element} &\rightarrow \mathit{Number} \,|\, \ldquote\hbox{\texttt{(}}\rdquote \mathit{expression} \ldquote\hbox{\texttt{)}}\rdquote\\ \mathit{Number} & \rightarrow -[\ldquote\mathtt{0}\rdquote\endash\ldquote\mathtt{9}\rdquote]{+} \; -(\ldquote\mathtt{.}\rdquote \; -[\ldquote\mathtt{0}\rdquote\endash\ldquote\mathtt{9}\rdquote]*)?\\ +[\ldquote\texttt{0}\rdquote\endash\ldquote\texttt{9}\rdquote]{+} \; +(\ldquote\texttt{.}\rdquote \; +[\ldquote\texttt{0}\rdquote\endash\ldquote\texttt{9}\rdquote]*)?\\ \end{aligned} \] -Le code JavaCC correspondant peut se trouve à l'adresse +Le code JavaCC correspondant peut se trouver à l'adresse \url{http://perso.enst.fr/~madore/inf105/Calculatrice-final.jj} \end{corrige} |