Projet assembleur

publicité
Projet 2011
Architecture des ordinateurs
DEMI2E – Semestre 1
Machine à pile
Réalisé par :
Sok Daline
Lien William
SOMMAIRE
I. INTRODUCTION .......................................................... 1
II. ASSEMBLEUR........................................................1 - 3
A.
ORGANISATION DES DONNEES DANS LE PROGRAMME ................................................. 1
B.
CHARGEMENT ET VERIFICATION DU FICHIER ............................................................... 2
C.
CREATION DU FICHIER LANGAGE MACHINE ................................................................. 3
III. SIMULATEUR .........................................................4 - 5
A.
IMPLEMENTATION GENERALE ................................................................................... 4
B.
CHARGEMENT DES INSTRUCTIONS ............................................................................ 4
C.
EXECUTION DES INSTRUCTIONS ................................................................................ 5
IV. CODE ................................................................... 6 - 24
A.
ASSEMBLEUR ........................................................................................................ 6
B.
SIMULATEUR ....................................................................................................... 17
C.
EXEMPLE D’EXECUTION ......................................................................................... 22
I.
Introduction
L’utilisateur doit écrire un programme en assembleur dans un fichier texte nommé «
Assembleur.txt » et le mettre dans le même dossier que les programmes.
Le programme doit respecter les règles suivantes :
 Le programme ne doit comporter que les instructions suivantes : push, push#, ipush, pop, ipop, read,
write, op, dup, jmp, jpc, call, ret, rnd, et halt. Il ne faut pas dépasser 3000 instructions par fichier.
 Chaque ligne ne doit comporter qu’une seule instruction. Les instructions ne sont pas sensibles à la
casse.
 Il ne faut pas sauter de ligne entre deux instructions.
 Si une ligne commence par une étiquette, ceci doit se terminer par ‘:’. De plus, chaque étiquette est
sensible à la casse.
 Il faut respecter l’orthographe, la syntaxe et le nombre de donnée de chaque instruction. Il faut
mettre un espace entre les instructions et les données. Par exemple : « ins donnée » alors que «
insdonnée » n’est pas correcte.
 Le programme se termine par l’instruction « halt ». Il ne faut pas aller à la ligne après la dernière
