Mostrando entradas con la etiqueta else. Mostrar todas las entradas
Mostrando entradas con la etiqueta else. Mostrar todas las entradas

miércoles, 19 de abril de 2017

PROCEDURE DIVISION: proceso del programa.

Actualizado: incluimos EVALUATE
La PROCEDURE DIVISION es la parte del programa donde se codifica el proceso en sí. Es decir, aquí escribiremos las sentencias cobol para llevar a cabo la función del programa.

INFORMANDO VARIABLES

En cobol lo que se hace es "mover" la información de una variable a otra utilizando la sentencia MOVE.
A la hora de mover información tendremos que tener en cuenta 2 cosas:
  • Formato(PIC) de ambas variables
  • Longitud de ambas variables

Ejemplo 1.
01 WX-TELEFONO   PIC X(9) VALUE '666111333'.
01 WX-TELEFONO-2 PIC X(9).


Tienen mismo formato y misma longitud, por lo que no habrá problemas. La sentencia sería:
MOVE WX-TELEFONO TO WX-TELEFONO-2

Ahora WX-TELEFONO-2 tendrá el valor '666111333'.

Ejemplo 2.
01 WX-TELEFONO     PIC X(9) VALUE '666111333'.
01 WX-TELEFONO-NUM PIC 9(9).


Ahora tenemos misma longitud pero distinto formato. En este caso la variable alfanumérica sólo tiene números, por lo que no habrá problema.

MOVE WX-TELEFONO TO WX-TELEFONO-NUM
Ahora WX-TELEFONO-NUM tendrá el valor 666111333.

Ejemplo 3.
01 WX-TELEFONO     PIC X(9) VALUE 'AAA111333'.
01 WX-TELEFONO-NUM PIC 9(9).


Ahora tenemos caracteres alfabéticos en la variable alfanumérica, esto no dará error, aunque no tiene mucho sentido hacerlo.

Dependiendo de la instalación, este tipo de movimientos donde pasamos caracteres alfabéticos a campos numéricos darán, o no, un error en ejecución: el MOVE dará un estupendo "casque" al ejecutar con código error S0C7. Lo mismo ocurre si lo movemos a un campo COMP-3 o COMP.
En cualquier caso, NO debemos mover caracteres alfabéticos a un campo numérico, COMP o COMP-3.

Ejemplo 4.
01 WX-TELEFONO     PIC X(9) VALUE '666111333'.
01 WX-TELEFONO-NUM PIC 9(6).


En este caso no coinciden ni las longitudes ni los formatos. Como el campo alfanumérico sólo lleva números no habrá problema, pero al no coincidir las longitudes el campo se "truncará".

MOVE WX-TELEFONO TO WX-TELEFONO-NUM
Ahora el campo WX-TELEFONO-NUM tendrá valor 111333. Hemos perdido los 3 primeros dígitos.

Si fuese al revés:
01 WX-TELEFONO-NUM PIC 9(9) VALUE 666111333.
01 WX-TELEFONO     PIC X(6).

MOVE WX-TELEFONO-NUM TO WX-TELEFONO

El valor del campo WX-TELEFONO sería 666111.

Cuando se mueve a un campo alfanumérico, el movimiento se hace de la posición 1 del campo inicial a la posición 1 del campo alfanumérico.
Cuando se mueve a un campo numérico, el movimiento se hace de la última posición del campo inicial a la última posición del campo numérico.

Ejemplo 5.
01 WX-NUMERO-ALF PIC X(4) VALUE '12 '.
01 WX-NUMERO     PIC 9(4).


Puede darse el caso de que valores numéricos nos vengan con espacios en lugar de ceros a la izquierda.
Una manera de solventar esto es utilizando el COMPUTE FUNCTION NUMVAL:

COMPUTE WX-NUMERO = FUNCTION NUMVAL(WX-NUMERO-ALF)


