Interpretador de Comandos
Você está em: MarMSX >> Cursos >> Jogos >> Alcatraz
Foi visto no capítulo anterior, que a sub-rotina que recebe comandos escritos é responsável por capturar o comando do usuário e gravar na string FR$.
o objetivo desse capítulo é ver como o programa analisa a frase (comando) do usuário, a codifica em uma ação e verifica se essa ação é válida.
Análise da Frase FR$
A primeira parte consiste na análise léxica e sintática da frase, que são feitas simultaneamente. A primeira consiste em dividir uma frase em palavras, onde o elemento utilizado para a divisão é o espaço em branco. A segunda consiste em analisar a estrutura gramatical da frase, a partir da ordem das palavras. São duas estruturas gramáticais esperadas pelo analisador sintático: um verbo seguido de um susbstantivo ou um verbo seguido de dois substantivos: V->S ou V->S->S.
1020 FORN=LEN(FR$)TO1STEP-1:IFMID$(FR$,N,1)=" "THENNEXT
1030 FR$=LEFT$(FR$,N)
1040 FORN=1TOLEN(FR$)
1050 IFMID$(FR$,N,1)<>" "THENNEXT
1060 FORM=0TONV
1070 IFVE$(M)=LEFT$(FR$,N-1)THENI$=CHR$(M+50):GOTO1100
1080 NEXTM
1090 PRINT#1,"O que e' ";LEFT$(FR$,N);" ?":GOTO340
1100 IFLEN(FR$)=N-1THEN1230 ELSE FR$=MID$(FR$,N+1):FORN=1TOLEN(FR$)
1110 IFMID$(FR$,N,1)<>" "THENNEXT
1120 FORM=0TONS
1130 IFFNS$(M)=LEFT$(FR$,N-1)THENI$=I$+CHR$(M+50):GOTO1150
1140 NEXTM:GOTO1090
1150 IFLEN(FR$)=N-1THEN1230 ELSE FR$=MID$(FR$,N+1)
1160 FORN=LEN(FR$)TO1STEP-1
1170 IFMID$(FR$,N,1)<>" "THENNEXT
1180 FORM=0TONS
1190 IFFNS$(M)=MID$(FR$,N+1)THENI$=I$+CHR$(M+50):GOTO1230
1200 NEXTM:PRINT#1,"O que e' ";MID$(FR$,N+1);" ?":GOTO340
Passos:
- Eliminar espaços em branco ao final de FR$.
- Identificar a primeira palavra da frase e procurá-la no vetor de verbos VE$.
- Identificar a segunda palavra na frase e procurá-la no vetor de substantivos SU$.
- Codificar o substantivo em I$, agregando o valor.
- Identificar a terceira palavra na frase e procurá-la no vetor de substantivos SU$.
- Codificar o substantivo em I$, agregando o valor.
Eliminar espaços em branco
As linhas 1020-1030 tem como objetivo eliminar de FR$ os espaços em branco ao final.
A linha 1020 varre a frase de trás para frente, procurando o primeiro caractere diferente de espaço em branco. A variável N guarda essa posição.
A linha 1030 elimina os caracteres em branco ao final, de acordo com a posição N encontrada. Ex:
FR$="PEGUE AGUA "
fica:
"PEGUE AGUA"
Identificação do verbo
A frase é então quebrada em palavras, onde o critério de separação é o espaço em branco.
A primeira palavra esperada é um verbo, onde a obtenção dela é feita pela rotina a seguir.
1040 FORN=1TOLEN(FR$)
1050 IFMID$(FR$,N,1)<>" "THENNEXT
1060 FORM=0TONV
1070 IFVE$(M)=LEFT$(FR$,N-1)THENI$=CHR$(M+50):GOTO1100
1080 NEXTM
1090 PRINT#1,"O que e' ";LEFT$(FR$,N);" ?":GOTO340
Nas linhas 1040-1050, o programa varre para frente os caracteres de FR$, desde a posição 1 até encontrar o caracter "espaço em branco". A variável N guarda a posição do caractere em branco encontrado.
Nas linhas 1060-1080, a primeira palavra é obtida através instrução LEFT$(FR$,N-1). Além disso, ele procura no vetor de verbos VE$ a primeira palavra encontrada. A variável M controla o índice do vetor de verbos VE$.
Caso haja sucesso na busca, ele codifica a posição M do verbo encontrado na lista em I$, através do comando CHR$(M+50). Isto significa dizer que, I$ recebe um caractere, cujo o valor ASCII é 50 mais a posição do verbo.
Depois, desvia o programa para a linha 1100, para seguir em frente na análise da frase.
Caso não encontre o verbo, a linha 1090 é atingida, onde imprime uma mensagem de erro e retorna para a sub-rotina "aguarda movimento".
Identificação do primeiro substantivo
Uma vez identificado o verbo, o programa segue procurando por um ou dois substantivos.
1100 IFLEN(FR$)=N-1THEN1230 ELSE FR$=MID$(FR$,N+1):FORN=1TOLEN(FR$)
1110 IFMID$(FR$,N,1)<>" "THENNEXT
1120 FORM=0TONS
1130 IFFNS$(M)=LEFT$(FR$,N-1)THENI$=I$+CHR$(M+50):GOTO1150
1140 NEXTM:GOTO1090
A linha 1010 verifica se a palavra anterior era a última. Em caso afirmativo, ele desvia para a sub-rotina de análise das ações. Senão, corta a frase FR$, eliminando a primeira palavra.
A seguir, varre FR$ em busca da segunda palavra.
Se encontrar o substantivo, o codifica do mesmo modo que o verbo, só que agora a posição M é do vetor de substantivos. O resultado é agragado (colocado ao final) a I$ e o programa desvia para a sub-rotina que irá procurar pela terceira palavra.
Assim, como no verbo, caso não encontre o substantivo, desvia para 1090, que imprime a mensagem de erro e retorna.
O último substantivo
Eis a sub-rotina que procura pelo último substantivo.
1150 IFLEN(FR$)=N-1THEN1230 ELSE FR$=MID$(FR$,N+1)
1160 FORN=LEN(FR$)TO1STEP-1
1170 IFMID$(FR$,N,1)<>" "THENNEXT
1180 FORM=0TONS
1190 IFFNS$(M)=MID$(FR$,N+1)THENI$=I$+CHR$(M+50):GOTO1230
1200 NEXTM:PRINT#1,"O que e' ";MID$(FR$,N+1);" ?":GOTO340
Na linha 1150, observa-se que tanto nessa sub-rotina, como na anterior, se FR$ não tiver mais palavras, o programa desvia para a sub-rotina de análise das ações. É assim que o programa aceita um, dois, ou até nenhum substantivo.
Caso FR$ ainda tenha mais palavras, ele corta a segunda palavra da frase original.
Nas linhas 1160-1170, para ignorar uma possível preposição antes do último substantivo, o analisador agora lê de trás para frente, até encontrar o espaço em branco, de forma a capturar a última palavra da frase.
Nas linhas 1180-1190, ele procura a palavra na lista de substantivos. Caso encontre, adiciona codificação em I$ e continua o programa em 1230 (análise de ações).
Caso a palavra não conste no dicionário, imprime mensagem de erro e retorna para a sub-rotina "aguarda movimento".
O processo completo
Seja a frase "ABRA GRADES COM CHAVE", veja como a frase é quebrada e codificada:
1. Verbo
→
ABRA GRADES COM CHAVE
↑
N
VE$(23)="ABRA"
M=23;
I$ = CHR$(50+23) = CHR$(73) = "I"
2. Substantivo 1
→
GRADES COM CHAVE
↑
N
LEFT(SU$(24),3) = "GRADES"
M=24;
I$ = I$ + CHR$(50+24) = I$ + CHR$(74) = "IJ"
3. Substantivo 2
←
COM CHAVE
↑
N
LEFT(SU$(3),3) = "CHAVE"
M=3;
I$ = I$ + CHR$(50+3) = I$ + CHR$(53) = "IJ5"
Análise da Ação
Uma vez codificada a ação em I$, é necessário realizar a análise semântica do comando dado pelo usuário, ou seja, verificar se a frase faz sentido dentro da linguagem do jogo. Em caso afirmativo, obter o índice da respectiva ação, com base no vetor de ações AC$.
O código responsável por isso é:
1220 REM ♦♦♦ CODIFICA ACAO EM I$♦♦♦
1230 P$=CHR$(PC+60)+CHR$(PL+60)
1240 IFLEN(I$)<>1THENGOSUB1520
1250 FORN=0TOAS
1260 IFI$=AC$(N)THEN1330
1270 NEXT
1280 IFLEN(I$)=1THEN1320
1290 FORN=AS+1TONA
1300 IFLEFT$(I$,1)=AC$(N)THEN1330
1310 NEXT
1320 PRINT#1,"Isto nao e possivel.":GOTO340
1330 ON(N+1)GOSUB1620,1630,1630,1650,1660,1660,1660,1670,1680,1700,1720,1730,1740,
1770,1790,1700,1800,1820,1840,1860,1890,1910,1930,1940,1970,1990,2010,2030,2060,1630
1340 IF N<30 THEN 340
1350 ON(N-29)GOSUB1630,1620,2100,2160,2170,2180,2190,2200,2960,2230,2240,2260,2270,
2280,2310,2330,2370,2450,2520,2610,2650,2740,2760,2920,2940
1360 GOTO340
O vetor de ações AC$ está dividido em duas partes: ações com verbo + substantivo e ações com um verbo. A primeira parte, fica de 0 até AS, enquanto que a segunda, de AS+1 até NA.
A sub-rotina acima, realiza a busca nas duas partes do vetor, uma de cada vez.
A análise semântica consiste em verificar se o código em I$ existe na lista AC$, em qualquer uma das partes.
A linha 1230 codifica o local em P$.
A linha 1240 verifica na linha 1520, se o objeto citado está com o jogador ou no local, caso o código I$ tenha, pelo menos, um substantivo.
1510 REM ♦♦ VERIFICA OBJETOS CITADOS ♦♦
1520 J=ASC(MID$(I$,2,1))-50:IFLEFT$(SU$(J),2)=P$ OR LEFT$(SU$(J),2)="**" OR
LEFT$(SU$(J),2)=".." OR LEFT$(I$,1)=">" OR LEFT$(I$,1)="9" THEN 1540
1530 I=J:GOTO1560
1540 IF LEN(I$)<3 THEN RETURN
1550 I=ASC(MID$(I$,3,3))-50:IF LEFT$(SU$(I),2)=P$ OR LEFT$(SU$(I),2)="**" OR
LEFT$(SU$(I),2)=".." THEN RETURN
1560 PRINT#1,"Nao estou vendo ";FNS$(I):GOTO340
Na linha 1510, ele identifica o primeiro substantivo, através da decodificação de I$ em J, obtendo a posição do substantivo em SU$.
Depois, compara o código de posição do substantivo com o código do local, com o código "**" e "..", para ver se o objeto está disponível.
No mesmo teste, ele verifica se o verbo é PECA ou TIRE.
Assim, se qualquer um desses testes for verdadeiro, o objeto é validado e ele passa para a verificação do segundo objeto na linha 1540.
Caso o objeto seja invalidado (existe no jogo, mas não está disponível), ele desvia para 1560, imprimindo uma mensagem de erro e retornando para a sub-rotina "aguarda movimento".
A verificação do segundo objeto (substantivo) segue as mesmas regras do primeiro.
Voltando à sub-rotina de tratamento de ações ...
As linhas 1250-1270 buscam pelo código I$ na parte de verbo + substantivos, armazenando a posição encontrada em N.
Em caso de sucesso, desvia o programa para a linha 1330, que irá decidir a ação, com base no número N encontrado no vetor AC$ (soma-se mais um, devido à instrução ON GOSUB trabalhar de 1 a N).
Caso ele não ache a ação na lista de verbos + substantivos, ele parte para a lista de ações AC$ só com o verbo.
Primeiro, ele verifica novamente se I$ só tem o verbo. Caso não tenha, ele fará a análise agora na parte de AC$ que só tem ações com verbos. Por quê ele faz isso ?
Porque primeiro, algumas frases, embora corretas, podem estar incompletas; depois, alguns verbos possuem sinônimos, como, por exemplo, jogar e colocar, e ele trata isso.
Veja o caso para o verbo PECA, seguido de substantivo (vide a lista de ações no capítulo seguinte).
2330 IFLEN(I$)=2 THEN PRINT#1,"A quem?":RETURN ELSE IF I<>22 AND I<>25 AND
I<> 30 THEN PRINT#1,"Voce esta' louco? Por que nao fala com pessoas?":RETURN
Caso PECA não esteja na lista de substantivo + verbo, cairá forçosamente na lista de verbos. Então, o tratamento da ação PECA envia um GOSUB para a linha 2330.
Caso haja mais de um substantivo, ele verifica se o objeto (I=J em 1530) não é o guarda, presidiário ou poço. Em afirmativo, emite a mensagem.
Agora veja o tratamento do verbo JOGUE, a partir da lista de verbos.
2370 IF I$="?>S" THEN GOTO 1990
2380 IF I$="?>N" THEN GOTO 1910
2390 IF I$="?=N" THEN GOTO 1890
2400 IF I$="?4O" THEN GOTO 1700
2410 IF J<22 AND J<>2 THEN PRINT#1,"Voce perdeu o objeto.":GOTO1590
2420 IF J>21 THEN PRINT#1,"Voce nao e' tao forte assim...":RETURN
As primeiras quatro linhas criam uma lista de sinônimos entre o verbo colocar e jogar.
6>S COLOQUE AGUA ALARME <=> ?>S JOGUE AGUA ALARME
6>N COLOQUE AGUA FOGO <=> ?>N JOGUE AGUA FOGO
6=N COLOQUE COBERTOR FOGO <=> ?=N JOGUE COBERTOR FOGO
64O COLOQUE CORDA POCO <=> ?4O COLOQUE CORDA POCO
Tirando os quatro casos acima, se o substantivo junto ao verbo JOGAR tiver índice de 2 a 21, esse tratamento irá sumir com ele. Caso seja maior, ele diz que o objeto é muito pesado para você jogar.
Por fim, a instrução ON GOSUB trata as ações de acordo com o número delas no vetor AC$. Essa instrução foi dividida em duas partes: a linha 1330 trata os casos de 0 ≤ N ≤ 29. Já a linha 1350 trata dos casos de 30 ≤ N ≤ 54.