instruction.
II. Assembleur
Le but de ce programme est de transformer un fichier écrit en assembleur (assembleur.txt) en un
programme écrit en langage machine (fichier binaire.txt).
Instructions
assembleur
A.
Assembleur
Simulation
Organisation des données dans le programme
Nous avons crée une structure de l’instruction qui permettra un contrôle et une utilisation
simplifiée pour la traduction du fichier assembleur.
struct Instruction {
char *nomIns;
unsigned short codeOpe;
unsigned short nbrDonnee;
int donnee;
char *donneeEnChaine;
char *etiq;
};
/*le nom de l'instruction*/
/*code d'opération*/
/*le nombre de donnée de l'instruction*/
/*valeur de la donnée*/
/*valeur de la donnée en chaine de caractère*/
/*étiquette de l'instruction s'il y en a*/
1
B.
Chargement et vérification du fichier
Tout d’abord, on récupère un fichier texte dans lequel est écrit un programme en assembleur.
Si le fichier n’est pas trouvé ou si la dernière ligne du fichier ne se termine pas par « halt », le programme
se finit. Sinon, on traite le fichier ligne par ligne. Pour ce faire, nous avons stocké chaque ligne d’instruction
dans une structure qui est elle-même « stockée » par un tableau de structure à portée globale. Puis, durant
le remplissage du tableau de structure « instruction » on vérifie si chaque ligne est écrite correctement. Si
la ligne n’est pas correcte, un message d’erreur sera affiché avec la ligne d’erreur et le programme
s’arrêtera.
La vérification de chaque ligne se fera de la manière suivante :
Traitement du texte brut
• On traite ligne par ligne le fichier assembleur contenant les instructions
Traitement des étiquettes
• On teste la présence de l’étiquette par la fonction "presenceetiq " et on sauvegarde la position du
“ : ” si l’étiquette est présente dans la variable pos. Si une ligne commence par ":" la fonction
renvoie -2, car il y a une erreur d'étiquetage. Et s'il n'y a pas d'étiquette la fonction renvoie -1.
• On stocke l’étiquette grâce à la fonction “stockageetiq". En effet, "stockageetiq" ne stocke que le
nom de l'étiquette dans un tableau etiq en sautant tous les espaces. Pour ce faire, on récupère la
position du ":" grâce à la fonction "presenceetiq". Si "presenceetiq" renvoie une valeur négative
c'est qu'il y a une erreur donc on ne stocke pas l'étiquette. Si la fonction renvoie une valeur
positive alors on avance tant qu'il y a des espaces ou des tabulations. Dès que l'on trouve un
caractère différent de l'espace ou de tabulation, on teste si ce caractère est un ":" si c'en est un on
renvoie -1 car ce n'est pas bon puisqu'une étiquette ne peut pas commencer par ":". Sinon, on part
de la positon du ":" et on enlève tous les espaces avant le ":" afin de récupérer que le nom de
l'étiquette. Pour récupérer le nom on fait une boucle for qui remplit le tableau etiq caractère par
caractère.
Formalisation de la ligne
• On formalise la ligne pour un traitement uniforme et plus simple, en effet chaque ligne sera de la
forme suivante: etiquette+espace+':'+espace+instruction+espace+donnée. Pour cela on utilise la
fonction supBlanc. Cette formalisation permet de connaître exactement la position de chaque
élément de la ligne.
• La fonction « supBlanc » regroupe tous les espaces en un seul. En effet, on fait une boucle sur la
chaine, on teste si un caractère de la chaine est un espace. Si c’est diffèrent, on sauvegarde le
caractère dans une chaine auxiliaire. Sinon, on avance tant que c’est un espace. Ensuite, on
sauvegarde le caractère.
• On récupère la nouvelle position des ':' pour mettre en minuscule seulement les instructions car
les étiquettes et les données sont sensibles à la casse. Afin de mettre les instructions en minuscule
on utilise la fonction « str_tolower ». Cette fonction parcourt chaque caractère de la chaine, si la
position du caractère en cours est inférieure à la position de ‘:’ (pos) ou que le booléen est à 0 alors
on met le caractère en minuscule. Lorsque la position du caractère est supérieure à la position de
(pos+ 1) alors on test si celui ci est un espace, si c’est le cas on mets le booléen à 1. Concrètement,
si le booléen est à 1 cela indique que les caractères qu’on va lire représentent la donnée qui est
sensible à la casse et donc on sauvegarde le caractère sans modification.
2
Traitement des instructions
• On sépare chaque ligne les instructions des données par la fonction “separationLigne”. Le nom de
l’instruction sera stocké dans la structure "instruction" sur le pointeur "nomIns" et les données le
seront sur le pointeur "donneEnChaine". Pour ce faire, on part de pos+1, autrement dit un
caractère après la position du “ :”, on avance tant qu’il y a des espaces ou des tabulation. Si, c’est
une ligne vide un message d’erreur sera affiché et le programme s’arrêtera. Si la ligne n’est pas vide,
on appelle à la fonction « testeEspace » qui teste si un caractère est un espace, tabulation, retour à
la ligne, ou le caractère 0. Tant que cette fonction renvoie 0 on stocke chaque caractère dans tab
instruction. Quand on a terminé avec les instructions on refait les même tests pour les données. Si
tout va bien on stocke les données dans le tableau donnee et on renvoie le nombre données lues.
• On vérifie si les instructions et les données sont entrées de manière correcte avec la fonction
“testIns_Don”. On traite tous les cas possibles avec des sous-fonctions. C'est à dire s'il n'y a pas
d'erreur de syntaxe. S’il y a une erreur un message d’erreur sera affiché et le programme s’arrête. De
plus, on teste également les données de l’instruction, c’est à dire si le nombre des données est bien
respecté pour l’instruction correspondante, si le type des données est correcte et ainsi de suite.
• Si la fonction “testIns_Don” ne renvoie pas -1, on stocke les informations de l’instruction (nomIns,
codeOpe, nbrDonnee, etiq, donneeEnChaine, donnee) dans la structure.
Vérification générale
• Problème doublage d’étiquette : on vérifie qu'il n’y a pas de doublon d’étiquette (des étiquettes qui
ont le même nom) grâce à la fonction “doublonEtiq”. S’il y en a une, un message d’erreur sera affiché
et le programme s’arrêtera.
• Vérification de « halt ». En effet, si le fichier assembleur n’a pas de « halt » un message d’erreur sera
affiché et le programme s’arrêtera.
• Problème d’appel d’étiquette : On teste si les l’appel des instructions “call”, “jmp”, “jpc” existent
bien(c'est à dire qu'ils font référence à une étiquette existante) grâce à la fonction “occurEtiqAvant”.
S ‘il n’existe pas un message d’erreur sera affiché et le programme s’arrêtera.
C.
Création du fichier langage machine
Franchit l’étape de vérification de syntaxe du fichier assembleur, un message indiquera que la
syntaxe du fichier d’assembleur est correct que le programme va procéder à la traduction vers le langage
machine :
On crée un fichier « fichier binaire.txt », qu’on écrit ligne par ligne les codes opération et les données de
chaque instruction en langage machine.
Affichage du résultat.
Fermeture du programme.
3
III. Simulateur
Le but de ce deuxième programme est de simuler une machine fictive capable de comprendre et
d’exécuter les instructions que l’on a précédemment traduites.
Instructions
assembleur
A.
Assembleur
Simulation
Implémentation générale
A la sortie de l’assembleur, le fichier binaire que l’on doit exécuter est supposé correct (il n’y a pas
d’instructions illégales contenu dans le fichier en code binaire texte) en effet s’il y en avait eu une,
l’assembleur l’aurais signalé.
Vérification
présence du fichier
d'instruction
Chargement
des
instructions
Exécution
des
instructions
Fin de la
simulation
La machine que l’on doit simuler comporte une mémoire de 2000 cases pouvant contenir 4 octets
chacun. Nous avons choisi de la représenté par un tableau à portée globale de int d’une taille de 2000, le
pointeur SP sera ici simuler par un int globale indiquant les indices correspondant dans le tableau.
Le pointeur PC sera aussi simulé par une variable globale int indiquant l’indice de la prochaine
instruction à exécuter.
De plus le processeur que l’on doit simuler doit exécuter une multitude d’instructions différentes.
C’est pour cela que nous avons opté pour une « boucle infinie » complété d’un switch afin de sélectionner
directement la bonne fonction à exécuter.
B.
Chargement des instructions
Pour que notre machine comprenne les instructions à exécuter nous avons tout d’abord chargé nos
instructions du fichier texte dans un tableau nommé “Instruction” qui est un tableau de structure
instructions.
De la même façon que le précédent programme nous avons utilisé une structure avec un tableau à
Vérification
présence du fichier
d'instruction
Chargement
des
instructions
Exécution
des
instructions
portée globale afin de charger les instructions du fichier texte.
4
Fin de la
simulation
struct Instruction{
unsigned char codeIns;
int donnee;
};
C.
/*code instruction*/
/*donnée instruction*/
Exécution des instructions
Vérification
présence du fichier
d'instruction
Chargement
des
instructions
Exécution
des
instructions
Fin de la
simulation
Pour exécuter les instructions contenues dans le tableau de structure on se sert d’une boucle infinie
avec PC qui sert à indiquer la prochaine instruction à exécuter (i.e. : ici il sert « d’indice » sur le tableau
d’instruction).
Ensuite, le switch sélectionne la bonne instruction à exécuter et on incrémente PC. Le programme
répète la même boucle jusqu'à rencontre de l’instruction halt qui ici, le fait sortir de la boucle et par
conséquent termine le programme.
Points important :
 Dans la fonction read il y a « while ((c = getchar ()) != '\n' && c != EOF); » cette ligne permet de