Ahora la variable WX-NUMERO tendrá el valor 0012. Es una manera de asegurarnos de que no casque el programa porque algún vago no haya escrito los ceros^^
El movimiento en sí no daría error, pero no debe hacerse.

Un ejemplo más claro:
01 WX-NUMERO-ALF PIC X(4) VALUE '12,00  '.
01 WX-NUMERO     PIC 9(4)V9(2).


Con el COMPUTE FUNCTION NUMVAL conseguiríamos que WX-NUMERO tuviese el valor  00120{ (aplantillado con la coma decimal).

Campos COMP-3 y COMP.
Ejemplo 6.
01 WX-SUELDO-COMP3 PIC S9(6) COMP-3 VALUE 100000.
01 WX-SUELDO-NUM   PIC 9(6).

MOVE WX-SUELDO-COMP3 TO WX-SUELDO-NUM

Sin problema. WX-SUELDO-NUM valdrá 100000.

Ejemplo 7.
01 WX-SUELDO-COMP3 PIC S9(6) COMP-3 VALUE 100000.
01 WX-SUELDO-ALF   PIC X(6).

MOVE WX-SUELDO-COMP3 TO WX-SUELDO-ALF

Sin problema. WX-SUELDO-ALF valdrá 100000.

Ejemplo 8.
01 WX-SUELDO-COMP PIC S9(6) COMP VALUE 100000.
01 WX-SUELDO-NUM  PIC 9(6).

MOVE WX-SUELDO-COMP TO WX-SUELDO-NUM

Sin problema. WX-SUELDO-ALF valdrá 100000.

Ejemplo 9.
01 WX-SUELDO-COMP PIC S9(6) COMP VALUE 100000.
01 WX-SUELDO-ALF  PIC X(6).

MOVE WX-SUELDO-COMP TO WX-SUELDO-ALF

Sin problema. WX-SUELDO-ALF valdrá 100000.

Ejemplo 10.
01 WX-SUELDO-COMP3 PIC S9(6) COMP-3 VALUE 100000.
01 WX-SUELDO-COMP  PIC 9(6) COMP.

MOVE WX-SUELDO-COMP3 TO WX-SUELDO-COMP

Sin problema, WX-SUELDO-COMP valdrá 100000 pero en formato hexadecimal: 186A0

Ejemplo 11.
01 WX-SUELDO-COMP  PIC 9(6) COMP VALUE 100000.
01 WX-SUELDO-COMP3 PIC S9(6) COMP-3.

MOVE WX-SUELDO-COMP TO WX-SUELDO-COMP3

Sin problema, WX-SUELDO-COMP valdrá 100000.

Para campos numéricos existe también la sentencia COMPUTE para pasar información de uno a otro:
Ejemplo 12.
01 WX-NUMERO-1 PIC 9(5) VALUE 12345.
01 WX-NUMERO-2 PIC 9(5).

COMPUTE WX-NUMERO-2 = WX-NUMERO-1

Ahora WX-NUMERO-2 valdrá 12345.

Aunque la sentencia COMPUTE se usa en general para operaciones aritméticas: suma, resta, multiplicación, división, potencia...

COMPUTE WX-NUMERO1 =
((WX-NUMERO2 + WX-NUMERO3) - (WX-NUMERO4 * WX-NUMERO5) / WX-NUMERO6) ** 2


Y se aplican las mismas reglas de prioridades que en matemáticas.(el doble asterisco es la potencia)

Es en estos casos cuando un campo numérico que lleve caracteres o espacios pierde su sentido, pues adivinad que sucede si intentamos dividir 'ABC?%&' entre 1000 al ejecutar el programa...
Premio! Un S0C7!!


Nunca va a tener sentido dividor letras entre números, imagino que en esto estamos todos de acuerdo : P

Para operaciones aritméticas existen también:
ADD: operador suma. "ADD 1 TO WX-CAMPO"
SUBTRACT: operador resta. "SUBTRACT 1 FROM WX-CAMPO"
MULTIPLY: operador multiplicación. "MULTIPLY WX-CAMPO BY 1"
DIVIDE: operador división. "DIVIDE WX-CAMPO BY 1"
REMAINDER: es el resto de una división. "DIVIDE WX-CAMPO BY 1 REMAINDER WX-RESTO"


Ejemplo 13.
01 WX-TELEFONO-NUM PIC 9(9) VALUE  666111333.
01 WX-TELEFONO-ALF PIC X(9) VALUE '666111333'.
01 WX-TELEFONO     PIC X(6).


Para campos alfanuméricos y numéricos sin comprimir existe la posibilidad de mover sólo determinadas posiciones del campo.

MOVE WX-TELEFONO-NUM(1:6) TO WX-TELEFONO

En este caso estamos cogiendo 6 posiciones, empezando desde la posición 1. Ahora WX-TELEFONO valdrá '666111'.

MOVE WX-TELEFONO-ALF(4:) TO WX-TELEFONO

En este caso estamos cogiendo todas las posiciones hasta final de campo desde la posición 4. Ahora WX-TELEFONO valdrá '111333'.

Para mover posiciones de un campo que pertenece a un array o tabla, primero habrá que indicar el occurs o índice y después la posición:
01 WX-TABLA OCCURS 5 TIMES.
   05 WX-TELEFONO1 PIC X(9) VALUE '111111111'.
      05 WX-TELEFONO2 PIC X(9) VALUE '222222222'.
   05 WX-TELEFONO3 PIC X(9) VALUE '333333333'.
   05 WX-TELEFONO4 PIC X(9) VALUE '444444444'. 

MOVE WX-TELEFONO3(3)(4:) TO WX-TELEFONO

Ahora WX-TELEFONO valdrá '333333'.


CONCATENANDO CAMPOS

En COBOL también existe la opción de concatenar campos usando la sentencia STRING. Lo que haremos será indicar las variables a concatenar, el modo en que se unirán y el campo donde se guardará el resultado.

01 WX-CAMPO1    PIC X(17) VALUE 'CONSULTORIO COBOL'.
01 WX-CAMPO2    PIC X(10) VALUE ' SON GUAYS'.
01 WX-RESULTADO PIC X(41).

STRING 'LOS TIPOS DEL ' WX-CAMPO1 WX-CAMPO2
DELIMITED BY SIZE
INTO WX-RESULTADO





Donde DELIMITED BY SIZE indica que los campos se unirán según el tamaño que ocupen, y el INTO indicará el campo donde guardar la información concatenada.
Si por ejemplo tuviésemos campos con espacios al final podríamos indicarle un DELIMITED BY SPACES, para que cortase la información al encontrarse el primer espacio. Vamos a ver el ejemplo:

01 WX-DIA   PIC 9(2) VALUE 31.
01 WX-MES   PIC X(10).
01 WX-FECHA PIC X(19).

MOVE 'MAYO' TO WX-MES

Ahora WX-MES valdrá 'MAYO      '.

STRING 'HOY ES ' WX-DIA ' DE ' DELIMITED BY SIZE
WX-MES DELIMITED BY SPACE
'.' DELIMITED BY SIZE
INTO WX-FECHA


El resultado:
HOY ES 31 DE MAYO.


Si no hubiésemos indicado el DELIMITED BY SPACE, el resultado sería:
HOY ES 31 DE MAYO      .


Recordad: el DELIMITED BY se aplica a todos los campos que lo preceden. Usad el DELIMITED BY correcto en cada caso!

INICIALIZANDO CAMPOS

Para "vaciar" un campo podríamos moverle ceros o espacios (según su formato). Pero
en cobol existe una instrucción más sencilla que es el INITIALIZE.

01 WX-NUMERO PIC 9(5) VALUE 12345.
(...)
INITIALIZE WX-NUMERO


Ahora WX-NUMERO valdrá 00000. Si fuese alfanumérico valdría '     ' (cinco espacios).

Las variables "vacías" en cobol pueden tener 3 tipos de información:
ceros: 00000
espacios: '     '
low-values: '.....'

Por eso a la hora de preguntar si un campo está vacío en cobol preguntaremos:
IF WX-CAMPO EQUAL ZEROES OR SPACES OR LOW-VALUES
(...)


Nota: Tanto LOW-VALUES como HIGH-VALUES son palabras reservadas en cobol, y se pueden definir como "el valor más bajo posible" y "el valor más alto posible" respectivamente. Veremos su uso en otros artículos.


BUCLES Y CONDICIONES

Las condiciones en cobol se escriben de la siguiente manera:
IF WX-CAMPO = 1
   MOVE 1        TO WX-CAMPO2
ELSE
   MOVE WX-CAMPO TO WX-CAMPO2
END-IF


Podemos escribir IFs dentro de IFs (IFs anidados) y La sentencia ELSE no es obligatoria:

IF WX-CAMPO1 = 1
   IF WX-CAMPO2 = 2
      MOVE WX-CAMPO1 TO WX-CAMPO3
   END-IF
ELSE
   MOVE 1 TO WX-CAMPO3
END-IF

No tienen más ciencia que cualquier IF de cualquier otro lenguaje.

Los operadores lógicos serán OR, AND, EQUAL, NOT EQUAL.
Los operadores de mayor, menor, serán GREATER y LESS.
También se pueden utilizar combinaciones como GREATER OR EQUAL (mayor o igual), y también con símbolos: >= (mayor o igual), <= (menor o igual).

Otra forma de preguntar por una condición es con un EVALUATE.
Preguntando si se cumple una condición, es decir, si es TRUE:

EVALUATE TRUE
  WHEN WS-CAMPO1 EQUAL WS-CAMPO2
      (instrucciones a realizar)
  WHEN WS-CAMPO1 NOT EQUAL WS-CAMPO2
      (instrucciones a realizar)
  WHEN OTHER
      (instrucciones a realizar)
END-EVALUATE

Preguntando por el valor de un campo:
EVALUATE WS-CAMPO1
  WHEN 1
      (instrucciones a realizar) 
  WHEN 2
      (instrucciones a realizar) 
  WHEN OTHER
      (instrucciones a realizar) 
END-EVALUATE

Preguntando por el valor de varios campos:
EVALUATE WS-CAMPO1 ALSO WS-CAMPO2
  WHEN 1 ALSO 1
      (instrucciones a realizar) 
  WHEN 2 ALSO 2
      (instrucciones a realizar) 
  WHEN OTHER
      (instrucciones a realizar) 
END-EVALUATE

ó

EVALUATE TRUE ALSO TRUE
  WHEN WS-CAMPO1 = 1 ALSO WS-CAMPO2 = 1
      (instrucciones a realizar) 
  WHEN WS-CAMPO1 = 2 ALSO WS-CAMPO2 = 2
      (instrucciones a realizar) 
  WHEN OTHER
      (instrucciones a realizar) 
END-EVALUATE 

ó

EVALUATE WS-CAMPO1 ALSO TRUE
  WHEN 1 ALSO WS-CAMPO2 = 1
      (instrucciones a realizar) 
  WHEN 2 ALSO WS-CAMPO2 = 2
      (instrucciones a realizar) 
  WHEN OTHER
      (instrucciones a realizar) 
END-EVALUATE 

Los bucles son diferentes debido a que en cobol no existe la sentencia "while" de otros lenguajes. Aquí los bucles son siempre "UNTIL", es decir, hasta que se cumpla la condición especificada.

MOVE 0 TO WX-CAMPO

PERFORM UNTIL WX-CAMPO = 5 -> aquí es donde pregunta por la condición
   proceso a realizar
   ADD 1 TO WX-CAMPO
END-PERFORM


El proceso se realizará para:
WX-CAMPO = 0
WX-CAMPO = 1
WX-CAMPO = 2
WX-CAMPO = 3
WX-CAMPO = 4

MOVE 5 TO WX-CAMPO

PERFORM UNTIL WX-CAMPO = 5 -> aquí es donde pregunta por la condición
   proceso a realizar
END-PERFORM


El proceso no se llega a realizar.

Si quisiésemos preguntar por la condición al final del bucle, tendríamos que codificar el bucle con un "WITH TEST AFTER":

MOVE 0 TO WX-CAMPO


PERFORM WITH TEST AFTER
  UNTIL WX-CAMPO = 5
   proceso a realizar
   ADD 1 TO WX-CAMPO
END-PERFORM -> aquí es donde pregunta por la condición

El proceso se realizará para:
WX-CAMPO = 0
WX-CAMPO = 1
WX-CAMPO = 2
WX-CAMPO = 3
WX-CAMPO = 4

MOVE 5 TO WX-CAMPO

PERFORM WITH TEST AFTER
  UNTIL WX-CAMPO = 5
   proceso a realizar

   ADD 1 TO WX-CAMPO
END-PERFORM -> aquí es donde pregunta por la condición

El proceso se realiza una vez, antes de comprobar si se cumple la codición.

Como veíamos en la estructura general de un programa cobol, un párrafo entero también se puede repetir hasta que se cumpla una condición:

PERFORM 2000-PROCESO
  UNTIL CUMPLA-CONDICION

Otro tipo de bucles son los "PERFORM VARYING". En este caso tendremos un contador que se irá incrementando automáticamente según le indiquemos:

PERFORM VARYING WI-INDICE FROM 1 BY 1 UNTIL WI-INDICE = 10
  código a ejecutar
END-PERFORM

El "FROM" le indica desde que valor empezar. El "BY" le indica cuanto le ha de sumar cada vez.
Como en el otro caso, el "UNTIL" le indicará la condición de final de bucle.

Con todo esto, ya podemos empezar a ver un ejemplo de un programa sencillo : )

