Partie IPartie IIPartie IIIPartie IVPartie VCet article est consacré à la création d'un interprète d'un certain langage ésotérique
LMCode , basé sur l'architecture de
Little Man Computer .
En fait, il s'agit d'un émulateur assembleur pour
LMC , uniquement ici au lieu des commandes assembleur INP, STA, ADD, SUB, OUT, des commandes spéciales sont utilisées. caractères.
Pour charger le nombre dans la mémoire des commandes
command_mem , des transitions de commande en commande, et également pour sortir le résultat, des commandes
brainfuck sont utilisées.
- Laissez la commande INP correspondre
- La commande OUT correspond .
- La commande ADD correspond à +
- la sous- commande correspond à -
- La commande STA correspond à ~
- La commande LDA correspond à ^
Nous écrivons un programme qui charge un nombre du périphérique d'entrée dans la batterie, enregistre le nombre dans la mémoire, ajoute le nombre de la mémoire à la batterie (double le nombre) et sort le nombre doublé vers le périphérique de sortie.
Dans l'assembleur LMC, ce programme ressemblera à ceci (que la cellule initiale soit 20)
INP STA 20 ADD 20 OUT
Dans LMCode, ce programme ressemblera à
~ +.Dans notre machine LMCode, la mémoire de code et la mémoire de données sont séparées (architecture Harvard), nous allons créer la ligne
command_mem pour charger le code LMCode. La chaîne
command_mem représentera la mémoire des commandes. Nous créons également un
tableau de données
data_mem qui représentera la mémoire de données.
Nous chargeons le programme dans
command_mem , ~ +. #include <stdio.h> int main(void) { int i=0; // int j=0; // int acc = 0; // char command_mem[100] = ",~+."; // int data_mem[10]={0}; // while (command_mem[i] != '\0') { if (command_mem[i]==',') // scanf("%d", &acc); if (command_mem[i]=='+') // data_mem acc=acc+data_mem[j]; // if (command_mem[i]=='~') // data_mem[j]=acc; // if (command_mem[i]=='.') // printf("Output: %d",acc); i++; // } // printf("\n"); // for (int k = 0; k<10; k++) printf("%d ", data_mem[k]); return 0; }
Lors du chargement du nombre
123 dans le périphérique d'entrée, nous obtenons le nombre
246 .
Vous pouvez vérifier dans oline ide
ideone.comAjouter des commandes pour
- aller à la cellule suivante >
- aller à la cellule précédente <
Lors du traitement du symbole
> nous augmenterons l'indice
j du tableau de données
data_mem if(command_mem[i]=='>') j++;
Lors du traitement du symbole
<, nous diminuerons l'indice
j du tableau de données
data_mem if(command_mem[i]=='<') j--;
Pour sauter sur commande
? Nous allons effectuer la transition vers le label
!Pour ce faire, nous allons sauter tous les caractères entre
? et
! if(command_mem[i]=='?') { while(command_mem[i] != '!' ) { i++; } }
À titre de comparaison, nous écrivons un programme dans lequel l'utilisateur entre un nombre, par exemple
5 , avec une commande
, dans cinq cellules d'affilée avec des commandes
~> ~> ~> ~> ~ #include <stdio.h> int main(void) { int i=0; // int j=0; // int acc = 0; // char command_mem[100] = ",~>~>~>~>~"; // int data_mem[10]={0}; // while (command_mem[i] != '\0') { if (command_mem[i]==',') // scanf("%d", &acc); if (command_mem[i]=='+') // data_mem acc=acc+data_mem[j]; // if (command_mem[i]=='~') // data_mem[j]=acc; // if (command_mem[i]=='.') // printf("Output: %d",acc); if(command_mem[i]=='>') // j++; if(command_mem[i]=='<') // j--; if(command_mem[i]=='?') { // ! while(command_mem[i] != '!') i++; } i++; // } // printf("\n"); // for (int k = 0; k<10; k++) printf("%d ", data_mem[k]); return 0; }
En conséquence, nous obtenons un tableau
5 5 5 5 5 0 0 0 0 0 0ideone.comet le même programme dans lequel plusieurs pas en avant sont sautés par la commande de saut inconditionnel
, ~> ~?> ~> ~> ~!On obtient un tableau
5 5 0 0 0 0 0 0 0 0 0 0ideone.comAjouter le drapeau
pzflag PositiveZero-flag
Le drapeau ne sera levé que si le nombre dans la batterie est supérieur ou égal à zéro.
if(acc>=0){ pzflag=1;} else { pzflag=0;}
En poursuivant par la condition
pzflag == 1 nous exécuterons les commandes
{ et
} if(command_mem[i]=='{') && (pzflag==1){ while(command_mem[i] != '}' ) i++; }
Ensuite, laissez deux nombres être stockés dans notre mémoire
data_mem [0] = 3 et
data_mem [1] = 5Nous allons écrire un programme qui affiche le nombre maximum.
#include <stdio.h> int main(void) { int i=0; // int j=0; // int acc = 0; int pzflag = 1; // acc>=0 char command_mem[100] = "^>-{^?}<^!."; // int data_mem[10]={0}; data_mem[0]=3; // data_mem[1]=5; while ( command_mem[i] != '\0') { if(command_mem[i]==',') // scanf("%d", &acc); if(command_mem[i]=='+') // data_mem acc=acc+data_mem[j]; // if(command_mem[i]=='-') // data_mem acc=acc-data_mem[j]; // if(command_mem[i]=='>') // j++; if(command_mem[i]=='<') // j--; if(command_mem[i]=='~') // data_mem[j]=acc; // if(command_mem[i]=='^') // data_mem acc=data_mem[j]; // if(command_mem[i]=='.') { // printf("Output: %d",acc); printf(" "); }; if(command_mem[i]=='?') { // ! while(command_mem[i] != '!') i++; } if (command_mem[i]=='{' && pzflag==1) { // acc>=0 while(command_mem[i] != '}') i++; } if(acc>=0){ // , acc>=0 pzflag=1; } else { pzflag=0; } i++; // } // printf("\n"); // for (int k = 0; k<10; k++) printf("%d ", data_mem[k]); return 0; }
ideone.comPour revenir en arrière, ajoutez la variable
pz_prev .
Si le caractère actuel est
{ , alors "lever le drapeau"
pz_prev if (command_mem[i]=='}') pz_prev=1;
Si l'étiquette
} précède la commande
{ , alors vous devez revenir en arrière
if (command_mem[i]=='{' && pzflag==1 && pz_prev==1) { while(command_mem[i] != '}') i--; }
Nous allons écrire un programme qui affiche des nombres pairs de
10 à
0 .
Nous chargeons les nombres
10 et
2 dans le tableau
data_mem , puis, tandis que le nombre dans
acc est supérieur ou égal à zéro, nous soustraireons
2 de
10 et afficherons le résultat
#include <stdio.h> int main(void) { int i=0; // int j=0; // int acc = 0; int pzflag = 1; // acc>=0 int pz_prev=0; // acc>=0 char command_mem[100] = "}^.>-<~{"; // 10 0 int data_mem[10]={0}; data_mem[0]=10; // data_mem[1]=2; while ( command_mem[i] != '\0') { if(command_mem[i]==',') // scanf("%d", &acc); if(command_mem[i]=='+') // data_mem acc=acc+data_mem[j]; // if(command_mem[i]=='-') // data_mem acc=acc-data_mem[j]; // if(command_mem[i]=='>') // j++; if(command_mem[i]=='<') // j--; if(command_mem[i]=='~') // data_mem[j]=acc; // if(command_mem[i]=='^') // data_mem acc=data_mem[j]; // if(command_mem[i]=='.') { // printf("Output: %d",acc); printf(" "); }; if (command_mem[i]=='}') // ? pz_prev=1; if(command_mem[i]=='?') { // ! while(command_mem[i] != '!') i++; } if (command_mem[i]=='{' && pzflag==1 && pz_prev==0) { // while(command_mem[i] != '}') // acc>=0 i++; } if (command_mem[i]=='{' && pzflag==1 && pz_prev==1) { // while(command_mem[i] != '}') // acc>=0 i--; } if(acc>=0){ // , acc>=0 pzflag=1;} else { pzflag=0;} //printf("i=%d",i);printf(" "); i++; // } // printf("\n"); // for (int k = 0; k<10; k++) printf("%d ", data_mem[k]); return 0; }
ideone.comAfin de multiplier deux nombres
A et
B , vous devez ajouter
B fois
A à
B.Dans la boucle, à chaque itération, nous soustraireons un à
A et, alors que
A n'est pas nul, ajouter
B à B.
Programme LMCode
} >>> ^ <+> ~ <<< ^> - <~ {>>> ^. multiplie les nombres
A + 1 et
B , c'est-à-dire un facteur doit être délibérément réduit d'un.
En effet, la boucle ne se terminera que lorsque
-1 est en
acc .
Par exemple, multipliez
5 par
5 .
Pour ce faire, placez d'abord les valeurs nécessaires dans
data_mem data_mem[0]=4; data_mem[1]=1; data_mem[2]=5;
ideone.comAjoutez des sauts inconditionnels en
arrière .
Pour ce faire, ajoutez la variable
prev .
Nous ajoutons également des transitions
avant / arrière sous la condition
acc = 0 . Pour de telles transitions, créez l'indicateur zflag (ZeroFlag) et la variable
z_prev .
Les transitions par la condition
zflag == 1 seront effectuées par des commandes
( et
)On multiplie
5 et
5 en utilisant la transition inconditionnelle et la transition selon la condition
zflag == 1 .
Placez d'abord les valeurs nécessaires dans
data_arr data_arr[0]=5; data_arr[1]=1; data_arr[2]=5;
Programme LMCode
! >>> ^ <+> ~ <<< ^> - <~ (?) >>> ^. correspond au programme assembleur
INP STA 20 INP STA 21 INP STA 22 LDA 23 ADD 22 STA 23 LDA 20 SUB 21 STA 20 BRZ 14 BRA 06 LDA 23 OUT HLT
Code C
#include <stdio.h> int main(void) { int i=0; // int j=0; // int acc = 0; int pzflag = 1; // acc>=0 int zflag =1; // acc==0 int pz_prev=0; // acc>=0 int z_prev=0; // acc==0 int prev=0; // char command_mem[100] ="!>>>^<+>~<<<^>-<~(?)>>>^."; int data_mem[10]={0}; data_mem[0]=5; // data_mem[1]=1; data_mem[2]=5; while ( command_mem[i] != '\0') { if(command_mem[i]==',') // scanf("%d", &acc); if(command_mem[i]=='+') // data_mem acc=acc+data_mem[j]; // if(command_mem[i]=='-') // data_mem acc=acc-data_mem[j]; // if(command_mem[i]=='>') // j++; if(command_mem[i]=='<') // j--; if(command_mem[i]=='~') // data_mem[j]=acc; // if(command_mem[i]=='^') // data_mem acc=data_mem[j]; // if(command_mem[i]=='.') { // printf("Output: %d",acc); printf(" "); }; if (command_mem[i]=='}') // ? pz_prev=1; if (command_mem[i]==')') // ? z_prev=1; if (command_mem[i]=='!') // ? prev=1; // if (command_mem[i]=='?' && prev==0) { while(command_mem[i] != '!') i++; } // if (command_mem[i]=='?' && prev==1) { while(command_mem[i] != '!') i--; } // acc=0 if (command_mem[i]=='(' && zflag==1 && z_prev==0) { while(command_mem[i] != ')') i++; } // acc=0 if (command_mem[i]=='(' && zflag==1 && z_prev==1) { while(command_mem[i] != ')') i--; } // acc>=0 if (command_mem[i]=='{' && pzflag==1 && pz_prev==0) { while(command_mem[i] != '}') i++; } // acc>=0 if (command_mem[i]=='{' && pzflag==1 && pz_prev==1) { while(command_mem[i] != '}') i--; } // if(acc>=0){ pzflag=1;} else { pzflag=0;} if(acc==0){ zflag=1;} else { zflag=0;} //printf("i=%d",i);printf(" "); i++; // } // printf("\n"); // for (int k = 0; k<10; k++) printf("%d ", data_mem[k]); return 0; }
ideone.comEn général, les drapeaux n'ont pas pu être créés, mais au lieu de cela, vérifiez immédiatement à quoi correspond le nombre dans la batterie.
Vérifions comment les nombres de Fibonacci sont calculés.
#include <stdio.h> int main(void) { int i=0; // int j=0; // int acc = 0; int pzflag = 1; // acc>=0 int zflag =1; // acc==0 int pz_prev=0; // acc>=0 int z_prev=0; // acc==0 int prev=0; // char command_mem[100] ="}>>^>+.~<+.~<<^>-<~{"; int data_mem[10]={0}; data_mem[0]=5; // data_mem[1]=1; data_mem[2]=1; while ( command_mem[i] != '\0') { if(command_mem[i]==',') // scanf("%d", &acc); if(command_mem[i]=='+') // data_mem acc=acc+data_mem[j]; // if(command_mem[i]=='-') // data_mem acc=acc-data_mem[j]; // if(command_mem[i]=='>') // j++; if(command_mem[i]=='<') // j--; if(command_mem[i]=='~') // data_mem[j]=acc; // if(command_mem[i]=='^') // data_mem acc=data_mem[j]; // if(command_mem[i]=='.') { // printf("Output: %d",acc); printf(" "); }; if (command_mem[i]=='}') // ? pz_prev=1; if (command_mem[i]==')') // ? z_prev=1; if (command_mem[i]=='!') // ? prev=1; // if (command_mem[i]=='?' && prev==0) { while(command_mem[i] != '!') i++; } // if (command_mem[i]=='?' && prev==1) { while(command_mem[i] != '!') i--; } // acc=0 if (command_mem[i]=='(' && zflag==1 && z_prev==0) { while(command_mem[i] != ')') i++; } // acc=0 if (command_mem[i]=='(' && zflag==1 && z_prev==1) { while(command_mem[i] != ')') i--; } // acc>=0 if (command_mem[i]=='{' && pzflag==1 && pz_prev==0) { while(command_mem[i] != '}') i++; } // acc>=0 if (command_mem[i]=='{' && pzflag==1 && pz_prev==1) { while(command_mem[i] != '}') i--; } // if(acc>=0){ pzflag=1;} else { pzflag=0;} if(acc==0){ zflag=1;} else { zflag=0;} //printf("i=%d",i);printf(" "); i++; // } // printf("\n"); // for (int k = 0; k<10; k++) printf("%d ", data_mem[k]); return 0; }
ideone.comJ'ai posté une note sur le langage LMCode sur esolang.org
iciPS Un article sur l'émulateur assembleur pour Intel-4004
pour le divertissement ici