Como o BASIC localiza uma instrução NEXT fora de ordem quando o corpo do loop é ignorado

9

Defina a máquina WABAC , Sherman. Esta pergunta é sobre o BASIC em geral, e o BASIC-80 da Microsoft em particular. Velha escola básica. Com números de linha.

Como (ou melhor) os intérpretes do BASIC da velha escola lidam com loops FOR ... NEXT quando o corpo do loop não foi executado e a instrução NEXT apareceu fora de ordem?

Uma instrução NEXT fora de ordem do tempo anterior:

Aqui está uma sub-rotina do jogo Awari de "101 Basic Computer Games" de David H. Ahl :

200 K=M:GOSUB 600
205 E=0:IF K>6 THEN K=K-7
210 C=C+1:IF C<9 THEN F(N)=F(N)*6+K
215 FOR I=0 TO 5:IF B(I)<>0 THEN 230
220 NEXT I
225 RETURN
230 FOR I=7 TO 12:IF B(I)<>0 THEN E=1:RETURN
235 GOTO 220

e aqui está tudo, exceto o controle de fluxo redigido:

200 GOSUB 600
215 FOR I=0 TO 5:IF ... THEN 230
220 NEXT I
225 RETURN
230 FOR I=7 TO 12:IF ... THEN RETURN
235 GOTO 220

Isso traz de volta memórias não tão boas? Você pode ouvir Dijkstra rolando em seu túmulo?

Aqui está a parte interessante do que está acontecendo neste fragmento:

  • O segundo loop FOR, uma vez que usa a mesma variável de loop, substitui o primeiro loop FOR
  • Os dois loops FOR compartilham a mesma instrução NEXT
  • A instrução NEXT do segundo loop FOR vem antes, na ordem de origem, mas depois, na ordem de execução

Você pode supor, então, que o intérprete, após iniciar um loop FOR, simplesmente executa instruções até que ocorra no loop NEXT. A ordem da declaração na fonte não importa neste caso. Mas vamos ver o que o manual basic80 tem a dizer sobre os loops FOR:

O manual do basic-80 diz "moo ..."

O corpo do loop é pulado se o valor inicial do loop multiplicar o sinal da etapa exceder o valor final multiplicar o sinal da etapa.

Portanto, o corpo do loop pode ser ignorado completamente.

Temos evidências, na forma de programas publicados, de que pelo menos algumas versões do BASIC estavam localizando dinamicamente suas declarações NEXT. Isso é fácil o suficiente quando o corpo do loop está sendo executado. No entanto, no caso em que o corpo da instrução FOR deve ser ignorado, como permite o BASIC-80, como o BASIC localizou a instrução NEXT, considerando que ela pode estar antes da instrução FOR na ordem de origem?

  • A versão do BASIC usada em "101 Basic Computer Games" sempre executava o corpo do loop pelo menos uma vez?
  • O BASIC-80 exigiu que a instrução NEXT de um loop FOR ocorresse após a instrução FOR, na ordem de origem?

PS: Sim, estou escrevendo um intérprete BASIC para o BASIC da velha escola. É uma doença.

Wayne Conrad
fonte
O livro Ahl foi publicado originalmente pela DEC em 1973, anterior ao Microsoft BASIC por dois anos. Os programas provavelmente teriam sido realizados no RT-11 BASIC ou BASIC-PLUS. Além das extensões específicas do sistema, a maioria dos dialetos era compatível e eu executei programas da versão DEC do livro em vários sistemas com pouca ou nenhuma dificuldade. Você pode achar as fontes documentadas e desmontadas da Applesoft BASIC ROM esclarecedoras. O código que implementa a NEXTinstrução começa em $ DCF9.
Blrfl 17/02
Não sei sobre o BASIC-80, mas tenho 100% de certeza de que o Commodore Basic (que era o Microsoft BASIC V2) sempre executa o loop uma vez, e a ordem das instruções na fonte não importa - exatamente como você suspeita.
Doc Brown

Respostas:

7

Isso traz de volta os velhos tempos ...

Eu tenho uma cópia do livro, terceira impressão, 1975. Eu verifiquei sua listagem e ela não é original. No código fonte original, as instruções não têm espaços e as atribuições têm a palavra-chave LET. Por exemplo

200 LETK=M:GOSUB600

O dialeto é DIGITAL PDP-11 BASIC (não Basic-plus ou BASIC-80). Por experiência, nem todos esses jogos funcionaram em todos os dialetos do BASIC. Tenho uma vaga lembrança de ter que recodificar vários desses jogos para fazê-los funcionar em outros dialetos. Esse tipo de estrutura horrível de loop era definitivamente um problema.

Eu tive experiência com mais de 20 dialetos diferentes do BASIC e posso dizer que essa era uma pergunta irritante na época. Havia 2 campos principais.

Em um campo, havia os intérpretes completos, que analisavam cada linha novamente a cada vez que eram vistos. Eles manipularam um loop FOR empurrando-o em uma pilha, identificada por sua variável, e depois varrendo a pilha em busca de uma correspondência com cada NEXT. Se eles pulassem um loop, teriam que procurar na fonte o NEXT. Alguns fizeram, outros não.

O outro campo eram os tokenizers ou semi-compiladores. Eles varriam todas as linhas antes da execução e as convertiam para algum tipo de formato interno. Eles também encontraram loops FOR / NEXT e verificaram a falta de alvos GOTO e GOSUB. DEC e BASIC-80 estavam neste campo, pelo que me lembro, mas faz muito tempo.