miércoles, 6 de abril de 2011

Proceso de un programa PL/I

El proceso del programa comienza en donde nosotros queramos, aunque por poner un poco de orden, podemos decir que empazará después de que acabemos de definir todas las variables que vayamos a necesitar.

INFORMANDO VARIABLES

En PL/I la manera de informar variables es "asignándoles" un valor:
DCL CAMPO1 CHAR(3) INIT ('123');
DCL CAMPO2 CHAR(3);

CAMPO2 = CAMPO1;


Ahora CAMPO2 valdrá '123'.

Vamos a ver algunos ejemplos de asignaciones denominadas "simples", es decir, la asignación se hace entre variables del mismo tipo (numéricos con numéricos, alfanuméricos con alfanuméricos).

Ejemplo 1: Campos numéricos.
DCL CAMPO_NUM1 DEC FIXED (3,2) INIT (0);
DCL CAMPO_NUM2 DEC FIXED (6,3) INIT (0);

CAMPO_NUM1 = 1.23;
CAMPO_NUM2 = CAMPO_NUM1;


Ahora CAMPO_NUM2 valdrá 001.230.

CAMPO_NUM2 = 456.789;
CAMPO_NUM1 = CAMPO_NUM2;


Ahora CAMPO_NUM1 valdrá 6.78.
Como podéis ver, mantiene la posición del punto decimal.

