Appendice E: Il linguaggio Inform ================================= Fate riferimento a questa appendice per un sommario succinto ma essenzialmente completo del linguaggio di programmazione Inform; copre tutto quello che abbiamo trattato in questa guida, più vari costrutti che non sono capitati naturalmente, ed altri di natura avanzata od oscura. Literal ******* Nel linguaggio specialistico dei computer l'unità fondamentale di immagazzinamento dati è un byte composto da otto bit, in grado di memorizzare i valori tra 0 e 255. È così piccolo che è utile a contenere nient'altro che un singolo carattere, quindi la maggior parte dei computer lavora con gruppi di due, quattro od otto byte conosciuti come word [parola] (da non confondere con le voci del dizionario di Inform [dictionary word]). Nella Z-Machine una word di immagazzinamento è composta da due byte e potete specificare in varii modi il valore letterale che deve memorizzare. * Decimale: da -32768 a 32767 Esadecimale: da $0 a $FFFF Binario: da $$0 a $$1111111111111111 * Azione: ##Look * Carattere: 'a' * Voce di dizionario: 'maiale' (fino a nove caratteri significativi); usate l'accento circonflesso "^" per indicare l'apostrofo Parola plurale: 'maiali//p' Parola di un carattere: "e" (solo nella proprietà name) o "e//" * Stringa: "l'avventura del maiale" (per un massimo di 4000 caratteri circa); può includere valori speciali tra cui: ^ vai a nuova riga ~ virgolette " @@64 il segno della chiocciola "@" @@92 barra inversa (backslash) "\" @@94 accento circonflesso "^" @@126 tilde "~" @`a a con accento grave "à", e così via @LL il simbolo della sterlina "£", e così via @@00..@@31 stringhe da 00 a 31 Nomi **** Sono gli identificatori di const_id [costanti], var_id [variabili], array [matrici], class_id [classi], obj_id [oggetti], property [proprietà], attribute [attributi], routine_id o label [etichette] di Inform. Accettano fino a 32 caratteri: alfabetici (maiuscole e minuscole non fanno differenza), numerici e l'underscore (_); il primo carattere non deve essere un numero. Costanti ******** Valori word con un nome, che non cambiano durante l'esecuzione, e che sono sono inzializzati a zero in mancanza di altra indicazione: Constant const_id; Constant const_id = espressione; Costanti standard sono true (1), false (0) e nothing (0), anche NULL (-1). Per definire una costante (a meno che già esista): Define const_id espressione; Variabili ed array [matrici] **************************** Valori byte/word con un nome che possono cambiare durante l'esecuzione e che sono inzializzati a zero in mancanza di altra indicazione: Una variabile globale è una word singola: Global var_id; Global var_id = espressione; Un array di word è un insieme di word globali a cui si accede con array-->0, array-->1, ..., array-->(N-1): Array array --> N; Array array --> espressione1 espressione2 ... espressioneN; Array array --> "stringa"; Un array di tabelle è un insieme di word globali a cui si accede con array-->1, array-->2, ..., array-->N, ed in cui array-->0 è inzializzato a N: Array array table N; Array array table espressione1 espressione2 ... espressioneN; Array array table "stringa"; Un array di byte è un insieme di byte globali a cui si accede con array->0, array->1, ..., array->(N-1): Array array -> N; Array array -> espressione1 espressione2 ... espressioneN; Array array -> "stringa"; Un array di stringhe è un insieme di byte globale a cui si accede con array->1, array->2, ..., array->N, ed in cui array->0 è inzializzato a N: Array array string N; Array array string espressione1 espressione2 ... espressioneN; Array array string "stringa"; In tutti questi casi i caratteri della stringa che inizializza sono spacchettati nei singoli elementi byte/word dell'array. Consultate anche Oggetti (per le variabili di proprietà) e Routine (per le variabili locali). Espressioni ed operatori ************************ Per controllare l'ordine di valutazione si usano le parentesi (...). Le espressioni aritmetiche/logiche supportano questi operatori: p + q addizione p - q sottrazione p * q moltiplicazione p / q divisione intera p % q resto della divisione p++ incrementa p, restituisce il valore originale ++p incrementa p, restituisce il nuovo valore p-- decrementa p, restituisce il valore originale --p decrementa p, restituisce il nuovo valore p & q AND a livello di bit p | q OR a livello di bit ~p NOT a livello di bit (inversione) Le espressioni condizionali restituiscono true [vero] o false [falso]; q può essere un elenco di possibilità q1 or q2 or ... qN: p == q p è uguale a q p ~= q p è diverso da q p > q p è più grande di q p < q p è più piccolo di q p >= q p è più grande od uguale a q p <= q p è più piccolo od uguale a q p ofclass q l'oggetto p è della classe q p in q l'oggetto p è figlio dell'oggetto q p notin q l'oggetto p non è figlio dell'oggetto q p provides q l'oggetto p fornisce la proprietà q p has q l'oggetto p ha l'attributo q p hasnt q l'oggetto p non ha l'attributo q Le espressioni Booleane restituiscono true o false; se p è determinante per il risultato, q non viene valutata: p && q sia p che q sono true (non zero) p || q uno dei due è true (non zero) ~~p p è false (zero) Per restituire -1, 0 o 1 in base ad un confronto senza segno: UnsignedCompare(p, q) Per restituire true se l'oggetto q è figlio o nipote o... di p: IndirectlyContains(p, q) Per restituire il parente comune più vicino (o nothing) di due oggetti: CommonAncestor(p, q) Per restituire un numero casuale tra 1 e N, od uno tra una lista di valori costanti: random(N) random(valore, valore, ..., valore) Classi ed oggetti ***************** Per dichiarare un class_id - un template [modello] per una famiglia di oggetti - dove il valore opzionale (N) limita il numero di istanze create durante l'esecuzione: Class class_id(N) class class_id class_id ... class_id with prop_def, ... prop_def, has attr_def attr_def ... attr_def; Per dichiarare un obj_id, "Object" può essere la posto di class_id, gli altri quattro elementi di intestazione sono ozionali e le frecce (->, -> ->, ...) e parent_obj_id sono incompatibili: Object frecce obj_id "nome_esteso" parent_obj_id class class_id class_id ... class_id with prop_def, ... prop_def, has attr_def attr_def ... attr_def; I segmenti class, with e has (anche lo scarsamente usato private) sono opzionali e possono apparire in qualsiasi ordine. Per determinare se la classe di un oggetto fa parte di Class, Object, Routine, String (o nothing): metaclass(obj_id) Segmento has: Ogni attr_def può essere: attributo ~attributo Per modificare gli attributi durante l'esecuzione: give obj_id attr_def ... attr_def; Segmenti with/private: Ogni prop_def dichiara una variabile (o un array di word) e può prendere una di queste forme (dove un valore è un'espressione, una stringa od una routine incorporata): proprietà proprietà valore proprietà valore valore ... valore Una variabile di proprietà viene indirizzata tramite obj_id.proprietà (od all'interno della dichiarazione dell'oggetto con self.proprietà). Valori multipli creano un array di proprietà; in questo caso obj_id.#proprietà è il numero di byte occupati dall'array, si può accedere ai singoli elementi con obj_id.&proprietà-->0, obj_id.&proprietà-->1, ..., e obj_id.proprietà si riferisce al valore del primo elemento. Una variabile di proprietà ereditata da una classe oggetto si indirizza tramite obj_id.class_id::proprietà che restituisce il valore originale prima delle modifiche che vengono apportate all'interno dell'oggetto. Manipolare l'albero degli oggetti ********************************* Per modificare le relazioni tra oggetti durante l'esecuzione: move obj_id to parent_obj_id; remove obj_id; Per ottenere il genitore di un oggetto (o nothing): parent(obj_id) Per ottenere il primo figlio di un oggetto (o nothing): child(obj_id) Per ottenere il figlio adiacente di un oggetto genitore (o nothing): sibling(obj_id) Per ottenere il numero di oggetti figli diretti di un oggetto: children(obj_id) Invio di messaggi ***************** Ad una classe: class_id.remaining() class_id.create() class_id.destroy(obj_id) class_id.recreate(obj_id) class_id.copy(da_obj_id, a_obj_id) Ad un oggetto: obj_id.proprietà(a1, a2, ... a7) Ad una routine: routine_id.call(a1, a2, ... a7) Ad una stringa: stringa.print() stringa.print_to_array(array) Istruzioni poco comuni e "deprecate" ************************************ Per saltare ad un'istruzione con etichetta: jump etichetta; ... .etichetta; istruzione; Per terminare il programma: quit; Per salvare e ripristinare lo stato del programma: save etichetta; ... restore etichetta; Per visualizzare il numero di versione del compilatore Inform: inversion; Per accettare dei dati dal flusso corrente di input: read text_array parse_array routine_id; Per assegnare un valore ad una delle 32 variabili "low string": string N "stringa"; Lowstring var_stringa "stringa"; string N var_stringa; Istruzioni ********** Ogni istruzione deve terminare con un punto e virgola ";". Un blocco_istruzioni è un'istruzione singola od una serie di istruzioni racchiuse tra parentesi graffe {...}. Un punto esclamativo "!" segna l'inizio di un commento - il resto della riga viene ignorato. Un'istruzione comune è quella di assegnazione: var_id = espressione; Ci sono due modi per fare un'assegnazione multipla: var_id = var_id = ... = espressione; var_id = epressione, var_id = espressione, ... ; Routine ******* Una routine può avere fino a 15 variabili locali: valori word che sono privati all'interno della routine (non visibili all'esterno) e che vengono impostati a 0 in mancanza d'indicazione ad ogni chiamata. La ricorsione è consentita. Una routine "standalone": * ha un nome con il quale viene chiamata tramite routine_id(); può anche essere chiamata in maniera indiretta usando indirect(routine_id, a1, a2, ..., a7) * accetta argomenti, con routine_id(a1, a2, ..., a7) i cui valori inizializzano le variabili locali equivalenti * restituisce true all'ultimo "]" [ routine_id var_locale var_locale ... var_locale; istruzione; istruzione; ... istruzione; ]; Una routine incorporata come valore di una proprietà di un oggetto: * non ha nome e viene chiamata quando la proprietà viene invocata; può anche essere chiamata esplicitamente usando obj_id.proprietà() * accetta argomenti solo quando viene chiamata in maniera esplicita * restituisce false all'ultimo "]" proprietà [ var_locale var_locale ... var_locale; istruzione; istruzione; ... istruzione; ] Le routine restituiscono un valore singolo quando l'esecuzione raggiunge l'ultimo "]" o quando viene incontrata un'istruzione return: return espressione; return; rtrue; rfalse; Controllo del flusso d'esecuzione ********************************* Per eseguire le istruzioni se l'espressione è vera (true); opzionalmente per eseguire altre istruzioni se l'espressione è falsa (false): if (espressione) blocco_istruzioni if (espressione) blocco_istruzioni else blocco_istruzioni Per eseguire le istruzioni in base al valore di espressione: switch (espressione) { valore: istruzione; ... istruzione; valore: istruzione; ... istruzione; ... default: istruzione; ... istruzione; } dove ogni valore può essere fornito come: costante costante_inferiore to costante_superiore costante, costante, ..., costante E, se proprio dovete: jump etichetta; ... .etichetta; istruzione; Cicli ***** Per eseguire le istruzioni mentre l'espressione è true: while (espressione) blocco_istruzioni Per eseguire le istruzioni fino a quando l'espressione diventa true: do blocco_istruzioni until (espressione) Per eseguire le istruzioni mentre una variabile cambia: for ( imposta_var : ciclo_mentre_var : aggiorna_var) blocco_istruzioni Per eseguire le istruzioni per tutti gli oggetti definiti: objectloop (var_id) blocco_istruzioni Per eseguire le istruzioni per tutti gli oggetti selezionati da espressione: objectloop (espressione_comincia_con_var) blocco_istruzioni Per uscire dal ciclo corrente più interno o dalla switch: break; Per cominciare immediatamente la successiva iterazione del ciclo corrente: continue; Visualizzazione di informazioni ******************************* Per visualizzare una lista di valori: print valore, valore, ..., valore; Per visualizzare una lista di valori seguita da un ritorno a capo e dalla restituzione del valore true dalla routine corrente: print_ret valore, valore, ..., valore; Se il primo (o l'unico) valore è una stringa, print_ret può essere omesso: "stringa", valore, ..., valore; Ogni valore può essere un'espressione, una stringa od una regola. Un'espressione viene visualizzata come un valore decimale con segno. Una stringa tra virgolette "..." viene visualizzata come testo. Una regola è una tra: (number) espressione l'espressione in parole (char) espressione l'espressione è un carattere singolo (stringa) indirizzo la stringa che si trova all'indirizzo (address) indirizzo la voce di dizionario che si trova all'indirizzo (name) obj_id il nome esterno (sintetico) dell'oggetto obj_id (a) obj_id il nome sintetico preceduto da "a/an", "some" o da niente per i nomi corretti (the) obj_id il nome sintetico preceduto da "the" (The) obj_id il nome sintetico preceduto da "The" (routine_id)valore l'output della chiamata routine_id(valore) Per visualizzare un carattere di ritorno a capo: new_line; Per visualizzare degli spazi multipli: space espressione; Per visualizzare il testo in un box: box "stringa" "stringa" ... "stringa"; Per cambiare dal set di caratteri normale a quello a spaziatura fissa: font off; ... font on; Per cambiare gli attributi del set di caratteri: style bold; ! grassetto style underline; ! sottolineato style reverse; ! inversione del fondo style roman; ! normale Verbi ed azioni *************** Per specificare un nuovo verbo: Verb 'verbo' 'verbo' ... 'verbo' * chiave chiave ... chiave -> azione * chiave chiave ... chiave -> azione ... * chiave chiave ... chiave -> azione dove al posto di "Verb" si può usare "Verb meta", "azione" può essere "azione reverse", le chiavi sono opzionali ed ognuna può essere: 'parola' quella parola 'p1'/'p2'/... una di quelle parole attributo un oggetto con quell'attributo creature un oggetto che ha l'attributo animate held un oggetto in possesso del giocatore noun un oggetto _in scope_ (raggiungibile dal giocatore) noun=routine_id un oggetto per il quale routine_id restituisca true scope=routine_id un oggetto in questa ridefinizione di scope multiheld uno o più oggetti in possesso del giocatore multi uno o più oggetti in scope multiexcept come multi, tranne l'oggetto indicato multiinside come multi, tranni quelli contenuti nell'oggetto specificato topic qualunque testo number qualunque numero routine_id una routine generale di parsing Per aggiungere sinonimi ad un verbo esistente: Verb 'verbo' 'verbo' ... = 'verbo_esistente'; Per modificare un verbo esistente: Extend 'verbo_esistente' last * chiave chiave ... chiave -> azione * chiave chiave ... chiave -> azione ... * chiave chiave ... chiave -> azione dove al posto di "Extend" si può usare "Extend only" e "last" [ultimo] può essere omesso, o cambiato in "first" [primo] o "replace" [sostituisci]. Per eseguire esplicitamente un'azione (con nome e secondo_nome opzionali, in base a quale azione si esegue): ; Per eseguire esplicitamente un'azione e restituire true dalla routine corrente: <>; Altre direttive utili ********************* Per includere una direttiva all'interno della definizione di una routine [...], inserite un simbolo del cancelletto "#" come primo carattere. Per la compilazione condizionale: Ifdef nome; !se è definitio nome Ifndef nome; !se non è definito nome Iftrue espessione; !se l'espressione è true Iffalse espressione; !se l'espressione è false ... Ifnot; !altrimenti ... Endif; !fine controllo Per visualizzare un messaggio durante la compilazione: Message "stringa"; Per includere il contenuto di un file, cercandolo all'interno del percorso Library (solitamente il percorso della libreria): Include "codice_sorgente"; Per includere il contenuto di un file, cercandolo nella stessa directory in cui si trova il file corrente: Include ">codice_sorgente"; Per indicare che una routine della libreria deve essere sosostituita: Replace routine_id; Per impostare il numero di versione del gioco (l'impostazione predefinita è 1), il numero seriale (il predefinito è la data di oggi nel formato aammgg) ed il formato della riga di stato (il predefinito è score): Release espressione; !la versione Serial "aammgg"; !il numero seriale Statusline score; !riga di stato con il punteggio Statusline time; !riga di stato con l'ora Per dichiarare un nuovo attributo comune a tutti gli oggetti: Attribute attributo; Per dichiarare una nuova proprietà comune a tutti gli oggetti: Property proprietà; Property proprietà espressione; Direttive poco comuni e "deprecate" *********************************** È improbabile che ne abbiate bisogno; cercatele all'interno dell'Inform Designer's Manual se necessario. Abbreviate "stringa" ... "stringa"; End; Import var_id var_id ... var_id; Link "file_compilato"; Stub routine_id N; Switches elenco_degli_switch_del_compilatore System_file;