un linguaggio logo-like per programmare piccoli robotbarbara/microbot/tesinqcbaby/tesi_rosanna...
TRANSCRIPT
UNIVERSITÀ DEGLI STUDI DI TORINO
FACOLTÀ DI SCIENTE MATEMATICHE, FISICHE E NATURALI
Corso di laurea in Informatica
UUUNNN LLLIIINNNGGGUUUAAAGGGGGIIIOOO LLLOOOGGGOOO---LLLIIIKKKEEE PPPEEERRR
PPPRRROOOGGGRRRAAAMMMMMMAARRREEE PPPIIICCCCCCOOOLLLIII RRROOOBBBOOOTTT
G
A
Tesi di Laurea
RELATORE: Prof. G. Barbara Demo
CORELATORE: Prof. Giovanni Marcianò
CANDIDATO: Rinaldi Rosa Anna
ANNO ACCADEMICO
2006 – 2007
Indice
Indice ................................................................................................................................. i
Elenco delle figure........................................................................................................... iii
Introduzione...................................................................................................................... v
Ringraziamenti ............................................................................................................... vii
Capitolo 1 ......................................................................................................................... 1
Piccoli robot programmabili ......................................................................................... 1
1.1 L’ RCX ........................................................................................................ 2
1.2 Linguaggi di programmazione per i robot................................................... 5
1.2.1 Robolab: un linguaggio iconico........................................................ 5
1.2.2 NQC.................................................................................................. 6
1.3 Ambienti di programmazione.................................................................... 15
1.3.1 IDE ................................................................................................. 15
1.3.2 Bricx Command Center .................................................................. 16
1.4 Conclusioni................................................................................................ 20
Capitolo 2 ....................................................................................................................... 21
Il linguaggio NQCBaby.............................................................................................. 21
2.1 Il linguaggio LOGO .................................................................................. 21
2.2 Il linguaggio NQCBaby............................................................................. 26
2.3 Diagrammi sintattici di NQCBaby ............................................................ 36
2.4 Utilizzo di NQCBaby con in BricxCC ...................................................... 42
Capitolo 3 ....................................................................................................................... 45
i
NQCBaby Editor ........................................................................................................ 45
3.1 L’interfaccia grafica .................................................................................. 45
3.1.1 Guida all’uso .................................................................................. 46
3.1.2 Dettagli Implementativi.................................................................. 54
3.2 Il pre-compilatore NQCBaby .................................................................... 60
............................................................................. 623.2.1 Analisi lessicale
3.2.2 Analisi sintattica ............................................................................ 63
........................................................................... 713.2.3 Analisi semantica
3.2.4 Progettazione di un Predictive Parser............................................. 73
Capitolo 4 ....................................................................................................................... 82
Conclusioni e sviluppi futuri ...................................................................................... 82
Appendice A................................................................................................................... 84
Glossario..................................................................................................................... 84
Bibliografia..................................................................................................................... 89
ii
Elenco delle figure
Figura 1.1: Mattone programmabile RCX....................................................................... 2
Figura 1.2: processore Hitachi H8/3292.......................................................................... 4
Figura 1.3: Esempio di programma con Robolab............................................................ 6
Tabella 1.1: Elenco dei comandi in NQC...................................................................... 10
Tabella 1.2: Elenco delle possibili condizioni............................................................... 10
Tabella 1.3: Elenco delle espressioni. ........................................................................... 11
Tabella 1.4: Elenco dei possibili operatori. ................................................................... 12
Tabella 1.5: Elenco di tutte le funzioni utilizzate in NQC ............................................ 13
Tabella 1.6: Elenco di tutte le costanti. ......................................................................... 14
Figura 1.4: Finestra di dialogo per scaricare il firmware. ............................................. 16
Figura 1.5: Parte del menù a tendina “Tools”. .............................................................. 17
Figura 1.6: Il pannello templates. .................................................................................. 17
Figura 1.7: Vari elementi che permettono di programmare con il BricxCC. ................ 18
Figura 1.8: Menù a tendina Compile............................................................................. 18
Figura 1.9: Rispettivamente BricxCC con errori e senza errori. ................................... 19
Figura 2.1: I “Fogli bianchi”. ........................................................................................ 27
Tabella 2.1: Le primitive del linguaggio NQCBaby. .................................................... 28
Figura 2.2: Nascita e vita di un programma NQCBaby. ............................................... 30
Tabella 2.2: Primitive di NQCBaby_1 .......................................................................... 30
Tabella 2.3: Primitive di NQCBaby_2 ......................................................................... 32
Tabella 2.4: Primitive di NQCBaby_3 ......................................................................... 33
iii
Tabella 2.5: Primitive di NQCBaby_4 ......................................................................... 34
Tabella 2.6: Primitive di NQCBaby_5 ......................................................................... 35
Figura 2.3: Niklaus Wirth.............................................................................................. 37
Figura 2.4: Segnalazione errori sintattici del BricxCC. ................................................ 43
Figura 2.5: Segnalazione errori semantici del BricxCC................................................ 43
Figura 3.1: La finestra di dialogo che richiede il percorso fino alla cartella BricxCC.. 46
Figura 3.2: La finestra di dialogo che permette di assegnare il nome al robot RCX. ... 46
Figura 3.3: La finestra di con il nome di default del robot RCX. ................................. 47
Figura 3.4: La finestra principale del programma NQCBaby Editor. ........................... 47
Figura 3.5: Le scelte disponibili nel menu File. ............................................................ 48
Figura 3.6: La finestra di dialogo che permette l’apertura di documenti già salvati..... 49
Figura 3.7: La finestra di dialogo che permette il salvataggio di nuovi documenti. ..... 49
Figura 3.8: La finestra di dialogo che richiede il salvataggio delle modifiche. ............ 50
Figura 3.9: Le scelte disponibili nel menu Progetto...................................................... 50
Figura 3.10: La barra dei pulsanti. ................................................................................ 51
Figura 3.11: Il pannello contenente le due aree di testo. ............................................... 52
Figura 3.12: La segnalazione di un errore sintattico. .................................................... 52
Figura 3.13: Rispettivamener pannello delle versioni e dei comandi di “Baby 4”. ...... 53
Figura 3.14: Estratto javadoc della classe Interfaccia.java............................................ 55
Figura 3.15: Lo schema dell’interfaccia........................................................................ 56
Figura 3.16: Rappresentazione grafica dei menu. ......................................................... 56
Tabella 3.1: Funzioni di NQCBaby e relative classi per i gestori di eventi .................. 57
Figura 3.17: Lo schema dell’interfaccia della classe Help............................................ 60
Figura 3.18: Pre-compilazione da in NQCBaby a NQC e compilazione in linguaggio
macchina.................................................................................................... 61
Figura 3.19: Rispettivamente fase front end e back end ............................................... 73
iv
Introduzione
OBIETTIVO DI QUESTA TESI
L’utilizzo della robotica come strumento educativo, nella scuola dell’obbligo, sta
assumendo un ruolo sempre più importante.
Nasce, quindi, l’esigenza di fornire ai bambini uno strumento che permetta loro di
programmare piccoli robot, senza la necessità di conoscerne il linguaggio “nativo”
(NQC Not Quite C) ma usando un linguaggio ad hoc con comandi in italiano:
NQCBaby.
Per questa tesi l’hardware di riferimento, scelto tra i mattoncini programmabili messi
in commercio dalla LEGO, è l’RCX (Robot Commander eXplorer) in quanto il suo
linguaggio di programmazione è definitivo e standardizzato.
Per quanto riguarda l’implementazione sviluppo dell’ambiente di sviluppo e del
traduttore integrati in NQCBaby Editor è stato utilizzato il linguaggio di
programmazione Java, versione 1.6 mentre, per quanto riguarda la documentazione di
supporto, è stato utilizzato Javadoc.
STATO DELL’ARTE
Il professore Giovanni Marcianò, docente di lettere oggi responsabile del progetto di
ricerca “Uso didattico della robotica” presso l'IRRE Piemonte, ha sviluppato una
versione del linguaggio NQC mediante l’uso di macro, che permettono un’opera di
semplificazione delle sintassi native, come pura trasposizione linguistica dal
vocabolario tecnico inglese ad un vocabolario naturale italiano. Tali macro sono state
inserite in cinque “fogli bianchi” che permettono una programmazione “LOGO-like”
dei robot compatibili con NQC. Una volta aperti questi “fogli bianchi”, tramite il BCC
(Bricx Command Center), gli alunni inseriranno i loro programmi.
Questa soluzione porta con se il vantaggio della semplicità implementativa derivante
dalla struttura flessibile del linguaggio NQC, ma al tempo stesso comporta lo
svantaggio di una possibile modifica delle macro da parte di alunni più curiosi e la non
sincronizzazione degli eventuali messaggi d’errore con il codice scritto dai bambini.
CONTRIBUTI E ORGANIZZAZIONE DELLA RELAZIONE
Il nostro lavoro ha riguardato le seguenti attività principali:
Specifica di una grammatica per il linguaggio NQCBaby.
Analisi dell’ambiente di sviluppo programmi BricxCC che viene usato da chi
utilizza il linguaggio originale NQC. Infatti, pensando all’utente finale ovvero i
bambini delle elementari, abbiamo cercato di essere coerenti con lo stile del
BricxCC durante lo sviluppo del nostro software.
Progetto e sviluppo di un semplice IDE (Integrated Development Environment)
per lo sviluppo di programmi NQCBaby, dove sono disponibili dei templates
contenenti le primitive di tale linguaggio che facilitano la scrittura di
programmi NQCBaby e di un’area in cui viene visualizzato il corrispondente
codice NQC.
Ricerca e prova di strumenti tipo Yacc&Lex, come alternative per la
generazione del traduttore.
Molte di queste attività hanno naturalmente richiesto l’interazione con le insegnanti che
stanno conducendo esperienze di uso dei robot nelle scuole.
Questo confronto ci è stato particolarmente utile per la verifica del primo prototipo
realizzato, che è stato usato durante fine maggio e inizio giugno nelle classi di alcune
scuole e per la definizione delle modifiche da realizzare per la produzione della
versione beta che sarà usata dall’inizio del prossimo anno scolastico.
Ringraziamenti Vorrei ringraziare prima di tutto la mia famiglia, alla quale dedico la mia laurea, per essermi stata vicino in questi anni di studio. Inoltre ringrazio la professoressa Giuseppina Barbara Demo per la sua disponibilità e presenza in tutto il corso del tirocinio e durante la stesura della tesi e per l’entusiasmo che ha dimostrato nel nostro lavoro. Un grazie particorale va alla mia collega di studi e grande Amica Veronica Scruci, che mi ha sempre sopportata e ha sempre sorriso alle mie mille manie. Abbiamo iniziato questo lungo percorso inseme e non avremmo potuto non concluderlo così. Non posso certo dimenticare le mie più care amiche, che mi hanno sempre spronata e grazie alle quali sono cresciuta. Non sono mai stata una persona di tante parole ma quelle poche che ho detto non avrei potute dirle ad altri. Infine, ma non meno importante, un grande ringraziamento a Sandro, che nei momenti di difficoltà è stato sempre presente e pronto a concedere il suo tanto prezioso aiuto, e a tutti coloro che in tutti questi mesi ci hanno aiutate e sostenute, facendoci sorridere nei momenti più duri. L'esperienza universitaria ci ha lasciato tanti ricordi, alcuni tristi ma tanti belli, e tra le persone che abbiamo conosciuto alcune ci sono rimaste nel cuore. Concludiamo questa fase della nostra vita con la speranza che questi nuovi amici continuino a far parte delle prossime fasi.
Capitolo 1
Piccoli robot programmabili
Il crescente interesse verso tutto ciò che è tecnologico, ha fatto sì che nell’ultimo
decennio siano stati realizzati vari progetti al fine di introdurre l’insegnamento
dell’informatica usando piccoli robot. In questo contesto LEGO, in collaborazione con
il Massachusetts Institute of Technology (MIT), dopo aver presentato al pubblico il suo
kit Mindstorms chiamato "RIS" (Robotic Invention System - "Sistema di Invenzione
Robotico") ha distribuito una versione educativa chiamata LEGO Mindstorms for
Schools, venduta con un software di programmazione basato sulla GUI ROBOLAB.
Ogni confezione del kit Robotic Invention System, al di là del soggetto proposto,
consiste in una miriade di pezzi LEGO standard e LEGO Technics di cui l’elemento
sostanziale è RCX Brick. Tale kit rappresenta il punto di partenza per chiunque voglia
creare dei robot indipendenti.
1
1. Piccoli robot programmabili
1.1 L’ RCX
Nella confezione del RIS si trovano: l’RCX Brick, il mattoncino programmabile
contenente il chip con il microprocessore, due motori con relativi cavetti di
collegamento e tre sensori, due di contatto Touch Sensor e un Light Sensor, sensore di
luce.
Nel RIS c’è anche tutto quello che serve per programmare e gestire il mattoncino RCX
utilizzando un Personal Computer: la IR Tower, cioè un dispositivo che, collegato ad
una porta seriale a 9 pin standard o ad una porta USB RCX dispone anche di uno
spinotto per un alimentatore esterno che permette di far lavorare il mattoncino
continuamente, eliminando i limiti imposti dalle batterie.
L’RCX Brick è un componente della Lego Mindstorms System, il cui scopo è quello di
pilotare piccoli robot mobili.
Realizzato in perfetto stile Lego, consente di attaccare un qualunque altro mattoncino
sia sulla facciata superiore, che su quella inferiore: si veda la figura 1.1.
Figura 1.1: Mattone programmabile RCX.
2
1. Piccoli robot programmabili
Sulla facciata superiore vengono messi a disposizione alcuni componenti utili alla
costruzione e all’interazione con il mattoncino.
Innanzitutto vi sono quattro pulsanti, ognuno dei quali svolge una funzione specifica:
Il pulsante “On-Off”, contraddistinto dal colore rosso, ha il compito di
accendere e spegnere l’RCX Brick.
Il pulsante “View”, di colore nero, mostra lo stato dei sensori e dei motori.
Il pulsante “Prgm” permette la selezione del programma da eseguire tra quelli
caricati in memoria, esiste un massimo di programmi memorizzabile che è di
cinque. “View” e “Prgm” sono dipendenti dal firmware installato, quindi le
loro funzioni sono programmabili ma se utilizzati con il firmware standard
svolgono la funzione sopra descritta.
Il pulsante verde “Run” manda in esecuzioni il programma selezionato.
Ancora sulla facciata superiore, sono presenti tre porte di input, numerate da 1 a 3 in
modo da distinguerle da quelle di output e utilizzate per il collegamento di vari tipi di
sensori presenti nel kit (luminosità, rotazione, contatto e temperatura), e tre porte di
output, etichettate A, B e C, che consentono pilotaggio di attuatori (più comunemente
motori).
A completare sono disponibili sul mattonciono un display, che consente la
visualizzazione di numeri utile anche per il debug, uno speaker e una porta a raggi
infrarossi. Quest’ultima è l’unico modo per trasferire programmi dall’IR Tower
collegata con l’esterno e l’RCX Brick. Tipicamente l’IR Tower viene collegata ad una
porta USB del PC e attraverso essa un’applicazione software residente su PC (nel nostro
caso Bricx Command Center come vedremo in seguito) può scaricare programmi
eseguibili sull’RCX.
Come noto l’RCX necessita di un firmware per l’esecuzione dei programmi che gli
vengono caricati. Questo firmware interpreta i bytecode nel rispettivo codice macchina,
chiamando le routine cablate nella ROM. Il Lego RIS e NQC usano entrambi lo stesso
firmware, ovvero il “LEGO firmware”, che viene fornito con un CD-ROM presente
nella scatola del kit Mindstorms.
3
1. Piccoli robot programmabili
La prima volta che si vuole usare il robot o quando vengono cambiate le batterie
bisogna trasferire il firmware, dopo di ciò e dopo aver inviato i programmi il robot sarà
autonomo e indipendente dal computer.
L'RCX di Lego Mindstorms si basa sul processore Hitachi H8/3292 della famiglia
H8/3297. Il chip integra in se una CPU della serie H8/300, memoria e dispositivi di I/O,
e un controllore di interruzioni.
Figura 1.2: processore Hitachi H8/3292.
La CPU H8/300 è un microprocessore di tipo RISC con registri accessibili a 16 bit o a 8
bit. I modi di indirizzamento previsti sono indirizzamento indiretto di registro,
indirizzamento assoluto, indirizzamento immediato, indirizzamento relativo al Program
Counter e indirizzamento indiretto di memoria.
Lo spazio di indirizzamento è a 16 bit (dunque un totale di 64 Kbytes) per dati e
programma. Il set di istruzioni è composto di 55 istruzioni, divise in varie categorie:
trasferimento dati singoli e a blocchi, operazioni di tipo logico e aritmetiche, operazioni
di shift, manipolazione di bit, salti, controllo di sistema.
Il microcontrollore contiene 16KB di ROM, e 512 bytes di RAM on-board. Nella ROM
sono memorizzate in modo permanente una collezione di routine di basso livello per
l’accesso ai motori, sensori e display LCD che in sistemi embedded viene definita
firmware.
4
1. Piccoli robot programmabili
La RAM invece viene usata, come in ogni calcolatore, per contenere le istruzioni che
devono essere eseguite dalla CPU. L’RCX è equipaggiato con 32KB di RAM
aggiuntiva. Questa serve per memorizzare il firmware e i programmi utente. Il firmware
che risiede in RAM è in realtà un’estensione di quello residente nella ROM. Questo
firmware che possiamo definire di alto livello può essere sostituito con altri per fornire
diverse funzionalità all’RCX.
1.2 Linguaggi di programmazione per i robot
1.2.1 Robolab: un linguaggio iconico
Frutto della collaborazione tra Tufts University, Lego Education e National Instruments,
è un ambiente grafico per la programmazione della robotica Lego.
Robolab è la versione di MINDSTORMS prevista per un uso di RCX in un contesto
tipicamente scolastico, dove fondamentale è la figura del docente, ma anche la prassi di
un lavoro articolato in piccoli gruppi e finalizzato a comuni obiettivi didattici.
In figura è rappresentato un esempio di un possibile programma e si può osservare che
le icone dello schema rappresentano azioni e controlli del programma; il semaforo verde
rappresenta il punto d’ingresso del diagramma, e quello rosso il suo elemento terminale.
Le icone con le frecce sono rispettivamente un “go to” e la relativa etichetta d’arrivo;
altre icone rappresentano i motori, il sensore di luce ecc. Robolab non gestisce gli
ingressi in termini di eventi: la struttura del programma è quindi basata su un ciclo
infinito di lettura dello stato del sensore e controllo conseguente dei motori.
Robolab offre, inoltre, diversi sottoambienti: “pilot”, destinato alle fasi introduttive;
“inventor”, per successivi approfondimenti; “investigator”, per raccogliere, elaborare e
visualizzare dati letti dai sensori. Ognuno di questi ambienti è strutturato su vari livelli
di difficoltà, in cui le funzionalità vengono rese progressivamente disponibili al crescere
della competenza dell’utente. Robolab permette, inoltre, la gestione remota (via
Internet) del robot.
5
1. Piccoli robot programmabili
Figura 1.3: Esempio di programma con Robolab.
1.2.2 NQC
NQC (Not Quite C) è un semplice linguaggio di programmazione, open-source, con una
sintassi ispirata al C, che permette la programmazione dell’RCX.
NQC fu creato da Dave Baum, che opera presso il Dipartimento di Computer Science
all’Utrecht University nei Paesi Bassi, ed è noto nel mondo dell’open-source per molti
altri progetti.
Questo linguaggio utilizza il firmware standard Lego dell'RCX, che permette di
sfruttarne appieno le possibilità. Facile da installare, molto stabile, ben documentato e
multipiattaforma (Win, Mac, Linux), è il più usato ambiente di sviluppo per chi si
avvicina alla programmazione vera e propria dell’RCX.
I programmi in NQC consistono di task (compiti), al massimo 10, ognuno dei quali è
costituito da un elenco di istruzioni, chiamate anche statement che terminano con un
punto e virgola. Ogni task deve avere un nome e uno solo può essere chiamato main che
viene eseguito automaticamente e che sarà quello eseguito dal robot. Gli altri, invece,
vengono eseguiti solo tramite la chiamata con il comando start. Per delimitare l’inizio e
la fine dei task vengono usate le parentesi graffe. Un task in esecuzione può fermare
altri task utilizzando il comando stop. Un task bloccato con tale comando può essere
fatto ripartire da capo, ma non dal punto in cui è stato bloccato.
NQC possiede un’ulteriore molteplicità di caratteristiche:
6
1. Piccoli robot programmabili
Gli output vengono rappresentati tramite constanti:
OUT_A
OUT_B
OUT_C
Permette l’utilizzo di variabili: viste come locazioni di memoria nelle quali
vengono memorizzati valori. Questi valori possono essere utilizzati più volte
all’interno del programma ed essere modificati. L’unico tipo utilizzato da NQC
è int che corrisponde ai numeri interi.
Permette anche l’utilizzo di costanti definite con il comando #define. A
differenza delle variabili, una volta dichiarate, le costanti non possono essere
modificati.
Utilizza diverse strutture di controllo, tra le quali:
if else, while, do while, repeat.
Consente la creazione di macro usando il comando #define e assegnando loro
un nome. Queste macro possono contenere frammenti di codice che hanno lo
stesso scopo delle subroutine e inline function.
Permette la creazione di subroutine con il comando sub. Queste vengono
utilizzate per creare pezzi di codice da richiamare in vari punti del task per
evitare la ripetizione di codice. È possibile dare un nome alla subroutine. Non
possono richiamare altre subroutine e possono essere chiamate da task diversi.
Questo però è sconsigliato in quanto potrebbero essere usate
contemporaneamente in task diversi producendo risultati indesiderati. Il
vantaggio delle subroutine è quello di essere memorizzate una volta sola
nell’RCX.
Permette la creazione di inline function con il comando void. Queste hanno lo
stesso utilizzo delle subroutine ma possono avere argomenti (come in C). Lo
svantaggio, al contrario delle subroutine è quello di non essere memorizzate
separatamente ma copiate in ogni punto in cui vengono usate occupando così
più memoria.
Mette a disposizione i semafori, che vengono utilizzati per l’esecuzione di task
paralleli. Sono variabili che indicano quale task ha il controllo dei motori
permette l’accesso ai motori in maniera sincrona.
7
1. Piccoli robot programmabili
I motori, all’inizio di ogni programma, sono impostati in avanti e con una
potenza di 7. Per ogni istruzione riguardante i motori, è possibile inserire come
argomento una costante corrispondente ad un determinato motore, direzione o
modalità.
I robot Lego sono dotati di sensori che reagiscono a determinati stimoli.
Vengono utilizzate delle costanti per indicare il numero di porta alla quale il
sensore è connesso: SENSOR_1, SENSOR_2, SENSOR_3. Inoltre, esistono
altre costanti, quali SENSOR_TOUCH per indicare il sensore al tocco,
SENSOR_LIGHT per il sensore alla luce tra quelli di maggior utilizzo.
SENSOR_TYPE_TEMPERATURE per il sensore termico,
SENSOR_TYPE_ROTATION per il sensore di rotazione. L’RCX possiede tre
porte di input e quindi è possibile connettervi solo tre sensori, ma è possibile
connettere più sensori ad una stessa porta.
L’RCX dispone di quattro timer che producono battiti da 1/10 di secondo e
sono numerati da 0 a 3 e che vengono richiamati con la funzione Timer().
Il display dell’RCX viene controllato in due modi diversi: è possibile indicare
cosa visualizzare (l’orologio di sistema, uno dei sensori o uno dei motori)
oppure è possibile controllare il display tramite l’orologio di sistema per
mostrare, ad esempio, informazioni per la diagnostica.
L’RCX è dotato di uno speaker interno che emette suoni con il comando
PlaySound() o motivi musicali con il comando PlayTone().
Mette a disposizione la funzione di datalogging, infatti l’RCX può
memorizzare il valore di variabili, sensori e timer in uno spazio di memoria
chiamato datalog. Tali valori non possono essere utilizzati dall’RCX ma letti
dal computer permettendo di controllare, per esempio, quello che è successo al
robot.
Possedendo almeno due RCX, NQC consente di mandare messaggi da un robot
ad un altro usando la porta infrarossi.
Programmando con NQC, è possibile inserire commenti all’interno del codice
tramite // se scritti solo su una riga, altrimenti /* */ per commenti di più righe.
8
1. Piccoli robot programmabili
Rispetto a C, NQC possiede alcune differenze: non consente l’utilizzo degli array,
utilizza il solo tipo int e ha speciali librerie per essere usato con il mattoncino della
Lego.
Concludendo, si possono elencare alcuni tra i vantaggi e gli svantaggi di NQC:
Vantaggi
NQC è il più utilizzato ambiente di sviluppo alternativo.
È semplice da istallare.
La documentazione è ottima.
Svantaggi
Si basa sul firmware LEGO.
Limiti imposti dalla V.M. LASM (es. non supporta numeri in virgola
mobile).
Difficile interfacciamento con codice che coinvolga altri dispositivi.
Interfacciamento RCX-PC o RCX-Vision Command.
Si elencano qui di seguito tutti i comandi, le possibili condizioni, espressioni, costanti e
funzioni che possono essere utilizzate in NQC.
COMANDI
Comando Descrizione while (cond) corpo esegui il corpo zero o più volte fintanto che la
condizione è vera do corpo while (cond) esegui il corpo una o più volte fintanto che la condizione
è vera di NQC until (cond) corpo esegui il corpo zero o più volte fintanto che la
condizione è falsa break esci dal corpo di un while/do/until continue salta alla prossima iterazione di un while/do/until repeat (espressione) corpo ripeti il corpo un determinato numero di volte if (cond) stmt1 if (cond) stmt1 else stmt2
esegui stmt1 se la condizione è vera. Esegui stmt2 (se presente) se la condizione è falsa.
start nome_task esegui il task specificato stop nome_task arresta il task specificato function(argomenti) chiama una funzione con gli argomenti specificati var = espressione valuta un’espressione e la memorizza in una variabile var += espressione valuta un’espressione e la aggiunge ad una variabile
9
1. Piccoli robot programmabili
var -= espressione valuta un’espressione e la sottrae da una variabile var *= espressione valuta un’espressione e la moltiplica con una variabile var /= espressione valuta un’espressione e ci divide una variabile var |= espressione valuta un’espressione ed esegue un OR bit a bit con una
variabile var &= espressione espressione ed esegue un AND bit a bit con valuta un’
una variabile return funzione a dove è stata chiamata ritorna da una espressione valuta un’espressione
Tab i in NQC.
CONDIZIONI
Le condizioni sono utilizzate dalle strutture di controllo per prendere decisioni. Nella
ella 1.1: Elenco dei comand
maggior parte dei casi la condizione implica un confronto tra espressioni.
Condizione Significato true sempre vero false sempre falso espr1 == espr2 essioni sono uguali vero se le esprespr1 != espr2 vero se le espressioni sono diverse espr1 < espr2 vero se la prima espressione è minore dell’altra espr1 <= espr2 ll’altra vero se la prima espressione è minore o uguale aespr1 > espr2 vero se la prima espressione è maggiore dell’altra espr1 >= espr2 ll’altra vero se la prima espressione è maggiore o uguale a! condizione negazione logica di una condizione cond1 && cond2 ro se e soltanto se entrambeAND logico tra due condizioni (ve
sono vere) cond1 || cond2 tra due condizioni (vero se e soltanto se almeno unaOR logico
delle due è vera) Tabella 1.2: Elenco delle possibili condizioni.
10
1. Piccoli robot programmabili
ESPRESSIONI
Ci sono diversi valori che possono essere usati tra le espressioni, tra cui costanti,
variabili e valori dei sensori. Nota che SENSOR_1, SENSOR_2 e SENSOR_3 sono
macro che si espandono rispettivamente a SensorValue(0), SensorValue(1) e
SensorValue(2).
Valore Descrizione numero un valore costante (ad esempio "123") variabile una variabile con un nome (ad esempio "x") Timer(n) valore del timer n, dove n è compreso tra 0 e 3 Random(n) un numero casuale compreso tra 0 e n SensorValue(n) valore corrente dl sensore n, dove n è compreso tra 0 e 2 Watch() valore dell’orologio di sistema Message() valore dell’ultimo messaggio IR ricevuto
Tabella 1.3: Elenco delle espressioni.
I valori possono essere combinati usando degli operatori. Alcuni operatori possono
essere usati solo per valutare espressioni costanti, il che significa che gli operandi
devono essere valori costanti. Gli operatori sono qui elencati in ordine di precedenza
(dalla più alta alla più bassa).
Operatore Descrizione Associazione Restrizioni Esempio abs() sign()
valore assoluto segno
n/a n/a
abs(x) sign(x)
++ --
incremento decremento
Sinistra sinistra
solo variabili solo variabili
x++ o ++xx-- o --x
- ~
meno unario negazione bit a bit (unario)
Destra destra
solo costanti -x ~123
* / %
moltiplicazione divisione modulo
Sinistra sinistra sinistra
solo costanti
x * y x / y 123 % 4
+ -
addizione sottrazione
Sinistra sinistra
x + y x - y
<< >>
spostamento a sinistra spostamento a destra
Sinistra sinistra
solo costanti solo costanti
123 << 4 123 >> 4
& AND bit a bit Sinistra x & y ^ XOR bit a bit Sinistra solo costanti 123 ^ 4 | OR bit a bit Sinistra x | y
11
1. Piccoli robot programmabili
&& AND logico Sinistra solo costanti 123 && 4 || OR logico Sinistra solo costanti 123 || 4
Tabella 1.4: Elenco dei possibili operatori.
FUNZIONI DELL’RCX
La maggior parte delle funzioni richiede come argomenti dei valori costanti. Le
eccezioni sono quelle funzioni che richiedono sensori come argomento, e quelle che
possono usare qualsiasi espressione. Nel caso dei sensori, l’argomento deve essere un
nome di sensore: SENSOR_1, SENSOR_2 o SENSOR_3. In alcuni casi esistono nomi
predefiniti (ad esempio SENSOR_TOUCH) per le costanti appropriate.
Funzione Descrizione Esempio SetSensor(sensore, config) configura un sensore SetSensor(SENSOR_1,
SENSOR_TOUCH) SetSensorMode(sensore, modo)
imposta la modalità del sensore
SetSensor(SENSOR_2, SENSOR_MODE_PERCENT)
SetSensorType(sensore, tipo) imposta il tipo del sensore
SetSensor(SENSOR_2, SENSOR_TYPE_LIGHT)
ClearSensor(sensore) azzera un sensore ClearSensor(SENSOR_3) On(output) accende uno o più
output On(OUT_A + OUT_B)
Off(output) spegne uno o più output Off(OUT_C) Float(output) spegne uno o più output
senza usare il freno Float(OUT_B)
Fwd(output) imposta la direzione dell’output in avanti
Fwd(OUT_A)
Rev(output) imposta la direzione dell’output indietro
Rev(OUT_B)
Toggle(output) inverte la direzione dell’output
Toggle(OUT_C)
OnFwd(output) accende ed imposta la direzione in avanti
OnFwd(OUT_A)
OnRev(output) accende ed imposta la direzione indietro
OnRev(OUT_B)
OnFor(output, tempo) accende per uno specificato numero di centesimi di secondo. Il tempo può essere un’espressione
OnFor(OUT_A, 200)
SetOutput(output, modo) imposta la modalità SetOutput(OUT_A, OUT_ON)
12
1. Piccoli robot programmabili
dell’output SetDirection(output, dir) imposta la direzione
dell’output SetDirection(OUT_A, OUT_FWD)
SetPower(output, potenza) imposta la potenza dell’output (0-7). La potenza può essere un’espressione
SetPower(OUT_A, 6)
Wait(tempo) Attende per uno specificato numero di centesimi di secondo. Il tempo può essere un’espressione
Wait(x)
PlaySound(suono) esegue il suono specificato (0-5)
PlaySound(SOUND_CLICK)
PlayTone(freq, durata) esegue un tono della frequenza indicata per la durata specificata (in centesimi di secondo)
PlayTone(440, 5)
ClearTimer(timer) azzera un timer (0-3) ClearTimer(0) StopAllTasks() arresta tutti i task in
esecuzione StopAllTasks()
SelectDisplay(modo) imposta una delle 7 modalità del display: 0: orologio, 1-3: valore dei sensori, 4-6: impostazione degli output. La modalità può essere un’espressione
SelectDisplay(1)
SendMessage(messaggio) invia un messaggio IR (1-255). Il messaggio può essere un’espressione
SendMessage(x)
ClearMessage() azzera il buffer dei messaggi
ClearMessage()
CreateDatalog(dimensione) crea un nuovo datalog della dimensione specificata
CreateDatalog(100)
AddToDatalog(valore) aggiunge un valore al datalog. Il valore può essere un’espressione
AddToDatalog(Timer(0))
SetWatch(ore, minuti) imposta l’orologio di sistema
SetWatch(1,30)
SetTxPower(hi_lo) imposta la potenza della porta ad infrarossi
SetTxPower(TX_POWER_LO)
Tabella 1.5: Elenco di tutte le funzioni utilizzate in NQC
13
1. Piccoli robot programmabili
COSTANTI DELL’RCX
Molti valori per le funzioni dell’RCX hanno un nome sotto forma di costante che può
rendere il codice più leggibile. Dove possibile, è preferibile usare il nome della costante
piuttosto che il valore direttamente.
Configurazione dei sensori per SetSensor()
SENSOR_TOUCH, SENSOR_LIGHT, SENSOR_ROTATION, SENSOR_CELSIUS, SENSOR_FAHRENHEIT, SENSOR_PULSE, SENSOR_EDGE
Modalità per SetSensorMode() SENSOR_MODE_RAW, SENSOR_MODE_BOOL, SENSOR_MODE_EDGE, SENSOR_MODE_PULSE, SENSOR_MODE_PERCENT, SENSOR_MODE_CELSIUS, SENSOR_MODE_FAHRENHEIT, SENSOR_MODE_ROTATION
Tipi per SetSensorType() SENSOR_TYPE_TOUCH, SENSOR_TYPE_TEMPERATURE, SENSOR_TYPE_LIGHT, SENSOR_TYPE_ROTATION
Output per On(), Off(), ecc. OUT_A, OUT_B, OUT_C Modalità per SetOutput() OUT_ON, OUT_OFF, OUT_FLOAT Direzioni per SetDirection() OUT_FWD, OUT_REV,
OUT_TOGGLE Potenza di output per SetPower() OUT_LOW, OUT_HALF, OUT_FULL Suoni per PlaySound() SOUND_CLICK,
SOUND_DOUBLE_BEEP, SOUND_DOWN, SOUND_UP, SOUND_LOW_BEEP, SOUND_FAST_UP
Modalità per SelectDisplay() DISPLAY_WATCH, DISPLAY_SENSOR_1, DISPLAY_SENSOR_2, DISPLAY_SENSOR_3, DISPLAY_OUT_A, DISPLAY_OUT_B, DISPLAY_OUT_C
Potenza per SetTxPower() TX_POWER_LO, TX_POWER_HI Tabella 1.6: Elenco di tutte le costanti.
14
1. Piccoli robot programmabili
1.3 Ambienti di programmazione
Un ambiente integrato di sviluppo di progetti software, normalmente chiamato IDE
(Integrated Development Environment), è un software che aiuta i programmatori nello
sviluppo del codice.
Anche per programmare i piccoli robot sono stati realizzati degli IDE: Bricx Command
Center Integrated Development Enviroment (BricxCC) è il più famoso e utilizzato
ambiente integrato per programmare i robot RCX tramite il linguaggio NQC (sopra
descritto).
1.3.1 IDE
E verso la fine degli anni ’70 che sono comparsi i primi IDE. Basic fu il primo
linguaggio ad essere creato con un IDE, era basato sui comandi e quindi non assomiglia
molto agli IDE grafici guidati ma menu di oggi. Da ricordare l’ambiente di
programmazione Smalltalk e la Lisp machine.
Tuttavia questi sistemi comprendevano l'intero sistema operativo, e non pemettevano
l'esecuzione sulla stessa macchina di software scritto in altri linguaggi, se non
riavviando il sistema.
Nel 1983 viene commercializzato il primo IDE per Personal Computer che funziona
come semplice applicazione, il Turbo Pascal della Borland, basato sul linguaggio
Pascal. Dopo di allora sono nati numerosi IDE, inizialmente con interfaccia utente a
carattere, poi di tipo grafico.
Il termine IDE si pone in contrasto con gli strumenti command-line, come VI.
Un IDE sufficientemente completo generalmente comprende:
un editor per la scrittura del codice sorgente;
un compilatore e/o un interprete;
un tool di building automatico;
un debugger;
15
1. Piccoli robot programmabili
uno o più tool per semplificare la costruzione di una GUI.
Alcuni IDE, rivolti allo sviluppo di software orientato agli oggetti comprendono anche
un navigatore di classi, un analizzatore di oggetti e un diagramma della gerarchia delle
classi.
Sebbene siano in uso alcuni IDE multi-linguaggio, come Eclipse, NetBeans e Visual
Studio, generalmente gli IDE sono rivolti ad uno specifico linguaggio di
programmazione.
1.3.2 Bricx Command Center
Bricx Command Center è un software open-source, scaricabile seguendo il seguente
link http://bricxcc.sourceforge.net, che fornisce molte funzioni per controllare e gestire
il robot RCX della Lego.
Per poter utilizzare il Bricx Command Center con l’RCX bisogna innanzitutto scaricare
il firmware sul robot., ossia il codice residente che sussiste nell’accensione del robot.
All’avvio del BricxCC viene visualizzata una finestra di dialogo dalla quale si può
scegliere tra i vari firmware disponibili (standard, brickOS, phForth, Lejos o altri) e
inviarli immediatamente.
Figura 1.4: Finestra di dialogo per scaricare il firmware.
16
1. Piccoli robot programmabili
Da ora è possibile controllare l’RCX, ad esempio clickando dal menù “Tools” la voce
“Direct Control” vengono visualizzate tutte le componenti, hardware e software, del
robot sottocontrollo.Inoltre con la voce “Watching the Brick” si possono richiedere
informazioni sullo stato di ogni pezzo, sensore, motore, variabile, programma,
impostando anche la visualizzazione grafica dei dati, da ricevere in un colpo solo, a
intervalli predefiniti, in flusso continuo.
Figura 1.5: Parte del menù a tendina “Tools”.
L’utente dispone, quindi, di un editor di comandi in NQC, munito di una vasta gamma
di funzionalità utilizzabili mediante il menù a tendina “Tools”.
L’editor è guidato dalla sintassi e fornisce un pannello chiamato “Template” che
contiene tutte le possibili espressioni del linguaggio NQC.
Figura 1.6: Il pannello templates.
17
1. Piccoli robot programmabili
Clickando sui vari elementi il BricxCC visualizza su un documento aperto la
corrispondente espressione. Bisogna solo fare attenzione a modificare gli eventuali
parametri. Inoltre digitando i singoli elementi viene verificata la correttezza della
digitazione. Per cui se una parola è sintatticamente corretta viene colorata. Il colore è
personalizzabile secondo i gusti dell’utente. Una possibile scelta potrebbe essere:
comandi in azzurro, valori in rosso e così via. Inoltre NQC è case-sensitive quindi
digitare una lettera minuscola invece che maiuscola non fa colorare la parola (ad
esempio wait (85) invece di Wait(85)), evidenziando subito l’errore.
Prima di essere inviato al robot il programma deve essere compilato. Questo si fa o
mediante il menù “Compile” e clickando la voce “Compile” o clickando il
corrispondente bottone nella toolbar.
Figura 1.7: Vari elementi che permettono di programmare con il BricxCC.
Figura 1.8: Menù a tendina Compile.
Al momento della compilazione il programma viene controllato sia per quanto riguarda
la parte sintattica che semantica. Gli eventuali errori vengono visualizzati a fondo
pagina e clickando sulle segnalazioni vengono visualizzati gli errori sul codice. Quando
tutti gli errori sono stati corretti il pannello a fondo pagina sparirà proprio ad indicare la
correttezza del programma.
18
1. Piccoli robot programmabili
Figura 1.9: Rispettivamente BricxCC con errori e senza errori.
Con un solo clic il codice viene compilato, controllato, trasmesso al robot tramite la
porta a infrarossi. Nel caso in cui un programma venga creato e compilato senza che il
robot sia collegato al computer si può, in un secondo momento, scaricare l’eseguibile
sull’RCX clickando dal menù “Compile” la voce “Download” o clickando il
corrispondente bottone nella toolbar (vedere Figura 1.8).
Si ricorda ancora che il mattoncino della Lego permette di memorizzare un massimo di
cinque programmi fino ad una dimensione totale di 64 Kbyte, per cui periodicamente
bisognerà rimuoverne alcuni per eseguirne altri.
Una volta trasferito il programma nella memoria del robot (o compilando o solo con il
download) viene emesso un bip. A questo punto il programma può essere lanciato
pigiando il pulsante di avvio fisicamente presente sull'RCX (si veda nella Figura 1.1)
oppure il pulsante virtuale sulla barra di BCC (la freccina verde). Allo stesso modo,
reale o virtuale, si opera per bloccare il programma (il segnale rosso indica la funzione
STOP) e quindi il robot.
19
1. Piccoli robot programmabili
1.4 Conclusioni
In questo capitolo abbiamo descritto, situandoli nell’ambiente di utilizzo, due
componenti importanti del lavoro: il linguaggio NQC e l’ambiente di sviluppo di
progetti per il robot RCX.
L’esigenza di introdurre anche per i piccoli robot dei linguaggi di programmazione di
alto livello e la necessità di rimanere molto vicini all’ambiente BricxCC, ha
caratterizzato il nostro lavoro di realizzazione dell’interfaccia grafica e la stesura di una
grammatica.
20
Capitolo 2
Il linguaggio NQCBaby
In questo capitolo raccogliamo le motivazioni che hanno portato alla nascita del
linguaggio NQCBaby insieme con la specifica di tale linguaggio attraverso la sua
grammatica espressa nella notazione dei grafi sintattici.
2.1 Il linguaggio LOGO
Il linguaggio LOGO, ideato e realizzato negli anni '60 dal professor Seymour Papert del
MIT (Massachusetts Institute of Tecnology), è un linguaggio di programmazione
fortemente orientato alla grafica e alla geometria, pensato per esser usato nelle scuole
elementari e medie inferiori perché permette anche a un principiante di ottenere subito
risultati visibili.
Papert, nel riassumere quasi trent’anni di attività nel campo della teoria dell’educazione
costruttivista, evidenzia come spesso la complessità dell’approccio didattico da lui
promosso sia stato ridotto al banale imparare facendo.
21
2. Il linguaggio NQCBaby
Proprio per il modello della rete neurale, alla base di un apprendimento che avviene
nello sviluppo di una rete concettuale, ridurre il costruttivismo alla semplice
manipolazione di oggetti non è corretto. Di più, il ridurre la teoria dell’educazione
costruttivista a pratiche didattiche deterministe è contro quella “Filosofia del LOGO”
che, alla soglia del 2000, Papert rilancia come un approccio culturale all’educazione, e
non meramente tecnico.
“Chi programma in LOGO rifiuta la preoccupazione scolastica di avere risposte giuste e
sbagliate; rifiutare giusto e sbagliato non significa che "tutto va bene", la vita, il senso
della vita non è avere la risposta giusta ma portare avanti le cose! Il concetto riferibile
alla cultura del LOGO porta a "fare in modo che succeda" ed è molto più di un principio
educativo o pedagogico. È meglio descrivibile come il riflesso di una filosofia del
vivere piuttosto che di una teoria dell'educazione. È anche qualcosa di più specifico del
costruttivismo nel senso comune attribuito a questo termine” [Papert99].
Fare qualcosa, e farlo funzionare, si distanzia da ogni precedente teoria educativa, e c'è
bisogno di una nuova definizione, che Papert definisce costruzionismo. Con questo
termine Papert si rifa a tutto quello che ha a che fare col costruire qualcosa, ma va anche
oltre il concetto di imparare facendo.
Il termine costruttivismo si riferisce ad una teoria su come matematica e scienze e ogni
altra materia può essere insegnata e sulle aspettative in merito a come potrebbero essere
apprese. Il termine costruzionismo si riferisce anch'esso a principi generali di
insegnamento e apprendimento, ma comprende in sé anche una specifica area di
contenuto che viene rigettata dalla scuola tradizionale.
Scegliere un approccio costruttivista per insegnare discipline tradizionali è un compito
di chi insegna, dell'insegnante: una scelta metodologica che ogni docente è bene faccia
con responsabilità. Ma i contenuti del costruzionismo sono una faccenda ben diversa.
Non si tratta di scegliere una teoria pedagogica e un metodo didattico di riferimento, ma
una scelta su cosa i cittadini del futuro debbano conoscere. È la scelta che Papert
sollecita vada fatta pensando al futuro della nostra civiltà e della nostra società: lo
sviluppo a cui assistiamo richiede di acquisire le competenze necessarie a partecipare
con cognizione di causa all'innovazione, in caso contrario ci attende una vita di
dipendenza.
22
2. Il linguaggio NQCBaby
Se quindi l’obiettivo dell’istruzione è far crescere le occasioni di apprendimento, in cui
l’alunno viene a sviluppare anche una capacità di orientamento di fronte a stimoli non
univoci, il docente ritrova pienamente un ruolo educativo non più nella posizione di tipo
gerarchico verso la classe ma cooperativo. Infatti non si tratta più di insegnare ad
imparare, ma di imparare cooperando, nel momento in cui accettiamo che “...l’attività
di concettualizzazione, originaria nel bambino, è una funzione analoga a quella che
caratterizza la ricerca dello scienziato. La formazione dei concetti è il compito comune,
di fronte alla realtà di scienziati e uomini ‘comuni’, fin dalla nascita ...” [Damian99].
E l’insegnante si troverà ad accompagnare per mano gli allievi in una funzione loro
naturale: apprendere, per conoscere e padroneggiare la realtà, acquisendo concetti,
perché “I concetti semplificano, ordinano ed organizzano la realtà ... ma soprattutto si
intessono secondo reti che diventano sempre più fitte, man mano che si prende
coscienza delle interconnessioni presenti nelle varie sfaccettature della realtà”
[Damian99].
Ed egli stesso si troverà ad apprendere, certamente su un altro piano, ma assieme ai
propri allievi.
Di fronte all’incessante evoluzione delle TIC alcuni insegnanti possono vedere superato
il loro personale patrimonio di strumenti didattici sviluppati e basati su un programma
informatico. Bisogna accettare l’idea dell’aggiornamento permanente, personale e dei
propri strumenti.
Le esigenze degli alunni cambiano: sempre più esposti alle tecnologie, anno dopo anno
dimostrano maggiore confidenza con mouse e computer, e in grado di rispondere
positivamente a proposte didattiche più articolate e complesse rispetto all’anno
precedente.
Per cui si richiede un ripensamento continuo sull'uso del computer a scuola, che sempre
meno è motivante in sé, ma diviene strumento efficace solo se posto al servizio di
progetti didattici complessi, multidisciplinari, collaborativi, coerenti con lo scenario
attuale delle TIC caratterizzato da connettività e portabilità.
Nonostante siano trascorsi oltre 40 anni, il LOGO rimane comunque attuale e
comunemente usato nei progetti didattici non tanto “come linguaggio di
programmazione tanto quanto invece un certo spirito nel realizzare i progetti”
[Papert99].
23
2. Il linguaggio NQCBaby
Dal punto di vista didattico, il LOGO insegnava un metodo di programmazione più
strutturato rispetto al più famoso BASIC in cui anche i programmi più banali
costringono ad un uso massiccio del goto. Infatti il LOGO permette di effettuare le
tipiche operazioni consentite da altri linguaggi, ma fornisce in più un insieme di
comandi chiamati Turtle Graphics (Grafica della tartaruga) finalizzati al disegno di
figure geometriche realizzate comandando opportunamente un cursore, detto tartaruga,
sullo schermo.
La geometria della tartaruga si differenzia dal modo tradizionale di disegnare al
computer perché descrive i percorsi "dall'interno" piuttosto che "dall'esterno" o
"dall'alto". Ad esempio dicendo "gira a destra" non si esprime una direzione assoluta,
ma una direzione relativa all'orientamento corrente della tartaruga, dicendo "vai avanti
di 10 passi" ci si riferisce alla posizione e alla direzione correnti.
Questo approccio ha molti vantaggi, ad esempio disegnare un quadrato inclinato è facile
come disegnare un quadrato con i lati orizzontali e verticali: la sequenza delle istruzioni
sarà la stessa, cambierà solo la posizione iniziale della tartaruga. Un altro vantaggio è di
carattere pedagogico, piuttosto che computazionale, perché questo modo di disegnare è
consono all'esperienza del ragazzo, perchè è analogo al modo di muoversi nello spazio.
LOGO stimola il bambino a risolvere specifici problemi e una immediata
visualizzazione globale gli consente di controllare la correttezza del suo programmino.
La tartaruga risponde interattivamente agli ordini, grazie al fatto che LOGO è
interpretato e soprattutto per venire incontro alle esigenza della fascia d’età cui vuole
rivolgersi.
In origine il LOGO fu utilizzato per muovere un semplice robot che stava sul
pavimento, il quale poteva essere pilotato dal computer mediante la digitazione di
istruzioni tipo FORWARD 50 per andare avanti di 50 passi o RIGHT 90 per girare a
destra di 90 gradi. Il primo di questi robot aveva una corazza simile a quella di una
tartaruga, da cui il nome del cursore (che nelle prime versioni su schermo era
semplicemente un piccolo triangolo). Con lo sviluppo dei monitor il linguaggio LOGO
divenne più accessibile e negli anni '80 la tartaruga passò allo schermo grafico dove fu
utilizzata per scopi didattici (costruire forme e disegni).
24
2. Il linguaggio NQCBaby
LOGO diventa uno strumento didattico che permette non solo di apprendere determinati
concetti di una materia, ma di imparare ad imparare.
Il motivo fondamentale che lo rende “linguaggio programmativo per bambini” deriva
dal concetto di “tartaruga”: un triangolino che si muove sullo schermo lasciando una
scia luminosa sulla base di pochi ordini fondamentali:
FORWARD (che si abbrevia con FD) seguito dal numero passi per
camminare avanti;
BACKWARD (che si abbrevia con BK) seguito dal numero passi per
camminare indietro;
RIGTH (che si abbrevia con RT) seguito dal gradi di rotazione per ruotare a
destra;
LEFT (che si abbrevia con LT) seguito dal gradi di rotazione per ruotare a
sinistra;
PENUP (che si abbrevia con PU) per disattivare la visualizzazione della scia;
PENDOWN (che si abbrevia con PD) per attivare la visualizzazione della scia.
Altri ordini consentono di cambiare il tratto colorandolo o ingrossandolo, di cambiare
colore allo sfondo e così via.
Il LOGO si basa su una idea fondamentale: tutto è fatto usando dichiarazione formale:
le procedure. Ve ne sono circa 200 predefinite e su queste si innestano quelle
dell’utente.
Negli anni '80 fu realizzata anche una variante, con istruzioni in italiano, del LOGO.
Segue un esempio, un piccolo programma che disegna un quadrato con 50 pixel di lato:
Versione LOGO in inglese:
REPEAT 4 [FORWARD 50 RIGHT 90]
REPEAT 4 [FD 50 RT 90] nella corrispondente sintassi abbreviata
Versione LOGO in italiano:
RIPETI 4 [AVANTI 50 DESTRA 90]
RIPETI 4 [A 50 D 90] nella corrispondente sintassi abbreviata
Riassumendo quindi possiamo dire che il LOGO è senz'altro il linguaggio di
programmazione didattico per eccellenza. Ha il vantaggio, sugli altri linguaggi, di
esistere nella lingua nazionale, di essere di immediata esecuzione e di essere un
linguaggio che usa le procedure.
25
2. Il linguaggio NQCBaby
Il LOGO deve essere recepito dagli alunni come un gioco. Infatti, se impostato e
insegnato in modo corretto, aiuta il bambino:
a riflettere su ciò che fa;
sugli errori che inevitabilmente commette;
sulla possibilità di usare tali errori come alleati e non come nemici;
sulle tante possibilità che ci sono per risolvere un unico problema.
2.2 Il linguaggio NQCBaby
NQCBaby nasce con l’idea di fornire un linguaggio orientato ai bambini piuttosto che ai
robot come nel caso di NQC, e si sviluppa come una versione del linguaggio open-
source NQC orientata alle attività di robotica a partire dalla scuola elementare. Questo
nuovo linguaggio è ora in sperimentazione in alcune scuole piemontesi con riferimento
al progetto “Uso didattico della robotica” dell’IRRE Piemonte (delibera n. 106 del
22/12/05).
La metodologia pedagogica costruttivista struttura l’apprendimento di NQCBaby in fasi
precise, partendo con NQCBaby_1 e man mano aggiungendo nuovi componenti
hardware al robot che si riflettono sulla definizione del linguaggio per arrivare quindi a
NQCBaby_5.
L’idea iniziale, proposta e utilizzata da Marcianò, era di sfruttare la flessibilità offerta
dal linguaggio NQC e di definire delle macro da usare come istruzioni primitive del
linguaggio NQCBaby. Per cui si ha la seguente definizione di istruzione dove ad ogni
primitiva (sia P) corrisponde una traduzione in codice NQC (sia Q):
#define P Q
Non si deve però pensare a questo lavoro come un semplice intervento sul vocabolario,
l’obiettivo è stato di sintetizzare gli step tecnici in step di azione e di semplificare la
sintassi NQC nascondendo e anche eliminando alcuni concetti del linguaggio come le
parentesi graffe e la dichiarazione di variabili.
L’insieme di tutte le macro sono contenute in documenti chiamati “Fogli Bianchi”, che
con gradualità permettono una programmazione “LOGO-like” dei robot compatibili con
26
2. Il linguaggio NQCBaby
NQC. Al momento sono disponibili cinque fogli bianchi “baby” e due “junior” (pensati
per la scuola media), che progressivamente portano gli alunni a cimentarsi con un
maggior numero di comandi, partendo quindi dalla gestione del solo movimento
(baby01) per arrivare alla programmazione con più task paralleli (junior02).
Grazie a questi “Fogli Bianchi” i ragazzi vengono a contatto con NQC vedendo come le
loro istruzioni vengono tradotte in NQC, che alla fine è il linguaggio che il robot
capisce.
Figura 2.1: I “Fogli bianchi”.
27
2. Il linguaggio NQCBaby
La seguente tabella mostra l’evoluzione delle primitive nei vari linguaggi NQCBaby e
come molte istruzioni sono sintatticamente vicine al LOGO di Papert, che è
indubbiamente il nostro punto di riferimento. LOGO è già consolidato in Italia e gli
insegnanti hanno già svolto attività in sintonia con la filosofia LOGO. Da questo punto
di partenza passare all’uso di NQCBaby sarà meno problematico per i bambini, che si
troveranno davanti a comandi molto simili a quelle del LOGO.
PRIMITIVE
BABY_1 PRIMITIVE
BABY_2 PRIMITIVE
BABY_3 PRIMITIVE
BABY_4 PRIMITIVE
BABY_5 Robby Robby Robby Robby Robby ciao ciao ciao Ciao ciao indietro ( x ) indietro ( x ) indietro ( x ) Indietro ( x ) indietro ( x ) avanti ( x ) avanti ( x ) avanti ( x ) avanti ( x ) avanti ( x ) sinistra ( x ) sinistra ( x ) sinistra ( x ) Sinistra ( x ) sinistra ( x ) destra ( x ) destra ( x ) destra ( x ) destra ( x ) destra ( x ) veloce ( x ) veloce ( x ) veloce ( x ) veloce ( x ) veloce ( x ) ripeti ( x ) ripeti ( x ) ripeti ( x ) ripeti ( x ) ripeti ( x ) avantisempre avantisempre avantisempre avantisempre avantisempre ripetisempre ripetisempre ripetisempre ripetisempre ripetisempre fine fine fine Fine fine -- accendiluce accendiluce accendiluce accendiluce -- spegniluce spegniluce spegniluce spegniluce -- aspetta ( x ) aspetta ( x ) aspetta ( x ) aspetta ( x ) -- sensore1_tocco sensore1_tocco Sensore1_tocco sensore1_tocco -- se_tocca se_tocca se_tocca se_tocca -- -- sensore2_tocco Sensore2_tocco sensore2_tocco -- -- se_toccadietro se_toccadietro se_toccadietro -- -- sensore3_luce Sensore3_luce sensore3_luce -- -- se_chiaro se_chiaro se_chiaro -- -- se_scuro se_scuro se_scuro -- -- -- sinoache_chiaro sinoache_chiaro -- -- -- sinoache_scuro sinoache_scuro -- -- -- altrimenti altrimenti -- -- -- acaso ( n ) acaso ( n ) -- -- -- -- uno -- -- -- -- fai_uno -- -- -- -- stop_uno -- -- -- -- due -- -- -- -- fai_due -- -- -- -- stop_due -- -- -- -- fine_fai
Tabella 2.1: Le primitive del linguaggio NQCBaby.
28
2. Il linguaggio NQCBaby
In questo modo i bambini al primo anno delle elementari progrediscono nello sviluppo
delle loro abilità linguistiche e logiche usando il loro linguaggio nativo e anche perché
usano un linguaggio di più alto livello scritto nel linguaggio NQC. Un linguaggio di alto
livello compatto, in quanto riassume in una sola primitiva più istruzioni NQC e, che
permette ai bambini di utilizzare “concetti noti” rispetto ad usare i nomi dei componenti
del robot.
L’utilizzo di “concetti noti” da un lato porta ad una programmazione “naturale” ma
dall’altro fa perdere la flessibilità del linguaggio. Per cui se consideriamo la primitiva
se_tocca , associata alle istruzioni NQC “if (SENSOR_1 == 1) {”, possiamo notare che
è vincolata con il sensore_1 così come se_chiaro è legato al sensore_3.
Forniamo alcuni esempi di programmi con le primitive sopra descritte.
Programma che utilizza le primitive NQCBaby_1: Robby veloce ( 3 ) avanti ( 100 ) veloce ( 7 ) indietro ( 100 ) ripeti ( 3 ) destra ( 90 ) sinistra ( 90 ) fine ripeti(2) indietro(10) avanti(20) fine ciao
Programma che utilizza le primitive NQCBaby_2: Robby ripetisempre avanti( 10 ) se_tocca indietro ( 100 ) destra( 100 ) fine fine ciao
Programma che utilizza le primitive NQCBaby_3: Robby ripetisempre se_scuro avanti( 10 ) accendiluce destra( 10 ) spegniluce fine avanti( 10 ) sinistra( 10 ) fine ciao
Questi programmi vengono editati nei cosiddetti “Fogli Bianchi” e utilizzati insieme al
Bricx Command Center IDE, che come detto precedentemente consente la compilazione
in NQC e l’invio del programma compilato al robot.
29
2. Il linguaggio NQCBaby
Le fasi di sviluppo di un programma NQCBaby possono essere chiarite con la seguente
figura:
Compilazione in NQC e invio al robot dal BricxCC
Programma editato, utilizzando il BricxCC, nel Foglio bianco N utilizzando il BricxCC
Classe N
Figura 2.2: Nascita e vita di un programma NQCBaby.
Segue la descrizione di ogni primitiva NQCBaby con la relativa traduzione nel
linguaggio NQC, partendo a spiegare i comandi di NQCBaby_1 fino ad arrivare alla
versione NQCBaby_5.
Codice in NQCBaby Codice in NQC Robby Task main{ Ciao Off(OUT_A+OUT_C); } indietro ( x ) OnRev(OUT_A+OUT_C); Wait(x); avanti ( x ) OnFwd(OUT_A+OUT_C); Wait(x); sinistra ( x ) OnFwd(OUT_C); OnRev(OUT_A); Wait(x); destra ( x ) OnFwd(OUT_A); OnRev(OUT_C); Wait(x); veloce ( x ) SetPower(OUT_A+OUT_C, x); ripeti ( x ) repeat(z) { Avantisempre while(true) {OnFwd(OUT_A+OUT_C);}; ripetisempre while(true) { Fine Off(OUT_A+OUT_C); }
Tabella 2.2: Primitive di NQCBaby_1
Robby
Ogni volta che si scrive un nuovo programma si deve assegnare un nome al robot.
Questo nome rappresenta un comando di avvio e fa si che il robot esegua quello che gli
viene ordinato di fare.
30
2. Il linguaggio NQCBaby
ciao
Per concludere il programma bisogna obbligatoriamente inserire questo comando che
chiude spegne i motori del robot.
indietro ( x )
Dopo aver montato un motore sul fianco sinistro del robot e collegato alla porta A e un
motore sul lato destro del robot collegato alla porta C, il robot procederà indietro per il
tempo (x) in centesimi di secondo.
avanti ( x )
Dopo aver montato un motore sul fianco sinistro del robot e collegato alla porta A e un
motore sul lato destro del robot collegato alla porta C, il robot in avanti per il tempo (x)
in centesimi di secondo.
sinistra ( x )
Dopo aver montato un motore sul fianco sinistro del robot e collegato alla porta A e un
motore sul lato destro del robot collegato alla porta C, il robot ruoterà verso sinistra per
il tempo (x) in centesimi di secondo.
destra ( x )
Dopo aver montato un motore sul fianco sinistro del robot e collegato alla porta A e un
motore sul lato destro del robot collegato alla porta C, il robot ruoterà verso destra per il
tempo (x) in centesimi di secondo.
veloce ( x )
Permette di regolare la velocità dei motori collegati alle porte A e C dell’RCX. Si
possono usare valori da 1 (lentissimo) a 7 (velocissimo).
ripeti ( x )
31
2. Il linguaggio NQCBaby
Avvia una sequenza di istruzioni che il robot deve eseguire in un ciclo, ovvero, una
ripetizione per (x) volte di quello che è compreso tra questo comando e fine.
avantisempre
Dopo aver montato un motore sul fianco sinistro del robot e collegato alla porta A e un
motore sul lato destro del robot collegato alla porta C, il robot procederà in avanti senza
fermarsi. Bisogna fare comunque attenzione perchè questo comando blocca
l’esecuzione del programma e le successive istruzioni non verranno eseguire.
ripetisempre
Avvia una sequenza di istruzioni che il robot deve eseguire in un ciclo infinito, ovvero,
una ripetizione senza fine delle istruzioni comprese tra questo comando e fine.
fine
Chiude la sequenza di istruzioni che il robot deve eseguire in un ciclo. Va posto
obbligatoriamente dopo i comandi che avviano cicli.
Codice in NQCBaby Codice in NQC Accendiluce On(OUT_B); spegniluce Off(OUT_B); aspetta ( x ) wait(x); sensore1_tocco SetSensor(SENSOR_1,SENSOR_TOUCH); se_tocca if (SENSOR_1 == 1) {
Tabella 2.3: Primitive di NQCBaby_2
accendiluce
Dopo aver collegato la lampadina LEGO alla porta B, questo comando permette di
accendere la lampadina a piacere.
spegniluce
Dopo aver collegato la lampadina LEGO alla porta B, questo comando permette
spegnere la lampadina a piacere.
32
2. Il linguaggio NQCBaby
aspetta ( x )
Introduce una pausa lunga (x) centesimi di secondo nel programma. Il robot continuerà
a eseguire le istruzioni ricevute per questo tempo (x) prima di eseguire i comandi
successivi.
sensore1_tocco
Setta il robot ad avere un sensore di contatto collegato alla porta 1. Senza questa
informazione il robot non potrà poi eseguire i comandi che prevedono l’uso del sensore,
come se_tocca.
se_tocca
Legge il valore del sensore di contatto collegato alla porta 1 e se diviene = 1 (ovvero
viene premuto) fa eseguire al robot le istruzioni comprese tra questo comando e fine.
Codice in NQCBaby Codice in NQC sensore2_tocco SetSensor(SENSOR_2,SENSOR_TOUCH); se_toccadietro if (SENSOR_1 == 1) { sensore3_luce SetSensor(SENSOR_3,SENSOR_LIGHT); se_chiaro if (SENSOR_3 > 48) { se_scuro if (SENSOR_3 <= 48) {
Tabella 2.4: Primitive di NQCBaby_3
sensore2_tocco
Se si dispone di un altro sensore di contatto permette di informare il robot che il sensore
è collegato alla porta 2. In genere questa primitiva serve quando sul robot viene
collegato un sensore del contatto sia davanti che dietro. Senza questa informazione il
robot non potrà poi eseguire i comandi che prevedono l’uso del sensore, come
se_toccadietro.
se_toccadietro
33
2. Il linguaggio NQCBaby
Legge il valore del sensore di contatto collegato alla porta 2 e se diviene = 1 (ovvero
viene premuto) fa eseguire al robot le istruzioni comprese tra questo comando e fine.
sensore3_luce
Setta il robot ad avere un sensore di luce collegato alla porta 3. Senza questa
informazione il robot non potrà poi eseguire i comandi che prevedono l’uso del sensore,
come se_chiaro o se_scuro.
se_chiaro
Legge il valore del sensore di luce collegato alla porta 3 e se superiore al valore indicato
(in questo caso 48) fa eseguire al robot le istruzioni comprese tra questo comando e fine.
se_scuro
Legge il valore del sensore di luce collegato alla porta 3 e se uguale o inferiore al valore
indicato (in questo caso 48) fa eseguire al robot le istruzioni comprese tra questo
comando e fine.
Codice in NQCBaby Codice in NQC sinoache_chiaro until (SENSOR_3 > 48) { sinoache_scuro until (SENSOR_3 <= 48) { altrimenti Else acaso ( n ) Random (n)
Tabella 2.5: Primitive di NQCBaby_4
sinoache_chiaro
Legge il valore del sensore di luce collegato alla porta 3 e sino a quando il suo valore
non diviene maggiore della soglia indicata (in questo caso 48) fa eseguire al robot le
istruzioni comprese tra questo comando e fine.
sinoache_scuro
34
2. Il linguaggio NQCBaby
Legge il valore del sensore di luce collegato alla porta 3 e sino a quando il suo valore
non diviene minore o uguale della soglia indicata (in questo caso 48) fa eseguire al
robot le istruzioni comprese tra questo comando e fine.
altrimenti
Permette di programmare un’azione da far svolgere al robot nel caso la precedente
istruzione “se” risultasse falsa. Va quindi posta dopo comandi come se_chiaro,
se_scuro, se_tocca e se_toccadietro. Diversamente scatta un errore logico.
acaso ( n )
Permette di avere valori casuali tra 0 e n-1 al posto di valori fissi nei comandi dati al
robot. Particolarmente utile in molti compiti di esplorazione in cui solo procedendo
casualmente il robot può coprire l’intera area di esplorazione.
Codice in NQCBaby Codice in NQC uno task prima() { fai_uno start prima; stop_uno stop prima; due task seconda() { fai_due start seconda; stop_due stop seconda; fine_fai }
Tabella 2.6: Primitive di NQCBaby_5
uno
Questo comando permette di definire una procedura chiamata uno. Va scritto all’esterno
del programma principale, racchiuso tra Robby e ciao nel quale può essere richiamata
con il comando fai_uno.
fai_uno
Permette di chiamare la procedura uno e può essere invocata all’interno di altre
procedure.
35
2. Il linguaggio NQCBaby
stop_uno
Permette di fermare la procedura uno in esecuzione, e può essere invocata all’interno di
altre procedure (Robby o due).
due
Questo comando permette di definire una procedura chiamata due. Va scritto all’esterno
del programma principale, racchiuso tra Robby e ciao nel quale può essere richiamata
con il comando fai_due.
fai_due
Permette di chiamare la procedura due e può essere invocata all’interno di altre
procedure.
stop_due
Permette di fermare la procedura due in esecuzione, e può essere invocata all’interno di
altre procedure (Robby o uno).
fine_fai
Per concludere una procedura, sia uno che due, bisogna obbligatoriamente inserire
questo comando.
2.3 Diagrammi sintattici di NQCBaby
Negli anni ’70, fin dalle prime presentazioni del linguaggio Pascal, Niklaus Wirth usò i
diagrammi sintattici che da allora furono un modo molto usato per la specifica di
grammatiche.
I Diagrammi Sintattici descrivono la grammatica mediante l’utilizzo di grafi e come tali
sono costituiti da:
nodi etichettati con simboli (terminali e non terminali), collegati da archi
orientati;
36
2. Il linguaggio NQCBaby
un arco da i a j significa che il simbolo i è seguito al simbolo j;
più archi rappresentano le possibili alternative.
Anche per descrivere la sintassi del linguaggio NQCBaby, peraltro molto semplice,
abbiamo scelto di usare questo tipo di specifica e di rappresentare con dei rettangoli gli
elementi non terminali del linguaggio, mentre i simboli terminali sono inseriti in ovali o
tondi.
Figura 2.3: Niklaus Wirth.
Segue la descrizione della grammatica di NQCBaby con i Diagrammi sintattici.
Programma
37
2. Il linguaggio NQCBaby
Task
Nome Task
Chiusura Task
Operazioni Senza Chiusura (OSC)
38
2. Il linguaggio NQCBaby
Operazioni Con Chiusura (OCC)
Operazioni Dei Task (ODT)
OSC_Senza_Numeri
39
2. Il linguaggio NQCBaby
OSC_Con_Numeri
OCC_Con_Numeri
OCC_Senza_Numeri
40
2. Il linguaggio NQCBaby
Numero
Casuale
Percorrendo il grafo da sinistra a destra si ottengono le frasi sintatticamente corrette del linguaggio. Analogamente si può vedere se una determinata frase può essere generata dal corrispondente grafo sintattico. Se si incontrano simboli non terminali si deve percorrere il grafo corrispondente il cui nome compare tra parentesi angolate .
Vediamo alcuni esempi di un programmi generati dai grafi sintattici appena vista.
Esempio 1: Robby ripetisempre se_chiaro indietro ( 10 ) destra ( acaso ( 30 ) ) spegniluce fine avanti ( 10 ) sinistra ( 10 ) fine ciao
Esempio 2: Robby ciao
41
2. Il linguaggio NQCBaby
2.4 Utilizzo di NQCBaby con in BricxCC
Come già accennato, utilizzando il linguaggio di programmazione NQC è stato
possibile creare un nuovo linguaggio, chiamato NQCBaby, costituito da comandi in
italiano di facile utilizzo per i giovani studenti. Tali comandi sono stati creati usando
delle macro tramite l’istruzione #define di NQC e inseriti nei fogli di lavoro, che il
giovane programmatore utilizza per scrivere il programma da inviare al robot.
Questo è stato necessario in quanto il robot riconosce solo i comandi in NQC e tali
macro consentono la traduzione di una primitiva nel rispettivo pezzo di codice.
L’approccio sopra descritto porta con se vantaggi e inconvenienti.
Senza dubbio si è rivelata una soluzione veloce da implementare soprattutto perché la
creazione delle macro richiede solo la conoscenza delle potenzialità del linguaggio
NQC.
Bisogna però considerare gli utilizzatori del linguaggio NQCBaby: i bambini, che anche
se seguiti dagli insegnanti, potrebbero cambiare l’intestazione dei “Fogli Bianchi”
modificando o cancellando le definizioni delle macro.
L’immediata conseguenza è l’insorgere di numerosi errori in fase di compilazione,
nonostante la correttezza del codice. Errori difficili da individuare e risolvere, in quanto
non legati alla logica del problema da risolvere con il programma ma all’intraprendenza
degli allievi più curiosi.
Rimane da considerare il problema di digitazione errata da parte di un bambino che
inizia ad interagire con NQCBaby. Il Bricx Command Center ci viene in contro
segnalando gli errori sintattici in fase di compilazione nell’apposito pannello. Questa
funzionalità però viene persa in quando i messaggi risultano incomprensibili dal
giovane programmatore.
Lo stesso discorso vale per gli errori semantici, per cui se il bambino dimentica, per
esempio, di inserire il comando fine o il comando ciao il BricxCC segnalerà un errore
che però non potrà essere molto di aiuto.
Le seguenti figure mostrano appunto come il BricxCC segnala questi errori.
42
2. Il linguaggio NQCBaby
Figura 2.4: Segnalazione errori sintattici del BricxCC.
Figura 2.5: Segnalazione errori semantici del BricxCC.
43
2. Il linguaggio NQCBaby
L’utilizzo di questi “Fogli bianchi” è limitativo per quanto riguarda la scelta del nome
da dare al robot. Se il bambino volesse cambiarlo dovrebbe modificare il foglio
aggiungendo una nuova macro o modificando quella già esistente.
Il prossimo capitolo presenta la soluzione da noi implementata durante il periodo di
stage: NQCBaby Editor.
44
Capitolo 3
NQCBaby Editor
Nella prima parte di questo capitolo vengono introdotti aspetti legati all’interfaccia
grafica, descrivendo le fasi implementative e esaminando le varie componenti del
programma fornendo così una sorta di guida per l’utente.
La seconda parte, invece, contiene la descrizione del linguaggio NQCBaby mediante la
notazione Backus-Naur, che viene utilizzata per la creazione degli insiemi guida e delle
associate procedure e per la generazione del parser mediante JavaCup. Il tutto integrato
con brevi richiami alla teoria sui Compilatori quale si può trovare nel libro di Aho, Sethi
ed Ullman [ASU86], il testo piú classico sull’argomento.
3.1 L’interfaccia grafica
Per quanto riguarda l’aspetto grafico abbiamo cercato di essere coerenti con lo stile del
BricxCC realizzando una interfaccia user-friendly, semplice e intuitiva.
45
3. NQCBaby Editor
3.1.1 Guida all’uso
Quando il programma viene avviato viene visualizzata una finestra di input che richiede
all’utente l’inserimento del percorso completo del file BricxCC.exe (esempio
C:\Programmi\BricxCC). Questa finestra è stata introdotta per evitare l’insorgere di
problemi (mancanza del pathname in fase di apertura del BricxCC) che necessiterebbero
di successive configurazioni manuali.
Figura 3.1: La finestra di dialogo che richiede il percorso fino alla cartella BricxCC.
Finché non verrà inserito non sarà possibile proseguire in quanto l’assenza del percorso
disabiliterebbe una funzionalità dell’NQCBaby Editor.
Una volta inserito il percorso del BricxCC.exe sarà visualizzata un’altra finestra di
input. Quest’ultima permette all’utente di scegliere il nome da dare al robot RCX.
Figura 3.2: La finestra di dialogo che permette di assegnare il nome al robot RCX.
46
3. NQCBaby Editor
Se non viene modificato il nome di default, il robot RCX verrà chiamato “Robby”.
Figura 3.3: La finestra di con il nome di default del robot RCX.
Dopo la scelta del nome apparirà il frame principale con cui l’utente interagisce. e che
gli permette di programmare il robot direttamente il linguaggio NQCBaby.
Figura 3.4: La finestra principale del programma NQCBaby Editor.
47
3. NQCBaby Editor
Esaminiamo nel dettaglio le varie componenti.
MENU FILE
Il menu file contiene sei possibili alternative.
Figura 3.5: Le scelte disponibili nel menu File.
L’opzione “Nuovo” permette di creare un nuovo documento senza nome, se le varie
aree dell’interfaccia sono già state modificate resetta le impostazioni di visualizzazione
di default.
La scelta di “Apri “ permette l’apertura di un documento (in formato .txt) esitente.
Una volta clickato viene visualizzata una finestra di dialogo che contiene opzioni che
permettono di indicare quali file aprire:
Nome File: permette di digitare o selezionare il nome del file che si vuole
aprire; questo riquadro contiene il file con l'estensione scelta nella voce Tipo
file.
Tipo File: permette di selezionare il tipo di file che si vuole aprire; di default è
settato “Documento di testo”.
Cerca in: permette di selezionare la cartella che contiene i file che si vogliono
aprire.
48
3. NQCBaby Editor
Figura 3.6: La finestra di dialogo che permette l’apertura di documenti già salvati.
L’opzione “Chiudi” chiude il documento corrente e reimposta l’interfaccia per la
prossima sessione di lavoro.
Seguono le voci “Salva con nome” e “Salva”. Quando si salva un documento per la
prima volta, sarà visualizzata la finestra di dialogo “Salva con nome”, sarà così
possibile dare un nome al file.
Figura 3.7: La finestra di dialogo che permette il salvataggio di nuovi documenti.
49
3. NQCBaby Editor
La finestra di dialogo contiene opzioni che permettono di specificare il nome e la
posizione del file da salvare.
Nome File: permette di inserire il nome del file da salvare.
Tipo File: permette di selezionare il tipo di file del file che si vuole salvare; di
default è settato “Documento di testo”
Cerca in: permette di selezionare la cartella nella quale si vuole salvare il
documento.
Infine l’opzione “Esci” comporta l’uscita dal programma.
Ogni operazione che potrebbe comportare la perdita di dati è preceduta da una finestra
di dialogo che chiede all’utente se desidera il salvataggio delle modifiche.
Figura 3.8: La finestra di dialogo che richiede il salvataggio delle modifiche.
MENU PROGETTO
Il menu progetto contiene due possibili alternative.
Figura 3.9: Le scelte disponibili nel menu Progetto.
La prima opzione “Traduci” permette di trasformare il programma scritto nel linguaggio
NQCBaby nel corrispondente programma in linguaggio NQC. Quest’ultimo verrà
50
3. NQCBaby Editor
automaticamente salvato con estensione “.nqc”, nella stessa cartella in qui si trova il
programma NQCBaby in formato “.txt”.
Ovviamente prima della traduzione viene richiesto il salvataggio con nome del
documento, nel caso non fosse stato salvato.
Infine l’opzione “Bricx Command Center” permette di aprire il corrispondente editor.
È da qui che il programma potrà essere inviato al robot RCX.
In linea di principio questa funzionalità dovrebbe essere invocata dopo la traduzione, in
questo modo nell’editor BricxCC verrà direttamente aperto il file appena tradotto.
In ogni caso si può usare questa opzione per aprire rapidamente un nuovo documento
nel BricxCC.
BARRA DEI BOTTONI
Subito sotto i menu viene messa a disposizione una barra dei bottoni, che racchiudendo
le opzioni dei menu ha il semplice scopo di facilitare l’accesso alle funzioni usate più
frequentemente.
Figura 3.10: La barra dei pulsanti.
AREE DI TESTO
Il pannello principale contiene due aree di testo, distinte da due rispettive etichette.
Sotto l’etichetta “Codice in NQCBaby” c’è l’area di testo editabile in cui l’utente può
scrivere il suo programma in linguaggio NQCBaby.
Dopo aver salvato il documento, l’utente può procedere con la traduzione. Se
quest’ultima è andata a buon fine, quindi non sono stati commessi errori di sintassi,
viene attivata l’area di testo sottostante l’etichetta “Codice in NQC”.
Quest’ultima non è editabile e ha il semplice scopo di visualizzare la traduzione del file
con estensione “.txt”.
51
3. NQCBaby Editor
Figura 3.11: Il pannello contenente le due aree di testo.
AREA DI SEGNALAZIONE ERRORI
Questo pannello si attiva dopo la traduzione. Se non sono stati commessi errori sintattici
in quest’area viene visualizzato il messaggio “Il programma è corretto” per indicarne
appunto la correttezza. Altrimenti, come mostrato nella figura successiva, verranno
mostrati messaggi che guidano l’utente alla correzione degli errori.
Figura 3.12: La segnalazione di un errore sintattico.
52
3. NQCBaby Editor
LISTE DELLE VERSIONI E DEI COMANDI
Il pannello contenente le versioni permette, come mostrato in figura, permette all’utente
la scelta tra cinque release. Questo crescendo di versioni corrisponde ad un percorso
scolastico che si sviluppa a partire dalla seconda elementare fino alla prima media,
almeno per quanto riguarda il robot RCX.
Clickare su uno degli elementi della lista comporta la modifica dell’insieme di comandi
utilizzabili dall’utente. La seguente figura riporta i comandi corrispondenti alla versione
“Baby 4”
Figura 3.13: Rispettivamener pannello delle versioni e dei comandi di “Baby 4”.
Intuitivamente “Baby 1” sarà sottoinsieme di “Baby 2”, quest’ultimo lo sarà di “Baby
3” e cosi via fino ad arrivare a “Baby 5” che conterrà tutti i sottoinsiemi.
L’utente, in base alla versione scelta, può quindi disporre dei rispettivi comandi. Il
doppio click su ognuno dei comandi scatena un evento: il comando clickato viene
inserito nell’area di testo “Codice in NQCBaby”. Questa funzionalità vuole agevolare
53
3. NQCBaby Editor
soprattutto gli utenti meno esperti che ancora con conoscono bene tutti i comandi e la
loro sintassi.
3.1.2 Dettagli Implementativi
L’NQCBaby Editor è stato realizzato mediante il linguaggio di programmazione Java,
versione 1.6 mentre, per quanto riguarda la documentazione di supporto, è stato
utilizzato Javadoc.
Durante la fase di sviluppo sono stati di grande aiuto il tutorial di Java della Sun,
disponibile on-line al link: http://java.sun.com/docs/books/tutorial/ e gli articoli tecnici
forniti dalla “prima rivista web dedicata a Java” MokaByte.
Questi due strumenti hanno permesso la creazione dell’interfaccia grafica di NQCBaby
Editor soprattutto grazie alle dettagliate spiegazioni e descrizioni dei concetti principali
correlate da numerosi esempi.
Nell’implementazione del software sono state utilizzate diverse librerie Java, tra le quali
ricordiamo java.io, javax.swing e java.awt.
Il Package java.io serve per leggere e scrivere dal file system, quindi nel nostro progetto
ci è tornato utile per la memorizzazione e l’apertura del file su e da disco.
Esistono dei Packages dedicati solo alla grafica, dai più semplici e primitivi oggetti
come in java.awt, a soluzioni più professionali quali javax.swing.
Il Package java.awt mette a disposizione del programmatore una serie di classi e
Interfacce per la gestione di interfacce grafiche. Infatti fornisce il classi necessarie per
trattare i possibili eventi che si possono verificare nell’utilizzo dell’editor.
Il Pacchetto javax.swing, contiene classi per la grafica, i cui nomi si distinguono
facilmente con la lettera J anteposta a loro: JLabel, JFrame, JPanel, JMenu,
JTable, JTree, ecc.
In questo capitolo verranno elencate e descritte le varie classi che costituiscono il
programma, mettendo in rilievo le varie interazioni tra il codice, il tutto supportato dalla
54
3. NQCBaby Editor
relativa documentazione Javadoc che illustra le funzionalità di ogni classe (costruttori e
metodi).
Il progetto NQCBaby Editor si compone di cinque classi pubbliche.
CLASSE MAIN
La classe principale, contenente il main, è InterfacciaTest.java. Non appena inizia la sua
esecuzione, questa richiede all’utente di impostare alcune configurazioni tramite due
finestre di dialogo di tipo JOptionPane e subito dopo svolgerà la sua funzione
principale, ossia creare un oggetto istanza della classe Interfaccia.java.
CLASSE INTERFACCIA
La classe Interfaccia.java, che estende JFrame, si occupa della creazione grafica
dell’interfaccia e contiene una serie di classi interne private responsabili per lo più
dell’ascolto degli eventi che si possono verificare durante l’utilizzo dell’editor.
Figura 3.14: Estratto javadoc della classe Interfaccia.java.
La seguente figura illustra la composizione dell’interfaccia nei vari componenti che la
costituiscono e come la stratificazione dei pannelli è stata utilizzata.
55
3. NQCBaby Editor
Figura 3.15: Lo schema dell’interfaccia.
Il pannello esterno è di tipo Container, a cui è associato un gestore di layout di tipo
BorderLayout, ed è composto da un oggetto di tipo JMenuBar, un altro di tipo
JToolBar e infine da un JSplitPane. Ognuno di questi elementi è formato da
sottocomponenti.
Iniziamo a considerare la barra dei menù. Essa è istanza della classe JMenuBar e
contiene i vari menù necessari all’applicazione. L’editor NQCBaby contiene una
menubar alla quale sono stati aggiunti due menù “File” e “Progetto” di tipo JMenu.
Ogni menu ha varie voci, ad esempio il menù File avrà le voci: Apri, Chiudi, Salva e
Esci, questi in Java sono degli oggetti della classe JMenuItem.
Figura 3.16: Rappresentazione grafica dei menu.
56
3. NQCBaby Editor
Una volta inseriti i menù bisogna munirli di gestori per gli eventi ad essi associati.
Quello che abbiamo dovuto gestire sono gli eventi legati a JMenuItem, in quanto
quelli relativi a JMenu sono gestiti dal sistema.
Lo stesso discorso vale per la barra dei bottoni, istanza di JToolBar, alla quale
abbiamo aggiunto i vari pulsanti, di tipo JBotton, ai quali sono associati specifici
gestori di eventi.
Quindi abbiamo scritto delle classi, una per ogni item del menù e una per la gestione di
ogni bottone (come mostrato nella tabella #), che implementano degli
ActionListener e che quindi specificano un metodo actionPerformed, che
prende in input un evento di tipo ActionEvent (ad esempio la pressione di un
bottone), ed è poi il metodo nel quale vengono specificate tutte le operazione che
devono essere eseguite in conseguenza del verificarsi dell’evento.
FUNZIONE ITEM BOTTONI Nuovo file MenuItemNewListener ButtonNewListener Apri file MenuItemFileOpenListener ButtonOpenListener Chiudi file MenuItemCloseListener ButtonCloseListener Salva con nome MenuItemSaveAsListener -- Salva MenuItemSaveListener ButtonSaveListener Esci dal programma MenuItemExitListener -- Traduci MenuItemConvertListener ButtonTranslateListener Bricx Command Center MenuItemBricxListener ButtonBricxListener Guida -- ButtonHelpListener
Tabella 3.1: Funzioni di NQCBaby e relative classi per i gestori di eventi
La zona immediatamente sotto ai bottoni è un JSplitPane, che ci è servito per
dividere lo spazio in due Components separati da una barra di split riposizionabile
orizzontale (.HORIZONTAL_SPLIT) o verticale (.VERTICAL_SPLIT). Inoltre
abbiamo impostato la dimensione dei componenti invocando il metodo
setDividerLocation che vuole come parametro un intero che rappresenta la
nuova coordinata x o y, a seconda dell’orientamento dello JSplitPane.
L’area splittata risulta quindi composta da due oggetti di tipo Component, e in quanto
tali possono a loro volta essere nuovamente definiti come JSplitPane. Questo è
quello che abbiamo fatto e quindi il componente sinistro e destro sono due
JSplitPane quindi composti da due Components ciascuno.
57
3. NQCBaby Editor
Il JSplitPane di sinistra, chiamato leftInternalSplit, contiene due JScrollPane,
ognuno dei quali ha al suo interno una JList, componente che permette di scegliere tra
gli elementi che compongono una lista. In ordine avremo le liste versione e comandi.
Entrambe le JList hanno una classe interna privata che implementa il metodo
mouseClicked(MouseEvent e) dell’interfaccia MouseListener.
Una volta riconosciuto un doppio click, nel seguente modo: if (e.getClickCount() == 2) { /* Corpo dell’if */ } la sola differenza è nell’insieme di istruzioni da eseguire al verificarsi dell’evento.
Clickando sugli elementi della lista versione si modifica la JList comandi, che
visualizza l’elenco delle primitive relative alla versione desiderata. Clickando, invece,
sugli elementi della seconda lista il corpo del metodo fa si che le primitive vengano
visualizzate nell’area dedicata alla digitazione del testo.
Consideriamo ora il JSplitPane rightInternalSplit. Esso è composto da un
JPanel, che contiene le aree i cui un programma può essere scritto in NQCBaby e
visualizzato in NQC, e da un JScrollPane per la visualizzazione degli errori in fase
di traduzione/compilazione.
Il JPanel è associato ad un gestore di layout di tipo GridBagLayout. Questo è uno
dei più flessibili e complessi gestori di layout Java, che colloca i componenti in una
griglia le cui righe e colonne possono avere, rispettivamente, altezza e larghezza
diverse. Inoltre un componente può occupare più di una cella della griglia ed i
componenti possono assumere orientamenti diversi all'interno delle celle.
Bisogna prima di tutto stabilire il come indicare le celle all'interno del pannello, la
notazione è quella classica (numero colonna, numero riga) a partire dall'angolo in alto a
sinistra della griglia :
( 0 , 0 ) ( 1 , 0 ) ( 2 , 0 )
( 0 , 1 ) ( 1 , 1 ) ( 2 , 1 )
( 0 , 2 ) ( 1 , 2 ) ( 3 , 1 )
58
3. NQCBaby Editor
Ad ogni componente può essere associato con un istanza di GridBagConstraints,
che specifica le dimensioni e la collocazione degli elementi all’interno della griglia.
Avendo quattro elementi da inserire di cui due sono etichette e quindi JLabel e due
pannelli scrollabili contenenti due aree (una editabile e una no) di tipo JTextArea.
Da notare che il pannello di sinistra deve contenere oltre all’area di testo anche una
JTextArea indicante i numeri di riga. Questo è stato possibile usando di nuovo il
JSplitPane che divide in due il pannello scollabile e nascondendo la barra di split. Il
fatto che il JScrollPane contenga entrambe fa si che le due aree di testo vengano
scrollate insieme.
Inoltre è da aggiungere che l’area di sinistra è munita di un ricevitore di evento che
reagisce alla digitazione dei tasti Backspace, Delete e Enter, modificando
opportunamente il pannello contenente i numeri di riga.
Per concludere bisogna parlare dell’altro Component del rightInternalSplit. Questo è
semplicemente definita come un JScrollPane contenente una JTextArea non
editabile nel quale verranno visualizzati i possibili errori sintattici e semantici.
CLASSE COMANDI
Questa è una semplice classe di supporto ad Interfaccia.java e costruisce semplicemente
le strutture dati per contenere l’insieme di primitive del linguaggio, a partire da
NQCBaby_1 fino a NQCBaby_5.
In questo modo è stato possibile, man mano che il linguaggio evolveva, aggiungere i
comandi senza dover modifica la classe principale.
CLASSE HELP
Lo scopo di questa classe è fornire all’utente una piccola guida per l’utilizzo del
software. Estendendo JFrame è stata definita utilizzando delle componenti swing
come mostrato nella figura seguente.
59
3. NQCBaby Editor
Figura 3.17: Lo schema dell’interfaccia della classe Help.
CLASSE TRADUTTORE_BABY
L’altra classe importante del nostro progetto è Traduttore_Baby.java. Questa classe si
occupa dell’effettiva compilazione del codice NQCBaby in NQC e verrà spigata nella
sezione 3.2.4.
3.2 Il pre-compilatore NQCBaby
Un compilatore è un programma che prende in ingresso una sequenza di istruzioni
scritte in un certo linguaggio di programmazione (codice sorgente), controlla che la
sequenza sia effettivamente una frase del linguaggio dato e le traduce in istruzioni di un
secondo linguaggio (codice oggetto).
Generalmente i compilatori sono in grado di riconoscere alcuni tipi di errori presenti nel
programma e in alcuni casi possono suggerire una possibili correzione.
Nei compilatori moderni l’operazione di compilazione si divide in due stadi principali:
il front end e il back end.
Il primo stadio si occupa di tradurre il sorgente in un linguaggio intermedio (di solito
interno al compilatore) ed è diviso in più punti:
60
3. NQCBaby Editor
analisi lessicale;
analisi sintattica;
analisi semantica.
È nella seconda fase, quella back end, che avviene l’ottimizzazione del codice
intermedio e la generazione del codice oggetto in un linguaggio target che spesso è il
linguaggio macchina.
NQCBaby Editor mette a disposizione un pre-compilatore, che implementando i punti
dello stadio front end, si occupa di pre-elaborare un codice sorgente NQCBaby per
generarne un nuovo, di codice NQC, il quale verrà compilato dal compilatore NQC.
La seguente figura cerca di spiegare meglio i passaggi sopra descritti, applicandoli al
contesto.
Figura 3.18: Pre-compilazione da in NQCBaby a NQC e compilazione in linguaggio macchina.
61
3. NQCBaby Editor
3.2.1 Analisi lessicale
L'Analisi lessicale è il processo che, attraverso un analizzatore lessicale spesso chiamato
scanner o lexer, prende in ingresso un flusso di caratteri e produce in uscita una
sequenza di token.
Il flusso di caratteri è genericamente il codice sorgente di un programma mentre i token
sono gli elementi minimi (non ulteriormente divisibili) di un linguaggio, ad esempio
parole chiave (for, while), nomi di variabili (pippo) o operatori (+, -, <<).
L'analisi lessicale interviene genericamente nella parte di front end della compilazione e
ricevendo in input una sequenza di caratteri, legge un carattere per volta (da sinistra
verso destra). Opera in modo iterativo e ad ogni iterazione cerca di generare una
sottosequenza (token) che costituisce una stringa cha appartiene al linguaggio denotato
da una delle espressioni regolari del lessico. Ad ogni iterazione cerca di generare il
token di lunghezza massima tra quelli ammissibili. Se invece non riesce a generare un
token ammesso dal lessico, si ferma restituendo un errore (detto errore lessicale). Spesso
alcuni token non hanno importanza per la successiva fase di analisi sintattica e possono
quindi non essere restituiti dall’analizzatore lessicale: per esempi i simboli di spaziatura,
i commenti nei vari linguaggi di programmazione. Ad ogni token viene associato il tipo
corrispondente all’espressione regolare che riconosce il token. Questa attribuzione dei
tipi facilita la successiva analisi sintattica.
Un noto generatore di scanner è Lex (1975) che usa espressioni regolari per specificare
lo scanner. Utilizzando espressioni regolari ed associati segmenti di codice chiamati
azioni, Lex genera una tabella delle transizioni e un programma che interpreta tale
tabella. L’azione è eseguita quando si riconosce un token generato dall’espressione
regolare.
Lex prende in input una specifica del lessico, ossia una sequenza di definizioni ausiliare
e una sequenza di regole di traduzione.
Un’azione è un pezzo di codice che deve essere eseguito ogni volta che viene
riconosciuto il token specificato dall’espressione corrispondente. L’output di Lex è un
analizzatore lessicale per il lessico specifico.
62
3. NQCBaby Editor
Lo scanner generato da Lex può essere usato in congiunzione con un parser (YACC) per
eseguire sia l’analisi lessicale che sintattica.
Lex utilizza per la specifica dell'analizzatore lessicale le espressioni regolari, che sono
un formalismo più efficiente delle grammatiche ma meno potente. La distinzione tra
grammatiche e espressioni regolari sta nel fatto che le espressioni regolari non sono in
grado di riconoscere strutture sintattiche ricorsive, mentre le grammatiche non hanno
questo problema. Una struttura sintattica come le parentesi bilanciate, che richiede che
le parentesi aperte siano nello stesso numero di quelle chiuse non può essere
riconosciuta da un analizzatore lessicale, e per questo scopo si ricorre all’analizzatore
sintattico. Invece costanti numeriche, identificatori o keyword vengono normalmente
riconosciute dall'analizzatore lessicale.
Per la programmazione in Java è stato realizzato il generatore lessicale JFlex, una
versione migliorata di JLex (un precedente generatore di analizzatori lessicali),
realizzato per lavorare insieme con il generatore di parser LALR JavaCup di Scott
Hudson.
3.2.2 Analisi sintattica
L'analisi sintattica, o parsing, è il processo atto ad analizzare uno stream continuo in
input, letto per esempio da un file o una tastiera in una fase precedente, in modo da
determinare la sua struttura attraverso una grammatica formale.
Nella maggior parte dei linguaggi l'analisi sintattica opera su una sequenza di token in
cui l'analizzatore lessicale spezzetta l'input ed effettua il riconoscimento di una
grammatica e alla conseguente costruzione di un albero sintattico, che mostra le regole
utilizzate durante il riconoscimento dall'input; l'albero sintattico viene poi visitato
(anche più volte) durante l'esecuzione di un'interprete o di un compilatore. Il risultato di
questa fase è un albero di sintassi.
Bisogna dire ancora che l’accezione inglese, parser, viene usata per indicare l'insieme
della analisi lessicale e della analisi sintattica vera e propria e che nella maggior parte
dei casi un parser non viene a mano ma generati attraverso dei generatori di parser.
L'insieme delle regole sintattiche costituisce la grammatica del linguaggio.
63
3. NQCBaby Editor
Una grammatica libera dal contesto o CFG è una grammatica formale (ovvero un
insieme di stringhe di lunghezza finita costruite sopra un alfabeto finito) in cui ogni
regola di derivazione è nella forma:
V → w
In cui V rappresenta un simbolo non terminale e w è una sequenza di simboli terminali e
non.
“Libera dal contesto” vuole indicare che il simbolo non terminale V può sempre essere
rimpiazzato da w, a prescindere dai simboli che lo precedono o seguono.
Per descrivere linguaggi di programmazione la grammatica deve espressa in modo
formale e non ambiguo.
Le più usate modalità di descrizione di regole sintattiche sono la notazione Backus-Naur
(BNF) e i diagrammi sintattici (visti nella sezione 2.3).
La notazione BNF, proposta da John Backus, è un formalismo che permette di
descrivere, in modo preciso e non ambiguo, la grammatica CFG di un linguaggio
formale.
La specifica della sintassi di un linguaggio di programmazione ha tipicamente un non
terminale principale <programma>, e un insieme di regole di derivazione che
descrivono come un programma è strutturato in moduli, i moduli in istruzioni, le
istruzioni in espressioni, e via dicendo. Un testo scritto da un programmatore si potrà
considerare sintatticamente corretto (e quindi effettivamente un programma nel
linguaggio in questione) se è possibile ricavarlo per sostituzioni successive a partire dal
non terminale <programma>. Questo tipo di verifica, dato il testo da verificare e una
specifica BNF, si presta a essere eseguito in modo automatico. Una verifica di questo
tipo rappresenta infatti una parte importante del funzionamento dei compilatori.
Segue la grammatica del linguaggi NQCBaby secondo la notazione Backus-Naur. <programma> ::= <task> ROBBY <body> CIAO <task> <body> :: = <operazioni_senza_chiusura> <body> | <operazioni_con_chiusura> <body> | <operazioni_dei_task> <body> | ε ; <task> ::= <nome_task> <body_task > FAI_FINE | ε ; <nome_task> ::= UNO | DUE
64
3. NQCBaby Editor
<body_task> :: = <operazioni_senza_chiusura> <body_task> | <operazioni_con_chiusura> <body_task> | ε ; <operazioni_dei_task> :: = FAI_UNO | FAI_DUE | STOP_UNO | STOP_DUE <operazioni_senza_chiusura> ::= <operazioni_senza_chiusura_con_numeri> | <operazioni_senza_chiusura_senza_numeri> <operazioni_senza_chiusura_con_numeri> ::= VELOCE ( <espressione> ) | AVANTI ( < espressione > ) | INDIETRO ( < espressione > ) | DESTRA ( < espressione > ) | SINISTRA ( < espressione > ) | ASPETTA ( < espressione > ) | ACASO ( < espressione > ) <operazioni_senza_chiusura_senza_numeri> ::= AVANTISEMPRE | ACCENDILUCE | SPEGNILUCE | SENSORE1_TOCCO | SENSORE3_LUCE <operazioni_con_chiusura> ::= <operazioni_con_chiusura_con_numeri> <body> FINE | <operazioni_con_chiusura_senza_numeri> <body> FINE <operazioni_con_chiusura_con_numeri> ::= RIPETI ( <espressione> ) <operazioni_con_chiusura_senza_numeri>::= RIPETISEMPRE | SE_TOCCA | SE_CHIARO | SE_SCURO | SINOACHE_CHIARO | SINOACHE_SCURO | ALTRIMENTI <cifra> ::= 0|1|2|3|4|5|6|7|8|9 <espressione> ::= <numero> | ACASO ( <numero> ) <numero> ::= <cifra> <numero> | ε A prescindere dallo strumento usato il compito di un parser è quello di determinare se e
come l’input può essere derivato dal simbolo iniziale seguendo le regole della
grammatica formale.
65
3. NQCBaby Editor
Il parser ottiene un token dall’analizzatore lessicale e verifica se questo token può essere
generato dalla grammatica del linguaggio sorgente. Ci si aspetta inoltre che il parser
riporti gli errori sintattici in forma intelligibile.
I metodi di parsificazione usati nei compilatori possono essere classificati come top-
down e bottom-up. Il primo costruisce l’albero di sintassi dalla radice alle foglie, mentre
il secondo parte dalle foglie per arrivare alla radice. In ambedue i casi l’input del parser
viene scandito da sinistra a destra, un simbolo per volta.
I più efficienti metodi top-down e bottom-up lavorano solo su sottoclassi di
grammatiche, come ad esempio le grammatiche LL e LR che sono abbastanza
espressive da descrivere la maggior parte dei costrutti sintattici dei linguaggi di
programmazione.
Parser sviluppati a mano spesso lavorano con grammatiche LL, mentre quelli per le
grammatiche LR sono costruiti con strumenti automatici.
Un importante distinzione da dire è che i parser LL usano una derivazione sinistra
(leftmost) per cui il non terminale più a sinistra viene rimpiazzato ad ogni passo della
derivazione. Quelli LR invece sostituiscono il non terminale più a destra.
Un parser botton-up viene utilizzato per grammatiche libere da contesto e nella
creazione di compilatori dei linguaggi di programmazione.
L’analisi LR è complessa per le grammatiche dei linguaggi di programmazione, viene
quindi definita LALR (Look-Ahead LR) versione semplificata che approssimano la
tecnica di parsing LR e che può essere usata con le grammatiche libere dal contesto.
Il codice sorgente di questi tipi di parser possono essere creati con generatori di parser
(compiler-compiler), partendo dalla descrizione dello specifico linguaggio sotto forma
di grammatica (in genere BNF) unito al codice associato ad ogni regola della
grammatica.
Tra i più noti vanno ricordati Yacc (Yet Another Compiler Compiler) e JavaCup.
Yacc è un generatore di analizzatore sintattici, ossia programmi capaci di
“comprendere” le frasi scritte in un dato linguaggio e di prendere delle decisioni in base
al loro significato.
Il codice sorgente in output è scritto in C.
66
3. NQCBaby Editor
Lex e Yacc, solitamente usati in coppia, sono due strumenti che consentono di generare
automaticamente il parser data la grammatica di un linguaggio e le espressioni regolari
dei token.
Lex è l'abbreviazione di Lexer (ovvero analizzatore lessicale) come descritto nel
paragrafo precedente. Yacc è l'acronimo di una esclamazione: “Yet Another Compiler
Compiler!” ("Ancora un altro compilatore di compilatori!"), a testimoniare che al tempo
del suo primo sviluppo, strumenti automatici per la costruzione di compilatori dovevano
essere abbastanza comuni.
Originariamente scritti rispettivamente da Steve Johnson e da Mike Lesk, sono stati
usati in passato per realizzare molti dei compilatori oggi esistenti, compresi il C
portabile, il Pascal, il Fortran e sono tuttora usati nello sviluppo di pacchetti che
traducono da un linguaggio all’altro.
Compilatori prodotti con Lex e Yacc vengono spesso chiamati compilatori guidati dalla
sintassi, in quanto l'analisi sintattica è alla base di tutto il processo di compilazione; in
questo caso viene effettuata per prima l'analisi sintattica, e si utilizzano i risultati di
questa fase come guida per le fasi successive, più "semantiche". Tutto il processo può
essere visto come una serie di trasformazioni a partire dalla struttura sintattica del
sorgente.
Un’implementazione molto simile a Yacc è JavaCup. Quest’ultimo, sviluppato da Scoot
Hudson, è un generatore di parser LALR per il linguaggio di programmazione Java
(anch’esso scritto in Java) sempre a partire da una grammatica fornita nella notazione
BNF.
Riportiamo la specifica della grammatica di NQCBaby fornita al generatore JavaCup. import java_cup.runtime.*; import java.io.*; /* Preliminaries to set up and use the scanner. */ init with {: scanner.init(); :}; scan with {: return scanner.next_token(); :}; /* Terminals (tokens returned by the scanner). */ /* Keywords fisse */ terminal ROBBY; terminal FINE; terminal CIAO; terminal VUOTO; /* Keywords SC_CN */
67
3. NQCBaby Editor
terminal VELOCE; terminal AVANTI; terminal INDIETRO; terminal DESTRA; terminal SINISTRA; terminal ASPETTA; terminal ACASO; /* Keywords SC_SN */ terminal AVANTISEMPRE; terminal ACCENDILUCE; terminal SPEGNILUCE; terminal SENSORE1_TOCCO; terminal SENSORE3_LUCE; /* Keywords CC_CN */ terminal RIPETI; /* Keywords CC_SN */ terminal RIPETISEMPRE; terminal SE_TOCCA; terminal SE_CHIARO; terminal SE_SCURO; terminal SINOACHE_SCURO; terminal ALTRIMENTI; terminal UNO; terminal DUE; terminal FAI-FINE; terminal FAI_UNO; terminal FAI_DUE; terminal STOP_UNO; terminal STOP_DUE; /* Tokens that have a value */ terminal Integer NUMERO terminal String OPERAZIONE; /* Delimiters */ terminal LPAREN, RPAREN; /* Non terminals */ non terminal Programma programma; non terminal Body body; non terminal OSC operazioni_senza_chiusura ; non terminal OSC_CN operazioni_senza_chiusura_con_numeri; non terminal OSC_SN operazioni_senza_chiusura_senza_numeri; non terminal OCC operazioni_con_chiusura; non terminal OCC_CN operazioni_con_chiusura_con_numeri; non terminal OCC_SN operazioni_con_chiusura_senza_numeri; non terminal ODT operazioni_dei_task; non terminal T task; non terminal NT nome_task; non terminal CT chiusura_task; non terminal P parametro;
68
3. NQCBaby Editor
/* The grammar */ start with programma; parametro ::= NUMERO:n | casuale:c ; casuale ::= ACASO LPARENT parametro:p RPARENT {: System.out.println("\n Random(" + n + ");"); :} ; programma ::= task:t ROBBY {: System.out.println("task main(){ " ) :} body:b {: System.out.println(" \n Off(OUT_A+OUT_C); }"); :} CIAO task:t ; task ::= nome_task:nt body_task:bt FAI-FINE {: System.out.println("\n } "); :}| VUOTO ; nome_task ::= UNO {: System.out.println("\n task prima() { "); :}| DUE {: System.out.println("\n task seconda() { "); :} ; body_task ::= operazioni_senza_chiusura:osc body_task:bt| operazioni_con_chiusura:occ body_task:bt| VUOTO ; body ::= operazioni_senza_chiusura:osc body:b| operazioni_con_chiusura:occ body:b| operazioni_dei_task:odt body:b| VUOTO ; operazioni_senza_chiusura ::= operazioni_senza_chiusura_con_numeri:osc_cn | operazioni_senza_chiusura_senza_numeri:osc_sn ; operazioni_senza_chiusura_con_numeri ::= VELOCE LPAREN
69
3. NQCBaby Editor
NUMERO:n RPAREN {: System.out.println("\n SetPower(OUT_A+OUT_C," + n + ");"); :} | AVANTI LPAREN parametro:p RPAREN {: System.out.println("\n OnFwd(OUT_A+OUT_C);Wait(" + n + ");"); :} | INDIETRO LPAREN parametro:p RPAREN {: System.out.println("\n OnRev(OUT_A+OUT_C);Wait(" + n + ");"); :} | DESTRA LPAREN parametro:p RPAREN {: System.out.println("\n OnFwd(OUT_A);OnRev(OUT_C);Wait(" + n + ");"); :} | SINISTRA LPAREN parametro:p RPAREN {: System.out.println("\n OnFwd(OUT_C);OnRev(OUT_A);Wait(" + n + ");"); :} | ASPETTA LPAREN parametro:p RPAREN {: System.out.println("\n Wait(" + n + ");"); :} | ; operazioni_senza_chiusura_senza_numeri ::= AVANTISEMPRE {: System.out.println("\n while(true) {OnFwd(OUT_A+OUT_C);};"); :} | ACCENDILUCE {: System.out.println("\n On(OUT_B);"); :}| SPEGNILUCE {: System.out.println("\n Off(OUT_B);"); :}| SENSORE1_TOCCO {: System.out.println("\nSetSensor(SENSOR_1,SENSOR_TOUCH);"); :}| SENSORE3_LUCE {: System.out.println("\nSetSensor(SENSOR_3,SENSOR_LIGHT);"); :} ; operazioni_con_chiusura ::= operazioni_con_chiusura_con_numeri:occ_cn body:b FINE {: System.out.println(" \n Off(OUT_A+OUT_C); }"); :}| operazioni_con_chiusura_senza_numeri:occ_cs body:b FINE {: System.out.println(" \n Off(OUT_A+OUT_C); }"); :} ; operazioni_con_chiusura_con_numeri ::= RIPETI LPAREN parametro:p RPAREN
70
3. NQCBaby Editor
{: System.out.println("\n repeat(" + n + ") {"); :} ; operazioni_con_chiusura_senza_numeri ::= RIPETISEMPRE {: System.out.println("\n while(true) {"); :}| SE_TOCCA {: System.out.println("\n if (SENSOR_ == 1) {"); :}| SE_CHIARO {: System.out.println("\n if (SENSOR_3 > 48) {"); :}| SE_SCURO {: System.out.println("\n if (SENSOR_3 <= 48) {"); :}| SINOACHE_CHIARO {: System.out.println("\n until (SENSOR_3 > 48) {"); :}| SINOACHE_SCURO {: System.out.println("\n until (SENSOR_3 <= 48) {"); :}| ALTRIMENTI {: System.out.println("\n else {"); :} ; operazioni_dei_task ::= FAI_UNO {: System.out.println("\n start prima;"); :}| FAI_DUE {: System.out.println("\n start seconda; "); :}| STOP_UNO {: System.out.println("\n stop prima; "); :}| STOP_DUE {: System.out.println("\n stop seconda; "); :} ;
3.2.3 Analisi semantica
L’analisi semantica è l’attività di assegnazione di un significato alla struttura sintattica
corretta e di conseguenza all’espressione linguistica. In altre parole si occupa di
controllare il significato delle istruzioni presenti nel codice in ingresso e quindi
controlla che non ci siano errori semantici del programma.
Durante questa fase si assume che il programma sia sintatticamente corretto in quanto si
lavora su una albero sintattico. Vengono fatti controlli statici del programma per
assicurarsi della sua correttezza, ossia controlli di tipo context sensitive.
Tra i vari tipi di controlli troviamo:
controlli sui tipi
si controlla che un operatore o una funzione siano invocate su
argomenti di tipo opportuno
sono ammesse conversioni predefinite (da int a float)
controlli matematici
71
3. NQCBaby Editor
divisioni per 0 (il valore deve essere determinabile al tempo di
compilazione)
overflow o underflow (costanti che eccedono la rappresentazione nel
linguaggio macchina)
controlli sul flusso
verificare se l’occorrenza di un break o continue è legale
verificare se l’occorrenza di una return è legale
controlli di unicità
verificare che una variabile sia dichiarata una sola volta all’interno
della sua portata
le etichette in uno switch o in un record devono essere uniche
le etichette devono essere uniche all’interno di una procedura
controlli in corrispondenza di nomi
in alcuni linguaggi ogni loop ha un nome e questo nome deve trovarsi
sia all’inizio che alla fine del loop
questi tipi di verifiche non possono essere fatti dal parser perché
esprimono una proprietà context-dependent
controlli sulla correttezza delle ottimizzazioni
questi tipi di controlli vengono di solito fatti nelle fasi successive di
’analisi statica è contrapposta di solito all’analisi dinamica che consente di controllare
generazione di codice
L
cicli infiniti
deferenziazioni di puntatori NULL
limiti degli array
metodo usato per l’analisi semantica consiste nell’identificare attributi o proprietà
e seguenti figure rappresentano uno schema riassuntivo delle fasi della compilazione.
Il
delle entità sintattiche che devono essere calcolate e di scrivere equazioni di attributi o
regole semantiche per esprimere tali calcoli. Il risultato di questa fase è l'albero
sintattico astratto (AST).
L
72
3. NQCBaby Editor
Flusso Attività Codice sorgente Editing
Flusso Generatore di codice intermedio
codice intermedio
Ottimizzatore codice intermedio
codice intermedio
Generatore codice target
codice target
Analizza lessicale tore Analisi lessicale
Token
Analizza Analisi ntatticatore sintattico si
Albero di sintassi
Analizzatore semantico Analisi s manticae
Albero di sint ssi astratta a
Figura 3.19: Ris ettivamente fase front end e back end
3.2.4 Progettazione di un Predictive Parser
Volendo sviluppare a mano un parser, abbiamo scelto di effettuare un’analisi sintattica
scesa ricorsiva è chiamato Predictive Parser. Il simbolo
gli insiemi guida, uno per
uida (<programma> → <task> ROBBY <body> CIAO <task>)=
> FAI-FINE) =
p
mediante il metodo top-down.
Un tipo di parser top-down a di
“current character” determina senza ambiguità la produzione che ha generato il carattere
mediano e quindi quale procedura del parser vada eseguita.
Abbiamo utilizzato le due funzioni Ini() e Seg() per definire
ogni produzione, che ci hanno permesso la costruzione del parser a discesa ricorsiva e
che riportiamo qui di seguito.
G Ini (<task> ROBBY <body> CIAO <task>) U Seg (<programma >) = {UNO, ROBBY, ┤} Ini (<task> ROBBY <body> CIAO <task>) = Ini (<task>) U Ini (ROBBY) = {UNO, ROBBY} Ini (<task>) = Ini (<nome_task> <body_task Ini (<nome_task>) = {UNO}
73
3. NQCBaby Editor
Ini (ROBBY) = {ROBBY} Seg(<programma>) = { ┤} Guida (<body> → <operazioni_senza_chiusura> <body>) =
Ini (<operazioni_senza_chiusura> <body>) =
) = {VELOCE, AVANTI, NTISEMPRE,
NTI,
Gu
U numeri>) = {RIPETI,
NOACHE_CHIARO,
SEMPRE, E_SCURO,
Gu oni_dei_task> <body>) =
, STOP_UNO, STOP_DUE} Ini (FINE) = {CIAO,
ask> → <nome_task> <body_task > FAI-FINE) = Ini (<nome_task> <body_task > FAI-FINE) =
E} rogramma>) =
Ini (UNO) = {UNO} i {DUE}
a> <body_task>) = Ini (<operazioni_senza_chiusura><body_task>) =
{VELOCE, AVANTI, NTISEMPRE,
NTI,
Gu
Ini (<operazioni_senza_chiusura>) =
U Ini (<operazioni_senza_chiusura_con_numeri>) umeri>Ini(<operazioni_senza_chiusura_senza_n
INDIETRO, DESTRA, SINISTRA, ASPETTA, ACASO, AVAACCENDILUCE, SPEGNILUCE, SENSORE1_TOCCO, SENSORE3_LUCE} Ini (<operazioni_senza_chiusura_con_numeri>) = {VELOCE, AVAINDIETRO, DESTRA, SINISTRA, ASPETTA, ACASO} Ini(<operazioni_senza_chiusura_senza_numeri>) = {AVANTISEMPRE, ACCENDILUCE, SPEGNILUCE, SENSORE1_TOCCO, SENSORE3_LUCE} ida (<body> → <operazioni_con_chiusura> <body>) = Ini (<operazioni_con_chiusura> <body>) =
Ini (<operazioni_con_chiusura>) = Ini (<operazioni_con_chiusura_con_numeri>)
Ini (<operazioni_con_chiusura_senza_RIPETISEMPRE, SE_TOCCA, SE_CHIARO, SE_SCURO, SISINOACHE_SCURO, ALTRIMENTI} Ini (<operazioni_con_chiusura_con_numeri>) = {RIPETI} Ini (<operazioni_con_chiusura_senza_numeri>) = {RIPETISE_TOCCA, SE_CHIARO, SE_SCURO, SINOACHE_CHIARO, SINOACHALTRIMENTI} ida (<body> → <operazioni_dei_task> <body>) = Ini (<operazi
Ini (<operazioni_dei_task>) = {FAI_UNO, FAI_DUECIAO) U Guida (<body> → ε) = Seg (<body>) = Ini (
FINE} Guida (<t Ini (<nome_task>) = Ini (UNO) U Ini (DUE) = {UNO, DUGuida (<task> → ε ) = Seg (<task>) = Ini (ROBBY) U Seg (<p { ROBBY, ┤ } Ini (ROBBY) = {ROBBY}
a>) = {┤} Seg (<programm Guida (<nome_task> → UNO) =
da (<nome_task> → DUE) = Ini (DUE) = Gu Guida ( <body_task> → <operazioni_senza_chiusur Ini (<operazioni_senza_chiusura>) =
Ini (<operazioni_senza_chiusura_con_numeri>) U umeri>) = Ini(<operazioni_senza_chiusura_senza_n
INDIETRO, DESTRA, SINISTRA, ASPETTA, ACASO, AVAACCENDILUCE, SPEGNILUCE, SENSORE1_TOCCO, SENSORE3_LUCE} Ini (<operazioni_senza_chiusura_con_numeri>) = {VELOCE, AVAINDIETRO, DESTRA, SINISTRA, ASPETTA, ACASO} Ini(<operazioni_senza_chiusura_senza_numeri>) = {AVANTISEMPRE, ACCENDILUCE, SPEGNILUCE, SENSORE1_TOCCO, SENSORE3_LUCE} ida ( <body_task> → <operazioni_con_chiusura> <body_task>) = Ini (<operazioni_con_chiusura> <body_task>) =
Ini (<operazioni_con_chiusura>) = Ini (<operazioni_con_chiusura_con_numeri>) U
74
3. NQCBaby Editor
Ini (<operazioni_con_chiusura_senza_numeri>) = {RIPETI, RIPETISEMPRE, SE_TOCCA, SE_CHIARO, SE_SCURO, SINOACHE_CHIARO, SINOACHE_SCURO, ALTRIMENTI} Ini (<operazioni_con_chiusura_con_numeri>) = {RIPETI} Ini (<operazioni_con_chiusura_senza_numeri>) = { RIPETISEMPRE, SE_TOCCA, SE_CHIARO, SE_SCURO, SINOACHE_CHIARO, SINOACHE_SCURO, ALTRIMENTI}
Guida (<body_task> → ε) = Seg (<body_task>) = Ini (FAI_FINE) = {FAI_FINE} Guida (<operazioni_dei_task> → FAI_UNO) = Ini (FAI_UNO) = {FAI_UNO} Guida (<operazioni_dei_task> → FAI_DUE) = Ini (FAI_DUE) = {FAI_DUE} Guida (<operazioni_dei_task> → STOP_UNO) = Ini (STOP_UNO) = {STOP_UNO} Guida (<operazioni_dei_task> → STOP_DUE) = Ini (STOP_DUE) = {STOP_DUE} Guida (<operazioni_senza_chiusura> → <operazioni_senza_chiusura_con_numeri>) =
Ini (<operazioni_senza_chiusura_con_numeri>) = {VELOCE, AVANTI, INDIETRO, DESTRA, SINISTRA, ASPETTA, ACASO}
Guida (<operazioni_senza_chiusura> → <operazioni_senza_chiusura_senza_numeri>) =
Ini (<operazioni_senza_chiusura_senza_numeri>) = {AVANTISEMPRE, ACCENDILUCE, SPEGNILUCE, SENSORE1_TOCCO, SENSORE3_LUCE}
Guida (<operazioni_senza_chiusura_con_numeri> → VELOCE ( <espressione> )) = Ini (VELOCE ( <espressione> )) = {VELOCE} Guida (<operazioni_senza_chiusura_con_numeri> → AVANTI ( <espressione> )) = Ini (AVANTI ( <espressione> )) = {AVANTI} Guida (<operazioni_senza_chiusura_con_numeri> → INDIETRO ( <espressione> )) = Ini (INDIETRO ( <espressione> )) = {INDIETRO} Guida (<operazioni_senza_chiusura_con_numeri> → DESTRA ( <espressione> )) = Ini (DESTRA ( <espressione> )) = {DESTRA} Guida (<operazioni_senza_chiusura_con_numeri> → SINISTRA ( <espressione> )) = Ini (SINISTRA ( <espressione> )) = {SINISTRA} Guida (<operazioni_senza_chiusura_con_numeri> → ASPETTA ( <espressione> )) = Ini (ASPETTA ( <espressione> )) = {ASPETTA} Guida ( <operazioni_senza_chiusura_con_numeri> → ACASO ( <espressione> )) = Ini (ACASO ( < espressione > )) = {ACASO} Guida (<operazioni_senza_chiusura_senza_numeri> → AVANTISEMPRE ) = Ini (AVANTISEMPRE ) = {AVANTISEMPRE} Guida (<operazioni_senza_chiusura_senza_numeri> → ACCENDILUCE) = Ini (ACCENDILUCE) = {ACCENDILUCE} Guida (<operazioni_senza_chiusura_senza_numeri> → SPEGNILUCE) = Ini (SPEGNILUCE) = {SPEGNILUCE} Guida (<operazioni_senza_chiusura_senza_numeri> → SENSORE1_TOCCO) = Ini (SENSORE1_TOCCO) = {SENSORE1_TOCCO} Guida (<operazioni_senza_chiusura_senza_numeri> → SENSORE3_LUCE) = Ini (SENSORE3_LUCE) = {SENSORE3_LUCE} Guida (<operazioni_con_chiusura> → <operazioni_con_chiusura_con_numeri> <body> FINE) = Ini (<operazioni_con_chiusura_con_numeri> ) = {RIPETI}
75
3. NQCBaby Editor
Guida ( <operazioni_con_chiusura> → <operazioni_con_chiusura_senza_numeri> <body> FINE) =
Ini (<operazioni_con_chiusura_senza_numeri>) = {RIPETISEMPRE, SE_TOCCA, SE_CHIARO, SE_SCURO, SINOACHE_CHIARO, SINOACHE_SCURO, ALTRIMENTI}
Guida (<operazioni_con_chiusura_con_numeri> → RIPETI ( <espressione> )) = Ini (RIPETI ( <espressione> )) = {RIPETI} Guida (<operazioni_con_chiusura_senza_numeri> → RIPETISEMPRE) = Ini (RIPETISEMPRE) = {RIPETISEMPRE} Guida (<operazioni_con_chiusura_senza_numeri> → SE_TOCCA) = Ini (SE_TOCCA) = {SE_TOCCA} Guida (<operazioni_con_chiusura_senza_numeri> → SE_CHIARO) = Ini (SE_CHIARO ) = {SE_CHIARO} Guida (<operazioni_con_chiusura_senza_numeri> → SE_SCURO) = Ini (SE_SCURO ) = {SE_SCURO} Guida (<operazioni_con_chiusura_senza_numeri> → SINOACHE_CHIARO) = Ini (SINOACHE_CHIARO) = {SINOACHE_CHIARO} Guida (<operazioni_con_chiusura_senza_numeri> → SINOACHE_SCURO) = Ini (SINOACHE_SCURO) = {SINOACHE_SCURO} Guida (<operazioni_con_chiusura_senza_numeri> → ALTRIMENTI) = Ini (ALTRIMENTI) = {ALTRIMENTI} Guida (<cifra> → 0) = Ini ( 0 ) = {0} … Guida (<cifra> → 9) = Ini ( 9 ) = {9} Guida (<espressione> → <numero>) = Ini ( <numero> ) U Seg (<espressione>) =
Ini (<numero>) = Ini (<cifra><numero>) = Ini (<cifra>) = {0,1,2,3,4,5,6,7,8,9}
Seg (<espressione>) = {)} Guida (<espressione> → ACASO ( <numero> )) = Ini (ACASO ( <numero> )) = {ACASO} Guida (<numero> → <cifra><numero>) = Ini (<cifra><numero>) = Ini (<cifra>) = {0,1,2,3,4,5,6,7,8,9} Guida (<numero> → ε) = Seg (<numero>) = Seg (<espressione>) U { ) }= {)} Seg (<espressione>) = { ) }
Ad ogni non terminale della grammatica viene associata una procedura sempre
seguendo ASU86.
Mostriamo qui di seguito, come abbiamo realizzato alcune procedure: Program discesa_ricorsiva begin cc:= PROSS call(<programma>) if cc = ‘ ┤ ‘ then “programma corretto” else ERRORE(…) end
76
3. NQCBaby Editor
Procedure <programma> Begin if cc = ‘ROBBY’ or ‘UNO’ then call(<task>) if cc = ‘ROBBY’ then cc := PROSS call (<body>) if cc = ‘CIAO’ then cc := PROSS call (<task>) else ERRORE (…) else ERRORE (…) else ERRORE(…) end Procedure <body> Begin if cc = ‘VELOCE’ or ‘…’ or cc = ‘SENSORE3_LUCE’ PROSS then call(<operazioni_senza_chiusura>) call (<body>) else if cc = ‘RIPETI’ or ‘…’ or cc = ‘ALTRIMENTI’ PROSS then call(<operazioni_con_chiusura>) call (<body>) else if cc = ‘FAI_UNO’ or ‘…’ cc = ‘ STOP_DUE’ PROSS then call(<operazioni_dei_task>) call(<body>) else if cc = ‘CIAO’ or cc = ‘FINE’ then do nothing else ERRORE (…) end Procedure <task> Begin if cc = ‘UNO’ or cc = ‘DUE’ PROSS then call(<nome_task>) call (<body_task>) if cc = ‘FAI_FINE’ then cc := PROSS else ERRORE (…) else if cc = ‘ROBBY’ or cc = ‘┤’ then do nothint else ERRORE (…) end Procedure <nome_task> Begin if cc = ‘UNO’ PROSS then cc := PROSS else if cc = ‘DUE’ then cc := PROSS else ERRORE (…) end Procedure <body_task> Begin if cc = ‘VELOCE’ or ‘…’ or cc = ‘SENSORE3_LUCE’ PROSS then call(<operazioni_senza_chiusura>) call (<body_task>) else if cc = ‘RIPETI’ or ‘…’ or cc = ‘ALTRIMENTI’ PROSS then call(<operazioni_con_chiusura>) call (<body_task>) else if cc = ‘FAI_FINE’ PROSS then do nothing
77
3. NQCBaby Editor
else ERRORE (…) end Procedure <operazioni_dei_task> Begin if cc = ‘FAI_UNO’ PROSS then cc := PROSS else if cc = ‘FAI_DUE’ then cc := PROSS else if cc = ‘STOP_UNO’ then cc := PROSS else if cc = ‘STOP_DUE’ then cc := PROSS else ERRORE (…) end Procedure <operazioni_senza_chiusura> Begin if cc = ‘VELOCE’ or ‘…’ or cc = ‘ACASO’ PROSS then call(<operazioni_senza_chiusura_con_numeri>) else if cc = ‘AVANTISEMPRE’ or ‘…’ or cc = ‘SENSORE3_LUCE’ PROSS then call(<operazioni_senza_chiusura_senza_numeri>) else ERRORE (…) end Procedure <operazioni_senza_chiusura_con_numeri> Begin if cc = ‘VELOCE’ PROSS then cc := PROSS else if cc = ‘AVANTI’ then cc := PROSS else if cc = ‘INDIETRO’ then cc := PROSS else if cc = ‘DESTRA’ then cc := PROSS else if cc = ‘SINISTRA’ then cc := PROSS else if cc = ‘ASPETTA’ then cc := PROSS else if cc = ‘ACASO’ then cc := PROSS else ERRORE (…) end Procedure <operazioni_senza_chiusura_senza_numeri> Begin if cc = ‘AVANTISEMPRE’ PROSS then cc := PROSS else if cc = ‘ACCENDILUCE’ then cc := PROSS else if cc = ‘SPEGNILUCE’ then cc := PROSS else if cc = ‘SENSORE1_TOCCO’ then cc := PROSS else if cc = ‘SENSORE3_LUCE’ then cc := PROSS else ERRORE (…) end
78
3. NQCBaby Editor
Procedure <operazioni_con_chiusura> Begin if cc = ‘RIPETI’ PROSS then call(<operazioni_con_chiusura_con_numeri>) call(<body>) if cc = ‘FINE’ then cc := PROSS else ERRORE (…) else if cc = ‘RIPETISEMPRE’ or ‘…’ or cc = ‘ALTRIMENTI’ PROSS then call(<operazioni_con_chiusura_senza_numeri>) call(<body>) if cc = ‘FINE’ then cc := PROSS else ERRORE (…) else ERRORE (…) end Procedure <operazioni_con_chiusura_con_numeri> Begin if cc = ‘RIPETI’ PROSS then cc := PROSS else ERRORE (…) end Procedure <operazioni_con_chiusura_senza_numeri> Begin if cc = ‘RIPETISEMPRE’ PROSS then cc := PROSS else if cc = ‘SE_TOCCA’ then cc := PROSS else if cc = ‘SE_CHIARO’ then cc := PROSS else if cc = ‘SE_SCURO’ then cc := PROSS else if cc = ‘SINOACHE_CHIARO’ then cc := PROSS else if cc = ‘SINOACHE_SCURO’ then cc := PROSS else if cc = ‘ALTRIMENTI’ then cc := PROSS else ERRORE (…) end Procedure <cifra> Begin if cc = ‘0’ PROSS then cc := PROSS else if cc = ‘1’ then cc := PROSS else if cc = ‘…’ then cc := PROSS else if cc = ‘9’ then cc := PROSS else ERRORE (…) end Procedure <espressione> Begin if cc = ‘0’ or cc = ‘)’ PROSS then call(<numero>) else if cc = ‘ACASO’ PROSS
79
3. NQCBaby Editor
then if cc = ‘(‘ then cc := PROSS call(<numero>) if cc = ‘)’ then cc := PROSS else ERRORE (…) else ERRORE (…) else ERRORE (…) end Procedure <numero> Begin if cc = ‘0’ or ‘…’ or cc = ‘9’ PROSS then call(<cifra>) call(<numero>) else if cc = ‘)’PROSS do nothing else ERRORE (…) end Abbiamo potuto, così, scrivere un programma in java Traduttore_Baby.java che
processa l’input seguendo le linee guida delle procedure.
Nel nostro codice il “current character” (cc) viene ottenuto applicando uno
StringTokenizer a una stringa contenente il programma NQCBaby e invocando il
metodo nextToken() che corrisponde al PROSS delle procedere sopra descritte. La
maggior parte delle procedure sono unite in due metodi della classe chiamati
blocco() e controlloParametri(), data la semplicità del linguaggio.
Qualora un cc non corrisponda a nessun terminale viene segnalato un errore. Dopo che è
stata appurata la correttezza sintattica, viene invocato un metodo chiamato
controllo() che rileva eventuali errori semantici quali:
ROBBY senza la chiusura CIAO,
strutture di controllo senza la chiusura FINE,
se viene inserito il comando CIAO prima del comando ROBBY,
e così via.
Superato anche questo controllo il programma nel linguaggio NQCBaby viene tradotto
nel relativo linguaggio NQC.
Il riconoscimento e segnalazione degli errori è un ruolo molto importante.
Ogni fase è in grado di rilevare una particolare classe di errori:
Analisi lessicale: i caratteri rimanenti non formano nessun token;
Analisi sintattica: uno stream di token viola le regole sintattiche del linguaggio;
Analisi semantica: dei costrutti sintatticamente corretti.
80
3. NQCBaby Editor
Mostriamo quelli che nel nostro software sono gli errori segnalati.
"Manca il comando Robby"; "Manca il comando ciao"; "Manca il comando fine"; "Il programma contiene troppi comandi fine"; "Il comando contiene un errore di scrittura"; "Il comando contiene dei parametri sbagliati:"; "Il comando ciao deve essere usato solo per terminare il programma!"; "Il comando Robby deve essere usato solo per iniziare il programma!"; "Manca la parentesi tonda aperta al comando:"; "Manca la parentesi tonda chiusa al comando:"; "Fare attenzione alle minuscole e alle maiuscole del comando:"; "Manca il numero del comando:"; "Controllare gli spazi del comando:";
81
Capitolo 4
Conclusioni e sviluppi futuri
Il software NQCBaby Editor è nato grazie all’interazione con Giovanni Marcianò,
ricercatore presso l’IRRE Piemonte, e con alcune insegnanti elementari che hanno
aderito alle iniziative riguardanti l’uso delle robotica nella didattica.
Lo scopo di questo Editor è fornire uno strumento per programmare piccoli robot che:
sia orientato ai bambini;
sia simile all’ambiente di sviluppo Bricx Command Center;
sia basato sul linguaggio NQCBaby;
usi istruzioni in italiano non definite mediante macro;
permetta di conoscere NQC e di confrontare i due linguaggi.
Il professor Marcianò, durante lo svolgimento di un corso per docenti di scuola media
tenutosi a Cava dei Tirreni, ha fatto collaudare NQCBaby Editor agli altri insegnanti che
sono riusciti ad utilizzarlo facilmente per eseguire i loro programmi per l’RCX.
82
4. Conclusioni e sviluppi futuri
Sono state apprezzate semplicità, intuitività e chiarezza dell'interfaccia, considerando
che questo è solo l’inizio di un lavoro che può evolvere nel corso del tempo per essere
reso migliore e con più funzionalità (per esempio renderlo guidato dalla sintassi).
Nonostante fosse una versione provvisoria l’Editor da noi sviluppato ha trovato molti
consensi, tanto che è stato installato nel laboratorio informatico della scuola e da
settembre sarà utilizzato, insieme al BricxCC, nei nuovi progetti delle scuole elementari.
NQCBaby Editor è stato pensato per robot programmabili con NQC, come l’RCX, ma
uno sviluppo simile può essere fatto per un altro robot della Lego: l’NXT.
Ovviamente l’Editor dovrà essere adattato per la programmazione del nuovo robot,
basato sul linguaggio di programmazione NBC, quindi con istruzioni diverse rispetto a
NQC, e con ulteriori sensori e funzionalità.
Il periodo di tirocinio ci ha permesso di utilizzare conoscenze apprese durante i corsi
universitari, di apprenderne di nuove e di vedere come queste possano essere applicate
al di fuori di un contesto universitario.
83
Appendice A
Glossario
84
A. Glossario
Analizzatore lessicale (scanner)
Strumento prendere in ingresso un flusso di caratteri e produce in uscita una sequenza di
token.
Analizzatore sintattico (parser )
Strumento che analizza uno stream continuo in input, letto per esempio da un file o una
tastiera in una fase precedente, in modo da determinare la sua struttura attraverso una
grammatica formale.
BCC (Bricx Command Center)
Software open-source che permette di controllare e gestire il robot RCX, consentendo di
scrivere i programmi che il robot deve eseguire e infine inviandoli.
Bytecode
Linguaggio intermedio più astratto del linguaggio macchina, usato per descrivere le
operazioni che costituiscono un programma.
BNF
La notazione BNF, proposta da John Backus, è un formalismo che permette di
descrivere, in modo preciso e non ambiguo, la grammatica di un linguaggio formale.
Compilatore
Un programma che prende in ingresso una sequenza di istruzioni scritte in un certo
linguaggio di programmazione (codice sorgente), controlla che la sequenza sia
affettivamente una frase del linguaggio dato e la traduce in istruzioni di un secondo
linguaggio (codice oggetto).
Debugger
Programma che analizza approfonditamente un generico programma, al fine di aiutare il
programmatore a trovarne i bug.
85
A. Glossario
Diagrammi Sintattici
Formalismo, proposto da NikLaus Wirth, che permette di descrivere, in modo preciso e
non ambiguo, la grammatica di un linguaggio formale tramite l’uso di grafi.
Editor
Programma utilizzato per creare, modificare e salvare files generalmente di testo.
Firmware
Insieme di funzioni logiche che risiedono in un semiconduttore sia come topografia,
intendendo quindi l’insieme delle funzioni implementate in logica pura direttamente sul
die, sia come vero e proprio software che generalmente trova posto all’interno di una
memoria RON o EEPROM.
Grammatica
Descrizione di un linguaggio formale in modo preciso, è cioè delle regole sintattiche del
linguaggio, basate su insieme finito di simboli o caratteri, detto alfabeto.
IDE (Integrated Development Environment)
Ambiente integrato di sviluppo di progetti software che aiuta i programmatori nello
sviluppo del codice (nel nostro caso un esempio di IDE è il BricxCC).
Interprete
Programma che esegue altri programmi. Un linguaggio interpretato è un linguaggio di
programmazione i cui programmi vengono eseguiti da un interprete. Tale approccio si
distingue da quello dei linguaggi compilati: a differenza di un interprete, un compilatore
non esegue il programma che riceve in ingresso, ma lo traduce in linguaggio macchina
(memorizzando su file il codice oggetto pronto per l'esecuzione diretta da parte del
processore).
JavaCup
Un generatore di parser LALR per il linguaggio di programmazione Java.
86
A. Glossario
Logo
Linguaggio di programmazione orientato alla grafica e alla geometria usato come
strumento didattico nelle scuole elementari.
Macro
Una procedura ricorrente durante l’esecuzione di un programma alla quale è associato
un nome.
NQC
Linguaggio di programmazione, con sintassi ispirata al C che permette la
programmazione dell’RCX.
NQCBaby
Linguaggio di programmazione di alto livello (compatto) orientato ai bambini, che
permette la programmazione dell’RCX con istruzioni in italiano.
Open-source
Indica un software rilasciato con un tipo di licenza per la quale il sorgente è lasciato alla
disponibilità di alla disponibilità di eventuali sviluppatori.
Porta USB
Un bus esterno di nuova generazione facile da collegare, che permette di inserire fino a
127 dispositivi in una linea, se collegati tramite i relativi hub per USB. Le tavolette
USB non richiedono un adattatore a parte, poiché ricevono energia direttamente
dall'alimentatore incorporato della porta USB.
RCX Brick
Mattoncino programmabile. (vedere Figura 1.1)
RIS (robotic invention system)
87
A. Glossario
Kit della Mindstorm contenente i pezzi LEGO standard e Technics, l’RCX Brick e tutto
quello che permette di programmare e gestire il mattoncino RCX.
ROBOLAB
Ambiente grafico per la programmazione della robotica Lego. (vedere Figura 1.3)
Routine
Insieme di istruzioni ordinate in una determinata sequenza tale da portare il computer ad
eseguire un desiderato compito.
Yacc & Lex
sono due strumenti che consentono di generare automaticamente il parser data la
grammatica di un linguaggio e le espressioni regolari dei token. Yacc è un generatore di
analizzatore sintattici, ossia programmi capaci di “comprendere” le frasi scritte in un
dato linguaggio e di prendere delle decisioni in base al loro significato. Lex è
l'abbreviazione di Lexer (ovvero analizzatore lessicale).
88
Bibliografia
TESTI
[Bonfanti 2004] Marco Bonfanti, Robot mobili per l’esplorazione di ambienti:
esperienze con la tecnologia Lego Mindstorms, Università degli studi di Modena e
Reggio Emilia, Facoltà di Ingegneria Informatica,2004.
[DeLuca 2003] Diana DeLuca, Robotics and Teaching: Promoting the Effective Use of
Technology in Education, Tesi del Department of Child Development, Tufts University,
2003.
[Marcianò 2006] Giovanni Marcianò, Linguaggi robotici per la scuola, Cagliari,
DIDAMATICA, 2006.
[Marcianò 2005] Giovanni Marcianò, Robotica: un diverso tutoring, Ferrara, Expo e-
learning, 2005.
[Marcianò 2005] Giovanni Marcianò, Informatica come linguaggio, Potenza,
Didamatica, 2005.
[Marcianò 2005] Giovanni Marcianò, Usare il linguaggio LOGO per costruire
micromondi, INDIRE, PuntoEdu, 2005.
89
[Marcianò 2005] Giovanni Marcianò, Costruire microrobot e programmarli, INDIRE,
PuntoEdu, 2005.
[Marcianò 2004] Giovanni Marcianò, Robotica a scuola, Rassegna dell'Istruzione, Le
Monnier, 2004.
[Panessa 2004] Cristian Francesco Panessa, Progetto e sviluppo di un sistema per
l’iterfacciamento tra Computer Palmari e Robot Lego, Università degli studi di Modena
e Reggio Emilia, Facoltà di Ingegneria Informatica, 2004.
[Papert 1999] Seymour Papert, Logo Philosophy and Implementation, Logo Computer
Systems Inc., Canada, 1999.
[Papert 1993] Seymour Papert, The Children's Machine, Rethinking School in the Age
of the Computer, New York, Basic Books, 1993.
[Papert 1980] Seymour Papert, Mindstorms, Basic Books Inc, New York, 1980.
[Aho 1986] Aho, Sethi, Ullman, Addison Wesley, Compilers. Principles, Techniques,
and Tools, 1986.
[Damiano 1999] E.Damiano, Guida alla didattica per concetti, Juvenilia, Bergamo,
1999.
SITI WEB
[1]. http://it.wikipedia.org
[2]. http://margi.bmm.it/
[3]. http://jflex.de/index.html
[4]. http://robotica.irrepiemonte.it/
90
[5]. http://www.adrirobot.it/lego/rcx/rcx.htm
[6]. http://www.itd.cnr.it/TDMagazine/PDF27/Vetrina27.pdf
[7]. http://www.marcocioffi.com
[8]. http://digilander.libero.it/lego.mindstorms/faq.htm
[9]. http://www.areato.org/noquadri/ausiliDinamici.htm
[10]. http://www.altrascuola.it/article.php?sid=571
[11]. http://people.cis.ksu.edu/~millermj/NQCTutor/NQCtutorial.html
[12]. http://www.prato.linux.it/~lmasetti/seriamente/ProLOGO/relazione.htm
[13]. http://www.di.unipi.it/~lagana/log1.html
[14]. http://www.galileo.it/ludonord2/corsi/logo.html
[15]. http://www.di.uniba.it/~lops/linguaggi/Analizzatore_lessicale_stampati.pdf
[16]. http://www.ce.unipr.it/people/monica/Laboratorio/Trasparenze/lezione3.pdf
[17]. http://www.pluto.it/files/journal/pj9705/hp48g.html
[18]. http://www.cs.unibo.it/~laneve/html/linguaggi/lp4.1.pdf
[19]. http://java.sun.com/docs/books/tutorial/
[20]. http://www.mokabyte.it/
91