Document ID: /fineweb-2-swissfilter-quality_10-filterrobots/filtered/07239.jsonl.gz/1654

Compilation : partie 1
À présenter lors de la séance du 15 novembre 2002
Le but de cette partie est d'écrire un analyseur lexical pour le langage misc. Cet analyseur doit pouvoir déterminer si un fichier donné est conforme à la grammaire lexicale de misc. Si c'est le cas, il doit en outre retourner la suite de lexèmes constituant le fichier. Sinon, il doit signaler une ou éventuellement plusieurs erreurs.
Le projet se fait par groupe de deux ou trois étudiants. Pour former les groupes, utilisez le système Sygeco décrit ici.
Pour réaliser votre analyseur lexical, nous vous fournissons un certain nombre de fichiers (voir ci-dessous). Votre travail est de compléter deux de ces fichiers.
L'interface
Tokens a pour
but de définir toutes les classes de lexèmes. Pour l'instant, seules
quelques unes sont définies. Il vous faut donc examiner la grammaire syntaxique de
misc afin de déterminer quelles sont les classes de lexèmes
manquantes (à chaque symbol terminal de la grammaire syntaxique
correspond une classe de lexèmes).
Lorsque vous avez défini toutes les classes de lexèmes, vous
pouvez compléter la méthode
tokenClass de la classe
Scanner. Cette méthode retourne
simplement une représentation sous forme de chaîne de caractères de la
classe de lexèmes passée en argument. Pour la plupart des classes,
cela revient a retourner la représentation du seul lexème faisant
partie de cette classe.
Après cela, il ne vous restera plus qu'à compléter les méthodes
nextToken et
readToken de la classe
Scanner. Ces méthodes ont pour but
de sauter les commentaires et les espaces blancs et de lire le
prochain lexème. Elles doivent placer la classe de ce lexème dans la
variable d'instance
token et la position du premier
caractère le constituant dans la variable d'instance
start. Et, si le lexème est un identificateur, un nombre
ou une chaîne de caractères, elles doivent en plus stocker les
caractères qui le constituent dans la variable d'instance
chars. Pour assembler ces caractères en une chaîne, vous
pouvez utiliser la variable d'instance
buf.
Pour détecter la fin du fichier source, on utilise le caractère
spécial
EOF_CH. Celui-ci est retourné lorsque la fin du
fichier a été atteinte. On peut donc faire comme si la grammaire
lexicale avait été modifiée comme suit :
input = { inputelement } EOF_CH.
On modifie également la grammaire syntaxique comme suit :
Program = { Declaration ";" } Expression EOF_CH.
Le caractère
EOF_CH devient ainsi un terminal de la
grammaire syntaxique. Il doit donc exister une classes de lexèmes qui
lui corresponde. Cette classe est la classe
EOF définie
dans
Tokens.
Le caractère
EOF_CH définit un pseud-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 tous les vrais
lexèmes. L'analyseur lexical doit donc retourner tous les lexèmes
reconnus dans le fichier source plus le pseudo-lexème
EOF
pour signaler la fin du fichier.
Idéalement, un compilateur devrait toujours signaler autant d'erreurs que possible et non s'arrêter systématiquement après la première d'entre-elles. Toutefois, pour cette première partie, nous ne vous forçons pas à implanter cela. Vous pouvez donc vous contenter de signaler le première erreur rencontrée et ensuite stopper le compilateur.
Pour signaler des erreurs utilisez les méthodes
error
et
fatal fournies par la classe
Global et accessible dans
Scanner grâce à la variable
d'instance
global.
Les méthodes
fatal impriment un message d'erreur et
terminent l'exécution du programme. Utilisez ces méthodes si une
erreur empêche toute poursuite de l'analyse ou si votre but est de ne
signaler que la première erreur rencontrée. Si au contraire vous
aimeriez essayer de continuer l'analyse après l'erreur utilisez les
méthodes
error. Dans tous les cas, utilisez autant que
possible les versions incluant la position de l'erreur.
Tous les programmes de test que nous vous fournirons acceptent une
option
-debug qui permet de faire passer la variable
debug de la classe
Global à
true. Vous
pouvez donc utiliser cette variable pour exécuter du code de
déverminage seulement si celui-ci a effectivement été activé par
l'option
-debug.
La classe
Global fournit
également deux méthodes
debug qui permettent d'afficher
des messages de déverminage. Celles-ci peut avantageusement remplacer
certains appels à
System.out.println(...).
Notez encore que l'activation du déverminage change la manière
dont les erreurs sont imprimées. En temps normal, si plusieurs erreurs
se rapportent à la même position, seule la première est
affichée. Lorsque le déverminage est activé, les suivantes sont aussi
affichées suffixées avec la mention
[debug].
Programme de Test
Le programme de test ScannerTest.java vous permet de tester votre analyseur lexical. Il lit un fichier source et imprime dans un fichier objet la séquence de lexèmes reconnue par l'analyseur.
Le fichier source est spécifié par le premier argument fourni au
programme et le fichier object par le second. Si le premier argument
est absent ou égal à
- alors le programme lit sur
l'entrée standard. Si le second argument est absent ou égal à
- alors le programme écrit sur la sortie standard.
Comme déjà mentionné ci-dessus, le programme
accepte aussi une option
-debug qui permet d'activer le
déverminage.
Pour lancer le programme à partir du répertoire racine de votre projet, utilisez la commande suivante :
java -classpath ./classes misc.ScannerTest <options> [fichier-source [fichier-objet]]
Ci-dessous les fichiers dont vous aurez besoin pour cette première
partie. Il est fortement conseillé de créer un nouveau répertoire
dédié à ce projet. Placez-y le fichier
Makefile et, afin
de pouvoir utiliser ce dernier, placez tous les fichiers Java dans un
sous-répertoire nommé
src/misc. Les fichiers générés lors
de la compilation seront placés dans un sous-répertoire nommé
classes (ne placez aucun fichier important dans ce
répertoire car celui-ci est détruit par la commande
gmake
clean).
Makefile : L'utilisation de ce
Makefile est décrite ci-dessous.
Position.java : Cette classe fournit des méthodes pour encoder la position dans un fichier source (ligne & colonne) à l'aide d'un seul entier.
Global.java : Cette classes fournit des services pour signaler des erreurs et pour le déverminage. Elle contient aussi quelques autres méthodes dont vous n'aurez pas directement besoin mais qui sont utilisées par le code que nous vous fournissons.
AbstractMain.java : Cette classes fournit une base commune aux programmes de test que nous vous fournirons. Vous n'en aurez par directement besoin ; inutile donc de vous y attarder.
Tokens.java : Cette interface définit toutes les classes de lexèmes. Pour l'instant elle n'en contient que quelques unes. A vous de la compléter.
Scanner.java : Cette classe implante l'analyseur lexical. Une grande partie du code manque. A vous de l'écrire.
ScannerTest.java : Cette classe permet de tester votre analyseur lexical.
Attention, ce
Makefile nécessite
GNU
Make. Vous devez donc utiliser la commande
gmake
au lieu de
make. Ci-dessous, la liste des différentes
commandes qu'il fournit :
gmake (ou
gmake all) : compile tous les
fichiers modifiés depuis la dernière compilation réussie et place les
fichiers
.class dans le sous-répertoire
./classes qui est créé si nécessaire.
gmake force : compile de tous les fichiers (y compris
ceux qui n'ont pas changés depuis la dernière compilation
réussie). Cette opération est parfois nécessaire. Si vous avez des
erreurs très étranges à l'exécution, pensez à faire un
gmake
force, c'est souvent suffisant pour résoudre le problèmes ou du
moins pour localiser sa cause.
gmake clean : efface tous les fichiers générés et
suprime le répertoire
./classes (ne placez jamais rien
d'important dans ce répertoire).
gmake distclean : même chose que
gmake
clean, mais en plus suprime tous les fichiers
*.class
*~
core dans le
répertoire courant et tous ses sous-répertoires.
gmake grep ARGS=<regexp> : recherche
l'expression régulière
regexp dans tous les fichiers
sources.
gmake wc : compte le nombre de lignes, mots et
caractères dans tous les fichiers sources.