Parte IParte IIParte IIIParte ivParte vEste 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.comAdicione 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 0ideone.come 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 0ideone.comAdicione 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] = 5Escreveremos 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.comPara 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.comPara 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.comAdicione 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.comEm 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.comPubliquei uma nota sobre a linguagem LMCode no esolang.org
aquiPS Um artigo sobre o emulador de assembler para Intel-4004
para entretenimento aqui