Acorn System BASIC y Atom BASIC son dos dialectos estrechamente relacionados del lenguaje de programación BASIC desarrollado por Acorn Computers para sus primeros microordenadores , como Acorn System 3 y Acorn Atom . Desarrollados internamente, tienen una serie de idiosincrasias significativas en comparación con la mayoría de los dialectos BASIC de la era de los ordenadores domésticos .
En particular, el lenguaje carecía de instrucciones para muchas de las funciones internas de la máquina y las proporcionaba mediante el acceso directo y la manipulación de las posiciones de memoria mediante operadores de indirección en lugar de PEEK y POKE . Ambos también carecían de soporte de punto flotante , aunque esto podía añadirse con una ROM opcional que introducía más idiosincrasias. El BASIC System y Atom difieren principalmente en que Atom utilizaba el mismo sistema de indirección para proporcionar una manipulación rudimentaria de cadenas, de la que carecía Standard, y añadía una pequeña cantidad de nuevas instrucciones para gráficos de ordenador .
La mayoría de estas rarezas se eliminaron cuando el sistema subyacente se expandió en gran medida para producir BBC BASIC en el sucesor del Atom, el BBC Micro . Las ROM BBC BASIC se ofrecieron más tarde a los usuarios del Atom.
Acorn Computers se formó en 1978 y comenzó a fabricar una serie de sistemas basados en Eurocard y en kits, comenzando con el Acorn System 1 en 1979. Para estas máquinas desarrollaron Acorn System BASIC, [1] un dialecto de solo números enteros que requería solo 4 KB de memoria en total. [2] El lenguaje tenía una serie de detalles de implementación que lo hacían "muy poco estándar". [3]
El Atom , introducido en 1980, se construyó a partir de partes del System 3 empaquetadas en una sola placa. Los sistemas se entregaban de serie con 2 KB de RAM y 8 KB de ROM, que incluían BASIC y una serie de controladores de dispositivos . Atom BASIC solo tenía unos pocos cambios con respecto a la versión System, añadiendo soporte para manipulación de cadenas y una pequeña cantidad de comandos gráficos. El Atom era actualizable, con hasta 12 KB de RAM en total y 4 KB adicionales de ROM que añadían soporte de punto flotante . Esto utilizaba funciones y operaciones independientes que funcionaban en ellas, indicadas por el símbolo %. [3] Esta elección de símbolo fue desafortunada, ya que Microsoft BASIC utilizaba el signo de porcentaje para indicar números enteros, no de punto flotante. [4]
El Atom estuvo en el mercado durante un breve período antes de que Acorn comenzara a desarrollar su sucesor, el Proton. Inicialmente, se suponía que sería una unidad de dos procesadores. El diseño estaba todavía en sus primeras etapas cuando una serie de eventos llevaron a que se lo seleccionara como base del BBC Micro de una sola CPU . [1] En ese momento, hubo comentarios de que definitivamente no debería usar la variedad de BASIC de Acorn, que "prácticamente ningún otro microordenador puede entender" y que "si el nuevo lenguaje se basara en la forma de BASIC del Atom, sería un desastre". [5]
En definitiva, el sistema BBC utilizó las variantes antiguas del BASIC escrito por Acorn, pero con importantes modificaciones. El BBC BASIC resultante era mucho más parecido al Microsoft BASIC y más tarde se ofreció como una actualización del Atom. [6]
Como los dos dialectos son muy similares, lo siguiente se referirá principalmente a Atom BASIC y señalará las diferencias cuando existan.
Como la mayoría de los BASIC de la época, Atom BASIC utilizaba un editor orientado a líneas con modos directo (inmediato) e indirecto. Al escribir una sentencia sin un número de línea se realizaba la operación inmediatamente. Al añadir un número de línea, esas sentencias se colocaban en el programa almacenado. Una idiosincrasia era que, si bien permitía múltiples sentencias en una sola línea, el separador entre sentencias era el punto y coma [7] en lugar de los dos puntos de uso común, lo que requería que el usuario convirtiera ese carácter al escribir programas para otras computadoras.
Pensado para su uso con terminales de ordenador , Acorn BASIC no admitía un modo de edición de pantalla completa. Por el contrario, en Commodore BASIC (y muchos otros dialectos de microordenadores), se pueden utilizar las teclas del cursor para desplazarse hacia arriba en una lista de programas, realizar cambios en la pantalla y, a continuación, pulsar Returnpara introducir dichos cambios. En Atom, se podía desplazarse hacia arriba en una lista utilizando las teclas del cursor , pero para editar ese texto, se pulsaba la tecla para copiarlo al área de entrada donde se podía editar. [8]Copy
Otra diferencia en el Atom era la tecla, que realizaba un reinicio del sistema, borrando potencialmente el programa de la memoria. Para reiniciar esto si la tecla se presionaba por error, Atom BASIC agregó el comando, que también podía usarse para reiniciar un programa accidental . Un cambio menor fue que se usaban números de línea separados por comas en lugar del signo menos, lo que imprime las líneas 20 a 40. [9]BreakOLD
NEW
LIST
LIST 20,40
El lenguaje también tenía la capacidad de usar etiquetas de línea en lugar de números para la ramificación . Las etiquetas consistían en una sola letra minúscula escrita inmediatamente después del número de línea. Por ejemplo: [10]
10s IMPRIMIR "*"20 IR A
La ventaja de este método es que la dirección de memoria de la declaración se almacena en s, lo que significa que la rama, un GOTO, puede moverse directamente a esa línea sin tener que buscar en cada línea del programa el número de línea correspondiente. [10] Acorn también permitió que se usara cualquier expresión para producir el número de línea para los objetivos de la rama, como GOSUB 500+(A*10)
. [11]
Los primitivos de Acorn eran similares a otros BASIC de la época y admitían la mayoría de las sentencias elementales como CLEAR, DIM, END, FOR..TO..STEP..NEXT , GOSUB , GOTO , IF..THEN , INPUT, (opcional) LET, LIST, LOAD, PRINT, REM , RETURN , RUN, SAVE, STOP . [12] Hay una serie de sentencias comunes que faltan, en particular DATA, READ, RESTORE utilizadas para almacenar datos en un programa, ON..GOSUB, ON..GOTO ( ramificaciones calculadas ) y DEF FN para funciones definidas por el usuario. [a]
A estos conceptos básicos, Acorn les agregó DO..UNTIL
la construcción de bucles basados en expresiones y probados desde el punto de vista inferior. Los bucles FOR están altamente optimizados mediante una comparación directa entre su variable de índice y un valor constante que se establece solo una vez al ingresar al bucle. Otra optimización es que se almacena la dirección del FOR, no el número de línea, de modo que cuando se encuentra el NEXT coincidente, el programa puede volver inmediatamente al FOR. Si bien FOR es adecuado para muchos bucles, cuando se necesita más control, por ejemplo, al comparar con un criterio más complejo, se puede utilizar la declaración IF:
500 A = A + 1510 REM declaraciones adicionales aquí600 SI A>10 Y B>100 ENTONCES 500
La desventaja de este tipo de bucle es que la bifurcación requiere que se busque en el programa la línea 500, lo que, en un bucle, normalmente ocurre muchas veces. En programas grandes, esto puede generar una sobrecarga significativa. El uso de un DO para este propósito ofrece un mayor rendimiento:
500 HACER A=A+1510 REM declaraciones adicionales aquí600 HASTA A>10 Y B>100
En este caso, al igual que en el bucle FOR, la dirección del DO se almacena cuando se ingresa al bucle, lo que permite que UNTIL regrese al principio del bucle inmediatamente sin tener que escanear el programa. [14] Nótese el caso especial de que el DO puede ser seguido directamente por otra declaración sin que se requiera el separador de punto y coma: el A=A+1
no es parte del DO
, es una declaración separada. [15]
Entre las adiciones menores se encuentra la WAIT
declaración que pausa la ejecución hasta el siguiente tic del reloj, cada 1 ⁄ 60 de segundo. Esto no espera un tic completo, sino hasta el siguiente tic, que puede ocurrir inmediatamente. [14] LINK
llama a una rutina de lenguaje de máquina , [16] el análogo de CALL
o SYS
en la mayoría de los dialectos. [17]
Acorn utilizó números enteros con signo de 32 bits para todas las operaciones matemáticas, [18] sin compatibilidad con coma flotante estándar . Para manejar la división, que a menudo devuelve una parte fraccionaria, agregaron el %
operador para devolver el resto. Por ejemplo, PRINT 7/3
devolverá 2, mientras que PRINT 7%3
devolverá 1. [19]
Los nombres de las variables pueden constar de una sola letra, de la A a la Z. [20] Todas las combinaciones de dos letras están reservadas como matrices, por lo que E era un valor único, mientras que EE era una matriz. Todas las matrices requerían una declaración DIM, [21] no asumía una dimensión de 10 como los BASIC de Microsoft . En tiempo de ejecución, la única comprobación realizada en una matriz era que el índice que se pasaba fuera un valor positivo, por lo que se podía leer en la memoria pasando valores mayores que la dimensión. [22] No admitía matrices multidimensionales. [23]
Las operaciones matemáticas básicas incluían +, -, *, /, % . También admitía operadores lógicos bit a bit, como &, \, : utilizados para AND, OR y XOR, respectivamente. Estos operadores realizan comparaciones, por lo que devuelven 0. El uso de dos puntos para OR [b] es la razón por la que el separador de sentencias tenía que utilizar el punto y coma. [24] Tenga en cuenta que estos son independientes de las conexiones lógicas que se encuentran en las sentencias IF, como , que también son compatibles. [25]1 & 0
IF A=1 AND B=0 THEN...
Sólo había dos funciones matemáticas, ABS y RND . ABS funciona como en otros BASIC, devolviendo el valor absoluto de una entrada dada. RND no, devuelve un valor entre los valores enteros máximos -ve y +ve. Para utilizar esto en la forma convencional para devolver un valor entre 0 y un valor positivo dado, entre 0 y 10 por ejemplo, se utilizó . [26]ABS(RND)%11
La mayoría de los BASIC de la época utilizaban PEEK y POKE para acceder a funciones específicas de la máquina que no estaban integradas en el lenguaje en sí. Acorn no tenía PEEK ni POKE, y utilizaba nuevos operadores para proporcionar esta funcionalidad en un sistema más fácil de usar. Los operadores eran ?
y !
, el primero establecía o devolvía el byte en una ubicación determinada, y el segundo establecía o devolvía una "palabra" de 4 bytes. [27] Por ejemplo, ejemplos comunes de PEEK en la mayoría de los dialectos, como PRINT PEEK(4000)
, se podían lograr con PRINT ?4000
. [28] La mayoría de los dialectos carecían del equivalente de !. [c] Además, se podía utilizar la misma sintaxis para establecer el valor en la memoria, como un POKE, por ejemplo, ?4000=200
. [28]
Para facilitar el acceso a los datos dispuestos en forma continua en la memoria, como matrices de números, los operadores se podían aplicar al lado derecho de una variable. Cuando se utilizaban de esta manera, como A?
, el sistema accedía a la memoria en la ubicación de la variable en la memoria. Cualquier número que siguiera al operador se aplicaba como un desplazamiento, por lo que, por ejemplo, A?100
devolvería el valor del byte 100 posiciones después de la ubicación de A en la memoria. [28]
Esto se usaba a menudo con otro concepto exclusivo de Acorn, el "vector". Para confundir, estos se creaban utilizando los mismos comandos DIM que una matriz, pero aplicados a variables de una sola letra. Cuando se encontraba el DIM, el sistema reservaba esa cantidad de ubicaciones en la parte superior de la memoria y luego movía el puntero de memoria hacia arriba. Esto dejaba un bloque de memoria al que se podía acceder con los operadores de indirección. Por ejemplo: [28]
10 dimensiones A(100)20 IMPRIMIR A?10
Que imprimirá el valor del byte en la ubicación 11 en A (todos los accesos están indexados a cero). [28] De la misma manera, uno podría almacenar valores en la memoria usando el mismo operador aplicado antes del nombre de la variable:
!A=123456
Esto convertirá el valor decimal 123456 de ASCII en un entero y lo almacenará en las ubicaciones de memoria comenzando en la ubicación base de A. [27]
Para facilitar la operación con vectores, Acorn agregó la pseudovariable TOP
. Cuando el sistema se inició por primera vez, señaló la primera ubicación después del final del programa. Luego, se crearon todos los DIM con el valor actual de TOP y, luego, TOP se actualizó hasta el final del nuevo objeto. Fue posible crear vectores dinámicos manipulando directamente TOP. [30]
Atom BASIC agregó soporte para cadenas, pero no admitía variables de cadena ni tenía el concepto de cadena como un tipo atómico. En su lugar, se utilizó el sistema vectorial para manipular datos de cadena en memoria, como valores ASCII . [28] Para facilitar este uso, el $
operador convertía los valores en memoria a sus valores ASCII. Este operador continuaba leyendo datos de la memoria hasta que encontraba un retorno y, al escribir datos en la memoria, siempre agregaba un retorno al final. [31] Entonces, mientras que PRINT ?A
imprimiría el valor único del byte en la ubicación de A en la memoria como un número, PRINT $A
leería los valores a partir de esa ubicación y los imprimiría como una cadena. [31] Por ejemplo:
10 dimensiones A(12)20 $A="HOLA, MUNDO"30 IMPRIMIR $A
Este código puede parecer muy similar al uso de cadenas en otros dialectos, aunque la ubicación del $ en relación con el nombre de la variable cambia. Es especialmente similar a aquellos dialectos que requerían un DIM en todas las cadenas, como HP Time-Shared BASIC o Atari BASIC . Internamente, la operación es muy diferente. En esos dialectos, A y A$ son dos variables diferentes y el $ es, en efecto, parte del nombre. En Acorn, A y $A son la misma variable, y el $ está aplicando una operación unaria a esa variable. Esto también significa que uno puede usar matrices para cadenas, como $AA(10)
, que convierte el valor en AA(10) a una cadena. [3]
Este concepto permite acceder a caracteres individuales mediante notación vectorial. Por ejemplo, A?5
devolvería el valor ASCII del quinto carácter, 79 para O en este caso, mientras que PRINT $A?5
daría como resultado "O". [32] No hay forma de extraer una subcadena en una sola operación, hay que recorrer los caracteres uno por uno. La concatenación es posible asignando una variable al final de otra, por ejemplo, $A+LEN(A)=$B
copiando la cadena B al final de A. [33]
El lenguaje tiene sólo dos funciones de cadena, LEN
que buscan el carácter de retorno final y devuelven la longitud, y CH
devuelven el valor ASCII de un carácter. CH tiene un formato extraño sin paréntesis, por lo que CH"A"
devolvería 65. [32] Por lo demás, es similar al más común ASC
que se ve en otros dialectos. [34]
Otro operador nuevo era #
, que convertía un valor numérico en una cadena hexadecimal . Al igual que $, este operador se podía utilizar en cualquier lugar para realizar la conversión. Por ejemplo, A=#4000
establece el valor de A en el valor decimal 16384, la ubicación de la memoria de la pantalla. Esto se combinaba a menudo con el operador $ para permitir que las cadenas contuvieran caracteres no imprimibles, como el carácter de "cursor arriba". [8]
Se pudo añadir soporte de punto flotante con la expansión adicional de 4 KB de ROM. Esto utilizó un tamaño de palabra expandido de 40 bits, 32 bits de mantisa con signo seguidos de un exponente de 8 bits. [35] Esto significaba que el sistema necesitaba alguna forma de distinguir los datos al leer y escribir desde la memoria, lo que se manejaba de una manera similar al operador de cadena, utilizando el %
prefijo: [35]
%A=123,45
Como el código estaba contenido en una ROM separada de 4 KB, no modificaba las instrucciones existentes como PRINT. En cambio, se introdujo un conjunto completamente nuevo de instrucciones, que incluía FDIM, FIF, FINPUT, FPRINT, FUNITL . Esto significa, por ejemplo, que no se puede si los valores son de punto flotante, se debe en cambio . Un valor entero se puede convertir a flotante usando el operador , y flotante a entero usando el operador flotante, %. [27]IF A=B
FIF A=B THEN...
FLT
La ROM también incluía una variedad mucho mayor de funciones matemáticas, entre ellas ABS, ACS, ASN, ATN, COS, DEG, EXP, FLT, HTN, LOG, PI, RAD, SGN, SIN, SQR, STR, TAN, VAL . [36] convertía un número de punto flotante en una cadena, como era el caso de otros dialectos, pero en este caso, la cadena se escribía en la memoria y la función devolvía la dirección donde estaba almacenada. Como la cadena requería almacenamiento lo suficiente para contenerla, esto se lograba a menudo utilizando TOP. Por ejemplo: STR
STR$
STR PI, SUPERIOR IMPRIMIR $TOP TOP=TOP-LEN(TOP)
Esto convierte el valor de la pseudovariable PI en una cadena que comienza en la ubicación de memoria TOP, imprime la cadena usando $TOP y luego abandona esa memoria. [37]
PRINT
y INPUT
funcionaba principalmente como en otros dialectos. Una rareza surgió porque los dos puntos y el punto y coma ya se usaban para otros fines, dejando solo la coma para separar campos. Para imprimir valores sin espacios entre ellos, los valores se enumeraban con un carácter de espacio entre ellos, como PRINT A B C
, un formato que también se permitía en muchos otros dialectos aunque rara vez se usaba. Esto por sí solo no haría que los números se imprimieran en formato compacto, porque normalmente se imprimen con espacios a la derecha para que cada uno tenga 8 caracteres de ancho. Esto se podía ajustar cambiando el valor en la @
pseudovariable. [38] Una nueva línea se imprimía con una comilla simple, PRINT "HELLO" ' "WORLD"
. [27] COUNT
devuelve la columna del cursor, similar a POS
en la mayoría de los dialectos. [39]
El dispositivo de almacenamiento predeterminado para el Atom era un sistema de casete compacto . Cada archivo se almacenaba como una serie de bloques, cada uno de los cuales contenía un encabezado con el nombre del archivo. [40] Los archivos guardados con SAVE THISFILE
se podían volver a leer con LOAD THISFILE
, mientras que *CAT
enumeraba los nombres de los archivos en el casete a medida que leía más allá de sus encabezados. [41]
Se podían abrir datos arbitrarios para leerlos usando FIN
o escribirlos con FOUT
, y ambos devolvían un identificador de archivo numérico . Los archivos se cerraban con SHUT
. Los datos se leían o escribían en formato numérico usando GET, PUT
, como bytes individuales con BGET, BPUT
, y como cadenas usando SGET, SPUT
. El EXT
devolvía la longitud del archivo, mientras que PTR
devolvía o establecía el puntero actual en el archivo, [16] el número de bytes leídos o escritos hasta el momento. [42] Si la ROM de punto flotante estaba presente, añadía FGET, FPUT
. [36]
Por ejemplo:
A=FUERA"ARCHIVO"HAGA BPUT A,88; ESPERE; ESPERE; ESPERE; ESPERE; HASTA 0
Se utilizará BPUT
para escribir una serie de bytes, 88 s, hasta que el usuario presione para detener el programa. Luego se pueden volver a leer (después de rebobinar manualmente la cinta) utilizando: [43]Escape
A=FIN"ARCHIVO AFILE"IMPRIMA $BGET A; HASTA 0
El signo de dólar le indica al sistema que convierta los datos binarios entrantes a formato de cadena, por lo que en este caso, la salida será una serie de X, no 88. [43] Puede parecer que se podría utilizar SGET en lugar de BGET, pero esto intentaría continuar leyendo el archivo hasta que viera un carácter de retorno, que en este ejemplo no se había escrito. [44]
El Atom tenía gráficos de mapa de bits rudimentarios y Atom BASIC agregó una serie de comandos para respaldarlo. CLEAR
Limpiaba la pantalla, MOVE
movía el cursor gráfico a la ubicación X,Y dada y DRAW
dibujaba una línea desde la ubicación actual hasta la X,Y proporcionada. [45]
La ROM de punto flotante también incluía soporte para gráficos en color con la incorporación de la COLOUR
instrucción. Al llamar a COLOUR con un parámetro de 0 a 3, se establece la salida subsiguiente en ese color. En una pantalla en blanco y negro, los colores se mostraban como tonos de gris. [46]
DPEEK
"double peek", que devolvían un valor de 16 bits. Estos son similares en concepto a !. [29]