Nociones de BASIC
Nociones de Basic
(Tomado de los apuntes de la asignatura "Periféricos" de Ingeniería Técnica en Informática de Sistemas, Universidad de Alicante, por Javier Gil Chica, 1995).
1.- ELEMENTOS
1.1. Introducción.
BASIC nació en la Universidad de Hannover en 1969 como un intérprete apto para todos los públicos, incluso personas sin relación directa con la informática. Desde entonces se ha ramificado en multitud de versiones, y durante un tiempo llegó a dominar de forma hegemónica como lenguaje de "todo uso".
La evolución de los ordenadores, mas rápidos, capaces y baratos, impulsó la creación de software de complejidad creciente a lo que BASIC temporalmente no pudo hacer frente de forma competitiva ante compiladores de lenguajes estructurados como Pascal o C.
Puede decirse que el compilador BASIC llegó tarde, y cuando se ha querido reaccionar en los últimos años, incluyendo una versión estructurada, QBasic 1.1, en la entrega 5.0 del sistema operativo de Microsoft, BASIC ya tenía muy poco que hacer en el mercado del DOS frente a productos de la calidad de Turbo Pascal de Borland, por ejemplo.
Sin embargo, el impulso de los entornos gráficos y la complejidad de la programación en Windows han abierto hueco a la programación visual, espacio en el que VisualBasic brilla por su potencia y facilidad de uso. En su última versión va mas allá, incluyendo funciones de base de datos, política reforzada por el hecho de existir en el mercado aplicaciones que incorporan VB como lenguaje de macros.
Daremos aquí un repaso somero y rápido al BASIC standard.
1.2. Tipos de datos básicos.
El siguiente gráfico refleja concisamente los tipos de datos básicos del lenguaje:
TIPOS DE DATOS
NUMERICOS CADENA
REALES ENTEROS LONGITUD FIJA LONGITUD VARIABLE
a su vez, los datos numéricos pueden ser de simple o de doble precisión.
Existen dos formas principales de declarar las variables:
a) por el carácter final del nombre
% indica entero simple
& indica entero doble
! indica real simple
# indica real doble
$ indica cadena de longitud variable
b) a través del modificador AS
COMMON, SHARED o STATIC. Los distintos tipos de AS son
AS INTEGER entero simple
AS LONG entero doble
AS SINGLE real simple
AS DOUBLE real doble
AS STRING cadena de longitud variable
AS STRING * numero cadena de longitud fija
AS var_def_us variable definida por usuario
1.3. Operadores
BASIC incorpora los operadores habituales de todos los lenguajes:
a) Numéricos
+ suma
- resta
* multiplicación
/ división
^ exponenciación
\ división entera
MOD resto
b) Alfanuméricos. Solo se incluye el operador + de concatenación de cadenas
c) Relacionales
= igual
<> distinto
> mayor
>= mayor o igual
< menor
<= menor o igual
d) Lógicos
AND
OR
NOT
XOR
IMP
EQV
Las tablas de verdad de los operadores menos conocidos son las siguientes:
A B A EQV B A IMP B
V V V V
V F F F
F V F V
F F V V
1.4. Variables multidimensionales
Las variables multidimensionales se declaran mediante la sentencia DIM, cuya sintaxis es
DIM <nombre_variable> (rango)
donde <nombre_variable> es un nombre de variable que normalmente incluye como último carácter aquél que determina su tipo y (rango) indica el n
a) Un número simple n, lo que indica los n+1 elementos 0..n
b) p to q, donde p es el primer índice y q el último
c) (rango1,rango2,...rangon) para declarar matrices cuadradas, cúbicas, etc.
Ejemplos:
DIM matriz! (1 to 20, 1 to 20)
DIM pesos! (40)
DIM tensor! (2,2,2)
El tipo de elementos de la variable se puede definir mediante el modificador AS
DIM Lista$ (100) AS STRING*20
1.5. Variables tipo registro.
El usuario puede definir variables tipo registro, donde bajo el mismo nombre se engloba información relacionada pero de naturaleza diferente. La sintaxis de este tipo de declaraciones es la siguiente:
TYPE nombre_del_tipo
nombre_variable1 AS tipo1
nombre_variable2 AS tipo2
.
.
.
END TYPE
Por ejemplo:
TYPE Tordenador
procesador AS string*5
RAM AS integer
HD AS integer
precio AS real
END TYPE
Una vez definido el tipo, pueden declararse variables de dicho tipo mediante DIM, como se muestra a continuación:
DIM miordenador AS Tordenador
DIM INTERNET(1,2000) AS Tordenador
1.6. Funciones numéricas y de cadena de caracteres.
BASIC incorpora las funciones numéricas habituales:
- SEN seno
- EXP exponencial
- COS coseno
- LOG logaritmo
- TAN tangente
- RND número aleatorio
- ATN arco tangente
- ABS valor absoluto
- SQR raiz cuadrada
y algunas otras como FIX, INT y CINT cuyas sintaxis y acciones pueden consultarse en la ayuda en línea de Qbasic.
En cuanto a las funciones de manejo de cadenas, las mas habituales son:
- VAL devuelve el valor numérico de una cadena
- STR$ convierte un número en una cadena de caracteres
- HEX$ convierte decimal a hexadecimal
- LEN devuelve la longitud de una cadena
- STRING$ genera una cadena repitiendo un carácter
- SPACE$ genera una cadena de espacios en blanco
2.- ESTRUCTURAS DE CONTROL
El BASIC clásico controlaba el flujo del programa mediante sentencias como GOTO, GOSUB o ON...GOTO, poco apropiadas para programar estructuradamente. Actualmente se cuenta con instrucciones de control de flujo similares a las de otros lenguajes.
2.1. Ejecución condicional.
Se consigue mediante la sentencia IF.
Su sintaxis es:
IF condicion THEN
Se puede usar en combinación con ELSEIF:
IF condicion1 THEN
bloque de sentencias 1
ELSEIF
bloque de sentencias 2
ENDIF
Pueden escribirse tantos ELSEIF como se desee, pero cuando hay varias posibilidades, es mejor usar la sentencia SELECT CASE, según el modelo siguiente:
SELECT CASE expresion
CASE valor1
bloque 1
CASE valor2
bloque 2
CASE valor 3
bloque 3
CASE ELSE
bloque alternativo
END SELECT
2.2. Bloque repetitivos.
La instrucción FOR..NEXT ejecuta un bloque de sentencias un número determinado de veces. Su sintaxis es
FOR contador=inicio TO final (STEP incremento)
bloque
NEXT contador
donde inicio es el valor inicial del contador, fin su valor final y opcionalmente podemos especificar el incremento del contador en cada iteración.
Un grupo de sentencias puede ejecutarse mientras se cumple una determinada condición, o hasta que se cumpla una determinada condición. En el primer caso, se escribe
DO WHILE condicion
bloque
LOOP
y en el segundo
DO UNTIL condicion
bloque
LOOP
En estos dos casos, la condición se evalúa antes de ejecutar el bloque de sentencias. Cuando WHILE o UNTIL se sitúan al final del bloque, tras LOOP, la condición se evalúa después de ejecutar el de ejecutarse el bloque de sentencias:
DO
bloque
LOOP WHILEUNTIL condicion
Es posible forzar la salida del bloque mediante la instrucción DO EXIT. La sintaxis habitual es:
DO
bloque
IF condicion2 THEN DO EXIT
LOOP WHILEUNTIL condicion1
La sentencia WHILE..WEND no es necesaria, dada la flexibilidad de la construcción DO..LOOP.
3.- PERIFERICOS Y FICHEROS
3.1. Pantalla.
La sentencia mas habitual es PRINT, que se usa para escribir textos en pantalla. Sus argumentos pueden ser numéricos o de cadena. Puede tener uno, varios o ninguno de ellos, en cuyo caso se escribe una línea en blanco. Los argumentos pueden ir separados por ";" en cuyo caso se escriben uno a continuación de otro, o por ",", y entonces entre el primer carácter de un argumento y el primer carácter del siguiente hay 14 columnas. Un control mas preciso se consigue con la sentencia PRINT USING. Su sintaxis puede buscarse en la ayuda en línea de Qbasic.
La instrucción LOCATE coloca el cursor en una fila y columna determinadas. Puede especificarse si el cursor está visible o nó, así como su tamaño. La sintaxis es
LOCATE fila, columna, cursor, inicio, fin
donde cursor especifica si está visible, 1 o no, 0 e inicio y fin indican la primer y última líneas de exploración del cursor, empezando por la parte inferior.
Otras instrucciones útiles son CSRLIN, que devuelve la línea actual del cursor, y POS, que devuelve la columna actual.
3.2. Teclado.
La forma usual de obtener respuestas a través de teclado es mediante la sentencia INPUT , que permite leer uno o varios datos, que se almacenan en la lista de variables especificadas en la sentencia.
INPUT "Mensaje_optativo" listavariables
Mensaje_optativo es un mensaje que aparece antes de que se introduzcan los datos, haciendo en general referencia a su naturaleza. Si tras él se escribe ";" aparecerá un signo de interrogación.
listavariables es una lista con las variables a leer, separadas por comas.
La sentencia LINE INPUT permite leer desde teclado o fichero una línea de texto. El texto introducido no necesita comillas dobles y puede incluir comas simples, sin que esto signifique que se están introduciendo varias cadenas. Su sintaxis es
LINE INPUT "Texto opcional"; variable$
Tanto INPUT como LINE INPUT esperan la pulsación de
3.3. Ficheros.
Los ficheros en BASIC pueden ser de acceso secuencial o aleatorio. Pueden estar organizados en líneas o en registros, o pueden ser vistos como una simple sucesión de bytes. Se abren con la sentencia OPEN y se cierran con CLOSE. Cuando se abre un fichero, se asigna un "canal" de comunicación con él. Puede haber varios canales abiertos simultáneamente, dependiendo el número máximo de la configuración de nuestro sistema. La sintaxis de OPEN es:
OPEN "nombre_archivo" FOR <modificador> AS #X
donde
a) Para archivos de acceso secuencial
-
INPUT solo lectura
-
OUTPUT solo escritura
- APPEND añadir registros
b) Acceso directo
- RANDOM lectura y escritura
c) Modo binario
- BINARY lectura y escritura
Por ejemplo, para crear un archivo de texto en el que vamos a escribir registros:
OPEN "Datos.txt" FOR OUTPUT AS #1
Los ficheros de acceso secuencial están formados por líneas, delimitadas por el carácter salto de carro. Cada una de ellas contiene una o mas variables, que pueden ser campos de una variable de tipo registro.
Para escribir en un fichero abierto para escritura, se usa la sentencia WRITE, con la sintaxis WRITE #X, variable$, donde X es el número del canal y las variables van separadas por ",".
Para leer registros de un fichero secuencial, este se abre con el modificador INPUT. La sentencia que permite leer línea por línea es INPUT, y su sintaxis es:
INPUT #X, variable(s)
donde X es el número de canal y las variables van separadas por comas. Con LINE INPUT #X, variable$ se lee una línea completa del archivo, incorporando todos los registros a una única variable de texto. Como ejemplo, el siguiente fragmento introduce líneas desde teclado para después leer línea a línea y escribirlas en pantalla:
OPEN "FileBas.txt" FOR OUTPUT AS #1
DO
LINE INPUT linea$
WRITE #1, linea$
LOOP UNTIL linea$=" "
CLOSE #1
OPEN "FileBas.txt" FOR INPUT AS #1
DO UNTIL EOF(1)
INPUT #1, linea$
PRINT linea$
LOOP
CLOSE #1
Ejemplo: Escribir un archivo de texto conteniendo en cada línea el nombre, dirección y teléfono de una persona. Recuperar después esa información y exponerla en pantalla:
OPEN "FileBas.txt" FOR OUTPUT AS #1
DO
INPUT nombre$
INPUT edad$
INPUT telefono$
WRITE #1, nombre$,edad$,telefono$
LOOP WHILE telefono$<>"0"
CLOSE #1
OPEN "FileBas.txt" FOR INPUT AS #1
DO UNTIL EOF(1)
INPUT #1, nombre$,edad$,telefono$
PRINT nombre$,edad$,telefono$
LOOP
CLOSE #1
Los ficheros de acceso aleatorio, están formados por registros de longitud fija. Cada registro tiene una serie de campos, también de longitud fija. Lo usual es declarar el tipo de registro y la distribución de campos mediante TYPE. El fichero se abre mediante las instrucciones:
OPEN "nombre_fichero" FOR RANDOM AS#X LEN=LEN(variable)
donde variable es una variable del tipo especificado en el bloque TYPE y LEN es su longitud en bytes. Por ejemplo:
TYPE Tmoto
marca AS STRING*10
potencia AS INTEGER
cilindros AS INTEGER
tipo AS STRING*10
END TYPE
DIM moto AS Tmoto
OPEN "Motos.dat" FOR RANDOM AS#1 LEN=LEN(moto)
Los ficheros de acceso directo o aleatorio pueden verse como una secuencia de registros, cada uno con la misma longitud, numerados desde el primero al último. Para leer/escribir uno determinado, es necesario referirse a él por su número, usando las sentencias GET y PUT respectivamente. La sintaxis es:
PUT #X, numero_registro, variable
GET #X, numero_registro, variable
Los ficheros binarios pueden considerarse como ficheros de acceso directo donde los registros son de 1 byte. Se lee y escribe con GET y PUT, y cada vez se leen o escriben tantos bytes como la longitud de la variable donde se almacenan los datos. La función SEEK permite colocar el puntero de archivo en el byte que deseemos.
3.4. Periféricos.
Se pueden abrir periféricos específicos mediante OPEN especificando el nombre predefinido para ese periférico. Los periféricos permitidos por QBASIC son los siguientes:
- COM1 Puerto Serie 1 Entrada/Salida
- COM2 Puerto Serie 2 Entrada/Salida
- KYBD Teclado Entrada
- LPT1 Puerto paralelo 1 Salida
- LPT2 Puerto paralelo 2 Salida
- LPT3 Puerto paralelo 3 Salida
- SCRN Pantalla Salida
3.5. Puertos
BASIC proporciona procedimientos para leer o escribir datos en un puerto. Estos procedimientos son INP y OUT. INP devuelve el valor que se encuentra en el puerto que se especifica como argumento:
INP(puerto%)
donde puerto% es un número entre 0 y 65535 que identifica al puerto. Para enviar información a un puerto se usa OUT, con la sintaxis
OUT puerto%, datos%
donde datos% es un byte que será enviado al puerto puerto%.
3.6. Acceso a memoria.
Las instrucciones PEEK y POKE permiten leer y escribir en posiciones específicas de memoria. Para leer:
PEEK (direccion%)
y para escribir:
POKE direccion%, byte%
donde direccion% es una dirección relativa al segmento actual, definido previamente mediante DEF SEG y byte% es un valor que será escrito en la posición de memoria especificada.
4.- ESTRUCTURA GENERAL DE UN PROGRAMA
BASIC no obliga a escribir los programas con una estructura definida, lo cual, lejos de ser una ventaja, es un inconveniente, como demuestra la experiencia. Por ese motivo, es aconsejable imitar la estructura de un lenguaje fuertemente estructurado, como C. Un programa debe estar constituido por un pequeño bloque de gestión de subprogramas, ocupándose cada uno de ellos de una tarea específica.
4.1. Subprogramas.
Cuando vaya a usarse un subprograma, será necesario declararlo como tal antes del programa principal mediante la sentencia DECLARE:
DECLARE SUB nombre(lista_argumentos)
Desde el programa principal, o desde otro subprograma, un subprograma se llama usando la sentencia CALL:
CALL nombre(lista_argumentos)
El subprograma en sí se escribe entre las sentencias SUB..END SUB:
SUB nombre(argumento1,argumento2...)
bloque
END SUB
Por defecto, los argumentos de un subprograma se pasan por dirección, con lo cual, quedan modificados en el programa. Para forzar el paso por valor, de modo que el subprograma opere con una copia de las variables del programa, los argumentos se incluyen entre paréntesis. El siguiente programa, junto con su salida debe ser suficientemente ilustrativo:
DECLARE SUB misub (a%, b%)
CLS
a%=23: b%=23
PRINT a%: PRINT b%
CALL misub (a%, (b%) )
PRINT a%: PRINT b%
pausa$=INPUT$(1)
SUB misub (a%, b%)
a%=200: b%=300
PRINT a%: PRINT b%
END SUB
23
23
200
300
200
23
4.2. Funciones.
QBASIC proporciona también la posibilidad de definir funciones externas al programa principal. Una función devuelve un único valor, como resultado de un cálculo. Este valor se almacena en una variable especial cuyo nombre es el de la función. Una función se escribe entre FUNCTION y END FUNCTION. En QBASIC, las funciones pueden ser recursivas. El siguiente ejemplo debe ser suficiente:
DECLARE FUNCTION resta(a%, b%)
CLS
a% = 34: b% = 20
PRINT resta (a%, b%)
pausa$ = INPUT$(1)
FUNCTION resta(a%, b%)
resta = a% - b%
END FUNCTION
14
4.3. Conclusión.
Con todos estos elementos, podemos estructurar el programa en bloques, escribiéndolos uno a continuación de otro en el orden que se sugiere a continuación:
- * declaración de procedimientos y funciones
- * declaración de tipos de variables
- * dimensionamiento de variables y arrays
- * asignación de constantes
- * inicialización de variables
- * CODIGO DEL BLOQUE PRINCIPAL
- END
- * código de las funciones y subprogramas