En las asginaciones de campos numéricos también podremos guardar operaciones artiméticas:

CAMPO_NUM1 = CAMPO_NUM2/2 + CAMPO_NUM3 * (CAMPO_NUM4 - CAMPO_NUM5) ** 2;


Y se aplican las mismas reglas de prioridades que en matemáticas (el doble asterisco es la potencia).

Ejemplo 2: campos alfanuméricos.
DCL ALFANUM1 CHAR (5)  INIT(' ');
DCL ALFANUM2 CHAR (11) INIT (' ');

ALFANUM1 = 'COBOL';
ALFANUM2 = ALFANUM1;


Ahora ALFANUM2 valdrá 'COBOL       '.

ALFANUM2 = 'CONSULTORIO';
ALFANUM1 = ALFANUM2;


Ahora ALFANUM1 valdrá 'CONSU'.

Usando el operador de concatenación || podemos guardar varios campos en una variable:
DCL CAMPO1 CHAR(10) INIT ('COMO MOLA ');
DCL CAMPO2 CHAR(20) INIT ('EL CONSULTORIO COBOL');
DCL CAMPO3 CHAR(30);

CAMPO3 = CAMPO1||CAMPO2;


Ahora CAMPO3 contendrá 'COMO MOLA EL CONSULTORIO COBOL' :D

