Gli elementi di dati da utilizzare in un programma ULP devono essere definiti prima dell'utilizzo. Sono disponibili tre tipi di definizioni:
L'ambito di una definizione di costante o variabile di estende dalla riga in cui è stata definita alla fine del blocco corrente o alla fine del programma ULP, se la definizione appare all'esterno di un blocco.
L'ambito di una definizione di funzione è inclusa tra la parentesi graffa di chiusura (}) del corpo della funzione e la fine del ULP.
Le costanti vengono definite utilizzando la parola chiave enum, come in
enum { a, b, c };
che definisce le tre costanti a, b e c, assegnando loro i valori rispettivamente di 0, 1 e 2.
Le costanti possono anche essere inizializzate su valori specifici, come
enum { a, b = 5, c };
dove a è 0, b è 5 e c è 6.
La sintassi generale di una definizione di variabile è
[numeric] type identifier [= initializer][, ...];
dove type uno dei tipi di dati o di oggetti, identifier è il nome della variabile e initializer è un valore iniziale facoltativo.
Più definizioni di variabile dello stesso tipo sono separate da virgole (,).
Se l'identificatore è seguito da una coppia di parentesi ([ ]), definisce una serie di variabili del tipo specificato. La dimensione di una serie viene regolata automaticamente in fase di esecuzione.
La parola chiave facoltativa numeric può essere utilizzata con le serie di stringhe per ordinarle in ordine alfanumerico mediante la funzione sort().
Per default (se initializer non è presente), le variabili dati vengono impostate su 0 (o "", nel caso di una stringa) e le variabili oggetto sono "non valide".
| int i; | definisce una variabile int denominata i |
| string s = "Hello"; | definisce una variabile stringa denominata s e la inizializza ad "Hello" |
| real a, b = 1.0, c; | definisce tre variabili reali denominate a, b e c, inizializzando b sul valore 1.0 |
| int n[] = { 1, 2, 3 }; | definisce una serie di interi, inizializzando i primi tre elementi a 1, 2 e 3 |
| numeric string names[]; | definisce una serie di stringhe che può essere ordinata in ordine alfanumerico |
| UL_WIRE w; | definisce un oggetto UL_WIRE denominato w |
| I membri degli elementi della serie dei tipi di oggetto non sono accessibili direttamente: | |
| UL_SIGNAL signals[]; | |
| ... | |
| UL_SIGNAL s = signals[0]; | |
| printf("%s", s.name); |
È possibile scrivere le proprie funzioni ULP e richiamarle in modo analogo alle funzioni integrate. La sintassi generale di una definizione di funzione è
type identifier(parameters)
{
statements
}dove type è uno dei tipi di dati o di oggetto, identifier è il nome della funzione, parameters è un elenco di definizioni di parametri separati da virgola e statements è una sequenza di istruzioni. Le funzioni che non restituiscono un valore sono di tipo void.
Una funzione deve essere definita prima di poterla chiamare e una funzione non può essere chiamata in modo ricorsivo (una funzione non può chiamare sé stessa).
Le istruzioni nel corpo della funzione possono modificare i valori dei parametri, ma ciò non avrà alcun effetto sugli argomenti della chiamata di funzione.
L'esecuzione di una funzione può essere terminata dall'istruzione return. In assenza dell'istruzione return, il corpo della funzione viene eseguito fino alla parentesi graffa di chiusura (}).
Una chiamata alla funzione exit() interromperà l'intero ULP.
Se l'ULP contiene una funzione denominata main(), questa verrà chiamata in modo esplicito come funzione principale e il valore restituito sarà quello restituito del programma.
Gli argomenti della riga di comando sono disponibili per il programma tramite le variabili integrate globali argc e argv.
int CountDots(string s)
{
int dots = 0;
for (int i = 0; s[i]; ++i)
if (s[i] == '.')
++dots;
return dots;
}
string dotted = "This.has.dots...";
output("test") {
printf("Number of dots: %d\n",
CountDots(dotted));
}