Em resposta às suas perguntas,

  1. Sim, o dialeto do BASIC pula um loop se inicialmente satisfeito
  2. Não, o sequenciamento de FOR NEXT não era um requisito documentado, mas o comportamento era indefinido. Como profissional, obviamente eu nunca fiz isso. :)

Espero que isto ajude. Essas são linguagens horríveis, mas se você precisar ...

david.pfx
fonte
Isso é muito útil, obrigado. O livro possui uma versão DEC, uma versão TRS-80 e uma versão em microcomputador. Os programas na versão de microcomputador estão no Microsoft 8080 basic (MITS Altair Basic Rev 4.0); esse é o alvo do meu intérprete.
Wayne Conrad
Eu usei o MBASIC no CP / M por volta de 1980, mas nenhuma dessas máquinas amadores anteriores. Você precisa de um sistema de arquivos! De muitas maneiras, eu acharia uma reencarnação de um DEC / DG / HP / CAI / Prime / Interdata / Tektronix Basic mais interessante, mas posso entender por que você talvez não o faça. Boa sorte! Entre em contato comigo se eu puder ajudar.
David.pfx
2

Não tenho uma cópia da especificação para um desses intérpretes antigos do BASIC na minha frente (talvez nem exista), mas vou me expor e dizer que o intérprete do BASIC não executará um NEXT em um loop FOR que não pertence a ele, mesmo que a variável do loop tenha o mesmo nome.

Então, em outras palavras, no seu exemplo

200 K=M:GOSUB 600
205 E=0:IF K>6 THEN K=K-7
210 C=C+1:IF C<9 THEN F(N)=F(N)*6+K
215 FOR I=0 TO 5:IF B(I)<>0 THEN 230
220 NEXT I
225 RETURN
230 FOR I=7 TO 12:IF B(I)<>0 THEN E=1:RETURN
235 GOTO 220

quando a linha 235 é executada e vai para a linha 220, a linha 220 PRÓXIMO do loop FOR superior, não o inferior.

Isso é evidente na mensagem de erro "NEXT without FOR"; o intérprete BASIC rejeita qualquer PRÓXIMO para o qual não encontrou um FOR correspondente. Isso normalmente acontece quando você deixa seus PRÓXIMOS fora de ordem, como em

100 FOR I = 1 to 10
110 FOR J = 1 to 10
120 ...
130 NEXT I
140 NEXT J

Então, para responder às suas perguntas com marcadores:

  • Sim, se a variável do loop estiver dentro do alcance do FOR.
  • Sim, que eu saiba, é esse o caso.
Robert Harvey
fonte
2
"o intérprete do BASIC não executará um PRÓXIMO em um loop FOR que não pertence a ele" - conheço pelo menos uma família de antigos intérpretes do BASIC em que esta declaração está errada, você não pode generalizar isso para "todos os intérpretes do BASIC antigos".
Doc Brown
A especificação existe. Procure por PDP-11 BASIC.
David.pfx
11
Obrigado por dar uma facada nessa pergunta estranha. Confirmei agora que o BASIC usado no livro, ao encontrar a segunda instrução FOR com a mesma variável de contador, esquece a primeira instrução FOR e reinicia o loop da segunda. Isso contradiz sua facada no escuro. É uma maneira odiosa de escrever loops, mas BASIC é algo fedido de qualquer maneira.
Wayne Conrad
2

O que o BASIC "101 Jogos de Computador" faz

O dialeto do BASIC usado na edição de microcomputador "101 Computer Games" executará o corpo de um loop FOR ... NEXT pelo menos uma vez. Isso difere do BASIC-80 v. 5 .

Da p. i12 , listando exceções ao BASIC "normal":

PARA ... PASSO

Como no BASIC padrão, exceto que o teste para finalizar o loop é feito depois que h é executado. Ou seja, quando este programa é executado:

10 FOR X=2 TO 1
20 PRINT "HI"
30 NEXT X
40 END

"HI" será impresso ...

Por esse motivo, esse dialeto do BASIC não tem problemas para localizar a instrução NEXT ou compartilhar a mesma instrução seguinte com várias instruções FOR. Nenhuma análise estática é necessária. Simplesmente execute todas as instruções à medida que elas ocorrerem, e você chegará à instrução NEXT, onde quer que esteja.

É possível para o BASIC-80 lidar com um NEXT fora de ordem?

É possível que uma instrução FOR ignore o corpo do loop, como permite o BASIC-80 v.5, e ainda permita instruções NEXT fora de ordem na maioria dos casos. Aqui está como:

  • O intérprete obtém dois estados, "executando" e "pulando para NEXT"
  • Quando no estado "em execução", o intérprete executa cada instrução normalmente.
  • Ao avaliar uma instrução FOR, se o corpo do loop precisar ser pulado, o estado será alterado para "pulando para NEXT"
  • Quando no estado "pular para o próximo", o intérprete pula todas as instruções, exceto NEXT e GOTO incondicional.
    • Uma declaração GOTO incondicional é seguida
    • Uma instrução NEXT, se sua variável corresponder à da instrução FOR (ou se a variável não for especificada), retornará ao estado "running". Se a variável não corresponder, o intérprete permanecerá no estado "pulando para NEXT".

Isso lidaria com seqüências patológicas simples, como a da questão. Ele não trataria dos casos em que o NEXT fosse alcançado por uma instrução IF ... GOTO ou um GOSUB. O código que faz isso é muito pior do que o já ruim na pergunta, e não é irracional declarar simples que o intérprete não dará suporte a esses casos. Pode até ser permitido ao intérprete incendiar esse código.

Wayne Conrad
fonte