I.2.1. Notaci¢n Occam I.2.1.1. Canales y Concurrencia Los procesos en Occam constituyen la estructura fundamental para el lenguaje. En Occam, los procesos son computaciones independientes y pueden comunicarse con otros procesos para formar sistemas concurrentes. Esta comunicaci¢n se produce a trav‚s de canales de comunicaci¢n. Los procesos son finitos, en ellos cada proceso empieza, desarrolla un determinado n£mero de acciones y termina o se detiene (no acaba nunca). La acci¢n que desarrolla cada proceso puede ser un conjunto de procesos secuenciales, como en lenguajes tradicionales, o un conjunto de procesos paralelos. Cada proceso puede consistir a su vez en otros procesos que pueden ejecutarse de forma secuencial o en paralelo, de esta forma el concepto de proceso da al lenguaje cierto tipo de concurrencia interna. El grado de concurrencia en un instante determinado se alterar  cuando los procesos empiezan y terminan. Un par de procesos concurrentes se comunican utilizando un canal. Cada canal ofrece una forma de conexi¢n entre dos procesos concurrentes, un proceso pone un mensaje en el canal y el otro proceso lo recoge de ‚l. La idea importante del concepto de canal es que las comunicaciones son sincronizadas y sin "buffer", es decir, si un proceso utiliza un canal de entrada y ese canal sirve de salida a otro proceso, la comunicaci¢n no se produce hasta que los dos procesos est‚n preparados. Una vez que los dos procesos est n preparados se produce la comunicaci¢n. Un proceso puede estar preparado para comunicarse con cualquier n£mero de canales. La comunicaci¢n tiene lugar cuando otro proceso est  preparado para comunicarse a trav‚s de uno de los canales. Como un proceso puede poseer concurrencia interna puede tener varios canales de entrada y varios de salida y, desarrollar comunicaciones al mismo tiempo. Como el transputer utiliza el concepto Occam de concurrencia y comunicaci¢n, Occam puede utilizarse para programar a un solo transputer o a una red de transputers. En el caso de un £nico transputer, ‚ste comparte su tiempo entre los procesos concurrentes y las comunicaciones. Para una red de transputers, cada transputer ejecuta el proceso que le ha sido asignado. La comunicaci¢n entre procesos Occam de distintos transputers se hace a trav‚s de los links. De esta forma, el mismo proceso Occam puede implementarse para un solo transputer o para una red de transputers. En general, la implementaci¢n usando una red alcanzar  mejores resultados, en lo que se refiere a la velocidad, que el proceso equivalente para un solo transputer. Sin embargo el costo de tal red puede ser significativo, por lo que la configuraci¢n elegida para un proceso dado depende de consideraciones como el rendimiento - costo. I.2.1.2. Notaci¢n La notaci¢n utilizada en la descripci¢n de Occam se sigue de la definici¢n del lenguaje ofrecida por David May y que ha sido descrita por Inmos (1984). Los programas Occam est n compuestos de procesos. El proceso m s simple en un programa Occam es la acci¢n. Una acci¢n puede estar compuesta por los siguientes procesos: - Asignaci¢n (assignment) - Entrada (input) - Salida (output) donde una asignaci¢n computa el valor de una expresi¢n y hace que una variable tome ese valor, lo que puede expresarse como: assignment = variable := expression input = channel ? variable output = channel ! expression La asignaci¢n se realiza teniendo en cuenta que el tipo de la variable es el de la expresi¢n, en otro caso la asignaci¢n es inv lida. El s¡mbolo ':=' indica la asignaci¢n. Por ejemplo: y := 0 asigna a y el valor 0. Tambi‚n es posible realizar asignaciones m£ltiples: a, b, c := p+3, q-2, r aqu¡, por ejemplo, se asignan los valores p+3, q-2, y r a las variables a, b, c respectivamente. En tales asignaciones m£ltiples, los valores de las expresi¢nes a asignar, p+3, q-2 y r en este caso, se calculan y se realiza la asignaci¢n en paralelo. Un ejemplo interesante es: a, b := b, a que produce el efecto de intercambiar los valores de a y b. El significado de: action = assignment | input | output refleja el hecho de que una acci¢n puede ser una asignaci¢n , una entrada (recepci¢n) o una salida (envio). La estructura escrita de un programa Occam viene especificada por la sintaxis. Cada sentencia de programa ocupa una £nica l¡nea, excepto en el caso de sentencias largas que pueden ocupar m s de una l¡nea. Al contrario de lo que ocurre algunos lenguajes de programaci¢n en los que no es obligatorio el nivel de "identaci¢n" (sangrado) , en Occam la identaci¢n de las l¡neas de programa forma parte intr¡nseca de la sintaxis del lenguaje. La sintaxis de la contrucci¢n SEQ, se discutir  posteriormente pero, toma la forma: sequence = SEQ replicator {process} Esta sintaxis denota una secuencia seguida por uno o m s procesos, cada uno en una l¡nea distinta e identados dos espacios a partir de SEQ. La notaci¢n {process} significa el n£mero de veces que ocurrir  el objeto sint ctico; en este caso el objeto es un proceso. El proceso ocurrir  cero o m s veces. Una extensi¢n a esta notaci¢n podr¡a ser: {0, expression} Hace referencia a una lista de cero o m s expresiones separadas por comas. {1, expression} Hace referencia a una lista de una o m s expresiones separadas por comas. Las sentencias largas que necesitan m s de una l¡nea pueden partirse. Cuando una sentencia se parte, la continuaci¢n de la sentencia en la siguiente l¡nea debe identarse al menos tanto como la primera l¡nea de la sentencia. Una sentencia puede partirse inmediatamente despu‚s de alguno de los siguientes puntos: - Una asignaci¢n := - Una coma , - Una palabra reservada IS, FROM o FOR - Un operador +, -, *, /, etc... - Un punto y coma ; Una cadena de texto puede partirse para continuar en l¡neas adicionales, pero en este caso la primera l¡nea de la cadena debe finalizar con un car cter '*' y, la continuaci¢n en las siguientes l¡neas debe comenzar con '*'. Un comentario tiene que ir precedido por el par de caracteres '--', y se extiende hasta el final de la l¡nea. Los comentarios no pueden identarse menos que las siguientes sentencias. Por ejemplo: SEQ -- Proceso secuencial -- Ejemplo de uso de comentarios -- Un comentario no puede identarse menos que las -- siguientes sentencias ....... SEQ -- Proceso secuencial El siguiente uso de comentarios es inv lido: SEQ -- Proceso secuencial -- Uso inv lido de comentarios, identaci¢n insuficiente ....... SEQ Los envios (Output) y recepciones (Input) se utilizan para comunicarse entre procesos. Una recepci¢n se indica mediante el s¡mbolo '?'. Por ejemplo: keyboard ? char recibe el valor desde el canal keyboard y lo asigna a la variable char. Un envio se indica con el s¡mbolo '!'. Por ejemplo: screen ! char envia el valor de la variable char al canal screen. I.2.2. Tipos de datos Occam requiere que cada objeto que se utilice en el programa sea declarado antes de usarse para poder saber con qu‚ clase de objeto se est  tratando. Antes de empezar, aclarar que el nombre de un objeto en Occam puede ser tan largo como el usuario desee empezando por una letra del alfabeto. Despu‚s de la primera letra, el resto pueden ser letras, n£meros o el car cter '.'. Occam trata las may£sculas y min£sculas como caracteres distintos, por ejemplo, Counter y counter indicar¡an variables distintas. Adem s Occam posee un n£mero determinado de palabras que no pueden ser utilizados como variables y se escriben en may£sculas, estas palabras reservadas son las de la tabla siguiente: AFTER IS PROTOCOL ALT INT REAL32 AND INT16 REAL64 ANY INT32 REM AT INT64 RESULT BITAND MINUS RETYPES BITNOT MOSTNEG ROUND BITOR MOSTPOS SEQ BOOL NOT SIZE BYTE OR SKIP CASE PAR STOP CHAN OF PLACE TIMER ELSE PLACED TIMES FALSE PLUS TRUE FOR PORT OF TRUNC FROM PRI VAL FUNCTION PROC VALOF IF PROCESSOR WHILE I.2.2.1. Tipos primitivos En Occam cada variable, expresi¢n y valor tienen un tipo, que puede ser un tipo primitivo o un array. Este tipo define su longitud y representaci¢n. La representaci¢n general de los tipos primitivos viene dada por: type = primitive.type | array.type primitive.type = CHAN OF protocol | TIMER | BOOL | BYTE | INT | INT16 | INT32 | INT64 | REAL32 | REAL64 array.type = [expression]type Los tipos primitivos que poseen todas las implementaciones Occam son los siguientes: - CHAN OF type: Cada canal de comunicaci¢n permite que los procesos comuniquen valores del tipo especificado. - TIMER: Cada "Timer" ofrece un reloj que puede utilizarse por cualquier n£mero de procesos concurrentes. - INT: Es el tipo de enteros con signo, representados en complemento a dos. Soporta el siguiente rango de valores n: INT16 -32768 <= n < 32768 INT32 -2147483648 <= n < 2147483648 INT64 -2 ** 63 <= n < 2 ** 63 - REAL32: N£meros en punto flotante que utilizan un bit 's' para el signo, un exponente 'e' de 8-bits y una mantisa de 23-bits, 'f'. Su magnitud es: (2 ** (e-127)) * 1.f si 0 < e < 255 (2 ** -126) * 0.f si e = 0 y f <> 0 0 si e = 0 y f = 0 - REAL64: N£meros en punto flotante que utilizan un bit 's' para el signo, un exponente 'e' de 11-bits y una mantisa de 52-bits, 'f'. Su magnitud es: (2 ** (e-1023)) * 1.f si 0 < e < 2047 (2 ** -1022) * 0.f si e = 0 y f <> 0 0 si e = 0 y f = 0 - BOOL: Los valores de tipo BOOL son TRUE y FALSE. - BYTE: Los valores de typo BYTE son aquellos n£meros entre 0 y 255. Una variable, expresi¢n o valor debe declararse como uno de los tipos anteriores usando una declaraci¢n de la forma: declaration = type{1, name} : El uso de `:` indicar  el final de la declaraci¢n, por ejemplo, INT x,y: P declara a x e y como variables enteras. El car cter `:`. Este car cter une la declaraci¢n de tipo con el proceso que le sigue (P) y est  identado al mismo nivel. El proceso que le sigue es el proceso en el que la especificaci¢n es v lida, a ‚l nos referiremos cuando hablemos de  mbito de la especificaci¢n. Esto significa que el mismo nombre puede utlizarse por diferentes objetos en diferentes  mbitos. La comunicaci¢n entre los procesos que componen una instrucci¢n PAR s¢lo es posible mediante el uso de canales canales. Occam no permite que los valores se pasen entre procesos utilizando la opci¢n de variables compartidas. Las razones de esta restricci¢n son evidentes si se tiene en cuenta que en la construcci¢n PAR los procesos que se ejecutan en paralelo, se est n ejecutando al mismo tiempo, sincroniz ndose en el momento en el que se producen las comunicaciones entre ellos a trav‚s de los canales. Ser¡a imposible permitir el uso de variables compartidas en tal entorno. Por ejemplo, si fuera posible escribir en Occam: INT v.1: PAR p.1 p.2 en el que los procesos p.1 y p.2 acceden a v.1, ¨c¢mo se controlar¡a el acceso a v.1?. T‚ngase en mente, que en Occam no est  definido el n£mero de procesadores necesarios para ejecutar un proceso paralelo. En el ejemplo anterior, los dos procesos podr¡an estar en el mismo procesador o en procesadores distintos, cada uno con su propio  rea de memoria. Si Occam permitiera procesos como el anterior ser¡a extremadamente dif¡cil garantizar que el programa es correcto. La especificaci¢n de una variable en Occam no inicializa el valor de esa variable a ning£n valor particular. El valor de la variable puede ser cualquiera hasta que se inicialice o se haga una entrada en el proceso en el que se ha especificado. Una vez que el proceso asociado con esta especificaci¢n ha acabado, la variable no existe y su valor en el proceso no tiene significado. Cuando se utilizan operadores aritm‚ticos con operandos reales, el resultado se redondea para producir un valor que es del mismo tipo que sus operandos. I.2.2.1.1. El tipo CHAN OF Los canales son todos del tipo CHAN OF protocol. Es necesario especificar el tipo del dato y la estructura con la que est n asociados, a lo que nos referiremos como protocolos del canal. Un ejemplo de canal sobre el que pueden enviarse enteros podr¡a ser: CHAN OF INT count: Aqu¡ la especificaci¢n INT define el tipo de dato que se va a comunicar a trav‚s del canal "count". Si se intenta comunicar a trav‚s de este canal otro tipo de dato que el de tipo INT, obtendremos como resultado un error. Veamos algunos ejemplos de declaraci¢n y uso de canales: CHAN OF INT c.1, c.2: CHAN OF BOOL c.3: INT v.1, v.2: BOOL b.1: SEQ c.1 ? v.1 -- Recibe el valor de v.1 desde c.1 c.2 ! v.1 -- Env¡a el valor de v.1 a trav‚s de c.2 c.3 ? b.1 -- Recibe el valor de b.1 a trav‚s de c.3 c.3 ? v.2 -- Incorrecto, c.3 es un canal l¢gico I.2.2.1.2. El tipo BOOL Los valores del tipo BOOL son TRUE o FALSE. Estos valores pueden obtenerse como resultado de la comparaci¢n de los valores de distintas operaciones aritm‚ticas. Occam dispone de los siguientes operadores relacionales, las comparaci¢nes pueden realizarse £nicamente sobre datos del mismo tipo: = igual <> no igual > mayor que < menor que >= mayor o igual que < menor que < menor o igual que Los valores TRUE y FALSE son constantes Occam que pueden utilizarse como opeandos en una comparaci¢n. I.2.2.1.3. Constantes Los valores constantes pueden tener un nombre asociado utilizando una especificaci¢n de la forma: VAL type name IS value: Por ejemplo, podr¡amos escribir: VAL INT week IS 7: especificando que el nombre del dato es de tipo INT y tiene valor constante 7. En los casos donde el tipo del dato puede deducirse del valor del dato, no es necesario especificar el tipo, por ejemplo, el caso anterior podr¡a haber sido: VAL week IS 7: I.2.2.1.4. Caracteres Occam no tiene ning£n tipo que represente letras del alfabeto o palabras espec¡ficamente. Los caracteres se representan con n£meros del tipo BYTE y los strings como arrays de BYTEs. I.2.2.1.5. El tipo TIMER Occam tiene un tipo (TIMER) que permite la creaci¢n de "Timers" que pueden usarse como relojes por los procesos. Los Timers son tipos primitivos como los canales. Su sintaxis es: primitive.type = TIMER Se puede utilizar el operador AFTER para comparar tiempos. Un timer se declara de la misma forma que los canales y las variables. Por ejemplo: TIMER ClockA: declara un timer y lo identifica con el nombre "ClockA". Los valores de entrada de los timers son enteros que representan el tiempo. El valor proviene de un reloj que se incrementa en intervalos regulares. El promedio en el que se incrementa el timer depende de la implementaci¢n. El valor del reloj es c¡clico, una vez que se alcanza un valor entero positivo m ximo el siguiente incremento lleva al valor m s negativo y se repite el ciclo. A los timers se accede usando formas especiales de acceso llamadas "entradas del timer" que son similares a las de los canales. La sintaxis es: input = timer input | delayed input timer input = timer ? variable delayed input = timer ? AFTER expression Una entrada timer recibe un valor del timer nombrado en la izquierda del s¡mbolo de entrada `?`, y asigna ese valor a la variable nombrada a la derecha del s¡mbolo. Una entrada con retraso (delayed input) espera a que el valor del timer nombrado a la izquierda de s¡mbolo `?`, sea mayor que el valor de la expresi¢n de la derecha de la palabra reservada AFTER. Por ejemplo: ClockA ? time recoge un valor del timer "ClockA" y lo asigna a la variable "time". Pueden aparecer entradas del mismo timer en cualquier n£mero de componentes en paralelo como entradas desde canales. En el siguiente ejemplo: ClockA ? AFTER time la entrada espera hasta que el valor de "ClockA" sea mayor que el valor de "time". Un ejemplo de entradas de timers en puntos distintos de un programa y en los que se ha fijado un retraso es: SEQ ClockA ? time ClockA ? AFTER time PLUS delay Aqu¡ se recoje un valor en "time" que representa la hora actual. Se produce una entrada adicional despu‚s de que el valor del reloj sea mayor que "time" m s el retraso "delay". I.2.2.2. Array En Occam un array es un grupo de objetos que son todos del mismo tipo. Se combinan juntos en un objeto con un nombre. Cada objeto en el array puede ser especificado o referido a trav‚s de su sub¡ndice o su posici¢n en el array. La declaraci¢n de un array viene a ser similar a otros lenguajes, aunque en este caso el n£mero de componentes del array se encuentra entre corchetes que preceden al tipo. Por ejemplo: [50]INT total: -- Array de 50 enteros llamado total En la declaraci¢n se especifica el tama¤o, o n£mero de componentes y tipo. La numeraci¢n en Occam comienza en 0 con lo que el rango de elementos en la definici¢n anterior va desde total[0] hasta total[49]. Los tipos de array se construyen de n componentes de tipo T. Los arrays pueden ser del tipo canal, timer o de cualquier tipo de dato, dependiendo del tipo de sus componentes. Dos arrays tienen el mismo tipo si tienen el mismo n£mero de componentes y el tipo de sus componentes es el mismo. En el tipo array [e]T, el valor e define el n£mero de componentes del array y T define el tipo de las componentes. Se puede seleccionar una componente de un array haciendo referencia al sub¡ndice. Por ejemplo v[e] selecciona la componente e+1 de v; tambi‚n se puede seleccionar un conjunto de elementos. Por ejemplo v[FROM e FOR c] seleccionar  v[e], v[e+1], ....., v[e+c-1]. Aqu¡ c especifica el n£mero de componentes seleccionado. Occam permite al programador hacer asignaciones de arrays completos y segmentos de arrays en una £nica sentencia. Por ejemplo: [20]INT a.1, a.2: SEQ a.1 := a.2 asigna el contenido total de a.2 a a.1 y, hace que el traductor Occam lo implemente de la manera m s eficiente posible. Tambi‚n es posible asignar segmentos de un array. Por ejemplo, si consideramos de nuevo los arrays a.1 y a.2 anteriores y deseamos copiar los cinco £ltimos elementos de a.2 en las 5 primeras entradas de a.1, podemos escribir: [20]INT a.1,a.2: SEQ [a.1 FROM 0 FOR 5] := [a.2 FROM 15 FOR 5] de esta forma el traductor de Occam lo har  de la manera m s eficiente posible. Las cotas usadas como l¡mites de los segmentos, a saber, 0 y 5 y, 15 y 5 respectivamente, pueden sustituirse por variables. La £nica restricci¢n es que, la cota inferior no debe ser negativa y la cota superior, que es la longitud del segmento, debe ser mayor que cero. Occam tambi‚n permite asignar un segmento de un array a una lista de variables. Por ejemplo, puede escribirse: [20]INT a.1: INT v.1,v.2,v.3: SEQ [v.1,v.2,v.3] := [a.1 FROM 4 FOR 3] dar  como resultado las asignaciones de a.1[4] al entero v.1, a.1[5] a v.2 y a.1[6] a v.3.