Ejemplo 3: matrices (tablas internas).
DCL TABLA(3) CHAR(1);


Para utilizar un elemento de una matriz tendremos que indicar el índice del elemento entre paréntesis.

TABLA(1) = 'A';
TABLA(2) = 'B';
TABLA(3) = 'C';


Ahora el elemento 1 de la tabla valdrá 'A', el elemento 2 valdrá 'B', y el elemento 3 valdrá 'C'.

Para tablas de 2 dimensiones se indicarán los dos índices entre paréntesis.
DCL TABLA_DOBLE(2,3) CHAR(1);

Y en las asignaciones también se indicarán los dos índices:
TABLA_DOBLE(1,1) = 'A';


INICIALIZANDO VARIABLES

La inicialización de variables en PL/I se hace en el momento de declararlas, con la sentencia INIT que vimos en el artículo del "Esquema de un programa pl/i".

Vamos a ver algunos ejemplos:
DCL CAMPO_ALFANUM CHAR(10)  INIT(' '); Se rellena con espacios. Para campos alfanuméricos el valor se indica entre comillas simples ''.
DCL CAMPO_ALFANUM CHAR(100) INIT((100)'-'); Se rellena con 100 guiones.
DCL CAMPO_NUM PIC 10(9)        INIT(0); Se rellena con ceros. Para campos numéricos, el valor se indica sin comillas.
DCL CAMPO_DEC DEC FIXED (10,3) INIT(0); Se rellena con ceros.

