giovedì 15 novembre 2018

C e C++: Appunti di una riscoperta 3

E' ora di passare a qualche elemento teorico magari facendo qualche esperimento sul proprio Visual Studio Community. Elemento fondamentale del linguaggio C è il Token.

Il Token è quell'insieme di lettere, numeri e simboli che per il compilatore hanno un significato e non hanno bisogno di essere ulteriormente frazionati.

Nella sostanza il compilatore C riceve in ingresso un flusso di caratteri (il nostro codice sorgente scritto in C) e man mano che lo riceve cerca di ricavarne i token. Sono token per il C 

  • le parole chiave (speciali parole del linguaggio che non possono essere ridefinite dal programmatore)
  • gli identificatori (nomi di variabili, funzioni, ecc.),
  • le costanti
  • i letterali stringa
  • gli operatori
  • la punteggiatura tra cui parentesi quadre, graffe, tonde e la virgola
Quindi il compilatore tenta di riconoscere il token utilizzando il massimo numero di caratteri in ingresso, prima di procedere con il riconoscimento di un altro token. I token possono essere separati da spazi vuoti che sono ignorati dal compilatore. Fanno parte degli spazi vuoti il carattere di spazio, il tabulatore, l'accapo e i commenti (testo racchiuso tra /* e */).

Gli spazi vuoti non sono ignorati dal compilatore quando fanno parte di una striga o un carattere (il carattere spazio per esempio), o quando sono utilizzati per separare dei token.

Un esempio veloce che però insegna che è meglio non giocare con queste caratteristiche ma utilizzarle per rendere chiaro il codice:

int i = 0;
i = i
/*commentino*/+++i;

Al di là del fatto che una simile istruzione è progettata per farsi del male, nella riga il compilatore riconoscerà
  • i identificatore
  • ignorerà il commento che va da /* a */ o al più lo interpreterà come separatore fra token
  • utilizzando il massimo numero di caratteri riconoscerà l'operatore unario di post incremento++
  • quindi l'operatore +
  • infine l'identificatore i
quindi quell'istruzione è uguale a

i = i++ + i; 
/* alla fine i vale 1 per Visual Studio*/

e diversa dallo scrivere

i = i + ++i; 
/* alla fine i vale 2 per Visual Studio*/ 

Ovviamente al posto dello spazio vuoto per separare i token e rendere leggibile l'istruzione si sarebbero potuti usare altri spazi vuoti tra cui commenti, altro carattere di spazio, accapo e quant'altro. Ma dato che le insidie sono dietro l'angolo è meglio utilizzare gli spazi vuoti con criterio. In più, istruzioni complesse sarebbero meglio leggibili utilizzando le parentesi tonde per stabilire le priorità nell'espressione, senza affidarsi alle politiche del compilatore quindi alla priorità degli operatori e alla direzione di valutazione o associatività.

Abbiamo quindi scoperto anche che il commento è uno spazio vuoto, ignorato dal compilatore, che in quanto tale può essere utilizzato per dividere dei token (ma meglio di no) e sono costituiti da una qualsiasi sequenza di caratteri racchiusi tra /* e */. Non è però possibile annidare i commenti uno dentro l'altro. Ciò perché scrivendo 

/*Primo Commento
    /*commento annidato*/
*/

il secondo /* è interpretato come sequenza di caratteri all'interno del primo commento e non come avvio di un nuovo commento dentro il primo. Di conseguenza il primo commento si chiuderà al primo */ che il compilatore incontra, e tutto ciò che segue, commento  o sequenza */ a chiusura del commento, produrrà un errore non essendo dei token validi.