Compilation : Corrections et éclaircissements (partie 1)
Nous avons apporté quelques corrections à la donnée de la partie 1 du projet. Ce document énumère ces corrections et fournit également quelques éclaircissements supplémentaires.
Dans la version originale de la donnée, nous utilisions les termes syntaxe lexicale et syntaxe pour désigner les deux grammaires décrites dans ce document. Le second terme peut prêter à confusion car il peut aussi bien désigner la première grammaire que la seconde. Nous avons donc remplacé ces deux termes par les termes grammaire lexicale et grammaire syntaxique respectivement.
token
La définitions de token
dans la grammaire lexicale
a été légérement augmentée afin de correspondre à la classe Tokens
que nous vous avons
fournie.
Dans la version originale de la donnée, on indiquait que pour traiter la fin du fichier source, on modifiait la grammaire syntaxique comme suit :
Program = { Declaration ";" } Expression EOF. EOF = EOF_CH
Ceci est incorrect car cela signifierait que EOF
est
un non-terminal de la grammaire syntaxique, ce qui est faux. Voilà
comment il faut modifier la grammaire :
Program = { Declaration ";" } Expression EOF_CH.
La grammaire syntaxique contient ainsi un terminal
EOF_CH
auquel correspond la classe de lexèmes
EOF
définie dans Tokens
. On dit que
EOF_CH
définit un pseudo-lexème car, dans la grammaire
lexicale, EOF_CH
apparaît dans la définition de
input
et non comme une alternative de token
comme c'est le cas pour tout vrai lexème.
nextToken
et readToken
Dans la classe Scanner
que
nous vous avons fournie, une partie du travail de la méthode
nextToken
est délégué à la méthode
readToken
. Cette dernière étant privée (donc inaccessible
depuis n'importe quelle autre classe), vous pouvez en faire ce que
vous voulez et par exemple décider de la supprimer et d'implanter
toute l'analyse dans nextToken
.
Plus généralement, vous pouvez toujours supprimer ou modifier des méthodes privées que nous vous fournissons du moment que vous adaptez aussi le code des méthodes qui les utilisaient. Par contre, vous ne devriez pas toucher aux méthodes non privées car celles-ci risquent d'être utilisées par des classes que vous n'avez pas encore reçues. Bien sûr, vous pouvez aussi, si vous le désirez, ajouter de nouvelles méthodes aux classes que nous vous fournissons. Ces méthodes peuvent elles être aussi bien privées que publiques.
nextCh
La classe Scanner
définit
deux méthodes nextCh
. La première simplement appelle la
seconde et retourne la valeur passée en argument. Sa seule utilité est
de simplifier votre code. Par exemple, au lieu d'écrire
if (<cond>) { nextCh(); return <token1>; } else { return <token2>; }vous pouvez écrire
return <cond> ? nextCh(<token1>) : <token2>;
fatal
Les méthodes fatal
de la classe Global
ne retournent jamais (elles
lèvent toujours une exception pour stopper l'exécution), mais elles
sont tout de même déclarées avec un type de retour de la classe
Error
. Cela permet de placer l'appel à l'intérieur d'une
instruction throw
:
throw global.fatal(pos, "erreur fatale");
Cela est parfois très utile. Par exemple lorsque l'on doit appeler
cette méthode dans une fonction dont le type de retour n'est pas
void
. Dans ce cas, si on écrit un simple appel à la
méthode fatal
, le compilateur Java sera incapable de
déterminer que cette méthode ne retourne jamais et il vous obligera de
placer une instruction return
quelque part après votre
appel à fatal
. L'utilisation du throw
permet
d'éviter cela.