Dichiarazione del modulo
La dichiarazione dei moduli viene eseguita con un proprio linguaggio di descrizione che è simile alla dichiarazione delle variabili nel codice testo strutturato (ST).
Formato della dichiarazione del modulo
Un'intestazione del modulo MODULE<name>
inizia la dichiarazione. Questo è seguito da un elenco di "sezioni".
Ogni sezione è introdotta dalla parola chiave SEC
(per "sezione") e un nome univoco. La parola chiave END_SEC
chiude la sezione. Il contenuto di una sezione contiene un elenco di voci composto da ulteriori sezioni o cosiddette definizioni.
Una definizione è composta da un nome e un valore opzionale e termina con un punto e virgola.
I commenti possono essere utilizzati come nel codice ST: "//"" per commenti a riga singola e "(*" e "*)" per commenti su più righe. È possibile utilizzare spazi bianchi (tabulazioni e spazi) e fine riga/avanzamento riga per separare le parti di una dichiarazione, altrimenti vengono ignorati durante l'ulteriore elaborazione.
Come con il codice ST, la distinzione tra maiuscole e minuscole non fa differenza.
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
Nella riga 01 c'è la definizione del nome del modulo "Persistenza". IMPLEMENTED_BY
definisce il blocco funzione "PersitenceFB" che contiene la logica del modulo. Questo blocco funzione deve derivare da IModule
. Nella riga 02 la sezione MetaData
inizia e termina con la riga 08. Questa sezione contiene cinque definizioni. La possibilità di sezioni nidificate è mostrata nella sezione Toplevel
(righe 09–16) che contiene la sottosezione STANDARD_TASK
(riga 10).
Sintassi della dichiarazione del modulo
In questa sezione verrà spiegata la sintassi e la struttura sintattica consentita per una dichiarazione di modulo.
Nello scanner seguente i token verranno scritti in maiuscolo (esempio: ID
). I non terminali della grammatica saranno scritti tra parentesi graffe (esempio: {Entry}
).
Analisi lessicale (scanner)
Nel primo passo verranno creati i cosiddetti token (o lessemi) dai caratteri della dichiarazione del modulo (esempio: parole chiave, costanti, identificatori).
Gli spazi bianchi e i caratteri newline/linefeed separano i token, ma altrimenti verranno ignorati. Anche i commenti verranno ignorati per l'ulteriore trattamento della dichiarazione. (I commenti possono essere scritti su una sola riga (//
") o commenti su più righe ((*
E *)
) come nel linguaggio ST. I commenti su più righe possono essere nidificati.
Fondamentalmente un token ha sempre una lunghezza massima. Per esempio a123
verrà interpretato come un identificatore e non come un identificatore a
seguito da un letterale 123
.
L'ordine dei token nell'elenco seguente mostra la loro priorità. Ad esempio l'input MODULE
verrà intesa come parola chiave e non come identificatore.
Parole chiave:
MODULE
,SEC
,END_SEC
,IMPORTS
, EIMPLEMENTED_BY
OP: una sequenza non vuota dei seguenti caratteri:
.:,%()[]{}<>|+-*/@!?^°=\~
Nota: gli indicatori di commento
//
,(*
, E*)
hanno una priorità più alta rispetto agli operatori. Non può esserci alcun commento all'interno di un operatore, nessun commento può essere, ad esempio:+//+
verrà, secondo la regola della massima lunghezza, interpretato come un operatore e non come+
seguito da un commento.LIT: un valore letterale IEC, come viene utilizzato in ST, esempio:
1.4
,tod#12:13:14
. Ciò include i valori letterali booleaniTRUE
EFALSE
(maiuscolo o minuscolo non è rilevante).Nota: letterali non tipizzati con segno negativo (
-1
,-3.2
) verranno letti come due token, cioè come operatore-
seguito da un letterale non tipizzato. Il risultato di questi valori letterali numerici non tipizzati non può mai essere negativo. Letterali digitati (INT#-34
) verrà sempre interpretato come un token.ID: un identificatore IEC valido (
[a-zA-Z_][a-zA-Z0-9_]*
), per cui non sono ammesse due sottolineature consecutive. Ciò include, contrariamente a ST, anche le parole chiave di ST (cioè:FUNCTION
,INT
,EXTENDS
,…)Punto e virgola: il carattere
;
Sintassi (parser)
La sintassi della dichiarazione del modulo è definita dalla seguente grammatica. µ
è una sequenza vuota.
{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}
L'elenco dei valori di definizione ({ValList}
) deve essere completato con un punto e virgola. Ciò semplifica la grammatica ed evita ambiguità, perché il punto e virgola non può far parte di un valore ({VAL}
), tranne che all'interno di una stringa letterale.
L'operatore di assegnazione (:=
) delle definizioni ({Def}
) serve anche a evitare ambiguità ({QID}
) dei nomi e dei valori delle definizioni.
Tipi definiti per le definizioni
Testo: ID.ID (nome dell'elenco di testi e identificatore dell'elenco di testi) - vedi Localizzazione delle stringhe dell'elenco di testi
Immagine: ID.ID (nome del pool di immagini e identificatore del pool di immagini)
ID (identificatore IEC)
QID (identificatore qualificato):
{QID} ::= ID | ID.ID
CategoryPath ::= {StringLiteral} | {CategoryPath}
Cardinalità:
[{MIN} .. {MAX}]
|[ {MIN} .. INF [
{MIN}
, E{MAX}
sono valori letterali interi e non negativi. Se{MAX} != INF
, Poi{MIN} <= {MAX}
deve applicare.StringLiteral: una stringa letterale IEC può contenere interruzioni di riga.
StdTaskFlags ::= {StdTaskFlag} | {StdTaskFlags} StdTaskFlag ::=
NONE
|CREATE_IF_MISSING
|READONLY
Letterale: qualsiasi letterale IEC o QID (per costanti Enum)
DTBoolFlag:
µ
(sequenza vuota) |TRUE
|FALSE
Tipo di slot:
SUBMODULE
|REFERENCE
Pragma:
[ {PragmaList} ] {PragmaList} ::= {Pragma}
|{Pragma} , {PragmaList} {Pragma} ::= { ( ID
|{StringLiteral}
|{OP2} )+ } {OP2}
: tutti gli operatori tranne{, }, [, ]
E,
.Percorso istanza:
InstancePath ::= {IComp}
|{IComp} . {IComp}
mit{IComp} ::= ID {ArrayAccess}*
e{ArrayAccess} ::= [ {IntList} ]
e{IntList} ::= Int
|Int , {IntList}
Rif.Attività: Attività_Standard. (
Low
|Medium
|High
) |Custom_Task.ID
Percorsi delle istanze
In alcune posizioni nella dichiarazione del modulo è possibile definire percorsi di istanza per indirizzare una variabile di un blocco funzione: per parametri, slot, I/O, array con dimensioni variabili e riferimenti di istanza.
Un percorso di istanza è definito come una sequenza non vuota di componenti, separati da punti: C1.C2…CN
. Un componente deve essere un identificatore IEC o un componente seguito da un'espressione di indice [i1, …, iN]
, Dove i1
A iN
sono valori interi.
I percorsi delle istanze sono sempre relativi al blocco funzione che implementa la logica del modulo. Il primo componente del percorso dell'istanza è un membro (VAR_INPUT
O VAR_OUTPUT
, a seconda del caso d'uso) del blocco funzione. In caso di componenti aggiuntivi nel percorso dell'istanza, questi componenti indirizzano la variabile all'interno del membro. Altrimenti viene indirizzato il membro stesso. I percorsi delle istanze possono essere limitati alle variabili di ingresso o di uscita (esempio: per I/O). Per le strutture queste restrizioni non valgono. Questo tipo di percorsi di istanza sono chiamati percorsi di istanza di input risp. percorsi delle istanze di output.
Localizzazione delle stringhe dell'elenco di testi
I testi nei moduli (esempio: descrizione del modulo, nome, descrizione del parametro) possono essere visualizzati in diverse lingue. Questi testi vengono gestiti in elenchi di testi.
Il nome della lingua è di formato
<LanguageCode>[-<Country/Region>]
(esempio:en-US
,de-DE
).<LanguageCode>
è il nome della lingua secondo ISO 639-1 (esempio:de
Oen
).<Country/Region>
è un codice paese secondo ISO 3166.Quando si richiama una voce dell'elenco di testi, il sistema cerca innanzitutto il nome completo della lingua. Se non viene trovato nulla, cerca il file
<LanguageCode>
. Se anche questa ricerca fallisce, verrà utilizzato il testo predefinito.
Lingua | Nome della lingua |
---|---|
Cinese | zh-CHS |
Inglese | it-USA |
francese | fr-FR |
Tedesco | de-DE |
Italiano | esso esso |
giapponese | ja-JP |
portoghese | pt-PT |
russo | ru-RU |
spagnolo | es-ES |
Derivazione delle dichiarazioni dei moduli
Analogamente all'ereditarietà orientata agli oggetti di un blocco funzione A da un blocco funzione B ("EXTENDS") esiste la possibilità di derivare dichiarazioni di moduli utilizzando l'istruzione IMPORTS
parola chiave. I modificatori UPDATE
E HIDE
vengono trattati in modo speciale.
Il nome del modulo importato deve essere specificato con namespace se questo modulo è definito in una libreria diversa.
Non sono consentite importazioni cicliche, in particolare un modulo non deve importare se stesso. (Esempio di importazione ciclica: il modulo M_1 importa il modulo M_2, M_2 importa M_3, …, M_N importa nuovamente M_1.)
Un modulo derivato può essere definito senza il file
IMPLEMENTED_BY
direttiva. In questo caso verrà utilizzato il blocco funzione del modulo base.Se un modulo derivato specifica un blocco funzione (tramite l'uso di
MPLEMENTED_BY
), questo blocco funzione deve derivare dal blocco funzione del modulo base oppure deve essere identico ad esso.Un modulo derivato eredita tutte le sezioni del modulo base. Può aggiungere nuove sezioni o modificare sezioni esistenti.
Una sezione può essere modificata nel modulo derivato utilizzando lo stesso nome e destinazione estesi con il modificatore
UPDATE
. In questo caso, le sue voci vengono modificate. Tutte le definizioni mancanti della sezione nel modulo derivato verranno riprese dal modulo base.Il modificatore
UPDATE
EHIDE
può essere utilizzato solo se la rispettiva sezione (nome e destinazione) è definita nel modulo base. Al contrario, una sezione definita nel modulo base può essere utilizzata nel modulo derivato solo se ha l'estensioneHIDE
OUPDATE
modificatore. Se c'è solo ilHIDE
modificatore nella sezione e nonUPDATE
, allora non sono ammesse definizioni.Alcune voci devono essere modificate nel modulo derivato (esempio: la descrizione).
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
Nell'esempio sopra il parametro paramIn
del modulo MBase
è nascosto nel modulo derivato MDerived
(utilizzando il HIDE
modificatore) e allo stesso tempo un nuovo valore predefinito (TRUE
) è impostato.
Note sull'ordine delle sezioni e definizioni
L'ordine delle sezioni direttamente dopo l'intestazione del modulo è irrilevante. All'interno delle sezioni l'ordine può essere molto importante. Ad esempio, l'ordine delle dichiarazioni degli slot definisce l'ordine dei moduli nell'albero dei moduli.
L'ordine delle definizioni è sempre irrilevante.
Le sezioni dei moduli base sono sempre definite prima delle sezioni del modulo stesso.
Se una sezione del modulo base viene modificata mediante l'uso di
UPDATE
OHIDE
, il suo ordine non viene influenzato.Non è possibile per un modulo derivato modificare l'ordine definito nel modulo base.
Completamento automatico e "componenti elenco"
Quando si inizia a digitare nell'editor del modulo, tutte le definizioni di sezione disponibili/possibili vengono visualizzate in un menu "elenco componenti". Vengono mostrate solo le sezioni e le definizioni significative per la posizione corrente. Anche se alcune voci di sottosezione hanno lo stesso nome delle voci di sottosezione di altre sezioni, proverà a visualizzare solo le definizioni di sezione corrispondenti.
Se Ritorno viene premuto dopo aver completato la prima riga di una sezione, la sezione verrà completata con tutte le definizioni/sezioni necessarie e il file END_SEC
.
Dopo le definizioni delle variabili, le variabili di input/output vengono presentate dalle definizioni dei "componenti dell'elenco". I flag o i valori predefiniti vengono presentati anche in una selezione "elenco componenti", che mostra i possibili flag/valori.
Dopo le definizioni, che utilizzano voci di elenchi di testi o voci di pool di immagini (esempio: la maggior parte delle volte Desc :=
), viene presentato un menu "Elenco componenti" che comprende tutti gli elenchi di testi o i pool di immagini disponibili e visibili e le relative voci.
Premendo F2, è possibile aprire il supporto di input corrispondente.