DCL TABLA1 DEC FIXED(2,2) INIT(1,2,3,4);
Asigna valores a cada elemento de la tabla:
TABLA1(1,1) = 1
TABLA1(1,2) = 2
TABLA1(2,1) = 3
TABLA1(2,2) = 4

DCL TABLA1 DEC FIXED(2,2) INIT(4(0));
Asigna ceros a los 4 elementos de la tabla.



CONDICIONES

Para expresar condiciones en PL/I se utilizará el IF/ELSE de toda la vida, pero con sus particularidades.

Ejemplo 1: IF.
IF CAMPO1 = CAMPO2
   THEN CAMPO1 = 2;


Al poner el ; finalizamos la sentencia IF (no hay que cerrarla con un END-IF como en cobol).

Ejemplo 2: IF/ELSE.
IF CAMPO1 = CAMPO2
   THEN CAMPO1 = 2;
ELSE CAMPO1 = 1;


La condición finaliza con el ; de la parte del ELSE.
Puede darse el caso de que no queramos realizar ninguna acción para la condición del IF, sino sólo en el caso contrario (ELSE):

IF CAMPO1 = CAMPO2 THEN;
ELSE CAMPO1 = 1;


Ejemplo 3: IF/ELSE con DO.
IF CAMPO1 = CAMPO2
   THEN DO;
          CAMPO1 = 2;
          CAMPO2 = 1;
        END;
ELSE DO;
       CAMPO1 = 1;
       CAMPO2 = 2;
     END;


