Lenguaje esotérico LMCode

Parte 1
Parte II
Parte III
Parte iv
Parte v

Este 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.com

Agregar 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 0
ideone.com

y 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 0
ideone.com

Agregue 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] = 5
Escribiremos 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.com

Para 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.com

Para 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.com

Agregue 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.com

En 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.com

Publiqué 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í

Source: https://habr.com/ru/post/es427629/


All Articles