¿Cómo BASIC ubica una declaración NEXT fuera de orden cuando se omite el cuerpo del bucle?

9

Configura la máquina WABAC , Sherman. Esta pregunta es sobre BASIC en general, y BASIC-80 de Microsoft en particular. Vieja escuela básica. Con números de línea.

¿Cómo manejan (o mejor dicho) los intérpretes BASIC de la vieja escuela los bucles FOR ... NEXT cuando el cuerpo del bucle no se ejecutó y la instrucción NEXT apareció fuera de orden?

Una declaración NEXT fuera de servicio del tiempo anterior:

Aquí hay una subrutina del juego 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

y aquí está con todo excepto el control de flujo redactado:

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

¿Eso te trae recuerdos no tan cariñosos? ¿Puedes oír a Dijkstra rodando en su tumba?

Aquí está la parte interesante de lo que está sucediendo en este fragmento:

  • El segundo bucle FOR, ya que usa la misma variable de bucle, reemplaza el primer bucle FOR
  • Los dos bucles FOR comparten la misma instrucción NEXT
  • La segunda instrucción NEXT del bucle FOR viene antes, en orden de origen, pero después, en orden de ejecución

Puede suponer, entonces, que el intérprete, después de haber iniciado un ciclo FOR, simplemente ejecuta declaraciones hasta que sucede a través del ciclo NEXT. El orden de la declaración en la fuente no importa en este caso. Pero veamos qué dice el manual basic80 sobre los bucles FOR:

El manual básico-80 dice "mu ..."

El cuerpo del bucle se omite si el valor inicial del bucle multiplicado por el signo del paso excede el valor final multiplicado por el signo del paso.

Por lo tanto, el cuerpo del bucle se puede omitir por completo.

Tenemos evidencia, en forma de programas publicados, de que al menos algunas versiones de BASIC estaban localizando dinámicamente sus declaraciones NEXT. Esto es bastante fácil de hacer cuando se ejecuta el cuerpo del bucle. Sin embargo, en el caso en el que se debe omitir el cuerpo de la instrucción FOR, como lo permite BASIC-80, ¿cómo BASIC ubicó la instrucción NEXT, dado que podría estar antes de la instrucción FOR en orden de origen?

  • ¿La versión de BASIC utilizada en "101 Juegos básicos de computadora" siempre ejecutó el cuerpo del bucle al menos una vez?
  • ¿BASIC-80 requirió que se produjera una instrucción NEXT del bucle FOR después de la instrucción FOR, en orden de origen?

PD: Sí, estoy escribiendo un intérprete BASIC para BASIC de la vieja escuela. Es una enfermedad.

Wayne Conrad
fuente
El libro de Ahl fue publicado originalmente por DEC en 1973, anterior a Microsoft BASIC por dos años. Los programas probablemente se habrían realizado en RT-11 BASIC o BASIC-PLUS. Además de las extensiones específicas del sistema, la mayoría de los dialectos eran compatibles, y ejecuté programas de la versión DEC del libro en varios sistemas con poca o ninguna dificultad. Puede encontrar las fuentes desmontadas y documentadas de la ROM BÁSICA de Applesoft esclarecedoras. El código que implementa la NEXTdeclaración comienza en $ DCF9.
Blrfl
No sé acerca de BASIC-80, pero estoy 100% seguro de que Commodore Basic (que era Microsoft BASIC V2) siempre ejecuta el ciclo una vez, y el orden de las declaraciones en la fuente no importa, como sospecha.
Doc Brown

Respuestas:

7

Esto trae de vuelta los viejos tiempos ...

Tengo una copia del libro, tercera impresión, 1975. Revisé su listado y no es original. En el código fuente original, las declaraciones no tienen espacios y las asignaciones tienen la palabra clave LET. Por ejemplo

200 LETK=M:GOSUB600

El dialecto es DIGITAL PDP-11 BASIC (no Basic-plus o BASIC-80). Por experiencia, no todos estos juegos funcionaron en todos los dialectos de BASIC. Tengo un vago recuerdo de tener que volver a codificar varios de estos juegos para que funcionen en otros dialectos. Este tipo de estructura de bucle horrible fue definitivamente un problema.

Tenía experiencia con más de 20 dialectos diferentes de BASIC y puedo decirle que esta era una pregunta molesta en ese momento. Hubo 2 campamentos principales.

En un campamento estaban los intérpretes completos, que analizaban cada línea de nuevo cada vez que se veía. Manejaron un bucle FOR empujándolo en una pila, identificado por su variable, y luego escaneando la pila para encontrar una coincidencia con cada SIGUIENTE. Si se saltaban un bucle, tendrían que escanear la fuente en busca de NEXT. Algunos lo hicieron, otros no.

El otro campamento eran los tokenizadores o semi-compiladores. Escanearían todas las líneas antes de la ejecución y las convertirían a algún tipo de formato interno. También combinaron los bucles FOR / NEXT y comprobaron la falta de objetivos GOTO y GOSUB. DEC y BASIC-80 estaban en este campamento, según recuerdo, pero hace mucho tiempo.

