## 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. El resto de los apuntes se pueden conseguir en estas mismas páginas. Convertido a HTML por Nacho Cabanes).

### 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 <tipo> de las sentencias DIM, REDIM

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 <tipo>. Por ejemplo:

           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 <sentencia>

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 va rias 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 <INTRO> para leer la(s) variable(s). La función INPUT$(X) lee las variables después de haber pulsado X caracteres, sin devolver eco a pantalla.

#### 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 <modificador> indica la operación a realizar y X es el número del canal. Pueden usarse los siguientes modificadores:

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

(Volver a la Pagina inicial )