Wang BASIC es una serie de lenguajes de programación BASIC para computadoras de Wang Laboratories . El término puede usarse para referirse al BASIC en cualquier máquina Wang, pero se asocia principalmente con las versiones de la serie de minicomputadoras Wang 2200 de principios de la década de 1970. Cuando estas máquinas se actualizaron a la serie VP en 1976, se introdujo BASIC-2 y siguió siendo el patrón para futuras máquinas de la serie 2200. Un BASIC-3 planeado nunca fue lanzado.
Wang ofreció varios modelos de cada versión de la serie 2200, diferenciándose sólo en la cantidad de microcódigo almacenado en la memoria de sólo lectura (ROM) y, por tanto, en la cantidad de comandos disponibles en BASIC en esa máquina. Por ejemplo, las máquinas modelo B se diferenciaban del modelo base A al duplicar la ROM y usarla para almacenar una variedad de comandos de entrada/salida y administración de archivos.
Wang BASIC siguió de cerca el Dartmouth BASIC original en sintaxis, pero era un intérprete en lugar de un sistema de compilación y listo . Una característica notable fue que todas las matemáticas utilizaban el formato decimal codificado en binario (BCD) de doble precisión , lo cual era inusual para los BASIC de la época. [a] Carecía de muchas características comunes a dialectos posteriores como Microsoft BASIC , pero muchas de estas características se agregaron en BASIC-2.
La siguiente descripción se basa en el BASIC original que se encuentra en el 2200A. No todas las instrucciones que se enumeran a continuación estarán disponibles en el modelo base; 2200B y C agregaron docenas de palabras clave nuevas y se describen por separado a continuación.
El Wang BASIC original para el 2200 es una versión relativamente estándar del concepto Dartmouth BASIC y resultará familiar para los usuarios de cualquier intérprete BASIC común como Microsoft BASIC . Como la mayoría de los intérpretes de BASIC, Wang BASIC operaba en modo inmediato o modo de programa , cambiando al último cuando se ve un número de línea al comienzo de la línea cuando EXECse presiona la tecla (retorno). Los números de línea iban del 0 al 9999. Las líneas podían tener hasta 192 caracteres, abarcando varias líneas en pantalla, [1] y las líneas podían contener múltiples declaraciones separadas por dos puntos. [2] Para ayudar a organizar programas grandes, el lenguaje incluía un RENUMBER
comando. [3]
LIST
se utilizó para mostrar el código fuente del programa, mientras que LIST S
solo se mostraban las primeras 15 líneas y luego se pausaba. Cuando estaba en pausa, al presionar la tecla EXEC se mostraban las siguientes 15 líneas. [4] SAVE "filename"
guardó el programa actual en un casete y LOAD "filename"
lo volvió a leer. SKIP 2F
Leería los siguientes dos archivos encontrados en la cinta de casete y luego se detendría, permitiendo que un archivo posterior LOAD
o SAVE
trabajara en el tercer archivo. [5] BACKSPACE
era lo opuesto a SKIP, rebobinar el puntero del archivo. Trabajar con almacenamiento en disco fue un poco más complejo, usando LOAD DC F "filename"
, donde F se refería a una de varias unidades predefinidas, en este caso "Fijo". [6]
RUN
inició la ejecución y podría dirigirse a una línea particular, como en RUN 100
. El STOP
comando, normalmente utilizado para la depuración, permitía una siguiente cadena opcional que se imprimió cuando se realizó esa declaración. [7] TRACE
podría usarse para imprimir líneas a medida que se ejecutaban, lo que a menudo se usaba junto con las teclas personalizadas (interrupción) y del teclado para moverse línea por línea a través de un programa. [8] se utilizó para establecer un retraso entre líneas en unidades de 1 ⁄ 6 segundos; establecer el retraso en cero, provocaría una pausa de 1 ⁄ 2 segundo después de cada línea. [9]HALTSTEP SELECT P
TRACE
SELECT P0
SELECT P3
No había ningún NEW
comando para borrar la memoria de un programa existente, [10] en lugar de eso se usaba CLEAR
para restablecer la memoria. [11] CLEAR P
(para el programa "P") era el equivalente a NUEVO pero agregaba números de línea opcionales desde y hacia, [12] eliminando solo ese rango de líneas de una manera similar al DELETE
comando visto en algunos dialectos. CLEAR V
borra valores variables, [13] normalmente logrado CLR
en la mayoría de los dialectos. [14] CLEAR N
era similar a CLEAR V, pero no borraba el valor de las variables compartidas (ver más abajo). [12]
La ramificación fue admitida a través de IF...THEN
, GOTO
y GOSUB
. La forma alternativa, GO TO
no fue admitida. Una limitación de Wang BASIC, como también en el caso del Dartmouth original, es que la cláusula THEN de una declaración IF solo puede ser un número de línea, a diferencia de los dialectos más modernos que permiten cualquier declaración después de THEN. También carecía de conjunciones booleanas como AND
o OR
, por lo que la prueba solo podía tener una comparación única. [15]
Una adición interesante al lenguaje fue la idea de rutinas con nombre. La implementación se basó en la DEF FN
declaración seguida de una comilla simple y luego un número del 0 al 255, por ejemplo DEFFN' 1
. Entonces esto podría llamarse usando GOSUB '1
. Para confundir aún más las cosas, la línea DEFFN era una verdadera definición de función y podía usar parámetros, como DEFFN'5(A$, N)
, que podían llamarse con GOSUB'5("hello", 4)
. Permite implementar definiciones de funciones de varias líneas, que otros dialectos a veces ofrecían usando el estilo de función convencional en lugar de usar GOSUB. [16] Además, se asignaron rutinas con nombre en el rango de 0 a 31 a teclas con números similares en el teclado 2200, lo que permitió llamarlas directamente con una sola pulsación de tecla. [17]
PRINT
parámetros de separación admitidos por coma y punto y coma; el primero mueve el cursor a la siguiente columna de 16 caracteres de ancho y el segundo deja el cursor al final del valor impreso. Admitía la TAB()
función, pero no SPC()
. Al igual que otros BASIC de "alta gama" de la época, Wang BASIC ofrecía salida formateada con PRINTUSING
una "imagen" separada. La imagen se definió usando una línea separada que comenzaba con el signo de porcentaje, por ejemplo, 180 % ##,###.##
y luego usaba ese formato con 190 PRINTUSING 180, N
. [18] Cualquier carácter que no sea el de formato se repitió durante la impresión, por lo que se podría definir una salida completa con algo como 180 % ANGLE= #.#### RADIANS
. [19]
INPUT
Las declaraciones podrían incluir un mensaje, junto con una lista delimitada por comas de una o más variables. No se podían utilizar punto y coma en INPUT y el cursor siempre permanecía al final del último elemento impreso durante la entrada. [20]
Como la mayoría de los dialectos de la época, los nombres de las variables podían consistir en una sola letra mayúscula o una letra seguida de un solo dígito. No admitía nombres de dos letras. [21] Se podrían establecer varias variables en un valor inicial utilizando una lista separada por comas, por ejemplo, LET A,B,C=1
. Como ocurre con la mayoría de los BASIC, LET
siempre fue opcional. [22] Las variables se pueden convertir en listas (matrices unidimensionales) usando DIM
, como en DIM A(5)
el cual se hizo una lista de 5 valores numéricos. [23] o matrices bidimensionales usando DIM B(5,5)
. [24]
Los operadores relacionales incluían el conjunto estándar de =
, <
, >
, <>
y . [25] Las funciones trigonométricas incluyeron , , , , , , y . [26] era un alias de ARCTAN. [27] Las funciones trigonométricas normalmente operan en radianes , pero se pueden configurar para usar grados usando o gradianes usando , volviendo a radianes con . Otras funciones incluyeron , , , [28] y la pseudovariable. [29]<=
>=
SIN
COS
TAN
ARCSIN
ARCCOS
ARCTAN
LOG
EXP
SQR
ATN
SELECT D
SELECT G
SELECT R
INT
ABS
SGN
RND
#PI
A diferencia de la mayoría de los BASIC, la RND
función no trataba el parámetro como un marcador de posición; cualquier valor distinto de cero lo hacía funcionar como el RND visto en otros BASIC, mientras que un valor de cero reiniciaba la secuencia numérica de la misma manera que la RANDOMIZE
declaración vista en otros BASIC. [29] Esta es una fuente potencial de errores al realizar la portabilidad desde otros dialectos, que generalmente ignoraban el parámetro y a menudo usaban cero como parámetro simplemente como un marcador de posición común. [b]
Se admitían variables de cadena y se admitía la concatenación mediante el operador más. A diferencia de los BASIC posteriores que usaban cadenas de longitud dinámica en un montón, como Microsoft, Wang BASIC configuró todas las cadenas en una longitud predeterminada de 16 caracteres e ignoraría cualquier carácter asignado más allá de eso. [c] Los caracteres no utilizados al final de una cadena se llenaron con caracteres de espacio y los espacios finales se ignoraron en las declaraciones PRINT, [30] lo cual es otra fuente potencial de problemas al transferir código a Wang BASIC.
La longitud de almacenamiento de cualquier cadena individual podría cambiarse usando la DIM
declaración, que en este caso usó la sintaxis ligeramente extraña de colocar la longitud inmediatamente después del nombre de la variable, como DIM A$40
, [31] en lugar de usar paréntesis como en una declaración DIM típica. [32] Las cadenas tenían una longitud máxima de 64 caracteres. [33] La sintaxis permitía listas de cadenas, por ejemplo, DIM A$(5)
hacía una lista de 5 cadenas con la longitud predeterminada de 16 caracteres, mientras que DIM B$(10)20
hacía una lista de 10 cadenas de 20 caracteres. [34]
Había un pequeño conjunto de funciones de cadena. es un comando de división de matricesSTR
de uso general que reemplaza el estilo DEC/Microsoft // . Por ejemplo, devuelve los cinco caracteres de A$ comenzando en el carácter 10. [35] El segundo parámetro era opcional y devolvía todo desde el quinto carácter en adelante. devolvió la longitud de la cadena, ignorando los espacios finales, por lo que devolvería 3. [36] Para confundir aún más las cosas, las variables de cadena vacías siempre devolvieron una longitud de 1. [37] Tenga en cuenta que las funciones de cadena no incluyen el $, en contraste a la mayoría de los BASIC donde estas funciones se nombrarían , por ejemplo, indicando que el valor de retorno es una cadena, no un valor numérico. [38]MID
LEFT
RIGHT
STR(B$,10,5)
STR(C$,5)
LEN
LEN("ABC ")
STR$
De acuerdo con el modelo de Dartmouth, Wang BASIC incluía DATA
declaraciones para almacenar constantes dentro del código del programa, y estas se leían usando la READ
declaración, que comenzaba en el primer elemento de datos y luego movía un puntero hacia el siguiente elemento con cada LECTURA. RESTORE
podía restablecer el puntero LEER y se amplió desde la versión original de Dartmouth al permitir que el puntero se estableciera en un elemento particular de la lista, por ejemplo, RESTORE 10
que lo establecía en el décimo elemento. Sólo se podían ingresar 256 valores en declaraciones de DATOS en total en un programa. [39]
La SELECT
declaración podría usarse para redirigir la salida de otros comandos BASIC a otros dispositivos, según la "dirección" del dispositivo. Por ejemplo, SELECT PRINT 215
enviaría la salida de declaraciones PRINT posteriores a la impresora en la dirección 215, mientras SELECT PRINT 005
devolvía la salida al CRT integrado. SELECT LIST 215
haría lo mismo para las siguientes declaraciones LIST. [40] SELECT también tenía un siguiente parámetro opcional para establecer la longitud máxima de línea, como SELECT PRINT 215 (132)
. Se podría usar SELECT con una variedad de dispositivos predefinidos, como CI para "entrada de consola" (normalmente el teclado) o LIST para redirigir la lista de programas a un dispositivo diferente. [40]
Como las máquinas de la época tenían cantidades de memoria muy limitadas, la mayoría de los dialectos de BASIC incluían alguna forma de "encadenar" programas para permitir que un solo programa se dividiera en módulos más pequeños. En Wang BASIC, esto se logró con las declaraciones COM
y LOAD
. [41]
COM
declaró una o más variables como "comunes", [d] o globales en la terminología moderna. Un programa que utiliza encadenamiento normalmente declararía una cantidad de variables como comunes cerca de la parte superior del código, tal vez COM A,B,I,A$20
. [42] Cuando se CARGA un módulo de programa independiente, los valores de estas variables no se borrarán, a diferencia de las variables no comunes que se restablecerán. Las variables comunes se pueden borrar explícitamente usando CLEAR V
, mientras que CLEAR N
borra las variables no comunes y deja las variables comunes en paz. Las variables también podrían declararse no comunes usando COM CLEAR
, que restablece todas las variables comunes a la normalidad, o COM CLEAR A
para restablecer solo el estado de A. Confusamente, COM CLEAR también restablece cualquier otra variable COM definida antes de A, por lo que los resultados de COM CLEAR A serían diferente si el programa original usaba COM S,B,A
o COM A,B,S
, en el primer ejemplo se restablecerían los tres mientras que en el segundo solo se restablecería A. [43]
El comando LOAD también se utilizó para encadenar. Opcionalmente, se podrían agregar números de línea de inicio y fin, en cuyo caso se eliminarían las líneas existentes entre esos límites, o desde la línea de inicio hasta el final del programa si solo se especificara un número. Luego, el nuevo programa se carga en ese punto y la ejecución comienza en el número de línea de inicio, o al inicio del programa si no se especificó ninguna línea de inicio. [44]
El Wang BASIC original vino en varias versiones que se diferenciaban en la cantidad de microcódigo basado en ROM y, por lo tanto, en la cantidad de palabras clave admitidas.
BASIC en el 2200B fue una expansión importante de la versión 2200A. Las adiciones generalmente se pueden clasificar en cuatro categorías; características faltantes, comandos de cadena adicionales, comandos similares a vectores y entrada/salida. Las diferencias entre las versiones se pueden encontrar en forma de tabla en el documento de descripción general del 2200. [45]
Las características faltantes que se abordaron en 2200B incluyeron la adición de ON...GOTO
[46] y ON...GOSUB
. [47] KEYIN
lee un carácter del teclado sin pausa, similar a INKEY$
MS BASIC. VAL
buscó una cadena y devolvió un valor numérico dentro de ella. La NUM
función era similar a LEN, pero devolvía la longitud de la subcadena hasta el primer carácter no numérico. Por ejemplo, si A$ es "1234,5", NUM(A$)
devolvería 6, mientras que si A$ fuera "1234,5" , NUM devolvería 10, porque los espacios son válidos en los números. [48]
2200B no agregó una función STR$, que convierte un valor numérico en una cadena. En cambio, agregaron el CONVERT
comando para leer cadenas en números y viceversa. Por ejemplo, usar A$ arriba, CONVERT A$ TO B
daría como resultado que B contuviera el valor 1234.5, mientras que CONVERT 123 TO B$
B$ dejaría algo como "123". [49] Dartmouth BASIC incluía un comando CAMBIAR, pero su propósito era muy diferente: en Dartmouth, CHANGE A$ TO B
produciría una matriz de valores en B, y cada elemento contendría el código ASCII para el carácter correspondiente en A$; en este caso, B contendría 49,50,51,52,46,53, los valores ASCII para los caracteres "1234,5". CONVERT de Wang también tenía un segundo modo que tomaba un especificador de formato como PRINTUSING y lo usaba para convertir un número en una cadena formateada de una manera análoga a sprintf de C. [49]
La POS
función devuelve el índice de un carácter determinado en una cadena; POS("HELLO WORLD", "L")
devolvería 3. A diferencia de MS INSTR
, POS podría buscar solo un carácter, no una cadena de varios caracteres.
HEX
convirtió un valor hexadecimal en el carácter correspondiente. Por ejemplo, A$=HEX(20)
pondría un carácter de espacio (hexadecimal 20) en el primer carácter de A$. [50] Se podrían insertar varios códigos a la vez; PRINT HEX(080809)
produce tres caracteres, dos retrocesos y un cursor hacia la derecha. [51] HEX es la contraparte de la función ASC que se encuentra en la mayoría de los BASIC, [52] pero utiliza una entrada hexadecimal en lugar de un número decimal. BIN
Hizo lo mismo con los números binarios. [37]
Se agregó un comando de propósito especial para completar una cadena con un valor inicial que no es un espacio. INIT ("X") A$
llenaría A$ con X caracteres, mientras que INIT (41) B$
pondría el valor hexadecimal 41, el carácter A, en B$. [53]
2200B también incluía una serie de comandos que funcionaban en forma de vector para realizar tareas comunes que normalmente se llevarían a cabo mediante un bucle o, en las versiones de Dartmouth, comandos matemáticos matriciales. Por ejemplo, ADD
tomó una lista de expresiones, las sumó y devolvió el resultado. Esto se logró mucho más rápido que lo mismo expresado usando una expresión infija; A=ADD(B,C,D)
se completaría más rápido que A=B+C+D
. Comandos similares fueron OR
, AND
y XOR
.
La mayoría de las adiciones en 2200B estaban relacionadas con la entrada/salida, y principalmente con el trabajo con archivos de disquete. Introdujo el concepto de tener varios tipos de archivos diferentes, incluido el archivo de datos, indicado con el prefijo "DA" en los comandos del archivo. Una variedad de otros comandos admitían trabajar con estos archivos, incluido COPY
duplicar un archivo, MOVE
dentro de un archivo, VERIFY
archivos y SCRATCH
borrar un archivo o SCRATCH DISK
borrar todo.
A diferencia de la versión 2200B, que fue una expansión importante del 2200A, el 2200C tenía un alcance mucho más limitado. Agregó el COM CLEAR
comando para borrar variables compartidas, una versión de DEFFN'
ese hexadecimal devuelto, RETURN CLEAR
que se usó para "sacar" un GOSUB de la pila, [47] y ON ERROR
para detectar errores dentro del programa.
Los modelos posteriores de la serie agregaron algunos o todos los comandos en las versiones B o C, pero solo el 2200T los amplió. Lo más notable en las expansiones fue la adición de matemáticas matriciales, pero también se agregaron algunos detalles de E/S.
Los comandos matemáticos matriciales eran en gran medida idénticos a los que se encuentran en versiones posteriores de Dartmouth BASIC. Por lo general, estos tomaban la forma de una asignación, como LET, pero reemplazando el LET con MAT
. Por ejemplo, MAT A=B+C
produciría una matriz A cuyos elementos fueran las sumas de los elementos correspondientes en la matriz B y C. [54] Otros comandos matriciales incluyen INV
ert, para la IDN
matriz identidad y ZER
para la matriz cero, y varias utilidades como COPY
, MERGE
y . [45]MOVE
SORT
La introducción del conjunto de instrucciones completamente nuevo del 2200VP requirió que se escribiera un BASIC completamente nuevo desde cero. Si bien el objetivo principal era la compatibilidad con versiones anteriores , el nuevo BASIC-2 también agregó una serie de características que faltaban. El cambio más notable fue que BASIC ya no se almacenaba en la memoria de sólo lectura (ROM) y en su lugar se cargaba desde el disco en el momento del arranque, lo que permitía parchearlo fácilmente en el campo para corregir errores. También fue mucho más rápido, unas ocho veces, debido a que se centró en el rendimiento más que en el tamaño, y al mejor rendimiento de la plataforma VP. [55]
Las declaraciones IF eran limitadas en la versión original y se mejoraron significativamente en BASIC-2. Se agregaron conjunciones booleanas, lo que permitió pruebas más complejas como La declaración que sigue a ENTONCES ya no tenía que ser un GOTO implícito, lo que permitió declaraciones comunes como . Se añadió una cláusula que debía seguir a dos puntos; . ELSE también podría usarse con declaraciones ON; pasaría a las líneas 10, 20 o 30 si el valor en X fuera 1, 2 o 3, mientras que cualquier otro valor pasaría a 100. [55]IF X=5 AND Y=10 THEN...
IF X=10 THEN PRINT "IT IS TEN"
ELSE
IF X=10 THEN PRINT "IT IS TEN":ELSE PRINT "IT IS NOT TEN"
ON X GOTO 10,20,30:ELSE 100
Las nuevas funciones incluyen FIX
, que siempre se redondea hacia cero en lugar de INT, que siempre se redondea hacia abajo; FIX(-4.5)
devuelve -4, mientras que INT(-4.5)
devuelve -5. ROUND(value,num)
es similar a FIX pero se redondea al decimal proporcionado en el segundo parámetro. MOD
realiza una división de enteros y devuelve el resto. MAX(a,b,c...)
y MIN(d,e,f...)
devolvió el valor entre la lista de entradas con el valor más alto o más bajo. LGT
devuelve el registro en base 10 del valor. VER
comprueba si la cadena en el primer parámetro coincide con el formato en el segundo, el formato era el mismo que PRINTUSING. [55]
PRINTUSING ahora podría generar una cadena; PRINTUSING TO A$, "#.##", SQR(3)
formatearía la raíz cuadrada de tres a dos decimales y pondría el resultado en A$. Se agregaron varias pseudofunciones nuevas a PRINT; la AT(X,Y)
función era similar en concepto a TAB, pero movía el cursor a la ubicación X, Y, BOX(W,H)
dibujaba un cuadro del ancho y alto dados con la esquina superior izquierda en la posición actual del cursor y HEXOF(v)
devolvía el valor hexadecimal. [55]
El tamaño de cadena predeterminado no cambió, pero el tamaño máximo aumentó de 64 a 124 caracteres. Las dimensiones máximas de la matriz aumentaron de 255 a 65535 elementos. [55]
En marzo de 1977, Wang anunció una versión ampliada del sistema VP que incluía más memoria, hasta 256 KB, y un sistema de servidor de terminales para permitir que una sola máquina admitiera hasta doce terminales. Conocidas como 2200MVP, las primeras unidades se enviaron en enero de 1978. Los modelos LVP de cuatro usuarios y SVP de un solo usuario de la misma máquina se enviaron en 1980. [56]
El 2 de abril de 1981, en la Feria de Hannover , Wang anunció una importante actualización del microcódigo de la serie MVP. La opción "C" de $ 2000 agregó un compilador COBOL así como una versión actualizada de BASIC, BASIC-3. En ese momento, esperaban lanzarlo en forma beta en agosto y para todos los clientes en noviembre. [57] El sistema se envió a un pequeño número de sitios para realizar pruebas beta, pero nunca se lanzó. [58]
RND(0)
ampliamente.COMMON
.