Linguaggi e modelli computazionali LS Manni Tiziano 0000279932 SimMouse Linguaggi e modelli computazionali LS Manni Tiziano 0000279932
OBIETTIVO Realizzare un’applicazione che permetta di descrivere movimenti ed azioni del mouse (click) e della tastiera (pressione tasti) in modo da poterli automatizzare. Introdurre inoltre: costrutti per il controllo del flusso di esecuzione(repeat, for, if else) concetti di variabile, funzione e scope di visibilità.
Possibilità di collocare frammenti di codice in opportune procedure OBIETTIVO Vediamo quindi un esempio del linguaggio che si vuole ottenere: var i; fun Esempio fun Run { write “simulazione tasti” + i; for (i=0; i<10; i=i+1) doubleClick 50*i+10 300; Esempio; clickDx 10 10; clickSx 40 50; } Possibilità di collocare frammenti di codice in opportune procedure
LA GRAMMATICA VN = <PROG, BLOCK, STATEMENT, OPERATION, ASSIGN, DICVAR, WAIT, MOUSE, KEYBOARD, FUNCTION, EXP, TERM, FACTOR, COND, CONTROL, FOR, REPEAT, IF>. VT = <+, -, *, /, <, >, <=, >=, ==, !=, =, id, idfun, num, string, for, repeat, if, else, doubleClick, clickDx, clickSx, clickSxUp, clickSxDw>. S = <PROG> Definiamo le regole di produzione del parser. Le funzioni iniziano per lettera maiuscola Le variabili iniziano per lettera minuscola
LA GRAMMATICA <PROG> ::= { fun idfun <BLOCK> | <DICVAR> ';' } fun Run <BLOCK> { fun idfun <BLOCK> | <DICVAR> ';' }; <BLOCK> ::= '{' { <STATEMENT> } '}'; <STATEMENT> ::= <OPERATION> ';' | <CONTROL> ; < OPERATION> ::= <ASSIGN> | <DICVAR> | <WAIT> | <MOUSE> | <KEYBOARD> | <FUNCTION> ; <CONTROL>::= for <FOR> | repeat <REPEAT> | if <IF>; Self-Embedding Funzione di partenza.
LA GRAMMATICA <FUNCTION> ::= <idfun>; <DICVAR> ::= var id [ assign <EXP> ]; <ASSIGN>::= id assign <EXP>; Variabili LOOSELY TYPED L’assegnamento non è interpretato come operatore. Può cambiare il tipo della variabile.
LA GRAMMATICA <EXP> ::= <TERM> { + <TERM> | - <TERM>}; <TERM> ::= <FACTOR> { * <FACTOR> | / <FACTOR>}; <FACTOR> ::= number | string | id | '(' <EXP> ')'; <COND>::= <EXP> ( < | > | <= | >= | == | !=) <EXP>; Possibilità di definire espressioni anche fra tipo diversi. Operazione meno prioritaria delle altre operazioni matematiche
ISTRUZIONI COMANDO <MOUSE> ::= (doubleClick | clickSx | clickDx | clickSxUp | clickSxDw) <EXP> ' ' <EXP>; <KEYBOARD> ::= write <EXP>; <WAIT> ::= wait <EXP>; Coordinate di azione espresse in pixel. Stringa da simulare Attesa (espressa in secondi)
ISTRUZIONI CONTROL-FLOW <FOR> ::= '(' <ASSIGN> ';' <COND> ';' <ASSIGN> ')' <BLOCK>; <REPEAT> ::= '(' <COND> ')' <BLOCK>; <IF> ::= '(' <COND> ')' <BLOCK> [ else <BLOCK> ]; Istruzione di inizializzazione Blocco di istruzioni Istruzione di modifica Condizione di controllo Blocco da eseguire con condizione vera … nel caso sia falsa
GRAMMATICA: PROPRIETA’ La grammatica ottenuta è di tipo 2 … … e risulta LL(1) in quanto per qualunque simbolo non terminale della grammatica gli starter symbol sono disgiunti. → il parser sa sempre quale produzione usare.
ANALISI LESSICALE Per l’analisi lessicale del programma scritto dall’utente sono stati realizzati due componenti: Lo scanner: scorre la stringa (che rappresenta il programma scritto dall’utente) e lo separa in sotto-stringhe in base ad una lista di delimitatori. Il lexer che riceve dallo scanner le varie sotto-stringhe, le esamina assegnando una corrispondente categoria lessicale: costruisce quindi una serie di oggetti “Token” passati poi all’analizzatore sintattico.
ANALISI SINTATTICA Essendo la grammatica LL(1), risulta possibile utilizzare l’analisi ricorsiva discendente per analizzare le frasi passate in input: Si introducono tante funzioni quanti i simboli non terminali della grammatica. Si fa sì che ogni funzione riconosca il sotto-linguaggio generato da ciascun simbolo non terminale. Risulta quindi semplice effettuare chiamate ricorsive di funzioni.
ANALISI SINTATTICA L’analisi sintattica viene svolta dal componente Parser: esso ottiene l’istanza della classe Lexer e la utilizza per ottenere i vari Token di cui la frase da analizzare è costituita. Ricevuto in ingresso il primo Token di una frase, il parser(essendo la grammatica LL(1)) è in grado di richiamare la funzione corrispondente che analizzerà la correttezza dei Token successivi. In caso di errore il Parser provvede a lanciare una nuova istanza della classe ParserException.
ANALISI SINTATTICA
ANALISI SEMANTICA I visitor creati sono due, ed entrambi implementano ovviamente la comune classe astratta “Visitor”: ExecuteVisitor: ha il compito di interpretare il programma scritto da utente e simulare le azioni descritte dal programma stesso. TreeViewVisitor: ha il compito di disegnare graficamente l’albero restituito dal parser.
ANALISI SEMANTICA Il visitor ExecuteVisitor provvede inoltre a lanciare un’opportuna eccezione “RunTimeException” nel caso in cui trovi frasi senza senso nel programma: Riferimenti a variabili non esistenti Tipi non compatibili. Utilizzo di variabili non inizializzate. Operatori non compatibili con gli argomenti passati. Richiamo di funzioni non definite. Per individuare errori a RunTime è stata introdotta nell’ExecuteVisitor una modalità di simulazione (valutazione delle variabili, espressioni e funzioni).
L’APPLICAZIONE L’applicazione è stata suddivisa in due thread: Un flusso si occupa dell’interfaccia grafica, L’altro flusso esegue l’ExecuteVisitor. → l’utente ha la possibilità di interrompere l’esecuzione in presenza ad esempio di errori (esempio: loop infiniti, ecc). Inoltre è stato implementato un sistema di “generazione di codice” per aiutare la programmazione: Recupero della posizione corrente del mouse e di eventuali tasti premuti, Recupero del codice corrispondente ad alcuni tasti speciali della tastiera (esempio: tab, enter, ctrl, alt, ecc).
L’APPLICAZIONE Scanner Lexer Parser Programma TreeViewVisitor ExecuteVisitor
SVILUPPI FUTURI Introduzione di comandi per simulare la pressione di combinazioni di tasti della tastiera (esempio ctrl + … , ctrl+alt+… , ecc. ). Esecuzione di funzioni con passaggio di dati. Introduzione di comandi per interagire con l’utente durante l’esecuzione.