sécurisé le scanf si l’utilisateur rentre plus de chose au clavier.
 Dans la fonction op nous avons choisi la structure de contrôle switch car elle est l’instruction de
contrôle la mieux adapté.
 Pour rnd, “srand((unsigned)time(NULL));” permet de rendre le résultat de rand plus aléatoire.
5
IV. Code
A.
#include
#include
#include
#include
#define
#define
#define
#define
#define
Assembleur
<stdio.h>
<stdlib.h>
<string.h>
<ctype.h>
TAILLE_MAX 3000
tailleMax 3000
nombreInstruction 3000 /* le nombre d'instruction qu'on a*/
nombreMaxDonnee 1 /* le nombre de donnée maxi par instruction */
longueurMaxDonnee 3000 /* longueur maxi d'une donnée */
/*******************************************************************************************/
/*PROTOTYPE DES FONCTIONS*/
int testEspace(char c);
/* teste si le caractere est un espace, tabulation, retour chariot ou 0 */
/* renvoie 1 dans ce cas, 0 sinon */
int separationLigne(char *ligne, char *instruction, char *donnee, short numLigne, int pos);
/*(char ligne[],char instruction[],char donnee[],short numLigne,int pos(la position de ':'de
l'etiquette*/
/*separe chaque ligne les instrustions des donnees*/
/* on sauvegarde l'instruction dans le tab de chaine instruction et les donnee dans le
tab de chaine donnee*/
/*revoie le nombre de donnees lues, il y en a nombreMaxDonnee au max*/
int testLettre(char *s);
/*Teste si une chaine ne presente que des caractere*/
/*Renvoie un si c'est le cas 0 sinon*/
int presenceetiq(char* p);
/*cherche s'il y a une étiquette*/
/*s'il y en a revoie la position du ':' vu qu'une étiquette se termine par ':'*/
/*revoie -2 la chaine commence par ':',-1 s'il n'y a pas d'étiquette*/
int stockageetiq(char* ligne, char* etiq, int pos);
/*stockage des étiquette*/
/*pos est la position de ':' de l'étiquette*/
/*return 0 si tout va bien,-1 sinon*/
int doublonEtiq(void);
/*teste si il y a plusieurs etiquettes identiques*/
/*renvoie la position du doublon et affiche un message d'erreur*/
/*renvoie 0 sinon*/
char* supBlanc(char* ch);
char* Ent2Char(int Nb);
/*transforme un entier en une chaine de caractère*/
long Char2Ent(char* Nb);
/*transforme une chaine de caractère en entier*/
/*met un '-'devant si le nombre est négatif*/
6
int occurEtiqAvant(char* s);
/*la chaine s est l'appel de l'etiquette*/
/*cette fonction teste si l'appel de l'etiquette(s)existe bien*/
/*renvoie 1 s'il existe bien, 0 sinon*/
int onlyChr(const char* p);
/* renvoi 1 si la chaine ne contient que des chiffres 0 sinon */
char *str_tolower (const char *ct,int pos);
/*transfome une chaine de caractere en minuscule*/
void liberationMemoire(void);
int testIns_Don(char *instruction, char donnee[], short nbrdonnee, short numLigne);
/*retourne le numero code de l'instruction si elle est bien tapee,
* sinon retourne -1 si instruction est mal tapee ou donnee erronee
* char* instruction(respc. donnee) etant la chaine contenant l'instruction(respec. donnee),
* nbrdonne : nombre de donnee
*/
/*FIN PROTOTYPES DES FONCTIONS*/
**********************************************************************************************
**********************************************************************************************
STRUCTURE
définition de la structure de l'instruction qui permettra un contrôle simplifié
**********************************************************************************************
struct Instruction{
char *nomIns;
unsigned short codeOpe;
unsigned short nbrDonnee;
int donnee;
char* donneeEnChaine;
char* etiq;
/* le nom de l'instruction*/
/*code d'operation*/
/*le nombre de donnee de l'instruction */
/*valeur de la donnee*/
/*valeur de la donnee en chaine de caractere*/
/*etiquette de l'instruction s'il y en a*/
};
struct Instruction tab[nombreInstruction];
int indiceSaut[nombreInstruction];
int indiceSaut2[nombreInstruction];
int sommetVerif = 0;
int sommetEtiq = 0;
int sommetTab = 0;
d'instruction */
/*Situe le dernier element inserer dans le tableau indiceSaut2 */
/* Situe le dernier element inserer dans ce tableau */
/* Situe ou se positionne le dernier element stocker dans tableau
/**********************************************************************************************/
/*CODE*/
int testEspace(char c){
/* teste si le caractere est un espace, tabulation, retour chariot ou 0
* renvoie 1 dans ce cas, 0 sinon
*/
return (((c==' ') || (c=='\t') || (c=='\n') || !c) ? 1 : 0);
}
int separationLigne(char *ligne, char *instruction, char *donnee, short numLigne, int pos){
/*(char ligne[],char instruction[],char donnee[],short numLigne,int pos(la position de ':'de
7
l'etiquette*/
/*separe chaque ligne les instrustions des donnees*/
/* on sauvegarde l'instruction dans le tab de chaine instruction et les donnee dans le
tab de chaine donnee*/
/*revoie le nombre de donnees lues, il y en a nombreMaxDonnee au max*/
int caractereNext = pos+1 ;
int i = 0;
int d = 0;/*le nombre des données*/
instruction[0]='\0';
donnee[0] = '\0';
while((ligne[caractereNext]==' ')||(ligne[caractereNext]=='\t')){
caractereNext++; /*on avance tant qu'il y a de l'espace afin de prendre que
l'instruction*/
}
if((ligne[caractereNext]=='\n')||(ligne [caractereNext]=='\0')){
printf("Erreur ligne %d instruction mal taper",numLigne);
return -1;/*ligne vide,pas d'instruction donc on returne -1*/
}
while(!testEspace(ligne[caractereNext])){
instruction[i]=ligne[caractereNext];/* on stock chaque caractere dans tab instruction*/
i++;
caractereNext++;
}
instruction[i]='\0';/* pour la fin de chaine*/
while((ligne[caractereNext]==' ')|| ligne[caractereNext]=='\t' ){
caractereNext++;
}
if((ligne[caractereNext]=='\n')||(ligne [caractereNext]=='\0')){
return 0;/*ligne vide,pas de donnee donc on returne 0*/
}/*on finit avec les instruction on regarde les donnees maintenant*/
else{
i = 0;
while((!testEspace(ligne[caractereNext]))){
donnee[i++] = ligne[caractereNext++];
donnee[i] = '\0';
}
d++;
}
while ((ligne[caractereNext] == ' ') || (ligne[caractereNext] == '\t'))
caractereNext++;
if (!testEspace(ligne[caractereNext]))
d++;
return d;
}
int testLettre(char *s){
/*Teste si une chaine ne presente que des caractere*/
/*Renvoie un si c'est le cas 0 sinon*/
unsigned int i = 0;
for(i=0; i<strlen(s) ; i++){
if(*(s+i) >= 'a' && *(s+i) <= 'z'){
return 1;
}else{ if(*(s+i) >= 'A' && *(s+i) <= 'Z')
return 1;
8
}
}
return 0;
}
int presenceetiq(char* p){
/*cherche s'il y a une etiquette*/
/*s'il y en a revoie la position du ':' vu qu'une etiquette se termine par ':'*/
/*revoie -2 la chaine commence par ':',-1 s'il n'y a pas d'etiquette*/
unsigned int i;
if(*p == ':'){
return -2;
}
for(i=1 ; i<strlen(p) ; i++){
if(*(p+i) == ':')
return i;
}
return -1;
}
int stockageetiq(char* ligne, char* etiq, int pos){
/*stockage des etiquette*/
/*pos est la position de ':' de l'etiquette*/
/*return 0 si tout va bien,-1 sinon*/
int i=0;
int j=pos-1;
int k=0,l=0;
if(pos>0)
{
while((ligne[i]==' ')||(ligne[i]=='\t')){
i++;
}
if(ligne[i]==':'){/*si il n'y a que ':' ce n'est bon donc on returne -1*/
return -1;
}
while((ligne[j]==' ')||(ligne[j]=='\t')){/*une fois trouvé la position du ':'on enleve tous
les espaces avant du ':'*/
j--;
}
for(k=i;k<=j;k++){
if((ligne[k]==' ')||(ligne[k]=='\t')){
return -1;
}else{
etiq[l]=ligne[i];
i++;
l++;
}
}
etiq[l]='\0';
if(onlyChr(etiq)==1)/*si la chaine ne presente que des chiffres on renvoie -1*/
return -1;
}
return 0;
}
int doublonEtiq(void){
/*teste si il y a plusieurs etiquettes identiques*/
/*renvoie la position du doublon et affiche un message d'erreur*/
/*renvoie 0 sinon*/
/* sommetTab Situe où se positionne le dernier element stocké dans tableau d'instruction */
9
/*tab est le tableau d'instruction de type instruction*/
int i = 0;
int j = 0;
for(i=0 ; i<sommetTab ; i++){
if(strcmp(tab[i].etiq, "") == 0) continue;
for(j=i+1 ; j<sommetTab ; j++){
if(strcmp(tab[i].etiq, tab[j].etiq) == 0){
printf("ATTENTION ETIQUETTE UTILISEE PLUSIEURS FOIS LIGNE %d\n", j);
return j;
}
}
}
return 0;
}
char* supBlanc(char* ch){
char* inter = (char*)malloc(strlen(ch)+1), *set, *aux;
aux = inter;
while(*ch){
if(*ch!=' ')
*aux++=*ch++;
else{
while(*(ch+1)==' '&& (*ch))
ch++;
*aux++ = *ch++;
}
}
*aux = 0;
set = strdup(inter);
free(inter);
return set;
}
char* Ent2Char(int Nb){
char t[100];
char *res;
int i=0, j=0, n=0;
if(Nb<0)
{
Nb=-Nb;
n=1;
}
if(Nb > 0){
while(Nb!=0){
t[i++] = Nb%10+'0';
Nb/=10;
}
}else{
t[i++] = '0';
}
t[i] = 0;
res = (char *)malloc(i+2);
if(n)res[j++]='-';
i--;
while(i>=0){
res[j++] = t[i--];
}
res[j] = 0;
return res;
}
10
long Char2Ent(char* Nb){
long n = 0;
unsigned i;
for(i=0; i<strlen(Nb); i++){
if(Nb[i] >= '0' && Nb[i] <= '9')
n = n*10 + Nb[i] - '0';
}
return (Nb[0] == '-')? -n : n;
}
int occurEtiqAvant(char* s){
/*la chaine s est l'appel de l'etiquette
cette fonction teste si l'appel de l'etiquette(s)existe bien
renvoie 1 s'il existe bien, 0 sinon
sommetTab Situe où se positionne le dernier element stocké dans tableau d'instruction
tab est le tableau d'instruction*/
int i;
for(i=0 ; i<sommetTab ; i++)
if(strcmp(s, tab[i].etiq) == 0)
return 1;
return 0;
}
int onlyChr(const char* p){
/* renvoi 1 si la chaine ne contient que des chiffres 0 sinon */
unsigned int i = 0;
for(i=0 ; i<strlen(p) ; i++){
if(i==0 && *p == '-') continue;
if(*(p+i) < '0' || *(p+i) > '9')
return 0;
}
return 1;
}
char *str_tolower (const char *ct, int pos){
char *s = NULL;
int test = 0;
if (ct){
int i;
s = malloc (sizeof (*s) * (strlen (ct) + 1));
if (s){
for (i = 0; ct[i]; i++){
if(i > pos+1)
if(ct[i] == ' ')
test = 1;
if(i<pos || test == 0)
s[i] = tolower (ct[i]);
else
s[i] = ct[i];
}
s[i] = '\0';
}
}
return s;
}
11
int testIns_Don(char *instruction, char donnee[], short nbrdonnee, short numLigne){
/* retourne le numero code de l'instruction si elle est bien tapee,
sinon retourne -1 si instruction est mal tapee ou donnee erronee
char* instruction(respc. donnee) etant la chaine contenant l'instruction(respec. donnee),
nbrdonne : nombre de donnee*/
int val = 0;
char* auxTest = NULL;
if(strcmp(instruction, "push")==0){
val = Char2Ent(donnee);
auxTest = Ent2Char(val);
if(val < 0 || val > 2000 || strcmp(auxTest, donnee) != 0 || nbrdonnee != 1){
printf("ERREUR donnee de l'instruction push mal saisite ligne %d\n", numLigne);
return -1;
}
printf("Instruction push bien enregistree ligne %d avec donnee %s\n", numLigne, donnee);
return 0;
}
if(strcmp(instruction, "push#")==0){
if(nbrdonnee != 1){
printf("ERREUR donnee de l'instruction push# mal saisite ligne %d\n", numLigne);
return -1;
}
printf("Instruction push# bien enregistree ligne %d avec donnee %s\n", numLigne, donnee);
return 1;
}
else if(strcmp(instruction, "ipush")==0){
if(nbrdonnee != 0){
printf("ERREUR iPush a une donnee ligne %d\n", numLigne);
return -1;
}
printf("Instruction iPush bien enregistree ligne %d\n", numLigne);
return 2;
}
else if(strcmp(instruction, "pop")==0){
val = Char2Ent(donnee);
auxTest = Ent2Char(val);
if(nbrdonnee != 1 || strcmp(donnee, auxTest) != 0 || val < 0 || val > 2000){
printf("ERREUR pop a une donnee erronee ligne %d\n", numLigne);
return -1;
}
printf("Instruction pop bien enregistree ligne %d avec donnee %d\n", numLigne, val);
return 3;
}
else if(strcmp(instruction, "ipop")==0){
if(nbrdonnee != 0){
printf("ERREUR iPop a une donnee ligne %d\n", numLigne);
return -1;
}
printf("Instruction iPop bien enregistree ligne %d\n", numLigne);
return 4;
}
else if(strcmp(instruction, "read")==0){
val = Char2Ent(donnee);
auxTest = Ent2Char(val);
if(nbrdonnee != 1 || strcmp(donnee, auxTest) != 0 || val < 0 || val > 2000){
printf("ERREUR read a une donnee erronee ligne %d\n", numLigne);
return -1;
}
12
if(testLettre(donnee)){
printf("ERREUR read a une valeur erronee ligne %d\n", numLigne);
return -1;
}
printf("Instruction read bien enregistree ligne %d avec donnee %s\n", numLigne, donnee);
return 5;
}
else if(strcmp(instruction, "write")==0){
val = Char2Ent(donnee);
auxTest = Ent2Char(val);
if(nbrdonnee != 1 || strcmp(donnee, auxTest) != 0 || val < 0 || val > 2000){
printf("ERREUR write a une donnee erronee ligne %d\n", numLigne);
return -1;
}
printf("Instruction write bien enregistree ligne %d avec donnee %s\n", numLigne, donnee);
return 6;
}
else if(strcmp(instruction, "op")==0){
val = Char2Ent(donnee);
auxTest = Ent2Char(val);
if(nbrdonnee != 1 || strcmp(donnee, auxTest) != 0 || val < 0 || val > 15){
printf("ERREUR op a une donnee erronee ligne %d\n", numLigne);
return -1;
}
printf("Instruction op bien enregistree ligne %d avec operation numero %d\n", numLigne,
val);
return 7;
}
else if(strcmp(instruction, "dup")==0){
if(nbrdonnee != 0){
printf("ERREUR dup a une donnee ligne %d\n", numLigne);
return -1;
}
printf("Instruction dup bien enregistree ligne %d\n", numLigne);
return 8;
}
else if(strcmp(instruction, "jmp")==0){
val = Char2Ent(donnee);
auxTest = Ent2Char(val);
if((strcmp(auxTest, donnee) != 0 || nbrdonnee != 1) && onlyChr(donnee)){
printf("ERREUR jmp a une donnee mal saisie ligne %d avec donnee %d\n", numLigne,
val);
return -1;
}
if(!onlyChr(donnee))
indiceSaut[sommetEtiq++] = numLigne;
else
indiceSaut2[sommetVerif++] = numLigne;
printf("Instruction jmp bien enregistree ligne %d\n", numLigne);
return 9;
}
else if(strcmp(instruction, "jpc")==0){
val = Char2Ent(donnee);
auxTest = Ent2Char(val);
if((strcmp(donnee, auxTest) != 0 || nbrdonnee != 1) && onlyChr(donnee)){
printf("ERREUR jpc a une donnee mal saisie ligne %d\n", numLigne);
return -1;
}
if(!onlyChr(donnee))
indiceSaut[sommetEtiq++] = numLigne;
13
else
indiceSaut2[sommetVerif++] = numLigne;
printf("Instruction jpc bien enregistree ligne %d avec donnee %s\n", numLigne, donnee);
return 10;
}
else if(strcmp(instruction, "call")==0){
val = Char2Ent(donnee);
auxTest = Ent2Char(val);
if((strcmp(donnee,auxTest) != 0 || nbrdonnee != 1) && onlyChr(donnee)){
printf("ERREUR call a une donnee mal saisie ligne %d\n", numLigne);
return -1;
}
if(!onlyChr(donnee))
indiceSaut[sommetEtiq++] = numLigne;
else
indiceSaut2[sommetVerif++] = numLigne;
printf("Instruction call bien enregistree ligne %d avec donnee %s\n", numLigne, donnee);
return 11;
}
else if(strcmp(instruction, "ret")==0){
if(nbrdonnee != 0){
printf("ERREUR ret a une donnee ligne %d\n", numLigne);
return -1;
}
printf("Instruction ret bien enregistree ligne %d\n", numLigne);
return 12;
}
else if(strcmp(instruction, "rnd")==0){
val = Char2Ent(donnee);
auxTest = Ent2Char(val);
if(!onlyChr(donnee) || nbrdonnee != 1){
printf("ERREUR red a une valeur erronne car plus grosse que 4 octets\n");
return -1;
}
printf("Instruction rnd bien enregistree ligne %d avec donnee %s\n", numLigne, donnee);
return 13;
}
else if(strcmp(instruction, "halt")==0){
if(strcmp(donnee,"") != 0){
printf("ERREUR halt a une donnee ligne %d\n", numLigne);
return -1;
}
printf("Instruction halt bien enregistree ligne %d\n", numLigne);
return 99;
}
printf("Instruction inconnue a la ligne : %d\n", numLigne);
return -1; /*valeur renvoyer si instruction non trouvee*/
}
void liberationMemoire(void){
int i;
for(i=0 ; i<sommetTab ; i++){
free(tab[i].nomIns);
free(tab[i].etiq);
free(tab[i].donneeEnChaine);
}
}
/**********************************************************************************************/
14
/*MAIN*/
int main(void){
FILE* fichierass = NULL;
FILE* fichierbit = NULL;
char chaine2[TAILLE_MAX]="", *chaine = NULL, *chaine3;
int numLigne = 0,verif_donnee = 0;
char instruction[TAILLE_MAX]="", donnee[TAILLE_MAX]="", etiq[TAILLE_MAX]="";
int pos = 0, codeAux = 3, i = 0, k = 0, f = 0, val = 0, j = 0,verif_etiq;
fichierass = fopen("assembleur.txt", "r"); /*ouvre fichier en langage assembleur */
if(fichierass == NULL){ /*sªcuritª d'ouverture du fichier*/
printf("WARNING : Fichier assembleur non present\n");
getchar();
return 5; /*valeur si fichier assembleur non prªsent*/
}
/*--------------------------------------------------------------------------------------------*/
DEBUT DU BLOC 1 qui teste validitee du programme assembleur et stocke les instructions dans la
structure
/*--------------------------------------------------------------------------------------------*/
while(!feof(fichierass)){
fgets(chaine2, TAILLE_MAX, fichierass);
pos = presenceetiq(chaine2);
verif_etiq=stockageetiq(chaine2, etiq, pos);
chaine3 = supBlanc(chaine2);
pos = presenceetiq(chaine3);
chaine = str_tolower(chaine3, pos);
free(chaine3);
if((pos == -2) || (verif_etiq == -1)){
printf("ERREUR ERREUR mauvais etiquettage ligne %d\n", numLigne);
liberationMemoire();
fclose(fichierass);
printf("ATTENTION FERMETURE DU PROGRAMME DU A UNE ERREUR DE SAISIE DE VOTRE PART\n");
getchar();
return 6;
}
verif_donnee = separationLigne(chaine, instruction, donnee, numLigne, pos);
codeAux = testIns_Don(instruction, donnee, verif_donnee, numLigne);
if((codeAux)!= -1){
if((tab[numLigne].nomIns = strdup(instruction)) == NULL) return 2;
tab[numLigne].codeOpe = codeAux;
tab[numLigne].nbrDonnee = verif_donnee;
if((tab[numLigne].etiq = strdup(etiq)) == NULL) return 2;
tab[numLigne].donneeEnChaine = strdup(donnee);
tab[numLigne].donnee = Char2Ent(donnee);
printf("%02X %08X %s\n", tab[numLigne].codeOpe, tab[numLigne].donnee,
tab[numLigne].etiq);
}else{
printf("ATTENTION FERMETURE DU PROGRAMME DU A UNE ERREUR DE SAISIE DE VOTRE PART\n");
liberationMemoire();
fclose(fichierass);
getchar();
return 7;
}
sommetTab++;
free(chaine);
strcpy(instruction,"");
strcpy(etiq,"");
15
pos = 0;
numLigne++;
}
if(strcmp(tab[numLigne-1].nomIns, "halt") != 0){/* Test si jamais le fichier assembleur pas
de halt */
printf("ERREUR ERREUR halt manquant ligne %d\n", numLigne);
liberationMemoire();
fclose(fichierass);
printf("ATTENTION FERMETURE DU PROGRAMME DU A UNE ERREUR DE SAISIE DE VOTRE PART\n");
getchar();
return 1;
}
if(doublonEtiq()){ /* verification qu'il n'y a aucun doublons dans les etiquettes */
printf("ATTENTION FERMETURE DU PROGRAMME DU A UNE ERREUR DE SAISIE DE VOTRE PART\n");
liberationMemoire();
fclose(fichierass);
getchar();
return 3;
}
for(k=0 ; k<sommetVerif ; k++){
f = indiceSaut2[k];
if(tab[f].donnee > (sommetTab-2) || (tab[f].donnee + f + 1) < 0){
printf("ERREUR donnee qui deborde ligne %d, donnee : %d\n", f, tab[f].donnee);
printf("ATTENTION FERMETURE DU PROGRAMME DU A UNE ERREUR DE SAISIE DE VOTRE PART\n");
liberationMemoire();
fclose(fichierass);
getchar();
return 3;
}
}
for(k=0 ; k<sommetEtiq ; k++){ /* creation des valeurs pour les instruction call, jpc et jmp */
f = indiceSaut[k];
if(occurEtiqAvant(tab[f].donneeEnChaine)){ /*test si jamais il n'y a pas d'etiquette egal a
la donnee */
for(j=0 ; j<sommetTab ; j++)
if(strcmp(tab[j].etiq, tab[f].donneeEnChaine) == 0){
val = j;
break;
}
}else{
printf("ERREUR etiquette inconnnue ligne %d, etiquette : %s\n",
f,tab[f].donneeEnChaine);
printf("ATTENTION FERMETURE DU PROGRAMME DU A UNE ERREUR DE SAISIE DE VOTRE PART
BOSS\n");
liberationMemoire();
fclose(fichierass);
getchar();
return 3;
}
tab[f].donnee = val - f - 1;
}
printf("\n==> SYNTAXE DU FICHIER ASSEMBLEUR CORRECT TRADUCTION VERS LANGUAGE MACHINE...\n\n");
/*-----------------------------------------------------------*/
16
/*FIN DU BLOC 1 qui testait validitee du programme assembleur*/
/*-----------------------------------------------------------*/
/*-------------------------------------------------------------------------------*/
/*DEBUT BLOC 2 traduction des instructions vers le fichier binaire de destination*/
/*-------------------------------------------------------------------------------*/
fichierbit = fopen("fichier binaire.txt","w");
if(fichierbit == NULL){ /*securite creation du fichier binaire*/
printf("ATTENTION CREATION DU FICHIER BINAIRE IMPOSSIBLE\n");
getchar();
return 1;
}
for(i=0 ; i<sommetTab ; i++){
fprintf(fichierbit, "%02X%08X\n", tab[i].codeOpe, tab[i].donnee);
printf("(%d)%s %d ---> %02X %08X\n", tab[i].codeOpe, tab[i].nomIns, tab[i].donnee,
tab[i].codeOpe, tab[i].donnee);
free(tab[i].nomIns);
free(tab[i].etiq);
free(tab[i].donneeEnChaine);
}
printf("\n==> TRADUCTION REUSSITE FERMETURE DU PROGRAMME...\n\nVeuillez recuperer la traduction
dans le fichier \"fichier binaire.txt\"\n");
/*-----------------------------------------------------------------------------*/
/*FIN BLOC 2 traduction des instructions vers le fichier binaire de destination*/
/*-----------------------------------------------------------------------------*/
fclose(fichierass);
fclose(fichierbit);
getchar();
return 0;
}
B.
Simulateur
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#define NB_INSTRUCTION 3000
/******************************************************************************/
/*Structure*/
struct Instruction{
unsigned char codeIns;
int donnee;
};
struct Instruction tab[NB_INSTRUCTION];
int sommetIns = 0;
int espaceMem[2000];
int PC = 0; /* Pointeur d'instruction */
int SP = 0; /* Pointeur sur pile */
/******************************************************************************/
/*PROTOYPE DES FONCTIONS*/
void push(int x);
void push2(int i);
17
void
void
void
void
void
void
void
void
void
void
void
void
iPush(void);
pop(int x);
iPop(void);
read(int x);
write(int x);
op(int i);
dup(void);
jmp(int a);
jpc(int a);
call(int a);
rnd(int x);
ret(void);
/*FIN DES PROTOTYPES*/
/******************************************************************************/
/*CODE*/
void push(int x){
int tmp = espaceMem[x];
espaceMem[SP] = tmp;
SP++;
}
void push2(int i){
espaceMem[SP] = i;
SP++;
}
void iPush(void){
int i=0;
int n=espaceMem[SP-1];
int tmp=espaceMem[n];
for(i=n;i<SP-1;i++){
espaceMem[i]=espaceMem[i+1];
espaceMem[SP-1]=tmp;
}
}
void pop(int x){
SP--;
espaceMem[x] = espaceMem[SP];
}
void iPop(void){
espaceMem[espaceMem[SP-1]] = espaceMem[SP-2];
SP -= 2;
}
void read(int x){
int i = 0;
int c;
printf("Veuillez rentrer une valeur\n");
scanf("%d", &i);
while ((c = getchar ()) != '\n' && c != EOF);
espaceMem[x] = i;
}
void write(int x){
printf("%d\n",espaceMem[x]);
}
void op(int i){
switch(i){
case 0 :
SP--;
espaceMem[SP-1] += espaceMem[SP];
break;
case 1 :
SP--;
espaceMem[SP-1] -= espaceMem[SP];
18
break;
case 2 :
SP--;
espaceMem[SP-1] *= espaceMem[SP];
break;
case 3 :
SP--;
espaceMem[SP-1] /= espaceMem[SP];
break;
case 4 :
SP--;
espaceMem[SP-1] %= espaceMem[SP];
break;
case 5 :
espaceMem[SP-1] = -espaceMem[SP-1];
break;
case 6 :
espaceMem[SP-1] = (!espaceMem[SP-1]);
break;
case 7 :
SP--;
espaceMem[SP-1] = (espaceMem[SP-1] & espaceMem[SP]);
break;
case 8 :
SP--;
espaceMem[SP-1] = (espaceMem[SP-1] | espaceMem[SP]);
break;
case 9 :
SP--;
espaceMem[SP-1] = (espaceMem[SP-1] ^ espaceMem[SP]);
break;
case 10 :
SP--;
if(espaceMem[SP-1] == espaceMem[SP])
espaceMem[SP-1] = 1;
else
espaceMem[SP-1] = 0;
break;
case 11 :
SP--;
if(espaceMem[SP-1] != espaceMem[SP])
espaceMem[SP-1] = 1;
else
espaceMem[SP-1] = 0;
break;
case 12 :
SP--;
if(espaceMem[SP-1] > espaceMem[SP])
espaceMem[SP-1] = 1;
else
espaceMem[SP-1] = 0;
break;
case 13 :
SP--;
if(espaceMem[SP-1] >= espaceMem[SP])
espaceMem[SP-1] = 1;
else
espaceMem[SP-1] = 0;
19
break;
case 14 :
SP--;
if(espaceMem[SP-1] < espaceMem[SP])
espaceMem[SP-1] = 1;
else
espaceMem[SP-1] = 0;
break;
default :
SP--;
if(espaceMem[SP-1] <= espaceMem[SP])
espaceMem[SP-1] = 1;
else
espaceMem[SP-1] = 0;
break;
}
}
void dup(void){
SP++;
espaceMem[SP-1] = espaceMem[SP-2];
}
void jmp(int a){
PC += a;
}
void jpc(int a){
SP--;
if(espaceMem[SP]==0)
PC +=a;
}
void call(int a){
push2(PC);
PC += a;
}
void ret(void){
SP--;
PC = espaceMem[SP];
}
void rnd(int x){
int n;
srand((unsigned)time(NULL));
n=rand();
n=n%x;
espaceMem[SP++]=n;
}
/******************************************************************************/
/*MAIN*/
int main(void){
FILE* fichierbit = NULL;
int fin = 1;
fichierbit = fopen("fichier binaire.txt", "r");
if(fichierbit == NULL){
printf("WARNING : Fichier assembleur non present\n");
getchar();
return 5; /*valeur si fichier assembleur non present*/
}
while(!feof(fichierbit)){
fscanf(fichierbit, "%2X%X", &(tab[sommetIns].codeIns), &(tab[sommetIns].donnee)); /* a
completer ici */
sommetIns++;
}
while(fin){
20
switch(tab[PC].codeIns){
case 0 :
PC++;
push(tab[PC-1].donnee);
break;
case 1 :
PC++;
push2(tab[PC-1].donnee);
break;
case 2 :
PC++;
iPush();
break;
case 3 :
PC++;
pop(tab[PC-1].donnee);
break;
case 4 :
PC++;
iPop();
break;
case 5 :
PC++;
read(tab[PC-1].donnee);
break;
case 6 :
PC++;
write(tab[PC-1].donnee);
break;
case 7 :
PC++;
op(tab[PC-1].donnee);
break;
case 8 :
PC++;
dup();
break;
case 9 :
PC++;
jmp(tab[PC-1].donnee);
break;
case 10 :
PC++;
jpc(tab[PC-1].donnee);
break;
case 11 :
PC++;
call(tab[PC-1].donnee);
break;
case 12 :
PC++;
ret();
break;
case 13 :
PC++;
rnd(tab[PC-1].donnee);
21
break;
default :
fin = 0;
break;
/*comme ce n’est pas un des autres c'est forcement halt donc on arrête */
}
}
fclose(fichierbit);
return 0;
}
C.
Exemple d’exécution
Nous avons pris pour exemple d’exécution de programme la simulation d’un « jeu » où le « joueur »
tire dans une urne (comportant 6 boules) une boule numéroté (1, 2, 3, -3, -4, -5), où ce numéro représente
le montant du gain qu’il gagne ou perd. La valeur « tiré » sera affichée à l’écran.
Instruction
SP
PC
Push# 1
1
1
Push# 2
2
2
Pile
1
2
1
3
Push# 3
3
2
3
1
-3
3
Push# -3
4
4
2
1
22
-4
-3
Push# -4
5
5
3
2
1
-5
-4
-3
Push# -5
6
6
3
2
1
1
-5
-4
Rnd 6
7
7
-3
3
2
1
23
2
1
-5
-4
iPush
7
8
-3
3
2
1
2
1
-5
-4
Pop 10
6
9
-3
3
2
1
Write 10
Halt
6
6
10
11
Même pile
Même pile
24
Téléchargement