Il linguaggio Forth

L'attenzione nel linguaggio Forth deve essere rivolta al controllo dello stack, a quello che si inserisce e quello che si consuma da esso: lo stack è in effetti la parte più importante di un programma Forth. Questo linguaggio è nato dall'idea di un astronomo insoddisfatto delle complicazioni che altri linguaggi di programmazione opponevano allo sviluppo di sistemi per l'automazione del suo laboratorio: controllo del telescopio, analisi spettrale, elaborazioni di immagini. Niente di meglio di uno stack dove inserire i parametri per i processi, per poi consumarli al momento opportuno. Pensò quindi a un linguaggio snello e molto vicino al linguaggio naturale, scalabile, cioè dove nuove parole possano essere definite senza alcuna difficoltà.
Caratteristica del Forth è quindi la versatilità: per creare nuovi comandi basta seguire una corretta sintassi, fare attenzione a quello che succede nello stack, e il nuovo nome del comando sarà aggiunto al dizionario.
Inoltre si può dire che con il suo stile di programmazione e la manipolazione diretta di uno stack, questo linguaggio possa essere visto sia ad alto livello, per la sua somiglianza con il linguaggio naturale, sia a basso livello, per la libertà che offre di manipolare le risorse del sistema.
Addentriamoci negli aspetti peculiari del Forth.

  1. Lo stack

    Lo stack è un'area attiva nella memoria del computer nella quale il Forth mantiene la rappresentazione dei numeri e dei caratteri usati nei processi di elaborazione. Ogni valore aggiunto allo stack ne aumenta la profondità di uno. Solo l'ultimo valore aggiunto è direttamente disponibile: lo stack è una struttura di tipo LIFO.
    Il concetto di stack non è solo del Forth, ma solo questo offre un accesso ad esso diretto: basta inserire al prompt dell'interprete un valore, ed esso sarà scritto direttamente nello stack. Per estrarlo basta usare un comando che possa farlo, consumandolo come crede: ad esempio il comando . (punto) estrae un valore dallo stack e lo visualizza sullo schermo.
    Ecco quello che succede ogni volta che inseriamo un dato:

    1. L'interprete per prima cosa verifica la lista dei comandi Forth per vedere se l'inserimento corrisponde ad un comando eseguibile; in quel caso, esegue ciò che è stato comandato.
    2. Se l'inserimento non è eseguibile, l'interprete cerca di determinare se è un numero valido. In questo caso lo inserisce nello stack.
    3. Se l'inserimento non è un comando valido 0 un numero riconoscibile, l'interprete avverte di una condizione d'errore.
    Nell'esempio in figura 1, l'interprete incontra per prima cosa il numero 47. Dal momento che 47 non è un comando Forth, ma è un comando valido, l'interprete lo sistema nello stack; allo stesso modo anche il numero 54 viene messo nello stack. Di seguito l'interprete incontra il segno + che viene riconosciuto come un comando valido; ciò comporta che i due numeri vengano estratti dallo stack, addizionati e la loro somma venga inserita nello stack. Anche il comando successivo estrae un valore dallo stack, questa volta per la visualizzazione, lasciando lo stack vuoto.

  2. Il dizionario

    Tutti i comandi eseguibili sono detti parole e tutte insieme costituiscono il dizionario del Forth.
    Saper usare il Forth quindi significa utilizzare propriamente le parole del dizionario per crearne delle nuove da aggiungenge al dizionario, e per poterle anch'esse utilizzare per creare altre nuove parole e risolvere i compiti prefissati.
    Non è mio compito dare una visione totale del linguaggio, quindi non mi dilungherò spiegando tutti i comandi che possono esserci in un dizionario standard Forth: più importante invece è vedere come si creano parole nuove.
    Per prima cosa dobbiamo informare il Forth che stiamo per definire una parola nuova. Questo è compiuto tramite i due punti d'apertura : nella definizione. Anche questa è una parola del Forth, definita come parte del sistema. Dopo : dobbiamo dare un nome alla nuova parola, fornire una lista di comandi, anche vuota se il nostro comando non dovrà compiere nessuna operazione, e chiudere la definizione con la parola Forth ; .
    Inserendo la nuova parola all'interprete, esso la eseguirà esattamente come se avessimo scritto tutti quei comandi della definizione.
    L'attenzione, ripeto un concetto importante, deve essere sempre rivolta a quello che succede allo stack.

  3. Variabili e costanti

    Nella struttura del Forth c'è un set di parole che permettono di memorizzare un valore in locazioni di memoria che non compongono lo stack, queste parole permettono di creare delle vere e proprie variabili e costanti.
    Per creare un variabile bisogna affidarsi al comando VARIABLE, per una costante ovviamente il comando sarà CONSTANT.
    L'utilizzo è semplice:
    55 VARIABLE RO
    memorizza nella variabile RO il valore 55.
    Per estrarre il valore da una variabile bisogna usare il comando @ :

     RO @
      
    e il valore prima inserito, 55, verrà posto nello stack, pronto ad essere usato. Questo anche per le costanti.
    Naturalmente esiste anche il comando per cambiare il valore di una variabile:
     15 RO !
      
    In questo modo il nuovo valore viene inserito nella locazione di memoria riservata alla variabile.
    Ci sono delle variabili particolari, già definite, che servono a scopi di gestione:

  4. Decisioni e loop

    Benchè non voglia dare una completa visione del Forth, nei programmi CAM 8 spesso bisogna ricorrere a a decisioni e a cicli di ricorsione, quindi è necessario darne una panoramica.
    La struttura IF ELSE THEN è presente all'interno del Forth ed essa, tramite il comando IF, verifica se l'operazione di confronto eseguita prima ha avuto esito positivo, nel qual caso esegue le operazioni fino al comando THEN o fino al comando ELSE se presente.
    Nel caso di esito negativo, IF salta i comandi fino a ELSE ed esegue quelli fino a THEN. Nel caso non fosse presente l'alternativa ELSE nessun comando viene eseguito e continua l'elaborazione saltando oltre THEN.
    Gli operatori di confronto rilasciano un flag, controllato poi da IF.
    Ad esempio:

     RO @ 100 > IF
     ."Resistenza specifica elevata"  \ se RO>100, RO e' elevata
     ELSE
     ."Tutto bene"                    \ altrimenti va bene
     THEN
     
      
    Sappiamo già che RO @ serve per inserire nello stack il valore in RO, 100 inserisce 100 nello stack, e l'operatore > confronta i primi due valori in cima allo stack e rilascia il flag sul risultato nello stack. Il comando ." seguito da " visualizza quello che c'è all'interno.
    Per i loop è un pò più complicato. Essi si avvalgono di un altro stack, finora taciuto, creato dal Forth, chiamato return stack. In questo return stack viene tenuta traccia di Il comando più utile in questo contesto è I : esso copia il valore in cima al return stack nello stack dei parametri, quello visto finora, senza nessun effetto per il return stack.
    Per indicare la ricorsione, i comandi veri e propri sono: Il primo, DO LOOP, è un loop definito, prima si imposta quante volte deve essere eseguito, poi si manda in esecuzione. Tramite il comando I già visto si conosce a che punto è arrivata la ricorsione.
    
      100 0          \ imposto limite 100 e indice 0
      DO             \ compio il quadrato dei numeri da 0 a 100
      I DUP *        \ estrae il valore dal return stack
      . CR           \ li visualizzo
      LOOP
    
      
    Le altre due strutture sono loop indefiniti, cioè ripetono finchè un flag ha un valore appropriato: vero per BEGIN UNTIL, falso per BEGIN WHILE REPEAT.
    La sintassi di BEGIN UNTIL è la seguente:
     BEGIN comando1 comando2 ... flag
     UNTIL
      
    dove flag può essere un comando che restituisce 0 o 1, come ?TERMINAL, che fornisce un flag vero se dopo l'ultima sua esecuzione (ricordiamoci che in Forth i comandi sono interpretati al momento dell'arrivo) è stato premuto un tasto.
    La sintassi invece di BEGIN WHILE REPEAT è:
     BEGIN comando1 comando2 ... flag
     WHILE comando3 comando4 ...
     REPEAT
      
    In primo luogo vengono eseguite le parole tra BEGIN e WHILE. Quest'ultimo controlla il flag rilasciato nello stack e se questo è vero esegue le parole tra WHILE e REPEAT, altrimenti, se trova il flag falso, esce dal loop.
    Il primo dei loop indefiniti rimane in esecuzione finchè qualcosa diventa vero, mandando in esecuzione il corpo almeno una volta, il secondo rimane in esecuzione finchè una condizione rimane vera, eseguendo le operazioni tra BEGIN e WHILE almeno una volta e le operazioni tra WHILE e REPEAT nessuna o infinite volte.


Ritorno al precedente