Declaración del módulo
La declaración de módulos se realiza con un lenguaje de descripción propio similar a la declaración de variables en código de texto estructurado (ST).
Formato de la declaración del módulo.
Un encabezado del formulario MODULE<name>
Comienza la declaración. A esto le sigue una lista de "secciones".
Cada sección está introducida por la palabra clave. SEC
(para "sección") y un nombre único. La palabra clave END_SEC
cierra la sección. El contenido de una sección contiene una lista de entradas que se componen de otras secciones o las llamadas definiciones.
Una definición consta de un nombre y un valor opcional y termina con un punto y coma.
Los comentarios se pueden usar como en el código ST: "//"" para un comentario de una sola línea y "(*" y "*)" para comentarios de varias líneas. Se pueden usar espacios en blanco (tabulaciones y espacios) y nueva línea/avance de línea para separar las partes. de una declaración; de lo contrario, se ignorarán durante el procesamiento posterior.
Al igual que con el código ST, la distinción entre mayúsculas y minúsculas no hace ninguna diferencia.
01 MODULE Persistence IMPLEMENTED_BY PersistenceFB 02 SEC MetaData 03 NAME := TL.ChannelName ; 04 DESC := TL.ChannelDesc ; 05 COLLECTION CATEGORY := ’Persistence’TL.Collection ; 06 ICON_16 := IP.Channel16 ; 07 ICON_32 := IP.Channel32 ; 08 END_SEC 09 SEC Toplevel 10 SEC STANDARD_TASK : LOW 11 NAME := LOW ; 12 DESC := TL.TaskLow ; 13 FLAGS := CREATE_IF_MISSING | READONLY ; 14 END_SEC 15 GVL_NAME := 'GVL_%InstanceName%' ; 16 END_SEC
En la línea 01 está la definición del nombre del módulo "Persistencia". IMPLEMENTED_BY
define el bloque de funciones "PersitenceFB" que contiene la lógica del módulo. Este bloque de funciones debe derivar de IModule
. En la línea 02 la sección MetaData
comienza y termina con la línea 08. Esta sección contiene cinco definiciones. La posibilidad de secciones anidadas se muestra en la sección Toplevel
(líneas 09 a 16) que contiene la subsección STANDARD_TASK
(línea 10).
Sintaxis de la declaración del módulo.
En esta sección se explicará la sintaxis y la estructura sintáctica permitida de una declaración de módulo.
En el siguiente escáner, los tokens se escribirán en mayúsculas (ejemplo: ID
). Los no terminales de la gramática se escribirán entre llaves (ejemplo: {Entry}
).
Análisis léxico (escáner)
En el primer paso se crearán los llamados tokens (o lexemas) a partir de los caracteres de la declaración del módulo (ejemplo: palabras clave, constantes, identificadores).
Los espacios en blanco y los caracteres de nueva línea/avance de línea separan los tokens, pero de lo contrario se ignorarán. Los comentarios también serán ignorados para el tratamiento posterior de la declaración. (Los comentarios se pueden escribir en una sola línea (//
") o comentarios de varias líneas ((*
y *)
) como en el lenguaje ST. Los comentarios de varias líneas se pueden anidar.
Básicamente, un token siempre tiene una longitud máxima. Por ejemplo a123
se interpretará como un identificador y no como un identificador a
seguido de un literal 123
.
El orden de los tokens en la lista siguiente muestra su prioridad. Por ejemplo la entrada MODULE
se entenderá como palabra clave y no como identificador.
Palabras clave:
MODULE
,SEC
,END_SEC
,IMPORTS
, yIMPLEMENTED_BY
OP: una secuencia no vacía de los siguientes caracteres:
.:,%()[]{}<>|+-*/@!?^°=\~
Nota: Los marcadores de comentarios
//
,(*
, y*)
tienen mayor prioridad que los operadores. No puede haber ningún comentario dentro de un operador, ningún comentario puede ser, ejemplo:+//+
se interpretará, según la regla de la longitud máxima, como un operador y no como+
seguido de un comentario.LIT: Un literal IEC, tal como se usa en ST, ejemplo:
1.4
,tod#12:13:14
. Esto incluye los literales booleanos.TRUE
yFALSE
(Las mayúsculas o minúsculas no son relevantes).Nota: Literales sin tipo con signo negativo (
-1
,-3.2
) se leerá como dos tokens, es decir, como operador-
seguido de un literal sin tipo. Como resultado de estos literales numéricos sin tipo, nunca puede ser negativo. Literales escritos (INT#-34
) siempre se interpretará como un token.ID: un identificador IEC válido (
[a-zA-Z_][a-zA-Z0-9_]*
), por lo que no se permiten dos subrayados consecutivos. A diferencia de ST, esto incluye también las palabras clave de ST (es decir:FUNCTION
,INT
,EXTENDS
,…)PUNTO Y COMA: el personaje
;
Sintaxis (analizador)
La sintaxis de la declaración del módulo está definida por la siguiente gramática. µ
es una secuencia vacía.
{MDecl} ::= MODULE {QID} {ImplSpec} {ImportsSpec} {MBody} {ImplSpec} ::= IMPLEMENTED_BY {QID} | µ {ImportsSpec} ::= IMPORTS {QID} | µ {MBody} ::= {SecList} {SecList} ::= {Modifiers} {Sec} {SecList} | µ {Sec} ::= SEC {QID} {SecTarget} {EntryList} END_SEC {SecTarget} ::= OP(":") {QID} | µ {Modifiers} ::= OP("[") {ModifierList} OP("]") | µ {ModifierList} ::= {QID} OP(",") {ModifierList} | {QID} {EntryList} ::= {Modifiers} {Entry} {EntryList} {Entry} ::= {Sec} | {Def} {Def} ::= {QID} OP(":=") {ValList} SEMICOLON | {QID} SEMICOLON {ValList} ::= {Val} {ValList} | {Val} {Val} ::= ID | LIT | OP {QID} ::= ID | ID OP(".") {QID}
La lista de valores de definición ({ValList}
) debe completarse con punto y coma. Esto simplifica la gramática y evita ambigüedades, porque el punto y coma no puede ser parte de un valor ({VAL}
), excepto dentro de una cadena literal.
El operador de asignación (:=
) de definiciones ({Def}
) también sirve para evitar ambigüedades ({QID}
) de nombres y valores de definiciones.
Tipos definidos para definiciones
Texto: ID.ID (nombre de la lista de texto e identificador de la lista de texto) - consulte Localización de cadenas de listas de texto.
Imagen: ID.ID (nombre del grupo de imágenes e identificador del grupo de imágenes)
ID (identificador IEC)
QID (Identificador calificado):
{QID} ::= ID | ID.ID
CategoryPath ::= {StringLiteral} | {CategoryPath}
Cardinalidad:
[{MIN} .. {MAX}]
|[ {MIN} .. INF [
{MIN}
, y{MAX}
son literales enteros no negativos. Si{MAX} != INF
, entonces{MIN} <= {MAX}
tiene que aplicar.StringLiteral: un literal de cadena IEC puede contener saltos de línea.
Indicadores de tareas estándar ::= {Indicador de tareas estándar} | {StdTaskFlags} StdTaskFlag ::=
NONE
|CREATE_IF_MISSING
|READONLY
Literal: cualquier literal IEC o QID (para constantes Enum)
DTBoolFlag:
µ
(secuencia vacía) |TRUE
|FALSE
Tipo de ranura:
SUBMODULE
|REFERENCE
Pragmas:
[ {PragmaList} ] {PragmaList} ::= {Pragma}
|{Pragma} , {PragmaList} {Pragma} ::= { ( ID
|{StringLiteral}
|{OP2} )+ } {OP2}
: todos los operadores excepto{, }, [, ]
y,
.Ruta de instancia:
InstancePath ::= {IComp}
|{IComp} . {IComp}
mit{IComp} ::= ID {ArrayAccess}*
y{ArrayAccess} ::= [ {IntList} ]
y{IntList} ::= Int
|Int , {IntList}
TaskRef: Tarea_estándar. (
Low
|Medium
|High
) |Custom_Task.ID
Rutas de instancia
En algunas posiciones de la declaración del módulo, se pueden definir rutas de instancia para direccionar una variable de un bloque de funciones: para parámetros, ranuras, E/S, matrices con tamaño variable y referencias de instancia.
Una ruta de instancia se define como una secuencia de componentes no vacía, separados por puntos: C1.C2…CN
. Un componente debe ser un identificador IEC o un componente seguido de una expresión de índice [i1, …, iN]
, dónde i1
a iN
son valores enteros.
Las rutas de instancia siempre son relativas al bloque de funciones que implementa la lógica del módulo. El primer componente de la ruta de la instancia es un miembro (VAR_INPUT
o VAR_OUTPUT
, dependiendo del caso de uso) del bloque de funciones. En el caso de componentes adicionales en la ruta de la instancia, estos componentes abordan la variable dentro del miembro. De lo contrario, se dirige al propio miembro. Las rutas de instancia se pueden restringir a variables de entrada o salida (ejemplo: para E/S). Para estructuras estas restricciones no son válidas. Este tipo de rutas de instancia se denominan rutas de instancia de entrada, respectivamente. rutas de instancia de salida.
Localización de cadenas de listas de texto.
Los textos de los módulos (ejemplo: descripción del módulo, nombre, descripción del parámetro) se pueden mostrar en diferentes idiomas. Estos textos se gestionan en listas de textos.
El nombre del idioma es de formato.
<LanguageCode>[-<Country/Region>]
(ejemplo:en-US
,de-DE
).<LanguageCode>
es el nombre del idioma según ISO 639-1 (ejemplo:de
oen
).<Country/Region>
es un código de país según ISO 3166.Al recuperar una entrada de la lista de texto, el sistema primero busca el nombre completo del idioma. Si no encuentra nada, busca el
<LanguageCode>
. Si esta búsqueda también falla, se utilizará el texto predeterminado.
Idioma | Nombre del idioma |
---|---|
Chino | zh-CHS |
Inglés | es-US |
Francés | fr-fr |
Alemán | de-DE |
italiano | eso eso |
japonés | ja-JP |
portugués | pt-PT |
ruso | ru-RU |
Español | es-ES |
Derivando declaraciones de módulo
De manera análoga a la herencia orientada a objetos de un bloque de funciones A de un bloque de funciones B ("EXTENDS"), existe la posibilidad de derivar declaraciones de módulo mediante el uso de IMPORTS
palabra clave. Los modificadores UPDATE
y HIDE
son tratados de manera especial.
El nombre del módulo importado debe especificarse con un espacio de nombres si este módulo está definido en una biblioteca diferente.
No se permiten importaciones cíclicas; en particular, un módulo no debe importarse a sí mismo. (Ejemplo de una importación cíclica: el módulo M_1 importa el módulo M_2, M_2 importa M_3,…, M_N importa M_1 nuevamente.)
Un módulo derivado se puede definir sin el
IMPLEMENTED_BY
directiva. En este caso se utilizará el bloque de funciones del módulo base.Si un módulo derivado especifica un bloque de funciones (mediante el uso de
MPLEMENTED_BY
), este bloque de funciones debe derivar del bloque de funciones del módulo base o debe ser idéntico a él.Un módulo derivado hereda todas las secciones del módulo base. Puede agregar nuevas secciones o modificar secciones existentes.
Se puede modificar una sección en el módulo derivado usando el mismo nombre y destino extendido con el modificador
UPDATE
. En este caso, se modifican sus entradas. Todas las definiciones que falten de la sección en el módulo derivado se tomarán del módulo base.el modificador
UPDATE
yHIDE
sólo se puede utilizar si la sección respectiva (nombre y destino) está definida en el módulo básico. Por el contrario, una sección que está definida en el módulo base sólo puede usarse en el módulo derivado si tiene laHIDE
oUPDATE
modificador. Si solo existe elHIDE
modificador en la sección y noUPDATE
, entonces no se permiten definiciones.Algunas entradas deben cambiarse en el módulo derivado (ejemplo: la descripción).
MODULE MBase IMPLEMENTED_BY FBBase SEC MetaData DESC := TL.Desc_Base ; END_SEC SEC Parameters SEC Param : paramxIn Variable := xIn ; Name := TL.Param1_Name ; Desc := TL.Param1_Desc ; END_SEC END_SEC MODULE MDerived IMPORTS MBase [UPDATE] SEC MetaData DESC := TL.Desc_Derived ; END_SEC [UPDATE] SEC Parameters [UPDATE,HIDE] SEC Param : paramIn Variable := xIn ; DEFAULT := TRUE ; END_SEC END_SEC
En el ejemplo anterior el parámetro paramIn
del módulo MBase
está oculto en el módulo derivado MDerived
(mediante el uso del HIDE
modificador), y al mismo tiempo un nuevo valor predeterminado (TRUE
) Está establecido.
Notas sobre el orden de las secciones y definiciones.
El orden de las secciones inmediatamente después del encabezado del módulo es irrelevante. Dentro de las secciones el orden puede ser muy importante. Por ejemplo, el orden de las declaraciones de ranuras define el orden de los módulos en el árbol de módulos.
El orden de las definiciones siempre es irrelevante.
Las secciones de los módulos base siempre se definen antes que las secciones del propio módulo.
Si se cambia una sección del módulo base mediante el uso de
UPDATE
oHIDE
, su orden no se ve afectado.No es posible que un módulo derivado cambie el orden definido en el módulo base.
Autocompletar y "listar componentes"
Cuando comience a escribir en el editor de módulos, todas las definiciones de sección disponibles/posibles se muestran en un menú de "lista de componentes". Sólo se muestran secciones y definiciones significativas para la posición actual. Incluso si algunas entradas de subsección tienen el mismo nombre que las entradas de subsección de otras secciones, intentará mostrar solo las definiciones de sección coincidentes.
Si Devolver se presiona después de completar la primera línea de una sección, entonces la sección se completará con todas las definiciones/secciones necesarias y el END_SEC
.
Después de las definiciones de variables, las variables de entrada/salida se presentan mediante definiciones de "componentes de lista". Las banderas o valores predefinidos también se presentan en una selección de "componentes de lista", que muestra las posibles banderas/valores.
Después de las definiciones, que utilizan entradas de lista de texto o entradas de grupo de imágenes (ejemplo: la mayoría de las veces Desc :=
), se presenta un menú de "componentes de lista" que incluye todas las listas de texto o grupos de imágenes disponibles y visibles y sus entradas.
Presionando F2, se puede abrir el soporte de entrada correspondiente.