reorganisation par cours dans sous-répertoires
This commit is contained in:
13
1-ComputationAndData/MVaP/3n+2.mvap
Normal file
13
1-ComputationAndData/MVaP/3n+2.mvap
Normal file
@@ -0,0 +1,13 @@
|
||||
# calcule : 2 + 3 * n
|
||||
PUSHI 2
|
||||
LABEL 1
|
||||
PUSHI 3
|
||||
ADD
|
||||
WRITE
|
||||
DUP
|
||||
PUSHI 100
|
||||
INF
|
||||
JUMPF 2
|
||||
JUMP 1
|
||||
LABEL 2
|
||||
HALT
|
36
1-ComputationAndData/MVaP/ALIRE
Normal file
36
1-ComputationAndData/MVaP/ALIRE
Normal file
@@ -0,0 +1,36 @@
|
||||
# La machine virtuelle à pile.
|
||||
|
||||
Une machine pédagogique pour donner une idée de ce qu'est l'assembleur.
|
||||
|
||||
Dans le cadre d'un cours de compilation, par exemple en L3 informatique, on peut demander aux étudiants de coder un compilateur qui va transcrire un langage de haut niveau similaire à du python (sans objets et avec quelques types simples entiers, flottants, tableaux) vers du code MVàP.
|
||||
|
||||
## Contenu du répertoire.
|
||||
* add.mvap Un exemple simple de programme
|
||||
* 3n+2.mvap Un exemple moins simple de programme
|
||||
* test.mvap Un exemple avec appel de fonction
|
||||
|
||||
* MVaP.jar Une archive java qui propose 2 exécutables
|
||||
MVaPAssembler (assemble en un binaire)
|
||||
CBaP (interprète le binaire).
|
||||
|
||||
* antlr-4.5.2-complete.jar Une archive java contenant de nombreux binaires permettant d'écrire des compilateurs sur lequel le code de la MVàP s'appuit.
|
||||
|
||||
## Pour utiliser la MVàP
|
||||
|
||||
Il faut avoir java d'installé sur sa machine (c'est le cas si vous passez par proxmox des machines de l'IUT).
|
||||
|
||||
** Pour exécuter du code mvap, il faut :
|
||||
|
||||
1- Assembler :
|
||||
$ java -cp antlr-4.5.2-complete.jar:MVaP.jar MVaPAssembler add.mvap
|
||||
ou avec des traces (option -d) :
|
||||
$ java -cp antlr-4.5.2-complete.jar:MVaP.jar MVaPAssembler -d add.mvap
|
||||
ce qui produit le fichier add.mvap.cbap
|
||||
|
||||
Le fichier .cbap (code binaire à pile) est du binaire que la machine peut exécuter.
|
||||
|
||||
2- Exécuter :
|
||||
$ java -jar MVaP.jar add.mvap.cbap
|
||||
ou pour mieux comprendre avec des traces :
|
||||
$ java -jar MVaP.jar -d add.mvap.cbap
|
||||
|
28
1-ComputationAndData/MVaP/ExamenCalcul.mvap
Normal file
28
1-ComputationAndData/MVaP/ExamenCalcul.mvap
Normal file
@@ -0,0 +1,28 @@
|
||||
# lire a et b puis calculer et afficher l'expression ci-dessous.
|
||||
#[(a+b)*(a-b)]+[(b+1)*(b-1)]
|
||||
PUSHI 0 # a habite à l'adresse 0
|
||||
PUSHI 0 # b habite à l'adresse 1
|
||||
READ
|
||||
STOREG 0
|
||||
READ
|
||||
STOREG 1
|
||||
PUSHG 0
|
||||
PUSHG 1
|
||||
ADD
|
||||
PUSHG 0
|
||||
PUSHG 1
|
||||
SUB
|
||||
MUL
|
||||
PUSHG 1
|
||||
PUSHI 1
|
||||
ADD
|
||||
PUSHG 1
|
||||
PUSHI 1
|
||||
SUB
|
||||
MUL
|
||||
ADD
|
||||
WRITE
|
||||
POP
|
||||
POP # oublier b
|
||||
POP # oublier a
|
||||
HALT
|
5
1-ComputationAndData/MVaP/ExampleBoucleInfinie.mvap
Normal file
5
1-ComputationAndData/MVaP/ExampleBoucleInfinie.mvap
Normal file
@@ -0,0 +1,5 @@
|
||||
# Boucle infinie
|
||||
LABEL 0
|
||||
PUSHI 42
|
||||
JUMP 0
|
||||
HALT
|
18
1-ComputationAndData/MVaP/ExampleBoucleWhile.mvap
Normal file
18
1-ComputationAndData/MVaP/ExampleBoucleWhile.mvap
Normal file
@@ -0,0 +1,18 @@
|
||||
# Boucle While
|
||||
LABEL 19
|
||||
# le test qui va laisser une valeur 0 ou 1 en haut de la pile
|
||||
#PUSHI 0 # pour faux, donc je saute après
|
||||
#PUSHI 1 # pour vrai, donc je ne saute pas.
|
||||
READ # on demande à l'utilisateur
|
||||
JUMPF 18 # saut conditionnel vers le label 1 si le test est Faux sinon continue
|
||||
# quelque chose
|
||||
READ
|
||||
# Fin du quelque chose
|
||||
JUMP 19
|
||||
LABEL 18
|
||||
#La suite
|
||||
PUSHI 666
|
||||
WRITE
|
||||
POP
|
||||
# Fin de la suite.
|
||||
HALT
|
13
1-ComputationAndData/MVaP/ExampleSautQuiEviteDuCode.mvap
Normal file
13
1-ComputationAndData/MVaP/ExampleSautQuiEviteDuCode.mvap
Normal file
@@ -0,0 +1,13 @@
|
||||
# Saut qui evite du code
|
||||
PUSHI 11
|
||||
PUSHI 12
|
||||
JUMP 42
|
||||
PUSHI 666
|
||||
LABEL 312
|
||||
PUSHI 111
|
||||
PUSHI 110
|
||||
LABEL 42
|
||||
PUSHI 42
|
||||
PUSHI 43
|
||||
PUSHI 44
|
||||
HALT
|
13
1-ComputationAndData/MVaP/ExampleTest.mvap
Normal file
13
1-ComputationAndData/MVaP/ExampleTest.mvap
Normal file
@@ -0,0 +1,13 @@
|
||||
# 11 - 1?
|
||||
PUSHI 11
|
||||
PUSHI 1
|
||||
SUB
|
||||
# 11 / 2?
|
||||
PUSHI 11
|
||||
PUSHI 2
|
||||
DIV
|
||||
# tester 3 < 5
|
||||
PUSHI 3
|
||||
PUSHI 5
|
||||
INF
|
||||
HALT
|
26
1-ComputationAndData/MVaP/ExampleVariable.mvap
Normal file
26
1-ComputationAndData/MVaP/ExampleVariable.mvap
Normal file
@@ -0,0 +1,26 @@
|
||||
# Example du cours de déclaratrion / restauration d'une variable
|
||||
PUSHI 1 # i habite à l'adresse 0
|
||||
# quelque chose ici si on veut
|
||||
PUSHI 42
|
||||
PUSHI 42
|
||||
PUSHI 42
|
||||
POP
|
||||
POP
|
||||
POP
|
||||
# Fin du quelque chose ici si on veut
|
||||
PUSHI 6
|
||||
STOREG 0
|
||||
# quelque chose ici si on veut
|
||||
PUSHI 42
|
||||
PUSHI 42
|
||||
PUSHI 42
|
||||
POP
|
||||
POP
|
||||
POP
|
||||
# Fin du quelque chose ici si on veut
|
||||
PUSHI 1
|
||||
PUSHG 0
|
||||
ADD
|
||||
STOREG 0
|
||||
# i est incrémenté et vaut 7.
|
||||
HALT
|
19
1-ComputationAndData/MVaP/ExempleCours.mvap
Normal file
19
1-ComputationAndData/MVaP/ExempleCours.mvap
Normal file
@@ -0,0 +1,19 @@
|
||||
# exemple du cours.
|
||||
PUSHI 11
|
||||
PUSHI 6
|
||||
PUSHI 15
|
||||
MUL
|
||||
SUB
|
||||
PUSHI 5
|
||||
ADD
|
||||
PUSHI 12
|
||||
ADD
|
||||
PUSHI 9
|
||||
PUSHI 4
|
||||
MUL
|
||||
PUSHI 7
|
||||
MUL
|
||||
ADD
|
||||
WRITE
|
||||
POP
|
||||
HALT
|
42
1-ComputationAndData/MVaP/ExoCours.mvap
Normal file
42
1-ComputationAndData/MVaP/ExoCours.mvap
Normal file
@@ -0,0 +1,42 @@
|
||||
# Exo.
|
||||
# j = 1
|
||||
# i = 0
|
||||
# i = j
|
||||
# while i < 10:
|
||||
# i += 1
|
||||
# print(i)
|
||||
#
|
||||
# étapes par étapes ci-dessous
|
||||
#
|
||||
# j = 1
|
||||
PUSHI 1 ### j habite à l'adresse 0
|
||||
# i = 0
|
||||
PUSHI 0 ### i habite à l'adresse 1
|
||||
# i = j
|
||||
PUSHG 0 ### récupère j
|
||||
STOREG 1 ### affecte à i cette valeur
|
||||
|
||||
LABEL 12
|
||||
|
||||
# test i<10 ?
|
||||
PUSHG 1 ### récupère i
|
||||
PUSHI 4 ### pousse 4 pour que la démo tienne sur l'écran au lieu de 10
|
||||
INF ### <?
|
||||
#
|
||||
JUMPF 34
|
||||
# i += 1
|
||||
PUSHG 1
|
||||
PUSHI 1
|
||||
ADD
|
||||
STOREG 1
|
||||
#
|
||||
JUMP 12
|
||||
LABEL 34
|
||||
#La suite
|
||||
# print(i)
|
||||
PUSHG 1
|
||||
WRITE
|
||||
POP
|
||||
POP
|
||||
POP
|
||||
HALT
|
11
1-ComputationAndData/MVaP/ExoMoyenne3Notes.mvap
Normal file
11
1-ComputationAndData/MVaP/ExoMoyenne3Notes.mvap
Normal file
@@ -0,0 +1,11 @@
|
||||
# Moyenne entière de 3 notes 12, 8, 14
|
||||
PUSHI 12
|
||||
PUSHI 8
|
||||
PUSHI 14
|
||||
ADD
|
||||
ADD
|
||||
PUSHI 3
|
||||
DIV
|
||||
WRITE
|
||||
POP
|
||||
HALT
|
71
1-ComputationAndData/MVaP/ExoVoyager.mvap
Normal file
71
1-ComputationAndData/MVaP/ExoVoyager.mvap
Normal file
@@ -0,0 +1,71 @@
|
||||
### On souhaite comparer 2 parcours en transport public entre l'université de Créteil et l'IUT de SF.
|
||||
# Parcours 1 :
|
||||
# prendre la ligne 1 puis 8 pour Gare de Lyon (30 minutes)
|
||||
# prendre la ligne R pour Fontainebleau-Avon (45 minutes)
|
||||
# prendre un vélo pour l'IUT (20 minutes).
|
||||
# vs
|
||||
# Parcours 2 :
|
||||
# marcher au Vert de Maison prendre la ligne D pour Melun (55 minutes)
|
||||
# changer à Melun prendre la ligne R pour Fontainebleau-Avon (16 minutes)
|
||||
# prendre un vélo pour l'IUT (20 minutes).
|
||||
#
|
||||
#
|
||||
# On souhaite afficher 1 ou 2 selon que le parcours 1 ou parcours 2 est le plus court en temps.
|
||||
#
|
||||
# calcul du parcours 1
|
||||
# PUSHI 30
|
||||
# PUSHI 45
|
||||
# PUSHI 20
|
||||
# ADD
|
||||
# ADD
|
||||
# calcul du parcours 2
|
||||
# PUSHI 55
|
||||
# PUSHI 16
|
||||
# PUSHI 20
|
||||
# ADD
|
||||
# ADD
|
||||
# Comparons les deux durées
|
||||
# INF
|
||||
# 0 veut dire non, différent de 0 veut dire oui
|
||||
# HALT
|
||||
|
||||
### On a fait le test (30+45+20 < 55+16+20)?
|
||||
### On veut vraiment faire
|
||||
### if (30+45+20 < 55+16+20):
|
||||
### write 1
|
||||
### else :
|
||||
### write 2
|
||||
# calcul du parcours 1
|
||||
PUSHI 30
|
||||
PUSHI 45
|
||||
PUSHI 20
|
||||
ADD
|
||||
ADD
|
||||
# calcul du parcours 2
|
||||
PUSHI 55
|
||||
PUSHI 16
|
||||
PUSHI 20
|
||||
ADD
|
||||
ADD
|
||||
# Comparons les deux durées
|
||||
INF
|
||||
# 0 veut dire non, différent de 0 veut dire oui
|
||||
JUMPF 0
|
||||
#
|
||||
# then
|
||||
PUSHI 1
|
||||
WRITE
|
||||
POP
|
||||
#
|
||||
JUMP 1
|
||||
LABEL 0
|
||||
#
|
||||
# else
|
||||
PUSHI 2
|
||||
WRITE
|
||||
POP
|
||||
#
|
||||
LABEL 1
|
||||
# la suite
|
||||
HALT
|
||||
|
77
1-ComputationAndData/MVaP/ExoVoyager2.mvap
Normal file
77
1-ComputationAndData/MVaP/ExoVoyager2.mvap
Normal file
@@ -0,0 +1,77 @@
|
||||
### On souhaite comparer 2 parcours en transport public entre l'université de Créteil et l'IUT de SF.
|
||||
# Parcours 1 :
|
||||
# prendre la ligne 1 puis 8 pour Gare de Lyon (30 minutes)
|
||||
# prendre la ligne R pour Fontainebleau-Avon (45 minutes)
|
||||
# prendre un vélo pour l'IUT (20 minutes).
|
||||
# vs
|
||||
# Parcours 2 :
|
||||
# marcher au Vert de Maison prendre la ligne D pour Melun (55 minutes)
|
||||
# changer à Melun prendre la ligne R pour Fontainebleau-Avon (16 minutes)
|
||||
# prendre un vélo pour l'IUT (20 minutes).
|
||||
#
|
||||
#
|
||||
# On souhaite afficher 1 ou 2 selon que le parcours 1 ou parcours 2 est le plus court en temps.
|
||||
# Puis on souhaite afficher la durée du parcours optimal
|
||||
#
|
||||
# A compléter
|
||||
#
|
||||
# réserve de la place pour la durée du parcours 1
|
||||
PUSHI 0
|
||||
# réserve de la place pour la durée du parcours 2
|
||||
PUSHI 0
|
||||
# dp1 habite à l'adresse 0
|
||||
# dp2 habite à l'addresse 1
|
||||
#
|
||||
#
|
||||
# calcul du parcours 1
|
||||
PUSHI 30
|
||||
PUSHI 45
|
||||
PUSHI 20
|
||||
ADD
|
||||
ADD
|
||||
# dupliquer le résultat pour le stocker dans dp1
|
||||
DUP
|
||||
STOREG 0
|
||||
# calcul du parcours 2
|
||||
PUSHI 55
|
||||
PUSHI 16
|
||||
PUSHI 20
|
||||
ADD
|
||||
ADD
|
||||
# dupliquer le résultat pour le stocker dans dp2
|
||||
DUP
|
||||
STOREG 1
|
||||
# Comparons les deux durées
|
||||
INF
|
||||
# 0 veut dire non, différent de 0 veut dire oui
|
||||
JUMPF 0
|
||||
#
|
||||
# then
|
||||
PUSHI 1
|
||||
WRITE
|
||||
POP
|
||||
# charge la valeur de dp1 en haut de la pile
|
||||
PUSHG 0
|
||||
WRITE
|
||||
POP
|
||||
#
|
||||
JUMP 1
|
||||
LABEL 0
|
||||
#
|
||||
# else
|
||||
PUSHI 2
|
||||
WRITE
|
||||
POP
|
||||
# charge la valeur de dp2 en haut de la pile
|
||||
PUSHG 1
|
||||
WRITE
|
||||
POP
|
||||
#
|
||||
LABEL 1
|
||||
# la suite
|
||||
#
|
||||
# vide la mémoire des variables globales dp1 et dp2
|
||||
POP
|
||||
POP
|
||||
HALT
|
||||
|
74
1-ComputationAndData/MVaP/ExoVoyager3.mvap
Normal file
74
1-ComputationAndData/MVaP/ExoVoyager3.mvap
Normal file
@@ -0,0 +1,74 @@
|
||||
### On souhaite comparer 2 parcours en transport public avec au plus deux changements
|
||||
### L'utilisateur doit nous donner ces 6 durées.
|
||||
# Parcours 1 :
|
||||
# 3 durées
|
||||
# vs
|
||||
# Parcours 2 :
|
||||
# 3 durées
|
||||
#
|
||||
#
|
||||
# On souhaite afficher 1 ou 2 selon que le parcours 1 ou parcours 2 est le plus court en temps.
|
||||
# Puis on souhaite afficher la durée du parcours optimal
|
||||
#
|
||||
# A compléter
|
||||
#
|
||||
# réserve de la place pour la durée du parcours 1
|
||||
PUSHI 0
|
||||
# réserve de la place pour la durée du parcours 2
|
||||
PUSHI 0
|
||||
# dp1 habite à l'adresse 0
|
||||
# dp2 habite à l'addresse 1
|
||||
#
|
||||
#
|
||||
# calcul du parcours 1
|
||||
READ
|
||||
READ
|
||||
READ
|
||||
ADD
|
||||
ADD
|
||||
# dupliquer le résultat pour le stocker dans dp1
|
||||
DUP
|
||||
STOREG 0
|
||||
# calcul du parcours 2
|
||||
READ
|
||||
READ
|
||||
READ
|
||||
ADD
|
||||
ADD
|
||||
# dupliquer le résultat pour le stocker dans dp2
|
||||
DUP
|
||||
STOREG 1
|
||||
# Comparons les deux durées
|
||||
INF
|
||||
# 0 veut dire non, différent de 0 veut dire oui
|
||||
JUMPF 0
|
||||
#
|
||||
# then
|
||||
PUSHI 1
|
||||
WRITE
|
||||
POP
|
||||
# charge la valeur de dp1 en haut de la pile
|
||||
PUSHG 0
|
||||
WRITE
|
||||
POP
|
||||
#
|
||||
JUMP 1
|
||||
LABEL 0
|
||||
#
|
||||
# else
|
||||
PUSHI 2
|
||||
WRITE
|
||||
POP
|
||||
# charge la valeur de dp2 en haut de la pile
|
||||
PUSHG 1
|
||||
WRITE
|
||||
POP
|
||||
#
|
||||
LABEL 1
|
||||
# la suite
|
||||
#
|
||||
# vide la mémoire des variables globales dp1 et dp2
|
||||
POP
|
||||
POP
|
||||
HALT
|
||||
|
39
1-ComputationAndData/MVaP/ExoWhileViderPile.mvap
Normal file
39
1-ComputationAndData/MVaP/ExoWhileViderPile.mvap
Normal file
@@ -0,0 +1,39 @@
|
||||
# mon compteur de passages dans la boucle while (donc de valeurs empilees)
|
||||
PUSHI 0
|
||||
# Boucle While
|
||||
LABEL 19
|
||||
# le test qui va laisser une valeur 0 ou 1 en haut de la pile
|
||||
READ # on demande à l'utilisateur
|
||||
JUMPF 18 # saut conditionnel vers le label 1 si le test est Faux sinon continue
|
||||
# quelque chose
|
||||
READ
|
||||
PUSHI 1
|
||||
PUSHG 0
|
||||
ADD
|
||||
STOREG 0
|
||||
# Fin du quelque chose
|
||||
JUMP 19
|
||||
LABEL 18
|
||||
#
|
||||
# La suite : il faut faire autant de pop que la valeur du compteur
|
||||
# en gros while compteur > 0 : Pop; compteur --:
|
||||
#
|
||||
|
||||
LABEL 0
|
||||
# le test qui va laisser une valeur 0 ou 1 en haut de la pile
|
||||
PUSHG 0
|
||||
PUSHI 0
|
||||
SUP
|
||||
JUMPF 1 # saut conditionnel vers le label 1 si le test est Faux sinon continue
|
||||
POP
|
||||
# decrementer le compter
|
||||
PUSHG 0
|
||||
PUSHI 1
|
||||
SUB
|
||||
STOREG 0
|
||||
JUMP 0
|
||||
LABEL 1
|
||||
#La suite
|
||||
POP # pour la variable
|
||||
# Fin de la suite.
|
||||
HALT
|
BIN
1-ComputationAndData/MVaP/MVaP-1.0.tgz
Normal file
BIN
1-ComputationAndData/MVaP/MVaP-1.0.tgz
Normal file
Binary file not shown.
80
1-ComputationAndData/MVaP/MVaP-1.0/MVaP/index.html
Normal file
80
1-ComputationAndData/MVaP/MVaP-1.0/MVaP/index.html
Normal file
@@ -0,0 +1,80 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
|
||||
<head>
|
||||
|
||||
<title>MVàP</title>
|
||||
|
||||
<script src="js/Pile.js" type="text/javascript"></script>
|
||||
<script src="js/MVaP.js" type="text/javascript"></script>
|
||||
|
||||
<style type="text/css">
|
||||
body{ color: #333; font: 13px 'Lucida Grande', Verdana, sans-serif; }
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<h1>Machine Virtuelle à Pile</h1>
|
||||
|
||||
<h2>Historique</h2>
|
||||
Blabla sur la MVàP...
|
||||
|
||||
<h2>Documentation</h2>
|
||||
Toute la doc
|
||||
<p>
|
||||
lorem ipsum
|
||||
<h2>La MVàP</h2>
|
||||
<h3>Entrez le code</h3>
|
||||
<div class="runcode">
|
||||
<textarea id="codeMVaP" name="Code MVàP" label="Enter your code" rows="15" cols="33" spellcheck="false">
|
||||
PUSHI 2
|
||||
DUP
|
||||
PUSHI 3
|
||||
ADD
|
||||
PUSHI 4
|
||||
MUL
|
||||
MUL
|
||||
WRITE
|
||||
POP
|
||||
HALT
|
||||
</textarea>
|
||||
</div>
|
||||
|
||||
<h3>Exécution</h3>
|
||||
<script>
|
||||
var M = "";
|
||||
function runCode() {
|
||||
let text = codeMVaP.value;
|
||||
let d = debugCheckBox.checked;
|
||||
let maxSteps = MaxStepsBox.value;
|
||||
if (M == "") M = new MVaP();
|
||||
M.load(text);
|
||||
M.runCode(maxSteps, d);
|
||||
}
|
||||
|
||||
</script>
|
||||
<input type="button" value="Run" onclick="runCode();"/>
|
||||
<label for="MaxStepsBox">Nombre maximum de pas (0 pour pas de limite)</label>
|
||||
<input type="text" id="MaxStepsBox" name="MaxSteps" value="1000" minLength="4" maxLength="8" size="10"/>
|
||||
<label for="debugCheckBox">Traces pas à pas</label>
|
||||
<input type="checkbox" id="debugCheckBox" name="debug" checked />
|
||||
|
||||
|
||||
<pre class='traces'>
|
||||
<input type="button" value="Nettoyer les traces" onclick="cleanTraces()"/>
|
||||
<div id="tracesBox"></div>
|
||||
<input type="text" id="inputBox" hidden="true"/>
|
||||
<div id="errorBox" style="color: red" hidden="true"></div>
|
||||
</pre>
|
||||
|
||||
|
||||
<script>
|
||||
function cleanTraces() {
|
||||
tracesBox.innerText = '';
|
||||
errorBox.innerText = '';
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
216
1-ComputationAndData/MVaP/MVaP-1.0/MVaP/js/CBaP.js
Normal file
216
1-ComputationAndData/MVaP/MVaP-1.0/MVaP/js/CBaP.js
Normal file
@@ -0,0 +1,216 @@
|
||||
/**
|
||||
* Code Binaire pour Machine Virtuelle à Pile.
|
||||
* Les flottants sont des double qui prennent la place de 2 ints.
|
||||
* Les adresses sont des int.
|
||||
* CALL empile l'adresse de retour et la vauler du framePointer dans la pile.
|
||||
*/
|
||||
public class CBaP {
|
||||
|
||||
|
||||
|
||||
pc = 0;
|
||||
fp = 0;
|
||||
stack;
|
||||
program;
|
||||
const SizeofDouble = 2;
|
||||
|
||||
_debug = false;
|
||||
|
||||
CBaP(program, debug, stackSize) {
|
||||
this.program = program;
|
||||
this._debug = debug;
|
||||
this.stack = new Pile(stackSize);
|
||||
}
|
||||
|
||||
dumpInstruction(ii, out) {
|
||||
let i = ii;
|
||||
switch(program.get_int(i)) {
|
||||
case AssembleMVaP.ADD: out.print("ADD "); break;
|
||||
case AssembleMVaP.SUB: out.print("SUB "); break;
|
||||
case AssembleMVaP.MUL: out.print("MUL "); break;
|
||||
case AssembleMVaP.DIV: out.print("DIV "); break;
|
||||
case AssembleMVaP.INF: out.print("INF "); break;
|
||||
case AssembleMVaP.INFEQ: out.print("INFEQ "); break;
|
||||
case AssembleMVaP.SUP: out.print("SUP "); break;
|
||||
case AssembleMVaP.SUPEQ: out.print("SUPEQ "); break;
|
||||
case AssembleMVaP.EQUAL: out.print("EQUAL "); break;
|
||||
case AssembleMVaP.NEQ: out.print("NEQ "); break;
|
||||
|
||||
case AssembleMVaP.FADD: out.print("FADD "); break;
|
||||
case AssembleMVaP.FSUB: out.print("FSUB "); break;
|
||||
case AssembleMVaP.FMUL: out.print("FMUL "); break;
|
||||
case AssembleMVaP.FDIV: out.print("FDIV "); break;
|
||||
case AssembleMVaP.FINF: out.print("FINF "); break;
|
||||
case AssembleMVaP.FINFEQ: out.print("FINFEQ"); break;
|
||||
case AssembleMVaP.FSUP: out.print("FSUP "); break;
|
||||
case AssembleMVaP.FSUPEQ: out.print("FSUPEQ"); break;
|
||||
case AssembleMVaP.FEQUAL: out.print("FEQUAL"); break;
|
||||
case AssembleMVaP.FNEQ: out.print("FNEQ "); break;
|
||||
case AssembleMVaP.ITOF: out.print("ITOF "); break;
|
||||
case AssembleMVaP.FTOI: out.print("FTOI "); break;
|
||||
|
||||
case AssembleMVaP.RETURN: out.print("RETURN"); break;
|
||||
case AssembleMVaP.POP: out.print("POP "); break;
|
||||
case AssembleMVaP.READ: out.print("READ "); break;
|
||||
case AssembleMVaP.WRITE: out.print("WRITE "); break;
|
||||
case AssembleMVaP.WRITEF: out.print("WRITEF"); break;
|
||||
case AssembleMVaP.PADD: out.print("PADD "); break;
|
||||
case AssembleMVaP.PUSHGP: out.print("PUSHGP"); break;
|
||||
case AssembleMVaP.PUSHFP: out.print("PUSHFP"); break;
|
||||
case AssembleMVaP.DUP: out.print("DUP "); break;
|
||||
|
||||
case AssembleMVaP.PUSHI: out.print("PUSHI "); out.format("%7d ", program.get_int(++i)); break;
|
||||
case AssembleMVaP.PUSHG: out.print("PUSHG "); out.format("%7d ", program.get_int(++i)); break;
|
||||
case AssembleMVaP.STOREG: out.print("STOREG"); out.format("%7d ", program.get_int(++i)); break;
|
||||
case AssembleMVaP.PUSHL: out.print("PUSHL "); out.format("%7d ", program.get_int(++i)); break;
|
||||
case AssembleMVaP.STOREL: out.print("STOREL"); out.format("%7d ", program.get_int(++i)); break;
|
||||
case AssembleMVaP.PUSHR: out.print("PUSHR "); out.format("%7d ", program.get_int(++i)); break;
|
||||
case AssembleMVaP.STORER: out.print("STORER"); out.format("%7d ", program.get_int(++i)); break;
|
||||
case AssembleMVaP.FREE: out.print("FREE "); out.format("%7d ", program.get_int(++i)); break;
|
||||
case AssembleMVaP.ALLOC: out.print("ALLOC "); out.format("%7d ", program.get_int(++i)); break;
|
||||
|
||||
case AssembleMVaP.PUSHF: out.print("PUSHF "); ++i; out.format("%7.3f ", program.get_double(++i)); break;
|
||||
|
||||
case AssembleMVaP.JUMP: out.print("JUMP "); out.format("%7d ", program.get_int(++i)); break;
|
||||
case AssembleMVaP.JUMPF: out.print("JUMPF "); out.format("%7d ", program.get_int(++i)); break;
|
||||
case AssembleMVaP.JUMPI: out.print("JUMPI "); out.format("%7d ", program.get_int(++i)); break;
|
||||
case AssembleMVaP.CALL: out.print("CALL "); out.format("%7d ", program.get_int(++i)); break;
|
||||
case AssembleMVaP.HALT: out.print("HALT "); break;
|
||||
default: System.err.println("Code inconnu "+program.get_int(i)+" ligne "+i);
|
||||
}
|
||||
if (i == ii) out.print(" ");
|
||||
return i;
|
||||
}
|
||||
|
||||
public void dumpProgram(PrintStream out) {
|
||||
// out.println(program.toString(true));
|
||||
// out.println(program.toString());
|
||||
out.println(" Adr | Instruction");
|
||||
out.println("-----+---------------");
|
||||
for(int i = 0; i < program.getSize(); i++) {
|
||||
out.format("%4d | ", i);
|
||||
i = dumpInstruction(i, out);
|
||||
out.println();
|
||||
}
|
||||
}
|
||||
|
||||
private void _call(int label) {
|
||||
push(pc+1);
|
||||
push(fp);
|
||||
fp = size();
|
||||
pc = label;
|
||||
}
|
||||
|
||||
private void _return() {
|
||||
while(size() > fp)
|
||||
pop();
|
||||
fp = pop();
|
||||
pc = pop();
|
||||
}
|
||||
|
||||
private BufferedReader input = null;
|
||||
private int _read() {
|
||||
try {
|
||||
if (input == null)
|
||||
input = new BufferedReader(new InputStreamReader(System.in));
|
||||
return Integer.parseInt(input.readLine());
|
||||
} catch (Exception e) {
|
||||
System.err.println(e);
|
||||
System.exit(1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean execute() {
|
||||
if (_debug) {
|
||||
dumpProgram(System.out);
|
||||
System.err.println();
|
||||
System.err.println(" pc | | fp pile");
|
||||
System.err.println("====================================================");
|
||||
}
|
||||
pc = 0;
|
||||
while (true) {
|
||||
if (_debug) {
|
||||
System.err.format("%4d | ", pc);
|
||||
dumpInstruction(pc, System.err);
|
||||
System.err.format("| %4d %s\n", fp, stack.toString());
|
||||
}
|
||||
try {
|
||||
int p1, p2; // utile pour être sûr de l'ordre des pop() !
|
||||
double d1, d2;
|
||||
switch(program.get_int(pc++)) {
|
||||
case AssembleMVaP.ADD: p1 = pop(); p2 = pop(); push(p2 + p1); break;
|
||||
case AssembleMVaP.SUB: p1 = pop(); p2 = pop(); push(p2 - p1); break;
|
||||
case AssembleMVaP.MUL: p1 = pop(); p2 = pop(); push(p2 * p1); break;
|
||||
case AssembleMVaP.DIV: p1 = pop(); p2 = pop(); push(p2 / p1); break;
|
||||
case AssembleMVaP.INF: p1 = pop(); p2 = pop(); push(p2 < p1 ? 1 : 0); break;
|
||||
case AssembleMVaP.INFEQ: p1 = pop(); p2 = pop(); push(p2 <= p1 ? 1 : 0); break;
|
||||
case AssembleMVaP.SUP: p1 = pop(); p2 = pop(); push(p2 > p1 ? 1 : 0); break;
|
||||
case AssembleMVaP.SUPEQ: p1 = pop(); p2 = pop(); push(p2 >= p1 ? 1 : 0); break;
|
||||
case AssembleMVaP.EQUAL: p1 = pop(); p2 = pop(); push(p2 == p1 ? 1 : 0); break;
|
||||
case AssembleMVaP.NEQ: p1 = pop(); p2 = pop(); push(p2 != p1 ? 1 : 0); break;
|
||||
|
||||
case AssembleMVaP.FADD: d1 = pop_double(); d2 = pop_double(); push(d2 + d1); break;
|
||||
case AssembleMVaP.FSUB: d1 = pop_double(); d2 = pop_double(); push(d2 - d1); break;
|
||||
case AssembleMVaP.FMUL: d1 = pop_double(); d2 = pop_double(); push(d2 * d1); break;
|
||||
case AssembleMVaP.FDIV: d1 = pop_double(); d2 = pop_double(); push(d2 / d1); break;
|
||||
case AssembleMVaP.FINF: d1 = pop_double(); d2 = pop_double(); push(d2 < d1 ? 1 : 0); break;
|
||||
case AssembleMVaP.FINFEQ: d1 = pop_double(); d2 = pop_double(); push(d2 <= d1 ? 1 : 0); break;
|
||||
case AssembleMVaP.FSUP: d1 = pop_double(); d2 = pop_double(); push(d2 > d1 ? 1 : 0); break;
|
||||
case AssembleMVaP.FSUPEQ: d1 = pop_double(); d2 = pop_double(); push(d2 >= d1 ? 1 : 0); break;
|
||||
case AssembleMVaP.FEQUAL: d1 = pop_double(); d2 = pop_double(); push(d2 == d1 ? 1 : 0); break;
|
||||
case AssembleMVaP.FNEQ: d1 = pop_double(); d2 = pop_double(); push(d2 != d1 ? 1 : 0); break;
|
||||
|
||||
case AssembleMVaP.FTOI: push((int)pop_double()); break;
|
||||
case AssembleMVaP.ITOF: push((double)pop()); break;
|
||||
|
||||
case AssembleMVaP.RETURN: _return(); break;
|
||||
case AssembleMVaP.POP: pop(); break;
|
||||
case AssembleMVaP.READ: push(_read()); break;
|
||||
case AssembleMVaP.WRITE: System.out.format("%7d\n", peek()); break;
|
||||
case AssembleMVaP.WRITEF: System.out.format("%7.3f\n", peek_double()); break;
|
||||
case AssembleMVaP.PADD: p1 = pop(); p2 = pop(); push(p2 + p1); break;
|
||||
case AssembleMVaP.PUSHGP: push(0); break;
|
||||
case AssembleMVaP.PUSHFP: push(fp); break;
|
||||
case AssembleMVaP.DUP: push(peek()); break;
|
||||
|
||||
case AssembleMVaP.PUSHI: push(program.get_int(pc++)); break;
|
||||
case AssembleMVaP.PUSHG: push(get(program.get_int(pc++))); break;
|
||||
case AssembleMVaP.STOREG: set(program.get_int(pc++), pop()); break;
|
||||
// ajouter -2 si adresse négative ?
|
||||
case AssembleMVaP.PUSHL: push(get(fp+program.get_int(pc++))); break;
|
||||
case AssembleMVaP.STOREL:set(fp+program.get_int(pc++), pop()); break;
|
||||
case AssembleMVaP.PUSHR: push(get(pop()+program.get_int(pc++)));break;
|
||||
case AssembleMVaP.STORER:p1 = pop(); p2 = pop(); set(p2+program.get_int(pc++), p1); break;
|
||||
case AssembleMVaP.FREE: doPop(program.get_int(pc++)); break;
|
||||
case AssembleMVaP.ALLOC: doPush(program.get_int(pc++)); break;
|
||||
|
||||
case AssembleMVaP.PUSHF: push(program.get_int(pc++)); push(program.get_int(pc++)); break;
|
||||
|
||||
case AssembleMVaP.JUMP: pc = program.get_int(pc); break;
|
||||
case AssembleMVaP.JUMPF: if (pop() == 0) pc = program.get_int(pc); else pc++; break;
|
||||
case AssembleMVaP.JUMPI: pc = program.get_int(pc)+pop(); break;
|
||||
case AssembleMVaP.CALL: _call(program.get_int(pc)); break;
|
||||
case AssembleMVaP.HALT: return true;
|
||||
default: System.err.println("Code inconnu "+program.get_int(pc)+" ligne "+pc); return false;
|
||||
}
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
System.err.println(stack.getException());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void push(int i) { stack.push(i); }
|
||||
int pop() { return stack.pop_int(); }
|
||||
void push(double d) { stack.push(d); }
|
||||
double pop_double() { return stack.pop_double(); }
|
||||
int peek() { return stack.peek_int(); }
|
||||
double peek_double() { return stack.peek_double(); }
|
||||
int size() { return stack.getSize(); }
|
||||
void set(int index, int i) { stack.set(index, i); }
|
||||
int get(int index) { return stack.get_int(index); }
|
||||
|
||||
void doPop(int nb) { for(; nb > 0; nb--) stack.pop_int(); }
|
||||
void doPush(int nb) { for(; nb > 0; nb--) stack.push(0); }
|
||||
}
|
33
1-ComputationAndData/MVaP/MVaP-1.0/MVaP/js/LexerMVaP.dot
Normal file
33
1-ComputationAndData/MVaP/MVaP-1.0/MVaP/js/LexerMVaP.dot
Normal file
@@ -0,0 +1,33 @@
|
||||
digraph LexerMVaP {
|
||||
Start -> Start [label="space "];
|
||||
Start -> Id [label="[A-Z]"];
|
||||
Id -> Id [label="[A-Z]"];
|
||||
|
||||
Start -> Int [label="[-+0-9]"];
|
||||
Int -> Int [label="[0-9]"];
|
||||
Int -> Decimal [label="."];
|
||||
Int -> E [label="E"];
|
||||
|
||||
Decimal -> Decimal [label="[0-9]"];
|
||||
Decimal -> E [label="E"];
|
||||
|
||||
E -> Exponent [label="[-+0-9]"];
|
||||
Exponent -> Exponent [label="[0-9]"];
|
||||
|
||||
Start -> error [label="*"];
|
||||
Id -> error [label="*"];
|
||||
Int -> error [label="*"];
|
||||
Decimal -> error [label="*"];
|
||||
E -> error [label="*"];
|
||||
Exponent -> error [label="*"];
|
||||
|
||||
edge [color=red, fontcolor=red];
|
||||
|
||||
Start -> Start [label="NL/[Newline] "];
|
||||
Id -> Start [label="space/ID"];
|
||||
Int -> Start [label="space/Int"];
|
||||
Decimal -> Start [label="space/Float"];
|
||||
Exponent -> Start [label="space/Float"];
|
||||
|
||||
{ rank = same; Decimal E Exponent }
|
||||
}
|
BIN
1-ComputationAndData/MVaP/MVaP-1.0/MVaP/js/LexerMVaP.png
Normal file
BIN
1-ComputationAndData/MVaP/MVaP-1.0/MVaP/js/LexerMVaP.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 72 KiB |
481
1-ComputationAndData/MVaP/MVaP-1.0/MVaP/js/MVaP.js
Normal file
481
1-ComputationAndData/MVaP/MVaP-1.0/MVaP/js/MVaP.js
Normal file
@@ -0,0 +1,481 @@
|
||||
/*
|
||||
MVàP : Machine Virtuelle à Pile
|
||||
|
||||
2 méthodes principales :
|
||||
|
||||
load(text) qui charge du texte, l'analyse et l'assemble.
|
||||
runcode(maxSteps, d) qui exécute le code en limitant le nombre d'étape à maxSteps et qui produit des traces si d est true.
|
||||
|
||||
Les sorties se font dans un élément d'id "tracesBox".
|
||||
Les entrées dans un élément d'id "inputBox".
|
||||
Les messages d'erreur vont dans un élément d'id "errorBox".
|
||||
|
||||
|
||||
Auteur : Jacques Madelaine
|
||||
Version 1.0
|
||||
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
let debugLexer = false;
|
||||
let debugAssemble = false;
|
||||
let debug = true;
|
||||
|
||||
/** token lexicaux */
|
||||
const T_ID = 0;
|
||||
const T_INT = 1;
|
||||
const T_FLOAT = 2;
|
||||
const T_SPACE = 3;
|
||||
const T_NL = 4;
|
||||
const T_ERROR = 5;
|
||||
const T_EOF = 6;
|
||||
|
||||
let T_Text = [ "T_ID", "T_INT", "T_FLOAT", "T_SPACE", "T_NL", "T_ERROR", "T_EOF" ];
|
||||
|
||||
/** token grammaticaux */
|
||||
const INSTR1 = 0;
|
||||
const INSTR2 = 1;
|
||||
const INT = 2;
|
||||
const INSTR2F = 3;
|
||||
const FLOAT = 4;
|
||||
const LABEL = 5;
|
||||
const JUMP = 6;
|
||||
const NEWLINE = 7;
|
||||
|
||||
class MVaP {
|
||||
|
||||
codes = [ // pour l'interprète de MVàP
|
||||
[ "ADD", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2+p1); } ],
|
||||
[ "SUB", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2-p1); } ],
|
||||
[ "MUL", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2*p1); } ],
|
||||
[ "DIV", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(Math.floor(p2/p1)); } ],
|
||||
[ "INF", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2<p1?1:0); } ],
|
||||
[ "INFEQ", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2<=p1?1:0); } ],
|
||||
[ "SUP", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2>p1?1:0); } ],
|
||||
[ "SUPEQ", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2>=p1?1:0); } ],
|
||||
[ "EQUAL", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2==p1?1:0); } ],
|
||||
[ "NEQ", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2!=p1?1:0); } ],
|
||||
[ "FADD", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.pushFloat64(d2+d1); } ],
|
||||
[ "FSUB", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.pushFloat64(d2-d1); } ],
|
||||
[ "FMUL", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.pushFloat64(d2*d1); } ],
|
||||
[ "FDIV", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.pushFloat64(d2/d1); } ],
|
||||
[ "FINF", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.push(d2<d1?1:0); } ],
|
||||
[ "FINFEQ", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.push(d2<=d1?1:0); } ],
|
||||
[ "FSUP", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.push(d2>d1?1:0); } ],
|
||||
[ "FSUPEQ", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.push(d2>=d1?1:0); } ],
|
||||
[ "FEQUAL", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.push(d2==d1?1:0); } ],
|
||||
[ "FNEQ", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.push(d2!=d1?1:0); } ],
|
||||
[ "ITOF", INSTR1, () => { let p1 = this.stack.pop(); this.trace("ITOF "+p1); this.stack.pushFloat64(p1); } ],
|
||||
[ "FTOI", INSTR1, () => { this.stack.push(Math.round(this.stack.popFloat64())); } ],
|
||||
[ "RETURN", INSTR1, () => { while(this.stack.getSize() > this.fp) this.stack.pop();
|
||||
this.fp = this.stack.pop(); this.pc = this.stack.pop(); } ],
|
||||
[ "POP", INSTR1, () => { this.stack.pop(); } ],
|
||||
[ "READ", INSTR1, () => { this.read(); return true; } ],
|
||||
[ "READF", INSTR1, () => { this.read(); return true; } ],
|
||||
[ "WRITE", INSTR1, () => { this.trace(this.stack.peek()+"\n"); } ],
|
||||
[ "WRITEF", INSTR1, () => { this.trace(this.stack.peekFloat64()+"\n"); } ],
|
||||
[ "PADD", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2+p1); } ],
|
||||
[ "PUSHGP", INSTR1, () => { this.stack.push(0); } ],
|
||||
[ "PUSHFP", INSTR1, () => { this.stack.push(this.fp); } ],
|
||||
[ "DUP", INSTR1, () => { this.stack.push(this.stack.peek()); } ],
|
||||
|
||||
[ "PUSHI", INSTR2, () => { this.stack.push(this.program.get(this.pc++)); } ],
|
||||
[ "PUSHG", INSTR2, () => { this.stack.push(this.stack.get(this.program.get(this.pc++)));} ],
|
||||
[ "STOREG", INSTR2, () => { this.stack.set(this.program.get(this.pc++), this.stack.pop())} ],
|
||||
[ "PUSHL", INSTR2, () => { this.stack.push(this.stack.get(this.fp+this.program.get(this.pc++))); } ],
|
||||
[ "STOREL", INSTR2, () => { this.stack.set(this.fp+this.program.get(this.pc++), this.stack.pop()); } ],
|
||||
[ "PUSHR", INSTR2, () => { this.stack.push(this.stack.get(this.stack.pop()+this.program.get(this.pc++))); } ],
|
||||
[ "STORER", INSTR2, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.set(p2+this.program.get(this.pc++)); } ],
|
||||
[ "FREE", INSTR2, () => { this.stack.doPop(this.program.get(this.pc++)); } ],
|
||||
[ "ALLOC", INSTR2, () => { this.stack.doPush(this.program.get(this.pc++)); } ],
|
||||
[ "PUSHF", INSTR2F, () => { this.stack.pushFloat64(this.program.getFloat64(this.pc)); this.pc += 2; } ],
|
||||
[ "CALL", JUMP, () => { this.stack.push(this.pc+1); this.stack.push(this.fp);
|
||||
this.fp = this.stack.getSize();
|
||||
this.pc = this.program.get(this.pc); } ],
|
||||
[ "JUMP", JUMP, () => { this.pc = this.program.get(this.pc); } ],
|
||||
[ "JUMPF", JUMP, () => { if (this.stack.pop()==0) this.pc = this.program.get(this.pc);
|
||||
else this.pc++; } ],
|
||||
[ "JUMPI", JUMP, () => { this.pc = this.program.get(this.pc)+this.stack.pop();} ],
|
||||
|
||||
[ "HALT", INSTR1, () => { return true; } ],
|
||||
|
||||
[ "LABEL", LABEL, /* erreur interne */ ]
|
||||
];
|
||||
/*** Ajouter instr : POPF */
|
||||
|
||||
tokens = []; // indexe le tableau codes sur son premier élément
|
||||
|
||||
text = "";
|
||||
|
||||
// <Lexer>
|
||||
// see LexerMVaP.png for the DFA diagram
|
||||
state = "Start";
|
||||
text; // le texte à analyser
|
||||
index = 0; // index dans la chaîne text
|
||||
lineNumber = 1;
|
||||
|
||||
transitions = [
|
||||
{ state: "Start", next: "Start", test: (c) => { return c == "\n"; }, token: T_NL },
|
||||
{ state: "Start", next: "Start", test: (c) => { return c.trim() == ""; }, token: false },
|
||||
{ state: "Start", next: "Id", test: (c) => { return "A" <= c && c <= "Z"; }, token: false },
|
||||
{ state: "Id", next: "Id", test: (c) => { return "A" <= c && c <= "Z"; }, token: false},
|
||||
{ state: "Id", next: "Start", test: (c) => { return c.trim() == ""; }, token: T_ID},
|
||||
{ state: "Start", next: "Int", test: (c) => { return ("0" <= c && c <= "9")||c=="-"||c=="+"; }, token: false },
|
||||
{ state: "Int", next: "Int", test: (c) => { return "0" <= c && c <= "9"; }, token: false },
|
||||
{ state: "Int", next: "Start", test: (c) => { return c.trim() == ""; }, token: T_INT },
|
||||
{ state: "Int", next: "Decimal", test: (c) => { return c == "."; }, token: false },
|
||||
{ state: "Int", next: "E", test: (c) => { return c == "E"; }, token: false },
|
||||
{ state: "Decimal", next: "Decimal", test: (c) => { return "0" <= c && c <= "9"; }, token: false },
|
||||
{ state: "Decimal", next: "E", test: (c) => { return c == "E"; }, token: false },
|
||||
{ state: "Decimal", next: "Start", test: (c) => { return c.trim() == ""; }, token: T_FLOAT },
|
||||
{ state: "E", next: "Exponent", test: (c) => { return ("0"<=c && c<="9")||c=="-"||c=="+"; }, token: false },
|
||||
{ state: "Exponent", next: "Exponent", test: (c) => { return "0" <= c && c <= "9"; }, token: false },
|
||||
{ state: "Exponent", next: "Start", test: (c) => { return c.trim() == ""; }, token: T_FLOAT }
|
||||
// else: error
|
||||
];
|
||||
|
||||
initLexer() {
|
||||
this.index = 0;
|
||||
this.lineNumber = 1
|
||||
console.log("*****************\n* C'est parti *\n*****************");
|
||||
}
|
||||
|
||||
// Donne la transition correspondante à l'état courant et au caractère entrant
|
||||
transition(c) {
|
||||
for (let v of this.transitions.values()) {
|
||||
// on aurait pu indexer les transitions sur state au lieu de tout énumérer
|
||||
if (this.state == v.state && v.test(c)) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
return T_ERROR;
|
||||
}
|
||||
|
||||
yytext = ""; // contient le texte du jeton syntaxique (nommé comme dans lex/yacc)
|
||||
|
||||
|
||||
nextToken() {
|
||||
let c;
|
||||
let trans;
|
||||
while (true) {
|
||||
c = this.text[this.index];
|
||||
if (c === undefined)
|
||||
return T_EOF;
|
||||
c = c.toUpperCase();
|
||||
trans = this.transition(c);
|
||||
if (trans == T_ERROR) { this.yytext += c; return T_ERROR; }
|
||||
if (this.state != trans.next && this.state == "Start") this.yytext ="";
|
||||
|
||||
this.state = trans.next;
|
||||
this.index++;
|
||||
|
||||
if (Number.isInteger(trans.token)) {
|
||||
break;
|
||||
}
|
||||
this.yytext += c;
|
||||
}
|
||||
|
||||
// séparateur significatif
|
||||
if (c == "\n") {
|
||||
if (trans.token != T_NL) {
|
||||
this.index--; // ne pas manger la fin de ligne non prise en compte
|
||||
// une autre façon de dire est que l'on n'incrémente pas l'index sur le renvoi de token
|
||||
// sauf en cas de token constitué de séparateur
|
||||
} else
|
||||
this.lineNumber++; // on en profite pour compter la ligne
|
||||
}
|
||||
// console.log(" line " + this.lineNumber + " " + trans.token + " '" + yytex + "' i="+i);
|
||||
return trans.token;
|
||||
}
|
||||
// </Lexer>
|
||||
|
||||
// <Analyse sémantique et assemblage>
|
||||
|
||||
/** Grammaire des instructions
|
||||
instr
|
||||
: INSTR1 T_NL
|
||||
| INSTR2 T_INT T_NL
|
||||
| JUMP T_INT T_NL
|
||||
| INSTR2F T_FLOAT T_NL
|
||||
| LABEL T_NL
|
||||
| T_NL
|
||||
;
|
||||
*/
|
||||
|
||||
program;// Pile contenant le programme compilé
|
||||
adressesLabels; // adresse des étiquettes pour l'assemblage
|
||||
|
||||
analyse() {
|
||||
|
||||
this.initLexer();
|
||||
|
||||
let token; // le jeton lexical courant
|
||||
let state = NEWLINE; // état de l'analyseur grammatical (ici le précédent syntagme grammatical)
|
||||
this.program = new Pile();
|
||||
this.adressesLabels = [];
|
||||
|
||||
while (true) {
|
||||
this.yytext = "";
|
||||
token = this.nextToken();
|
||||
if (debugLexer)
|
||||
console.log("** nextToken line "+this.lineNumber+" token "+token+" "+T_Text[token]+" '" +this.yytext+"' index "+this.index+" state "+state);
|
||||
|
||||
switch(token) {
|
||||
case T_EOF:
|
||||
return true;
|
||||
case T_ID:
|
||||
let k = this.tokens[this.yytext];
|
||||
if (k === undefined || state != NEWLINE) return false;
|
||||
state = this.codes[k][1];
|
||||
if (state != LABEL) { // pas d'instruction LABEL dans le code
|
||||
this.program.push(k);
|
||||
}
|
||||
break;
|
||||
case T_INT:
|
||||
if (state == LABEL) { // on mémorise juste l'adresse pour la passe d'assemblage
|
||||
this.adressesLabels[Number(this.yytext)] = this.program.getSize(); // ± 1 who knows?
|
||||
} else if(state == INSTR2 || state == JUMP) {
|
||||
this.program.push(Number(this.yytext));
|
||||
} else return false;
|
||||
state = INT;
|
||||
break;
|
||||
case T_FLOAT:
|
||||
if (state != INSTR2F) return false;
|
||||
state = FLOAT;
|
||||
this.program.pushFloat64(Number(this.yytext));
|
||||
break;
|
||||
case T_NL:
|
||||
if (state == INSTR2 || state == JUMP || state == INSTR2F) return false;
|
||||
state = NEWLINE;
|
||||
break;
|
||||
case T_ERROR:
|
||||
return false;
|
||||
default:
|
||||
alert("Erreur interne prévenir la maintenance d'urgence");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
console.log("Programme correct syntaxiquement");
|
||||
return true;
|
||||
}
|
||||
|
||||
assemble() {
|
||||
// change les numéros d'étiquettes par les adresses des instructions pointées.
|
||||
if (debugAssemble) {
|
||||
console.log("Label "+this.adressesLabels);
|
||||
console.log(this.dumpProgram());
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.program.getSize(); i++) {
|
||||
let k = this.program.get(i);
|
||||
// Attention il faut compter si par malchance un entier = code d'un saut
|
||||
switch (this.codes[k][1]) {
|
||||
case INSTR1:
|
||||
break;
|
||||
case INSTR2:
|
||||
i++; // on saute l'entier qui suit
|
||||
break;
|
||||
case INSTR2F:
|
||||
i += 2; // on saute le flottant qui suit
|
||||
break;
|
||||
case JUMP: // met à jour l'adresse du saut
|
||||
i++;
|
||||
console.log("--- set "+i);
|
||||
this.program.set(i, this.adressesLabels[this.program.get(i)]);
|
||||
break;
|
||||
default:
|
||||
alert("Erreur assemblage");
|
||||
}
|
||||
}
|
||||
// console.log(this.dumpProgram());
|
||||
return true;
|
||||
}
|
||||
// </Analyse sémantique et assemblage>
|
||||
|
||||
|
||||
dumpInstruction(i, result) {
|
||||
let code = this.codes[this.program.get(i)];
|
||||
result += code[0].padEnd(6, ' ');
|
||||
switch (code[1]) {
|
||||
case INSTR2:
|
||||
case JUMP:
|
||||
result += this.program.get(++i).toString().padStart(7, ' ');
|
||||
break;
|
||||
case INSTR2F:
|
||||
result += this.program.getFloat64(++i).toString().padStart(7, ' ');
|
||||
i++;
|
||||
break;
|
||||
default:
|
||||
result += " ";
|
||||
}
|
||||
|
||||
return [i, result];
|
||||
}
|
||||
|
||||
dumpProgram() {
|
||||
let result = "";
|
||||
result += this.program + "\n";
|
||||
|
||||
result += " Adr | Instruction\n-----+---------------\n";
|
||||
for(let i = 0; i < this.program.getSize(); i++) {
|
||||
result += i.toString().padStart(4, " ")+" | ";
|
||||
[i, result] = this.dumpInstruction(i, result);
|
||||
result += "\n";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
// init tokens
|
||||
for (let k of this.codes.keys())
|
||||
this.tokens[this.codes[k][0]] = k;
|
||||
try {
|
||||
inputBox.addEventListener("keydown", (event) => { this.enterText(event); });
|
||||
} catch(e) {
|
||||
alert("Warning READ indisponible");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// charge et compile le code
|
||||
load(text) {
|
||||
// on supprime les commentaires
|
||||
this.text = text.replaceAll(/(#|\/\/).*\n/g, "\n");
|
||||
// on insère une fin de ligne si le texte n'en a pas à sa fin
|
||||
if (this.text[this.text.length-1] != "\n") this.text = this.text+"\n";
|
||||
if (! this.analyse()) {
|
||||
alert("Erreur ligne "+this.lineNumber+" sur '" +this.yytext+"'");
|
||||
return false;
|
||||
}
|
||||
return this.assemble();
|
||||
|
||||
}
|
||||
|
||||
pc = 0;
|
||||
fp = 0;
|
||||
stack;
|
||||
step; // step number of the current run
|
||||
maxSteps;
|
||||
|
||||
runCode(maxSteps, d) {
|
||||
debug = d;
|
||||
//for (let i = 0; i < this.codes.length; i++) console.log(i+ " "+ this.codes[i][0]);
|
||||
this.pc = 0;
|
||||
this.fp = 0;
|
||||
this.stack = new Pile();
|
||||
|
||||
if (debug)
|
||||
this.trace("Programme\n"+this.dumpProgram() + "\nTraces exécution\n"
|
||||
+ " pc | Instruction | fp pile\n"
|
||||
+ "=====+===============+=============================\n");
|
||||
this.cleanInputAndErrorBoxes();
|
||||
this.step = 0;
|
||||
this.maxSteps = maxSteps;
|
||||
this.resumeRun();
|
||||
|
||||
}
|
||||
|
||||
resumeRun(readCode, readResult) {
|
||||
if (readCode != undefined && readResult != undefined) { // return from read
|
||||
// READ or READF ?
|
||||
if (readCode == "READ")
|
||||
this.stack.push(readResult);
|
||||
else if (readCode == "READF")
|
||||
this.stack.pushFloat64(readResult);
|
||||
else {
|
||||
this.trace("Read Code inattendu "+readCode, true);
|
||||
return;
|
||||
}
|
||||
this.step++;
|
||||
}
|
||||
for (; this.maxSteps <= 0 || this.step < this.maxSteps; this.step++) // while (true)
|
||||
{
|
||||
// if (this.pc < 0 || this.pc >= this.program.getSize()) break;
|
||||
try {
|
||||
|
||||
if (debug) {
|
||||
let s = this.pc.toString().padStart(4, " ")+" | ";
|
||||
let junk;
|
||||
[junk, s] = this.dumpInstruction(this.pc, s);
|
||||
s += " |"+this.fp.toString().padStart(4,' ')+' '+this.stack.toString()+"\n";
|
||||
this.trace(s);
|
||||
}
|
||||
if (this.codes[this.program.get(this.pc++)][2]() === true)
|
||||
break;
|
||||
|
||||
} catch(e) {
|
||||
this.trace(e, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trace(s, error) {
|
||||
if (error) {
|
||||
console.error(s);
|
||||
errorBox.innerText = s;
|
||||
errorBox.hidden = false;
|
||||
errorBox.scrollIntoView();
|
||||
} else {
|
||||
tracesBox.innerText += s;
|
||||
console.log(s);
|
||||
}
|
||||
}
|
||||
|
||||
cleanInputAndErrorBoxes() {
|
||||
errorBox.innerText = "";
|
||||
errorBox.hidden = true;
|
||||
inputBox.value = "";
|
||||
inputBox.hidden = true;
|
||||
}
|
||||
|
||||
|
||||
read() {
|
||||
inputBox.hidden = false;
|
||||
inputBox.focus();
|
||||
}
|
||||
|
||||
enterText(e) {
|
||||
if (e.code == "Enter") {
|
||||
let readResult = 0;
|
||||
// What is the last op token
|
||||
let t = this.codes[this.program.get(this.pc-1)][0];
|
||||
switch (t) {
|
||||
case "READ":
|
||||
readResult = Number.parseInt(inputBox.value, 10);
|
||||
if (! Number.isInteger(readResult)) {
|
||||
alert(inputBox.value+" n'est pas un nombre entier");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case "READF":
|
||||
readResult = Number.parseFloat(inputBox.value);
|
||||
if (Number.isNaN(readResult)) {
|
||||
alert(inputBox.value+" n'est pas un nombre entier");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
this.trace("Code inattendu pour lecture "+t+"\n", true);
|
||||
return;
|
||||
}
|
||||
|
||||
tracesBox.innerText += " > "+readResult+"\n";
|
||||
inputBox.value = "";
|
||||
inputBox.hidden = true;
|
||||
console.log("READ ->"+readResult);
|
||||
this.resumeRun(t, readResult);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
153
1-ComputationAndData/MVaP/MVaP-1.0/MVaP/js/Pile.js
Normal file
153
1-ComputationAndData/MVaP/MVaP-1.0/MVaP/js/Pile.js
Normal file
@@ -0,0 +1,153 @@
|
||||
// Class Pile
|
||||
// Auteur : Jacques Madelaine
|
||||
|
||||
// Une Pile est essentiellement une pile d'entiers ("int32")
|
||||
// Elle peut aussi empiler et dépiler des flottants définis sur 64 bits.
|
||||
// L'index est sur les entiers.
|
||||
|
||||
// Rappel : en JavaScript les Number sont tous stockés comme des flottants 64 bits.
|
||||
// Il faut donc voir cette Pile comme un objet pédagogique
|
||||
// et non une implémentation optimale en JavaScipt.
|
||||
|
||||
"use strict";
|
||||
|
||||
class Pile {
|
||||
buffer; // ArrayBuffer de bytes
|
||||
pile; // On va utiliser 4 bytes pour les entiers et 8 pour les flottants
|
||||
haut = 0; // index de sommet de pile en bytes
|
||||
|
||||
// size : taille en bytes de la pile
|
||||
constructor(size) {
|
||||
if (size === undefined)
|
||||
size = 1000;
|
||||
|
||||
this.buffer = new ArrayBuffer(size);
|
||||
this.pile = new DataView(this.buffer);
|
||||
}
|
||||
|
||||
push(i) {
|
||||
if (! Number.isInteger(i))
|
||||
throw new TypeError("Try to push a non integer");
|
||||
this.pile.setInt32(this.haut, i);
|
||||
this.haut += 4;
|
||||
}
|
||||
|
||||
doPush(nb) { for(; nb > 0; nb--) this.push(0); }
|
||||
|
||||
pop() {
|
||||
this.haut -= 4;
|
||||
return this.pile.getInt32(this.haut);
|
||||
}
|
||||
|
||||
doPop(nb) { for(; nb > 0; nb--) this.pop(); }
|
||||
|
||||
peek() {
|
||||
return this.pile.getInt32(this.haut-4);
|
||||
}
|
||||
|
||||
set(index, i) {
|
||||
if (! Number.isInteger(i))
|
||||
throw new TypeError("Try to set a non integer");
|
||||
this.pile.setInt32(index*4, i);
|
||||
}
|
||||
|
||||
get(index) {
|
||||
return this.pile.getInt32(index*4);
|
||||
}
|
||||
|
||||
|
||||
pushFloat64(f) {
|
||||
this.pile.setFloat64(this.haut, f);
|
||||
this.haut += 8;
|
||||
}
|
||||
|
||||
popFloat64() {
|
||||
this.haut -= 8;
|
||||
return this.pile.getFloat64(this.haut);
|
||||
}
|
||||
|
||||
peekFloat64() {
|
||||
return this.pile.getFloat64(this.haut-8);
|
||||
}
|
||||
|
||||
setFloat64(index, f) {
|
||||
this.pile.setFloat64(index*4, f);
|
||||
}
|
||||
|
||||
getFloat64(index) {
|
||||
return this.pile.getFloat64(index*4);
|
||||
}
|
||||
|
||||
getMaxSize() {
|
||||
return this.buffer.byteLength/2;
|
||||
}
|
||||
|
||||
getSize() {
|
||||
return this.haut/4;
|
||||
}
|
||||
|
||||
toString() {
|
||||
let out = "[ ";
|
||||
for (let i = 0; i < this.getSize(); i++)
|
||||
out += this.get(i) + ", ";
|
||||
return out + " ] " + this.getSize();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
let p = new Pile();
|
||||
try {
|
||||
let d = 12.34;
|
||||
let i = 0x7FFFFFFF;
|
||||
let j = 0;
|
||||
p.push(i);
|
||||
j = p.peek();
|
||||
console.log(i + " =?= " + j);
|
||||
|
||||
let N = 5;
|
||||
for(let n = 0; n < N; n++) {
|
||||
p.push(n);
|
||||
console.log("push "+n+" " + n);
|
||||
}
|
||||
|
||||
console.log("get(2) " + p.get(2));
|
||||
console.log(p.toString());
|
||||
|
||||
for(let n = N; n > 0; n--) {
|
||||
let m = p.pop();
|
||||
// if (2*n != m)
|
||||
console.log("push "+ n + " pop " + m);
|
||||
}
|
||||
p.pop();
|
||||
|
||||
p.push(40);
|
||||
p.pushFloat64(d);
|
||||
p.pushFloat64(13.34);
|
||||
p.push(i);
|
||||
console.log(p.toString());
|
||||
|
||||
for (let n = 0; n<6;n++)
|
||||
console.log("p.getFloat64("+n+") = "+p.getFloat64(n));
|
||||
|
||||
p.pop();
|
||||
p.popFloat64();
|
||||
let e = p.popFloat64();
|
||||
console.log(d + " =?= " + e);
|
||||
|
||||
|
||||
d = -1;
|
||||
p.pushFloat64(d);
|
||||
e = p.popFloat64();
|
||||
console.log(d + " =?= " + e);
|
||||
//
|
||||
// for (i = 0 ; i < 1000000; i++)
|
||||
// p.push(i);
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
}
|
||||
*/
|
||||
|
||||
|
BIN
1-ComputationAndData/MVaP/MVaP-v0.tgz
Normal file
BIN
1-ComputationAndData/MVaP/MVaP-v0.tgz
Normal file
Binary file not shown.
72
1-ComputationAndData/MVaP/MVaP-v0/MVaP/index.html
Normal file
72
1-ComputationAndData/MVaP/MVaP-v0/MVaP/index.html
Normal file
@@ -0,0 +1,72 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
|
||||
<head>
|
||||
|
||||
<title>MVàP</title>
|
||||
|
||||
<script src="js/Pile.js" type="text/javascript"></script>
|
||||
<script src="js/MVaP.js" type="text/javascript"></script>
|
||||
|
||||
<style type="text/css">
|
||||
body{ color: #333; font: 13px 'Lucida Grande', Verdana, sans-serif; }
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<h1>Machine Virtuelle à Pile</h1>
|
||||
|
||||
<h2>Historique</h2>
|
||||
Blabla sur la MVàP...
|
||||
|
||||
<h2>Documentation</h2>
|
||||
Toute la doc
|
||||
<p>
|
||||
lorem ipsum
|
||||
<h2>La MVàP</h2>
|
||||
<h3>Entrez le code</h3>
|
||||
<div class="runcode">
|
||||
<textarea id="codeMVaP" name="Code MVàP" label="Enter your code" rows="15" cols="33" spellcheck="false">
|
||||
PUSHI 2
|
||||
DUP
|
||||
PUSHI 3
|
||||
ADD
|
||||
PUSHI 4
|
||||
MUL
|
||||
WRITE
|
||||
HALT
|
||||
</textarea>
|
||||
</div>
|
||||
|
||||
<h3>Exécution</h3>
|
||||
<script>
|
||||
var M = "";
|
||||
function runcode() {
|
||||
let text = document.getElementById("codeMVaP").value;
|
||||
let d = document.getElementById("debug").checked;
|
||||
let maxSteps = document.getElementById("MaxSteps").value;
|
||||
if (M == "") M = new MVaP();
|
||||
M.load(text);
|
||||
M.runcode(maxSteps, d);
|
||||
}
|
||||
|
||||
</script>
|
||||
<input type="button" value="Run" onclick="runcode();"/>
|
||||
<label for="MaxSteps">Nombre maximum de pas (O pour pas de limite)</label>
|
||||
<input type="text" id="MaxSteps" name="MaxSteps" value="1000" minLength="4" maxLength="8" size="10"/>
|
||||
<label for="debug">Traces pas à pas</label>
|
||||
<input type="checkbox" id="debug" name="debug" checked />
|
||||
|
||||
|
||||
|
||||
<pre>
|
||||
<input type="button" value="Nettoyer les traces" onclick="traces.innerText='';"/>
|
||||
<div id="traces"></div>
|
||||
</pre>
|
||||
<script>
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
216
1-ComputationAndData/MVaP/MVaP-v0/MVaP/js/CBaP.js
Normal file
216
1-ComputationAndData/MVaP/MVaP-v0/MVaP/js/CBaP.js
Normal file
@@ -0,0 +1,216 @@
|
||||
/**
|
||||
* Code Binaire pour Machine Virtuelle à Pile.
|
||||
* Les flottants sont des double qui prennent la place de 2 ints.
|
||||
* Les adresses sont des int.
|
||||
* CALL empile l'adresse de retour et la vauler du framePointer dans la pile.
|
||||
*/
|
||||
public class CBaP {
|
||||
|
||||
|
||||
|
||||
pc = 0;
|
||||
fp = 0;
|
||||
stack;
|
||||
program;
|
||||
const SizeofDouble = 2;
|
||||
|
||||
_debug = false;
|
||||
|
||||
CBaP(program, debug, stackSize) {
|
||||
this.program = program;
|
||||
this._debug = debug;
|
||||
this.stack = new Pile(stackSize);
|
||||
}
|
||||
|
||||
dumpInstruction(ii, out) {
|
||||
let i = ii;
|
||||
switch(program.get_int(i)) {
|
||||
case AssembleMVaP.ADD: out.print("ADD "); break;
|
||||
case AssembleMVaP.SUB: out.print("SUB "); break;
|
||||
case AssembleMVaP.MUL: out.print("MUL "); break;
|
||||
case AssembleMVaP.DIV: out.print("DIV "); break;
|
||||
case AssembleMVaP.INF: out.print("INF "); break;
|
||||
case AssembleMVaP.INFEQ: out.print("INFEQ "); break;
|
||||
case AssembleMVaP.SUP: out.print("SUP "); break;
|
||||
case AssembleMVaP.SUPEQ: out.print("SUPEQ "); break;
|
||||
case AssembleMVaP.EQUAL: out.print("EQUAL "); break;
|
||||
case AssembleMVaP.NEQ: out.print("NEQ "); break;
|
||||
|
||||
case AssembleMVaP.FADD: out.print("FADD "); break;
|
||||
case AssembleMVaP.FSUB: out.print("FSUB "); break;
|
||||
case AssembleMVaP.FMUL: out.print("FMUL "); break;
|
||||
case AssembleMVaP.FDIV: out.print("FDIV "); break;
|
||||
case AssembleMVaP.FINF: out.print("FINF "); break;
|
||||
case AssembleMVaP.FINFEQ: out.print("FINFEQ"); break;
|
||||
case AssembleMVaP.FSUP: out.print("FSUP "); break;
|
||||
case AssembleMVaP.FSUPEQ: out.print("FSUPEQ"); break;
|
||||
case AssembleMVaP.FEQUAL: out.print("FEQUAL"); break;
|
||||
case AssembleMVaP.FNEQ: out.print("FNEQ "); break;
|
||||
case AssembleMVaP.ITOF: out.print("ITOF "); break;
|
||||
case AssembleMVaP.FTOI: out.print("FTOI "); break;
|
||||
|
||||
case AssembleMVaP.RETURN: out.print("RETURN"); break;
|
||||
case AssembleMVaP.POP: out.print("POP "); break;
|
||||
case AssembleMVaP.READ: out.print("READ "); break;
|
||||
case AssembleMVaP.WRITE: out.print("WRITE "); break;
|
||||
case AssembleMVaP.WRITEF: out.print("WRITEF"); break;
|
||||
case AssembleMVaP.PADD: out.print("PADD "); break;
|
||||
case AssembleMVaP.PUSHGP: out.print("PUSHGP"); break;
|
||||
case AssembleMVaP.PUSHFP: out.print("PUSHFP"); break;
|
||||
case AssembleMVaP.DUP: out.print("DUP "); break;
|
||||
|
||||
case AssembleMVaP.PUSHI: out.print("PUSHI "); out.format("%7d ", program.get_int(++i)); break;
|
||||
case AssembleMVaP.PUSHG: out.print("PUSHG "); out.format("%7d ", program.get_int(++i)); break;
|
||||
case AssembleMVaP.STOREG: out.print("STOREG"); out.format("%7d ", program.get_int(++i)); break;
|
||||
case AssembleMVaP.PUSHL: out.print("PUSHL "); out.format("%7d ", program.get_int(++i)); break;
|
||||
case AssembleMVaP.STOREL: out.print("STOREL"); out.format("%7d ", program.get_int(++i)); break;
|
||||
case AssembleMVaP.PUSHR: out.print("PUSHR "); out.format("%7d ", program.get_int(++i)); break;
|
||||
case AssembleMVaP.STORER: out.print("STORER"); out.format("%7d ", program.get_int(++i)); break;
|
||||
case AssembleMVaP.FREE: out.print("FREE "); out.format("%7d ", program.get_int(++i)); break;
|
||||
case AssembleMVaP.ALLOC: out.print("ALLOC "); out.format("%7d ", program.get_int(++i)); break;
|
||||
|
||||
case AssembleMVaP.PUSHF: out.print("PUSHF "); ++i; out.format("%7.3f ", program.get_double(++i)); break;
|
||||
|
||||
case AssembleMVaP.JUMP: out.print("JUMP "); out.format("%7d ", program.get_int(++i)); break;
|
||||
case AssembleMVaP.JUMPF: out.print("JUMPF "); out.format("%7d ", program.get_int(++i)); break;
|
||||
case AssembleMVaP.JUMPI: out.print("JUMPI "); out.format("%7d ", program.get_int(++i)); break;
|
||||
case AssembleMVaP.CALL: out.print("CALL "); out.format("%7d ", program.get_int(++i)); break;
|
||||
case AssembleMVaP.HALT: out.print("HALT "); break;
|
||||
default: System.err.println("Code inconnu "+program.get_int(i)+" ligne "+i);
|
||||
}
|
||||
if (i == ii) out.print(" ");
|
||||
return i;
|
||||
}
|
||||
|
||||
public void dumpProgram(PrintStream out) {
|
||||
// out.println(program.toString(true));
|
||||
// out.println(program.toString());
|
||||
out.println(" Adr | Instruction");
|
||||
out.println("-----+---------------");
|
||||
for(int i = 0; i < program.getSize(); i++) {
|
||||
out.format("%4d | ", i);
|
||||
i = dumpInstruction(i, out);
|
||||
out.println();
|
||||
}
|
||||
}
|
||||
|
||||
private void _call(int label) {
|
||||
push(pc+1);
|
||||
push(fp);
|
||||
fp = size();
|
||||
pc = label;
|
||||
}
|
||||
|
||||
private void _return() {
|
||||
while(size() > fp)
|
||||
pop();
|
||||
fp = pop();
|
||||
pc = pop();
|
||||
}
|
||||
|
||||
private BufferedReader input = null;
|
||||
private int _read() {
|
||||
try {
|
||||
if (input == null)
|
||||
input = new BufferedReader(new InputStreamReader(System.in));
|
||||
return Integer.parseInt(input.readLine());
|
||||
} catch (Exception e) {
|
||||
System.err.println(e);
|
||||
System.exit(1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean execute() {
|
||||
if (_debug) {
|
||||
dumpProgram(System.out);
|
||||
System.err.println();
|
||||
System.err.println(" pc | | fp pile");
|
||||
System.err.println("====================================================");
|
||||
}
|
||||
pc = 0;
|
||||
while (true) {
|
||||
if (_debug) {
|
||||
System.err.format("%4d | ", pc);
|
||||
dumpInstruction(pc, System.err);
|
||||
System.err.format("| %4d %s\n", fp, stack.toString());
|
||||
}
|
||||
try {
|
||||
int p1, p2; // utile pour être sûr de l'ordre des pop() !
|
||||
double d1, d2;
|
||||
switch(program.get_int(pc++)) {
|
||||
case AssembleMVaP.ADD: p1 = pop(); p2 = pop(); push(p2 + p1); break;
|
||||
case AssembleMVaP.SUB: p1 = pop(); p2 = pop(); push(p2 - p1); break;
|
||||
case AssembleMVaP.MUL: p1 = pop(); p2 = pop(); push(p2 * p1); break;
|
||||
case AssembleMVaP.DIV: p1 = pop(); p2 = pop(); push(p2 / p1); break;
|
||||
case AssembleMVaP.INF: p1 = pop(); p2 = pop(); push(p2 < p1 ? 1 : 0); break;
|
||||
case AssembleMVaP.INFEQ: p1 = pop(); p2 = pop(); push(p2 <= p1 ? 1 : 0); break;
|
||||
case AssembleMVaP.SUP: p1 = pop(); p2 = pop(); push(p2 > p1 ? 1 : 0); break;
|
||||
case AssembleMVaP.SUPEQ: p1 = pop(); p2 = pop(); push(p2 >= p1 ? 1 : 0); break;
|
||||
case AssembleMVaP.EQUAL: p1 = pop(); p2 = pop(); push(p2 == p1 ? 1 : 0); break;
|
||||
case AssembleMVaP.NEQ: p1 = pop(); p2 = pop(); push(p2 != p1 ? 1 : 0); break;
|
||||
|
||||
case AssembleMVaP.FADD: d1 = pop_double(); d2 = pop_double(); push(d2 + d1); break;
|
||||
case AssembleMVaP.FSUB: d1 = pop_double(); d2 = pop_double(); push(d2 - d1); break;
|
||||
case AssembleMVaP.FMUL: d1 = pop_double(); d2 = pop_double(); push(d2 * d1); break;
|
||||
case AssembleMVaP.FDIV: d1 = pop_double(); d2 = pop_double(); push(d2 / d1); break;
|
||||
case AssembleMVaP.FINF: d1 = pop_double(); d2 = pop_double(); push(d2 < d1 ? 1 : 0); break;
|
||||
case AssembleMVaP.FINFEQ: d1 = pop_double(); d2 = pop_double(); push(d2 <= d1 ? 1 : 0); break;
|
||||
case AssembleMVaP.FSUP: d1 = pop_double(); d2 = pop_double(); push(d2 > d1 ? 1 : 0); break;
|
||||
case AssembleMVaP.FSUPEQ: d1 = pop_double(); d2 = pop_double(); push(d2 >= d1 ? 1 : 0); break;
|
||||
case AssembleMVaP.FEQUAL: d1 = pop_double(); d2 = pop_double(); push(d2 == d1 ? 1 : 0); break;
|
||||
case AssembleMVaP.FNEQ: d1 = pop_double(); d2 = pop_double(); push(d2 != d1 ? 1 : 0); break;
|
||||
|
||||
case AssembleMVaP.FTOI: push((int)pop_double()); break;
|
||||
case AssembleMVaP.ITOF: push((double)pop()); break;
|
||||
|
||||
case AssembleMVaP.RETURN: _return(); break;
|
||||
case AssembleMVaP.POP: pop(); break;
|
||||
case AssembleMVaP.READ: push(_read()); break;
|
||||
case AssembleMVaP.WRITE: System.out.format("%7d\n", peek()); break;
|
||||
case AssembleMVaP.WRITEF: System.out.format("%7.3f\n", peek_double()); break;
|
||||
case AssembleMVaP.PADD: p1 = pop(); p2 = pop(); push(p2 + p1); break;
|
||||
case AssembleMVaP.PUSHGP: push(0); break;
|
||||
case AssembleMVaP.PUSHFP: push(fp); break;
|
||||
case AssembleMVaP.DUP: push(peek()); break;
|
||||
|
||||
case AssembleMVaP.PUSHI: push(program.get_int(pc++)); break;
|
||||
case AssembleMVaP.PUSHG: push(get(program.get_int(pc++))); break;
|
||||
case AssembleMVaP.STOREG: set(program.get_int(pc++), pop()); break;
|
||||
// ajouter -2 si adresse négative ?
|
||||
case AssembleMVaP.PUSHL: push(get(fp+program.get_int(pc++))); break;
|
||||
case AssembleMVaP.STOREL:set(fp+program.get_int(pc++), pop()); break;
|
||||
case AssembleMVaP.PUSHR: push(get(pop()+program.get_int(pc++)));break;
|
||||
case AssembleMVaP.STORER:p1 = pop(); p2 = pop(); set(p2+program.get_int(pc++), p1); break;
|
||||
case AssembleMVaP.FREE: doPop(program.get_int(pc++)); break;
|
||||
case AssembleMVaP.ALLOC: doPush(program.get_int(pc++)); break;
|
||||
|
||||
case AssembleMVaP.PUSHF: push(program.get_int(pc++)); push(program.get_int(pc++)); break;
|
||||
|
||||
case AssembleMVaP.JUMP: pc = program.get_int(pc); break;
|
||||
case AssembleMVaP.JUMPF: if (pop() == 0) pc = program.get_int(pc); else pc++; break;
|
||||
case AssembleMVaP.JUMPI: pc = program.get_int(pc)+pop(); break;
|
||||
case AssembleMVaP.CALL: _call(program.get_int(pc)); break;
|
||||
case AssembleMVaP.HALT: return true;
|
||||
default: System.err.println("Code inconnu "+program.get_int(pc)+" ligne "+pc); return false;
|
||||
}
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
System.err.println(stack.getException());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void push(int i) { stack.push(i); }
|
||||
int pop() { return stack.pop_int(); }
|
||||
void push(double d) { stack.push(d); }
|
||||
double pop_double() { return stack.pop_double(); }
|
||||
int peek() { return stack.peek_int(); }
|
||||
double peek_double() { return stack.peek_double(); }
|
||||
int size() { return stack.getSize(); }
|
||||
void set(int index, int i) { stack.set(index, i); }
|
||||
int get(int index) { return stack.get_int(index); }
|
||||
|
||||
void doPop(int nb) { for(; nb > 0; nb--) stack.pop_int(); }
|
||||
void doPush(int nb) { for(; nb > 0; nb--) stack.push(0); }
|
||||
}
|
33
1-ComputationAndData/MVaP/MVaP-v0/MVaP/js/LexerMVaP.dot
Normal file
33
1-ComputationAndData/MVaP/MVaP-v0/MVaP/js/LexerMVaP.dot
Normal file
@@ -0,0 +1,33 @@
|
||||
digraph LexerMVaP {
|
||||
Start -> Start [label="space "];
|
||||
Start -> Id [label="[A-Z]"];
|
||||
Id -> Id [label="[A-Z]"];
|
||||
|
||||
Start -> Int [label="[-+0-9]"];
|
||||
Int -> Int [label="[0-9]"];
|
||||
Int -> Decimal [label="."];
|
||||
Int -> E [label="E"];
|
||||
|
||||
Decimal -> Decimal [label="[0-9]"];
|
||||
Decimal -> E [label="E"];
|
||||
|
||||
E -> Exponent [label="[-+0-9]"];
|
||||
Exponent -> Exponent [label="[0-9]"];
|
||||
|
||||
Start -> error [label="*"];
|
||||
Id -> error [label="*"];
|
||||
Int -> error [label="*"];
|
||||
Decimal -> error [label="*"];
|
||||
E -> error [label="*"];
|
||||
Exponent -> error [label="*"];
|
||||
|
||||
edge [color=red, fontcolor=red];
|
||||
|
||||
Start -> Start [label="NL/[Newline] "];
|
||||
Id -> Start [label="space/ID"];
|
||||
Int -> Start [label="space/Int"];
|
||||
Decimal -> Start [label="space/Float"];
|
||||
Exponent -> Start [label="space/Float"];
|
||||
|
||||
{ rank = same; Decimal E Exponent }
|
||||
}
|
BIN
1-ComputationAndData/MVaP/MVaP-v0/MVaP/js/LexerMVaP.png
Normal file
BIN
1-ComputationAndData/MVaP/MVaP-v0/MVaP/js/LexerMVaP.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 72 KiB |
374
1-ComputationAndData/MVaP/MVaP-v0/MVaP/js/MVaP.js
Normal file
374
1-ComputationAndData/MVaP/MVaP-v0/MVaP/js/MVaP.js
Normal file
@@ -0,0 +1,374 @@
|
||||
// MVàP
|
||||
|
||||
let debugLexer = false;
|
||||
let debug = true;
|
||||
|
||||
/** token lexicaux */
|
||||
const T_ID = 0;
|
||||
const T_INT = 1;
|
||||
const T_FLOAT = 2;
|
||||
const T_SPACE = 3;
|
||||
const T_NL = 4;
|
||||
const T_ERROR = 5;
|
||||
const T_EOF = 6;
|
||||
|
||||
T_Text = [ "T_ID", "T_INT", "T_FLOAT", "T_SPACE", "T_NL", "T_ERROR", "T_EOF" ];
|
||||
|
||||
/** token grammaticaux */
|
||||
const INSTR1 = 0;
|
||||
const INSTR2 = 1;
|
||||
const INT = 2;
|
||||
const INSTR2F = 3;
|
||||
const FLOAT = 4;
|
||||
const LABEL = 5;
|
||||
const JUMP = 6;
|
||||
const NEWLINE = 7;
|
||||
|
||||
class MVaP {
|
||||
|
||||
codes = [ // pour l'interprète de MVàP
|
||||
[ "ADD", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2+p1); } ],
|
||||
[ "SUB", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2-p1); } ],
|
||||
[ "MUL", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2*p1); } ],
|
||||
[ "DIV", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(Math.floor(p2/p1)); } ],
|
||||
[ "INF", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2<p1?1:0); } ],
|
||||
[ "INFEQ", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2<=p1?1:0); } ],
|
||||
[ "SUP", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2>p1?1:0); } ],
|
||||
[ "SUPEQ", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2>=p1?1:0); } ],
|
||||
[ "EQUAL", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2==p1?1:0); } ],
|
||||
[ "NEQ", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2!=p1?1:0); } ],
|
||||
[ "FADD", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.pushFloat64(d2+d1); } ],
|
||||
[ "FSUB", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.pushFloat64(d2-d1); } ],
|
||||
[ "FMUL", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.pushFloat64(d2*d1); } ],
|
||||
[ "FDIV", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.pushFloat64(d2/d1); } ],
|
||||
[ "FINF", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.push(d2<d1?1:0); } ],
|
||||
[ "FINFEQ", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.push(d2<=d1?1:0); } ],
|
||||
[ "FSUP", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.push(d2>d1?1:0); } ],
|
||||
[ "FSUPEQ", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.push(d2>=d1?1:0); } ],
|
||||
[ "FEQUAL", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.push(d2==d1?1:0); } ],
|
||||
[ "FNEQ", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.push(d2!=d1?1:0); } ],
|
||||
[ "ITOF", INSTR1, () => { let p1 = this.stack.pop(); this.trace("ITOF "+p1); this.stack.pushFloat64(p1); } ],
|
||||
[ "FTOI", INSTR1, () => { this.stack.push(Math.round(this.stack.popFloat64())); } ],
|
||||
[ "RETURN", INSTR1, () => { while(this.stack.getSize() > this.fp) this.stack.pop();
|
||||
this.fp = this.stack.pop(); this.pc = this.stack.pop(); } ],
|
||||
[ "POP", INSTR1, () => { this.stack.pop(); } ],
|
||||
[ "READ", INSTR1, () => { this.stack.push(0); } ], // on lit toujours 0 (idée : prendre le contenu d'un input de type text spécial
|
||||
[ "WRITE", INSTR1, () => { this.trace(this.stack.peek()+"\n"); } ],
|
||||
[ "WRITEF", INSTR1, () => { this.trace(this.stack.peekFloat64()+"\n"); } ],
|
||||
[ "PADD", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2+p1); } ],
|
||||
[ "PUSHGP", INSTR1, () => { this.stack.push(0); } ],
|
||||
[ "PUSHFP", INSTR1, () => { this.stack.push(this.fp); } ],
|
||||
[ "DUP", INSTR1, () => { this.stack.push(this.stack.peek()); } ],
|
||||
|
||||
[ "PUSHI", INSTR2, () => { this.stack.push(this.program.get(this.pc++)); } ],
|
||||
[ "PUSHG", INSTR2, () => { this.stack.push(this.stack.get(this.program.get(this.pc++)));} ],
|
||||
[ "STOREG", INSTR2, () => { this.stack.set(this.program.get(this.pc++), this.stack.pop())} ],
|
||||
[ "PUSHL", INSTR2, () => { this.stack.push(this.stack.get(this.fp+this.program.get(this.pc++))); } ],
|
||||
[ "STOREL", INSTR2, () => { this.stack.set(this.fp+this.program.get(this.pc++), this.stack.pop()); } ],
|
||||
[ "PUSHR", INSTR2, () => { this.stack.push(this.stack.get(this.stack.pop()+this.program.get(this.pc++))); } ],
|
||||
[ "STORER", INSTR2, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.set(p2+this.program.get(this.pc++)); } ],
|
||||
[ "FREE", INSTR2, () => { this.stack.doPop(this.program.get(this.pc++)); } ],
|
||||
[ "ALLOC", INSTR2, () => { this.stack.doPush(this.program.get(this.pc++)); } ],
|
||||
[ "PUSHF", INSTR2F, () => { this.stack.pushFloat64(this.program.getFloat64(this.pc)); this.pc += 2; } ],
|
||||
[ "CALL", JUMP, () => { this.stack.push(this.pc+1); this.stack.push(this.fp);
|
||||
this.fp = this.stack.getSize();
|
||||
this.pc = this.program.get(this.pc); } ],
|
||||
[ "JUMP", JUMP, () => { this.pc = this.program.get(this.pc); } ],
|
||||
[ "JUMPF", JUMP, () => { if (this.stack.pop()==0) this.pc = this.program.get(this.pc);
|
||||
else this.pc++; } ],
|
||||
[ "JUMPI", JUMP, () => { this.pc = this.program.get(this.pc)+this.stack.pop();} ],
|
||||
|
||||
[ "HALT", INSTR1, () => { return true; } ],
|
||||
|
||||
[ "LABEL", LABEL, /* erreur interne */ ]
|
||||
];
|
||||
/*** Ajouter instr : READF WRITEF POPF */
|
||||
|
||||
tokens = []; // indexe le tableau codes sur son premier élément
|
||||
|
||||
text = "";
|
||||
|
||||
// <Lexer>
|
||||
// see LexerMVaP.png for the DFA diagram
|
||||
state = "Start";
|
||||
text; // le texte à analyser
|
||||
index = 0; // index dans la chaîne text
|
||||
lineNumber = 1;
|
||||
|
||||
transitions = [
|
||||
{ state: "Start", next: "Start", test: (c) => { return c == "\n"; }, token: T_NL },
|
||||
{ state: "Start", next: "Start", test: (c) => { return c.trim() == ""; }, token: false },
|
||||
{ state: "Start", next: "Id", test: (c) => { return "A" <= c && c <= "Z"; }, token: false },
|
||||
{ state: "Id", next: "Id", test: (c) => { return "A" <= c && c <= "Z"; }, token: false},
|
||||
{ state: "Id", next: "Start", test: (c) => { return c.trim() == ""; }, token: T_ID},
|
||||
{ state: "Start", next: "Int", test: (c) => { return ("0" <= c && c <= "9")||c=="-"||c=="+"; }, token: false },
|
||||
{ state: "Int", next: "Int", test: (c) => { return "0" <= c && c <= "9"; }, token: false },
|
||||
{ state: "Int", next: "Start", test: (c) => { return c.trim() == ""; }, token: T_INT },
|
||||
{ state: "Int", next: "Decimal", test: (c) => { return c == "."; }, token: false },
|
||||
{ state: "Int", next: "E", test: (c) => { return c == "E"; }, token: false },
|
||||
{ state: "Decimal", next: "Decimal", test: (c) => { return "0" <= c && c <= "9"; }, token: false },
|
||||
{ state: "Decimal", next: "E", test: (c) => { return c == "E"; }, token: false },
|
||||
{ state: "Decimal", next: "Start", test: (c) => { return c.trim() == ""; }, token: T_FLOAT },
|
||||
{ state: "E", next: "Exponent", test: (c) => { return ("0"<=c && c<="9")||c=="-"||c=="+"; }, token: false },
|
||||
{ state: "Exponent", next: "Exponent", test: (c) => { return "0" <= c && c <= "9"; }, token: false },
|
||||
{ state: "Exponent", next: "Start", test: (c) => { return c.trim() == ""; }, token: T_FLOAT }
|
||||
// else: error
|
||||
];
|
||||
|
||||
initLexer() {
|
||||
this.index = 0;
|
||||
this.lineNumber = 1
|
||||
console.log("*****************\n* C'est parti *\n*****************");
|
||||
}
|
||||
|
||||
// Donne la transition correspondante à l'état courant et au caractère entrant
|
||||
transition(c) {
|
||||
for (let v of this.transitions.values()) {
|
||||
// on aurait pu indexer les transitions sur state au lieu de tout énumérer
|
||||
if (this.state == v.state && v.test(c)) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
return T_ERROR;
|
||||
}
|
||||
|
||||
yytext = ""; // contient le texte du jeton syntaxique (nommé comme dans lex/yacc)
|
||||
|
||||
|
||||
nextToken() {
|
||||
let c;
|
||||
let trans;
|
||||
while (true) {
|
||||
c = this.text[this.index];
|
||||
if (c === undefined)
|
||||
return T_EOF;
|
||||
c = c.toUpperCase();
|
||||
trans = this.transition(c);
|
||||
if (trans == T_ERROR) { this.yytext += c; return T_ERROR; }
|
||||
if (this.state != trans.next && this.state == "Start") this.yytext ="";
|
||||
|
||||
this.state = trans.next;
|
||||
this.index++;
|
||||
|
||||
if (Number.isInteger(trans.token)) {
|
||||
break;
|
||||
}
|
||||
this.yytext += c;
|
||||
}
|
||||
|
||||
// séparateur significatif
|
||||
if (c == "\n") {
|
||||
if (trans.token != T_NL) {
|
||||
this.index--; // ne pas manger la fin de ligne non prise en compte
|
||||
// une autre façon de dire est que l'on n'incrémente pas l'index sur le renvoi de token
|
||||
// sauf en cas de token constitué de séparateur
|
||||
} else
|
||||
this.lineNumber++; // on en profite pour compter la ligne
|
||||
}
|
||||
// console.log(" line " + this.lineNumber + " " + trans.token + " '" + yytex + "' i="+i);
|
||||
return trans.token;
|
||||
}
|
||||
// </Lexer>
|
||||
|
||||
// <Analyse sémantique et assemblage>
|
||||
|
||||
/** Grammaire des instructions
|
||||
instr
|
||||
: INSTR1 T_NL
|
||||
| INSTR2 T_INT T_NL
|
||||
| JUMP T_INT T_NL
|
||||
| INSTR2F T_FLOAT T_NL
|
||||
| LABEL T_NL
|
||||
| T_NL
|
||||
;
|
||||
*/
|
||||
|
||||
program;// Pile contenant le programme compilé
|
||||
adressesLabels; // adresse des étiquettes pour l'assemblage
|
||||
|
||||
analyse() {
|
||||
|
||||
this.initLexer();
|
||||
|
||||
let token; // le jeton lexical courant
|
||||
let state = NEWLINE; // état de l'analyseur grammatical (ici le précédent syntagme grammatical)
|
||||
this.program = new Pile();
|
||||
this.adressesLabels = [];
|
||||
|
||||
while (true) {
|
||||
this.yytext = "";
|
||||
token = this.nextToken();
|
||||
if (debugLexer)
|
||||
console.log("** nextToken line "+this.lineNumber+" token "+token+" "+T_Text[token]+" '" +this.yytext+"' index "+this.index+" state "+state);
|
||||
|
||||
switch(token) {
|
||||
case T_EOF:
|
||||
return true;
|
||||
case T_ID:
|
||||
let k = this.tokens[this.yytext];
|
||||
if (k === undefined || state != NEWLINE) return false;
|
||||
state = this.codes[k][1];
|
||||
if (state != LABEL) { // pas d'instruction LABEL dans le code
|
||||
this.program.push(k);
|
||||
}
|
||||
break;
|
||||
case T_INT:
|
||||
if (state == LABEL) { // on mémorise juste l'adresse pour la passe d'assemblage
|
||||
this.adressesLabels[Number(this.yytext)] = this.program.getSize(); // ± 1 who knows?
|
||||
} else if(state == INSTR2 || state == JUMP) {
|
||||
this.program.push(Number(this.yytext));
|
||||
} else return false;
|
||||
state = INT;
|
||||
break;
|
||||
case T_FLOAT:
|
||||
if (state != INSTR2F) return false;
|
||||
state = FLOAT;
|
||||
this.program.pushFloat64(Number(this.yytext));
|
||||
break;
|
||||
case T_NL:
|
||||
if (state == INSTR2 || state == JUMP || state == INSTR2F) return false;
|
||||
state = NEWLINE;
|
||||
break;
|
||||
case T_ERROR:
|
||||
return false;
|
||||
default:
|
||||
alert("Erreur interne prévenir la maintenance d'urgence");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
console.log("Programme correct syntaxiquement");
|
||||
return true;
|
||||
}
|
||||
|
||||
assemble() {
|
||||
// change les numéros d'étiquettes par les adresses des instructions pointées.
|
||||
console.log("Label "+this.adressesLabels);
|
||||
console.log(this.dumpProgram());
|
||||
|
||||
for (let i = 0; i < this.program.getSize(); i++) {
|
||||
let k = this.program.get(i);
|
||||
// Attention il faut compter si par malchance un entier = code d'un saut
|
||||
switch (this.codes[k][1]) {
|
||||
case INSTR1:
|
||||
break;
|
||||
case INSTR2:
|
||||
i++; // on saute l'entier qui suit
|
||||
break;
|
||||
case INSTR2F:
|
||||
i += 2; // on saute le flottant qui suit
|
||||
break;
|
||||
case JUMP: // met à jour l'adresse du saut
|
||||
i++;
|
||||
console.log("--- set "+i);
|
||||
this.program.set(i, this.adressesLabels[this.program.get(i)]);
|
||||
break;
|
||||
default:
|
||||
alert("Erreur assemblage");
|
||||
}
|
||||
}
|
||||
// console.log(this.dumpProgram());
|
||||
}
|
||||
// </Analyse sémantique et assemblage>
|
||||
|
||||
|
||||
dumpInstruction(i, result) {
|
||||
let code = this.codes[this.program.get(i)];
|
||||
result += code[0].padEnd(6, ' ');
|
||||
switch (code[1]) {
|
||||
case INSTR2:
|
||||
case JUMP:
|
||||
result += this.program.get(++i).toString().padStart(7, ' ');
|
||||
break;
|
||||
case INSTR2F:
|
||||
result += this.program.getFloat64(++i).toString().padStart(7, ' ');
|
||||
i++;
|
||||
break;
|
||||
default:
|
||||
result += " ";
|
||||
}
|
||||
|
||||
return [i, result];
|
||||
}
|
||||
|
||||
dumpProgram() {
|
||||
let result = "";
|
||||
result += this.program + "\n";
|
||||
|
||||
result += " Adr | Instruction\n-----+---------------\n";
|
||||
for(let i = 0; i < this.program.getSize(); i++) {
|
||||
result += i.toString().padStart(4, " ")+" | ";
|
||||
[i, result] = this.dumpInstruction(i, result);
|
||||
result += "\n";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
// init tokens
|
||||
for (let k of this.codes.keys())
|
||||
this.tokens[this.codes[k][0]] = k;
|
||||
}
|
||||
|
||||
// charge et compile le code
|
||||
load(text) {
|
||||
this.text = text;
|
||||
// on insère une fin de ligne si le texte n'en a pas à sa fin
|
||||
if (text[text.length-1] != "\n") this.text = text+"\n";
|
||||
if (! this.analyse()) {
|
||||
alert("Erreur ligne "+this.lineNumber+" sur '" +this.yytext+"'");
|
||||
return;
|
||||
}
|
||||
this.assemble();
|
||||
}
|
||||
|
||||
pc = 0;
|
||||
fp = 0;
|
||||
stack;
|
||||
|
||||
runcode(maxSteps, d) {
|
||||
debug = d;
|
||||
//for (let i = 0; i < this.codes.length; i++) console.log(i+ " "+ this.codes[i][0]);
|
||||
this.pc = 0;
|
||||
this.fp = 0;
|
||||
this.stack = new Pile();
|
||||
|
||||
try {
|
||||
if (debug)
|
||||
this.trace("Programme\n"+this.dumpProgram() + "\nTraces exécution\n"
|
||||
+ " pc | Instruction | fp pile\n"
|
||||
+ "=====+===============+=============================\n");
|
||||
|
||||
for (let i= 0; i < maxSteps; i++) // while (true)
|
||||
{
|
||||
if (this.pc < 0 || this.pc >= this.program.getSize())
|
||||
break;
|
||||
|
||||
if (debug) {
|
||||
let s = this.pc.toString().padStart(4, " ")+" | ";
|
||||
let junk;
|
||||
[junk, s] = this.dumpInstruction(this.pc, s);
|
||||
s += " |"+this.fp.toString().padStart(4,' ')+' '+this.stack.toString()+"\n";
|
||||
this.trace(s);
|
||||
}
|
||||
|
||||
if (this.codes[this.program.get(this.pc++)][2]() === true)
|
||||
break;
|
||||
}
|
||||
} catch(e) {
|
||||
this.trace(e);
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
trace(s) {
|
||||
traces.innerText += s;
|
||||
console.log(s);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
153
1-ComputationAndData/MVaP/MVaP-v0/MVaP/js/Pile.js
Normal file
153
1-ComputationAndData/MVaP/MVaP-v0/MVaP/js/Pile.js
Normal file
@@ -0,0 +1,153 @@
|
||||
// Class Pile
|
||||
// Auteur : Jacques Madelaine
|
||||
|
||||
// Une Pile est essentiellement une pile d'entiers ("int32")
|
||||
// Elle peut aussi empiler et dépiler des flottants définis sur 64 bits.
|
||||
// L'index est sur les entiers.
|
||||
|
||||
// Rappel : en JavaScript les Number sont tous stockés comme des flottants 64 bits.
|
||||
// Il faut donc voir cette Pile comme un objet pédagogique
|
||||
// et non une implémentation optimale en JavaScipt.
|
||||
|
||||
"use strict";
|
||||
|
||||
class Pile {
|
||||
buffer; // ArrayBuffer de bytes
|
||||
pile; // On va utiliser 4 bytes pour les entiers et 8 pour les flottants
|
||||
haut = 0; // index de sommet de pile en bytes
|
||||
|
||||
// size : taille en bytes de la pile
|
||||
constructor(size) {
|
||||
if (size === undefined)
|
||||
size = 1000;
|
||||
|
||||
this.buffer = new ArrayBuffer(size);
|
||||
this.pile = new DataView(this.buffer);
|
||||
}
|
||||
|
||||
push(i) {
|
||||
if (! Number.isInteger(i))
|
||||
throw new TypeError("Try to push a non integer");
|
||||
this.pile.setInt32(this.haut, i);
|
||||
this.haut += 4;
|
||||
}
|
||||
|
||||
doPush(nb) { for(; nb > 0; nb--) this.push(0); }
|
||||
|
||||
pop() {
|
||||
this.haut -= 4;
|
||||
return this.pile.getInt32(this.haut);
|
||||
}
|
||||
|
||||
doPop(nb) { for(; nb > 0; nb--) this.pop(); }
|
||||
|
||||
peek() {
|
||||
return this.pile.getInt32(this.haut-4);
|
||||
}
|
||||
|
||||
set(index, i) {
|
||||
if (! Number.isInteger(i))
|
||||
throw new TypeError("Try to set a non integer");
|
||||
this.pile.setInt32(index*4, i);
|
||||
}
|
||||
|
||||
get(index) {
|
||||
return this.pile.getInt32(index*4);
|
||||
}
|
||||
|
||||
|
||||
pushFloat64(f) {
|
||||
this.pile.setFloat64(this.haut, f);
|
||||
this.haut += 8;
|
||||
}
|
||||
|
||||
popFloat64() {
|
||||
this.haut -= 8;
|
||||
return this.pile.getFloat64(this.haut);
|
||||
}
|
||||
|
||||
peekFloat64() {
|
||||
return this.pile.getFloat64(this.haut-8);
|
||||
}
|
||||
|
||||
setFloat64(index, f) {
|
||||
this.pile.setFloat64(index*4, f);
|
||||
}
|
||||
|
||||
getFloat64(index) {
|
||||
return this.pile.getFloat64(index*4);
|
||||
}
|
||||
|
||||
getMaxSize() {
|
||||
return this.buffer.byteLength/2;
|
||||
}
|
||||
|
||||
getSize() {
|
||||
return this.haut/4;
|
||||
}
|
||||
|
||||
toString() {
|
||||
let out = "[ ";
|
||||
for (let i = 0; i < this.getSize(); i++)
|
||||
out += this.get(i) + ", ";
|
||||
return out + " ] " + this.getSize();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
let p = new Pile();
|
||||
try {
|
||||
let d = 12.34;
|
||||
let i = 0x7FFFFFFF;
|
||||
let j = 0;
|
||||
p.push(i);
|
||||
j = p.peek();
|
||||
console.log(i + " =?= " + j);
|
||||
|
||||
let N = 5;
|
||||
for(let n = 0; n < N; n++) {
|
||||
p.push(n);
|
||||
console.log("push "+n+" " + n);
|
||||
}
|
||||
|
||||
console.log("get(2) " + p.get(2));
|
||||
console.log(p.toString());
|
||||
|
||||
for(let n = N; n > 0; n--) {
|
||||
let m = p.pop();
|
||||
// if (2*n != m)
|
||||
console.log("push "+ n + " pop " + m);
|
||||
}
|
||||
p.pop();
|
||||
|
||||
p.push(40);
|
||||
p.pushFloat64(d);
|
||||
p.pushFloat64(13.34);
|
||||
p.push(i);
|
||||
console.log(p.toString());
|
||||
|
||||
for (let n = 0; n<6;n++)
|
||||
console.log("p.getFloat64("+n+") = "+p.getFloat64(n));
|
||||
|
||||
p.pop();
|
||||
p.popFloat64();
|
||||
let e = p.popFloat64();
|
||||
console.log(d + " =?= " + e);
|
||||
|
||||
|
||||
d = -1;
|
||||
p.pushFloat64(d);
|
||||
e = p.popFloat64();
|
||||
console.log(d + " =?= " + e);
|
||||
//
|
||||
// for (i = 0 ; i < 1000000; i++)
|
||||
// p.push(i);
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
}
|
||||
*/
|
||||
|
||||
|
BIN
1-ComputationAndData/MVaP/MVaP.jar
Normal file
BIN
1-ComputationAndData/MVaP/MVaP.jar
Normal file
Binary file not shown.
7
1-ComputationAndData/MVaP/add.mvap
Normal file
7
1-ComputationAndData/MVaP/add.mvap
Normal file
@@ -0,0 +1,7 @@
|
||||
# calcule : 2 + 40
|
||||
PUSHI 2
|
||||
PUSHI 40
|
||||
ADD
|
||||
WRITE
|
||||
POP
|
||||
HALT
|
BIN
1-ComputationAndData/MVaP/antlr-4.5.2-complete.jar
Normal file
BIN
1-ComputationAndData/MVaP/antlr-4.5.2-complete.jar
Normal file
Binary file not shown.
27
1-ComputationAndData/MVaP/test.mvap
Normal file
27
1-ComputationAndData/MVaP/test.mvap
Normal file
@@ -0,0 +1,27 @@
|
||||
# On prend au départ 2
|
||||
# on ajoute 3 et on élève le tout au carré
|
||||
# on recommence et on s'arrête dès que l'on dépasse 100
|
||||
PUSHI 2
|
||||
LABEL 1
|
||||
PUSHI 3
|
||||
ADD
|
||||
WRITE
|
||||
CALL 2
|
||||
WRITE
|
||||
# a-t-on un sommet de pile < 100 ?
|
||||
DUP
|
||||
PUSHI 100
|
||||
SUP
|
||||
JUMPF 1
|
||||
# le nombre affiché est plus grand que 100, on s'arrête
|
||||
HALT
|
||||
# procédure qui élève un nombre au carré
|
||||
LABEL 2
|
||||
# récupère le premier paramètre (-3 = -1 - 2)
|
||||
PUSHL -3
|
||||
DUP
|
||||
MUL
|
||||
# on a donc son carré en sommet de pile
|
||||
STOREL -3
|
||||
# on remplace la valeur
|
||||
RETURN
|
Reference in New Issue
Block a user