Skip to main content

Propagación constante

Con el CODESYS Static Analysis versión V5.0.0.0, el análisis del código se basa en la propagación constante. Los resultados de la propagación constante se utilizan para diversas comprobaciones. Por ejemplo, comprueba si los punteros no son iguales a 0 o si los índices de la matriz están fuera del rango válido.

Puede respaldar eficazmente el análisis estático con solo saber cómo funciona este análisis y cuáles son sus limitaciones.

Propagación constante

El análisis estático intenta determinar el valor de una variable en función de su uso.

ejemplo 1. Ejemplo
PROGRAM PLC_PRG
//Declaration
VAR
    x: INT;
    bTest: BOOL;
END_VAR
//Implementation
x := 99;
IF x < 100 THEN
    bTest := TRUE;
END_IF

En la implementación en la línea 1, la propagación constante registra el valor 99 para la variable x utilizar este valor para análisis posteriores. El análisis luego reconoce que la expresión en el siguiente IF-Declaración constante TRUE es.



Propagación constante realizada localmente

Un valor se determina sólo localmente en el bloque de funciones. Es irrelevante cómo se pasa una entrada. Los resultados de las llamadas a funciones también son irrelevantes.

ejemplo 2. Ejemplo
FUNCTION Func : BOOL
//Declaration
VAR_INPUT
    bText : BOOL;
END_VAR
//Implementation
IF bTest THEN
    Func := OtherFunc(TRUE);
END_IF


Incluso si el parámetro bTest se establece en TRUE en cada llamada, esto no tiene ningún efecto sobre la propagación constante. Incluso si OtherFunc(TRUE) siempre regresa TRUE, esto no tiene ningún efecto sobre la propagación constante.

Sólo las variables temporales tienen valores iniciales.

Las variables locales estáticas en programas y bloques de funciones no asumen ningún valor inicial. Las variables conservan sus valores de la última llamada y, por lo tanto, en principio pueden ser "cualquier cosa".

Las variables locales en funciones y las variables temporales tienen un valor inicial en cada llamada. La propagación constante se calcula con este valor inicial.

ejemplo 3. Ejemplo
PROGRAM PLC_PRG
//Declaration
VAR
    x: INT := 6;
    bTest: BOOL;
END_VAR
VAR_TEMP
    y : INT := 8;
END_VAR
bText := x < y;

La variable y se ejecuta cada vez PLC_PRG tiene el valor 8. La variable x, sin embargo, no necesariamente. Por lo tanto, la propagación constante sólo se utiliza para y asumir un valor, pero no por x.

Se recomienda declarar variables que siempre se escriben primero y luego se leen como variables temporales.



La propagación constante determina rangos de valores para tipos de datos numéricos.

Para reducir la complejidad, se determina un rango de valores con límites superior e inferior para cada variable.

ejemplo 4. Ejemplo
PROGRAM PLC_PRG
VAR
    x: INT := 6;
    bTest: BOOL;
    y : INT;    
END_VAR
//Implementation
IF bTest THEN
    x := 1;
ELSSE
    x := 100;
END_IF
IF x = 77 THEN
    y := 13;
END_IF

Aquí el rango de valores. [1..100] se determina para la variable x. Como resultado, en la línea 7, la comparación x = 77 no se reconoce como una expresión constante porque 77 está dentro del rango de valores.



Las expresiones complejas recurrentes no se reconocen como la misma variable.

Es posible que las expresiones complejas no tengan un valor asignado. Si este tipo de expresiones aparecen varias veces, resulta útil introducir una variable auxiliar.

ejemplo 5. Ejemplo
PROGRAM PLC_PRG
VAR
    x: DINT;
    py : POINTER TO INT;
    y : INT; 
    testArray : ARRAY [0..4] OF DINT;   
END_VAR
//Implementation
IF py^ >= 0 AND py^<= 4 THEN
    x := testArray[py^];
END_IF
y := py^;
IF y <= 0 AND y <=4 THEN
    x := testArray[y];
END_IF

