Parte 1Parte IIParte IIIParte ivParte vEste artículo está dedicado a la creación de un intérprete de cierto lenguaje esotérico
LMCode , que se basa en la arquitectura de
Little Man Computer .
De hecho, este es un emulador de ensamblador para
LMC , solo que aquí en lugar de los comandos de ensamblador INP, STA, ADD, SUB, OUT, se usan los especiales. personajes
Para cargar el número en la memoria de los comandos
command_mem , las transiciones de comando a comando y también para generar el resultado, se utilizan comandos
brainfuck .
- Deje que el comando INP coincida
- El comando OUT corresponde .
- El comando AGREGAR corresponde a +
- el subcomando corresponde a -
- El comando STA corresponde a ~
- El comando LDA corresponde a ^
Escribimos un programa que carga un número del dispositivo de entrada en la batería, guarda el número en la memoria, agrega el número de la memoria a la batería (duplica el número) y envía el número duplicado al dispositivo de salida.
En el ensamblador LMC, este programa se verá así (deje que la celda inicial sea 20)
INP STA 20 ADD 20 OUT
En LMCode, este programa se verá así
, ~ +.En nuestra máquina LMCode, la memoria de código y la memoria de datos están separadas (arquitectura Harvard), crearemos la línea command_mem para cargar el código LMCode. La cadena
command_mem representará la memoria de los comandos. También creamos una
matriz de datos
data_mem que representará la memoria de datos.
Cargamos el programa en
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; }
Al cargar el número
123 en el dispositivo de entrada, obtenemos el número
246 .
Puedes consultar en oline ide
ideone.comAgregar comandos para
- ir a la celda siguiente >
- ir a la celda anterior <
Al procesar el símbolo
> aumentaremos el índice
j de la matriz de datos
data_mem if(command_mem[i]=='>') j++;
Al procesar el símbolo
<, disminuiremos el índice
j de la matriz de datos
data_mem if(command_mem[i]=='<') j--;
¿Saltar adelante al mando
? ¡Haremos la transición a la etiqueta
!Para hacer esto, saltaremos todos los caracteres entre
? y
! if(command_mem[i]=='?') { while(command_mem[i] != '!' ) { i++; } }
A modo de comparación, escribimos un programa en el que el usuario ingresa un número, por ejemplo
5 , con un comando
, en cinco celdas seguidas con comandos
~> ~> ~> ~> ~ #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; }
Como resultado, obtenemos una matriz
5 5 5 5 5 0 0 0 0 0 0ideone.comy el mismo programa en el que el comando de salto incondicional salta varios pasos hacia adelante
, ~> ~?> ~> ~> ~!Obtenemos una matriz
5 5 0 0 0 0 0 0 0 0 0ideone.comAgregue la bandera
pzflag Positiva-
cero -bandera
La bandera se elevará solo si el número en la batería es mayor o igual a cero.
if(acc>=0){ pzflag=1;} else { pzflag=0;}
Avanzando por la condición
pzflag == 1 ejecutaremos los comandos
{ y
} if(command_mem[i]=='{') && (pzflag==1){ while(command_mem[i] != '}' ) i++; }
Luego, dejemos dos números almacenados en nuestra memoria
data_mem [0] = 3 y
data_mem [1] = 5Escribiremos un programa que muestre el número máximo.
#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.comPara retroceder, agregue la variable
pz_prev .
Si el carácter actual es
{ , entonces "levanta la bandera"
pz_prev if (command_mem[i]=='}') pz_prev=1;
Si la etiqueta
} precede al comando
{ , entonces necesita retroceder
if (command_mem[i]=='{' && pzflag==1 && pz_prev==1) { while(command_mem[i] != '}') i--; }
Escribiremos un programa que muestre números pares del
10 al
0 .
Cargamos los números
10 y
2 en la matriz
data_mem , luego, mientras que el número en
acc es mayor o igual a cero, restaremos
2 de
10 y mostraremos el resultado
#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.comPara multiplicar dos números
A y
B , debes sumar
B por A a
B.En el bucle, en cada iteración, restaremos uno de
A y, mientras
A no
es cero, sumaremos
B a B.
Programa LMCode
} >>> ^ <+> ~ <<< ^> - <~ {>>> ^. multiplica los números
A + 1 y
B , es decir un factor debe reducirse deliberadamente en uno.
Esto se debe a que el ciclo solo terminará cuando
-1 esté en
acc .
Por ejemplo, multiplique
5 por
5 .
Para hacer esto, primero coloque los valores necesarios en
data_mem data_mem[0]=4; data_mem[1]=1; data_mem[2]=5;
ideone.comAgregue saltos incondicionales
hacia atrás .
Para hacer esto, agregue la variable
anterior .
También agregamos transiciones
hacia adelante / hacia atrás bajo la condición
acc = 0 . Para tales transiciones, cree la bandera zflag (ZeroFlag) y la variable
z_prev .
Las transiciones por la condición
zflag == 1 se llevarán a cabo mediante comandos
( y
)Multiplicamos
5 y
5 usando la transición incondicional y la transición de acuerdo con la condición
zflag == 1 .
Primero coloque los valores necesarios en
data_arr data_arr[0]=5; data_arr[1]=1; data_arr[2]=5;
¡Programa LMCode
! >>> ^ <+> ~ <<< ^> - <~ (?) >>> ^. corresponde al programa ensamblador
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
Código 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 general, no se pudieron crear indicadores, pero en lugar de ellos, verifique inmediatamente a qué equivale el número de la batería.
Veamos cómo se calculan los números de Fibonacci.
#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.comPubliqué una nota sobre el lenguaje LMCode en esolang.org
aquíPD: un artículo sobre el emulador de ensamblador para Intel-4004
para entretenimiento aquí