code ilp1 - jussieu · code ilp1 [email protected] 22 octobre 2007 ces chiers sont...

66
Code ILP1 [email protected] 22 octobre 2007 Ces fichiers sont diffusés pour l’enseignement ILP (Implantation d’un langage de programmation) dis- pensé depuis l’automne 2004 à l’UPMC (Université Pierre et Marie Curie). Ces fichiers sont diffusés selon les termes de la GPL (Gnu Public Licence). Pour les transparents du cours, la bande son et les autres documents associés, consulter le site http ://www.master.info.upmc.fr/ Table des matières 3 — LISEZ.MOI 4 — build.xml 11 — Grammars/Makefile 12 — Grammars/grammar1.rnc 13 — Java/jars/JARS.readme 14 — Java/src/fr/upmc/ilp/ilp1/interfaces/IAST.java 14 — Java/src/fr/upmc/ilp/ilp1/interfaces/IASTalternative.java 14 — Java/src/fr/upmc/ilp/ilp1/interfaces/IASTbinaryOperation.java 15 — Java/src/fr/upmc/ilp/ilp1/interfaces/IASTboolean.java 15 — Java/src/fr/upmc/ilp/ilp1/interfaces/IASTconstant.java 15 — Java/src/fr/upmc/ilp/ilp1/interfaces/IASTfloat.java 15 — Java/src/fr/upmc/ilp/ilp1/interfaces/IASTinteger.java 15 — Java/src/fr/upmc/ilp/ilp1/interfaces/IASTinvocation.java 16 — Java/src/fr/upmc/ilp/ilp1/interfaces/IASToperation.java 16 — Java/src/fr/upmc/ilp/ilp1/interfaces/IASTsequence.java 17 — Java/src/fr/upmc/ilp/ilp1/interfaces/IASTstring.java 17 — Java/src/fr/upmc/ilp/ilp1/interfaces/IASTunaryBlock.java 17 — Java/src/fr/upmc/ilp/ilp1/interfaces/IASTunaryOperation.java 17 — Java/src/fr/upmc/ilp/ilp1/interfaces/IASTvariable.java 17 — Java/src/fr/upmc/ilp/ilp1/fromxml/AST.java 18 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTException.java 18 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTParser.java 21 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTParserTest.java 26 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTalternative.java 27 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTblocUnaire.java 27 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTbooleen.java 28 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTchaine.java 28 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTentier.java 29 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTflottant.java 29 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTfromXML.java 30 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTinvocation.java 30 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTinvocationPrimitive.java 30 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASToperation.java 31 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASToperationBinaire.java 32 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASToperationUnaire.java 32 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTsequence.java 33 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTvariable.java 33 — Java/src/fr/upmc/ilp/ilp1/fromxml/Main.java 34 — Java/src/fr/upmc/ilp/ilp1/fromxml/MainTest.java 35 — Java/src/fr/upmc/ilp/ilp1/fromxml/MainTestSuite.java 35 — Java/src/fr/upmc/ilp/ilp1/runtime/AbstractInvokableImpl.java 36 — Java/src/fr/upmc/ilp/ilp1/runtime/Common.java 38 — Java/src/fr/upmc/ilp/ilp1/runtime/CommonPlus.java 45 — Java/src/fr/upmc/ilp/ilp1/runtime/ConstantsStuff.java 46 — Java/src/fr/upmc/ilp/ilp1/runtime/EmptyLexicalEnvironment.java 46 — Java/src/fr/upmc/ilp/ilp1/runtime/EvaluationException.java 47 — Java/src/fr/upmc/ilp/ilp1/runtime/ICommon.java 1

Upload: duonglien

Post on 15-Sep-2018

215 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

Code ILP1

[email protected]

22 octobre 2007

Ces fichiers sont diffusés pour l’enseignement ILP (Implantation d’un langage de programmation) dis-pensé depuis l’automne 2004 à l’UPMC (Université Pierre et Marie Curie). Ces fichiers sont diffusés selonles termes de la GPL (Gnu Public Licence). Pour les transparents du cours, la bande son et les autresdocuments associés, consulter le site http ://www.master.info.upmc.fr/

Table des matières3 — LISEZ.MOI4 — build.xml11 — Grammars/Makefile12 — Grammars/grammar1.rnc13 — Java/jars/JARS.readme14 — Java/src/fr/upmc/ilp/ilp1/interfaces/IAST.java14 — Java/src/fr/upmc/ilp/ilp1/interfaces/IASTalternative.java14 — Java/src/fr/upmc/ilp/ilp1/interfaces/IASTbinaryOperation.java15 — Java/src/fr/upmc/ilp/ilp1/interfaces/IASTboolean.java15 — Java/src/fr/upmc/ilp/ilp1/interfaces/IASTconstant.java15 — Java/src/fr/upmc/ilp/ilp1/interfaces/IASTfloat.java15 — Java/src/fr/upmc/ilp/ilp1/interfaces/IASTinteger.java15 — Java/src/fr/upmc/ilp/ilp1/interfaces/IASTinvocation.java16 — Java/src/fr/upmc/ilp/ilp1/interfaces/IASToperation.java16 — Java/src/fr/upmc/ilp/ilp1/interfaces/IASTsequence.java17 — Java/src/fr/upmc/ilp/ilp1/interfaces/IASTstring.java17 — Java/src/fr/upmc/ilp/ilp1/interfaces/IASTunaryBlock.java17 — Java/src/fr/upmc/ilp/ilp1/interfaces/IASTunaryOperation.java17 — Java/src/fr/upmc/ilp/ilp1/interfaces/IASTvariable.java17 — Java/src/fr/upmc/ilp/ilp1/fromxml/AST.java18 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTException.java18 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTParser.java21 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTParserTest.java26 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTalternative.java27 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTblocUnaire.java27 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTbooleen.java28 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTchaine.java28 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTentier.java29 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTflottant.java29 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTfromXML.java30 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTinvocation.java30 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTinvocationPrimitive.java30 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASToperation.java31 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASToperationBinaire.java32 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASToperationUnaire.java32 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTsequence.java33 — Java/src/fr/upmc/ilp/ilp1/fromxml/ASTvariable.java33 — Java/src/fr/upmc/ilp/ilp1/fromxml/Main.java34 — Java/src/fr/upmc/ilp/ilp1/fromxml/MainTest.java35 — Java/src/fr/upmc/ilp/ilp1/fromxml/MainTestSuite.java35 — Java/src/fr/upmc/ilp/ilp1/runtime/AbstractInvokableImpl.java36 — Java/src/fr/upmc/ilp/ilp1/runtime/Common.java38 — Java/src/fr/upmc/ilp/ilp1/runtime/CommonPlus.java45 — Java/src/fr/upmc/ilp/ilp1/runtime/ConstantsStuff.java46 — Java/src/fr/upmc/ilp/ilp1/runtime/EmptyLexicalEnvironment.java46 — Java/src/fr/upmc/ilp/ilp1/runtime/EvaluationException.java47 — Java/src/fr/upmc/ilp/ilp1/runtime/ICommon.java

1

Page 2: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

47 — Java/src/fr/upmc/ilp/ilp1/runtime/ILexicalEnvironment.java47 — Java/src/fr/upmc/ilp/ilp1/runtime/Invokable.java48 — Java/src/fr/upmc/ilp/ilp1/runtime/LexicalEnvironment.java48 — Java/src/fr/upmc/ilp/ilp1/runtime/PrintStuff.java49 — Java/src/fr/upmc/ilp/ilp1/eval/EAST.java50 — Java/src/fr/upmc/ilp/ilp1/eval/EASTConstant.java50 — Java/src/fr/upmc/ilp/ilp1/eval/EASTException.java50 — Java/src/fr/upmc/ilp/ilp1/eval/EASTFactory.java52 — Java/src/fr/upmc/ilp/ilp1/eval/EASTFileTest.java54 — Java/src/fr/upmc/ilp/ilp1/eval/EASTParser.java57 — Java/src/fr/upmc/ilp/ilp1/eval/EASTPrimitiveTest.java58 — Java/src/fr/upmc/ilp/ilp1/eval/EASTTest.java62 — Java/src/fr/upmc/ilp/ilp1/eval/EASTalternative.java63 — Java/src/fr/upmc/ilp/ilp1/eval/EASTblocUnaire.java64 — Java/src/fr/upmc/ilp/ilp1/eval/EASTbooleen.java64 — Java/src/fr/upmc/ilp/ilp1/eval/EASTchaine.java65 — Java/src/fr/upmc/ilp/ilp1/eval/EASTentier.java65 — Java/src/fr/upmc/ilp/ilp1/eval/EASTflottant.java65 — Java/src/fr/upmc/ilp/ilp1/eval/EASTinvocation.java66 — Java/src/fr/upmc/ilp/ilp1/eval/EASTinvocationPrimitive.java67 — Java/src/fr/upmc/ilp/ilp1/eval/EASToperation.java67 — Java/src/fr/upmc/ilp/ilp1/eval/EASToperationBinaire.java68 — Java/src/fr/upmc/ilp/ilp1/eval/EASToperationUnaire.java69 — Java/src/fr/upmc/ilp/ilp1/eval/EASTsequence.java69 — Java/src/fr/upmc/ilp/ilp1/eval/EASTvariable.java70 — Java/src/fr/upmc/ilp/ilp1/eval/IEASTFactory.java71 — Java/src/fr/upmc/ilp/ilp1/cgen/CgenEnvironment.java72 — Java/src/fr/upmc/ilp/ilp1/cgen/CgenLexicalEnvironment.java73 — Java/src/fr/upmc/ilp/ilp1/cgen/CgenerationException.java73 — Java/src/fr/upmc/ilp/ilp1/cgen/Cgenerator.java77 — Java/src/fr/upmc/ilp/ilp1/cgen/CgeneratorTest.java79 — Java/src/fr/upmc/ilp/ilp1/cgen/ICgenEnvironment.java80 — Java/src/fr/upmc/ilp/ilp1/cgen/ICgenLexicalEnvironment.java80 — Java/src/fr/upmc/ilp/ilp1/CoverageTest.java81 — Java/src/fr/upmc/ilp/ilp1/JDependTest.java81 — Java/src/fr/upmc/ilp/ilp1/Process.java83 — Java/src/fr/upmc/ilp/ilp1/ProcessTest.java83 — Java/src/fr/upmc/ilp/ilp1/WholeTestSuite.java84 — Java/src/fr/upmc/ilp/tool1/AbstractEnvironment.java84 — Java/src/fr/upmc/ilp/tool1/AbstractProcess.java87 — Java/src/fr/upmc/ilp/tool1/AbstractProcessTest.java88 — Java/src/fr/upmc/ilp/tool1/CStuff.java89 — Java/src/fr/upmc/ilp/tool1/CStuffTest.java90 — Java/src/fr/upmc/ilp/tool1/File.java90 — Java/src/fr/upmc/ilp/tool1/FileTool.java92 — Java/src/fr/upmc/ilp/tool1/FileToolTest.java92 — Java/src/fr/upmc/ilp/tool1/IContent.java93 — Java/src/fr/upmc/ilp/tool1/IProcess.java93 — Java/src/fr/upmc/ilp/tool1/IProcessListener.java94 — Java/src/fr/upmc/ilp/tool1/Parameterized.java96 — Java/src/fr/upmc/ilp/tool1/ProgramCaller.java98 — Java/src/fr/upmc/ilp/tool1/ProgramCallerTest.java100 — Java/src/fr/upmc/ilp/tool1/ToolTestSuite.java101 — C/C.readme101 — C/Makefile102 — C/compileThenRun.sh103 — C/ilp.c107 — C/ilp.h110 — C/ilpAlloc.c110 — C/ilpAlloc.h110 — C/ilpBasicError.c111 — C/ilpBasicError.h111 — C/ilpError.c112 — C/ilpException.c113 — C/ilpException.h113 — C/ilpField.c114 — C/ilpObj.c

2

123 — C/ilpObj.h128 — C/ilpTrace.c129 — C/ilpTrace.h

3

Page 3: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

LISEZ.MOI

1 Ces fichiers sont diffusés pour l’enseignement ILP (Implantationd’un langage de programmation) dispensé depuis l’automne 2004 à l’UPMC(Université Pierre et Marie Curie). Ces fichiers sont diffusés selonles termes de la GPL (Gnu Public Licence). Pour les transparents ducours, la bande son et les autres documents associés, consulter le

6 site http://www-master.ufr-info-p6.jussieu.fr/2007/

Adressez-moi toutes vos remarques concernant ce cours ou ces fichiersavec un courriel dont le titre contient la chaîne « ILP » ou, mieux,postez-les sur le forum associé au cours.

11

Usage depuis Eclipse:=====================

Si vous lisez ce fichier depuis Eclipse, alors vous pouvez regénérer16 tout ILP en exécutant le fichier build.xml (clic droit, Run as >

Ant build). La regéneration totale a besoin de make, bash, gcc etBigloo: un systeme Scheme que l’on peut trouver en

http://www-sop.inria.fr/mimosa/fp/Bigloo/

21 L’image ILP.tgz contient tous les programmes et la plupart desproduits derivés (classes Java compilées, documentation javadoc,grammaires converties, fichiers de tests) sont déjà présents.

Quelques détails sur ILP26 =======================

Quelques répertoires sont des sommaires documentations dans desfichiers *.readme ou LISEZ.MOI. C’est le cas pour

31 Compiler/C/C.readmeCompiler/Java/jars/JARS.readme

Les Makefile sont également d’importantes sources d’information.

36 Installation============

Si vous lisez ce fichier c’est probablement que vous avez décompresséle fichier ILP-uneCertaineDate.tgz. Assurez vous que les répertoires

41 Compiler/, PlugIns/ etc. sont bien juste en dessous de votre espace detravail pour Eclipse (usuellement ~/workspace/).

Demandez l’importation (menu File) de projets existant dans l’espacede travail (catégorie General) passez à la suite avec Next et

46 sélectionnez alors le répertoire correspondant à l’espace de travail.Eclipse s’aperçoit alors que des projets existent déjà et tentera deles récupérer tels quels. Une fois ceci fait, lancerCompiler/build.xml (menu contextuel (clic droit) run as "Ant build")depuis Eclipse pour regénérer les fichiers manquants. Enfin, pour

51 tester que tout va bien, lancer la classefr.upmc.ilp.ilp1.WholeTestSuite (menu contextuel run as "JUnit Test"):tout doit passer au vert!

Greffon ILP56 ===========

Depuis 2006, ILP a introduit un nouveau greffon à incorporer à Eclipse(au moins 3.2), facilitant quelques opérations. Ce greffon introduitquelques opérations contextuelles dans l’explorateur de projet. Voici,

61 par type de fichiers, les opérations principales que l’on peutobtenir (dans le sous-menu ILP):

Sur un fichier .rnc (une grammaire compacte d’ILP)- conversion en .rng

66 Sur un fichier .rng (une grammaire (en XML) pour ILP)- positionnement comme grammaire ILP par défaut

Sur un fichier .xml (un programme ILP)- validation vis-à-vis d’une grammaire ILP choisie dynamiquement- validation vis-à-vis de la grammaire ILP par défaut

71 (il existe maintenant sous Eclipse 3.3, un menu contextuel "Validate"qui ne vérifie que la conformité syntaxique vis-à-vis d’XML).

Sur un répertoire (de grammaires .rng)- positionnement comme répertoire des grammaires par défaut

76 La grammaire par défaut et le répertoire des grammaires par défaut nesont pas conservés entre deux sessions.

Le greffon est susceptible d’évoluer, abonnez-vous au site de mise à jour4

en http://www.master.info.upmc.fr/2007/Ext/queinnec/ILP/81 ce qui va aussi servir à l’installer. Dans le Menu Help, cherchez

Software Updates, Find and Install, Search for new features to install,new Remote Site. Remplissez le formulaire en indiquant qu’ILP est à l’urlhttp://www.master.info.upmc.fr/2007/Ext/queinnec/ILP/, OKpuis Finish. Eclipse cherche alors le greffon...

86

Autres greffons===============

D’autres greffons sont utiles (ou intéressants) mais on peut s’en91 passer, je tenterai toutefois de les faire inclure dans l’installation

à l’ARI. Ce sont:

Pour le plugin checkstyle,http://eclipse-cs.sourceforge.net/

96 Jdepend pour eclipse,http://andrei.gmxhome.de/eclipse/

PMD pour Eclipse,http://pmd.sf.net/eclipse

AnyEdit101 http://andrei.gmxhome.de/eclipse/

asmhttp://download.forge.objectweb.org/eclipse-update/

Emacs106 =====

Le paquetage nxml est réputé. Il se trouve enhttp://www.thaiopensource.com/download/nxml-mode-20041004.tar.gz

mais une copie est dans le répertoire ELISP/ ainsi qu’un mode111 pour éditer des schémas RelaxNG facilement.

Divers======

116 Depuis la 3.2, Eclipse dispose d’un éditeur structurel de XML (suffixe.xml) ainsi qu’un éditeur de grammaires XMLSchema (suffixe .xsd).

Mon Eclipse est réglé, depuis cette année, sur UTF-8, La plupart desfichiers *.java sont dans ce mode mais d’autres sont restés en Latin1

121 (ce LISEZ.MOI, les grammaires *.rnc). C’est un mal qui affecte lemonde entier et qui ne sera surmonté que dans longtemps.

#fin.

build.xml

1 <?xml version=’1.0’ encoding=’iso-8859-1’?><!--Exécuter Ant sans argument enchaîne toutes les compilations suiviesdes tests (en JUnit). Pour exécuter ce script à partir d’Eclipse, leprojet doit contenir junit.jar dans les bibliothèques à utiliser.

6 Pour exécuter ce script à partir de sh, positionnez la variableJAVA_HOME au répertoire contenant Java5 (le répertoire contenant bin,lib), positionnez ANT_HOME pour qu’Ant trouve lib/ant-junit.jar etlancez Ant (sans argument). Par exemple, sur MacOSX:

11 export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/1.5/Homeexport ANT_HOME=/Developer/Java/Antant

-->16 <project name=’ILP’ default=’install.ilp1.with.good.classpath’>

<description>Script de regénération et de test des versions d’ILP par Ant.

</description>

21 <target name=’install.ilp1.with.good.classpath’description=’Relancer Ant avec le bon CLASSPATH’>

<!-- Avec ant intégré à Eclipse, on ne sait jamais trop quels(et où) sont les bibliothèques ant, junit, etc. Pour que cebuild.xml puisse fonctionner à la fois depuis Eclipse ou bash,

26 on se relance en spécifiant les bons chemins. --><java classname=’org.apache.tools.ant.Main’

failonerror=’true’><arg value=’create.rng.schema.for.ilp1’/><arg value=’prepare.c.runtime’/>

31 <classpath><pathelement path=’${src}’/>

5

Page 4: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

<pathelement path=’${jing}’/><pathelement path=’${trang}’/><pathelement path=’${junit}’/>

36 <pathelement path=’${java.class.path}/’/></classpath>

</java><echo message=’Grammaires et support C regénérés!’/>

</target>41

<!-- Les chemins d’accès aux diverses archives --><property name=’testdir’ location=’.’/><property name=’rnc’ location=’Grammars’/>

46 <property name=’scm’ location=’Grammars/Scheme’/><property name=’c’ location=’C’/><property name=’src’ location=’Java/src’/><property name=’bin’ location=’Java/bin’/><property name=’doc’ location=’Java/doc’/>

51 <property name=’jing’ location=’Java/jars/jing.jar’/><property name=’junit’ location=’Java/jars/junit.jar’/><property name=’trang’ location=’Java/jars/trang.jar’/><property name=’xmlunit’ location=’Java/jars/xmlunit1.0.jar’/><property name=’bcel’ location=’Java/jars/bcel.jar’/>

56 <property name=’hansel’ location=’Java/jars/hansel.jar’/><!-- Archives additionnelles pour experiences diverses --><property name=’beautyj’ location=’Java/jars/beautyj.jar’/><property name=’pmd’ location=’Java/jars/pmd-3.7.jar’/>

61 <!-- Les chemins d’accès aux divers programmes adventices. En fait,seul make est utile les Makefile associés utiliseront par contregcc, bash et bigloo. -->

<property name=’make’ value=’make’/>

66 <!-- Les règles --><target name=’all’

depends=’create.rng.schemas,regenerate.CommonPlus.java,generate.ilp.programs.in.xml,

71 validate.xml.programs,compile.java.classes,generate.documentation,prepare.c.runtime,require.junit,

76 test.junit.ilp1,test.junit.ilp2,test.junit.ilp3,test.junit.ilp4,test.junit.ilp6’

81 description=’Tout regénérer, tout compiler, tout tester!’ />

<!-- Et une petite macro pour se simplifier la vie plus tard. --><macrodef name=’trang.one.file’>

<attribute name=’rnc.grammar’/>86 <attribute name=’rng.grammar’/>

<sequential><java classname=’com.thaiopensource.relaxng.translate.Driver’

failonerror=’true’><classpath>

91 <pathelement path=’${trang}’/><pathelement path=’${java.class.path}/’/>

</classpath><arg value=’-i’/><arg value=’encoding=iso-8859-15’/>

96 <arg value=’-o’/><arg value=’encoding=iso-8859-15’/><arg value=’@{rnc.grammar}’/><arg value=’@{rng.grammar}’/>

</java>101 <echo level=’info’ message=’@{rng.grammar} regenerated.’/>

</sequential></macrodef>

<target name=’create.rng.schemas’106 description=’Créer les schémas RelaxNG pour les grammaires’>

<trang.one.file rnc.grammar=’${rnc}/grammar1.rnc’rng.grammar=’${rnc}/grammar1.rng’ />

<trang.one.file rnc.grammar=’${rnc}/grammar2.rnc’111 rng.grammar=’${rnc}/grammar2.rng’ />

<trang.one.file rnc.grammar=’${rnc}/grammar2esc.rnc’rng.grammar=’${rnc}/grammar2esc.rng’ />

<trang.one.file rnc.grammar=’${rnc}/grammar2exdef.rnc’6

rng.grammar=’${rnc}/grammar2exdef.rng’ />116 <trang.one.file rnc.grammar=’${rnc}/grammar3.rnc’

rng.grammar=’${rnc}/grammar3.rng’ /><trang.one.file rnc.grammar=’${rnc}/grammar4.rnc’

rng.grammar=’${rnc}/grammar4.rng’ /><trang.one.file rnc.grammar=’${rnc}/grammar4enum.rnc’

121 rng.grammar=’${rnc}/grammar4enum.rng’ /><trang.one.file rnc.grammar=’${rnc}/grammar4enumens.rnc’

rng.grammar=’${rnc}/grammar4enumens.rng’ /><trang.one.file rnc.grammar=’${rnc}/grammar6.rnc’

rng.grammar=’${rnc}/grammar6.rng’ />126 <trang.one.file rnc.grammar=’${rnc}/grammar6dyn.rnc’

rng.grammar=’${rnc}/grammar6dyn.rng’ /><!-- FUTUR: engendrer les xsd pour beneficier du support xsd d’Eclipse ? -->

</target>

131 <target name=’create.rng.schema.for.ilp1’description=’Engendrer grammar1.rng’><trang.one.file rnc.grammar=’${rnc}/grammar1.rnc’

rng.grammar=’${rnc}/grammar1.rng’ /><trang.one.file rnc.grammar=’${rnc}/grammar1-td2_1.rnc’

136 rng.grammar=’${rnc}/grammar1-td2_1.rng’ /><trang.one.file rnc.grammar=’${rnc}/grammar1-td2_2.rnc’

rng.grammar=’${rnc}/grammar1-td2_2.rng’ /><trang.one.file rnc.grammar=’${rnc}/grammar1-tme2_1.rnc’

rng.grammar=’${rnc}/grammar1-tme2_1.rng’ />141 <trang.one.file rnc.grammar=’${rnc}/grammar1-tme2_2.rnc’

rng.grammar=’${rnc}/grammar1-tme2_2.rng’ /></target>

<target name=’generate.ilp.programs.in.xml’146 description=’Engendrer des programmes de tests en ILP1/2/3/4/6’ >

<!-- cette règle demande la présence des programmes make et bigloo --><echo message=’Convertir de Scheme vers XML ...’/><exec dir=’${scm}’

executable=’${make}’151 logError=’true’

failonerror=’true’ ><arg line=’restart.with.bigloo.and.generate.xml’/>

</exec></target>

156

<target name=’prepare.c.runtime’description=’Compiler la bibliotheque d&apos;execution en C’ >

<!-- cette règle demande la présence des programmes make et gcc --><echo message=’Compiler les programmes en C ...’/>

161 <exec dir=’${c}’executable=’${make}’logError=’true’failonerror=’true’ >

<arg line=’work’/>166 </exec>

</target>

<target name=’validate.xml.programs’description=’Validation XML de tous les programmes ILP’

171 depends=’create.rng.schemas’ ><taskdef name=’jing’

classname=’com.thaiopensource.relaxng.util.JingTask’classpath=’${jing}’ />

<!-- Les grammaires s’emboîtent strictement donc un programme ILP<i> doit176 être reconnu par toutes les grammaires suivant <i>. C’est ce que

l’on vérifie avec les expressions rationnelles suivantes. --><echo message=’Valider les programmes *-1.xml avec grammar1’/><jing compactsyntax=’true’ rngfile=’${rnc}/grammar1.rnc’>

<fileset dir=’${rnc}/Samples’ includes=’*-1.xml’/>181 </jing>

<echo message=’Valider les programmes *-1-td2_1.xml avec grammar1-td2_1’/><echo message=’Valider les programmes *-[1-2].xml avec grammar2’/><jing compactsyntax=’true’ rngfile=’${rnc}/grammar2.rnc’>

<fileset dir=’${rnc}/Samples’ includes=’*-[1-2].xml’/>186 </jing>

<jing compactsyntax=’true’ rngfile=’${rnc}/grammar2esc.rnc’><fileset dir=’${rnc}/Samples’ includes=’*-[1-2](escl?)?.xml’/>

</jing><echo message=’Valider les programmes *-[1-3].xml avec grammar3’/>

191 <jing compactsyntax=’true’ rngfile=’${rnc}/grammar3.rnc’><fileset dir=’${rnc}/Samples’ includes=’*-[1-3].xml’/>

</jing><echo message=’Valider les programmes *-[1-4].xml avec grammar4’/><jing compactsyntax=’true’ rngfile=’${rnc}/grammar4.rnc’>

196 <fileset dir=’${rnc}/Samples’ includes=’*-[1-4].xml’/>7

Page 5: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

</jing><echo message=’Valider les programmes *-[1-46].xml avec grammar6’/><jing compactsyntax=’true’ rngfile=’${rnc}/grammar6.rnc’>

<fileset dir=’${rnc}/Samples’ includes=’*-[12346].xml’/>201 </jing>

</target>

<target name=’validate.xml.programs.for.ilp1’description=’Validation XML de tous les programmes ILP1’

206 depends=’create.rng.schema.for.ilp1’ ><taskdef name=’jing’

classname=’com.thaiopensource.relaxng.util.JingTask’classpath=’${jing}’ />

<!-- Les grammaires s’emboîtent strictement donc un programme ILP<i> doit211 être reconnu par toutes les grammaires suivant <i>. C’est ce que

l’on vérifie avec les expressions rationnelles suivantes. --><echo message=’Valider les programmes *-1.xml avec grammar1’/><jing compactsyntax=’true’ rngfile=’${rnc}/grammar1.rnc’>

<fileset dir=’${rnc}/Samples’ includes=’*-1.xml’/>216 </jing>

<echo message=’Valider les programmes *-1-td2_1.xml avec grammar1-td2_1’/><jing compactsyntax=’true’ rngfile=’${rnc}/grammar1-td2_1.rnc’>

<fileset dir=’${rnc}/Samples’ includes=’*-1-td2_1.xml’/></jing>

221 <echo message=’Valider les programmes *-1-td2_2.xml avec grammar1-td2_2’/><jing compactsyntax=’true’ rngfile=’${rnc}/grammar1-td2_2.rnc’>

<fileset dir=’${rnc}/Samples’ includes=’*-1-td2_2.xml’/></jing><echo message=’Valider les programmes *-1-tme2_1.xml avec grammar1-tme2_1’/>

226 <jing compactsyntax=’true’ rngfile=’${rnc}/grammar1-tme2_1.rnc’><fileset dir=’${rnc}/Samples’ includes=’*-1-tme2_1.xml’/>

</jing><echo message=’Valider les programmes *-1-tme2_2.xml avec grammar1-tme2_2’/><jing compactsyntax=’true’ rngfile=’${rnc}/grammar1-tme2_2.rnc’>

231 <fileset dir=’${rnc}/Samples’ includes=’*-1-tme2_2.xml’/></jing>

</target>

<target name=’compile.java.classes’236 depends=’regenerate.CommonPlus.java’

description=’Compiler toutes les classes Java’><delete dir=’${bin}’/><mkdir dir=’${bin}’/>

<echo message=’Compiler ILP.tool...’/>241 <javac srcdir=’${src}/fr/upmc/ilp/tool/’ destdir=’${bin}’>

<classpath><pathelement path=’${junit}’/><pathelement path=’${xmlunit}’/><pathelement path=’${jing}’/>

246 <pathelement path=’${hansel}’/><pathelement path=’${java.class.path}/’/>

</classpath></javac><echo message=’Compiler ILP1...’/>

251 <javac srcdir=’${src}/fr/upmc/ilp/ilp1/’ destdir=’${bin}’><classpath>

<pathelement path=’${junit}’/><pathelement path=’${xmlunit}’/><pathelement path=’${jing}’/>

256 <pathelement path=’${hansel}’/><pathelement path=’${java.class.path}/’/>

</classpath></javac><echo message=’Compiler ILP2...’/>

261 <javac srcdir=’${src}/fr/upmc/ilp/ilp2/’ destdir=’${bin}’><classpath>

<pathelement path=’${junit}’/><pathelement path=’${xmlunit}’/><pathelement path=’${jing}’/>

266 <pathelement path=’${hansel}’/><pathelement path=’${java.class.path}/’/>

</classpath></javac><echo message=’Compiler le reste ...’/>

271 <javac srcdir=’${src}’ destdir=’${bin}’><classpath>

<pathelement path=’${junit}’/><pathelement path=’${xmlunit}’/><pathelement path=’${jing}’/>

276 <pathelement path=’${hansel}’/><pathelement path=’${java.class.path}/’/>

</classpath>8

</javac></target>

281

<target name=’DONT.regenerate.CommonPlus.java’/>

<target name=’regenerate.CommonPlus.java’description=’Engendrer CommonPlus.java avec PHP’>

286 <!-- PHP emet souvent des avertissements concernant certainesbibliotheques mal initialisees. Pas grave tant que le fichierest produit correctement. -->

<property name=’php.file.ilp1’location=’${src}/fr/upmc/ilp/ilp1/runtime/BinOp.php’/>

291 <echo message=’Expanser ${php.file.ilp1}...’/><exec dir=’${src}/fr/upmc/ilp/ilp1/runtime/’

executable=’php’output=’${src}/fr/upmc/ilp/ilp1/runtime/CommonPlus.java’logError=’true’

296 failonerror=’true’ ><arg file=’${php.file.ilp1}’/>

</exec></target>

301 <target name="require.junit"description="Verifier que junit.jar est present">

<available classname="junit.framework.Test"property="junit.available"/>

<fail unless="junit.available"306 message="Je ne trouve pas junit.jar !?"/>

</target>

<target name=’test.junit’depends=’require.junit,

311 compile.java.classes,prepare.c.runtime,test.junit.ilp1,test.junit.ilp2,test.junit.ilp3,

316 test.junit.ilp4,test.junit.ilp6’

description=’Tout tester avec Junit’ />

<target name=’DONT.test.junit.ilp1’/>321 <target name=’test.junit.ilp1’

depends=’require.junit,prepare.c.runtime’

description=’Tester ILP1’ ><echo level=’info’ message=’*** Les tests concernant ILP1 ***’/>

326 <junit fork=’true’ haltonerror=’true’ printsummary=’on’dir=’${testdir}’ >

<formatter type=’plain’ usefile=’false’/><classpath>

<pathelement path=’${bin}’/>331 <pathelement path=’${jing}’/>

<pathelement path=’${junit}’/><pathelement path=’${xmlunit}’/><pathelement path=’${hansel}’/><pathelement path=’${bcel}’/>

336 </classpath><batchtest>

<!-- Il faut un fileset par suite de test pour assurer l’ordreselon lequel les suites de test sont exécutées. -->

<fileset dir=’${bin}’>341 <include name=’**/tool/*TestSuite.class’/>

</fileset><fileset dir=’${bin}’>

<include name=’**/ilp1/fromxml/*TestSuite.class’/></fileset>

346 <fileset dir=’${bin}’><include name=’**/ilp1/eval/*TestSuite.class’/>

</fileset><fileset dir=’${bin}’>

<include name=’**/ilp1/cgen/*TestSuite.class’/>351 <include name=’**/ilp1/cgen/ProcessTest.class’/>

</fileset><fileset dir=’${bin}’>

<include name=’**/ilp1/TestsSuite.class’/></fileset>

356 </batchtest></junit>

</target>

<target name=’DONT.test.junit.ilp2’/>9

Page 6: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

361 <target name=’test.junit.ilp2’depends=’require.junit,

prepare.c.runtime’description=’Tester ILP2’ >

<echo level=’info’ message=’*** Les tests concernant ILP2 ***’/>366 <junit fork=’true’ haltonerror=’true’ printsummary=’on’

dir=’${testdir}’ ><formatter type=’plain’ usefile=’false’/><classpath>

<pathelement path=’${bin}’/>371 <pathelement path=’${jing}’/>

<pathelement path=’${junit}’/><pathelement path=’${xmlunit}’/><pathelement path=’${hansel}’/><pathelement path=’${bcel}’/>

376 </classpath><batchtest>

<fileset dir=’${bin}’><include name=’**/tool/*TestSuite.class’/>

</fileset>381 <fileset dir=’${bin}’>

<include name=’**/ilp1/fromxml/*TestSuite.class’/></fileset><fileset dir=’${bin}’>

<include name=’**/ilp1/eval/*TestSuite.class’/>386 </fileset>

<fileset dir=’${bin}’><include name=’**/ilp1/cgen/*TestSuite.class’/>

</fileset><fileset dir=’${bin}’>

391 <include name=’**/ilp2/*TestSuite.class’/></fileset><fileset dir=’${bin}’>

<include name=’**/ilp2esc/*TestSuite.class’/></fileset>

396 <fileset dir=’${bin}’><include name=’**/ilp2escl/*TestSuite.class’/>

</fileset><fileset dir=’${bin}’>

<include name=’**/ilp2exdef/CompilerTest.class’/>401 </fileset>

</batchtest></junit>

</target>

406 <target name=’DONT.test.junit.ilp3’/><target name=’test.junit.ilp3’

depends=’require.junit,prepare.c.runtime’

description=’Tester ILP3’ >411 <echo level=’info’ message=’*** Les tests concernant ILP3 ***’/>

<junit fork=’true’ haltonerror=’true’ printsummary=’on’dir=’${testdir}’ >

<formatter type=’plain’ usefile=’false’/><classpath>

416 <pathelement path=’${bin}’/><pathelement path=’${jing}’/><pathelement path=’${junit}’/><pathelement path=’${xmlunit}’/><pathelement path=’${hansel}’/>

421 <pathelement path=’${bcel}’/></classpath><batchtest><fileset dir=’${bin}’>

<include name=’**/ilp3/*TestSuite.class’/>426 </fileset>

</batchtest></junit>

</target>

431 <target name=’DONT.test.junit.ilp4’/><target name=’test.junit.ilp4’

depends=’require.junit,prepare.c.runtime’

description=’Tester ILP4’ >436 <echo level=’info’ message=’*** Les tests concernant ILP4 ***’/>

<junit fork=’true’ haltonerror=’true’ printsummary=’on’dir=’${testdir}’ >

<formatter type=’plain’ usefile=’false’/><classpath>

441 <pathelement path=’${bin}’/><pathelement path=’${jing}’/>

10

<pathelement path=’${junit}’/><pathelement path=’${xmlunit}’/><pathelement path=’${hansel}’/>

446 <pathelement path=’${bcel}’/></classpath><batchtest><fileset dir=’${bin}’>

<include name=’**/ilp4/*TestSuite.class’/>451 </fileset>

<fileset dir=’${bin}’><include name=’**/ilp4enum/*TestSuite.class’/>

</fileset></batchtest>

456 </junit></target>

<target name=’DONT.test.junit.ilp6’/><target name=’test.junit.ilp6’

461 depends=’require.junit,prepare.c.runtime’

description=’Tester ILP6’ ><echo level=’info’ message=’*** Les tests concernant ILP6 ***’/><junit fork=’true’ haltonerror=’true’ printsummary=’on’

466 dir=’${testdir}’ ><formatter type=’plain’ usefile=’false’/><classpath>

<pathelement path=’${bin}’/><pathelement path=’${jing}’/>

471 <pathelement path=’${junit}’/><pathelement path=’${xmlunit}’/><pathelement path=’${hansel}’/><pathelement path=’${bcel}’/>

</classpath>476 <batchtest>

<fileset dir=’${bin}’><include name=’**/tool/*TestSuite.class’/>

</fileset><fileset dir=’${bin}’>

481 <include name=’**/ilp6/*TestSuite.class’/></fileset>

</batchtest></junit>

</target>486

<target name=’DONT.generate.documentation’/><target name=’generate.documentation’

depends=’regenerate.CommonPlus.java’description=’Engendrer la documentation d&apos;interface’>

491 <javadoc sourcepath=’${src}’packagenames=’fr.upmc.ilp.*’defaultexcludes=’yes’Overview=’${src}/fr/upmc/ilp/overview.html’destdir=’${doc}’

496 classpath=’${junit};${xmlunit};${hansel};${jing}’ /></target>

501 <!-- Expériences diversesElles sont en commentaires afin que l’absence des .jar necessairesne soit pas consideree comme une anomalie qui affuble l’icone dece fichier d’une hideuse decoration.

-->506

<!-- target name="beautify.java.code"description=’Formater joliment le code Java’ >

<!- Reformater joliment le code avec Beautyj (cf.http://beautyj.berlios.de/) qui semble plus recent que

511 Jalopy. Cette tache n’est pas au point! Je ne suis pas surque Beautyj sache analyser du Java5. ->

<taskdef name=’beautyj’classname=’de.gulden.application.beautyj.ant.Task’classpath=’${beautyj}’ />

516 <beautyj project_name=’ILP’project_version=’$Revision$’author_name=’Christian Queinnec’author_email=’[email protected]’class_create_text=’description,author’

521 method_create_text=’description,param,throws,return’output_directory=’Java/beautified-src’verbose=’true’code_clean=’true’ >

11

Page 7: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

<src path=’${src}/fr’/>526 </beautyj>

</target -->

<!-- target name=’analyze.java.code’description=’Analyser le code Java avec PMD (dont shoot the messenger!)’ >

531 <!- Analyser avec PMD (http://pmd.sourceforge.net/)Un greffon http://www.eclipse-plugins.info/eclipse/ existe aussi. ->

<path id="pmd.classpath"><fileset dir="Java/jars"><include name="*.jar"/>

536 </fileset></path><!- L’anomalie suivante disparait si l’on extrait pmd.jar de pmd.zip -><taskdef name=’pmd’

classname=’net.sourceforge.pmd.ant.PMDTask’541 classpathref=’pmd.classpath’ />

<pmd failonerror=’true’printToConsole=’yes’targetjdk=’1.5’ >

<ruleset>rulesets/basic.xml</ruleset>546 <ruleset>rulesets/unusedcode.xml</ruleset>

<formatter type=’text’ toFile=’Java/pmd.report’/><fileset dir=’${src}’>

<include name=’**/*.java’/></fileset>

551 </pmd></target -->

</project>

Grammars/Makefile

1 work : create.rng.files \validate.xml.files

clean :: cleanMakefile-rm -f grammar*.rng

6 # 2007sep06: trang ne fonctionne pas avec le java d’Ubuntu (gij)!De# plus, le code de trang n’est pas generique (a ne pas reompiler donc).

JAVA = /usr/java/jdk1.6.0_02/bin/javaTRANG = ../Java/jars/trang.jar

11 JING = ../Java/jars/jing.jar

.SUFFIXES: .rnc .rng .xsd .dtd

.rnc.rng :${JAVA} -jar ${TRANG} \

16 -i encoding=iso-8859-15 \-o encoding=iso-8859-15 \$*.rnc $*.rng

.rnc.xsd :${JAVA} -jar ${TRANG} \

21 -i encoding=iso-8859-15 \-o encoding=iso-8859-15 \$*.rnc $*.xsd

.rnc.dtd :${JAVA} -jar ${TRANG} \

26 -i encoding=iso-8859-15 \-o encoding=iso-8859-15 \$*.rnc $*.dtd

# NOTA: Valider un document XML d.xml avec un schéma f.rng et jing ainsi:31 # ${JAVA} -jar ${JING} f.rng d.xml

GRAMMARS = \grammar1.rnc \grammar2.rnc \

36 grammar3.rnc \grammar4.rnc \grammar6.rnc

# Créer les équivalents XML des schémas RelaxNG compacts:41

create.rng.files : ${GRAMMARS:.rnc=.rng}

# Creer les équivalents XSD des schémas RelaxNG compacts:

46 create.xsd.files : ${GRAMMARS:.rnc=.xsd}

12

# Les grammaires s’incluent ce qui cree des dependances:grammar2.rng : grammar1.rnggrammar3.rng : grammar2.rng

51 grammar4.rng : grammar3.rnggrammar6.rng : grammar4.rng

# Valider les exemples de programmes qui sont en Samples/# Verifier que les grammaires sont bien incluses: tout ce que reconnait

56 # grammar1 doit etre reconnu par grammar2, etc.

validate.xml.files : ${GRAMMARS:.rnc=.rng}for i in 6 4 3 2 1 ; do \for p in Samples/?*-[1-$$i].xml ; do \

61 echo Validating $$p with grammar$$i ; \${JAVA} -jar ${JING} grammar$$i.rng $$p ; \done ; done

# fin de Makefile

Grammars/grammar1.rnc

# Première version du langage étudié: ILP1 pour « Innocent Langage# Parachuté. » Il sera complété dans les cours qui suivent.

start = programme15

programme1 = element programme1 {instruction +

}

10 # Ce langage est un langage d’instructions, assez réduit pour# l’instant. Voici les instructions possibles:

instruction =alternative

15 | sequence| blocUnaire| expression

# Le si-alors-sinon. L’alternant est facultatif car c’est un langage20 # d’instructions.

alternative = element alternative {element condition { expression },element consequence { instruction + },

25 element alternant { instruction + } ?}

# La séquence qui permet de regrouper plusieurs instructions en une seule.# Il est obligatoire qu’il y ait au moins une instruction dans la séquence.

30

sequence = element sequence {instruction +

}

35 # Un bloc local unaire. C’est, pour l’instant, la seule construction# permettant d’introduire une variable localement. Elle sera bientôt remplacée# par une construction permettant d’introduire plusieurs variables# locales en meme temps.

40 blocUnaire = element blocUnaire {variable,element valeur { expression },element corps { instruction + }

}45

# Comme en C, une expression est une instruction dont la valeur est# ignorée. Il n’y a pas d’expression parenthésée car ce n’est qu’une# fioriture syntaxique. Les expressions sont:

50 expression =constante

| variable| operation| invocationPrimitive

55

# Une variable n’est caractérisée que par son nom. Les variables dont# les noms comportent la séquence ilp ou ILP sont réservés et ne# peuvent être utilisés par les programmeurs.

13

Page 8: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

# FUTUR: restreindre plus les noms de variables aux seuls caracteres normaux!60

variable = element variable {attribute nom { xsd:Name - ( xsd:Name { pattern = "(ilp|ILP)" } ) },empty

}65

# L’invocation d’une fonction primitive. Une fonction primitive est# procurée par l’implantation et ne peut (usuellement) être définie# par l’utilisateur. Les fonctions primitives sont, pour être# utilisables, prédéfinies. Une fonction primitive n’est caractérisée

70 # que par son nom (éventuellement masquable).

invocationPrimitive = element invocationPrimitive {attribute fonction { xsd:Name },expression *

75 }

# Les opérations sont en fait des sortes d’invocations à des fonctions# primitives sauf que ces fonctions sont implantées par le matériel# par des instructions particulières. On ne distingue que les

80 # opérations unaires et binaires (les plus usuelles):

operation =operationUnaire

| operationBinaire85

operationUnaire = element operationUnaire {attribute operateur { "-" | "!" },element operande { expression }

}90 operationBinaire = element operationBinaire {

element operandeGauche { expression },attribute operateur {

"+" | "-" | "*" | "/" | "%" | # arithmétiques"|" | "&" | "^" | # booléens

95 "<" | "<=" | "==" | ">=" | ">" | "<>" | "!=" # comparaisons},element operandeDroit { expression }

}

100 # Les constantes sont les données qui peuvent apparaître dans les# programmes sous forme textuelle (ou littérale comme l’on dit# souvent). Ici l’on trouve toutes les constantes usuelles à part les# caractères:

105 constante =element entier {attribute valeur { xsd:integer },empty }

| element flottant {110 attribute valeur { xsd:float },

empty }| element chaine { text }| element booleen {

attribute valeur { "true" | "false" },115 empty }

# fin.

Java/jars/JARS.readme

Ce répertoire contient des archives .jar contenant les classes et ressourcesutiles pour les bibliothèques telles que jing ou trang. Les paquets .tgz

3 ou .zip contiennent les distributions originales et notamment la documentationdes interfaces (API).

Les bibliothèques vraiment importantes sontjing.jar

8 trang.jarxmlunit1.0.jar

Les bibliothèques Junit (3 et 4) à utiliser sont celles fournies par Eclipse.

13 Les documentations (Javadoc) de jing et trang sont dans le .zip demême nom. Il faut indiquer à Eclipse où elles sont pour l’aidecontextuelle.

14

Les autres bibliothèques sont les suivantes18 hansel une bibliothèque pour mesurer les taux de couverture de test

bcel une bibliothèque d’instrumentation de code octet utiliséepar hansel

groovy un langage de script dont je me servirai peut-être un jourpour des extensions dynamiques.

23 easymock une bibliothèque pour aider aux tests.freemarker une bibliothèque de patrons à instancier

#fin.

Java/src/fr/upmc/ilp/ilp1/interfaces/IAST.java

package fr.upmc.ilp.ilp1.interfaces;

/** Interface des arbres de syntaxe abstraite.4 *

* Les arbres de syntaxe abstraite (AST) ne sont utilisés que via* cette interface ou, plus exactement, via une de ses* sous-interfaces. Cette interface ressemble un peu à celle du DOM* (Document Object Model) sauf qu’elle est beaucoup plus légère: elle

9 * est plus typée mais elle ne permet que de descendre dans les AST.** La raison d’être de cette interface est qu’elle sert de point de* rencontre entre les analyseurs syntaxiques qui doivent produire des* IAST qui seront ainsi manipulables par les premières passes de

14 * l’interprète ou du compilateur.*/

public interface IAST {

19 /** Décrit l’AST sous forme d’une chaîne imprimable.** En fait, c’était pour mettre quelque chose (ce qui n’est pas* obligatoire) ! Cette méthode vient avec toute implantation* puisque l’objet implantant hérite d’Object qui définit

24 * toString()! Par contre, la mentionner ici rend sa définition* explicite obligatoire dans les classes qui implantent IAST.*/

String toString ();

29 // FUTURE ajoute-t-on toXML() pour sérialiser les IAST ?

}

Java/src/fr/upmc/ilp/ilp1/interfaces/IASTalternative.java

package fr.upmc.ilp.ilp1.interfaces;

3 /** Décrit une alternative (si-alors-sinon).** Une alternative comporte une condition (booléenne), une conséquence* (une expression quelconque) ainsi, éventuellement, qu’un alternant* (une expression aussi). La méthode isTernary() permet de distinguer

8 * entre ces deux cas.*/

public interface IASTalternative<Exc extends Throwable> extends IAST {

13 /** Renvoie la condition. */IAST getCondition ();

/** Renvoie la conséquence. */IAST getConsequent ();

18

/** Renvoie l’alternant si présent.** @throws Exc lorsqu’un tel argument n’existe pas.*/

23 IAST getAlternant () throws Exc;

/** Indique si l’alternative est ternaire (qu’elle a un alternant). */boolean isTernary ();

}

Java/src/fr/upmc/ilp/ilp1/interfaces/IASTbinaryOperation.java15

Page 9: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

package fr.upmc.ilp.ilp1.interfaces;2

/** Interface décrivant les opérations binaires.** Cette interface hérite de celle des opérations qui permet l’accès* à l’opérateur et à la liste des opérandes.

7 */

public interface IASTbinaryOperation extends IASToperation {

/** renvoie l’opérande de gauche. */12 IAST getLeftOperand ();

/** renvoie l’opérande de droite. */IAST getRightOperand ();

}

Java/src/fr/upmc/ilp/ilp1/interfaces/IASTboolean.java

package fr.upmc.ilp.ilp1.interfaces;

3 /** Decrit la citation d’un booleen. */

public interface IASTboolean extends IASTconstant {

/** Renvoie le booleen cite. */8 boolean getValue ();

}

Java/src/fr/upmc/ilp/ilp1/interfaces/IASTconstant.java

1 package fr.upmc.ilp.ilp1.interfaces;

/** Decrit une constante litterale. Cette interface n’existe que pour* etre raffinee en des sous-interfaces plus specialisees. */

6 public interface IASTconstant extends IAST {}

Java/src/fr/upmc/ilp/ilp1/interfaces/IASTfloat.java

package fr.upmc.ilp.ilp1.interfaces;

3 import java.math.BigDecimal;

/** Citation d’un flottant. */

public interface IASTfloat extends IASTconstant {8

/** Renvoie le flottant cité comme constante. */BigDecimal getValue ();

}

Java/src/fr/upmc/ilp/ilp1/interfaces/IASTinteger.java

package fr.upmc.ilp.ilp1.interfaces;

import java.math.BigInteger;4

/** Citation d’un entier. */

public interface IASTinteger extends IASTconstant {

9 /** Renvoie l’entier cite comme constante. */BigInteger getValue ();

}

Java/src/fr/upmc/ilp/ilp1/interfaces/IASTinvocation.java

16

package fr.upmc.ilp.ilp1.interfaces;

4 /** Décrit une invocation de fonction. La fonction peut être calculée* ou pas, c’est néanmoins un AST. Si le nom n’est pas calculée, c’est* une référence à un nom de variable (car, en JavaScript, les* fonctions sont dans le même espace de nom).*/

9

public interface IASTinvocation<Exc extends Throwable> extends IAST {

/** Renvoie la fonction invoquée. */IAST getFunction ();

14

/** Renvoie les arguments de l’invocation sous forme d’une liste. */IAST[] getArguments ();

/** Renvoie le nombre d’arguments de l’invocation. */19 int getArgumentsLength ();

/** Renvoie le i-ème argument de l’invocation.** @throws ILPException lorsqu’un tel argument n’existe pas.

24 */IAST getArgument (int i) throws Exc;

}

Java/src/fr/upmc/ilp/ilp1/interfaces/IASToperation.java

package fr.upmc.ilp.ilp1.interfaces;2

/** Interface décrivant les opérations.** Une opération implique un opérateur et un ou plusieurs opérandes.

7 * Les opérations peuvent être unaires ou binaires cf. les* sous-interfaces appropriées.*/

public interface IASToperation extends IAST {12

/** Renvoie le nom de l’opérateur concerné par l’opération. */String getOperatorName ();

/** Renvoie l’arité de l’opérateur concerné par l’opération. L’arité17 * est toujours de 1 pour une IASTunaryOperation et de 2 pour une

* IASTbinaryOperation. */int getArity ();

/** Renvoie les opérandes d’une opération.22 *

* NOTA: cette méthode est générale, les méthodes d’accès aux* opérandes des opérations unaires ou binaires sont, probablement,* plus efficaces.*

27 * NOTA2: normalement le nombre d’operandes doit être égal à l’arité* de l’opérateur (mais il se peut que certains opérateurs soit n-aires)* auquel cas, que l’arité soit un simple entier n’est pas une bonne idée!*/

IAST[] getOperands ();32

}

Java/src/fr/upmc/ilp/ilp1/interfaces/IASTsequence.java

1 package fr.upmc.ilp.ilp1.interfaces;

/** Décrit une séquence d’instructions. On reprend le même* style d’interface que IASTinvocation. */

6

public interface IASTsequence<Exc extends Throwable> extends IAST {

/** Renvoie la séquence des instructions contenues. */IAST[] getInstructions ();

1117

Page 10: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

/** Renvoie le nombre d’instructions de la sequence. */int getInstructionsLength ();

/** Renvoie la i-ème instruction.16 *

* @throws Exc lorsqu’un tel argument n’existe pas. */IAST getInstruction (int i) throws Exc;

// FUTURE ? ajouter getAllButLastInstructions() ???21 }

Java/src/fr/upmc/ilp/ilp1/interfaces/IASTstring.java

package fr.upmc.ilp.ilp1.interfaces;

3 /** Citation d’une chaine de caracteres.*/

public interface IASTstring extends IASTconstant {

/** Renvoie la chaine de caracteres citee. */8 String getValue ();

}

Java/src/fr/upmc/ilp/ilp1/interfaces/IASTunaryBlock.java

package fr.upmc.ilp.ilp1.interfaces;

/** Décrit un bloc local ne liant qu’une unique variable. */

5 public interface IASTunaryBlock<Exc extends Throwable> extends IAST {

/** Renvoie la variable liée localement. */IASTvariable getVariable();

10 /** Renvoie l’expression initialisant la variable locale. */IAST getInitialization();

/** Renvoie la sequence d’instructions présentes dans le corps du* bloc local. */

15 IASTsequence<Exc> getBody();}

Java/src/fr/upmc/ilp/ilp1/interfaces/IASTunaryOperation.java

package fr.upmc.ilp.ilp1.interfaces;

3 /** Interface décrivant les opérations unaires. */

public interface IASTunaryOperation extends IASToperation {

/** renvoie l’unique operande. */8 IAST getOperand ();

}

Java/src/fr/upmc/ilp/ilp1/interfaces/IASTvariable.java

1 package fr.upmc.ilp.ilp1.interfaces;

/*** Cette interface décrit une variable mais seulement une variable. D’autres* interfaces existent pour lire ou écrire des variables. Usuellement, les

6 * variables n’apparaissent que dans des lieurs (fonctions, methodes ou blocs* locaux).*/

public interface IASTvariable extends IAST {11

/** Renvoie le nom de la variable. */String getName();

}

18

Java/src/fr/upmc/ilp/ilp1/fromxml/AST.java

1 package fr.upmc.ilp.ilp1.fromxml;import fr.upmc.ilp.ilp1.interfaces.*;

public abstract class AST implements IAST {

6 /** Décrit l’AST en XML (surtout utile pour la mise au point).** NOTA: cette signature conduit à une implantation naïve* déraisonnablement coûteuse! Il vaudrait mieux se trimballer un* unique StringBuffer dans lequel concaténer les fragments XML.

11 */

public abstract String toXML ();

}

Java/src/fr/upmc/ilp/ilp1/fromxml/ASTException.java

package fr.upmc.ilp.ilp1.fromxml;

/** Une exception comme les autres mais qu’utilisent préférentiellement4 * les classes du paquetage fromxml.

*/

public class ASTException extends Exception {

9 static final long serialVersionUID = +1234567890001000L;

public ASTException (Throwable cause) {super(cause);

}14

public ASTException (String message) {super(message);

}

19 }

Java/src/fr/upmc/ilp/ilp1/fromxml/ASTParser.java

package fr.upmc.ilp.ilp1.fromxml;import java.util.List;import java.util.Vector;

5 import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.Node;import org.w3c.dom.NodeList;

10 /** Le but de cette classe est de transformer un document XML en un* AST conforme à fr.upmc.ilp.interfaces.IAST. */

public class ASTParser {

15 /** Constructeur. */

public ASTParser () {}

/** Transformer un document (ou un nœud) DOM en un AST (et donc un20 * IAST).

** C’est une grande méthode monolithique qui analyse le DOM (une* structure de données arborescente correspondant au document XML* initial) en un AST où chaque nœud est typé suivant sa catégorie

25 * syntaxique. Il est difficile d’avoir un style objet sur ce type* de code qui correspond à une construction. Nous verrons une* nouvelle organisation de ce code bientôt.** @throws ASTException en cas de problème.

30 * NOTA: comme le document d’entrée est supposé être valide pour le* schéma RelaxNG approprié, de nombreux risques d’erreur sont ainsi* éliminés et ne sont donc pas explicitement testés. Par exemple,* le fait qu’un fils « condition » apparaît toujours sous «* alternative, » que l’attribut « valeur » est présent dans «

19

Page 11: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

35 * entier, » etc. Tous ces faits sont assumés corrects.*/

public AST parse (Node n)throws ASTException {

40 switch ( n.getNodeType() ) {

case Node.DOCUMENT_NODE: {Document d = (Document) n;return this.parse(d.getDocumentElement());

45 }

case Node.ELEMENT_NODE: {Element e = (Element) n;NodeList nl = e.getChildNodes();

50 String name = e.getTagName();

if ( "programme1".equals(name) ) {return new ASTsequence(parseList(nl));

55 } else if ( "alternative".equals(name) ) {AST cond = findThenParseChild(nl, "condition");AST conseq = findThenParseChildAsInstructions(nl, "consequence");try {

AST alt = findThenParseChildAsInstructions(nl, "alternant");60 return new ASTalternative(cond, conseq, alt);

} catch (ASTException exc) {return new ASTalternative(cond, conseq);

}

65 } else if ( "sequence".equals(name) ) {return new ASTsequence(this.parseList(nl));

} else if ( "blocUnaire".equals(name) ) {ASTvariable var = (ASTvariable) findThenParseChild(nl, "variable");

70 AST init = findThenParseChild(nl, "valeur");ASTsequence body = (ASTsequence) findThenParseChild(nl, "corps");return new ASTblocUnaire(var, init, body);

} else if ( "variable".equals(name) ) {75 // La variable sera, suivant les contextes, encapsulée

// dans une référence.String nick = e.getAttribute("nom");return new ASTvariable(nick);

80 } else if ( "invocationPrimitive".equals(name) ) {String op = e.getAttribute("fonction");List<AST> largs = parseList(nl);return new ASTinvocationPrimitive(op, largs.toArray(new AST[0]));

85 } else if ( "operationUnaire".equals(name) ) {String op = e.getAttribute("operateur");AST rand = findThenParseChild(nl, "operande");return new ASToperationUnaire(op, rand);

90 } else if ( "operationBinaire".equals(name) ) {String op = e.getAttribute("operateur");AST gauche = findThenParseChild(nl, "operandeGauche");AST droite = findThenParseChild(nl, "operandeDroit");return new ASToperationBinaire(op, gauche, droite);

95

} else if ( "entier".equals(name) ) {return new ASTentier(e.getAttribute("valeur"));

} else if ( "flottant".equals(name) ) {100 return new ASTflottant(e.getAttribute("valeur"));

} else if ( "chaine".equals(name) ) {String text = e.getTextContent();return new ASTchaine(text);

105

} else if ( "booleen".equals(name) ) {return new ASTbooleen(e.getAttribute("valeur"));

// Une série d’éléments devant être analysés comme des expressions:110 } else if ( "operandeGauche".equals(name) ) {

return this.parseUniqueChild(nl);} else if ( "operandeDroit".equals(name) ) {

return this.parseUniqueChild(nl);} else if ( "operande".equals(name) ) {

115 return this.parseUniqueChild(nl);} else if ( "condition".equals(name) ) {

20

return this.parseUniqueChild(nl);} else if ( "consequence".equals(name) ) {

return this.parseUniqueChild(nl);120 } else if ( "alternant".equals(name) ) {

return this.parseUniqueChild(nl);} else if ( "valeur".equals(name) ) {

return this.parseUniqueChild(nl);

125 // Une série d’éléments devant être analysée comme une séquence:} else if ( "corps".equals(name) ) {

return new ASTsequence(this.parseList(nl));

} else {130 String msg = "Unknown element name: " + name;

throw new ASTException(msg);}

}

135 default: {String msg = "Unknown node type: " + n.getNodeName();throw new ASTException(msg);

}}

140 }

/** Analyser une séquence d’éléments pour en faire un ASTlist* c’est-à-dire une séquence d’AST.*/

145

protected List<AST> parseList (NodeList nl)throws ASTException {List<AST> result = new Vector<AST>();int n = nl.getLength();

150 LOOP:for ( int i = 0 ; i<n ; i++ ) {

Node nd = nl.item(i);switch ( nd.getNodeType() ) {

155 case Node.ELEMENT_NODE: {AST p = this.parse(nd);result.add(p);continue LOOP;

}160

default: {// On ignore tout ce qui n’est pas élément XML:

}}

165 }return result;

}

/** Trouver un élément d’après son nom et l’analyser pour en faire170 * un AST.

** @throws ASTException* lorsqu’un tel élément n’est pas trouvé.*/

175

protected AST findThenParseChild (NodeList nl, String childName)throws ASTException {int n = nl.getLength();for ( int i = 0 ; i<n ; i++ ) {

180 Node nd = nl.item(i);switch ( nd.getNodeType() ) {

case Node.ELEMENT_NODE: {Element e = (Element) nd;

185 if ( childName.equals(e.getTagName()) ) {return this.parse(e);

};}

190 default: {// On ignore tout ce qui n’est pas élément XML:

}}

}195 String msg = "No such child element " + childName;

throw new ASTException(msg);}

21

Page 12: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

/** Trouver un élément d’après son nom et analyser son contenu pour200 * en faire un ASTsequence.

** @throws ASTException* lorsqu’un tel élément n’est pas trouvé.*/

205

protected ASTsequence findThenParseChildAsInstructions (NodeList nl, String childName)

throws ASTException {int n = nl.getLength();

210 for ( int i = 0 ; i<n ; i++ ) {Node nd = nl.item(i);switch ( nd.getNodeType() ) {

case Node.ELEMENT_NODE: {215 Element e = (Element) nd;

if ( childName.equals(e.getTagName()) ) {return new ASTsequence(this.parseList(e.getChildNodes()));

};}

220

default: {// On ignore tout ce qui n’est pas élément XML:

}}

225 }String msg = "No such child element " + childName;throw new ASTException(msg);

}

230 /** Analyser une suite comportant un unique élément.** @throws ASTException* lorsque la suite ne contient pas exactement un seul élément.*/

235

protected AST parseUniqueChild (NodeList nl)throws ASTException {AST result = null;

int n = nl.getLength();240 for ( int i = 0 ; i<n ; i++ ) {

Node nd = nl.item(i);switch ( nd.getNodeType() ) {

case Node.ELEMENT_NODE: {245 Element e = (Element) nd;

if ( result == null ) {result = this.parse(e);

} else {String msg = "Non unique child";

250 throw new ASTException(msg);}

}

default: {255 // On ignore tout ce qui n’est pas élément XML:

}}

}if ( result == null ) {

260 throw new ASTException("No child at all");};return result;

}

265 }

Java/src/fr/upmc/ilp/ilp1/fromxml/ASTParserTest.java

package fr.upmc.ilp.ilp1.fromxml;

import org.custommonkey.xmlunit.XMLTestCase;4

import fr.upmc.ilp.ilp1.interfaces.IAST;import fr.upmc.ilp.ilp1.interfaces.IASTbinaryOperation;import fr.upmc.ilp.ilp1.interfaces.IASTboolean;import fr.upmc.ilp.ilp1.interfaces.IASTfloat;

9 import fr.upmc.ilp.ilp1.interfaces.IASTinteger;import fr.upmc.ilp.ilp1.interfaces.IASTinvocation;

22

import fr.upmc.ilp.ilp1.interfaces.IASTsequence;import fr.upmc.ilp.ilp1.interfaces.IASTstring;import fr.upmc.ilp.ilp1.interfaces.IASTunaryBlock;

14 import fr.upmc.ilp.ilp1.interfaces.IASTunaryOperation;

/** Tests (JUnit) simples d’equivalence depuis XML -> AST -> XML. */

public class ASTParserTest extends XMLTestCase {19

public void testEntier () throws ASTException {String program = "<entier valeur=’34’/>";AST a = ASTfromXML.toAST(program);assertEquals(program, a.toXML());

24 assertTrue(a instanceof fr.upmc.ilp.ilp1.fromxml.ASTentier);IASTinteger iast = (IASTinteger) a;assertEquals(34, iast.getValue().intValue());

}

29 public void testEntierNeg () throws ASTException {String program = "<entier valeur=’-34’/>";AST a = ASTfromXML.toAST(program);assertEquals(program, a.toXML());assertTrue(a instanceof fr.upmc.ilp.ilp1.fromxml.ASTentier);

34 IASTinteger iast = (IASTinteger) a;assertEquals(-34, iast.getValue().intValue());

}

public void testFlottant () throws ASTException {39 String program = "<flottant valeur=’3.14’/>";

AST a = ASTfromXML.toAST(program);assertEquals(program, a.toXML());assertTrue(a instanceof fr.upmc.ilp.ilp1.fromxml.ASTflottant);IASTfloat iast = (IASTfloat) a;

44 assertEquals(3.14, iast.getValue().doubleValue(), 0.01);}

public void testFlottantExp () throws ASTException {String program = "<flottant valeur=’-3.14e+3’/>";

49 AST a = ASTfromXML.toAST(program);//assertEquals(program, a.toXML()); // Pas la meme forme en sortie!assertTrue(a instanceof fr.upmc.ilp.ilp1.fromxml.ASTflottant);IASTfloat iast = (IASTfloat) a;assertEquals(-3140, iast.getValue().doubleValue(), 0.01);

54 }

public void testBoolTrue () throws ASTException {String program = "<booleen valeur=’true’/>";AST a = ASTfromXML.toAST(program);

59 assertEquals(program, a.toXML());assertTrue(a instanceof fr.upmc.ilp.ilp1.fromxml.ASTbooleen);IASTboolean iast = (IASTboolean) a;assertEquals(true, iast.getValue());

}64

public void testBoolFalse () throws ASTException {String program = "<booleen valeur=’false’/>";AST a = ASTfromXML.toAST(program);assertEquals(program, a.toXML());

69 assertTrue(a instanceof fr.upmc.ilp.ilp1.fromxml.ASTbooleen);IASTboolean iast = (IASTboolean) a;assertEquals(false, iast.getValue());

}

74 public void testChaine () throws ASTException {String program = "<chaine>foobar</chaine>";AST a = ASTfromXML.toAST(program);assertEquals(program, a.toXML());assertTrue(a instanceof fr.upmc.ilp.ilp1.fromxml.ASTchaine);

79 IASTstring iast = (IASTstring) a;assertEquals("foobar", iast.getValue());

}

// {{{84 // Bogue signalée par Jacques Malenfant <[email protected]>:

// les conditions et consequences étaient incapables de prendre// plusieurs instructions! On en profite pour utiliser XMLUnit// signalé par Jérémy Bobbio <[email protected]>

89 public void testAlternativeTernaire () throws Exception {String program = "<alternative>"

+ "<condition><booleen valeur=’true’/></condition>"+ "<consequence><entier valeur=’1’/></consequence>"

23

Page 13: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

+ "<alternant><chaine>foobar</chaine></alternant>"94 + "</alternative>";

AST a = ASTfromXML.toAST(program);String result = a.toXML();//System.err.println(result);//assertEquals(program, result);

99 assertXpathExists("/alternative", result);assertXpathExists("/alternative/condition", result);assertXpathExists("/alternative/condition/booleen", result);assertXpathExists("/alternative/consequence/sequence/entier", result);assertXpathValuesEqual("1",

104 "/alternative/consequence/sequence/entier/@valeur",result);

assertXpathExists("/alternative/alternant/sequence/chaine", result);assertXpathValuesEqual("foobar",

"/alternative/consequence/sequence/chaine",109 result);

assertTrue(a instanceof fr.upmc.ilp.ilp1.fromxml.ASTalternative);ASTalternative iast = (ASTalternative) a;assertXMLEqual("<booleen valeur=’true’/>",

((AST)iast.getCondition()).toXML());114 assertXMLEqual("<sequence><entier valeur=’1’/></sequence>",

((AST)iast.getConsequent()).toXML());assertXMLEqual("<sequence><chaine>foobar</chaine></sequence>",

((AST)iast.getAlternant()).toXML());}

119

public void testAlternativeBinaire () throws Exception {String program = "<alternative>"

+ "<condition><booleen valeur=’true’/></condition>"+ "<consequence><entier valeur=’1’/></consequence>"

124 + "</alternative>";AST a = ASTfromXML.toAST(program);String result = a.toXML();//assertEquals(program, a.toXML());assertTrue(a instanceof fr.upmc.ilp.ilp1.fromxml.ASTalternative);

129 ASTalternative iast = (ASTalternative) a;assertXMLEqual("<booleen valeur=’true’/>",

((AST)iast.getCondition()).toXML());assertXMLEqual("<sequence><entier valeur=’1’/></sequence>",

((AST)iast.getConsequent()).toXML());134 assertXpathExists("/alternative/consequence", result);

assertXpathExists("/alternative/consequence/sequence", result);assertXpathExists("/alternative/consequence/sequence/entier", result);assertXpathNotExists("/alternative/alternant", result);try {

139 iast.getAlternant();} catch (ASTException exc) {

assertTrue(true);}

}144

public void testAlternativeWithConsequences () throws ASTException {String program = "<alternative>"

+ "<condition><booleen valeur=’true’/></condition>"+ "<consequence><entier valeur=’1’/><entier valeur=’11’/></consequence>"

149 + "</alternative>";AST a = ASTfromXML.toAST(program);assertTrue(a instanceof fr.upmc.ilp.ilp1.fromxml.ASTalternative);IAST c = ((ASTalternative) a).getConsequent();assertTrue(c instanceof fr.upmc.ilp.ilp1.fromxml.ASTsequence);

154 assertEquals(2, ((ASTsequence) c).getInstructions().length);}

public void testAlternativeWithAlternants () throws Exception {String program = "<alternative>"

159 + "<condition><booleen valeur=’true’/></condition>"+ "<consequence><entier valeur=’1’/><entier valeur=’11’/></consequence>"+ "<alternant><chaine>foo</chaine><chaine>bar</chaine></alternant>"+ "</alternative>";

AST a = ASTfromXML.toAST(program);164 assertTrue(a instanceof fr.upmc.ilp.ilp1.fromxml.ASTalternative);

IAST c = ((ASTalternative) a).getConsequent();assertTrue(c instanceof fr.upmc.ilp.ilp1.fromxml.ASTsequence);assertEquals(2, ((ASTsequence) c).getInstructions().length);String result = a.toXML();

169 assertXpathExists("/alternative", result);assertXpathExists("/alternative/consequence", result);assertXpathExists("/alternative/consequence/sequence", result);assertXpathExists("/alternative/consequence/sequence/entier[@valeur=’1’]",

result);174 assertXpathExists("/alternative/consequence/sequence/entier[@valeur=’11’]",

24

result);assertXpathExists("/alternative/alternant", result);assertXpathExists("/alternative/alternant/sequence", result);assertXpathEvaluatesTo("2",

179 "count(/alternative/alternant/sequence/chaine)",result);

}

// }}}184

public void testSequence () throws ASTException {String program = "<sequence>"

+ "<booleen valeur=’true’/>"+ "<entier valeur=’1’/>"

189 + "</sequence>";AST a = ASTfromXML.toAST(program);assertEquals(program, a.toXML());assertTrue(a instanceof fr.upmc.ilp.ilp1.fromxml.ASTsequence);IASTsequence<ASTException> iast = (ASTsequence) a;

194 IAST[] iastlist = iast.getInstructions();assertNotNull(iastlist);assertTrue(iastlist.length == 2);IAST e1 = iastlist[0];assertEquals("<booleen valeur=’true’/>", ((AST)e1).toXML());

199 IAST e2 = iastlist[1];assertEquals("<entier valeur=’1’/>", ((AST)e2).toXML());

}

public void testSequenceOne () throws ASTException {204 String program = "<sequence>"

+ "<entier valeur=’1’/>"+ "</sequence>";

AST a = ASTfromXML.toAST(program);assertEquals(program, a.toXML());

209 assertTrue(a instanceof fr.upmc.ilp.ilp1.fromxml.ASTsequence);IASTsequence<ASTException> iast = (ASTsequence) a;IAST[] iastlist = iast.getInstructions();assertNotNull(iastlist);assertTrue(iastlist.length == 1);

214 IAST e1 = iastlist[0];assertEquals("<entier valeur=’1’/>", ((AST)e1).toXML());

}

public void testSequenceEmpty () throws ASTException {219 String program = "<sequence>"

+ "</sequence>";AST a = ASTfromXML.toAST(program);assertEquals(program, a.toXML());assertTrue(a instanceof fr.upmc.ilp.ilp1.fromxml.ASTsequence);

224 IASTsequence<ASTException> iast = (ASTsequence) a;IAST[] iastlist = iast.getInstructions();assertNotNull(iastlist);assertTrue(iastlist.length == 0);

}229

public void testVariable () throws ASTException {String program = "<variable nom=’foo’/>";AST a = ASTfromXML.toAST(program);assertEquals(program, a.toXML());

234 assertTrue(a instanceof fr.upmc.ilp.ilp1.fromxml.ASTvariable);assertTrue(a instanceof fr.upmc.ilp.ilp1.interfaces.IASTvariable);ASTvariable var = (ASTvariable) a;assertEquals("foo", var.getName());

}239

public void testBlocUnaire () throws ASTException {String program = "<blocUnaire>"

+ "<variable nom=’foo’/>"+ "<valeur><entier valeur=’11’/></valeur>"

244 + "<corps><variable nom=’bar’/></corps>"+ "</blocUnaire>";

AST a = ASTfromXML.toAST(program);//assertEquals(program, a.toXML());assertTrue(a instanceof fr.upmc.ilp.ilp1.fromxml.ASTblocUnaire);

249 IASTunaryBlock<ASTException> iast = (ASTblocUnaire) a;assertTrue(iast instanceof fr.upmc.ilp.ilp1.interfaces.IASTunaryBlock);assertEquals("<variable nom=’foo’/>",

((AST)iast.getVariable()).toXML());assertEquals("<entier valeur=’11’/>",

254 ((AST)iast.getInitialization()).toXML());//System.err.println(iast.getBody().toXML());assertEquals("<sequence><variable nom=’bar’/></sequence>",

25

Page 14: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

((AST)iast.getBody()).toXML());}

259

public void testInvocationPrimitive2 () throws ASTException {String program = "<invocationPrimitive fonction=’xy’>"

+ "<variable nom=’foo’/>"+ "<entier valeur=’11’/>"

264 + "</invocationPrimitive>";AST a = ASTfromXML.toAST(program);//assertEquals(program, a.toXML());assertTrue(a instanceof fr.upmc.ilp.ilp1.fromxml.ASTinvocationPrimitive);IASTinvocation<ASTException> iast = (ASTinvocation) a;

269 assertTrue(iast instanceof fr.upmc.ilp.ilp1.interfaces.IASTinvocation);assertEquals(2, iast.getArgumentsLength());assertEquals("<variable nom=’xy’/>",

((AST)iast.getFunction()).toXML());IAST[] iastlist = iast.getArguments();

274 assertTrue(iastlist.length == 2);IAST e1 = iastlist[0];assertEquals("<variable nom=’foo’/>", ((AST)e1).toXML());assertEquals("<variable nom=’foo’/>",

((AST)iast.getArgument(0)).toXML());279 IAST e2 = iastlist[1];

assertEquals("<entier valeur=’11’/>", ((AST)e2).toXML());assertEquals("<entier valeur=’11’/>",

((AST)iast.getArgument(1)).toXML());}

284

public void testInvocationPrimitive1 () throws ASTException {String program = "<invocationPrimitive fonction=’xy’>"

+ "<entier valeur=’11’/>"+ "</invocationPrimitive>";

289 AST a = ASTfromXML.toAST(program);//assertEquals(program, a.toXML());assertTrue(a instanceof fr.upmc.ilp.ilp1.fromxml.ASTinvocationPrimitive);IASTinvocation<ASTException> iast = (ASTinvocation) a;assertTrue(iast instanceof fr.upmc.ilp.ilp1.interfaces.IASTinvocation);

294 assertEquals(1, iast.getArgumentsLength());assertEquals("<variable nom=’xy’/>",

((AST)iast.getFunction()).toXML());IAST[] iastlist = iast.getArguments();assertTrue(iastlist.length == 1);

299 IAST e1 = iastlist[0];assertEquals("<entier valeur=’11’/>", ((AST)e1).toXML());assertEquals("<entier valeur=’11’/>",

((AST)iast.getArgument(0)).toXML());}

304

public void testInvocationPrimitive0 () throws ASTException {String program = "<invocationPrimitive fonction=’xy’>"

+ "</invocationPrimitive>";AST a = ASTfromXML.toAST(program);

309 //assertEquals(program, a.toXML());assertTrue(a instanceof fr.upmc.ilp.ilp1.fromxml.ASTinvocationPrimitive);IASTinvocation<ASTException> iast = (ASTinvocation) a;assertTrue(iast instanceof fr.upmc.ilp.ilp1.interfaces.IASTinvocation);assertEquals(0, iast.getArgumentsLength());

314 assertEquals("<variable nom=’xy’/>",((AST)iast.getFunction()).toXML());

IAST[] iastlist = iast.getArguments();assertTrue(iastlist.length == 0);

}319

public void testOperationUnaire () throws ASTException {String program = "<operationUnaire operateur=’-’>"

+ "<operande><entier valeur=’123’/></operande>"+ "</operationUnaire>";

324 AST a = ASTfromXML.toAST(program);assertEquals(program, a.toXML());assertTrue(a instanceof fr.upmc.ilp.ilp1.fromxml.ASToperationUnaire);IASTunaryOperation iast = (IASTunaryOperation) a;assertTrue(iast instanceof fr.upmc.ilp.ilp1.interfaces.IASTunaryOperation);

329 //System.err.println(iast.getOperator().toXML());assertEquals("-", iast.getOperatorName());assertEquals(1, iast.getArity());assertEquals("<entier valeur=’123’/>",

((AST)iast.getOperand()).toXML());334 IAST[] iastlist = iast.getOperands();

assertTrue(iastlist.length == 1);IAST e1 = iastlist[0];assertEquals("<entier valeur=’123’/>", ((AST)e1).toXML());

}26

339

public void testOperationBinaire () throws ASTException {String program = "<operationBinaire operateur=’+’>"

+ "<operandeGauche><entier valeur=’123’/></operandeGauche>"+ "<operandeDroit><entier valeur=’-34’/></operandeDroit>"

344 + "</operationBinaire>";AST a = ASTfromXML.toAST(program);assertEquals(program, a.toXML());assertTrue(a instanceof fr.upmc.ilp.ilp1.fromxml.ASToperationBinaire);IASTbinaryOperation iast = (IASTbinaryOperation) a;

349 assertTrue(iast instanceof fr.upmc.ilp.ilp1.interfaces.IASTbinaryOperation);//System.err.println(iast.getOperator().toXML());assertEquals("+", iast.getOperatorName());assertEquals(2, iast.getArity());assertEquals("<entier valeur=’123’/>",

354 ((AST)iast.getLeftOperand()).toXML());assertEquals("<entier valeur=’-34’/>",

((AST)iast.getRightOperand()).toXML());IAST[] iastlist = iast.getOperands();assertTrue(iastlist.length == 2);

359 AST e1 = (AST) iastlist[0];assertEquals("<entier valeur=’123’/>", e1.toXML());AST e2 = (AST) iastlist[1];assertEquals("<entier valeur=’-34’/>", e2.toXML());

}364

}

Java/src/fr/upmc/ilp/ilp1/fromxml/ASTalternative.java

package fr.upmc.ilp.ilp1.fromxml;import fr.upmc.ilp.ilp1.interfaces.*;

4 /** La représentation des alternatives (binaires ou ternaires). */

public class ASTalternativeextends ASTimplements IASTalternative<ASTException> {

9

public ASTalternative (AST condition,AST consequence,AST alternant ) {

this.condition = condition;14 this.consequence = consequence;

this.alternant = alternant;}

// NOTA: Masquer l’implantation de l’alternative binaire afin19 // d’éviter la propagation de null.

public ASTalternative (AST condition, AST consequence) {this(condition, consequence, null);

}24

private final AST condition;private final AST consequence;private final AST alternant;

29 public IAST getCondition () {return this.condition;

}

public IAST getConsequent () {34 return this.consequence;

}

public IAST getAlternant () throws ASTException {if ( isTernary() ) {

39 return this.alternant;} else {

throw new ASTException("No alternant");}

}44

/** Vérifie que l’alternative est ternaire c’est-à-dire qu’elle a unvéritable alternant. */

public boolean isTernary () {49 return alternant != null;

}27

Page 15: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

@Overridepublic String toXML () {

54 StringBuffer sb = new StringBuffer();sb.append("<alternative><condition>");sb.append(condition.toXML());sb.append("</condition><consequence>");sb.append(consequence.toXML());

59 sb.append("</consequence>");if ( isTernary() ) {

sb.append("<alternant>");sb.append(alternant.toXML());sb.append("</alternant>");

64 };sb.append("</alternative>");return sb.toString();

}

69 }

Java/src/fr/upmc/ilp/ilp1/fromxml/ASTblocUnaire.java

package fr.upmc.ilp.ilp1.fromxml;import fr.upmc.ilp.ilp1.interfaces.*;

/** Description d’un bloc local pourvu d’une seule variable locale, de5 * l’expression initialisant cette variable locale et d’un corps qui

* est une séquence d’instructions.*/

public class ASTblocUnaire10 extends AST

implements IASTunaryBlock<ASTException> {

public ASTblocUnaire (ASTvariable variable,AST initialization,

15 ASTsequence body){

this.variable = variable;this.initialization = initialization;this.body = body;

20 }

private final ASTvariable variable;private final AST initialization;private final ASTsequence body;

25

public IASTvariable getVariable () {return this.variable;

}public IAST getInitialization () {

30 return this.initialization;}public IASTsequence<ASTException> getBody () {

return this.body;}

35

@Overridepublic String toXML () {

StringBuffer sb = new StringBuffer();sb.append("<blocUnaire>");

40 sb.append(variable.toXML());sb.append("<valeur>");sb.append(initialization.toXML());sb.append("</valeur><corps>");sb.append(body.toXML());

45 sb.append("</corps></blocUnaire>");return sb.toString();

}

}

Java/src/fr/upmc/ilp/ilp1/fromxml/ASTbooleen.java

package fr.upmc.ilp.ilp1.fromxml;import fr.upmc.ilp.ilp1.interfaces.*;

28

/** Une constante booleenne. */5

public class ASTbooleenextends ASTimplements IASTboolean {

10 public ASTbooleen (String valeur) {this.valeur = "true".equals(valeur);

}private final boolean valeur;

15 public boolean getValue () {return valeur;

}

@Override20 public String toXML () {

return "<booleen valeur=’" + valeur + "’/>";}

}

Java/src/fr/upmc/ilp/ilp1/fromxml/ASTchaine.java

package fr.upmc.ilp.ilp1.fromxml;import fr.upmc.ilp.ilp1.interfaces.*;

/** Une constante chaine de caracteres. */5

public class ASTchaineextends ASTimplements IASTstring {

10 public ASTchaine (String valeur) {this.valeur = valeur;

}private final String valeur;

15 public String getValue () {return valeur;

}

@Override20 public String toXML () {

return "<chaine>" + valeur + "</chaine>";}

}

Java/src/fr/upmc/ilp/ilp1/fromxml/ASTentier.java

package fr.upmc.ilp.ilp1.fromxml;import fr.upmc.ilp.ilp1.interfaces.*;

import java.math.BigInteger;5

/** Une constante entière. */

public class ASTentierextends AST

10 implements IASTinteger {

public ASTentier (String valeur) {this.valeur = Integer.parseInt(valeur);this.bigint = new BigInteger(valeur);

15 }private final int valeur;private final BigInteger bigint;

public BigInteger getValue () {20 return bigint;

}

@Overridepublic String toXML () {

25 return "<entier valeur=’" + valeur + "’/>";}

}29

Page 16: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

Java/src/fr/upmc/ilp/ilp1/fromxml/ASTflottant.java

1 package fr.upmc.ilp.ilp1.fromxml;import fr.upmc.ilp.ilp1.interfaces.*;

import java.math.BigDecimal;

6 /** Une constante flottante. */

public class ASTflottantextends ASTimplements IASTfloat {

11

public ASTflottant (String valeur) {this.valeur = Double.parseDouble(valeur);this.bigfloat = new BigDecimal(valeur);

}16 private final double valeur;

private final BigDecimal bigfloat;

public BigDecimal getValue () {return bigfloat;

21 }

@Overridepublic String toXML () {

return "<flottant valeur=’" + valeur + "’/>";26 }

}

Java/src/fr/upmc/ilp/ilp1/fromxml/ASTfromXML.java

1 package fr.upmc.ilp.ilp1.fromxml;

import java.io.StringReader;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;

6 import org.w3c.dom.Document;import org.xml.sax.InputSource;

import fr.upmc.ilp.ilp1.interfaces.IAST;

11 /** Utilitaires pour convertir un fragment d’XML en un AST. Ces* utilitaires sont utiles pour les tests avec JUnit (voir* ASTParserTest.java par exemple).*/

16 public class ASTfromXML {

/** Convertir un fragment d’XML en AST. */

public static AST toAST (String xml)21 throws ASTException {

try {DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();DocumentBuilder db = dbf.newDocumentBuilder();StringReader sr = new StringReader(xml);

26 InputSource is = new InputSource(sr);Document d = db.parse(is);ASTParser ap = new ASTParser();AST ast = ap.parse(d);return ast;

31 } catch (ASTException exc) {throw exc;

} catch (Throwable cause) {throw new ASTException(cause);

}36 }

/** Convertir un fragment d’XML en un IAST. */

public static IAST toIAST (String xml)41 throws ASTException {

return ASTfromXML.toAST(xml);}

}30

Java/src/fr/upmc/ilp/ilp1/fromxml/ASTinvocation.java

package fr.upmc.ilp.ilp1.fromxml;import fr.upmc.ilp.ilp1.interfaces.IASTinvocation;

/** Une invocation mentionne une fonction et des arguments. */5

public class ASTinvocationextends ASTimplements IASTinvocation<ASTException> {

10 public ASTinvocation (AST fonction, AST[] arguments) {this.fonction = fonction;this.argument = arguments;

}private final AST fonction;

15 private final AST[] argument;

public AST getFunction () {return this.fonction;

}20

public AST[] getArguments () {return this.argument;

}

25 public int getArgumentsLength () {return this.argument.length;

}

public AST getArgument (int i) {30 return this.argument[i];

}

@Overridepublic String toXML () {

35 StringBuffer sb = new StringBuffer();sb.append("<invocation><function>");sb.append(fonction.toXML());sb.append("</function>");//sb.append("<arguments>");

40 for ( AST arg : this.argument ) {sb.append(arg.toXML());

}// sb.append("</arguments>");sb.append("</invocation>");

45 return sb.toString();}

}

Java/src/fr/upmc/ilp/ilp1/fromxml/ASTinvocationPrimitive.java

1 package fr.upmc.ilp.ilp1.fromxml;

/** Le cas particulier, parmi les invocations de fonctions,* des primitives.*/

6

public class ASTinvocationPrimitiveextends ASTinvocation {

public ASTinvocationPrimitive (String fonction, AST[] arguments) {11 super(new ASTvariable(fonction), arguments);

}

}

Java/src/fr/upmc/ilp/ilp1/fromxml/ASToperation.java

package fr.upmc.ilp.ilp1.fromxml;

/** La classe abstraite des opérations.

5 * Il y en a deux sortes: les unaires et les binaires.*/ 31

Page 17: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

public abstract class ASToperationextends AST

10 {protected ASToperation (String operateur, int arity) {

this.operateur = operateur;this.arity = arity;

}15 private final String operateur;

private final int arity;

public String getOperatorName () {return this.operateur;

20 }

public int getArity () {return this.arity;

}25

}

Java/src/fr/upmc/ilp/ilp1/fromxml/ASToperationBinaire.java

package fr.upmc.ilp.ilp1.fromxml;

3 import java.util.List;import java.util.Vector;

import fr.upmc.ilp.ilp1.interfaces.IAST;import fr.upmc.ilp.ilp1.interfaces.IASTbinaryOperation;

8

/** Opérations binaires. */

public class ASToperationBinaire extends ASToperationimplements IASTbinaryOperation {

13

public ASToperationBinaire(String operateur, AST operandeGauche,AST operandeDroit) {

super(operateur, 2);this.operandeGauche = operandeGauche;

18 this.operandeDroit = operandeDroit;}private final AST operandeGauche;private final AST operandeDroit;

23 public IAST getLeftOperand() {return this.operandeGauche;

}

public IAST getRightOperand() {28 return this.operandeDroit;

}

public IAST[] getOperands() {// On calcule paresseusement car ce n’est pas une méthode usuelle:

33 if (operands == null) {List<AST> loperands = new Vector<AST>();loperands.add(operandeGauche);loperands.add(operandeDroit);operands = loperands.toArray(new AST[0]);

38 };return operands;

}

// NOTA: remarquer que ce mode paresseux interdit de qualifier ce43 // champ de « final » ce qui n’est pas sûr!

private IAST[] operands;

@Overridepublic String toXML() {

48 StringBuffer sb = new StringBuffer();// Comme signalé par [email protected], il faudrait coder// getOperatorName() pour utiliser les entités &lt; &gt; etc.sb.append("<operationBinaire operateur=’" + getOperatorName() + "’>");sb.append("<operandeGauche>");

53 sb.append(operandeGauche.toXML());sb.append("</operandeGauche><operandeDroit>");sb.append(operandeDroit.toXML());sb.append("</operandeDroit></operationBinaire>");return sb.toString();

32

58 }

}

Java/src/fr/upmc/ilp/ilp1/fromxml/ASToperationUnaire.java

package fr.upmc.ilp.ilp1.fromxml;

import java.util.List;4 import java.util.Vector;

import fr.upmc.ilp.ilp1.interfaces.IAST;import fr.upmc.ilp.ilp1.interfaces.IASTunaryOperation;

9 /** Opérations unaires. */

public class ASToperationUnaire extends ASToperationimplements IASTunaryOperation {

14 public ASToperationUnaire(String operateur, AST operand) {super(operateur, 1);this.operand = operand;

}private final AST operand;

19

public IAST getOperand() {return this.operand;

}

24 public IAST[] getOperands() {// On calcule paresseusement car ce n’est pas une méthode usuelle:if (operands == null) {

List<AST> loperands = new Vector<AST>();loperands.add(operand);

29 operands = loperands.toArray(new AST[0]);};return operands;

}private AST[] operands = null;

34

@Overridepublic String toXML() {

StringBuffer sb = new StringBuffer();sb.append("<operationUnaire operateur=’" + getOperatorName() + "’>");

39 sb.append("<operande>");sb.append(operand.toXML());sb.append("</operande></operationUnaire>");return sb.toString();

}44

}

Java/src/fr/upmc/ilp/ilp1/fromxml/ASTsequence.java

package fr.upmc.ilp.ilp1.fromxml;

import java.util.List;4

import fr.upmc.ilp.ilp1.interfaces.IAST;import fr.upmc.ilp.ilp1.interfaces.IASTsequence;

public class ASTsequence extends AST9 implements IASTsequence<ASTException> {

public ASTsequence(List<AST> instructions) {this.instructions = instructions;

}14 private final List<AST> instructions;

public IAST[] getInstructions() {return this.instructions.toArray(new IAST[0]);

}19

public IAST getInstruction(int i) throws ASTException {return this.instructions.get(i);

}

33

Page 18: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

24 public int getInstructionsLength() {return this.instructions.size();

}

@Override29 public String toXML() {

StringBuffer sb = new StringBuffer("<sequence>");for (AST instruction : this.instructions) {

sb.append(instruction.toXML());}

34 sb.append("</sequence>");return sb.toString();

}

}

Java/src/fr/upmc/ilp/ilp1/fromxml/ASTvariable.java

1 package fr.upmc.ilp.ilp1.fromxml;import fr.upmc.ilp.ilp1.interfaces.*;

/** Description d’une variable. */

6 public class ASTvariableextends ASTimplements IASTvariable {

public ASTvariable (String name) {11 this.name = name;

}private final String name;

public String getName () {16 return name;

}

@Overridepublic String toXML () {

21 return "<variable nom=’" + name + "’/>";}

}

Java/src/fr/upmc/ilp/ilp1/fromxml/Main.java

package fr.upmc.ilp.ilp1.fromxml;import java.io.*;import javax.xml.parsers.*;import org.w3c.dom.*;

5 import org.xml.sax.*;import com.thaiopensource.validate.*;

/** Lit puis évalue un programme. Le langage utilisé est ILP1 défini* par grammar1.rnc

10 ** Usage: java fr.upmc.ilp.fromxml.Main grammaire.rng programme.xml*/

public class Main {15

public static void main (String[] argument)throws ASTException {Main m = new Main(argument);m.run();

20 }

protected Main (String[] argument)throws ASTException {if ( argument.length < 2 ) {

25 throw new ASTException("Usage: Main grammaire.rng programme.xml");};this.rngfile = new File(argument[0]);this.xmlfile = new File(argument[1]);if ( !this.rngfile.exists() ) {

30 throw new ASTException("Fichier .rng introuvable.");};if ( !this.xmlfile.exists() ) {

34

throw new ASTException("Fichier .xml introuvable.");};

35 }

private File rngfile;private File xmlfile;

40 protected void run ()throws ASTException {

try {

45 // (1) validation vis-à-vis de RNG:// MOCHE: c’est redondant avec (2) car le programme est relu encore une// fois avec SAX. Les phases 1 et 2 pourraient s’effectuer ensemble.ValidationDriver vd = new ValidationDriver();InputSource isg = ValidationDriver.fileInputSource(

50 rngfile.getAbsolutePath());vd.loadSchema(isg);InputSource isp = ValidationDriver.fileInputSource(

this.xmlfile.getAbsolutePath());if ( ! vd.validate(isp) ) {

55 throw new ASTException("programme XML non valide");};

// (2) convertir le fichier XML en DOM:DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

60 DocumentBuilder db = dbf.newDocumentBuilder();Document d = db.parse(this.xmlfile);

// (3) conversion vers un AST donc un IAST:ASTParser ap = new ASTParser();

65 AST ast = ap.parse(d);

// (3bis) Impression en XML:System.out.println(ast.toXML());

70 } catch (ASTException e) {throw e;

} catch (Throwable cause) {throw new ASTException(cause);

}75 }

}

Java/src/fr/upmc/ilp/ilp1/fromxml/MainTest.java

package fr.upmc.ilp.ilp1.fromxml;2

import junit.framework.TestCase;

/** Tests (JUnit) simples d’equivalence depuis fichier XML -> AST ->* XML. Tests a completer (notamment pour verifier que l’XML engendre

7 * est valide.*/

public class MainTest extends TestCase {

12 public void processFile (String grammarName, String fileName)throws ASTException {

Main m = new Main(new String[] {grammarName,fileName

17 });m.run();

}

public void testP1 () throws ASTException {22 processFile("Grammars/grammar1.rng",

"Grammars/Samples/p1-1.xml");}

public void testP2 () throws ASTException {27 processFile("Grammars/grammar1.rng",

"Grammars/Samples/p2-1.xml");}

public void testP2un () throws ASTException {32 processFile("Grammars/grammar1.rng",

35

Page 19: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

"Grammars/Samples/p2un-1.xml");}

public void testP3if () throws ASTException {37 processFile("Grammars/grammar1.rng",

"Grammars/Samples/p3if-1.xml");}

public void testP3if2 () throws ASTException {42 processFile("Grammars/grammar1.rng",

"Grammars/Samples/p3if2-1.xml");}

public void testP4seq () throws ASTException {47 processFile("Grammars/grammar1.rng",

"Grammars/Samples/p4seq-1.xml");}

public void testP5let1 () throws ASTException {52 processFile("Grammars/grammar1.rng",

"Grammars/Samples/p5let1-1.xml");}

public void testP6letvar () throws ASTException {57 processFile("Grammars/grammar1.rng",

"Grammars/Samples/p6letvar-1.xml");}

// et tous les programmes u*-1.xml62

}

Java/src/fr/upmc/ilp/ilp1/fromxml/MainTestSuite.java

1 package fr.upmc.ilp.ilp1.fromxml;

import junit.framework.Test;import junit.framework.TestSuite;

6 /** Regroupement de classes de tests pour le paquetage fromxml. */

public class MainTestSuite extends TestSuite {

public static Test suite() {11 TestSuite suite = new TestSuite();

suite.addTest(new TestSuite(ASTParserTest.class));suite.addTest(new TestSuite(MainTest.class));return suite;

}16

}

Java/src/fr/upmc/ilp/ilp1/runtime/AbstractInvokableImpl.java

package fr.upmc.ilp.ilp1.runtime;2

/** Une classe abstraite de fonction qui peut servir de base à des* implantations particulières. Il suffit, si la fonction a moins de* quatre arguments, de définir la méthode invoke appropriée.* @see fr.upmc.ilp.ilp1.runtime.PrintStuff

7 */

public abstract class AbstractInvokableImplimplements Invokable {

12 private static final String WRONG_ARITY ="Wrong arity";

/** Une fonction invoquée avec un nombre quelconque d’arguments. Les* petites arités sont renvoyées sur les méthodes appropriées. */

17

public Object invoke (final Object ... arguments)throws EvaluationException {switch (arguments.length) {case 0: return this.invoke();

22 case 1: return this.invoke(arguments[0]);case 2: return this.invoke(arguments[0], arguments[1]);

36

case 3: return this.invoke(arguments[0], arguments[1], arguments[2]);default: throw new EvaluationException(WRONG_ARITY);}

27 }

/** Invocation d’une fonction zéro-aire (ou niladique) */

public Object invoke ()32 throws EvaluationException {

throw new EvaluationException(WRONG_ARITY);}

/** Invocation d’une fonction unaire (ou monadique) */37

public Object invoke (final Object argument1)throws EvaluationException {throw new EvaluationException(WRONG_ARITY);

}42

/** Invocation d’une fonction binaire (ou dyadique) */

public Object invoke (final Object argument1,final Object argument2)

47 throws EvaluationException {throw new EvaluationException(WRONG_ARITY);

}

/** Invocation d’une fonction ternaire */52

public Object invoke (final Object argument1,final Object argument2,final Object argument3)

throws EvaluationException {57 throw new EvaluationException(WRONG_ARITY);

}

}

Java/src/fr/upmc/ilp/ilp1/runtime/Common.java

package fr.upmc.ilp.ilp1.runtime;import java.math.BigInteger;

4 /** Cette interface définit les caractéristiques globales d’un* interprète du langage ILP1. On y trouve, notamment, la définition* des opérateurs du langage.*/

9 public class Common implements ICommon {

public Common () {}

/** Les opérateurs unaires.14 *

* Comme il n’y a que deux tels opérateurs, leur définition est* intégrée dans cette méthode. */

public Object applyOperator (String opName, Object operand)19 throws EvaluationException {

checkNotNull(opName, 1, operand);

if ( "-".equals(opName) ) {if ( operand instanceof BigInteger ) {

24 BigInteger bi = (BigInteger) operand;return bi.negate();

} else if ( operand instanceof Double ) {double bd = ((Double) operand).doubleValue();return new Double(-bd);

29 } else {return signalWrongType(opName, 1, operand, "number");

}

} else if ( "!".equals(opName) ) {34 if ( operand instanceof Boolean ) {

Boolean b = (Boolean) operand;return Boolean.valueOf( ! b.booleanValue() );

} else {return signalWrongType(opName, 1, operand, "boolean");

39 }

37

Page 20: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

} else {String msg = "Unknown unary operator: " + opName;throw new EvaluationException(msg);

44 }}

/** Les opérateurs binaires.*

49 * Cette méthode n’est qu’un grand aiguillage. */

public Object applyOperator (String opName,Object leftOperand,Object rightOperand)

54 throws EvaluationException{

if ( "+".equals(opName) ) {return operatorPlus(opName, leftOperand, rightOperand);

} else if ( "-".equals(opName) ) {59 return operatorMinus(opName, leftOperand, rightOperand);

// continuer TEMP

} else {64 String msg = "Unknown binary operator: " + opName;

throw new EvaluationException(msg);}

}

69 // Vérifications diverses:

private void checkNotNull (String opName, int rank, Object o)throws EvaluationException {if ( o == null ) {

74 String msg = opName + ": Argument " + rank + " is null!\n"+ "Value is: " + o;

throw new EvaluationException(msg);};

}79

private Object signalWrongType (String opName, int rank, Object o,String expectedType)

throws EvaluationException {String msg = opName + ": Argument " + rank + " is not "

84 + expectedType + "\n" + "Value is: " + o;throw new EvaluationException(msg);

}

// {{{ Les opérateurs binaires:89

/** Le traitement de l’addition. C’est compliqué car il y a de* nombreuses conversions possibles. */

private Object operatorPlus (String opName, Object a, Object b)94 throws EvaluationException {

checkNotNull(opName, 1, a);checkNotNull(opName, 2, b);if ( a instanceof BigInteger ) {

BigInteger bi1 = (BigInteger) a;99 if ( b instanceof BigInteger ) {

BigInteger bi2 = (BigInteger) b;return bi1.add(bi2);

} else if ( b instanceof Double ) {double bd1 = bi1.doubleValue();

104 double bd2 = ((Double) b).doubleValue();return new Double(bd1 + bd2);

} else {return signalWrongType(opName, 2, b, "number");

}109 } else if ( a instanceof Double ) {

Double bd1 = (Double) a;if ( b instanceof Double ) {

Double bd2 = (Double) b;return new Double(bd1.doubleValue() + bd2.doubleValue());

114 } else if ( b instanceof BigInteger ) {BigInteger bi2 = (BigInteger) b;double bd2 = bi2.doubleValue();return new Double(bd1.doubleValue() + bd2);

} else {119 return signalWrongType(opName, 2, b, "number");

}} else {

return signalWrongType(opName, 1, a, "number");38

}124 }

/** Le traitement de la soustraction. Ca ressemble à l’addition. */

private Object operatorMinus (String opName, Object a, Object b)129 throws EvaluationException {

checkNotNull(opName, 1, a);checkNotNull(opName, 2, b);if ( a instanceof BigInteger ) {

BigInteger bi1 = (BigInteger) a;134 if ( b instanceof BigInteger ) {

BigInteger bi2 = (BigInteger) b;return bi1.subtract(bi2);

} else if ( b instanceof Double ) {double bd1 = bi1.doubleValue();

139 double bd2 = ((Double) b).doubleValue();return new Double(bd1 - bd2);

} else {return signalWrongType(opName, 2, b, "number");

}144 } else if ( a instanceof Double ) {

Double bd1 = (Double) a;if ( b instanceof Double ) {

Double bd2 = (Double) b;return new Double(bd1.doubleValue() - bd2.doubleValue());

149 } else if ( b instanceof BigInteger ) {BigInteger bi2 = (BigInteger) b;double bd2 = bi2.doubleValue();return new Double(bd1.doubleValue() - bd2);

} else {154 return signalWrongType(opName, 2, b, "number");

}} else {

return signalWrongType(opName, 1, a, "number");}

159 }

// }}}

}

Java/src/fr/upmc/ilp/ilp1/runtime/CommonPlus.java

1 //// ATTENTION: NE PAS MODIFIER! CETTE CLASSE A ÉTÉ ENGENDRÉE AUTOMATIQUEMENT// A PARTIR DE BinOp.php (voir build.xml pour les détails).

/* ******************************************************************6 * ILP -- Implantation d’un langage de programmation.

* Copyright (C) 2004-2005 <[email protected]>* $Id: BinOp.php 552 2006-11-03 18:18:44Z queinnec $* GPL version>=2* ******************************************************************/

11

package fr.upmc.ilp.ilp1.runtime;

import java.math.BigInteger;

16 /** Cette classe (engendrée par PHP) implante les caractéristiques* générales d’un interprète du langage ILP1. On y trouve, notamment,* la définition des opérateurs du langage.*/

21 public class CommonPlus implements ICommon {

public CommonPlus () {}

// Vérifications diverses:26

private void checkNotNull (final String opName,final int rank,final Object o)

throws EvaluationException {31 if ( o == null ) {

final String msg = opName + ": Argument " + rank + " is null!\n"+ "Value is: " + o;

throw new EvaluationException(msg);};

39

Page 21: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

36 }

private Object signalWrongType (final String opName,final int rank,final Object o,

41 final String expectedType)throws EvaluationException {final String msg = opName + ": Argument " + rank + " is not "

+ expectedType + "\n" + "Value is: " + o;throw new EvaluationException(msg);

46 }

/** Les opérateurs unaires.** Comme il n’y a que deux tels opérateurs, leur définition est

51 * intégrée directement dans cette méthode plutôt que d’être* macro-générée. */

public Object applyOperator (final String opName, final Object operand)throws EvaluationException {

56 checkNotNull(opName, 1, operand);

if ( "-".equals(opName) ) {if ( operand instanceof BigInteger ) {

final BigInteger bi = (BigInteger) operand;61 return bi.negate();

} else if ( operand instanceof Double ) {// Profitons du désemballage (unboxing) automatique:// final double bd = ((Double) operand).doubleValue();final double bd = (Double) operand;

66 return new Double(-bd);} else {

return signalWrongType(opName, 1, operand, "number");}

71 } else if ( "!".equals(opName) ) {if ( operand instanceof Boolean ) {

final Boolean b = (Boolean) operand;return Boolean.valueOf( ! b.booleanValue() );

} else {76 return signalWrongType(opName, 1, operand, "boolean");

}

} else {final String msg = "Unknown unary operator: " + opName;

81 throw new EvaluationException(msg);}

}

/** Les opérateurs binaires.86 *

* Cette méthode n’est qu’un grand aiguillage. */

public Object applyOperator (final String opName,final Object leftOperand,

91 final Object rightOperand)throws EvaluationException{

// Les opérateurs:

96 if ( "+".equals(opName) ) {return operatorPlus(opName, leftOperand, rightOperand);

} elseif ( "-".equals(opName) ) {

return operatorMinus(opName, leftOperand, rightOperand);101 } else

if ( "*".equals(opName) ) {return operatorMultiply(opName, leftOperand, rightOperand);

} elseif ( "/".equals(opName) ) {

106 return operatorQuotient(opName, leftOperand, rightOperand);} elseif ( "%".equals(opName) ) {

return operatorModulo(opName, leftOperand, rightOperand);} else

111

// Les comparateurs:

if ( "<".equals(opName) ) {return operatorLT(opName, leftOperand, rightOperand);

116 } elseif ( "<=".equals(opName) ) {

40

return operatorLE(opName, leftOperand, rightOperand);} elseif ( "==".equals(opName) ) {

121 return operatorEQ(opName, leftOperand, rightOperand);} elseif ( ">=".equals(opName) ) {

return operatorGE(opName, leftOperand, rightOperand);} else

126 if ( ">".equals(opName) ) {return operatorGT(opName, leftOperand, rightOperand);

} elseif ( "!=".equals(opName) ) {

return operatorNEQ(opName, leftOperand, rightOperand);131 } else

// L’operateur != est aussi connu sous l’alias <>// Cet oubli a été signalé par [email protected]:if ( "<>".equals(opName) ) {

return operatorNEQ(opName, leftOperand, rightOperand);136 } else

// Les opérateurs booléens:if ( "&".equals(opName) ) {

if ( leftOperand == Boolean.FALSE ) {141 return Boolean.FALSE;

} else {return rightOperand;

}} else

146 if ( "|".equals(opName) ) {if ( leftOperand != Boolean.FALSE ) {

return leftOperand;} else {

return rightOperand;151 }

} elseif ( "^".equals(opName) ) {

boolean left = (leftOperand != Boolean.FALSE);boolean right = (rightOperand != Boolean.FALSE);

156 return (Boolean) (left != right);} else

// NOTA: il serait plus astucieux de ranger les branches de// ces alternatives par ordre d’usage décroissant!

161 {final String msg = "Unknown binary operator: " + opName;throw new EvaluationException(msg);

}}

166

// Le cas de l’opérateur binaire + est plus compliqué car il permet// aussi la concaténation de chaînes de caractères. Il sera donc// traité à part et donc écrit à la main. C’est tout comme pour// modulo qui ne s’applique qu’à des entiers et non à des flottants.

171 // Tous les autres opérateurs binaires seront macro-générés.

/** Définition de l’opérateur binaire + */

private Object operatorPlus (final String opName,176 final Object a,

final Object b)throws EvaluationException {checkNotNull(opName, 1, a);checkNotNull(opName, 2, b);

181 if ( a instanceof BigInteger ) {final BigInteger bi1 = (BigInteger) a;if ( b instanceof BigInteger ) {

final BigInteger bi2 = (BigInteger) b;return bi1.add(bi2);

186 } else if ( b instanceof Double ) {final double bd1 = bi1.doubleValue();//final double bd2 = ((Double) b).doubleValue();final double bd2 = (Double) b;return new Double(bd1 + bd2);

191 } else {return signalWrongType(opName, 2, b, "number");

}} else if ( a instanceof Double ) {

final Double bd1 = (Double) a;196 if ( b instanceof Double ) {

final Double bd2 = (Double) b;//return new Double(bd1.doubleValue() + bd2.doubleValue());return new Double(bd1 + bd2);

41

Page 22: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

} else if ( b instanceof BigInteger ) {201 final BigInteger bi2 = (BigInteger) b;

final double bd2 = bi2.doubleValue();return new Double(bd1.doubleValue() + bd2);

} else {return signalWrongType(opName, 2, b, "number");

206 }} else if ( a instanceof String ) {

final String sa = (String) a;if ( b instanceof String ) {

final String sb = (String) b;211 return sa + sb;

} else {return signalWrongType(opName, 2, b, "string");

}} else {

216 return signalWrongType(opName, 1, a, "number");}

}

/** Définition de l’opérateur binaire modulo % */221

private Object operatorModulo (final String opName,final Object a,final Object b)

throws EvaluationException {226 checkNotNull(opName, 1, a);

checkNotNull(opName, 2, b);if ( a instanceof BigInteger ) {

final BigInteger bi1 = (BigInteger) a;if ( b instanceof BigInteger ) {

231 final BigInteger bi2 = (BigInteger) b;return bi1.mod(bi2);

} else {return signalWrongType(opName, 2, b, "integer");

}236 } else {

return signalWrongType(opName, 1, a, "integer");}

}

241 // Les opérateurs binaires (engendrés par PHP)

/** Définition de l’opérateur binaire - à l’aide de BigInteger.subtract.*/

246 private Object operatorMinus (final String opName, final Object a, final Object b)throws EvaluationException {

checkNotNull(opName, 1, a);checkNotNull(opName, 2, b);if ( a instanceof BigInteger ) {

251 final BigInteger bi1 = (BigInteger) a;if ( b instanceof BigInteger ) {

final BigInteger bi2 = (BigInteger) b;return bi1.subtract(bi2);

} else if ( b instanceof Double ) {256 final double bd1 = bi1.doubleValue();

//final double bd2 = ((Double) b).doubleValue();final double bd2 = (Double) b;return new Double(bd1 - bd2);

} else {261 return signalWrongType(opName, 2, b, "number");

}} else if ( a instanceof Double ) {

final Double bd1 = (Double) a;if ( b instanceof Double ) {

266 final Double bd2 = (Double) b;//return new Double(bd1.doubleValue() - bd2.doubleValue());return new Double(bd1 - bd2);

} else if ( b instanceof BigInteger ) {final BigInteger bi2 = (BigInteger) b;

271 final double bd2 = bi2.doubleValue();//return new Double(bd1.doubleValue() - bd2);return new Double(bd1 - bd2);

} else {return signalWrongType(opName, 2, b, "number");

276 }} else {

return signalWrongType(opName, 1, a, "number");}

}42

281

/** Définition de l’opérateur binaire * à l’aide de BigInteger.multiply.*/

private Object operatorMultiply (final String opName, final Object a, final Object b)throws EvaluationException {

286 checkNotNull(opName, 1, a);checkNotNull(opName, 2, b);if ( a instanceof BigInteger ) {

final BigInteger bi1 = (BigInteger) a;if ( b instanceof BigInteger ) {

291 final BigInteger bi2 = (BigInteger) b;return bi1.multiply(bi2);

} else if ( b instanceof Double ) {final double bd1 = bi1.doubleValue();//final double bd2 = ((Double) b).doubleValue();

296 final double bd2 = (Double) b;return new Double(bd1 * bd2);

} else {return signalWrongType(opName, 2, b, "number");

}301 } else if ( a instanceof Double ) {

final Double bd1 = (Double) a;if ( b instanceof Double ) {

final Double bd2 = (Double) b;//return new Double(bd1.doubleValue() * bd2.doubleValue());

306 return new Double(bd1 * bd2);} else if ( b instanceof BigInteger ) {

final BigInteger bi2 = (BigInteger) b;final double bd2 = bi2.doubleValue();//return new Double(bd1.doubleValue() * bd2);

311 return new Double(bd1 * bd2);} else {

return signalWrongType(opName, 2, b, "number");}

} else {316 return signalWrongType(opName, 1, a, "number");

}}

/** Définition de l’opérateur binaire / à l’aide de BigInteger.divide.*/

321

private Object operatorQuotient (final String opName, final Object a, final Object b)throws EvaluationException {

checkNotNull(opName, 1, a);checkNotNull(opName, 2, b);

326 if ( a instanceof BigInteger ) {final BigInteger bi1 = (BigInteger) a;if ( b instanceof BigInteger ) {

final BigInteger bi2 = (BigInteger) b;return bi1.divide(bi2);

331 } else if ( b instanceof Double ) {final double bd1 = bi1.doubleValue();//final double bd2 = ((Double) b).doubleValue();final double bd2 = (Double) b;return new Double(bd1 / bd2);

336 } else {return signalWrongType(opName, 2, b, "number");

}} else if ( a instanceof Double ) {

final Double bd1 = (Double) a;341 if ( b instanceof Double ) {

final Double bd2 = (Double) b;//return new Double(bd1.doubleValue() / bd2.doubleValue());return new Double(bd1 / bd2);

} else if ( b instanceof BigInteger ) {346 final BigInteger bi2 = (BigInteger) b;

final double bd2 = bi2.doubleValue();//return new Double(bd1.doubleValue() / bd2);return new Double(bd1 / bd2);

} else {351 return signalWrongType(opName, 2, b, "number");

}} else {

return signalWrongType(opName, 1, a, "number");}

356 }

// Les comparateurs binaires (engendrés par PHP)

43

Page 23: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

361 /** Définition de l’opérateur binaire LT à l’aide de BigInteger.compareTo().*/

private Object operatorLT (final String opName, final Object a, final Object b)throws EvaluationException {checkNotNull(opName, 1, a);

366 checkNotNull(opName, 2, b);if ( a instanceof BigInteger ) {

final BigInteger bi1 = (BigInteger) a;if ( b instanceof BigInteger ) {

final BigInteger bi2 = (BigInteger) b;371 return Boolean.valueOf(bi1.compareTo(bi2) < 0);

} else if ( b instanceof Double ) {final double bd1 = bi1.doubleValue();//final double bd2 = ((Double) b).doubleValue();final double bd2 = (Double) b;

376 return Boolean.valueOf(bd1 < bd2);} else {

return signalWrongType(opName, 2, b, "number");}

} else if ( a instanceof Double ) {381 final Double bd1 = (Double) a;

if ( b instanceof Double ) {final Double bd2 = (Double) b;//return Boolean.valueOf(bd1.doubleValue() < bd2.doubleValue());return Boolean.valueOf(bd1 < bd2);

386 } else if ( b instanceof BigInteger ) {final BigInteger bi2 = (BigInteger) b;final double bd2 = bi2.doubleValue();return Boolean.valueOf(bd1.doubleValue() < bd2);

} else {391 return signalWrongType(opName, 2, b, "number");

}} else {

return signalWrongType(opName, 1, a, "number");}

396 }

/** Définition de l’opérateur binaire LE à l’aide de BigInteger.compareTo().*/

private Object operatorLE (final String opName, final Object a, final Object b)401 throws EvaluationException {

checkNotNull(opName, 1, a);checkNotNull(opName, 2, b);if ( a instanceof BigInteger ) {

final BigInteger bi1 = (BigInteger) a;406 if ( b instanceof BigInteger ) {

final BigInteger bi2 = (BigInteger) b;return Boolean.valueOf(bi1.compareTo(bi2) <= 0);

} else if ( b instanceof Double ) {final double bd1 = bi1.doubleValue();

411 //final double bd2 = ((Double) b).doubleValue();final double bd2 = (Double) b;return Boolean.valueOf(bd1 <= bd2);

} else {return signalWrongType(opName, 2, b, "number");

416 }} else if ( a instanceof Double ) {

final Double bd1 = (Double) a;if ( b instanceof Double ) {

final Double bd2 = (Double) b;421 //return Boolean.valueOf(bd1.doubleValue() <= bd2.doubleValue());

return Boolean.valueOf(bd1 <= bd2);} else if ( b instanceof BigInteger ) {

final BigInteger bi2 = (BigInteger) b;final double bd2 = bi2.doubleValue();

426 return Boolean.valueOf(bd1.doubleValue() <= bd2);} else {

return signalWrongType(opName, 2, b, "number");}

} else {431 return signalWrongType(opName, 1, a, "number");

}}

/** Définition de l’opérateur binaire EQ à l’aide de BigInteger.compareTo().*/

436

private Object operatorEQ (final String opName, final Object a, final Object b)throws EvaluationException {checkNotNull(opName, 1, a);

44

checkNotNull(opName, 2, b);441 if ( a instanceof BigInteger ) {

final BigInteger bi1 = (BigInteger) a;if ( b instanceof BigInteger ) {

final BigInteger bi2 = (BigInteger) b;return Boolean.valueOf(bi1.compareTo(bi2) == 0);

446 } else if ( b instanceof Double ) {final double bd1 = bi1.doubleValue();//final double bd2 = ((Double) b).doubleValue();final double bd2 = (Double) b;return Boolean.valueOf(bd1 == bd2);

451 } else {return signalWrongType(opName, 2, b, "number");

}} else if ( a instanceof Double ) {

final Double bd1 = (Double) a;456 if ( b instanceof Double ) {

final Double bd2 = (Double) b;//return Boolean.valueOf(bd1.doubleValue() == bd2.doubleValue());return Boolean.valueOf(bd1 == bd2);

} else if ( b instanceof BigInteger ) {461 final BigInteger bi2 = (BigInteger) b;

final double bd2 = bi2.doubleValue();return Boolean.valueOf(bd1.doubleValue() == bd2);

} else {return signalWrongType(opName, 2, b, "number");

466 }} else {

return signalWrongType(opName, 1, a, "number");}

}471

/** Définition de l’opérateur binaire GE à l’aide de BigInteger.compareTo().*/

private Object operatorGE (final String opName, final Object a, final Object b)throws EvaluationException {

476 checkNotNull(opName, 1, a);checkNotNull(opName, 2, b);if ( a instanceof BigInteger ) {

final BigInteger bi1 = (BigInteger) a;if ( b instanceof BigInteger ) {

481 final BigInteger bi2 = (BigInteger) b;return Boolean.valueOf(bi1.compareTo(bi2) >= 0);

} else if ( b instanceof Double ) {final double bd1 = bi1.doubleValue();//final double bd2 = ((Double) b).doubleValue();

486 final double bd2 = (Double) b;return Boolean.valueOf(bd1 >= bd2);

} else {return signalWrongType(opName, 2, b, "number");

}491 } else if ( a instanceof Double ) {

final Double bd1 = (Double) a;if ( b instanceof Double ) {

final Double bd2 = (Double) b;//return Boolean.valueOf(bd1.doubleValue() >= bd2.doubleValue());

496 return Boolean.valueOf(bd1 >= bd2);} else if ( b instanceof BigInteger ) {

final BigInteger bi2 = (BigInteger) b;final double bd2 = bi2.doubleValue();return Boolean.valueOf(bd1.doubleValue() >= bd2);

501 } else {return signalWrongType(opName, 2, b, "number");

}} else {

return signalWrongType(opName, 1, a, "number");506 }

}

/** Définition de l’opérateur binaire GT à l’aide de BigInteger.compareTo().*/

511 private Object operatorGT (final String opName, final Object a, final Object b)throws EvaluationException {checkNotNull(opName, 1, a);checkNotNull(opName, 2, b);if ( a instanceof BigInteger ) {

516 final BigInteger bi1 = (BigInteger) a;if ( b instanceof BigInteger ) {

final BigInteger bi2 = (BigInteger) b;return Boolean.valueOf(bi1.compareTo(bi2) > 0);

45

Page 24: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

} else if ( b instanceof Double ) {521 final double bd1 = bi1.doubleValue();

//final double bd2 = ((Double) b).doubleValue();final double bd2 = (Double) b;return Boolean.valueOf(bd1 > bd2);

} else {526 return signalWrongType(opName, 2, b, "number");

}} else if ( a instanceof Double ) {

final Double bd1 = (Double) a;if ( b instanceof Double ) {

531 final Double bd2 = (Double) b;//return Boolean.valueOf(bd1.doubleValue() > bd2.doubleValue());return Boolean.valueOf(bd1 > bd2);

} else if ( b instanceof BigInteger ) {final BigInteger bi2 = (BigInteger) b;

536 final double bd2 = bi2.doubleValue();return Boolean.valueOf(bd1.doubleValue() > bd2);

} else {return signalWrongType(opName, 2, b, "number");

}541 } else {

return signalWrongType(opName, 1, a, "number");}

}

546 /** Définition de l’opérateur binaire NEQ à l’aide de BigInteger.compareTo().*/

private Object operatorNEQ (final String opName, final Object a, final Object b)throws EvaluationException {checkNotNull(opName, 1, a);

551 checkNotNull(opName, 2, b);if ( a instanceof BigInteger ) {

final BigInteger bi1 = (BigInteger) a;if ( b instanceof BigInteger ) {

final BigInteger bi2 = (BigInteger) b;556 return Boolean.valueOf(bi1.compareTo(bi2) != 0);

} else if ( b instanceof Double ) {final double bd1 = bi1.doubleValue();//final double bd2 = ((Double) b).doubleValue();final double bd2 = (Double) b;

561 return Boolean.valueOf(bd1 != bd2);} else {

return signalWrongType(opName, 2, b, "number");}

} else if ( a instanceof Double ) {566 final Double bd1 = (Double) a;

if ( b instanceof Double ) {final Double bd2 = (Double) b;//return Boolean.valueOf(bd1.doubleValue() != bd2.doubleValue());return Boolean.valueOf(bd1 != bd2);

571 } else if ( b instanceof BigInteger ) {final BigInteger bi2 = (BigInteger) b;final double bd2 = bi2.doubleValue();return Boolean.valueOf(bd1.doubleValue() != bd2);

} else {576 return signalWrongType(opName, 2, b, "number");

}} else {

return signalWrongType(opName, 1, a, "number");}

581 }

}

// fin de génération de CommonPlus.java

Java/src/fr/upmc/ilp/ilp1/runtime/ConstantsStuff.java

package fr.upmc.ilp.ilp1.runtime;

import fr.upmc.ilp.ilp1.interfaces.IASTvariable;

5 /** Cette classe permet d’etendre un environnement lexical avec une definition* de la constante Pi.*/

public class ConstantsStuff {10

46

public ConstantsStuff () {}

/** Étendre un environnement lexical pour y installer la constante Pi. */

15 public ILexicalEnvironment extendWithPredefinedConstants (final ILexicalEnvironment lexenv ) {

final ILexicalEnvironment lexenv1 = lexenv.extend(new IASTvariable() {

public String getName () {20 return "pi";

}},new Double(3.141592653589793238462643) );

return lexenv1;25 }

}

Java/src/fr/upmc/ilp/ilp1/runtime/EmptyLexicalEnvironment.java

package fr.upmc.ilp.ilp1.runtime;import fr.upmc.ilp.ilp1.interfaces.*;

4 /** Une définition de l’environnement vide. */

public class EmptyLexicalEnvironmentimplements ILexicalEnvironment {

9 // La technique du singleton:protected EmptyLexicalEnvironment () {}private static final EmptyLexicalEnvironment THE_EMPTY_LEXICAL_ENVIRONMENT;static {

THE_EMPTY_LEXICAL_ENVIRONMENT = new EmptyLexicalEnvironment();14 }

/** Creer un environnement lexical vide.* L’environnement vide ne contient rien et signale* systématiquement une erreur si l’on cherche la valeur d’une

19 * variable.*/

public static EmptyLexicalEnvironment create () {return EmptyLexicalEnvironment.THE_EMPTY_LEXICAL_ENVIRONMENT;

}24

/** Chercher la valeur d’une variable dans un environnement lexical.** @param variable la variable dont la valeur est cherchee* @throws EvaluationException si la variable n’a pas de valeur

29 */

public Object lookup (IASTvariable variable)throws EvaluationException {String msg = "Variable sans valeur: "

34 + variable.getName();throw new EvaluationException(msg);

}

/** On peut étendre l’environnement vide.39 *

* Malheureusement, cela crée une dépendance avec la classe des* environnements non vides et çà c’est moche! FIXME.*/

public ILexicalEnvironment extend (IASTvariable variable, Object value) {44 return new LexicalEnvironment(variable, value, this);

}

}

Java/src/fr/upmc/ilp/ilp1/runtime/EvaluationException.java

package fr.upmc.ilp.ilp1.runtime;2

public class EvaluationException extends Exception {

static final long serialVersionUID = +1234567890003000L;

7 public EvaluationException (String message) {super(message);

47

Page 25: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

}

public EvaluationException (Throwable cause) {12 super(cause);

}

}

Java/src/fr/upmc/ilp/ilp1/runtime/ICommon.java

package fr.upmc.ilp.ilp1.runtime;

/**4 * Cette interface définit les caractéristiques globales d’un interprète du

* langage ILP1. On y trouve, notamment, la définition des opérateurs du* langage.*/

9 public interface ICommon {

/** Appliquer un opérateur unaire sur un opérande. */Object applyOperator(String opName, Object operand)

throws EvaluationException;14

/** Appliquer un opérateur binaire sur deux opérandes. */Object applyOperator(String opName, Object leftOperand, Object rightOperand)

throws EvaluationException;

19 }

Java/src/fr/upmc/ilp/ilp1/runtime/ILexicalEnvironment.java

package fr.upmc.ilp.ilp1.runtime;import fr.upmc.ilp.ilp1.interfaces.*;

/** Cette interface définit un environnement lexical pour une5 * évaluation. Un environnement est une structure de données présente

* à l’exécution et contenant une suite de couples (on dit « liaison* ») variable - valeur de cette variable.*/

10 public interface ILexicalEnvironment {

/** Renvoie la valeur d’une variable si présente dans* l’environnement.*

15 * @throws EvaluationException si la variable est absente.*/

Object lookup (IASTvariable variable)throws EvaluationException;

20 /** Étend l’environnement avec un nouveau couple variable-valeur. */ILexicalEnvironment extend (IASTvariable variable, Object value);

}

Java/src/fr/upmc/ilp/ilp1/runtime/Invokable.java

1 package fr.upmc.ilp.ilp1.runtime;

import fr.upmc.ilp.ilp1.runtime.EvaluationException;

/** L’interface des fonctions. La plupart des fonctions ont moins de 46 * arguments aussi des méthodes d’arité diverses sont-elles procurées

* pour invoquer une fonction avec 0, 1, 2 ou 3 arguments.*/

public interface Invokable {11

/** Une fonction invoquée avec un nombre quelconque d’arguments. */

Object invoke (Object ... arguments)throws EvaluationException;

16

48

/** Invocation d’une fonction zéro-aire (ou niladique) */

Object invoke ()throws EvaluationException;

21

/** Invocation d’une fonction unaire (ou monadique) */

Object invoke (Object argument1)throws EvaluationException;

26

/** Invocation d’une fonction binaire (ou dyadique) */

Object invoke (Object argument1, Object argument2)throws EvaluationException;

31

/** Invocation d’une fonction ternaire */

Object invoke (Object argument1, Object argument2, Object argument3)throws EvaluationException;

36

}

Java/src/fr/upmc/ilp/ilp1/runtime/LexicalEnvironment.java

package fr.upmc.ilp.ilp1.runtime;2 import fr.upmc.ilp.ilp1.interfaces.*;

/** Cette implantation d’environnement est très naïve: c’est une* simple liste chaînée (mais comme nous n’avons pour l’instant que* des blocs unaires cela suffit!).

7 */

public class LexicalEnvironmentimplements ILexicalEnvironment {

12 public LexicalEnvironment (IASTvariable variable,Object value,ILexicalEnvironment next )

{this.variableName = variable.getName();

17 this.value = value;this.next = next;

}protected final String variableName;protected volatile Object value;

22 protected final ILexicalEnvironment next;

/** Renvoie la valeur d’une variable si présente dans* l’environnement.*/

27 public Object lookup (IASTvariable variable)throws EvaluationException {if ( variableName.equals(variable.getName()) ) {

return value;} else {

32 return next.lookup(variable);}

}

/** On peut étendre tout environnement. */37 public ILexicalEnvironment extend (IASTvariable variable, Object value) {

return new LexicalEnvironment(variable, value, this);}

}

Java/src/fr/upmc/ilp/ilp1/runtime/PrintStuff.java

package fr.upmc.ilp.ilp1.runtime;

3 import fr.upmc.ilp.ilp1.interfaces.*;

/** les primitives pour imprimer à savoir print et newline. En fait,* newline pourrait se programmer à partir de print et de la chaîne* contenant une fin de ligne mais comme nous n’avons pas encore de

8 * fonctions, elle est utile.*/ 49

Page 26: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

public class PrintStuff {

13 public PrintStuff () {this.output = new StringBuffer();

}private final StringBuffer output;

18 /** Renvoyer les caractères imprimés et remettre à vide le tampon* d’impression. */

public synchronized String getPrintedOutput () {final String result = output.toString();

23 output.delete(0, output.length());return result;

}

/** Étendre un environnement lexical pour y installer les primitives28 print() et newline(). */

public ILexicalEnvironmentextendWithPrintPrimitives (final ILexicalEnvironment lexenv) {final ILexicalEnvironment lexenv1 = lexenv.extend(

33 new IASTvariable() {public String getName () {

return "print";}

}, new PrintPrimitive());38 final ILexicalEnvironment lexenv2 = lexenv1.extend(

new IASTvariable() {public String getName () {

return "newline";}

43 }, new NewlinePrimitive());return lexenv2;

}

/** Cette classe implante la fonction print() qui permet d’imprimer48 * une valeur. */

private class PrintPrimitive extends AbstractInvokableImpl {private PrintPrimitive () {}// La fonction print() est unaire:

53 @Overridepublic Object invoke (Object value) {

output.append(value.toString());return Boolean.FALSE;

}58 }

/** Cette classe implante la fonction newline() qui permet de passer* à la ligne. */

63 private class NewlinePrimitive extends AbstractInvokableImpl {private NewlinePrimitive () {}// La fonction print() est zéro-aire:@Overridepublic Object invoke () {

68 output.append("\n");return Boolean.FALSE;

}}

73

}

Java/src/fr/upmc/ilp/ilp1/eval/EAST.java

package fr.upmc.ilp.ilp1.eval;import fr.upmc.ilp.ilp1.interfaces.*;import fr.upmc.ilp.ilp1.runtime.*;

5 public abstract class EAST implements IAST {

/** La méthode qui évalue un EAST et retourne sa valeur. Attention:* les valeurs sont des objets JAVA (POJO comme l’on dit). */

10 public abstract Object eval (ILexicalEnvironment lexenv, ICommon common)throws EvaluationException;

50

/** Un programme qui calcule n’importe quoi. C’est, par exemple,* utilisé pour les alternatives binaires.

15 ** NOTA: une fois que ce n’importe-quoi est déterminé, ici, il ne* change plus!*/

20 public static IAST voidConstant () {return THE_VOID_CONSTANT;

}private static final EAST THE_VOID_CONSTANT;static {

25 THE_VOID_CONSTANT = new EASTbooleen("false");}

}

Java/src/fr/upmc/ilp/ilp1/eval/EASTConstant.java

1 package fr.upmc.ilp.ilp1.eval;import fr.upmc.ilp.ilp1.runtime.ICommon;import fr.upmc.ilp.ilp1.runtime.ILexicalEnvironment;

/** La classe abstraite des constantes. Elles partagent un même6 * comportement à savoir rendre leur propre valeur (un objet Java).

** Attention, même si le code de la méthode eval serait le même dans* les sous-classes de EASTConstant, le type de valeur est varié et ne* peut être , sans précaution, partagé! Noter le abstract de la

11 * classe, le protected du constructeur. Noter le protected final sur* valueAsObject (explication en EASTentier).*/

public abstract class EASTConstant16 extends EAST

{

protected EASTConstant (Object value) {this.valueAsObject = value;

21 }protected final Object valueAsObject;

/** Toutes les constantes valent leur propre valeur. */

26 @Overridepublic Object eval (ILexicalEnvironment lexenv, ICommon common) {

return valueAsObject;}

31 }

Java/src/fr/upmc/ilp/ilp1/eval/EASTException.java

package fr.upmc.ilp.ilp1.eval;

3 /** Une exception comme les autres mais qu’utilisent préférentiellement* les classes du paquetage eval.*/

public class EASTException extends Exception {8

static final long serialVersionUID = +1234567890002000L;

public EASTException (Throwable cause) {super(cause);

13 }

public EASTException (String message) {super(message);

}18

}

Java/src/fr/upmc/ilp/ilp1/eval/EASTFactory.java51

Page 27: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

package fr.upmc.ilp.ilp1.eval;import java.util.List;

import fr.upmc.ilp.ilp1.interfaces.IAST;5 import fr.upmc.ilp.ilp1.interfaces.IASTalternative;

import fr.upmc.ilp.ilp1.interfaces.IASTbinaryOperation;import fr.upmc.ilp.ilp1.interfaces.IASTboolean;import fr.upmc.ilp.ilp1.interfaces.IASTfloat;import fr.upmc.ilp.ilp1.interfaces.IASTinteger;

10 import fr.upmc.ilp.ilp1.interfaces.IASTinvocation;import fr.upmc.ilp.ilp1.interfaces.IASTsequence;import fr.upmc.ilp.ilp1.interfaces.IASTstring;import fr.upmc.ilp.ilp1.interfaces.IASTunaryBlock;import fr.upmc.ilp.ilp1.interfaces.IASTunaryOperation;

15 import fr.upmc.ilp.ilp1.interfaces.IASTvariable;

/** Une fabrique pour fabriquer des EAST. */

public class EASTFactory implements IEASTFactory<EASTException> {20

/** Créer une séquence d’AST. */public IASTsequence<EASTException> newSequence (List<IAST> asts) {

return new EASTsequence(asts);}

25

/** Créer une alternative binaire. */public IASTalternative<EASTException> newAlternative (

IAST condition,IAST consequent) {

30 return new EASTalternative(condition, consequent);}

/** Créer une alternative ternaire. */public IASTalternative<EASTException> newAlternative (

35 IAST condition,IAST consequent,IAST alternant) {

return new EASTalternative(condition, consequent, alternant);}

40

/** Créer un bloc local unaire (avec une seule variable locale). */public IASTunaryBlock<EASTException> newUnaryBlock (

IASTvariable variable,IAST initialisation,

45 IASTsequence<EASTException> body) {return new EASTblocUnaire(variable, initialisation, body);

}

/** Créer une variable. */50 public IASTvariable newVariable (String name) {

return new EASTvariable(name);}

/** Créer une invocation (un appel à une fonction). */55 public IASTinvocation<EASTException> newInvocation (String name, List<IAST> asts) {

return new EASTinvocationPrimitive(name, asts);}

/** Créer une opération unaire. */60 public IASTunaryOperation newUnaryOperation (String operatorName,

IAST operand) {return new EASToperationUnaire(operatorName, operand);

}

65 /** Créer une opération binaire. */public IASTbinaryOperation newBinaryOperation (String operatorName,

IAST leftOperand,IAST rightOperand) {

return new EASToperationBinaire(operatorName, leftOperand, rightOperand);70 }

/** Créer une constante littérale entière. */public IASTinteger newIntegerConstant (String value) {

return new EASTentier(value);75 }

/** Créer une constante littérale flottante. */public IASTfloat newFloatConstant (String value) {

return new EASTflottant(value);80 }

/** Créer une constante littérale chaîne de caractères. */52

public IASTstring newStringConstant (String value) {return new EASTchaine(value);

85 }

/** Créer une constante littérale booléenne. */public IASTboolean newBooleanConstant (String value) {

return new EASTbooleen(value);90 }

/** Signaler un problème avec un message. */public IAST throwParseException (String message)

throws EASTException {95 throw new EASTException(message);

}

/** Signaler un problème avec une exception. */public IAST throwParseException (Throwable cause)

100 throws EASTException {throw new EASTException(cause);

}

}

Java/src/fr/upmc/ilp/ilp1/eval/EASTFileTest.java

package fr.upmc.ilp.ilp1.eval;

import java.io.File;import java.io.FilenameFilter;

5 import java.io.IOException;import java.util.regex.Matcher;import java.util.regex.Pattern;

import javax.xml.parsers.DocumentBuilder;10 import javax.xml.parsers.DocumentBuilderFactory;

import javax.xml.parsers.ParserConfigurationException;

import junit.framework.TestCase;

15 import org.w3c.dom.Document;import org.xml.sax.SAXException;

import fr.upmc.ilp.ilp1.runtime.CommonPlus;import fr.upmc.ilp.ilp1.runtime.ConstantsStuff;

20 import fr.upmc.ilp.ilp1.runtime.EmptyLexicalEnvironment;import fr.upmc.ilp.ilp1.runtime.EvaluationException;import fr.upmc.ilp.ilp1.runtime.ICommon;import fr.upmc.ilp.ilp1.runtime.ILexicalEnvironment;import fr.upmc.ilp.ilp1.runtime.PrintStuff;

25 import fr.upmc.ilp.tool1.FileTool;

/** Test d’evaluation de programmes XML.** Ces fichiers (situés en Grammars/Samples/) ont été préparés par des

30 * programmes rédigés en Scheme (situés en Grammars/Scheme/), ils sont* accompagnes d’un fichier .result qui représente la valeur attendue* et un fichier .print qui contient ce qui est imprimé. Cette classe* doit etre executee dans le repertoire qui contient Java et Grammars* (car Eclipse ne semble pas permettre que l’on indique Java/ tout court!).

35 */

public class EASTFileTest extends TestCase {

/** Établir l’environnement de test. */40

@Overridepublic void setUp () {

common = new CommonPlus();lexenv = EmptyLexicalEnvironment.create();

45 ps = new PrintStuff();lexenv = ps.extendWithPrintPrimitives(lexenv);cs = new ConstantsStuff();lexenv = cs.extendWithPredefinedConstants(lexenv);factory = new EASTFactory();

50 }private ILexicalEnvironment lexenv;private ICommon common;private EASTFactory factory;private PrintStuff ps;

53

Page 28: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

55 private ConstantsStuff cs;

/** Les caractéristiques des programmes XML à tester: */

private final File directory = new File("Grammars/Samples/");60 private final Pattern p = Pattern.compile("^u\\d+-1.xml$");

private final Pattern pfull =Pattern.compile("(.*" + File.separator + "u\\d+-1).xml$");

/** Tester un programme c’est-à-dire le lire depuis XML, le65 * convertir en un EAST, l’évaluer et comparer le résultat avec ce

* qui était attendu. */

protected void handleFile (String basefilename)throws IOException, ParserConfigurationException, SAXException,

70 EASTException, EvaluationException {// Imprimer le fichier Scheme ?File xmlFile = new File(basefilename + ".xml");DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();DocumentBuilder db = dbf.newDocumentBuilder();

75 Document d = db.parse(xmlFile);EASTParser parser = new EASTParser(factory);EAST east = (EAST) parser.parse(d);// Évaluer et comparer les résultats:Object result = east.eval(lexenv, common);

80 System.err.println("Obtained result is: " + result);String expectedResult = FileTool.readExpectedResult(basefilename);System.err.println("Expected result was: " + expectedResult);// Comme noté par [email protected], il faut équeuter// (par trim()) les deux termes de la comparaison:

85 assertEquals(expectedResult, result.toString().trim());// Comparer les impressions:String expectedPrinting = FileTool.readExpectedPrinting(basefilename);String printing = ps.getPrintedOutput();System.err.println("Obtained printing:" + printing);

90 System.err.println("Expected printing:" + expectedPrinting);assertEquals(expectedPrinting, printing.trim());

}

/** Rechercher tous les fichiers u*-1.xml et les tester. */95

public void testUFiles ()throws IOException, ParserConfigurationException, SAXException,

EASTException, EvaluationException {FilenameFilter ff = new FilenameFilter() {

100 public boolean accept (File dir, String name) {final Matcher m = p.matcher(name);return m.matches();

}};

105 final File[] testFiles = directory.listFiles(ff);// Si cette assertion n’est pas remplie, on n’est certainement pas// dans le bon repertoire (celui qui contient Grammars).assertNotNull(testFiles);// Au moins 38 programmes de test:

110 assertTrue(testFiles.length >= 38);// Trier les noms de fichiers en place:java.util.Arrays.sort(testFiles, new java.util.Comparator<File>() {

public int compare (File f1, File f2) {return f1.getName().compareTo(f2.getName());

115 }@Overridepublic boolean equals (Object comparator) {

return false;}

120 });for ( int i = 0 ; i<testFiles.length ; i++ ) {

final String filename = testFiles[i].getPath();System.err.println("Testing " + filename);final Matcher m = pfull.matcher(filename);

125 assertTrue(m.matches());handleFile(m.group(1));

}}

130 /*** Un point d’entree pour lancer cette classe de Test pour Junit3* comme une application Java. Elle requiert sur la ligne de* commande, le nom d’un fichier ILP a evaluer.*/

135

public static void main (String[] argument)54

throws Exception {if ( argument.length != 1 ) {

String msg = "Missing ILP filename!";140 throw new RuntimeException(msg);

}File f = new File(argument[0]);if ( f.exists() && f.canRead() ) {

String baseFileName = f.getAbsolutePath();145 if ( baseFileName.endsWith(".xml") ) {

int n = baseFileName.lastIndexOf(".xml");baseFileName = baseFileName.substring(0, n);

}EASTFileTest tc = new EASTFileTest();

150 tc.setUp();tc.handleFile(baseFileName);

}}

155 }

Java/src/fr/upmc/ilp/ilp1/eval/EASTParser.java

package fr.upmc.ilp.ilp1.eval;

import java.util.List;4 import java.util.Vector;

import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.Node;

9 import org.w3c.dom.NodeList;

import fr.upmc.ilp.ilp1.interfaces.IAST;import fr.upmc.ilp.ilp1.interfaces.IASTvariable;

14 /** Le but de cette classe est de transformer un document XML en un* AST avec évaluation conforme à fr.upmc.ilp.interfaces.IAST.** Cet analyseur améliore ASTParser en ce sens qu’il est paramétré par

* une fabrique de construction d’AST. À part sa construction, cet19 * analyseur s’utilise tout comme un ASTParser.

*/

public class EASTParser {

24 /** Constructeur d’analyseur de document (ou nœud) DOM en un AST* dont les constructeurs particuliers sont fournis par une* fabrique. */

public EASTParser (final IEASTFactory<EASTException> factory) {29 this.factory = factory;

}

private final IEASTFactory<EASTException> factory;

34 /** Analyseur de DOM en AST. Les nœuds de l’AST sont créés par la* fabrique spécifiée à la construction de l’EASTParser. Même les* exceptions sont signalées par cette même fabrique.*/

39 public IAST parse (final Node n)throws EASTException {

try {switch ( n.getNodeType() ) {

44 case Node.DOCUMENT_NODE: {final Document d = (Document) n;return this.parse(d.getDocumentElement());

}

49 case Node.ELEMENT_NODE: {final Element e = (Element) n;final NodeList nl = e.getChildNodes();final String name = e.getTagName();

54 if ( "programme1".equals(name) ) {return factory.newSequence(parseList(nl));

} else if ( "alternative".equals(name) ) {55

Page 29: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

final IAST cond = findThenParseChild(nl, "condition");59 final IAST conseq =

findThenParseChildAsInstructions(nl, "consequence");try {

final IAST alt =findThenParseChildAsInstructions(nl, "alternant");

64 return factory.newAlternative(cond, conseq, alt);} catch (EASTException exc) {

return factory.newAlternative(cond, conseq);}

69 } else if ( "sequence".equals(name) ) {return factory.newSequence(this.parseList(nl));

} else if ( "blocUnaire".equals(name) ) {final IASTvariable var =

74 (IASTvariable) findThenParseChild(nl, "variable");final IAST init = findThenParseChild(nl, "valeur");final EASTsequence body =

(EASTsequence) findThenParseChild(nl, "corps");return factory.newUnaryBlock(var, init, body);

79

} else if ( "variable".equals(name) ) {final String nick = e.getAttribute("nom");return factory.newVariable(nick);

84 } else if ( "invocationPrimitive".equals(name) ) {final String op = e.getAttribute("fonction");final List<IAST> args = parseList(nl);return factory.newInvocation(op, args);

89 } else if ( "operationUnaire".equals(name) ) {final String op = e.getAttribute("operateur");final IAST rand = findThenParseChild(nl, "operande");return factory.newUnaryOperation(op, rand);

94 } else if ( "operationBinaire".equals(name) ) {final String op = e.getAttribute("operateur");final IAST gauche = findThenParseChild(nl, "operandeGauche");final IAST droite = findThenParseChild(nl, "operandeDroit");return factory.newBinaryOperation(op, gauche, droite);

99

} else if ( "entier".equals(name) ) {return factory.newIntegerConstant(e.getAttribute("valeur"));

} else if ( "flottant".equals(name) ) {104 return factory.newFloatConstant(e.getAttribute("valeur"));

} else if ( "chaine".equals(name) ) {final String text = n.getTextContent();//final String text = this.extractText(e);

109 return factory.newStringConstant(text);

} else if ( "booleen".equals(name) ) {return factory.newBooleanConstant(e.getAttribute("valeur"));

114 // Une série d’éléments devant être analysés comme des expressions:} else if ( "operandeGauche".equals(name) ) {

return this.parseUniqueChild(nl);} else if ( "operandeDroit".equals(name) ) {

return this.parseUniqueChild(nl);119 } else if ( "operande".equals(name) ) {

return this.parseUniqueChild(nl);} else if ( "condition".equals(name) ) {

return this.parseUniqueChild(nl);} else if ( "consequence".equals(name) ) {

124 return this.parseUniqueChild(nl);} else if ( "alternant".equals(name) ) {

return this.parseUniqueChild(nl);} else if ( "valeur".equals(name) ) {

return this.parseUniqueChild(nl);129

// Une série d’éléments devant être analysée comme une séquence:} else if ( "corps".equals(name) ) {

return factory.newSequence(this.parseList(nl));

134 } else {final String msg = "Unknown element name: " + name;return factory.throwParseException(msg);

}}

139

56

default: {final String msg = "Unknown node type: " + n.getNodeName();return factory.throwParseException(msg);

}144 }

} catch (final EASTException e) {throw e;

} catch (final Exception e) {throw new EASTException(e);

149 }}

/** Analyser une séquence d’éléments pour en faire un ASTlist* c’est-à-dire une séquence d’AST.

154 */

public List<IAST> parseList (final NodeList nl)throws EASTException {

final List<IAST> result = new Vector<IAST>();159 final int n = nl.getLength();

LOOP:for ( int i = 0 ; i<n ; i++ ) {

final Node nd = nl.item(i);switch ( nd.getNodeType() ) {

164

case Node.ELEMENT_NODE: {final IAST p = this.parse(nd);result.add(p);continue LOOP;

169 }

default: {// On ignore tout ce qui n’est pas élément XML:

}174 }

}return result;

}

179 /** Trouver un élément d’après son nom et l’analyser pour en faire* un AST. */

public IAST findThenParseChild (final NodeList nl, final String childName)throws EASTException {

184 IAST result = null;final int n = nl.getLength();for ( int i = 0 ; i<n ; i++ ) {

final Node nd = nl.item(i);switch ( nd.getNodeType() ) {

189

case Node.ELEMENT_NODE: {final Element e = (Element) nd;if ( childName.equals(e.getTagName()) ) {

if ( result == null ) {194 result = this.parse(e);

} else {final String msg = "Non unique child with name " + childName;return factory.throwParseException(msg);

}199 };

}

default: {// On ignore tout ce qui n’est pas élément XML:

204 }}

}if ( result == null ) {

final String msg = "No such child element " + childName;209 return factory.throwParseException(msg);

};return result;

}

214 /** Trouver un élément d’après son nom et analyser son contenu pour* en faire un ASTsequence.** @throws ILPException* lorsqu’un tel élément n’est pas trouvé.

219 */

public IAST findThenParseChildAsInstructions (57

Page 30: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

final NodeList nl,final String childName)

224 throws EASTException {int n = nl.getLength();for ( int i = 0 ; i<n ; i++ ) {

Node nd = nl.item(i);switch ( nd.getNodeType() ) {

229

case Node.ELEMENT_NODE: {Element e = (Element) nd;if ( childName.equals(e.getTagName()) ) {

return factory.newSequence(this.parseList(e.getChildNodes()));234 };

}

default: {// On ignore tout ce qui n’est pas élément XML:

239 }}

}String msg = "No such child element " + childName;return factory.throwParseException(msg);

244 }

/** Analyser une suite comportant un unique élément. */

public IAST parseUniqueChild (final NodeList nl)249 throws EASTException {

IAST result = null;final int n = nl.getLength();for ( int i = 0 ; i<n ; i++ ) {

final Node nd = nl.item(i);254 switch ( nd.getNodeType() ) {

case Node.ELEMENT_NODE: {final Element e = (Element) nd;if ( result == null ) {

259 result = this.parse(e);} else {

final String msg = "Non unique child";return factory.throwParseException(msg);

}264 }

default: {// On ignore tout ce qui n’est pas élément XML:

}269 }

}if ( result == null ) {

factory.throwParseException("No child at all");};

274 return result;}

}

Java/src/fr/upmc/ilp/ilp1/eval/EASTPrimitiveTest.java

package fr.upmc.ilp.ilp1.eval;2

import java.util.List;import java.util.Vector;

import junit.framework.TestCase;7 import fr.upmc.ilp.ilp1.interfaces.IAST;

import fr.upmc.ilp.ilp1.runtime.Common;import fr.upmc.ilp.ilp1.runtime.ConstantsStuff;import fr.upmc.ilp.ilp1.runtime.EmptyLexicalEnvironment;import fr.upmc.ilp.ilp1.runtime.EvaluationException;

12 import fr.upmc.ilp.ilp1.runtime.ICommon;import fr.upmc.ilp.ilp1.runtime.ILexicalEnvironment;import fr.upmc.ilp.ilp1.runtime.PrintStuff;

/** Tests (Junit3) d’invocation des primitives (dans PrintStuff). */17

public class EASTPrimitiveTest extends TestCase {

@Overridepublic void setUp() {

58

22 common = new Common();lexenv = EmptyLexicalEnvironment.create();ps = new PrintStuff();lexenv = ps.extendWithPrintPrimitives(lexenv);cs = new ConstantsStuff();

27 lexenv = cs.extendWithPredefinedConstants(lexenv);}

private ILexicalEnvironment lexenv;private ICommon common;

32 private PrintStuff ps;private ConstantsStuff cs;

public void testPi() throws EASTException, EvaluationException {EASTvariable var = new EASTvariable("pi");

37 Object result = var.eval(lexenv, common);assertTrue(result instanceof Double);assertEquals((Double) result, 3.14, 0.1);

}

42 public void testNewline() throws EASTException, EvaluationException {List<IAST> args = new Vector<IAST>();EAST o = new EASTinvocationPrimitive("newline", args);Object result = o.eval(lexenv, common);assertTrue(result instanceof Boolean);

47 assertEquals(result, Boolean.FALSE);assertEquals("\n", ps.getPrintedOutput());

}

public void testPrintEntier() throws EASTException, EvaluationException {52 List<IAST> args = new Vector<IAST>();

args.add(new EASTentier("34"));EAST o = new EASTinvocationPrimitive("print", args);Object result = o.eval(lexenv, common);assertTrue(result instanceof Boolean);

57 assertEquals(result, Boolean.FALSE);assertEquals("34", ps.getPrintedOutput());

}

public void testPrintFlottant() throws EASTException, EvaluationException {62 List<IAST> args = new Vector<IAST>();

args.add(new EASTflottant("3.14"));EAST o = new EASTinvocationPrimitive("print", args);Object result = o.eval(lexenv, common);assertTrue(result instanceof Boolean);

67 assertEquals(result, Boolean.FALSE);assertEquals("3.14", ps.getPrintedOutput());

}

public void testPrintString() throws EASTException, EvaluationException {72 List<IAST> args = new Vector<IAST>();

args.add(new EASTchaine("foobar"));EAST o = new EASTinvocationPrimitive("print", args);Object result = o.eval(lexenv, common);assertTrue(result instanceof Boolean);

77 assertEquals(result, Boolean.FALSE);assertEquals("foobar", ps.getPrintedOutput());

}

public void testPrintBoolTrue() throws EASTException, EvaluationException {82 List<IAST> args = new Vector<IAST>();

args.add(new EASTbooleen("true"));EAST o = new EASTinvocationPrimitive("print", args);Object result = o.eval(lexenv, common);assertTrue(result instanceof Boolean);

87 assertEquals(result, Boolean.FALSE);assertEquals("true", ps.getPrintedOutput());

}

public void testPrintBoolFalse() throws EASTException, EvaluationException {92 List<IAST> args = new Vector<IAST>();

args.add(new EASTbooleen("false"));EAST o = new EASTinvocationPrimitive("print", args);Object result = o.eval(lexenv, common);assertTrue(result instanceof Boolean);

97 assertEquals(result, Boolean.FALSE);assertEquals("false", ps.getPrintedOutput());

}

}

59

Page 31: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

Java/src/fr/upmc/ilp/ilp1/eval/EASTTest.java

package fr.upmc.ilp.ilp1.eval;

3 import java.math.BigInteger;import java.util.List;import java.util.Vector;

import junit.framework.TestCase;8 import fr.upmc.ilp.ilp1.interfaces.IAST;

import fr.upmc.ilp.ilp1.runtime.Common;import fr.upmc.ilp.ilp1.runtime.CommonPlus;import fr.upmc.ilp.ilp1.runtime.EmptyLexicalEnvironment;import fr.upmc.ilp.ilp1.runtime.EvaluationException;

13 import fr.upmc.ilp.ilp1.runtime.ICommon;import fr.upmc.ilp.ilp1.runtime.ILexicalEnvironment;

/** Tests (JUnit) d’évaluation sans utiliser de fabrique. */

18 public class EASTTest extends TestCase {

@Overridepublic void setUp () {

lexenv = EmptyLexicalEnvironment.create();23 common = new Common();

}

private ILexicalEnvironment lexenv;

28 private ICommon common;

public void testEntier () throws EASTException, EvaluationException {EAST o = new EASTentier("34");Object result = o.eval(lexenv, common);

33 assertTrue(result instanceof BigInteger);assertEquals(result, new BigInteger("34"));

}

public void testFlottant () throws EASTException, EvaluationException {38 EAST o = new EASTflottant("3.14");

Object result = o.eval(lexenv, common);assertTrue(result instanceof Double);assertEquals(result, new Double("3.14"));

}43

public void testChaine () throws EASTException, EvaluationException {EAST o = new EASTchaine("foobar");Object result = o.eval(lexenv, common);assertTrue(result instanceof String);

48 assertEquals(result, "foobar");}

public void testBooleenVrai () throws EASTException, EvaluationException {EAST o = new EASTbooleen("true");

53 Object result = o.eval(lexenv, common);assertTrue(result instanceof Boolean);assertEquals(result, Boolean.TRUE);

}

58 public void testBooleenFaux () throws EASTException, EvaluationException {EAST o = new EASTbooleen("false");Object result = o.eval(lexenv, common);assertTrue(result instanceof Boolean);assertEquals(result, Boolean.FALSE);

63 }

public void testAlternativeVraie () throws EASTException,EvaluationException {

EAST o = new EASTalternative(new EASTbooleen("true"), new EASTentier(68 "1"), new EASTentier("0"));

Object result = o.eval(lexenv, common);assertEquals(result, new BigInteger("1"));

}

73 public void testAlternativeFausse () throws EASTException,EvaluationException {

EAST o = new EASTalternative(new EASTbooleen("false"), new EASTentier("1"), new EASTentier("0"));

Object result = o.eval(lexenv, common);78 assertEquals(result, new BigInteger("0"));

}60

public void testSequence1 () throws EASTException, EvaluationException {List<IAST> args = new Vector<IAST>();

83 args.add(new EASTentier("0"));EAST o = new EASTsequence(args);Object result = o.eval(lexenv, common);assertEquals(result, new BigInteger("0"));

}88

public void testSequence2 () throws EASTException, EvaluationException {List<IAST> args = new Vector<IAST>();args.add(new EASTentier("1"));args.add(new EASTentier("0"));

93 EAST o = new EASTsequence(args);Object result = o.eval(lexenv, common);assertEquals(result, new BigInteger("0"));

}

98 public void testSequence3 () throws EASTException, EvaluationException {List<IAST> args = new Vector<IAST>();args.add(new EASTentier("1"));args.add(new EASTentier("0"));args.add(new EASTbooleen("true"));

103 EAST o = new EASTsequence(args);Object result = o.eval(lexenv, common);assertEquals(result, Boolean.TRUE);

}

108 public void testSequence0 () throws EASTException, EvaluationException {List<IAST> args = new Vector<IAST>();EAST o = new EASTsequence(args);Object result = o.eval(lexenv, common);assertNotNull(result);

113 }

public void testVariable1 () throws EASTException, EvaluationException {lexenv = lexenv.extend(new EASTvariable("x"), new BigInteger("23"));EAST o = new EASTvariable("x");

118 Object result = o.eval(lexenv, common);assertEquals(result, new BigInteger("23"));

}

public void testVariable2 () throws EASTException, EvaluationException {123 lexenv = lexenv.extend(new EASTvariable("x"), new BigInteger("23"));

lexenv = lexenv.extend(new EASTvariable("y"), new BigInteger("25"));EAST o = new EASTvariable("x");Object result = o.eval(lexenv, common);assertEquals(result, new BigInteger("23"));

128 }

public void testVariable0 () throws EASTException, EvaluationException {lexenv = lexenv.extend(new EASTvariable("x"), new BigInteger("23"));lexenv = lexenv.extend(new EASTvariable("y"), new BigInteger("25"));

133 EAST o = new EASTvariable("z");try {

o.eval(lexenv, common);} catch (EvaluationException exc) {

assertTrue(true);138 }

}

public void testBlocUnaireVarless () throws EASTException,EvaluationException {

143 lexenv = lexenv.extend(new EASTvariable("x"), new BigInteger("23"));lexenv = lexenv.extend(new EASTvariable("y"), new BigInteger("25"));List<IAST> instructions = new Vector<IAST>();instructions.add(new EASTentier("1"));EAST o = new EASTblocUnaire(new EASTvariable("z"),

148 new EASTentier("345"), new EASTsequence(instructions));Object result = o.eval(lexenv, common);assertEquals(result, new BigInteger("1"));

}

153 public void testBlocUnaireWithVar () throws EASTException,EvaluationException {

lexenv = lexenv.extend(new EASTvariable("x"), new BigInteger("23"));lexenv = lexenv.extend(new EASTvariable("y"), new BigInteger("25"));List<IAST> instructions = new Vector<IAST>();

158 instructions.add(new EASTvariable("z"));EAST o = new EASTblocUnaire(new EASTvariable("z"),

new EASTentier("345"), new EASTsequence(instructions));Object result = o.eval(lexenv, common);

61

Page 32: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

assertEquals(result, new BigInteger("345"));163 }

public void testBlocUnaireOuterScope () throws EASTException,EvaluationException {

lexenv = lexenv.extend(new EASTvariable("x"), new BigInteger("23"));168 lexenv = lexenv.extend(new EASTvariable("y"), new BigInteger("25"));

List<IAST> instructions = new Vector<IAST>();instructions.add(new EASTvariable("y"));EAST o = new EASTblocUnaire(new EASTvariable("z"),

new EASTentier("345"), new EASTsequence(instructions));173 Object result = o.eval(lexenv, common);

assertEquals(result, new BigInteger("25"));}

public void testOperateurUnaireMoinsI () throws EASTException,178 EvaluationException {

EAST o = new EASToperationUnaire("-", new EASTentier("42"));Object result = o.eval(lexenv, common);assertEquals(result, new BigInteger("-42"));

}183

public void testOperateurUnaireMoinsF () throws EASTException,EvaluationException {

EAST o = new EASToperationUnaire("-", new EASTflottant("4.2"));Object result = o.eval(lexenv, common);

188 assertEquals(result, new Double("-4.2"));}

public void testOperateurUnaireMoins2I () throws EASTException,EvaluationException {

193 EAST o = new EASToperationUnaire("-", new EASToperationUnaire("-",new EASTentier("42")));

Object result = o.eval(lexenv, common);assertEquals(result, new BigInteger("42"));

}198

public void testOperateurUnaireMoins2F () throws EASTException,EvaluationException {

EAST o = new EASToperationUnaire("-", new EASToperationUnaire("-",new EASTflottant("4.2")));

203 Object result = o.eval(lexenv, common);assertEquals(result, new Double("4.2"));

}

public void testOperateurUnaireNot () throws EASTException,208 EvaluationException {

EAST o = new EASToperationUnaire("!", new EASTbooleen("true"));Object result = o.eval(lexenv, common);assertEquals(result, Boolean.FALSE);

}213

// Operateur binaire: addition.

public void testOperateurBinairePlusII () throws EASTException,EvaluationException {

218 EAST o = new EASToperationBinaire("+", new EASTentier("1"),new EASTentier("2"));

Object result = o.eval(lexenv, common);assertEquals(result, new BigInteger("3"));

}223

public void testOperateurBinairePlusIF () throws EASTException,EvaluationException {

EAST o = new EASToperationBinaire("+", new EASTentier("1"),new EASTflottant("3.1"));

228 Object result = o.eval(lexenv, common);assertEquals(result, new Double("4.1"));

}

public void testOperateurBinairePlusFI () throws EASTException,233 EvaluationException {

EAST o = new EASToperationBinaire("+", new EASTflottant("3.1"),new EASTentier("1"));

Object result = o.eval(lexenv, common);assertEquals(result, new Double("4.1"));

238 }

public void testOperateurBinairePlusFF () throws EASTException,EvaluationException {

EAST o = new EASToperationBinaire("+", new EASTflottant("3.1"),243 new EASTflottant("1.1"));

62

Object result = o.eval(lexenv, common);assertEquals(result, new Double("4.2"));

}

248 // Operateur binaire: soustraction

public void testOperateurBinaireMinusII () throws EASTException,EvaluationException {

EAST o = new EASToperationBinaire("-", new EASTentier("11"),253 new EASTentier("2"));

Object result = o.eval(lexenv, common);assertEquals(result, new BigInteger("9"));

}

258 public void testOperateurBinaireMinusIF () throws EASTException,EvaluationException {

EAST o = new EASToperationBinaire("-", new EASTentier("10"),new EASTflottant("3.1"));

Object result = o.eval(lexenv, common);263 assertEquals(result, new Double("6.9"));

}

public void testOperateurBinaireMinusFI () throws EASTException,EvaluationException {

268 EAST o = new EASToperationBinaire("-", new EASTflottant("3.1"),new EASTentier("1"));

Object result = o.eval(lexenv, common);assertEquals(result, new Double("2.1"));

}273

public void testOperateurBinaireMinusFF () throws EASTException,EvaluationException {

EAST o = new EASToperationBinaire("-", new EASTflottant("3.1"),new EASTflottant("1.1"));

278 Object result = o.eval(lexenv, common);assertEquals(result, new Double("2.0"));

}

// Les operateurs booleens. Ils ont besoin de CommonPlus.283

public void testOperateurBinaireEtFT () throws EASTException,EvaluationException {

EAST o = new EASToperationBinaire("&", new EASTbooleen("false"),new EASTbooleen("true"));

288 common = new CommonPlus();Object result = o.eval(lexenv, common);assertEquals(result, Boolean.FALSE);

}

293 public void testOperateurBinaireOuFT () throws EASTException,EvaluationException {

EAST o = new EASToperationBinaire("|", new EASTbooleen("false"),new EASTbooleen("true"));

common = new CommonPlus();298 Object result = o.eval(lexenv, common);

assertEquals(result, Boolean.TRUE);}

public void testOperateurBinaireXorFT () throws EASTException,303 EvaluationException {

EAST o = new EASToperationBinaire("^", new EASTbooleen("false"),new EASTbooleen("true"));

common = new CommonPlus();Object result = o.eval(lexenv, common);

308 assertEquals(result, Boolean.TRUE);}

}

Java/src/fr/upmc/ilp/ilp1/eval/EASTalternative.java

package fr.upmc.ilp.ilp1.eval;

3 import fr.upmc.ilp.ilp1.interfaces.IAST;import fr.upmc.ilp.ilp1.interfaces.IASTalternative;import fr.upmc.ilp.ilp1.runtime.EvaluationException;import fr.upmc.ilp.ilp1.runtime.ICommon;import fr.upmc.ilp.ilp1.runtime.ILexicalEnvironment;

8

public class EASTalternative63

Page 33: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

extends EASTimplements IASTalternative<EASTException> {

13 public EASTalternative(IAST condition, IAST consequence, IAST alternant) {this.condition = (EAST) condition;this.consequence = (EAST) consequence;this.alternant = (EAST) alternant;

}18

// NOTA: Masquer l’implantation de l’alternative binaire afin// d’éviter la propagation de null.

public EASTalternative(IAST condition, IAST consequence) {23 this.condition = (EAST) condition;

this.consequence = (EAST) consequence;this.alternant = null;

}

28 private final EAST condition;private final EAST consequence;private final EAST alternant;

public IAST getCondition() {33 return this.condition;

}

public IAST getConsequent() {return this.consequence;

38 }

/** Quand il n’y a pas d’alternant, on rend n’importe quoi. Ce* n’importe-quoi est engendré par un utilitaire partagé au niveau d’AST. */

43 public IAST getAlternant() throws EASTException {return this.alternant;

}

public boolean isTernary() {48 return alternant != null;

}

@Overridepublic Object eval(ILexicalEnvironment lexenv, ICommon common)

53 throws EvaluationException {Object bool = condition.eval(lexenv, common);if (Boolean.FALSE == bool) {

if (isTernary()) {return alternant.eval(lexenv, common);

58 } else {return EAST.voidConstant();

}} else {

return consequence.eval(lexenv, common);63 }

}

}

Java/src/fr/upmc/ilp/ilp1/eval/EASTblocUnaire.java

package fr.upmc.ilp.ilp1.eval;

3 import fr.upmc.ilp.ilp1.interfaces.IAST;import fr.upmc.ilp.ilp1.interfaces.IASTsequence;import fr.upmc.ilp.ilp1.interfaces.IASTunaryBlock;import fr.upmc.ilp.ilp1.interfaces.IASTvariable;import fr.upmc.ilp.ilp1.runtime.EvaluationException;

8 import fr.upmc.ilp.ilp1.runtime.ICommon;import fr.upmc.ilp.ilp1.runtime.ILexicalEnvironment;

/** Les blocs locaux à une seule variable. */

13 public class EASTblocUnaireextends EASTimplements IASTunaryBlock<EASTException> {

public EASTblocUnaire (IASTvariable variable,18 IAST initialization,

IASTsequence<EASTException> body){

64

this.variable = (EASTvariable) variable;this.initialization = (EAST) initialization;

23 this.body = (EASTsequence) body;}

private final EASTvariable variable;private final EAST initialization;

28 private final EASTsequence body;

public IASTvariable getVariable () {return this.variable;

}33 public IAST getInitialization () {

return this.initialization;}public IASTsequence<EASTException> getBody () {

return this.body;38 }

@Overridepublic Object eval (ILexicalEnvironment lexenv, ICommon common)

throws EvaluationException {43 ILexicalEnvironment newlexenv =

lexenv.extend(variable, initialization.eval(lexenv, common));return body.eval(newlexenv, common);

}

48 }

Java/src/fr/upmc/ilp/ilp1/eval/EASTbooleen.java

1 package fr.upmc.ilp.ilp1.eval;import fr.upmc.ilp.ilp1.interfaces.IASTboolean;

/** Une constante booleenne. */

6 public class EASTbooleenextends EASTConstantimplements IASTboolean

{

11 /** Nota: Encore un cas ennuyeux où l’appel à super() n’est pas* trivial. Il y a quelques années, le vérifieur de code-octet avait* tendance à refuser ce genre de programmation! */

public EASTbooleen (String valeur) {16 super( ("true".equals(valeur))

? Boolean.TRUE : Boolean.FALSE );this.valeur = "true".equals(valeur);

}private final boolean valeur;

21

public boolean getValue () {return valeur;

}

26 }

Java/src/fr/upmc/ilp/ilp1/eval/EASTchaine.java

package fr.upmc.ilp.ilp1.eval;import fr.upmc.ilp.ilp1.interfaces.IASTstring;

3

/** Les constantes de type chaine de caracteres. */

public class EASTchaineextends EASTConstant

8 implements IASTstring {

public EASTchaine (String valeur) {super(valeur);this.valeur = valeur;

13 }private final String valeur;

public String getValue () {return valeur;

65

Page 34: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

18 }

}

Java/src/fr/upmc/ilp/ilp1/eval/EASTentier.java

package fr.upmc.ilp.ilp1.eval;import java.math.BigInteger;

4 import fr.upmc.ilp.ilp1.interfaces.IASTinteger;

/** Les constantes entières littérales. Elles sont représentées par* des BigInteger ce qui permet de ne pas rendre syntaxiquement faux* un programme qui mentionnerait des entiers plus grand que ce que

9 * sait faire la machine. En outre, cela permet de donner une* arithmétique complète à cette implantation.*/

public class EASTentier14 extends EASTConstant

implements IASTinteger {

/** Constructeur.*

19 * NOTA: Pour initialiser le champ valueAsObject, on fait le bon* appel à super() mais comme un BigInteger est un gros objet que* l’on ne tient pas à dupliquer, on l’utilise tel qu’il apparaît* dans EASTConstant. Conclusion: valueAsObject ne peut plus être* privée à EASTConstant et voilà comment les « protected »

24 * croissent dans les codes!*/

public EASTentier (String valeur) {super(new BigInteger(valeur));

29 }

public BigInteger getValue () {return (BigInteger) this.valueAsObject;

}34

}

Java/src/fr/upmc/ilp/ilp1/eval/EASTflottant.java

package fr.upmc.ilp.ilp1.eval;import java.math.BigDecimal;

4 import fr.upmc.ilp.ilp1.interfaces.IASTfloat;

/** Les constantes flottantes. */

public class EASTflottant9 extends EASTConstant

implements IASTfloat {

/** Constructeur.*

14 * Ici, le double est pris comme une chaîne puis manipulé comme un* Double (en guise d’objet Java) pour l’évaluation. En revanche* pour les IAST, il est manipulé comme un BigDecimal pour ne pas* subir de dégradation de précision. L’implantation perd donc de la* précision par rapport à la syntaxe!

19 */

public EASTflottant (String valeur) {super(new Double(valeur));this.bigfloat = new BigDecimal(valeur);

24 }private final BigDecimal bigfloat;

public BigDecimal getValue () {return bigfloat;

29 }

}

66

Java/src/fr/upmc/ilp/ilp1/eval/EASTinvocation.java

package fr.upmc.ilp.ilp1.eval;

3 import java.util.List;

import fr.upmc.ilp.ilp1.interfaces.IAST;import fr.upmc.ilp.ilp1.interfaces.IASTinvocation;import fr.upmc.ilp.ilp1.runtime.EvaluationException;

8 import fr.upmc.ilp.ilp1.runtime.ICommon;import fr.upmc.ilp.ilp1.runtime.ILexicalEnvironment;import fr.upmc.ilp.ilp1.runtime.Invokable;

/** La classe abstraite des invocations en general. */13

public abstract class EASTinvocationextends EASTimplements IASTinvocation<EASTException> {

18 protected EASTinvocation (final EAST fonction, final List<IAST> arguments) {this.fonction = fonction;this.argument = arguments.toArray(new EAST[0]);

}private final EAST fonction;

23 private final EAST[] argument;

public IAST getFunction () {return this.fonction;

}28

public IAST[] getArguments () {return this.argument;

}

33 public int getArgumentsLength () {return this.argument.length;

}

public IAST getArgument (final int i) {38 return this.argument[i];

}

@Overridepublic Object eval (final ILexicalEnvironment lexenv, final ICommon common)

43 throws EvaluationException {final Object fn = this.fonction.eval(lexenv, common);if ( fn instanceof Invokable ) {

Invokable invokable = (Invokable) fn;final Object[] args = new Object[argument.length];

48 for ( int i = 0 ; i<argument.length ; i++ ) {args[i] = argument[i].eval(lexenv, common);

}return invokable.invoke(args);

} else {53 final String msg = "Not a function: " + fn;

throw new EvaluationException(msg);}

}

58 }

Java/src/fr/upmc/ilp/ilp1/eval/EASTinvocationPrimitive.java

1 package fr.upmc.ilp.ilp1.eval;

import java.util.List;

import fr.upmc.ilp.ilp1.interfaces.IAST;6 import fr.upmc.ilp.ilp1.runtime.EvaluationException;

import fr.upmc.ilp.ilp1.runtime.ICommon;import fr.upmc.ilp.ilp1.runtime.ILexicalEnvironment;

/** L’invocation des primitives. */11

public class EASTinvocationPrimitiveextends EASTinvocation {

public EASTinvocationPrimitive (final String fonction,67

Page 35: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

16 final List<IAST> arguments) {super(new EASTvariable(fonction), arguments);

}

@Override21 public Object eval (final ILexicalEnvironment lexenv, final ICommon common)

throws EvaluationException {return super.eval(lexenv, common);

}

26 }

Java/src/fr/upmc/ilp/ilp1/eval/EASToperation.java

package fr.upmc.ilp.ilp1.eval;

3 import fr.upmc.ilp.ilp1.interfaces.IASToperation;

/** La classe abstraite des operations.** NOTA: Notez que la méthode getOperands() manque alors qu’elle est

8 * présente dans l’interface (IASToperation) que cette classe* implante! Savez-vous pourquoi ?*/

public abstract class EASToperation13 extends EAST

implements IASToperation{

protected EASToperation (String operateur, int arity) {18 this.operateur = operateur;

this.arity = arity;}private final String operateur;private final int arity;

23

// et pourquoi les final ici ?public final String getOperatorName () {

return this.operateur;}

28

public final int getArity () {return this.arity;

}

33 }

Java/src/fr/upmc/ilp/ilp1/eval/EASToperationBinaire.java

1 package fr.upmc.ilp.ilp1.eval;

import java.util.List;import java.util.Vector;

6 import fr.upmc.ilp.ilp1.interfaces.IAST;import fr.upmc.ilp.ilp1.interfaces.IASTbinaryOperation;import fr.upmc.ilp.ilp1.runtime.EvaluationException;import fr.upmc.ilp.ilp1.runtime.ICommon;import fr.upmc.ilp.ilp1.runtime.ILexicalEnvironment;

11

/** Les operations binaires. */

public class EASToperationBinaireextends EASToperation

16 implements IASTbinaryOperation {

public EASToperationBinaire (String operateur,IAST operandeGauche,IAST operandeDroit)

21 {super(operateur, 2);this.operandeGauche = (EAST) operandeGauche;this.operandeDroit = (EAST) operandeDroit;

}26

private final EAST operandeGauche;68

private final EAST operandeDroit;

public IAST getLeftOperand () {31 return this.operandeGauche;

}public IAST getRightOperand () {

return this.operandeDroit;}

36

public IAST[] getOperands () {// On calcule paresseusement car ce n’est pas une methode usuelle:if ( operands == null ) {

List<EAST> loperands = new Vector<EAST>();41 loperands.add(operandeGauche);

loperands.add(operandeDroit);operands = loperands.toArray(new EAST[0]);

};return operands;

46 }// NOTA: remarquer que ce mode paresseux interdit de qualifier ce// champ de « final » ce qui n’est pas sûr!private EAST[] operands;

51 @Overridepublic Object eval (ILexicalEnvironment lexenv, ICommon common)

throws EvaluationException {Object r1 = operandeGauche.eval(lexenv, common);Object r2 = operandeDroit.eval(lexenv, common);

56 return common.applyOperator(this.getOperatorName(), r1, r2);}

}

Java/src/fr/upmc/ilp/ilp1/eval/EASToperationUnaire.java

package fr.upmc.ilp.ilp1.eval;

import java.util.List;import java.util.Vector;

5

import fr.upmc.ilp.ilp1.interfaces.IAST;import fr.upmc.ilp.ilp1.interfaces.IASTunaryOperation;import fr.upmc.ilp.ilp1.runtime.EvaluationException;import fr.upmc.ilp.ilp1.runtime.ICommon;

10 import fr.upmc.ilp.ilp1.runtime.ILexicalEnvironment;

/** Les operations unaires. */

public class EASToperationUnaire15 extends EASToperation

implements IASTunaryOperation {

public EASToperationUnaire (String operateur, IAST operand) {super(operateur, 1);

20 this.operand = (EAST) operand;}private final EAST operand;

public IAST getOperand () {25 return this.operand;

}

public IAST[] getOperands () {// On calcule paresseusement car ce n’est pas une methode usuelle:

30 if ( operands == null ) {List<EAST> loperands = new Vector<EAST>();loperands.add(operand);operands = loperands.toArray(new EAST[0]);

};35 return operands;

}private EAST[] operands;

@Override40 public Object eval (ILexicalEnvironment lexenv, ICommon common)

throws EvaluationException {return common.applyOperator(this.getOperatorName(),

operand.eval(lexenv, common));}

4569

Page 36: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

}

Java/src/fr/upmc/ilp/ilp1/eval/EASTsequence.java

package fr.upmc.ilp.ilp1.eval;

3 import java.util.List;

import fr.upmc.ilp.ilp1.interfaces.IAST;import fr.upmc.ilp.ilp1.interfaces.IASTsequence;import fr.upmc.ilp.ilp1.runtime.EvaluationException;

8 import fr.upmc.ilp.ilp1.runtime.ICommon;import fr.upmc.ilp.ilp1.runtime.ILexicalEnvironment;

/** Les sequences d’instructions. Les grammaires imposent normalement* qu’il y a au moins une instruction dans une sequence. */

13

public class EASTsequenceextends EASTimplements IASTsequence<EASTException> {

18 public EASTsequence (List<IAST> instructions) {this.instruction = instructions.toArray(new EAST[0]);

}private EAST[] instruction;

23 public IAST[] getInstructions () {return this.instruction;

}public IAST getInstruction (int i) throws EASTException {

try {28 return this.instruction[i];

} catch(ArrayIndexOutOfBoundsException exc) {throw new EASTException(exc);

}}

33 public int getInstructionsLength () {return this.instruction.length;

}

/**38 * L’évaluation d’une séquence passe par celle, ordonnée, de toutes

* les instructions qu’elle contient.** NOTA: inutile de se compliquer la vie, Java ne supporte pas la* récursion terminale.

43 * NOTA2: Le cas de la séquence vide est prévu.*/

@Overridepublic Object eval (ILexicalEnvironment lexenv, ICommon common)

48 throws EvaluationException {Object last = EAST.voidConstant();for ( int i = 0 ; i < instruction.length ; i++ ) {

last = instruction[i].eval(lexenv, common);}

53 return last;}

}

Java/src/fr/upmc/ilp/ilp1/eval/EASTvariable.java

package fr.upmc.ilp.ilp1.eval;

3 import fr.upmc.ilp.ilp1.interfaces.*;import fr.upmc.ilp.ilp1.runtime.*;

/** Une variable. */

8 public class EASTvariableextends EASTimplements IASTvariable {

public EASTvariable (String name) {13 this.name = name;

}70

private final String name;

public String getName () {18 return name;

}

@Overridepublic Object eval (ILexicalEnvironment lexenv, ICommon common)

23 throws EvaluationException {return lexenv.lookup(this);

}

}

Java/src/fr/upmc/ilp/ilp1/eval/IEASTFactory.java

package fr.upmc.ilp.ilp1.eval;2 import java.util.List;

import fr.upmc.ilp.ilp1.interfaces.IAST;import fr.upmc.ilp.ilp1.interfaces.IASTalternative;import fr.upmc.ilp.ilp1.interfaces.IASTbinaryOperation;

7 import fr.upmc.ilp.ilp1.interfaces.IASTboolean;import fr.upmc.ilp.ilp1.interfaces.IASTfloat;import fr.upmc.ilp.ilp1.interfaces.IASTinteger;import fr.upmc.ilp.ilp1.interfaces.IASTinvocation;import fr.upmc.ilp.ilp1.interfaces.IASTsequence;

12 import fr.upmc.ilp.ilp1.interfaces.IASTstring;import fr.upmc.ilp.ilp1.interfaces.IASTunaryBlock;import fr.upmc.ilp.ilp1.interfaces.IASTunaryOperation;import fr.upmc.ilp.ilp1.interfaces.IASTvariable;

17 /** Cette interface décrit une fabrique d’AST conforme aux IAST. Elle* est notamment utilisée par le convertisseur générique de DOM en* IAST (eval/EASTParser).*/

22 public interface IEASTFactory<Exc extends Exception> {

/** Créer une séquence d’AST. */IASTsequence<Exc> newSequence (List<IAST> asts);

27 /** Créer une alternative binaire. */IASTalternative<Exc> newAlternative (IAST condition,

IAST consequent);

/** Créer une alternative ternaire. */32 IASTalternative<Exc> newAlternative (IAST condition,

IAST consequent,IAST alternant);

/** Créer un bloc local unaire (avec une seule variable locale). */37 IASTunaryBlock<Exc> newUnaryBlock (IASTvariable variable,

IAST initialisation,IASTsequence<Exc> body);

/** Créer une variable. */42 IASTvariable newVariable (String name);

/** Créer une invocation (un appel à une fonction). */IASTinvocation<Exc> newInvocation (String name, List<IAST> asts);

47 /** Créer une opération unaire. */IASTunaryOperation newUnaryOperation (String operatorName,

IAST operand);/** Créer une opération binaire. */IASTbinaryOperation newBinaryOperation (String operatorName,

52 IAST leftOperand,IAST rightOperand);

/** Créer une constante littérale entière. */IASTinteger newIntegerConstant (String value);

57

/** Créer une constante littérale flottante. */IASTfloat newFloatConstant (String value);

/** Créer une constante littérale chaîne de caractères. */62 IASTstring newStringConstant (String value);

/** Créer une constante littérale booléenne. */71

Page 37: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

IASTboolean newBooleanConstant (String value);

67 /** Signaler un problème avec un message. */IAST throwParseException (String message)

throws Exc;

/** Signaler un problème avec une exception. */72 IAST throwParseException (Throwable cause)

throws Exc;

/* NOTA: on ne peut exprimer en Java que ces deux dernières méthodes* signalent toujours une exception et ne renvoient donc jamais une

77 * valeur. Comme on ne peut écrire ni:* factory.throwParseException("blabla");* [car alors la méthode englobante manque d’un return]* ni:* return factory.throwParseException("blabla");

82 * [car on ne peut renvoyer void]* je change le type de retour pour IAST. */

}

Java/src/fr/upmc/ilp/ilp1/cgen/CgenEnvironment.java

package fr.upmc.ilp.ilp1.cgen;

import java.util.*;4

import fr.upmc.ilp.ilp1.interfaces.*;

/** La représentation de l’environnement des opérateurs prédéfinis. Il* définit comment les compiler. C’est un peu l’analogue de

9 * runtime/Common pour le paquetage cgen. */

public class CgenEnvironmentimplements ICgenEnvironment {

14 private static final Map<String,String> MAP_OP1 = new HashMap<String,String>();private static final Map<String,String> MAP_OP2 = new HashMap<String,String>();static {

// Binaires:MAP_OP2.put("+", "Plus");

19 MAP_OP2.put("-", "Minus");MAP_OP2.put("*", "Times");MAP_OP2.put("/", "Divide");MAP_OP2.put("%", "Modulo");MAP_OP2.put("<", "LessThan");

24 MAP_OP2.put("<=", "LessThanOrEqual");MAP_OP2.put("==", "Equal");MAP_OP2.put(">=", "GreaterThanOrEqual");MAP_OP2.put(">", "GreaterThan");MAP_OP2.put("!=", "NotEqual");

29 // Unaires:MAP_OP1.put("-", "Opposite");MAP_OP1.put("!", "Not");

}

34 /** Comment convertir un opérateur unaire en C. */

public String compileOperator1 (final String opName)throws CgenerationException {return compileOperator(opName, MAP_OP1);

39 }

/** Comment convertir un opérateur binaire en C. */

public String compileOperator2 (final String opName)44 throws CgenerationException {

return compileOperator(opName, MAP_OP2);}

/** Méthode interne pour trouver le nom en C d’un opérateur. */49

private String compileOperator (final String opName, Map<String,String> map)throws CgenerationException {final String cName = map.get(opName);if ( cName != null ) {

54 return "ILP_" + cName;} else {

final String msg = "No such operator: " + opName;72

throw new CgenerationException(msg);}

59 }

/** Compiler une référence à une variable. */

public IASTvariable generateVariable () {64 CgenEnvironment.counter++;

return CgenEnvironment.createVariable("TEMP" + CgenEnvironment.counter);}private transient static int counter = 0;

69 private static IASTvariable createVariable (final String name) {return new IASTvariable () {

public String getName () {return name;

}74 };

}

/** Enrichir un environnement lexical avec les primitives* d’impression (print et newline). */

79

public ICgenLexicalEnvironmentextendWithPrintPrimitives (final ICgenLexicalEnvironment lexenv) {final ICgenLexicalEnvironment lexenv2 =

lexenv.extend(CgenEnvironment.createVariable("print"),84 "ILP_print");

final ICgenLexicalEnvironment lexenv3 =lexenv2.extend(CgenEnvironment.createVariable("newline"),

"ILP_newline");return lexenv3;

89 }

}

Java/src/fr/upmc/ilp/ilp1/cgen/CgenLexicalEnvironment.java

package fr.upmc.ilp.ilp1.cgen;

3 import fr.upmc.ilp.ilp1.interfaces.*;

/** La représentation des environnements lexicaux de compilation vers* C. C’est l’analogue de runtime/LexicalEnvironement pour le* paquetage cgen. */

8

public class CgenLexicalEnvironmentimplements ICgenLexicalEnvironment {

public CgenLexicalEnvironment (final IASTvariable variable,13 final String compiledName,

final ICgenLexicalEnvironment next) {this.variableName = variable.getName();this.compiledName = compiledName;this.next = next;

18 }private final String variableName;private final String compiledName;private final ICgenLexicalEnvironment next;

23 public String compile (final IASTvariable variable)throws CgenerationException {if ( variableName.equals(variable.getName()) ) {

return compiledName;} else {

28 return next.compile(variable);}

}

public ICgenLexicalEnvironment extend (final IASTvariable variable,33 final String compiledName) {

return new CgenLexicalEnvironment(variable, compiledName, this);}

public ICgenLexicalEnvironment extend (final IASTvariable variable) {38 return new CgenLexicalEnvironment(variable, variable.getName(), this);

}

// Classe interne:public static class Empty

73

Page 38: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

43 extends CgenLexicalEnvironment {

// La technique du singleton:private Empty () {

super(new IASTvariable() {48 public String getName() { return null; }

}, null, null);}private static final Empty

EMPTY_LEXICAL_ENVIRONMENT;53 static {

EMPTY_LEXICAL_ENVIRONMENT = new Empty();}

public static ICgenLexicalEnvironment create () {58 return Empty.EMPTY_LEXICAL_ENVIRONMENT;

}

@Overridepublic String compile (final IASTvariable variable)

63 throws CgenerationException {final String msg = "Variable inaccessible: " + variable.getName();throw new CgenerationException(msg);

}}

68

}

Java/src/fr/upmc/ilp/ilp1/cgen/CgenerationException.java

package fr.upmc.ilp.ilp1.cgen;

/** Les exceptions préférentiellement signalées par la conversion en C. */

5 public class CgenerationException extends Exception {

static final long serialVersionUID = +1234567890004000L;

public CgenerationException (Throwable cause) {10 super(cause);

}

public CgenerationException (String message) {super(message);

15 }

}

Java/src/fr/upmc/ilp/ilp1/cgen/Cgenerator.java

package fr.upmc.ilp.ilp1.cgen;2

import java.math.BigInteger;

import fr.upmc.ilp.ilp1.eval.EASTException;import fr.upmc.ilp.ilp1.interfaces.IAST;

7 import fr.upmc.ilp.ilp1.interfaces.IASTalternative;import fr.upmc.ilp.ilp1.interfaces.IASTbinaryOperation;import fr.upmc.ilp.ilp1.interfaces.IASTboolean;import fr.upmc.ilp.ilp1.interfaces.IASTconstant;import fr.upmc.ilp.ilp1.interfaces.IASTfloat;

12 import fr.upmc.ilp.ilp1.interfaces.IASTinteger;import fr.upmc.ilp.ilp1.interfaces.IASTinvocation;import fr.upmc.ilp.ilp1.interfaces.IASToperation;import fr.upmc.ilp.ilp1.interfaces.IASTsequence;import fr.upmc.ilp.ilp1.interfaces.IASTstring;

17 import fr.upmc.ilp.ilp1.interfaces.IASTunaryBlock;import fr.upmc.ilp.ilp1.interfaces.IASTunaryOperation;import fr.upmc.ilp.ilp1.interfaces.IASTvariable;

/** La génération vers C. */22

public class Cgenerator {

public Cgenerator (final ICgenEnvironment common) {this.common = common;

27 }74

protected final ICgenEnvironment common;

/** Convertir un AST en une chaîne de caractères C. */

32 public synchronized String compile (final IAST iast,final ICgenLexicalEnvironment lexenv,final String destination)

throws CgenerationException {this.buffer = new StringBuffer(1024);

37 buffer.append("/* Fichier compilé vers C */\n");analyze(iast, lexenv, this.common, destination);final String result = this.buffer.toString();return result;

}42 private transient StringBuffer buffer;

/** Convertir une expression en C. */

protected void analyzeExpression (final IAST iast,47 final ICgenLexicalEnvironment lexenv,

final ICgenEnvironment common)throws CgenerationException {analyze(iast, lexenv, common, "");

}52

/** Convertir une instruction en C.** La destination est soit "" (ou "(void)" pour indiquer que la* valeur obtenue est inutile, soit "return" pour indiquer que c’est

57 * la valeur finale d’une fonction ou encore "variable =" pour* ranger la valeur obtenue dans une variable.*/

protected void analyzeInstruction (final IAST iast,62 final ICgenLexicalEnvironment lexenv,

final ICgenEnvironment common,final String destination)

throws CgenerationException {analyze(iast, lexenv, common, destination);

67 }

/** Cette méthode analyse la nature de l’AST à traiter et détermine* la bonne méthode à appliquer. C’est un envoi de message simulé à* la main, l’ordre de discrimination n’est pas le plus efficace,

72 * mais utilise les marqueurs d’interface pour regrouper certains* tests. Le code spécifique aux divers cas se trouve dans les* méthodes generate() surchargées.*/

77 @SuppressWarnings(value={"unchecked"})protected void analyze (final IAST iast,

final ICgenLexicalEnvironment lexenv,final ICgenEnvironment common,final String destination)

82 throws CgenerationException {if ( iast instanceof IASTconstant ) {

if ( iast instanceof IASTboolean ) {generate((IASTboolean) iast, lexenv, common, destination);

} else if ( iast instanceof IASTfloat ) {87 generate((IASTfloat) iast, lexenv, common, destination);

} else if ( iast instanceof IASTinteger ) {generate((IASTinteger) iast, lexenv, common, destination);

} else if ( iast instanceof IASTstring ) {generate((IASTstring) iast, lexenv, common, destination);

92 } else {final String msg = "Unknown type of constant: " + iast;throw new CgenerationException(msg);

}} else if ( iast instanceof IASTalternative ) {

97 generate((IASTalternative) iast, lexenv, common, destination);} else if ( iast instanceof IASTinvocation ) {

generate((IASTinvocation) iast, lexenv, common, destination);} else if ( iast instanceof IASToperation ) {

if ( iast instanceof IASTunaryOperation ) {102 generate((IASTunaryOperation) iast, lexenv, common, destination);

} else if ( iast instanceof IASTbinaryOperation ) {generate((IASTbinaryOperation) iast, lexenv, common, destination);

} else {final String msg = "Unknown type of operation: " + iast;

107 throw new CgenerationException(msg);}} else if ( iast instanceof IASTsequence ) {

75

Page 39: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

generate((IASTsequence) iast, lexenv, common, destination);} else if ( iast instanceof IASTunaryBlock ) {

112 generate((IASTunaryBlock) iast, lexenv, common, destination);} else if ( iast instanceof IASTvariable ) {

generate((IASTvariable) iast, lexenv, common, destination);} else {

final String msg = "Unknown type of AST: " + iast;117 throw new CgenerationException(msg);

}}

/** Toutes les méthodes qui suivent remplissent le tampon courant122 * (buffer). Il y a une méthode generate par catégorie

* syntaxique. */

protected void generate (final IASTalternative<EASTException> iast,final ICgenLexicalEnvironment lexenv,

127 final ICgenEnvironment common,final String destination)

throws CgenerationException {buffer.append(" if ( ILP_isTrue( ");analyzeExpression(iast.getCondition(), lexenv, common);

132 buffer.append(" ) ) {\n");analyzeInstruction(iast.getConsequent(), lexenv, common, destination);buffer.append(";\n}");if ( iast.isTernary() ) {

buffer.append(" else {\n");137 try {

analyzeInstruction(iast.getAlternant(), lexenv, common, destination);buffer.append(";");

} catch (EASTException e) {final String msg = "Should never occur!";

142 assert false : msg;throw new CgenerationException(msg);

}buffer.append("\n}");

} else {147 buffer.append(" else {\n");

buffer.append(destination);buffer.append(" ILP_FALSE;");buffer.append("\n}");

}152 }

protected void generate (final IASTbinaryOperation iast,final ICgenLexicalEnvironment lexenv,final ICgenEnvironment common,

157 final String destination)throws CgenerationException {buffer.append(destination);buffer.append(" ");buffer.append(common.compileOperator2(iast.getOperatorName()));

162 buffer.append("(");analyzeExpression(iast.getLeftOperand(), lexenv, common);buffer.append(", ");analyzeExpression(iast.getRightOperand(), lexenv, common);buffer.append(") ");

167 }

protected void generate (final IASTboolean iast,final ICgenLexicalEnvironment lexenv,final ICgenEnvironment common,

172 final String destination)throws CgenerationException {buffer.append(destination);if ( iast.getValue() ) {

buffer.append(" ILP_TRUE ");177 } else {

buffer.append(" ILP_FALSE ");}

}

182 protected void generate (final IASTfloat iast,final ICgenLexicalEnvironment lexenv,final ICgenEnvironment common,final String destination)

throws CgenerationException {187 buffer.append(destination);

buffer.append(" ILP_Float2ILP(");buffer.append(iast.getValue());buffer.append(") ");

}76

192

protected void generate (final IASTinteger iast,final ICgenLexicalEnvironment lexenv,final ICgenEnvironment common,final String destination)

197 throws CgenerationException {final BigInteger bi = iast.getValue();// && et non || comme l’a remarqué [email protected] ( bi.compareTo(BIMIN) > 0

&& bi.compareTo(BIMAX) < 0 ) {202 buffer.append(destination);

buffer.append(" ILP_Integer2ILP(");buffer.append(bi.intValue());buffer.append(") ");

} else {207 final String msg = "Too large integer " + bi;

throw new CgenerationException(msg);}

}public static final BigInteger BIMIN;

212 public static final BigInteger BIMAX;static {

final Integer i = Integer.MIN_VALUE;BIMIN = new BigInteger(i.toString());final Integer j = Integer.MAX_VALUE;

217 BIMAX = new BigInteger(j.toString());}

protected void generate (final IASTinvocation<EASTException> iast,final ICgenLexicalEnvironment lexenv,

222 final ICgenEnvironment common,final String destination)

throws CgenerationException {buffer.append(destination);buffer.append(" ");

227 analyzeExpression(iast.getFunction(), lexenv, common);buffer.append("(");final int numberOfArguments = iast.getArgumentsLength();for ( int i=0 ; i<numberOfArguments ; i++ ) {

IAST iast2 = null;232 try {

iast2 = iast.getArgument(i);} catch (EASTException e) {

final String msg = "Should never occur!";assert false : msg;

237 throw new CgenerationException(msg);}analyzeExpression(iast2, lexenv, common);if ( i<numberOfArguments-1 ) {

buffer.append(", ");242 };

}buffer.append(")");

}

247 protected void generate (final IASTsequence<EASTException> iast,final ICgenLexicalEnvironment lexenv,final ICgenEnvironment common,final String destination)

throws CgenerationException {252 buffer.append("{\n");

final IAST[] instrs = iast.getInstructions();for ( int i = 0 ; i < instrs.length-1 ; i ++) {

final IAST iast2 = instrs[i];analyzeInstruction(iast2, lexenv, common, "(void)");

257 buffer.append(";\n");}analyzeInstruction(instrs[instrs.length-1], lexenv, common, destination);buffer.append(";\n}\n");

}262

protected void generate (final IASTstring iast,final ICgenLexicalEnvironment lexenv,final ICgenEnvironment common,final String destination)

267 throws CgenerationException {buffer.append(destination);buffer.append(" ILP_String2ILP(\"");final String s = iast.getValue();final int n = s.length();

272 for ( int i = 0 ; i<n ; i++ ) {char c = s.charAt(i);

77

Page 40: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

switch ( c ) {case ’\\’:case ’"’: {

277 buffer.append("\\");/* FALLTHRU */

}default: {

buffer.append(c);282 }

}}buffer.append("\") ");

}287

protected void generate (final IASTunaryBlock<EASTException> iast,final ICgenLexicalEnvironment lexenv,final ICgenEnvironment common,final String destination)

292 throws CgenerationException {final IASTvariable tmp = common.generateVariable();final ICgenLexicalEnvironment lexenv2 =

lexenv.extend(tmp, tmp.getName());final ICgenLexicalEnvironment lexenv3 =

297 lexenv2.extend(iast.getVariable());

buffer.append("{\n");buffer.append(" ILP_Object ");analyzeExpression(tmp, lexenv2, common);

302 buffer.append(" = ");analyzeExpression(iast.getInitialization(), lexenv, common);buffer.append(";\n");

buffer.append(" ILP_Object ");307 analyzeExpression(iast.getVariable(), lexenv3, common);

buffer.append(" = ");analyzeExpression(tmp, lexenv2, common);buffer.append(";\n");

312 analyzeInstruction(iast.getBody(), lexenv3, common, destination);buffer.append("}\n");

}

protected void generate (final IASTunaryOperation iast,317 final ICgenLexicalEnvironment lexenv,

final ICgenEnvironment common,final String destination)

throws CgenerationException {buffer.append(destination);

322 buffer.append(" ");buffer.append(common.compileOperator1(iast.getOperatorName()));buffer.append("(");analyzeExpression(iast.getOperand(), lexenv, common);buffer.append(") ");

327 }

protected void generate (final IASTvariable iast,final ICgenLexicalEnvironment lexenv,final ICgenEnvironment common,

332 final String destination)throws CgenerationException {buffer.append(destination);buffer.append(" ");buffer.append(lexenv.compile(iast));

337 buffer.append(" ");}

}

Java/src/fr/upmc/ilp/ilp1/cgen/CgeneratorTest.java

package fr.upmc.ilp.ilp1.cgen;

import java.io.File;4 import java.io.FilenameFilter;

import java.io.IOException;import java.util.List;import java.util.Vector;import java.util.regex.Matcher;

9 import java.util.regex.Pattern;

78

import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.parsers.ParserConfigurationException;

14

import junit.framework.TestCase;

import org.w3c.dom.Document;import org.xml.sax.SAXException;

19

import fr.upmc.ilp.ilp1.eval.EAST;import fr.upmc.ilp.ilp1.eval.EASTException;import fr.upmc.ilp.ilp1.eval.EASTFactory;import fr.upmc.ilp.ilp1.eval.EASTParser;

24 import fr.upmc.ilp.ilp1.eval.EASTentier;import fr.upmc.ilp.ilp1.eval.EASTsequence;import fr.upmc.ilp.ilp1.interfaces.IAST;import fr.upmc.ilp.tool1.FileTool;import fr.upmc.ilp.tool1.ProgramCaller;

29

/** Tests (JUnit) pour la compilation vers C. Il faut etre dans le repertoire* qui contient Grammars et Java afin que ce code puisse trouver les fichiers* de test a compiler. */

34 public class CgeneratorTest extends TestCase {

@Overridepublic void setUp () {final ICgenEnvironment common = new CgenEnvironment();

39 compiler = new Cgenerator(common);factory = new EASTFactory();lexenv = CgenLexicalEnvironment.Empty.create();lexenv = common.extendWithPrintPrimitives(lexenv);

}44 private Cgenerator compiler;

private EASTFactory factory;private ICgenLexicalEnvironment lexenv;

/** Verifier que l’on ne peut compiler en C un tres grand entier. */49

public void testBigInteger1 () {final List<IAST> args = new Vector<IAST>();args.add(new EASTentier("12345678909876543210123456789"));args.add(new EASTentier("1"));

54 final EAST east = new EASTsequence(args);// Compiler vers Ctry {

compiler.compile(east, lexenv, "return");} catch ( CgenerationException e) {

59 assertTrue(true);}

}

// La detection des grands entiers non compilable etait erronee64 // comme l’a remarqué [email protected]. Il faut donc tester

// aussi les grands entiers negatifs.

public void testBigInteger2 () {final List<IAST> args = new Vector<IAST>();

69 args.add(new EASTentier("-12345678909876543210123456789"));args.add(new EASTentier("1"));final EAST east = new EASTsequence(args);// Compiler vers Ctry {

74 compiler.compile(east, lexenv, "return");} catch ( CgenerationException e) {

assertTrue(true);}

}79 /** Les caractéristiques des programmes XML à tester: */

private final File directory = new File("Grammars/Samples/");private final Pattern p = Pattern.compile("^u\\d+-1.xml$");private final Pattern pfull =

84 Pattern.compile("(.*" + File.separator + "u\\d+-1).xml$");

/** Tester un programme c’est-à-dire le lire depuis XML, le* convertir en un EAST, le compiler en C, compiler ce code C avec* un patron standard et comparer le résultat avec ce qui était

89 * attendu. */

protected void handleFile (String basefilename)throws IOException, ParserConfigurationException, SAXException,

79

Page 41: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

EASTException, CgenerationException {94 // Imprimer le fichier scheme ?

File xmlFile = new File(basefilename + ".xml");DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();DocumentBuilder db = dbf.newDocumentBuilder();Document d = db.parse(xmlFile);

99 EASTParser parser = new EASTParser(factory);EAST east = (EAST) parser.parse(d);// Compiler vers CString ccode = compiler.compile(east, lexenv, "return");FileTool.stuffFile(basefilename + ".c", ccode);

104 // appeler indent, FUTUREString program = "bash "

+ "C/compileThenRun.sh "+ basefilename + ".c";

ProgramCaller pc = new ProgramCaller(program);109 pc.setVerbose();

pc.run();String expectedResult = FileTool.readExpectedResult(basefilename);String expectedPrinting = FileTool.readExpectedPrinting(basefilename);assertEquals(expectedPrinting + expectedResult, pc.getStdout().trim());

114 }

/** Rechercher tous les fichiers u*-1.xml et les tester. */

public void testUFiles ()119 throws IOException, ParserConfigurationException, SAXException,

EASTException, CgenerationException {FilenameFilter ff = new FilenameFilter() {

public boolean accept (File dir, String name) {final Matcher m = p.matcher(name);

124 return m.matches();}

};final File[] testFiles = directory.listFiles(ff);// Si cette assertion est fausse, on n’est probablement pas dans le

129 // bon repertoire.assertNotNull(testFiles);// Au moins 38 programmes de test:assertTrue(testFiles.length >= 38);// Trier les noms de fichiers en place:

134 java.util.Arrays.sort(testFiles, new java.util.Comparator<File>() {public int compare (File f1, File f2) {

return f1.getName().compareTo(f2.getName());}@Override

139 public boolean equals (Object comparator) {return false;

}});

for ( int i = 0 ; i<testFiles.length ; i++ ) {144 final String filename = testFiles[i].getPath();

System.err.println("Testing " + filename);final Matcher m = pfull.matcher(filename);assertTrue(m.matches());handleFile(m.group(1));

149 }}

}

Java/src/fr/upmc/ilp/ilp1/cgen/ICgenEnvironment.java

package fr.upmc.ilp.ilp1.cgen;2

import fr.upmc.ilp.ilp1.interfaces.*;

/** L’interface décrivant l’environnement des opérateurs prédéfinis du* langage à compiler vers C. Il est l’analogue de runtime/ICommon

7 * pour le paquetage cgen. */

public interface ICgenEnvironment {

/** Comment convertir un opérateur unaire en C. */12

String compileOperator1 (String opName)throws CgenerationException ;

/** Comment convertir un opérateur binaire en C. */17

80

String compileOperator2 (String opName)throws CgenerationException ;

/** un générateur de variables temporaires. */22

IASTvariable generateVariable ();

/** L’enrichisseur d’environnement lexical avec les primitives. */

27 ICgenLexicalEnvironmentextendWithPrintPrimitives (ICgenLexicalEnvironment lexenv);

}

Java/src/fr/upmc/ilp/ilp1/cgen/ICgenLexicalEnvironment.java

package fr.upmc.ilp.ilp1.cgen;

import fr.upmc.ilp.ilp1.interfaces.*;4

/** L’interface décrivant l’environnement lexical de compilation vers* C. Il est l’analogue de runtime/ILexicalEnvironment pour le* paquetage cgen. */

9 public interface ICgenLexicalEnvironment {

/** Renvoie le code compilé d’accès à cette variable.** @throws CgenerationException si la variable est absente.

14 */

String compile (IASTvariable variable)throws CgenerationException;

19 /** Étend l’environnement avec une nouvelle variable et vers quel* nom la compiler. */

ICgenLexicalEnvironment extend (IASTvariable variable,String compiledName );

24

/** Étend l’environnement avec une nouvelle variable qui sera* compilée par son propre nom. */

ICgenLexicalEnvironment extend (IASTvariable variable);29

}

Java/src/fr/upmc/ilp/ilp1/CoverageTest.java

package fr.upmc.ilp.ilp1;

import org.hansel.CoverageRunner;4 import org.junit.runner.RunWith;

import org.junit.runners.Suite;

/** La mode est aux annotations!* La classe n’a plus de corps seulement des annotations indiquant

9 * comment construire une instance et agir.* Cette suite de tests realise egalement des tests de couverture* a l’aide d’Hansel @see{http://hansel.sourceforge.net/}.** Attention, pour tourner ce test, il faut passer les options

14 * <code>-javaagent hansel.jar</code> a la JVM sous-jacente.*/

@RunWith(CoverageRunner.class)@Suite.SuiteClasses({

19 fr.upmc.ilp.ilp1.eval.EASTFileTest.class,fr.upmc.ilp.ilp1.cgen.CgeneratorTest.class

})@CoverageRunner.CoverClasses({

fr.upmc.ilp.ilp1.eval.EAST.class,24 fr.upmc.ilp.ilp1.eval.EASTalternative.class,

fr.upmc.ilp.ilp1.eval.EASTblocUnaire.class,fr.upmc.ilp.ilp1.eval.EASTbooleen.class,fr.upmc.ilp.ilp1.eval.EASTchaine.class,fr.upmc.ilp.ilp1.eval.EASTConstant.class,

81

Page 42: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

29 fr.upmc.ilp.ilp1.eval.EASTentier.class,fr.upmc.ilp.ilp1.eval.EASTException.class,fr.upmc.ilp.ilp1.eval.EASTFactory.class,fr.upmc.ilp.ilp1.eval.EASTflottant.class,fr.upmc.ilp.ilp1.eval.EASTinvocation.class,

34 fr.upmc.ilp.ilp1.eval.EASTinvocationPrimitive.class,fr.upmc.ilp.ilp1.eval.EASToperation.class,fr.upmc.ilp.ilp1.eval.EASToperationBinaire.class,fr.upmc.ilp.ilp1.eval.EASToperationUnaire.class,fr.upmc.ilp.ilp1.eval.EASTParser.class,

39 fr.upmc.ilp.ilp1.eval.EASTsequence.class,fr.upmc.ilp.ilp1.eval.EASTvariable.class,fr.upmc.ilp.ilp1.eval.EASTFactory.class,

})public class CoverageTest {}

Java/src/fr/upmc/ilp/ilp1/JDependTest.java

1 package fr.upmc.ilp.ilp1;

public class JDependTest {// FUTURE: verifier les dependances entre paquetages d’ilp1.

}6

// end of JDependTest.java

Java/src/fr/upmc/ilp/ilp1/Process.java

package fr.upmc.ilp.ilp1;

3 import java.io.File;

import org.w3c.dom.Document;

import fr.upmc.ilp.ilp1.cgen.CgenEnvironment;8 import fr.upmc.ilp.ilp1.cgen.Cgenerator;

import fr.upmc.ilp.ilp1.cgen.ICgenEnvironment;import fr.upmc.ilp.ilp1.cgen.ICgenLexicalEnvironment;import fr.upmc.ilp.ilp1.cgen.CgenLexicalEnvironment.Empty;import fr.upmc.ilp.ilp1.eval.EAST;

13 import fr.upmc.ilp.ilp1.eval.EASTFactory;import fr.upmc.ilp.ilp1.eval.EASTParser;import fr.upmc.ilp.ilp1.runtime.CommonPlus;import fr.upmc.ilp.ilp1.runtime.ConstantsStuff;import fr.upmc.ilp.ilp1.runtime.EmptyLexicalEnvironment;

18 import fr.upmc.ilp.ilp1.runtime.ICommon;import fr.upmc.ilp.ilp1.runtime.ILexicalEnvironment;import fr.upmc.ilp.ilp1.runtime.PrintStuff;import fr.upmc.ilp.tool1.AbstractProcess;import fr.upmc.ilp.tool1.FileTool;

23 import fr.upmc.ilp.tool1.ProgramCaller;

/** Cette classe précise comment est traité un programme d’ILP1. */

public class Process extends AbstractProcess {28

/** Un constructeur utilisant toutes les valeurs par defaut possibles. */

public Process () {this.rngFile =

33 new File("Grammars" + File.separator + "grammar1.rng");this.cFile = new File("Grammars" + File.separator

+ "Samples" + File.separator + "theProgram1.c");this.templateFileName = "templateTest.c";}

38 /** Le fichier contenant la grammaire d’ILP a utiliser: */protected final File rngFile;/** Le nom du fichier C qui sera engendré: */protected final File cFile;/** Le nom du patron C a utiliser: */

43 protected final String templateFileName;

/** Initialisation: @see fr.upmc.ilp.tool.AbstractProcess. */

/** Préparation. On analyse syntaxiquement le texte du programme,48 * on effectue quelques analyses et on l’amène à un état où il

* pourra être interprété ou compilé. Toutes les analyses communes82

* à ces deux fins sont partagées ici.*/

53 public void prepare() {try {

final Document d = getDocument(this.rngFile);

final EASTFactory factory = new EASTFactory();58 final EASTParser parser = new EASTParser(factory);

this.east = (EAST) parser.parse(d);

this.prepared = true;

63 } catch (Throwable e) {this.preparationFailure = e;

}notifyPreparationToListeners();

}68 protected EAST east;

/** Interpretation */

public void interpret() {73 try {

final ICommon intcommon = new CommonPlus();ILexicalEnvironment intlexenv = EmptyLexicalEnvironment.create();final PrintStuff intps = new PrintStuff();intlexenv = intps.extendWithPrintPrimitives(intlexenv);

78 final ConstantsStuff intcs = new ConstantsStuff();intlexenv = intcs.extendWithPredefinedConstants(intlexenv);

this.result = this.east.eval(intlexenv, intcommon);this.printing = intps.getPrintedOutput().trim();

83

this.interpreted = true;

} catch (Throwable e) {this.interpretationFailure = e;

88 }notifyInterpretationToListeners();

}

/** Compilation vers C. */93

public void compile() {try {

final ICgenEnvironment common = new CgenEnvironment();final Cgenerator compiler = new Cgenerator(common);

98 ICgenLexicalEnvironment lexenv = Empty.create();lexenv = common.extendWithPrintPrimitives(lexenv);this.ccode = compiler.compile(east, lexenv, "return");

this.compiled = true;103

} catch (Throwable e) {this.compilationFailure = e;

}notifyCompilationToListeners();

108 }

/** Exécution du programme compilé: */

public void runCompiled() {113 try {

FileTool.stuffFile(this.cFile, ccode);

// et le compiler:String program = "bash "

118 + "C/compileThenRun.sh "+ this.cFile.getAbsolutePath();

ProgramCaller pc = new ProgramCaller(program);pc.setVerbose();pc.run();

123 this.executionPrinting = pc.getStdout().trim();

this.executed = ( pc.getExitValue() == 0 );

} catch (Throwable e) {128 this.executionFailure = e;

}notifyExecutionToListeners();

}83

Page 43: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

133 }

Java/src/fr/upmc/ilp/ilp1/ProcessTest.java

1 package fr.upmc.ilp.ilp1;

import java.util.Collection;

import org.junit.Before;6 import org.junit.runner.RunWith;

import fr.upmc.ilp.tool1.AbstractProcessTest;import fr.upmc.ilp.tool1.File;import fr.upmc.ilp.tool1.Parameterized;

11 import fr.upmc.ilp.tool1.Parameterized.Parameters;

/** Cette classe de test utilise JUnit4 ainsi qu’une extension permettant de* donner (fr.upmc.ilp.tool.Parameterized) de jolis noms aux divers tests.*/

16

@RunWith(value=Parameterized.class)public class ProcessTestextends AbstractProcessTest {

21 @Beforepublic void setUp () {

this.process = new Process();}

26 /** Chercher tous les programmes à tester.** Comme c’est calculé au chargement de la classe, ce calcul doit être* statique afin de pouvoir instancier la classe avec chaque fichier* à tester. */

31

@Parameterspublic static Collection<Parameterized.TestClassParameters> data() {

AbstractProcessTest.staticSetUp("u\\d+-1");// Pour un (ou plusieurs) test(s) en particulier:

36 // AbstractProcessTest.staticSetUp("u01-1");return AbstractProcessTest.data();

}

/** Le constructeur du test sur un fichier. */41

public ProcessTest (final File file) {super(file);

}

46 // La méthode effective de test est héritée d’AbstractProcessTest}

Java/src/fr/upmc/ilp/ilp1/WholeTestSuite.java

package fr.upmc.ilp.ilp1;

3 import org.junit.runner.RunWith;import org.junit.runners.Suite;import org.junit.runners.Suite.SuiteClasses;

/** Regroupement de classes de tests d’evaluation et de compilation. */8

@RunWith(value=Suite.class)@SuiteClasses(value={

// ajout des tests de fabrication d’AST:fr.upmc.ilp.ilp1.fromxml.ASTParserTest.class,

13 // ajout des tests d’evaluation:fr.upmc.ilp.ilp1.eval.EASTTest.class,

fr.upmc.ilp.ilp1.eval.EASTPrimitiveTest.class,fr.upmc.ilp.ilp1.eval.EASTFileTest.class,// ajout des tests de compilation:

18 fr.upmc.ilp.ilp1.cgen.CgeneratorTest.class,// Un test de couverture://fr.upmc.ilp.ilp1.CoverageTest.class,// Et enfin tous les fichiers de tests un par un:fr.upmc.ilp.ilp1.ProcessTest.class

23 })public class WholeTestSuite {}

84

Java/src/fr/upmc/ilp/tool1/AbstractEnvironment.java

package fr.upmc.ilp.tool1;

/**5 * Une classe utilitaire pour les environnements: c’est une fonction

* des variables vers les valeurs representee par une liste chainee.** @param <V> la classe des variables* @param <W> la classe des valeurs

10 */

public abstract class AbstractEnvironment<V, W> {

public AbstractEnvironment(V variable, W value, AbstractEnvironment<V, W> next) {15 this.variable = variable;

this.value = value;this.next = next;

}private final V variable;

20 private W value;private final AbstractEnvironment<V, W> next;

public V getVariable () {return this.variable;

25 }public W getValue () {

return this.value;}public AbstractEnvironment<V, W> getNextEnvironment () {

30 return this.next;}

public W setValue (W newValue) {W oldValue = this.value;

35 this.value = newValue;return oldValue;

}

/** Renvoie la valeur d’une variable si prÃc©sente dans40 * l’environnement. */

public W lookup (V variable) {// NOTA: la comparaison s’effectue par equals():if (this.variable.equals(variable)) {

return this.value;45 } else {

return this.next.lookup(variable);}

}

50 }

// fin d’AbstractEnvironment.java

Java/src/fr/upmc/ilp/tool1/AbstractProcess.java

package fr.upmc.ilp.tool1;2

import java.io.IOException;import java.io.StringReader;import java.net.MalformedURLException;import java.util.List;

7 import java.util.Vector;

import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.parsers.ParserConfigurationException;

12

import org.w3c.dom.Document;import org.xml.sax.InputSource;import org.xml.sax.SAXException;

17 import com.thaiopensource.validate.ValidationDriver;

/** Cette classe abstraite est une implantation de IProcess avec quelques* methodes probablement utiles si l’on en herite. */

85

Page 44: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

22 public abstract class AbstractProcessimplements IProcess {

protected AbstractProcess () {this.listeners = new Vector<IProcessListener>();

27 }

// Gerer la liste des observateurs:

public void addProcessListener (IProcessListener ipl) {32 this.listeners.add(ipl);

}public void removeProcessListener (IProcessListener ipl) {

this.listeners.remove(ipl);}

37 private List<IProcessListener> listeners;

// Les methodes de notification

protected void notifyInitializationToListeners () {42 for ( IProcessListener listener : this.listeners ) {

listener.notifyInitialized();}

}

47 protected void notifyPreparationToListeners () {for ( IProcessListener listener : this.listeners ) {

listener.notifyPrepared();}

}52

protected void notifyInterpretationToListeners () {for ( IProcessListener listener : this.listeners ) {

listener.notifyInterpreted();}

57 }

protected void notifyCompilationToListeners () {for ( IProcessListener listener : this.listeners ) {

listener.notifyCompiled();62 }

}

protected void notifyExecutionToListeners () {for ( IProcessListener listener : this.listeners ) {

67 listener.notifyExecuted();}

}

// Autres methodes. La redefinition de ces methodes pour un langage72 // ILP ne doit pas oublier de notifier les observateurs.

/** Initialisation: On se contente de recuperer le texte du programme* dont on va s’occuper.*/

77

public void initialize (IContent ic) {try {

this.programText = ic.getContent();this.initialized = true;

82 // Notifier les observateurs:notifyInitializationToListeners();

} catch (Throwable e) {this.initializationFailure = e;

}87 }

public boolean isInitialized() {return this.initialized;

}92

public Throwable /* or null */ getInitializationFailure() {return this.initializationFailure;

}

97 public String /* or null */ getProgramText() {assert(this.initialized);return this.programText;

}

102 protected boolean initialized = false;protected Throwable initializationFailure = null;

86

protected String programText;

/** Preparation */107

public boolean isPrepared() {return this.prepared;

}protected boolean prepared = false;

112

public Throwable /* or null */ getPreparationFailure() {return this.preparationFailure;

}protected Throwable preparationFailure = null;

117

/** Un utilitaire pour la preparation. */public Document getDocument (java.io.File rngFile)

throws MalformedURLException, IOException, SAXException,ParserConfigurationException {

122 final ValidationDriver vd = new ValidationDriver();final InputSource isg = ValidationDriver.fileInputSource(

rngFile.getAbsolutePath());vd.loadSchema(isg);InputSource is =

127 new org.xml.sax.InputSource(new StringReader(this.programText));

// Manquait (comme signalé par [email protected]):if ( ! vd.validate(is) ) {

throw new SAXException("Invalid XML program!");132 };

final DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();

final DocumentBuilder db = dbf.newDocumentBuilder();137 // Le precedent flux est tari!

is = new org.xml.sax.InputSource(new StringReader(this.programText));

final Document d = db.parse(is);return d;

142 }

/** Interpretation */

public boolean isInterpreted() {147 return this.interpreted;

}protected boolean interpreted = false;

public Throwable /* or null */ getInterpretationFailure() {152 return this.interpretationFailure;

}protected Throwable interpretationFailure = null;

public String getInterpretationPrinting() {157 assert(this.interpreted);

return this.printing;}protected String printing = "";

162 public Object getInterpretationValue() {assert(this.interpreted);return this.result;

}protected Object result = null;

167

/** Compilation vers C. */

public boolean isCompiled() {return this.compiled;

172 }protected boolean compiled = false;

public Throwable /* or null */ getCompilationFailure() {return this.compilationFailure;

177 }protected Throwable compilationFailure = null;

public String getCompiledProgram() {assert(this.compiled);

182 return this.ccode;}protected String ccode;

87

Page 45: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

/** Exécution du programme compilé: */187

public Throwable /* or null */ getExecutionFailure() {return this.executionFailure;

}protected Throwable executionFailure = null;

192

public String getExecutionPrinting() {assert(this.executed);return this.executionPrinting;

}197 protected String executionPrinting;

public boolean isExecuted() {return this.executed;

}202 protected boolean executed = false;

}

Java/src/fr/upmc/ilp/tool1/AbstractProcessTest.java

1 package fr.upmc.ilp.tool1;

import static org.junit.Assert.assertEquals;import static org.junit.Assert.assertTrue;

6 import java.io.FilenameFilter;import java.util.Collection;import java.util.Vector;import java.util.regex.Matcher;import java.util.regex.Pattern;

11

import org.junit.Test;

/** Cette classe de test utilise JUnit4 ainsi qu’une extension permettant de* donner (fr.upmc.ilp.tool.Parameterized) de jolis noms aux divers tests.

16 * Elle concentre l’essentiel des methodes statiques qui permettent de tester* l’interprete et le compilateur sur une serie de fichiers specifies par un* repertoire et une expression rationnelle. Elle est generique sur la classe* implantant IProcess a tester.*/

21

public abstract class AbstractProcessTest {

/** Le process à tester. */protected IProcess process;

26

public static void staticSetUp (String thePattern) {directory = new File("Grammars" + File.separator + "Samples");pattern = thePattern;

}31

/** Le répertoire où trouver les exemples de programmes ILP à traiter.* C’est usuellement le répertoire Grammars/Samples. */

protected static File directory;/** Le motif (une regexp) indiquant les programmes ILP à traiter. */

36 protected static String pattern;

/** Chercher tous les programmes à tester.** Comme c’est calculé au chargement de la classe, ce calcul doit être

41 * statique afin de pouvoir instancier la classe avec chaque fichier* à tester. */

public static Collection<Parameterized.TestClassParameters> data() {final Pattern p = Pattern.compile("^" + pattern + ".xml$");

46 final FilenameFilter ff = new FilenameFilter() {public boolean accept (java.io.File dir, String name) {

final Matcher m = p.matcher(name);return m.matches();

}51 };

final java.io.File[] testFiles = directory.listFiles(ff);

// Vérifier qu’il y a au moins un programme à tester sinon on pourrait// avoir l’erreur bête que tout marche puisqu’aucune erreur n’a été vue!

56 if ( testFiles.length == 0 ) {final String msg = "ILP: Cannot find a single test like " + pattern;throw new RuntimeException(msg);

88

};

61 // Trier les noms de fichiers en place:java.util.Arrays.sort(testFiles,

new java.util.Comparator<java.io.File>() {public int compare (java.io.File f1, java.io.File f2) {

return f1.getName().compareTo(f2.getName());66 }

@Overridepublic boolean equals (Object comparator) {

return false;}

71 });

Collection<Parameterized.TestClassParameters> result =new Vector<Parameterized.TestClassParameters>();

for ( final java.io.File f : testFiles ) {76 result.add(new Parameterized.TestClassParameters(){

public Object[] getParameters () {return new Object[]{ new File(f) };

}public String getName () {

81 return f.getName();}

});}return result;

86 }

/** Le constructeur d’un test concernant un programme ILP à tester. */public AbstractProcessTest (final File file) {

this.file = file;91 }

// C’est un fichier avec un nom relatif comme "Grammars/Samples/u01-1.xml"// Attention, c’est un fr.upmc.ilp.tool.File et non un java.io.File!protected final File file;

96 /** Tester chaque programme ILP. */

@Test //(timeout=5000)public void handleFile ()throws Exception {

101 System.err.println("Testing " + this.file.getAbsolutePath() + " ...");

final fr.upmc.ilp.tool1.File xmlFile =new fr.upmc.ilp.tool1.File(this.file);

assertTrue(xmlFile.exists());106

this.process.initialize(xmlFile);assertTrue(this.process.isInitialized());

this.process.prepare();111 assertTrue(this.process.isPrepared());

final String expectedResult =FileTool.readExpectedResult(this.file.getNameWithoutSuffix());

final String expectedPrinting =116 FileTool.readExpectedPrinting(this.file.getNameWithoutSuffix());

{// Interpretation:this.process.interpret();

121 assertTrue(this.process.isInterpreted());final Object result = this.process.getInterpretationValue();assertEquals(expectedResult, result.toString());String printing = this.process.getInterpretationPrinting();assertEquals(expectedPrinting, printing);

126 }

{// Compilation:this.process.compile();

131 assertTrue(this.process.isCompiled());this.process.runCompiled();assertTrue(this.process.isExecuted());String printing = this.process.getExecutionPrinting();assertEquals(expectedPrinting + expectedResult, printing.trim());

136 }}

}

89

Page 46: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

Java/src/fr/upmc/ilp/tool1/CStuff.java

1 package fr.upmc.ilp.tool1;

/** Conversion de suites de lettres du monde ILP vers le monde C. */

public class CStuff {6

/** Transformer un identificateur ILP en un identificateur C. */

public static String mangle (final String s) {assert(s != null);

11 final StringBuffer sb = new StringBuffer(s.length());for ( int i=0 ; i<s.length() ; i++ ) {

final char c = s.charAt(i);if ( ( ’a’ <= c && c <= ’z’ )

|| ( ’A’ <= c && c <= ’Z’ )16 || ( ’0’ <= c && c <= ’9’ )

|| ( ’_’ == c ) ) {sb.append(c);

} else {sb.append("_");

21 sb.append(Integer.toHexString(c));}

}return sb.toString();

}26

/** Transformer une chaine ILP en une chaine C. */

public static String protect (String value) {final int n = value.length();

31 final StringBuffer result = new StringBuffer(n);for ( int i = 0 ; i<n ; i++ ) {

char c = value.charAt(i);switch ( c ) {case ’\\’:

36 case ’"’: {result.append("\\");/* FALLTHRU */

}default: {

41 result.append(c);}}

}return result.toString();

46 }

}

Java/src/fr/upmc/ilp/tool1/CStuffTest.java

1 package fr.upmc.ilp.tool1;

import junit.framework.TestCase;

public class CStuffTest extends TestCase {6

public void testMangle () {assertEquals("", CStuff.mangle(""));assertEquals("a", CStuff.mangle("a"));assertEquals("AZ9b", CStuff.mangle("AZ9b"));

11 assertNotSame("az9b", CStuff.mangle("AZ9b"));assertNotSame("AZ9B", CStuff.mangle("AZ9b"));assertEquals("i_40Z", CStuff.mangle("i@Z"));assertEquals("_40Z", CStuff.mangle("@Z"));assertEquals("_40", CStuff.mangle("@"));

16 assertEquals("i_3c0Z", CStuff.mangle("i\u03c0Z")); // Pi}

public void testProtect () {assertEquals("", CStuff.protect(""));

21 assertEquals("a", CStuff.protect("a"));assertEquals("aB?", CStuff.protect("aB?"));assertEquals("a\\\"", CStuff.protect("a\""));assertEquals("a\\\\n", CStuff.protect("a\\n"));

}90

26

}

Java/src/fr/upmc/ilp/tool1/File.java

package fr.upmc.ilp.tool1;2

import java.io.*;

public class File extends java.io.Fileimplements IContent {

7

static final long serialVersionUID = +12345678900021000L;

public File (String filename) {super(filename);

12 }

public File (java.io.File file) {super(file.getAbsolutePath());

}17

/** Calculer le nom de base (sans repertoire ni suffixe). */

public String getBaseName () {String name = getName();

22 int dotIndex = name.lastIndexOf(’.’);if (dotIndex >= 0) {

return name.substring(0, dotIndex);} else {

return name;27 }

}

/** Calculer le nom complet du fichier hors son suffixe. */

32 public String getNameWithoutSuffix () {return getParent() + File.separator + getBaseName();

}

/** Fournir le contenu d’un fichier sous la forme d’une chaine de37 * caracteres. */

public String getContent() {try {

return FileTool.slurpFile(this);42 } catch (IOException e) {

throw new RuntimeException(e);}

}

47 /** Cette methode statique est utile pour recuperer le contenu d’une* instance de java.io.File. */

public static String getContent (File file) {try {

52 return FileTool.slurpFile(file);} catch (IOException e) {

throw new RuntimeException(e);}

}57

}

Java/src/fr/upmc/ilp/tool1/FileTool.java

package fr.upmc.ilp.tool1;2

import java.io.File;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;

7

/** Utilitaire pour lire ou écrire des fichiers entiers. */

public final class FileTool {

91

Page 47: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

12 public FileTool () {super();

}

/** Convertir un fichier en une chaîne de caracteres.17 * @return le contenu du fichier lu

* @param file le fichier a lire*/

public static String slurpFile (final File file)22 throws IOException {

final FileReader fr = new FileReader(file);final int length = (int) file.length();final char[] buffer = new char[length];int offset = 0;

27 while ( offset < length ) {int read = fr.read(buffer, offset, length-offset);offset += read;

}fr.close();

32 return new String(buffer);}

/** Convertir un fichier en une chaîne de caracteres.* @return le contenu du fichier lu

37 * @param filename le nom du fichier a lire*/

public static String slurpFile (final String filename)throws IOException {

42 return FileTool.slurpFile(new File(filename));}

/** Lire un fichier correspondant au résultat attendu d’un programme ILP.* Cette methode est utile pour tester ILP car elle retire les

47 * separateurs (blancs et retours a la ligne) superflus ce qui permet* de compenser les differences d’impression entre Scheme, Java et C. */

public static String readExpectedResult (String basefilename)throws IOException {

52 File resultFile = new File(basefilename + ".result");return FileTool.slurpFile(resultFile).trim();

}

// TODO enlever les trim() en trop dans les CompilerTest57

/** Lire le fichier correspondant aux impressions attendues d’un* programme ILP. Cette methode est utile pour tester ILP car elle* retire les separateurs (blancs et retours a la ligne) superflus* ce qui permet de compenser les differences d’impression entre Scheme,

62 * Java et C. */

public static String readExpectedPrinting (String basefilename)throws IOException {File resultFile = new File(basefilename + ".print");

67 return FileTool.slurpFile(resultFile).trim();}

/** Écrire une chaîne dans un fichier.* @param filename le nom du fichier a ecrire

72 * @param s le nouveau contenu du fichier*/

public static void stuffFile (final String filename, final String s)throws IOException {

77 FileTool.stuffFile(new File(filename), s);}

/** Écrire une chaîne dans un fichier.* @param file le fichier a ecrire

82 * @param s le nouveau contenu du fichier*/

public static void stuffFile (final File file, final String s)throws IOException {

87 final FileWriter fw = new FileWriter(file);try {

fw.write(s, 0, s.length());} finally {

fw.close();92 }

92

}

}

Java/src/fr/upmc/ilp/tool1/FileToolTest.java

package fr.upmc.ilp.tool1;

import java.io.File;4 import java.io.IOException;

import junit.framework.TestCase;

/** Tests (Junit) de FileTool. */9

public class FileToolTest extends TestCase {

// Ce test ne sert qu’a invoquer le constructeur de FileTool// pour verifier que le taux de couverture

14 // est bien egal a 100% sinon Hansel declare que FileTool.<init>// n’est pas couvert! Il faut ruser un peu pour qu’Eclipse ne// s’apercoive pas que ce code est totalement inutile.

public void testInstantiation () {19 FileTool ft = new FileTool();

assertTrue(ft instanceof FileTool);}

/** Vérifier que slurpFile fonctionne sur un fichier. */24

public void testSlurpFileOnEmptyFile ()throws IOException {

File tmpFile = File.createTempFile("tsf0", "txt");String fileName = tmpFile.getAbsolutePath();

29 final String s = FileTool.slurpFile(fileName);assertTrue(s.length() == 0 );

}

/** Vérifier que stuffFile fonctionne. */34

public void testStuffFile ()throws IOException {

File tmpFile = File.createTempFile("tsf1", "txt");String fileName = tmpFile.getAbsolutePath();

39 String content = "coucou";FileTool.stuffFile(fileName, content);final String s = FileTool.slurpFile(fileName);assertEquals(content, s);

}44

public void testStuffFileChaineVide ()throws IOException {

File tmpFile = File.createTempFile("tsf2", "txt");String fileName = tmpFile.getAbsolutePath();

49 String content = "";FileTool.stuffFile(fileName, content);final String s = FileTool.slurpFile(fileName);assertEquals(content, s);

}54

}

Java/src/fr/upmc/ilp/tool1/IContent.java

package fr.upmc.ilp.tool1;

/** Une interface fournissant un contenu à savoir un programme ILP.4 * Cette interface sert le plus souvent à masquer un fichier mais ce

* pourrait être également une chaîne, une URL ou un générateur de* tests. */

public interface IContent {9

/** Fournir la chaîne de caractères représentant le programme ILP* auquel on s’intéresse.** @return String

93

Page 48: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

14 */String getContent ();

}

Java/src/fr/upmc/ilp/tool1/IProcess.java

package fr.upmc.ilp.tool1;

3 /** Cette interface décrit un java.bean pour l’évaluation d’un* programme ILP. Tous les résultats sont livrés sous forme* d’événement aux observateurs enregistrés (IProcessListener).*/

8 public interface IProcess {

void addProcessListener (IProcessListener ipl);void removeProcessListener (IProcessListener ipl);

13 // Cycle de vie

/** Initialiser le processus d’évaluation avec un contenu (le plus* souvent un fichier) qui est le texte du programme. */

void initialize (IContent ic);18 boolean isInitialized ();

Throwable getInitializationFailure ();String getProgramText ();

/** Préparer le processus d’évaluation jusqu’à choisir entre23 * interprétation ou compilation. Toutes les phases d’analyse communes

* sont effectuées ici. */void prepare ();boolean isPrepared ();Throwable getPreparationFailure ();

28

/** Évaluer par interprétation. */void interpret ();boolean isInterpreted ();Throwable getInterpretationFailure ();

33 Object getInterpretationValue ();String getInterpretationPrinting ();

/** Compiler vers un fichier. */void compile ();

38 boolean isCompiled ();Throwable getCompilationFailure ();String getCompiledProgram ();

/** Exécuter le fichier compilé. */43 void runCompiled ();

boolean isExecuted ();Throwable getExecutionFailure ();String getExecutionPrinting ();

48 }

Java/src/fr/upmc/ilp/tool1/IProcessListener.java

package fr.upmc.ilp.tool1;2

/** L’interface de l’observateur d’un IProcess. Un tel observateur peut* écrire ou visualiser à l’écran les progrès du processus observé. Le* processus est divisé en les phases suivantes:* <ol> <li> Initialisation </li>

7 * <li> Préparation </li>* <li> Interprétation </li>* <li> Compilation (vers C) </li>* <li> Exécution du programme compilé </li></ol>* */

12

public interface IProcessListener {

/** Obtenir l’unique IProcess observé pour obtenir des informations* additionnelles sur les résultats des phases d’évaluation.

17 ** @return IProcess*/ 94

IProcess getProcess ();

22 /** Par cette méthode, un IProcess indique qu’il a terminé son* initialisation. Les informations produites sont à demander* à l’IProcess observé. */

void notifyInitialized ();

27 /** Par cette méthode, un IProcess indique qu’il a terminé sa* preparation. Les informations produites sont à demander* à l’IProcess observé. */

void notifyPrepared ();

32 /** Par cette méthode, un IProcess indique qu’il a terminé son* interpretation. Les informations produites sont à demander* à l’IProcess observé. */

void notifyInterpreted ();

37 /** Par cette méthode, un IProcess indique qu’il a terminé sa* compilation. Les informations produites sont à demander* à l’IProcess observé. */

void notifyCompiled ();

42 /** Par cette méthode, un IProcess indique qu’il a terminé l’execution* du programme compile en C. Les informations produites sont à demander* à l’IProcess observé. */

void notifyExecuted ();

47 }

Java/src/fr/upmc/ilp/tool1/Parameterized.java

// $Id$package fr.upmc.ilp.tool1;

3

import static org.junit.Assert.assertEquals;

import java.lang.annotation.Annotation;import java.lang.annotation.ElementType;

8 import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;

13 import java.lang.reflect.Method;import java.lang.reflect.Modifier;import java.util.ArrayList;import java.util.Collection;import java.util.List;

18

import org.junit.internal.runners.CompositeRunner;import org.junit.internal.runners.MethodValidator;import org.junit.internal.runners.TestClassMethodsRunner;import org.junit.internal.runners.TestClassRunner;

23

/** This class is a revised version of the org.junit.runners.Parameterized* class. It modifies how the Parameters annotation is processed. Normally* the Parameters annotation annotates a static method that returns a* Collection of Objects array, it now returns a collection of

28 * TestClassParameters. An instance of the TestClassParameters interface yields* the usual array of objects with getParameters() but, additionnally* returns the name of the test with getName(). This allows, for example, in* Eclipse, to have a decent name for a test (especially these that fail)* rather than a simple integer telling its rank among all tests.

33 ** Here is an example of use: <pre>

import fr.upmc.ilp.tool.Parameterized;import fr.upmc.ilp.tool.Parameterized.Parameters;@RunWith(value=Parameterized.class)

38 public class someTest {@Parameterspublic static Collection<Parameterized.TestClassParameters> data() {

Collection<Parameterized.TestClassParameters> result = ...;result.add(new Parameterized.TestClassParameters(){

43 public Object[] getParameters () {return new Object[]{ someArguments... };

}public String getName () {

return someString;48 }

});95

Page 49: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

return result;}

</pre>53

* */

public class Parameterized extends TestClassRunner {@Retention(RetentionPolicy.RUNTIME)

58 @Target(ElementType.METHOD)public static @interface Parameters {}

/** The Parameter annotation must return a Collection of* instances of the following interface. */

63 public static interface TestClassParameters {/** Return the array of Objects needed to instantiate* a Test. These values will feed the constructor. */

Object[] getParameters ();/** A human-friendly name for the test. */

68 String getName ();}

public static Collection<Object[]> eachOne(Object... params) {List<Object[]> results= new ArrayList<Object[]>();

73 for (Object param : params)results.add(new Object[] { param });

return results;}

78 // TODO: single-class this extension

private static class TestClassRunnerForParameters extends TestClassMethodsRunner {private final TestClassParameters fParameters;

83 private final int fParameterSetNumber;

private final Constructor<?> fConstructor;

private TestClassRunnerForParameters(Class<?> klass, TestClassParameters parameters, int i) {88 super(klass);

fParameters= parameters;fParameterSetNumber= i;fConstructor= getOnlyConstructor();

}93

@Overrideprotected Object createTest() throws Exception {

return fConstructor.newInstance(fParameters.getParameters());}

98

@Overrideprotected String getName() {

return String.format("[%d-%s]", fParameterSetNumber, fParameters.getName());}

103

@Overrideprotected String testName(final Method method) {

return String.format("%s[%d-%s]", method.getName(), fParameterSetNumber, fParameters.getName());}

108

private Constructor<?> getOnlyConstructor() {Constructor<?>[] constructors= getTestClass().getConstructors();assertEquals(1, constructors.length);return constructors[0];

113 }}

// TODO: I think this now eagerly reads parameters, which was never the point.

118 public static class RunAllParameterMethods extends CompositeRunner {private final Class<?> fKlass;

public RunAllParameterMethods(Class<?> klass) throws Exception {super(klass.getName());

123 fKlass= klass;int i= 0;for (final TestClassParameters parameters : getParametersList()) {

super.add(new TestClassRunnerForParameters(klass, parameters, i++));}

128 }

@SuppressWarnings("unchecked")private Collection<TestClassParameters> getParametersList() throws IllegalAccessException, InvocationTargetException, Exception {

96

return (Collection<TestClassParameters>) getParametersMethod().invoke(null);133 }

private Method getParametersMethod() throws Exception {for (Method each : fKlass.getMethods()) {

if (Modifier.isStatic(each.getModifiers())) {138 Annotation[] annotations= each.getAnnotations();

for (Annotation annotation : annotations) {if (annotation.annotationType() == Parameters.class)

return each;}

143 }}throw new Exception("No public static parameters method on class "

+ getName());}

148 }

public Parameterized(final Class<?> klass) throws Exception {super(klass, new RunAllParameterMethods(klass));

}153

@Overrideprotected void validate(MethodValidator methodValidator) {

methodValidator.validateStaticMethods();methodValidator.validateInstanceMethods();

158 }}

Java/src/fr/upmc/ilp/tool1/ProgramCaller.java

1 package fr.upmc.ilp.tool1;

import java.io.BufferedInputStream;import java.io.IOException;import java.io.InputStream;

6 import java.util.concurrent.CountDownLatch;

/** Une classe pour invoquer un programme externe (gcc par exemple) et* récupérer le contenu de son flux de sortie. */

11 public class ProgramCaller {

/** Construire une instance de ProgramCaller qui permettra d’exécuter* une commande via le système d’exploitation.*

16 * @param program* la commande (programme et arguments) à exécuter.*/

public ProgramCaller (final String program) {21 this.program = program;

this.stdout = new StringBuffer(1023);this.stderr = new StringBuffer(1023);this.countDownLatch = new CountDownLatch(2);this.running = false;

26 this.verbose = 0;}private final String program;private static final Runtime RUNTIME = Runtime.getRuntime();private Process process;

31 private final StringBuffer stdout;private final StringBuffer stderr;private CountDownLatch countDownLatch;private boolean running;private int verbose = 0;

36

/** Verbaliser les traces d’exécution de la commande. */

public void setVerbose () {this.verbose++;

41 }

private void verbalize (final String message) {this.verbalize(message, 0);

}46

private void verbalize (final String message, final int level) {if ( this.verbose > level ) {

System.err.println(message);97

Page 50: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

};51 }

/** Récupérer le flux de sortie produit par la commande.** @return la sortie standard de la commande

56 */

public String getStdout () {return stdout.toString();

}61

/** Récupérer le flux de sortie d’erreur produit par la commande.** @return la sortie d’erreur de la commande*/

66

public String getStderr () {return stderr.toString();

}

71 /** Recuperer le code de retour de la commande.* Bloque quand celle-ci n’est pas terminee.** @return le code de retour*/

76

public int getExitValue () {this.verbalize("-getExitValue-", 10);try {

this.countDownLatch.await();81 } catch (InterruptedException e) {

this.verbalize("-getExitValue Exception-", 10);throw new RuntimeException(); // MOCHE

}return this.exitValue;

86 }private transient int exitValue = 199;

/** Lancer la commande et stocker ses flux de sortie (normale et* d’erreur) dans un tampon pour pouvoir les analyser apres-coup. */

91

public void run () {// Au plus, une seule invocation:synchronized (this) {

if ( running ) {96 return;

} else {running = true;

}}

101 // Exécuter la commande:verbalize("[Running: " + program + "...");try {

this.process = RUNTIME.exec(program);} catch (java.io.IOException e) {

106 // Exception signalee quand le programme n’existe pas:this.stderr.append(e.getMessage());// On ne fait pas partir les deux taches slurpStd*():this.countDownLatch.countDown();this.countDownLatch.countDown();

111 verbalize("...not started]");return;

} catch (Throwable t) {this.stderr.append(t.getMessage());// On ne fait pas partir les deux taches slurpStd*():

116 this.countDownLatch.countDown();this.countDownLatch.countDown();verbalize("...not started]");return;

}121

// NOTA: documentation tells that, on Windows, one should read// asap the results or deadlocks may occur.slurpStdOut();slurpStdErr();

126

try {this.process.waitFor();this.countDownLatch.await();

} catch (InterruptedException e) {131 this.verbalize("!run Exception!", 10);

98

throw new RuntimeException(); // MOCHE}this.exitValue = this.process.exitValue();verbalize("...finished]");

136 }

private void slurpStdOut () {final InputStream istdout = process.getInputStream();final BufferedInputStream bstdout = new BufferedInputStream(istdout);

141 final Thread tstdout = new Thread () {

@Overridepublic void run () {

final int size = 4096;146 final byte[] buffer = new byte[size];

READ:while ( true ) {

int count = 0;try {

151 count = bstdout.read(buffer, 0, size);} catch (IOException exc) {

continue READ;}if ( count > 0 ) {

156 final String s = new String(buffer, 0, count);stdout.append(s);ProgramCaller.this.verbalize("[stdout Reading: " + s + "]");

} else if ( count == -1 ) {ProgramCaller.this.verbalize("[stdout Dried!]", 10);

161 ProgramCaller.this.countDownLatch.countDown();return;

}}

}166 };

tstdout.start();}

// La meme chose sur le flux d’erreur:171 private void slurpStdErr () {

final InputStream istderr = process.getErrorStream();final BufferedInputStream bstderr = new BufferedInputStream(istderr);final Thread tstderr = new Thread () {

176 @Overridepublic void run () {

final int size = 4096;final byte[] buffer = new byte[size];READ:

181 while ( true ) {int count = 0;try {

count = bstderr.read(buffer, 0, size);} catch (IOException exc) {

186 continue READ;}if ( count > 0 ) {

final String s = new String(buffer, 0, count);stderr.append(s);

191 ProgramCaller.this.verbalize("[stderr Reading: " + s + "]");} else if ( count == -1 ) {

ProgramCaller.this.verbalize("[stderr Dried!]", 10);ProgramCaller.this.countDownLatch.countDown();return;

196 }}

}};tstderr.start();

201 }

}

Java/src/fr/upmc/ilp/tool1/ProgramCallerTest.java

1 package fr.upmc.ilp.tool1;

import java.util.regex.Matcher;import java.util.regex.Pattern;

99

Page 51: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

6 import junit.framework.TestCase;

/** Tests (Junit) de ProgramCaller. */

public class ProgramCallerTest extends TestCase {11

public void testProgramCallerInexistentVerbose () {final String programName = "lasdljsdfousadfl lsjd";ProgramCaller pc = new ProgramCaller(programName);assertNotNull(pc);

16 pc.setVerbose();pc.run();assertTrue(pc.getExitValue() != 0);

}

21 public void testProgramCallerInexistent () {final String programName = "lasdljsdfousadfl lsjd";ProgramCaller pc = new ProgramCaller(programName);pc.run();final String result = pc.getStderr();

26 System.err.println("Result: " + result); // DEBUGPattern p = Pattern.compile(".*(not found|Cannot run).*");Matcher m = p.matcher(result);assertTrue(m.matches());assertTrue(pc.getExitValue() != 0);

31 }

public void testProgramCallerEchoVerbose () {final ProgramCaller pc = new ProgramCaller("echo cou cou cou");assertNotNull(pc);

36 assertTrue(pc instanceof ProgramCaller);pc.setVerbose();pc.run();assertTrue(pc.getExitValue() == 0);final String result = pc.getStdout();

41 System.err.println("Result: " + result); // DEBUGassertNotNull(result);assertTrue(result.length() > 0);assertEquals(result.trim(), "cou cou cou");

}46

public void testProgramCallerEcho () {final ProgramCaller pc = new ProgramCaller("echo cou cou cou");assertNotNull(pc);assertTrue(pc instanceof ProgramCaller);

51 pc.run();assertTrue(pc.getExitValue() == 0);final String result = pc.getStdout();System.err.println("Result: " + result); // DEBUGassertNotNull(result);

56 assertTrue(result.length() > 0);assertEquals(result.trim(), "cou cou cou");

}

public void testProgramCallerGccOnStdout () {61 final ProgramCaller pc = new ProgramCaller("gcc -v");

assertNotNull(pc);assertTrue(pc instanceof ProgramCaller);pc.run();assertTrue(pc.getExitValue() == 0);

66 final String result = pc.getStdout();System.err.println("Result: " + result); // DEBUGassertNotNull(result);assertTrue(result.length() == 0);assertEquals(result.trim(), "");

71 }

public void testProgramCallerGccOnStderr () {final ProgramCaller pc = new ProgramCaller("gcc -c unexistent.c");assertNotNull(pc);

76 assertTrue(pc instanceof ProgramCaller);pc.run();assertTrue(pc.getExitValue() != 0);final String errors = pc.getStderr();System.err.println("Errors: " + errors); // DEBUG

81 assertNotNull(errors);assertTrue(errors.length() > 0);Pattern p = Pattern.compile(".*gcc.*", Pattern.DOTALL);Matcher m = p.matcher(errors);assertTrue(m.matches());

86 }

100

public void testProgramCallerGccOnStderrVerbose () {final ProgramCaller pc = new ProgramCaller("gcc -c unexistent.c");assertNotNull(pc);

91 assertTrue(pc instanceof ProgramCaller);pc.setVerbose();pc.run();assertTrue(pc.getExitValue() != 0);final String errors = pc.getStderr();

96 System.err.println("Errors: " + errors); // DEBUGassertNotNull(errors);assertTrue(errors.length() > 0);Pattern p = Pattern.compile(".*gcc.*", Pattern.DOTALL);Matcher m = p.matcher(errors);

101 assertTrue(m.matches());}

public void testProgramCallerVerbose () {final ProgramCaller pc = new ProgramCaller("echo Voir ce qui se passe");

106 assertNotNull(pc);assertTrue(pc instanceof ProgramCaller);pc.setVerbose();pc.run();assertTrue(pc.getExitValue() == 0);

111 final String result = pc.getStdout();System.err.println("Result: " + result); // DEBUGassertNotNull(result);assertTrue(result.length() > 0);Pattern p1 = Pattern.compile(".*Voir ce qui se passe.*");

116 Matcher m1 = p1.matcher(result.trim());assertTrue(m1.matches());// verifier verbosite sur stderr FUTUREfinal String errors = pc.getStderr();System.err.println("Errors: " + errors); // DEBUG

121 assertNotNull(errors);assertTrue(errors.length() == 0);

}

// test de 8 taches en parallele:126

public void testMultipleProgramCallers () {final int max = 8;final ProgramCaller[] pcs = new ProgramCaller[max];for ( int i = max ; i>0 ; i-- ) {

131 pcs[i-1] = new ProgramCaller("sleep " + i);pcs[i-1].run();

}for ( int i = 0 ; i<max ; i++ ) {

assertTrue(pcs[i].getExitValue() == 0);136 }

}

}

Java/src/fr/upmc/ilp/tool1/ToolTestSuite.java

package fr.upmc.ilp.tool1;

import junit.framework.Test;import junit.framework.TestSuite;

5 import org.hansel.CoverageDecorator;

/** Regroupement de classes de tests pour le paquetage fr.upmc.ilp.tool.* Si tourne directement a partir d’Eclipse, le repertoire doit etre* Java/src/

10 */

public final class ToolTestSuite extends TestSuite {

public static FileTool ft;15

/*** Tester les classes de test. Realiser* egalement une analyse du taux de couverture des tests*

20 * @return Test - la suite de tests a effectuer*/

public static Test suite () {final TestSuite suite = new TestSuite();

25 suite.addTest(101

Page 52: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

new CoverageDecorator(FileToolTest.class,new Class[] {fr.upmc.ilp.tool1.FileTool.class}));

suite.addTest(30 new CoverageDecorator(

CStuffTest.class,new Class[] {fr.upmc.ilp.tool1.CStuff.class}));

suite.addTestSuite(ProgramCallerTest.class);return suite;

35 }

}

C/C.readme

Ce répertoire contient la bibliothèque d’exécution des différentes2 versions d’ILP. Le Makefile contient les règles de reconstruction. Si

vous souhaitez utiliser un GC (glaneur de cellule ou garbagecollector), il faut installer le gc de Boehm présent dans gc.tgzet, pour cela, tourner:

7 make gc6.2/gc.a

Si les tests du GC passent, vous pouvez utiliser l’option +gc danscompileThenRun.sh.

12 #fin.

C/Makefile

# On efface les resultats de compilation pour faciliter le changement# de machine (et d’architecture (Intel*86 vers powerpc par exemple)).

3 # En fait, il serait mieux de stocker les .o et .a dans un# sous-repertoire mais comment automatiser (de facon portable) cela# sous un OS non Unix ?

work : clean libilp.a8

# Effacer les resultats de compilation

clean :-rm -f *.o libilp.a

13

# Les bibliotheques d’execution sont compilees en mode debug, c’est# plus utile pour les exercices.

CC = gcc18 CFLAGS = -Wall -ansi -pedantic -g

# On compile tout ce qui est en C.

CFILES = $(shell ls ilp*.c)23

# On place ilpBasicError dans l’archive et non ilpError (afin de# pouvoir en changer s’il le faut).

ARFILES = ilp.o ilpAlloc.o ilpBasicError.o ilpException.o28

# Ne pas oublier ranlib, c’est utile sur MacOSX.

libilp.a : ${CFILES:.c=.o}ar cvr libilp.a ${ARFILES}

33 -ranlib libilp.a

# Autres dependances:

ilp.o : ilp.c ilp.h38 ilpAlloc.o : ilpAlloc.c ilpAlloc.h ilp.h

ilpBasicError.o : ilpBasicError.c ilpBasicError.h ilp.hilpException.o : ilpException.c ilpException.h ilp.hilpError.o : ilpError.c ilpBasicError.h ilp.hilpObj.o : ilpObj.c ilpObj.h

43

# L’option +gc de compileThenRun.sh utilise le GC de Boehm qu’il faut# aussi installer (cf. C.readme):

gc6.2/gc.a : gc.tgz102

48 [ -d gc6.2 ] || tar xzf gc.tgzcd gc6.2/ && make test

# end of Imakefile

C/compileThenRun.sh

#! /bin/bash# Compiler le fichier templateTest.c dûment instancié avec le fichier# passé en argument.

4

USAGE="Usage: $0 [ -template.c ] [ +gc ] foo.c [bar.o ...]Compile les fichiers C, cree puis execute l’executable /tmp/templateTest$USER

template.c est le fichier devant inclure foo.c9 [Il y en a un par version d’ILP]

+gc est une option incluant le GC de Boehm (si utilisable)foo.c est le resultat de la compilation d’ILPbar.o sont des modules compiles a utiliser plutot que ceux de libilp.a

[libilp.a contient les modules par defaut d’ILP1. Pour certaines14 versions d’ILP, il faut des modules plus appropries.]

EXEMPLES:pour ILP1:

$0 foo.c19 pour ILP2:

$0 -templateTest2.c foo.cpour ILP3 ou ILP4:

$0 -templateTest3.c foo.c ilpError.opour ILP6:

24 $0 -templateTest6.c foo.c ilpObj.o"

# Les variables contrôlant si l’on utilise le GC de Boehm:# Chemin relatif vers la bibliotheque statique:

29 LIB_GC=gc6.2/gc.a# Incorpore-t-on un GC ou pas ?WITH_GC=false

# Le fichier servant de réceptacle au code C produit:34 # Chemin relatif vers ce fichier:

TEMPLATE=templateTest.c

case "$1" in-*.c)

39 TEMPLATE=${1#-}shift;;

-*)echo "Unknown option: $1"

44 exit 11;;

esac

case "$1" in49 +gc)

WITH_GC=trueshift;;

esac54

# Le fichier de code C produit à compiler avec gcc:FILE=$1shift

59 CFLAGS=’-Wall -Wno-unused-variable -Wno-unused-label -ansi -pedantic -g’# NOTE: Il y a des tests avec des variables inutilisees, ne pas# attirer l’attention dessus.

if [ -r "$FILE" ]64 then

# Rendre FILE absolu:case "$FILE" in

/*)true

69 ;;*)

FILE=‘pwd‘/$FILE;;

esac103

Page 53: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

74 elseecho Fichier inexistant: $FILE >&2exit 1

fi

79 COMMAND_DIR=‘dirname $0‘case "$COMMAND_DIR" in

# rendre le repertoire qui contient compileThenRun.sh absolu:/*)

true84 ;;

*)COMMAND_DIR=‘pwd‘/$COMMAND_DIR;;

esac89

if [ ! -r $COMMAND_DIR/libilp.a ]then

echo Bibliotheque introuvable: $COMMAND_DIR/libilp.a >&2exit 3

94 fi

if [ ! -r $COMMAND_DIR/$TEMPLATE ]then

echo Fichier introuvable: $COMMAND_DIR/$TEMPLATE >&299 exit 5

fi

if $WITH_GCthen

104 if [ -r $COMMAND_DIR/$LIB_GC ]then

CFLAGS="-DWITH_GC $CFLAGS"else

echo "GC introuvable (consulter Makefile): $COMMAND_DIR/$LIB_GC" >&2109 # On continue sans GC puisque non compilé!

WITH_GC=falsefi

fi

114 # Collecter les fichiers (.o, .a ou .c) à incorporer et les rendre absolus:OFILES=for ofiledo

case "$ofile" in119 /*)

true;;

*)ofile=$COMMAND_DIR/$ofile

124 if [ ! -r $ofile ]then

echo Module introuvable: $ofile >&2exit 7

fi129 ;;

esacOFILES="$OFILES $ofile"

done

134 OTHER_LIBS=if $WITH_GCthen OTHER_LIBS="$OTHER_LIBS $COMMAND_DIR/$LIB_GC"fi

139 AOUT=/tmp/templateTest$USERif [ -r $AOUT ]then rm -f $AOUTfi

144 #echo Trying to compile $FILE ... >&2gcc ${CFLAGS} -o $AOUT -DFICHIER_C="\"$FILE\"" \

-I. -I$COMMAND_DIR \$COMMAND_DIR/$TEMPLATE \$OFILES $COMMAND_DIR/libilp.a $OTHER_LIBS && \

149 $AOUT

# end of compileThenRun.sh

C/ilp.c

104

/** Ce fichier constitue la bibliothèque d’exécution d’ILP. */

#include <stdio.h>4 #include <stdlib.h>

#include <string.h>#include <ctype.h>#include "ilpAlloc.h"#include "ilpBasicError.h"

9 #include "ilp.h"

/** Booléens.** On alloue statiquement les deux booléens.

14 */

struct ILP_Object ILP_object_true = {ILP_BOOLEAN_KIND,{ ILP_BOOLEAN_TRUE_VALUE }

19 };

struct ILP_Object ILP_object_false = {ILP_BOOLEAN_KIND,{ ILP_BOOLEAN_FALSE_VALUE }

24 };

/** Une fonction pour stopper abruptement l’application. */

ILP_Object29 ILP_die (char *message)

{fputs(message, stderr);fputc(’\n’, stderr);fflush(stderr);

34 exit(EXIT_FAILURE);}

/** Allocateurs. */

39 /** Ce n’est pas une vraie allocation mais une simple conversion. */

ILP_ObjectILP_make_boolean (int b){

44 if ( b ) {return ILP_TRUE;

} else {return ILP_FALSE;

}49 }

ILP_ObjectILP_make_integer (int d){

54 ILP_Object result = ILP_AllocateInteger();result->_content.asInteger = d;return result;

}

59 ILP_ObjectILP_make_float (double d){

ILP_Object result = ILP_AllocateFloat();result->_content.asFloat = d;

64 return result;}

ILP_ObjectILP_make_string (char *s)

69 {int size = strlen(s);ILP_Object result = ILP_AllocateString(size);result->_content.asString._size = size;memmove(result->_content.asString.asCharacter, s, size);

74 return result;}

/** String primitives */

79 static ILP_ObjectILP_concatenate_strings (ILP_Object o1, ILP_Object o2){

int size1 = o1->_content.asString._size;105

Page 54: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

int total_size = size1 + o2->_content.asString._size;84 ILP_Object result = ILP_AllocateString(total_size);

memmove(&(result->_content.asString.asCharacter[0]),o1->_content.asString.asCharacter,o1->_content.asString._size);

memmove(&(result->_content.asString.asCharacter[size1]),89 o2->_content.asString.asCharacter,

o2->_content.asString._size);return result;

}

94 /** Opérateurs unaires. */

ILP_ObjectILP_make_opposite (ILP_Object o){

99 ILP_CheckIfInteger(o);{

ILP_Object result = ILP_AllocateInteger();result->_content.asInteger = (- o->_content.asInteger);return result;

104 }}

ILP_ObjectILP_make_negation (ILP_Object o)

109 {ILP_CheckIfBoolean(o);{

if ( ILP_isTrue(o) ) {return ILP_FALSE;

114 } else {return ILP_TRUE;

}}

}119

/** Opérateurs binaires. */

/* DefineOperator(addition, +) est incorrect car + représente également* la concaténation des chaînes de caractères. */

124

ILP_ObjectILP_make_addition (ILP_Object o1, ILP_Object o2){

if ( ILP_isInteger(o1) ) {129 if ( ILP_isInteger(o2) ) {

ILP_Object result = ILP_AllocateInteger();result->_content.asInteger =

o1->_content.asInteger + o2->_content.asInteger;return result;

134 } else if ( ILP_isFloat(o2) ) {ILP_Object result = ILP_AllocateFloat();result->_content.asFloat =

o1->_content.asInteger + o2->_content.asFloat;return result;

139 } else {return ILP_domain_error("Not a number", o2);

}} else if ( ILP_isFloat(o1) ) {

if ( ILP_isInteger(o2) ) {144 ILP_Object result = ILP_AllocateFloat();

result->_content.asFloat =o1->_content.asFloat + o2->_content.asInteger;

return result;} else if ( ILP_isFloat(o2) ) {

149 ILP_Object result = ILP_AllocateFloat();result->_content.asFloat =

o1->_content.asFloat + o2->_content.asFloat;return result;

} else {154 return ILP_domain_error("Not a number", o2);

}} else if ( ILP_isString(o1) ) {

if ( ILP_isString(o2) ) {return ILP_concatenate_strings(o1, o2);

159 } else {return ILP_domain_error("Not a string", o2);

}} else {

return ILP_domain_error("Not addable", o1);164 }

106

}

#define DefineOperator(name,op) \ILP_Object \

169 ILP_make_##name (ILP_Object o1, ILP_Object o2) \{ \

if ( ILP_isInteger(o1) ) { \if ( ILP_isInteger(o2) ) { \

ILP_Object result = ILP_AllocateInteger(); \174 result->_content.asInteger = \

o1->_content.asInteger op o2->_content.asInteger; \return result; \

} else if ( ILP_isFloat(o2) ) { \ILP_Object result = ILP_AllocateFloat(); \

179 result->_content.asFloat = \o1->_content.asInteger op o2->_content.asFloat; \

return result; \} else { \

return ILP_domain_error("Not a number", o2); \184 } \

} else if ( ILP_isFloat(o1) ) { \if ( ILP_isInteger(o2) ) { \

ILP_Object result = ILP_AllocateFloat(); \result->_content.asFloat = \

189 o1->_content.asFloat op o2->_content.asInteger; \return result; \

} else if ( ILP_isFloat(o2) ) { \ILP_Object result = ILP_AllocateFloat(); \result->_content.asFloat = \

194 o1->_content.asFloat op o2->_content.asFloat; \return result; \

} else { \return ILP_domain_error("Not a number", o2); \

} \199 } else { \

return ILP_domain_error("Not a number", o1); \} \

}

204 DefineOperator(subtraction, -)DefineOperator(multiplication, *)DefineOperator(division, /)

/* DefineOperator(modulo, %) est incorrect car le modulo ne se prend209 * que sur de entiers. */

ILP_ObjectILP_make_modulo (ILP_Object o1, ILP_Object o2){

214 if ( ILP_isInteger(o1) ) {if ( ILP_isInteger(o2) ) {

ILP_Object result = ILP_AllocateInteger();result->_content.asInteger =

o1->_content.asInteger % o2->_content.asInteger;219 return result;

} else {return ILP_domain_error("Not an integer", o2);

}} else {

224 return ILP_domain_error("Not an integer", o1);}

}

#define DefineComparator(name,op) \229 ILP_Object \

ILP_compare_##name (ILP_Object o1, ILP_Object o2) \{ \

if ( ILP_isInteger(o1) ) { \if ( ILP_isInteger(o2) ) { \

234 return ILP_make_boolean( \o1->_content.asInteger op o2->_content.asInteger); \

} else if ( ILP_isFloat(o2) ) { \return ILP_make_boolean( \

o1->_content.asInteger op o2->_content.asFloat); \239 } else { \

return ILP_domain_error("Not a number", o2); \} \

} else if ( ILP_isFloat(o1) ) { \if ( ILP_isInteger(o2) ) { \

244 return ILP_make_boolean( \o1->_content.asFloat op o2->_content.asInteger); \

} else if ( ILP_isFloat(o2) ) { \107

Page 55: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

return ILP_make_boolean( \o1->_content.asFloat op o2->_content.asFloat); \

249 } else { \return ILP_domain_error("Not a number", o2); \

} \} else { \

return ILP_domain_error("Not a number", o1); \254 } \

}

DefineComparator(less_than, <)DefineComparator(less_than_or_equal, <=)

259 DefineComparator(equal, ==)DefineComparator(greater_than, >)DefineComparator(greater_than_or_equal, >=)DefineComparator(not_equal, !=)

264 /** Primitives */

ILP_ObjectILP_newline (){

269 fputc(’\n’, stdout);return ILP_FALSE;

}

ILP_Object274 ILP_print (ILP_Object o)

{switch (o->_kind) {

case ILP_INTEGER_KIND: {fprintf(stdout, "%d", o->_content.asInteger);

279 break;}case ILP_FLOAT_KIND: {

/* Supprimer les blancs du debut */char buffer[15];

284 char *p = &buffer[0];sprintf(buffer, "%12.5g", o->_content.asFloat);while ( isspace(*p) ) {

p++;}

289 fprintf(stdout, "%s", p);break;

}case ILP_BOOLEAN_KIND: {

fprintf(stdout, "%s", (ILP_isTrue(o) ? "true" : "false"));294 break;

}case ILP_STRING_KIND: {

fprintf(stdout, "%s", o->_content.asString.asCharacter);break;

299 }default: {

fprintf(stdout, "<0x%x:0x%p>", o->_kind, (void*) o);break;

}304 }

return ILP_FALSE;}

309 /* end of ilp.c */

C/ilp.h

1 /* $Id: ilp.h 607 2007-01-05 21:27:15Z queinnec $ */

#ifndef ILP_H#define ILP_H

6 /** Il y a cinq types de valeurs pour l’instant repérées par ces* constantes (elles figureront dans le champ _kind d’ILP_Object.*/

enum ILP_Kind {11 ILP_BOOLEAN_KIND = 0xab010ba,

ILP_INTEGER_KIND = 0xab020ba,ILP_FLOAT_KIND = 0xab030ba,ILP_STRING_KIND = 0xab040ba,

108

ILP_PRIMITIVE_KIND = 0xab050ba16 };

/** Il y a deux sortes de booléens et ces deux constantes les repèrent. */

enum ILP_BOOLEAN_VALUE {21 ILP_BOOLEAN_FALSE_VALUE = 0,

ILP_BOOLEAN_TRUE_VALUE = 1};

/** Toutes les valeurs manipulées ont cette forme.26 *

* Un premier champ indique leur nature ce qui permet de décoder le* champ qui suit. Les chaînes de caractères sont préfixées par leur* longueur.

31 * NOTE: asBoolean est la première possibilité ce qui est nécessaire pour* l’allocation statiques des booléens (cf. ilp.c). Ce ne l’était pas* auparavant ce qui créait une bogue pour MacOSX (ILP_TRUE valait faux!).*/

36 typedef struct ILP_Object {enum ILP_Kind _kind;union {

unsigned char asBoolean;int asInteger;

41 double asFloat;struct asString {

int _size;char asCharacter[1];

} asString;46 struct asPrimitive {

void* _code;} asPrimitive;

} _content;} *ILP_Object;

51

/** -------------------------------------------* Des macros pour manipuler toutes ces valeurs.*/

56 /** Booléens. */

#define ILP_Boolean2ILP(b) \ILP_make_boolean(b)

61 #define ILP_isBoolean(o) \((o)->_kind == ILP_BOOLEAN_KIND)

#define ILP_isTrue(o) \(((o)->_kind == ILP_BOOLEAN_KIND) && \

66 ((o)->_content.asBoolean))

#define ILP_TRUE (&ILP_object_true)#define ILP_FALSE (&ILP_object_false)

71 #define ILP_isEquivalentToTrue(o) \((o) != ILP_FALSE)

#define ILP_CheckIfBoolean(o) \if ( ! ILP_isBoolean(o) ) { \

76 ILP_domain_error("Not a boolean", o); \};

/** Entiers */

81 #define ILP_Integer2ILP(i) \ILP_make_integer(i)

#define ILP_AllocateInteger() \ILP_malloc(sizeof(struct ILP_Object), ILP_INTEGER_KIND)

86

#define ILP_isInteger(o) \((o)->_kind == ILP_INTEGER_KIND)

#define ILP_CheckIfInteger(o) \91 if ( ! ILP_isInteger(o) ) { \

ILP_domain_error("Not an integer", o); \};

/** Flottants */96

109

Page 56: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

#define ILP_Float2ILP(f) \ILP_make_float(f)

#define ILP_AllocateFloat() \101 ILP_malloc(sizeof(struct ILP_Object), ILP_FLOAT_KIND)

#define ILP_isFloat(o) \((o)->_kind == ILP_FLOAT_KIND)

106 #define ILP_CheckIfFloat(o) \if ( ! ILP_isFloat(o) ) { \

ILP_domain_error("Not a float", o); \};

111 /** Chaînes de caractères */

#define ILP_String2ILP(s) \ILP_make_string(s)

116 #define ILP_AllocateString(length) \ILP_malloc(sizeof(struct ILP_Object) \

+ (sizeof(char) * (length)), ILP_STRING_KIND)

#define ILP_isString(o) \121 ((o)->_kind == ILP_STRING_KIND)

#define ILP_CheckIfString(o) \if ( ! ILP_isString(o) ) { \

ILP_domain_error("Not a string", o); \126 };

/** Opérateurs unaires */

#define ILP_Opposite(o) \131 ILP_make_opposite(o)

#define ILP_Not(o) \ILP_make_negation(o)

136 /** Opérateurs binaires FUTURE */

#define ILP_Plus(o1,o2) \ILP_make_addition(o1, o2)

141 #define ILP_Minus(o1,o2) \ILP_make_subtraction(o1, o2)

#define ILP_Times(o1,o2) \ILP_make_multiplication(o1, o2)

146

#define ILP_Divide(o1,o2) \ILP_make_division(o1, o2)

#define ILP_Modulo(o1,o2) \151 ILP_make_modulo(o1, o2)

/** modulo a faire */

#define ILP_LessThan(o1,o2) \156 ILP_compare_less_than(o1,o2)

#define ILP_LessThanOrEqual(o1,o2) \ILP_compare_less_than_or_equal(o1,o2)

161 #define ILP_GreaterThan(o1,o2) \ILP_compare_greater_than(o1,o2)

#define ILP_GreaterThanOrEqual(o1,o2) \ILP_compare_greater_than_or_equal(o1,o2)

166

#define ILP_Equal(o1,o2) \ILP_compare_equal(o1,o2)

#define ILP_NotEqual(o1,o2) \171 ILP_compare_not_equal(o1,o2)

/** Primitives:* Les fonctions ILP_print() et ILP_newline() sont définies dans ilp.c*/

176

typedef ILP_Object (*ILP_Primitive) ();

110

extern struct ILP_Object ILP_object_true;extern struct ILP_Object ILP_object_false;

181 extern ILP_Object ILP_die (char *message);extern ILP_Object ILP_make_boolean (int b);extern ILP_Object ILP_make_integer (int d);extern ILP_Object ILP_make_float (double d);extern ILP_Object ILP_make_string (char *s);

186 extern ILP_Object ILP_make_opposite (ILP_Object o);extern ILP_Object ILP_make_negation (ILP_Object o);extern ILP_Object ILP_make_addition (ILP_Object o1, ILP_Object o2);extern ILP_Object ILP_make_subtraction (ILP_Object o1, ILP_Object o2);extern ILP_Object ILP_make_multiplication (ILP_Object o1, ILP_Object o2);

191 extern ILP_Object ILP_make_division (ILP_Object o1, ILP_Object o2);extern ILP_Object ILP_make_modulo (ILP_Object o1, ILP_Object o2);extern ILP_Object ILP_compare_less_than (ILP_Object o1, ILP_Object o2);extern ILP_Object ILP_compare_less_than_or_equal (ILP_Object o1, ILP_Object o2);extern ILP_Object ILP_compare_equal (ILP_Object o1, ILP_Object o2);

196 extern ILP_Object ILP_compare_greater_than (ILP_Object o1, ILP_Object o2);extern ILP_Object ILP_compare_greater_than_or_equal (ILP_Object o1, ILP_Object o2);extern ILP_Object ILP_compare_not_equal (ILP_Object o1, ILP_Object o2);extern ILP_Object ILP_newline ();extern ILP_Object ILP_print (ILP_Object o);

201

#endif /* ILP_H */

/* end of ilp.h */

C/ilpAlloc.c

1 /** Ce fichier constitue la bibliothèque d’exécution d’ILP. */

#include <stdlib.h>#include "ilp.h"#include "ilpAlloc.h"

6 #include "ilpBasicError.h"

char *ilpAlloc_Id = "$Id: ilpAlloc.c 405 2006-09-13 17:21:53Z queinnec $";

/** Allouer un objet d’ILP avec une taille et une étiquette. */11

ILP_ObjectILP_malloc (int size, enum ILP_Kind kind){

ILP_Object result = malloc(size);16 if ( result == NULL ) {

return ILP_error("Memory exhaustion");};result->_kind = kind;return result;

21 }

/* end of ilpAlloc.c */

C/ilpAlloc.h

#ifndef ILP_ALLOC_H2 #define ILP_ALLOC_H

#include "ilp.h"

extern ILP_Object ILP_malloc (int size, enum ILP_Kind kind);7

#endif /* ILP_ALLOC_H *//* end of ilpAlloc.h */

C/ilpBasicError.c

1 /** Ce fichier constitue la bibliothèque d’exécution d’ILP. */

#include <stdlib.h>#include <stdio.h>/* Semble manquer: */

6 extern int snprintf(char *str, size_t size, const char *format, ...);#include "ilp.h"#include "ilpBasicError.h"

111

Page 57: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

char *ilpBasicError_Id = "$Id: ilpBasicError.c 405 2006-09-13 17:21:53Z queinnec $";11

/*** Signalement de problèmes.** Cette fonction ne renvoit rien mais le typage est meilleur si on

16 * l’utilise après un return (cf. exemples plus bas).*/

ILP_ObjectILP_error (char *message)

21 {ILP_die(message);/** NOT REACHED */return NULL;

}26

#define BUFFER_LENGTH 1000

/** Une fonction pour signaler qu’un argument n’est pas du type attendu. */

31 ILP_ObjectILP_domain_error (char *message, ILP_Object o){

char buffer[BUFFER_LENGTH];snprintf(buffer, BUFFER_LENGTH, "%s\nCulprit: 0x%p\n",

36 message, (void*) o);ILP_die(buffer);/** NOT REACHED */return NULL;

}41

/* end of ilpBasicError.c */

C/ilpBasicError.h

#ifndef ILP_BASIC_ERROR_H#define ILP_BASIC_ERROR_H

3

#include "ilp.h"

extern ILP_Object ILP_error (char *message);extern ILP_Object ILP_domain_error (char *message, ILP_Object o);

8

#endif /* ILP_BASIC_ERROR_H */

/* end of ilpBasicError.h */

C/ilpError.c

/** Ce fichier constitue la bibliothèque d’exécution d’ILP. Il* implante ilpBasicError.h avec des fonctions qui signalent* maintenant des exceptions rattrapables par ILP.

4 */

#include <stdlib.h>#include <stdio.h>/* Semble manquer: */

9 extern int snprintf(char *str, size_t size, const char *format, ...);#include <string.h>

#include "ilp.h"#include "ilpBasicError.h"

14 #include "ilpException.h"

char *ilpError_Id = "$Id: ilpError.c 405 2006-09-13 17:21:53Z queinnec $";

/** Allocation statique d’une instance d’exception. Sa définition fait19 * qu’elle peut être prise pour un ILP_Object. Par contre sa grosse

* taille n’influence pas la taille des ILP_Object. */

enum ILP_ExceptionKind {ILP_EXCEPTION_KIND = 0xab060ba

24 };

#define ILP_EXCEPTION_BUFFER_LENGTH 1000112

#define ILP_EXCEPTION_CULPRIT_LENGTH 10

29 struct ILP_exception {enum ILP_ExceptionKind _kind;union {

struct asException {char message[ILP_EXCEPTION_BUFFER_LENGTH];

34 ILP_Object culprit[ILP_EXCEPTION_CULPRIT_LENGTH];} asException;

} _content;};static struct ILP_exception ILP_the_exception = {

39 ILP_EXCEPTION_KIND, { { "", { NULL } } }};

/*** Signalement d’une exception

44 */

ILP_ObjectILP_error (char *message){

49 snprintf(ILP_the_exception._content.asException.message,ILP_EXCEPTION_BUFFER_LENGTH,"Error: %s\n",message);

fprintf(stderr, ILP_the_exception._content.asException.message); /*DEBUG*/54 ILP_the_exception._content.asException.culprit[0] = NULL;

return ILP_throw((ILP_Object) &ILP_the_exception);}

/** Une fonction pour signaler qu’un argument n’est pas du type attendu. */59

ILP_ObjectILP_domain_error (char *message, ILP_Object o){

snprintf(ILP_the_exception._content.asException.message,64 ILP_EXCEPTION_BUFFER_LENGTH,

"Domain error: %s\nCulprit: 0x%p\n",message, (void*) o);

fprintf(stderr, ILP_the_exception._content.asException.message); /*DEBUG*/ILP_the_exception._content.asException.culprit[0] = o;

69 ILP_the_exception._content.asException.culprit[1] = NULL;return ILP_throw((ILP_Object) &ILP_the_exception);

}

/* end of ilpError.c */

C/ilpException.c

/** Ce fichier constitue un complément à la bibliothèque d’exécution2 * d’ILP notamment les primitives manipulant les exceptions. */

#include <stdlib.h>#include <stdio.h>#include "ilpException.h"

7

/** Ces variables globales contiennent:* -- le rattrapeur d’erreur courant* -- l’exception courante (lorsque signalée)*/

12

static struct ILP_catcher ILP_the_original_catcher = {NULL

};struct ILP_catcher *ILP_current_catcher = &ILP_the_original_catcher;

17

ILP_Object ILP_current_exception = NULL;

/** Signaler une exception. */

22 ILP_ObjectILP_throw (ILP_Object exception){

ILP_current_exception = exception;if ( ILP_current_catcher == &ILP_the_original_catcher ) {

27 ILP_die("No current catcher!");};longjmp(ILP_current_catcher->_jmp_buf, 1);/** UNREACHABLE */ 113

Page 58: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

return NULL;32 }

/** Chaîner le nouveau rattrapeur courant avec l’ancien. */

void37 ILP_establish_catcher (struct ILP_catcher *new_catcher)

{new_catcher->previous = ILP_current_catcher;ILP_current_catcher = new_catcher;

}42

/** Remettre en place un rattrapeur. */

voidILP_reset_catcher (struct ILP_catcher *catcher)

47 {ILP_current_catcher = catcher;

}

/* end of ilpException.c */

C/ilpException.h

#ifndef ILP_EXCEPTION_H#define ILP_EXCEPTION_H

4 /** Les entêtes des ressources manipulant les exceptions.* Voici comment utiliser cette bibliothèque:** À tout instant, ILP_current_catcher contient le rattrapeur* d’exceptions. Lorsqu’une exception est signalée par ILP_throw, elle

9 * est envoyée au rattrapeur courant. Pour établir un nouveau* rattrapeur d’erreur, utilisez le motif suivant:** { struct ILP_catcher *current_catcher = ILP_current_catcher;* struct ILP_catcher new_catcher;

14 * if ( 0 == setjmp(new_catcher->_jmpbuf) ) {* ILP_establish_catcher(&new_catcher);* ...* ILP_current_exception = NULL;* };

19 * ILP_reset_catcher(current_catcher);* if ( NULL != ILP_current_exception ) {* if ( 0 == setjmp(new_catcher->_jmpbuf) ) {* ILP_establish_catcher(&new_catcher);* ... = ILP_current_exception;

24 * ILP_current_exception = NULL;* ...* };* };* ILP_reset_catcher(current_catcher);

29 * ...* if ( NULL != ILP_current_exception ) {* ILP_throw(ILP_current_exception);* };* }

34 */

#include <setjmp.h>#include "ilp.h"

39 struct ILP_catcher {struct ILP_catcher *previous;jmp_buf _jmp_buf;

};

44 extern struct ILP_catcher *ILP_current_catcher;extern ILP_Object ILP_current_exception;extern ILP_Object ILP_throw (ILP_Object exception);extern void ILP_establish_catcher (struct ILP_catcher *new_catcher);extern void ILP_reset_catcher (struct ILP_catcher *catcher);

49

#endif /* ILP_EXCEPTION_H */

/* end of ilpException.h */

C/ilpField.c114

/* $Id: ilpField.c 405 2006-09-13 17:21:53Z queinnec $ */

3 #include "ilpObj.h"

char *ilpField_Id = "$Id: ilpField.c 405 2006-09-13 17:21:53Z queinnec $";

ILP_Field8 ILP_find_field (ILP_Object o,

char* fieldName ){

ILP_Field current = o->_class->_content.asClass.last_field;

13 while ( current != NULL ) {if ( strcmp(current->_content.asField.name, fieldName) == 0 ) {

return current;} else {

current = current->_content.asField.previous_field;18 }

}return NULL;

}

23 ILP_ObjectILP_find_field_value_address (ILP_Object o,

char* fieldName ){

ILP_Field f = ILP_find_field(o, fieldName);28

if ( f != NULL ) {return o->_content.asInstance.field[f->_content.asField.offset];

} else {return NULL;

33 }}

/* end of ilpField.c */

C/ilpObj.c

/* $Id: ilpObj.c 551 2006-10-28 14:16:32Z queinnec $ *//** Ce fichier constitue la bibliothèque d’exécution d’ILP6. */

4 #include "ilpObj.h"

char *ilpObj_Id = "$Id: ilpObj.c 551 2006-10-28 14:16:32Z queinnec $";

/** Les classes de base. */9

extern struct ILP_Class ILP_object_Object_class;

struct ILP_Class ILP_object_Class_class = {&ILP_object_Class_class,

14 { { &ILP_object_Object_class,"Class",1,&ILP_object_super_field,2,

19 { ILP_print,ILP_classOf } } }

};

struct ILP_Class ILP_object_Object_class = {24 &ILP_object_Class_class,

{ { NULL,"Object",0,NULL,

29 2,{ ILP_print,

ILP_classOf } } }};

34 struct ILP_Class ILP_object_Method_class = {&ILP_object_Class_class,{ { &ILP_object_Object_class,

"Method",0,

39 NULL,3,{ ILP_print,

115

Page 59: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

ILP_classOf } } }};

44

struct ILP_Class ILP_object_Field_class = {&ILP_object_Class_class,{ { &ILP_object_Object_class,

"Field",49 1,

&ILP_object_defining_class_field,2,{ ILP_print,

ILP_classOf } } }54 };

struct ILP_Class ILP_object_Integer_class = {&ILP_object_Class_class,{ { &ILP_object_Object_class,

59 "Integer",0,NULL,2,{ ILP_print,

64 ILP_classOf } } }};

struct ILP_Class ILP_object_Float_class = {&ILP_object_Class_class,

69 { { &ILP_object_Object_class,"Float",0,NULL,2,

74 { ILP_print,ILP_classOf } } }

};

struct ILP_Class ILP_object_Boolean_class = {79 &ILP_object_Class_class,

{ { &ILP_object_Object_class,"Boolean",0,NULL,

84 2,{ ILP_print,

ILP_classOf } } }};

89 struct ILP_Class ILP_object_String_class = {&ILP_object_Class_class,{ { &ILP_object_Object_class,

"String",0,

94 NULL,2,{ ILP_print,

ILP_classOf } } }};

99

struct ILP_Class ILP_object_Exception_class = {&ILP_object_Class_class,{ { &ILP_object_Object_class,

"Exception",104 0,

NULL,2,{ ILP_print,

ILP_classOf } } }109 };

/** Les champs prédéfinis.** Tous les champs des structures C qui ne mènent pas à des valeurs

114 * d’ILP ne sont pas considérés comme des champs. C’est pourquoi (1)* ces champs sont regroupés en tête de structure et (2) il y en a peu.*/

struct ILP_Field ILP_object_super_field = {119 &ILP_object_Field_class,

{ { &ILP_object_Class_class,NULL,"super",0 } }

116

124 };

struct ILP_Field ILP_object_defining_class_field = {&ILP_object_Field_class,{ { &ILP_object_Field_class,

129 NULL,"defining_class",0 } }

};

134 struct ILP_Field ILP_object_previous_field_field = {&ILP_object_Field_class,{ { &ILP_object_Field_class,

&ILP_object_defining_class_field,"previous_field",

139 1 } }};

struct ILP_Field ILP_object_class_defining_field = {&ILP_object_Field_class,

144 { { &ILP_object_Method_class,NULL,"class_defining",0 } }

};149

/** Les méthodes prédéfinies.** Il n’y en a que deux (pour l’instant) d’arité nulle:* o.print() qui imprime l’objet

154 * o.getClass() qui renvoie sa classe.*/

struct ILP_Method ILP_object_print_method = {&ILP_object_Method_class,

159 { { &ILP_object_Object_class,"print",1, /* arité (incluant self) */0 /* offset */

} }164 };

struct ILP_Method ILP_object_classOf_method = {&ILP_object_Method_class,{ { &ILP_object_Object_class,

169 "classOf",1, /* arité (incluant self) */1 /* offset */

} }};

174

/** Booléens.** On alloue statiquement les deux booléens.*/

179

struct ILP_Object ILP_object_true = {&ILP_object_Boolean_class,{ ILP_BOOLEAN_TRUE_VALUE }

};184

struct ILP_Object ILP_object_false = {&ILP_object_Boolean_class,{ ILP_BOOLEAN_FALSE_VALUE }

};189

/** Exceptions** L’exception courante.* NOTA: il serait mieux qu’elle soit dynamiquement allouée.

194 */

static struct ILP_Exception ILP_the_exception = {&ILP_object_Exception_class,{ { "",

199 { NULL } } }};

/** Ces variables globales contiennent:* -- le rattrapeur d’erreur courant

204 * -- l’exception courante (lorsque signalée)*/

117

Page 60: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

static struct ILP_catcher ILP_the_original_catcher = {NULL

209 };struct ILP_catcher *ILP_current_catcher = &ILP_the_original_catcher;

ILP_Object ILP_current_exception = NULL;

214 /** Signaler une exception. */

ILP_ObjectILP_throw (ILP_Object exception){

219 ILP_current_exception = exception;if ( ILP_current_catcher == &ILP_the_original_catcher ) {

ILP_die("No current catcher!");};longjmp(ILP_current_catcher->_jmp_buf, 1);

224 /** UNREACHABLE */return NULL;

}

/** Chaîner le nouveau rattrapeur courant avec l’ancien. */229

voidILP_establish_catcher (struct ILP_catcher *new_catcher){

new_catcher->previous = ILP_current_catcher;234 ILP_current_catcher = new_catcher;

}

/** Remettre en place un rattrapeur. */

239 voidILP_reset_catcher (struct ILP_catcher *catcher){

ILP_current_catcher = catcher;}

244

/*** Signalement d’une erreur.*/

249 ILP_ObjectILP_error (char *message){

snprintf(ILP_the_exception._content.asException.message,ILP_EXCEPTION_BUFFER_LENGTH,

254 "Error: %s\n",message);

fprintf(stderr, ILP_the_exception._content.asException.message); /*DEBUG*/ILP_the_exception._content.asException.culprit[0] = NULL;return ILP_throw((ILP_Object) &ILP_the_exception);

259 }

/** Une fonction pour signaler qu’un argument n’est pas du type attendu. */

ILP_Object264 ILP_domain_error (char *message, ILP_Object o)

{snprintf(ILP_the_exception._content.asException.message,

ILP_EXCEPTION_BUFFER_LENGTH,"Domain error: %s\nCulprit: 0x%p\n",

269 message, (void*) o);fprintf(stderr, ILP_the_exception._content.asException.message); /*DEBUG*/ILP_the_exception._content.asException.culprit[0] = o;ILP_the_exception._content.asException.culprit[1] = NULL;return ILP_throw((ILP_Object) &ILP_the_exception);

274 }

/** Une fonction pour stopper abruptement l’application. */

ILP_Object279 ILP_die (char *message)

{fputs(message, stderr);fputc(’\n’, stderr);fflush(stderr);

284 exit(EXIT_FAILURE);}

/** Vérifier si une instance est d’une certaine classe.118

* Cet algorithme est linéaire: on peut faire mieux! */289

int /* boolean */ILP_is_a (ILP_Object o, ILP_Class class){

ILP_Class oclass = o->_class;294 if ( oclass == class ) {

return 1;} else {

oclass = oclass->_content.asClass.super;/* Object a NULL pour superclasse. */

299 while ( oclass ) {if ( oclass == class ) {

return 1;};oclass = oclass->_content.asClass.super;

304 }return 0;

}}

309 static intILP_is_subclass_of (ILP_Class oclass, ILP_Class otherclass){

if ( oclass == otherclass ) {return 1;

314 } else {oclass = oclass->_content.asClass.super;/* Object a NULL pour superclasse. */while ( oclass ) {

if ( oclass == otherclass ) {319 return 1;

};oclass = oclass->_content.asClass.super;

}return 0;

324 }}

/** Déterminer une méthode. */

329 ILP_general_functionILP_find_method (ILP_Object receiver,

ILP_Method method,int argc)

{334 ILP_Class oclass = receiver->_class;

if ( ! ILP_is_subclass_of(oclass,method->_content.asMethod.class_defining) ) {

/* Signaler une absence de méthode */snprintf(ILP_the_exception._content.asException.message,

339 ILP_EXCEPTION_BUFFER_LENGTH,"No such method %s\nCulprit: 0x%p\n",method->_content.asMethod.name,(void*) receiver);

/*DEBUG*/344 fprintf(stderr, ILP_the_exception._content.asException.message);

ILP_the_exception._content.asException.culprit[0] = receiver;ILP_the_exception._content.asException.culprit[1] =

(ILP_Object) method;ILP_the_exception._content.asException.culprit[2] = NULL;

349 ILP_throw((ILP_Object) &ILP_the_exception);/* UNREACHED */return NULL;

};if ( argc != method->_content.asMethod.arity ) {

354 /* Signaler une erreur d’arité */snprintf(ILP_the_exception._content.asException.message,

ILP_EXCEPTION_BUFFER_LENGTH,"Method %s arity error: %d instead of %d\nCulprit: 0x%p\n",method->_content.asMethod.name,

359 argc,method->_content.asMethod.arity,(void*) receiver);

/*DEBUG*/fprintf(stderr, ILP_the_exception._content.asException.message);

364 ILP_the_exception._content.asException.culprit[0] = receiver;ILP_the_exception._content.asException.culprit[1] =

(ILP_Object) method;ILP_the_exception._content.asException.culprit[2] = NULL;ILP_throw((ILP_Object) &ILP_the_exception);

369 /* UNREACHED */119

Page 61: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

return NULL;};{

int index = method->_content.asMethod.index;374 return oclass->_content.asClass.method[index];

}}

#define DefineSuperMethodCaller(i) \379 ILP_Object \

ILP_find_and_call_super_method##i ( \ILP_Object self, \ILP_Method current_method, \ILP_general_function super_method, \

384 ILP_Object arguments[1] ) \{ \

/* assert( super_method != NULL ); */ \switch ( i ) { \

case 0: { \389 return (*super_method)(self); \

} \case 1: { \

return (*super_method)(self, arguments[1]); \} \

394 case 2: { \return (*super_method)(self, arguments[1], arguments[2]); \

} \case 3: { \

return (*super_method)(self, arguments[1], \399 arguments[2], \

arguments[3]); \} \default: { \

snprintf(ILP_the_exception._content.asException.message, \404 ILP_EXCEPTION_BUFFER_LENGTH, \

"Cannot invoke supermethod %s\nCulprit: 0x%p\n", \current_method->_content.asMethod.name, \(void*) self ); \

/*DEBUG*/ \409 fprintf(stderr, ILP_the_exception._content.asException.message);\

ILP_the_exception._content.asException.culprit[0] = self; \ILP_the_exception._content.asException.culprit[1] = \

(ILP_Object) current_method; \ILP_the_exception._content.asException.culprit[2] = NULL; \

414 ILP_throw((ILP_Object) &ILP_the_exception); \/* UNREACHED */ \return NULL; \

} \} \

419 }

DefineSuperMethodCaller(0)DefineSuperMethodCaller(1)DefineSuperMethodCaller(2)

424 DefineSuperMethodCaller(3)

ILP_ObjectILP_dont_call_super_method (

ILP_Object self,429 ILP_Method current_method,

ILP_general_function super_method,ILP_Object arguments[1] )

{/* assert ( super_method == NULL ); */

434 snprintf(ILP_the_exception._content.asException.message,ILP_EXCEPTION_BUFFER_LENGTH,"No supermethod %s\nCulprit: 0x%p\n",current_method->_content.asMethod.name,(void*) self );

439 /*DEBUG*/fprintf(stderr, ILP_the_exception._content.asException.message);ILP_the_exception._content.asException.culprit[0] = self;ILP_the_exception._content.asException.culprit[1] =

(ILP_Object) current_method;444 ILP_the_exception._content.asException.culprit[2] = NULL;

ILP_throw((ILP_Object) &ILP_the_exception);/* UNREACHED */return NULL;

}449

/** Allocateurs. ILP_malloc est paramétré par l’allocateur de bas* niveau employé, par défaut: malloc() mais ce peut être GC_malloc()

120

* Cf. ilpObj.h pour plus de détails sur l’emploi d’un GC. */

454 ILP_ObjectILP_malloc (int size, ILP_Class class){

ILP_Object result = ILP_MALLOC(size);if ( result == NULL ) {

459 return ILP_die("Memory exhaustion");};result->_class = class;return result;

}464

ILP_ObjectILP_make_instance (ILP_Class class){

int size = sizeof(ILP_Class);469 size += sizeof(ILP_Object) * class->_content.asClass.fields_count;

return ILP_malloc(size, class);}

/** Ce n’est pas une vraie allocation mais une simple conversion. */474

ILP_ObjectILP_make_boolean (int b){

if ( b ) {479 return ILP_TRUE;

} else {return ILP_FALSE;

}}

484

ILP_ObjectILP_make_integer (int d){

ILP_Object result = ILP_AllocateInteger();489 result->_content.asInteger = d;

return result;}

ILP_Object494 ILP_make_float (double d)

{ILP_Object result = ILP_AllocateFloat();result->_content.asFloat = d;return result;

499 }

ILP_ObjectILP_make_string (char *s){

504 int size = strlen(s);ILP_Object result = ILP_AllocateString(size);result->_content.asString._size = size;memmove(result->_content.asString.asCharacter, s, size);return result;

509 }

/** String primitives */

static ILP_Object514 ILP_concatenate_strings (ILP_Object o1, ILP_Object o2)

{int size1 = o1->_content.asString._size;int total_size = size1 + o2->_content.asString._size;ILP_Object result = ILP_AllocateString(total_size);

519 memmove(&(result->_content.asString.asCharacter[0]),o1->_content.asString.asCharacter,o1->_content.asString._size);

memmove(&(result->_content.asString.asCharacter[size1]),o2->_content.asString.asCharacter,

524 o2->_content.asString._size);return result;

}

/** Opérateurs unaires. */529

ILP_ObjectILP_make_opposite (ILP_Object o){

ILP_CheckIfInteger(o);121

Page 62: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

534 {ILP_Object result = ILP_AllocateInteger();result->_content.asInteger = (- o->_content.asInteger);return result;

}539 }

ILP_ObjectILP_make_negation (ILP_Object o){

544 ILP_CheckIfBoolean(o);{

if ( ILP_isTrue(o) ) {return ILP_FALSE;

} else {549 return ILP_TRUE;

}}

}

554 /** Opérateurs binaires. */

/* DefineOperator(addition, +) est incorrect car + représente également* la concaténation des chaînes de caractères. */

559 ILP_ObjectILP_make_addition (ILP_Object o1, ILP_Object o2){

if ( ILP_isInteger(o1) ) {if ( ILP_isInteger(o2) ) {

564 ILP_Object result = ILP_AllocateInteger();result->_content.asInteger =

o1->_content.asInteger + o2->_content.asInteger;return result;

} else if ( ILP_isFloat(o2) ) {569 ILP_Object result = ILP_AllocateFloat();

result->_content.asFloat =o1->_content.asInteger + o2->_content.asFloat;

return result;} else {

574 return ILP_domain_error("Not a number", o2);}

} else if ( ILP_isFloat(o1) ) {if ( ILP_isInteger(o2) ) {

ILP_Object result = ILP_AllocateFloat();579 result->_content.asFloat =

o1->_content.asFloat + o2->_content.asInteger;return result;

} else if ( ILP_isFloat(o2) ) {ILP_Object result = ILP_AllocateFloat();

584 result->_content.asFloat =o1->_content.asFloat + o2->_content.asFloat;

return result;} else {

return ILP_domain_error("Not a number", o2);589 }

} else if ( ILP_isString(o1) ) {if ( ILP_isString(o2) ) {

return ILP_concatenate_strings(o1, o2);} else {

594 return ILP_domain_error("Not a string", o2);}

} else {return ILP_domain_error("Not addable", o1);

}599 }

#define DefineOperator(name,op) \ILP_Object \ILP_make_##name (ILP_Object o1, ILP_Object o2) \

604 { \if ( ILP_isInteger(o1) ) { \

if ( ILP_isInteger(o2) ) { \ILP_Object result = ILP_AllocateInteger(); \result->_content.asInteger = \

609 o1->_content.asInteger op o2->_content.asInteger; \return result; \

} else if ( ILP_isFloat(o2) ) { \ILP_Object result = ILP_AllocateFloat(); \result->_content.asFloat = \

614 o1->_content.asInteger op o2->_content.asFloat; \return result; \

122

} else { \return ILP_domain_error("Not a number", o2); \

} \619 } else if ( ILP_isFloat(o1) ) { \

if ( ILP_isInteger(o2) ) { \ILP_Object result = ILP_AllocateFloat(); \result->_content.asFloat = \

o1->_content.asFloat op o2->_content.asInteger; \624 return result; \

} else if ( ILP_isFloat(o2) ) { \ILP_Object result = ILP_AllocateFloat(); \result->_content.asFloat = \

o1->_content.asFloat op o2->_content.asFloat; \629 return result; \

} else { \return ILP_domain_error("Not a number", o2); \

} \} else { \

634 return ILP_domain_error("Not a number", o1); \} \

}

DefineOperator(subtraction, -)639 DefineOperator(multiplication, *)

DefineOperator(division, /)

/* DefineOperator(modulo, %) est incorrect car le modulo ne se prend* que sur de entiers. */

644

ILP_ObjectILP_make_modulo (ILP_Object o1, ILP_Object o2){

if ( ILP_isInteger(o1) ) {649 if ( ILP_isInteger(o2) ) {

ILP_Object result = ILP_AllocateInteger();result->_content.asInteger =

o1->_content.asInteger % o2->_content.asInteger;return result;

654 } else {return ILP_domain_error("Not an integer", o2);

}} else {

return ILP_domain_error("Not an integer", o1);659 }

}

#define DefineComparator(name,op) \ILP_Object \

664 ILP_compare_##name (ILP_Object o1, ILP_Object o2) \{ \

if ( ILP_isInteger(o1) ) { \if ( ILP_isInteger(o2) ) { \

return ILP_make_boolean( \669 o1->_content.asInteger op o2->_content.asInteger); \

} else if ( ILP_isFloat(o2) ) { \return ILP_make_boolean( \

o1->_content.asInteger op o2->_content.asFloat); \} else { \

674 return ILP_domain_error("Not a number", o2); \} \

} else if ( ILP_isFloat(o1) ) { \if ( ILP_isInteger(o2) ) { \

return ILP_make_boolean( \679 o1->_content.asFloat op o2->_content.asInteger); \

} else if ( ILP_isFloat(o2) ) { \return ILP_make_boolean( \

o1->_content.asFloat op o2->_content.asFloat); \} else { \

684 return ILP_domain_error("Not a number", o2); \} \

} else { \return ILP_domain_error("Not a number", o1); \

} \689 }

DefineComparator(less_than, <)DefineComparator(less_than_or_equal, <=)DefineComparator(equal, ==)

694 DefineComparator(greater_than, >)DefineComparator(greater_than_or_equal, >=)DefineComparator(not_equal, !=)

123

Page 63: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

/** Primitives */699

ILP_ObjectILP_newline (){

fputc(’\n’, stdout);704 return ILP_FALSE;

}

/** Imprimer le contenu d’une instance. */

709 voidILP_print_fields (ILP_Object o,

ILP_Field last){

if ( last == NULL ) {714 return;

};ILP_print_fields(o, last->_content.asField.previous_field);fprintf(stdout, ":%s=", last->_content.asField.name);ILP_print(o->_content.asInstance.field[last->_content.asField.offset]);

719 }

/** Cette fonction peut être utilisée comme une méthode. Elle imprime* le receveur sur le flux de sortie. */

724 ILP_ObjectILP_print (ILP_Object self){

if ( self->_class == &ILP_object_Integer_class ) {fprintf(stdout, "%d", self->_content.asInteger);

729 } else if ( self->_class == &ILP_object_Float_class ) {fprintf(stdout, "%12.5g", self->_content.asFloat);

} else if ( self->_class == &ILP_object_Boolean_class ) {fprintf(stdout, "%s", (ILP_isTrue(self) ? "true" : "false"));

} else if ( self->_class == &ILP_object_String_class ) {734 fprintf(stdout, "%s", self->_content.asString.asCharacter);

} else if ( self->_class == &ILP_object_Class_class ) {fprintf(stdout, "<Class:%s>", self->_content.asClass.name);

} else if ( self->_class == &ILP_object_Method_class ) {fprintf(stdout, "<Method:%s>", self->_content.asMethod.name);

739 } else if ( self->_class == &ILP_object_Field_class ) {fprintf(stdout, "<Field:%s>", self->_content.asField.name);

} else {fprintf(stdout, "<%s", self->_class->_content.asClass.name);ILP_print_fields(self, self->_class->_content.asClass.last_field);

744 fprintf(stdout, ">");}return ILP_FALSE;

}

749 /** Cette fonction renvoie la classe du receveur. La classe est* également un objet obéissant au modèle ObjVlisp. */

ILP_ObjectILP_classOf (ILP_Object self)

754 {return (ILP_Object) (self->_class);

}

/* end of ilpObj.c */

C/ilpObj.h

/* $Id: ilpObj.h 551 2006-10-28 14:16:32Z queinnec $ */2

#ifndef ILPOBJ_H#define ILPOBJ_H

#include <stdio.h>7 #include <stdlib.h>

/* Semble manquer: */extern int snprintf(char *str, size_t size, const char *format, ...);#include <string.h>#include <setjmp.h>

12

/** Les fonctions d’ILP sont représentées en C par des fonctions qui* prennent des ILP_Object et renvoie un ILP_Object. */

typedef struct ILP_Object* (*ILP_general_function)();124

17

/** Il y a deux sortes de booléens et ces deux constantes les repèrent. */

enum ILP_BOOLEAN_VALUE {ILP_BOOLEAN_FALSE_VALUE = 0,

22 ILP_BOOLEAN_TRUE_VALUE = 1};

#define ILP_EXCEPTION_BUFFER_LENGTH 100027 #define ILP_EXCEPTION_CULPRIT_LENGTH 10

/** Toutes les valeurs manipulées ont cette forme:* un entête indiquant la classe suivi des champs appropriés.

32 */

typedef struct ILP_Object {struct ILP_Class* _class;union {

37 unsigned char asBoolean;int asInteger;double asFloat;struct asString {

int _size;42 char asCharacter[1];

} asString;struct asException {

char message[ILP_EXCEPTION_BUFFER_LENGTH];struct ILP_Object* culprit[ILP_EXCEPTION_CULPRIT_LENGTH];

47 } asException;struct asClass {

struct ILP_Class* super;char* name;int fields_count;

52 struct ILP_Field* last_field;int methods_count;ILP_general_function method[1];

} asClass;struct asMethod {

57 struct ILP_Class* class_defining;char* name;short arity;short index;

} asMethod;62 struct asField {

struct ILP_Class* defining_class;struct ILP_Field* previous_field;char* name;short offset;

67 } asField;struct asInstance {

struct ILP_Object* field[1];} asInstance;

} _content;72 } *ILP_Object;

/** On identifie ces structures car la sémantique de C ne permet de* faire d’allocations statiques pour une variante d’union (autre que* la première). */

77

typedef struct ILP_Exception {struct ILP_Class* _class;union {

struct asException_ {82 char message[ILP_EXCEPTION_BUFFER_LENGTH];

struct ILP_Object* culprit[ILP_EXCEPTION_CULPRIT_LENGTH];} asException;

} _content;} *ILP_Exception;

87

typedef struct ILP_Class {struct ILP_Class* _class;union {

struct asClass_ {92 struct ILP_Class* super;

char* name;int fields_count;struct ILP_Field* last_field;int methods_count;

97 ILP_general_function method[2];} asClass;

125

Page 64: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

} _content;} *ILP_Class;

102 typedef struct ILP_Method {struct ILP_Class* _class;union {

struct asMethod_ {struct ILP_Class* class_defining;

107 char* name;short arity;short index;

} asMethod;} _content;

112 } *ILP_Method;

typedef struct ILP_Field {struct ILP_Class* _class;union {

117 struct asField_ {struct ILP_Class* defining_class;struct ILP_Field* previous_field;char* name;short offset;

122 } asField;} _content;

} *ILP_Field;

/** Engendrer le type des classes à i méthodes.127 *

* C’est nécessaire car gcc maintenant supprime les initialisations* superflues. Il faut donc soit allouer et initialiser dynamiquement* les classes soit créer autant de types que nécessaires (comment* éviter les doublons ?)

132 */

#define ILP_GenerateClass(i) \typedef struct ILP_Class##i { \

struct ILP_Class* _class; \137 union { \

struct asClass_##i { \struct ILP_Class* super; \char* name; \int fields_count; \

142 struct ILP_Field* last_field; \int methods_count; \ILP_general_function method[i]; \

} asClass; \} _content; \

147 } *ILP_Class##i

#define ILP_FindAndCallSuperMethod(i) \(((ilp_SuperMethod != NULL) \

? (*ILP_find_and_call_super_method##i) \152 : (*ILP_dont_call_super_method) )( \

ilp_Self, ilp_CurrentMethod, ilp_SuperMethod, ilp_CurrentArguments))

extern ILP_Object ILP_find_and_call_super_method0(ILP_Object self,

157 ILP_Method current_method,ILP_general_function super_method,ILP_Object arguments[] );

extern ILP_Object ILP_find_and_call_super_method1(ILP_Object self,

162 ILP_Method current_method,ILP_general_function super_method,ILP_Object arguments[] );

extern ILP_Object ILP_find_and_call_super_method2(ILP_Object self,

167 ILP_Method current_method,ILP_general_function super_method,ILP_Object arguments[] );

extern ILP_Object ILP_find_and_call_super_method3(ILP_Object self,

172 ILP_Method current_method,ILP_general_function super_method,ILP_Object arguments[] );

extern ILP_Object ILP_dont_call_super_method(ILP_Object self,

177 ILP_Method current_method,ILP_general_function super_method,ILP_Object arguments[] );

126

/** -------------------------------------------182 * Des macros pour manipuler toutes ces valeurs.

*/

#define ILP_IsA(o,c) \ILP_is_a(o, c)

187

/** Booléens. */

#define ILP_Boolean2ILP(b) \ILP_make_boolean(b)

192

#define ILP_isBoolean(o) \((o)->_class == &ILP_object_Boolean_class)

#define ILP_isTrue(o) \197 (((o)->_class == &ILP_object_Boolean_class) && \

((o)->_content.asBoolean))

#define ILP_TRUE (&ILP_object_true)#define ILP_FALSE (&ILP_object_false)

202

#define ILP_isEquivalentToTrue(o) \((o) != ILP_FALSE)

#define ILP_CheckIfBoolean(o) \207 if ( ! ILP_isBoolean(o) ) { \

ILP_domain_error("Not a boolean", o); \};

/** Entiers */212

#define ILP_Integer2ILP(i) \ILP_make_integer(i)

#define ILP_AllocateInteger() \217 ILP_malloc(sizeof(struct ILP_Object), &ILP_object_Integer_class)

#define ILP_isInteger(o) \((o)->_class == &ILP_object_Integer_class)

222 #define ILP_CheckIfInteger(o) \if ( ! ILP_isInteger(o) ) { \

ILP_domain_error("Not an integer", o); \};

227 /** Flottants */

#define ILP_Float2ILP(f) \ILP_make_float(f)

232 #define ILP_AllocateFloat() \ILP_malloc(sizeof(struct ILP_Object), &ILP_object_Float_class)

#define ILP_isFloat(o) \((o)->_class == &ILP_object_Float_class)

237

#define ILP_CheckIfFloat(o) \if ( ! ILP_isFloat(o) ) { \

ILP_domain_error("Not a float", o); \};

242

/** Chaînes de caractères */

#define ILP_String2ILP(s) \ILP_make_string(s)

247

#define ILP_AllocateString(length) \ILP_malloc(sizeof(struct ILP_Object) \

+ (sizeof(char) * (length)), &ILP_object_String_class)

252 #define ILP_isString(o) \((o)->_class == &ILP_object_String_class)

#define ILP_CheckIfString(o) \if ( ! ILP_isString(o) ) { \

257 ILP_domain_error("Not a string", o); \};

/** Opérateurs unaires */

262 #define ILP_Opposite(o) \127

Page 65: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

ILP_make_opposite(o)

#define ILP_Not(o) \ILP_make_negation(o)

267

/** Opérateurs binaires */

#define ILP_Plus(o1,o2) \ILP_make_addition(o1, o2)

272

#define ILP_Minus(o1,o2) \ILP_make_subtraction(o1, o2)

#define ILP_Times(o1,o2) \277 ILP_make_multiplication(o1, o2)

#define ILP_Divide(o1,o2) \ILP_make_division(o1, o2)

282 #define ILP_Modulo(o1,o2) \ILP_make_modulo(o1, o2)

#define ILP_LessThan(o1,o2) \ILP_compare_less_than(o1,o2)

287

#define ILP_LessThanOrEqual(o1,o2) \ILP_compare_less_than_or_equal(o1,o2)

#define ILP_GreaterThan(o1,o2) \292 ILP_compare_greater_than(o1,o2)

#define ILP_GreaterThanOrEqual(o1,o2) \ILP_compare_greater_than_or_equal(o1,o2)

297 #define ILP_Equal(o1,o2) \ILP_compare_equal(o1,o2)

#define ILP_NotEqual(o1,o2) \ILP_compare_not_equal(o1,o2)

302

/** Constantes de classes. */

extern struct ILP_Class ILP_object_Object_class;extern struct ILP_Class ILP_object_Class_class;

307 extern struct ILP_Class ILP_object_Method_class;extern struct ILP_Class ILP_object_Field_class;extern struct ILP_Class ILP_object_Integer_class;extern struct ILP_Class ILP_object_Float_class;extern struct ILP_Class ILP_object_Boolean_class;

312 extern struct ILP_Class ILP_object_String_class;extern struct ILP_Class ILP_object_Exception_class;extern struct ILP_Field ILP_object_super_field;extern struct ILP_Field ILP_object_defining_class_field;extern struct ILP_Method ILP_object_print_method;

317 extern struct ILP_Method ILP_object_classOf_method;

/** Primitives. */

extern struct ILP_Object ILP_object_true;322 extern struct ILP_Object ILP_object_false;

extern ILP_Object ILP_die (char *message);extern ILP_Object ILP_make_boolean (int b);extern ILP_Object ILP_make_integer (int d);extern ILP_Object ILP_make_float (double d);

327 extern ILP_Object ILP_make_string (char *s);extern ILP_Object ILP_make_opposite (ILP_Object o);extern ILP_Object ILP_make_negation (ILP_Object o);extern ILP_Object ILP_make_addition (ILP_Object o1, ILP_Object o2);extern ILP_Object ILP_make_subtraction (ILP_Object o1, ILP_Object o2);

332 extern ILP_Object ILP_make_multiplication (ILP_Object o1, ILP_Object o2);extern ILP_Object ILP_make_division (ILP_Object o1, ILP_Object o2);extern ILP_Object ILP_make_modulo (ILP_Object o1, ILP_Object o2);extern ILP_Object ILP_compare_less_than (ILP_Object o1, ILP_Object o2);extern ILP_Object ILP_compare_less_than_or_equal (ILP_Object o1, ILP_Object o2);

337 extern ILP_Object ILP_compare_equal (ILP_Object o1, ILP_Object o2);extern ILP_Object ILP_compare_greater_than (ILP_Object o1, ILP_Object o2);extern ILP_Object ILP_compare_greater_than_or_equal (ILP_Object o1, ILP_Object o2);extern ILP_Object ILP_compare_not_equal (ILP_Object o1, ILP_Object o2);extern ILP_Object ILP_newline ();

342 extern ILP_Object ILP_print (ILP_Object self);extern ILP_Object ILP_classOf (ILP_Object self);

128

extern ILP_Object ILP_malloc (int size, ILP_Class class);extern ILP_Object ILP_make_instance (ILP_Class class);

347 extern int /* boolean */ ILP_is_a (ILP_Object o, ILP_Class class);extern ILP_general_function ILP_find_method (ILP_Object receiver,

ILP_Method method,int argc);

352 /** Mecanisme d’allocation */

#ifdef WITH_GC/* Le GC de Boehm se trouve là: */

# include "gc6.2/include/gc.h"357 # define ILP_START_GC GC_init()

# define ILP_MALLOC GC_malloc#else# define ILP_START_GC# define ILP_MALLOC malloc

362 #endif

/** Exceptions. */

struct ILP_catcher {367 struct ILP_catcher *previous;

jmp_buf _jmp_buf;};

extern struct ILP_catcher *ILP_current_catcher;372 extern ILP_Object ILP_current_exception;

extern ILP_Object ILP_throw (ILP_Object exception);extern void ILP_establish_catcher (struct ILP_catcher *new_catcher);extern void ILP_reset_catcher (struct ILP_catcher *catcher);extern ILP_Object ILP_error (char *message);

377 extern ILP_Object ILP_domain_error (char *message, ILP_Object o);

#define ILP_UnknownFieldError(f, o) \ILP_domain_error("Unfound field " f, o);

382 #endif /* ILPOBJ_H */

/* end of ilpObj.h */

C/ilpTrace.c

1 /* $Id: ilpTrace.c 578 2006-12-31 10:12:13Z queinnec $ */

#include <stdlib.h>#include <stdio.h>#include <stdarg.h>

6 #include "ilp.h"#include "ilpTrace.h"

/** La fonction ILP_beforeInvocation peut s’utiliser avec 0, 1, 2, ...arguments. Le dernier argument d’appel doit etre NULL. Par

11 exemple, pour tracer l’appel a foo(true, x) on ecrira:ILP_beforeInvocation("foo", ILP_TRUE, x, NULL);

*/

void16 ILP_beforeInvocation (char *function_name, ...)

{ILP_Object one_argument;va_list args;

21 va_start(args, function_name);printf("-> %s", function_name);while ( NULL != ( one_argument = va_arg(args, ILP_Object) ) ) {

putchar(’ ’);ILP_print(one_argument);

26 }va_end(args);putchar(’\n’);

}

31 ILP_ObjectILP_afterInvocation (char *function_name, ILP_Object result){

printf("<- %s ", function_name);ILP_print(result);

36 putchar(’\n’);return result;

129

Page 66: Code ILP1 - Jussieu · Code ILP1 Christian.Queinnec@lip6.fr 22 octobre 2007 Ces chiers sont diffusés pour l'enseignement ILP (Implantation d'un langage de programmation) dis-

}

/* end of ilpTrace.c */

C/ilpTrace.h

/* $Id: ilpTrace.h 578 2006-12-31 10:12:13Z queinnec $ */

#ifdef ILP_TRACE_H#define ILP_TRACE_H

5

extern voidILP_beforeInvocation (char *function_name, /* ILP_Object argument */ ...);extern ILP_Object

ILP_afterInvocation (char *function_name, ILP_Object result);10

#endif /* ILP_TRACE_H */

/* end of ilpTrace.h */

130