En respuesta a tus preguntas,

  1. Sí, el dialecto de BASIC omite un bucle si inicialmente está satisfecho
  2. No, la secuencia de FOR NEXT no era un requisito documentado, pero el comportamiento era indefinido. Como profesional, obviamente nunca lo hice. :)

Espero que esto ayude. Estos son idiomas horribles, pero si tienes que hacerlo ...

david.pfx
fuente
Esto es muy útil, gracias. El libro tiene una versión DEC, una versión TRS-80 y una versión de microordenador. Los programas en la versión de microordenador están en Microsoft 8080 basic (MITS Altair Basic Rev 4.0); Ese es el objetivo de mi intérprete.
Wayne Conrad
Utilicé MBASIC en CP / M alrededor de 1980, pero ninguna de esas máquinas de aficionados anteriores. ¡Necesitas un sistema de archivos! En muchos sentidos, me parece más interesante la reencarnación de un DEC / DG / HP / CAI / Prime / Interdata / Tektronix Basic, pero puedo entender por qué no. ¡La mejor de las suertes! Contáctame si puedo ser de ayuda.
david.pfx
2

No tengo una copia de la especificación para uno de estos antiguos intérpretes BASIC frente a mí (puede que ni siquiera exista), pero voy a ponerme nervioso y decir que el intérprete BASIC no ejecutará un SIGUIENTE en un bucle FOR que no le pertenece, incluso si la variable del bucle tiene el mismo nombre.

En otras palabras, en tu ejemplo

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

cuando la línea 235 se ejecuta y va a la línea 220, la línea 220 SIGUIRÁ el bucle FOR superior, no el inferior.

Esto es evidente en el mensaje de error "SIGUIENTE sin FOR"; el intérprete BÁSICO rechaza cualquier SIGUIENTE para el cual no encontró un FOR correspondiente. Esto suele suceder cuando obtiene sus NEXT fuera de servicio, como en

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

Entonces, para responder a sus preguntas con viñetas:

  • Sí, si la variable de bucle está dentro del rango de FOR.
  • Sí, que yo sepa, ese es el caso.
Robert Harvey
fuente
2
"el intérprete BASIC no ejecutará un SIGUIENTE en un bucle FOR que no le pertenece". Conozco al menos una familia de viejos intérpretes BASIC donde esta afirmación es incorrecta, no puede generalizar esto a "todos los intérpretes BASIC antiguos".
Doc Brown
La especificación existe. Busque PDP-11 BASIC.
david.pfx
1
Gracias por apuñalar esta extraña pregunta. Ahora he confirmado que el BASIC utilizado en el libro, cuando se encuentra con la segunda instrucción FOR que tiene la misma variable de contador, se olvida de la primera instrucción FOR y reinicia el ciclo a partir de la segunda. Esto contradice su puñalada en la oscuridad. Es una forma odiosa de escribir bucles, pero BASIC es algo maloliente de todos modos.
Wayne Conrad
2

Lo que hace el BASIC "101 juegos de computadora"

El dialecto de BASIC utilizado en la edición Microcomputer de "101 Computer Games" ejecutará el cuerpo de un bucle FOR ... NEXT al menos una vez. Esto difiere de BASIC-80 v. 5 .

De p. i12 , enumerando excepciones a BASIC "normal":

PARA ... A ... PASO

Como en BASIC estándar, excepto que la prueba para finalizar el ciclo se realiza después de que se ejecute. Es decir, cuando se ejecuta este programa:

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

"HI" se imprimirá ...

Debido a eso, este dialecto de BASIC no tiene problemas para localizar la declaración NEXT o compartir la misma declaración siguiente con varias declaraciones FOR. No se requiere análisis estático. Simplemente ejecute cada declaración a medida que ocurra, y eventualmente llegará a la siguiente declaración, donde sea que esté.

¿Es posible que BASIC-80 maneje un NEXT fuera de servicio?

Es posible que una instrucción FOR omita el cuerpo del bucle, como lo permite BASIC-80 v.5, y aún permite instrucciones NEXT fuera de orden en la mayoría de los casos. Así es cómo:

  • El intérprete obtiene dos estados, "en ejecución" y "saltando a NEXT"
  • Cuando está en el estado "en ejecución", el intérprete ejecuta cada declaración normalmente.
  • Al evaluar una instrucción FOR, si se va a omitir el cuerpo del bucle, el estado cambia a "omitir a NEXT"
  • Cuando está en el estado "saltando al siguiente", el intérprete omite todas las declaraciones excepto NEXT y GOTO incondicional.
    • Se sigue una declaración GOTO incondicional
    • Una instrucción NEXT, si su variable coincide con la de la instrucción FOR (o si no se especifica la variable), vuelve al estado "en ejecución". Si la variable no coincide, el intérprete permanece en el estado "saltando a SIGUIENTE".

Esto manejaría secuencias patológicas simples como la de la pregunta. No manejaría los casos en que el SIGUIENTE fue alcanzado por una declaración IF ... GOTO o un GOSUB. El código que hace eso es mucho peor que el código ya malo en la pregunta que no es irracional declarar simplemente que el intérprete no admitirá tales casos. Incluso podría ser permisible que el intérprete incendie dicho código.

Wayne Conrad
fuente