LMCode de linguagem esotérica

Parte I
Parte II
Parte III
Parte iv
Parte v

Este artigo é dedicado à criação de um intérprete de uma determinada linguagem esotérica LMCode , baseada na arquitetura do Little Man Computer .
De fato, este é um emulador de assembler para LMC , somente aqui, em vez dos comandos do assembler INP, STA, ADD, SUB, OUT, especiais são usados. caracteres.
Para carregar o número na memória dos comandos command_mem , transições de comando para comando e também para gerar o resultado, são utilizados comandos brainfuck .

  • Deixe o comando INP corresponder
  • O comando OUT corresponde .
  • O comando ADD corresponde a +
  • o subcomando corresponde a -
  • O comando STA corresponde a ~
  • O comando LDA corresponde a ^

Escrevemos um programa que carrega um número do dispositivo de entrada na bateria, salva o número na memória, adiciona o número da memória à bateria (dobra o número) e envia o número duplicado ao dispositivo de saída.

No assembler LMC, este programa terá esta aparência (deixe a célula inicial ter 20)

INP STA 20 ADD 20 OUT 


No LMCode, este programa será semelhante a ~ +.
Em nossa máquina LMCode, a memória de código e a memória de dados são separadas (arquitetura Harvard), criaremos a linha command_mem para carregar o código LMCode. A cadeia command_mem representará a memória dos comandos. Também criamos uma matriz de dados data_mem que representará a memória de dados.

Carregamos o programa em 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; } 

Ao carregar o número 123 no dispositivo de entrada, obtemos o número 246 .
Você pode conferir oline ide ideone.com

Adicione comandos para

  • vá para a próxima célula >
  • vá para a célula anterior <

Ao processar o símbolo > aumentaremos o índice j da matriz de dados data_mem

 if(command_mem[i]=='>') j++; 

Ao processar o símbolo <, diminuiremos o índice j da matriz de dados data_mem

 if(command_mem[i]=='<') j--; 

Para avançar no comando ? Faremos a transição para o rótulo
Para fazer isso, vamos pular todos os caracteres entre ? e !

 if(command_mem[i]=='?') { while(command_mem[i] != '!' ) { i++; } } 

Para comparação, escrevemos um programa no qual o usuário digita um número, por exemplo 5 , com um comando , em cinco células seguidas com 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, obtemos uma matriz 5 5 5 5 5 0 0 0 0 0 0 0
ideone.com

e o mesmo programa em que vários passos adiante são ignorados pelo comando de salto incondicional , ~> ~?> ~> ~> ~!

Temos uma matriz 5 5 0 0 0 0 0 0 0 0 0
ideone.com

Adicione a bandeira pzflag PositiveZero-flag

A bandeira será elevada apenas se o número na bateria for maior ou igual a zero.

  if(acc>=0){ pzflag=1;} else { pzflag=0;} 

Avançando pela condição pzflag == 1 , executaremos os comandos { e }

 if(command_mem[i]=='{') && (pzflag==1){ while(command_mem[i] != '}' ) i++; } 


Em seguida, deixe dois números serem armazenados em nossa memória
data_mem [0] = 3 e data_mem [1] = 5
Escreveremos um programa que exibe o 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 voltar, adicione a variável pz_prev .

Se o caractere atual for { , então "levante a bandeira" pz_prev

 if (command_mem[i]=='}') pz_prev=1; 

Se o rótulo } preceder o comando { , será necessário voltar atrás

 if (command_mem[i]=='{' && pzflag==1 && pz_prev==1) { while(command_mem[i] != '}') i--; } 

Escreveremos um programa que exibe números pares de 10 a 0 .

Carregamos os números 10 e 2 na matriz data_mem ; então, enquanto o número em acc é maior ou igual a zero, subtraímos 2 de 10 e produzimos

 #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 dois números A e B , você precisa adicionar B vezes A a B.

No loop, a cada iteração, subtraímos um de A e, enquanto A não é zero, adicionamos B a B.

Programa LMCode } >>> ^ <+> ~ <<< ^> - <~ {>>> ^. multiplica os números A + 1 e B , ou seja, um fator deve ser deliberadamente reduzido em um.

Isso ocorre porque o loop só termina quando -1 estiver em conformidade .

Por exemplo, multiplique 5 por 5 .

Para fazer isso, primeiro coloque os valores necessários em data_mem

  data_mem[0]=4; data_mem[1]=1; data_mem[2]=5; 

ideone.com

Adicione saltos incondicionais de volta .

Para fazer isso, adicione a variável prev .

Também adicionamos transições para frente / para trás sob a condição acc = 0 . Para essas transições, crie o sinalizador zflag (ZeroFlag) e a variável z_prev .

As transições pela condição zflag == 1 serão executadas por comandos ( e )
Multiplicamos 5 e 5 usando a transição incondicional e a transição de acordo com a condição zflag == 1 .

Primeiro, coloque os valores necessários em data_arr
  data_arr[0]=5; data_arr[1]=1; data_arr[2]=5; 

Programa LMCode ! >>> ^ <+> ~ <<< ^> - <~ (?) >>> ^. corresponde ao programa assembler
  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

Em geral, não foi possível criar sinalizadores, mas em vez deles, verifique imediatamente qual é o número na bateria.

Vamos verificar como os números de Fibonacci são calculados.
 #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

Publiquei uma nota sobre a linguagem LMCode no esolang.org aqui

PS Um artigo sobre o emulador de assembler para Intel-4004 para entretenimento aqui

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


All Articles