En la línea 2 se emite error por un posible acceso mediante puntero a un valor, aunque se comprueba la zona a la que apunta el puntero. Si el valor se copia primero en una variable local y se verifica su rango, entonces la propagación constante puede determinar el rango de valores para esa variable y permite el acceso a la matriz en la línea 7.



Derivación

Para las bifurcaciones, las ramas individuales se calculan por separado. A continuación, los rangos de valores de los rangos individuales se combinan para formar un nuevo rango de valores.

ejemplo 6. Ejemplo
//Implementation
IF func(TRUE) THEN
    x := 1;
ELSE 
    x := 10;
END_IF

IF func(FALSE) THEN
    y := x;
ELSE
    Y := 2*x;
END_IF

En la línea 6, x tiene el rango [1..10]. Después de la línea 11, y tiene el rango de valores [1..20]; esto resulta de la unión de los dos rangos de valores [1..10] y [2..20].



Condiciones

ejemplo 7. Ejemplo

Las condiciones pueden restringir el rango de valores de una variable en un bloque de código. Se pueden combinar varias condiciones. Las condiciones mutuamente excluyentes también pueden dar como resultado un rango de valores vacío.

IF y > 0 AND y < 10 THEN
    x := y;
ELSE
    x:= 0;
END_IF
IF x < 0 THEN
    i := 99;
END_IF

y tiene el rango de valores [1..9] en la línea 2. Esto da como resultado el rango de valores [0..9] para x en la línea 6. Combinado con la condición x < 0, esto da como resultado un conjunto vacío de valores posibles para x en la línea 8. No se puede acceder al código. El análisis estático informará que la condición x < 0 siempre regresa FALSE en este punto.



Bucle

La propagación constante hará un bucle en el código hasta que los valores de las variables en el bucle ya no cambien. Se supone que un bucle se puede ejecutar cualquier número de veces. Los valores determinados hasta ahora se combinan con los valores anteriores. Las variables que se modifican dentro del bucle tienen un rango cada vez mayor. Aquí, la propagación constante no toma todos los valores posibles para los rangos, sino que utiliza sólo los límites que aparecen en el código y también los valores 0, 1, 2, 3 y 10 porque suelen ser relevantes.

ejemplo 8. Ejemplo

La forma más sencilla de describir el procedimiento es con el ejemplo:

PROGRAM PLC_PRG
VAR
    x: DINT;
    i : DINT;
    y : DINT;
END_VAR
//Implementation
x := 0;
y := 0;
FOR i := 0 TO 5 DO
    x := x + 1;
    y := i;
END_FOR

La propagación constante sabe lo siguiente sobre el bucle:

i, x, y y son 0 al comienzo de la primera ejecución del bucle. La condición i <= 5 se aplica al código en el bucle. La condición i > 5 se aplica al código después del bucle.

Para los valores de las variables en el bucle, la propagación constante determina los siguientes valores:

i

x

y

[0..5]

[0..MAXDINT]

[0..5]

En detalle, se pasan por los siguientes pasos intermedios:

Aprobar

i

x

y

1

0

[0..1]

0

i se inicializó con 0; y siempre obtiene los mismos valores que i.

2

[0..1]

[0..2]

[0..1]

6

[0..5]

[0..6]

[0..5]

Primero, el rango [0..6] en realidad se calcula para i. Sin embargo, se sabe que i < 5 es una condición. Por lo tanto, el valor del código en el bucle está limitado a este valor.

7

[0..5]

[0..7]

[0..5]

10

[0..5]

[0..10]

[0..5]

x se incrementa cada vez más. De 10, sin embargo, el valor se "redondea" a MAXINT.

11

[0..5]

[0..MAXDINT]

[0..5]

MAXDINT + 1 resultados en MAXDINT

A partir de las 11

A partir del undécimo pase, los valores en el bucle no cambiarán. La propagación ha terminado.

Además, i = 6 se aplica al código que sigue a este bucle. El rango [0..6] se determina en el bucle y esto se combina con la condición i > 5, lo que da como resultado exactamente el valor 6.