Cuando dentro de un IF o un ELSE hay más de una expresión, todas ellas se incluirán dentro de la sentencia DO/END.

Los operadores que se utilizan en las condiciones serán:
= : igual a
¬= : distinto
& : y
| : o
< : menor que
> : mayor que
<= : menor o igual
>= : mayor o igual
¬< : no menor que
¬> : no mayor que

Otra manera de incluir una condición es con la sentencia SELECT. Viene a ser el equivalente al EVALUATE de Cobol, pero hay que tener cuidado porque no funcionan exactamente igual.

Si queremos poner como condición el valor que tome una variable:
SELECT(CAMPO_1);
  WHEN(1);
  WHEN(2)   CAMPO_2 = 2;
  OTHERWISE CAMPO_2 = 0;
END;


Si queremos validar que se cumple una condición:
SELEC;
  WHEN(CAMPO_1 = CAMPO_2);
  WHEN(CAMPO_1 < CAMPO_2) CAMPO_3 = 2;
  OTHERWISE CAMPO_3 = 0;
END;


Fijaos en el primer WHEN de los dos ejemplos. Cuando un WHEN finaliza con ; significa que para ese caso no haremos nada. Sería el equivalente a poner un CONTINUE en Cobol.
MUY IMPORTANTE no confundir con el caso del EVALUATE, donde al poner dos WHEN seguidos significa que el código que venga a continuación se realizará para los dos WHEN:

EVALUATE WX-CAMPO1
  WHEN 1
  WHEN 2
       DISPLAY 'CAMPO1 ES 1 o 2'
  WHEN OTHER
       CONTINUE
END-EVALUATE


El display se mostrará para WX-CAMPO1 = 1 y WX-CAMPO1 = 2.

En el caso del SELECT, se indicarán los dos valores en el mismo WHEN:

SELEC CAMPO_1;
  WHEN(1,2) PUT EDIT ('CAMPO_1 ES 1 o 2') (A);
  OTHERWISE;
END;


Para terminar decir que en caso de que dentro de un WHEN queramos escribir más de una instrucción, tendremos que usar el DO/END como en el caso del IF.

BUCLES

En PL/I los bucles se codifican con la sentencia DO/END. Existen varias opciones para acompañar al DO:

DO WHILE
En este caso las sentencias entre el DO y el END se ejecutarán "mientras que" se cumpla una condición, es decir, mientras esa condición sea cierta.

DO WHILE CAMPO1 ¬= ' ';
sentencias a ejecutar;
END;


Si tuviésemos más de una condición, deberá ir entre paréntesis.
DO WHILE (CAMPO1 ¬= ' ' & CAMPO2 = 1);
sentencias a ejecutar;
END;


DO UNTIL
En este caso las sentencias entre el DO y el END se ejecutarán "hasta que" se cumpla la condición especificada.

DO UNTIL CAMPO_ANO = 2012;
sentencias a ejecutar;
END;


Si tuviésemos más de una condición, deberá ir entre paréntesis.

DO + TO
En este caso las sentencias entre el DO y el END se ejecutarán hasta que se cumpla la condición especificada.

DO INDICE = 1 TO 10;
sentencias a ejecutar;
END;


Las sentencias a ejecutar se harán 10 veces (desde INDICE = 1 hasta 10, de 1 en 1).

Para retorcerlo un poco más podemos usar la sentencia BY:
DO INDICE = 1 TO 10 BY 2
sentencias a ejecutar;
END;


Las sentencias a ejecutar se harán 5 veces (desde INDICE = 1 hasta 10, de 2 en 2).

También se puede combinar el DO/TO con la opción WHILE:
DO INDICE = 1 TO 10 WHILE CAMPO1 = ' ';
sentencias a ejecutar;
END;

En este caso, además de controlar el valor de INDICE, la expresión del WHILE debe ser cierta.