Corso di Laurea Magistrale in Ingegneria Informatica A.A Linguaggi Formali e Compilatori LEX, FLEX, JLEX. Giacomo PISCITELLI

Documenti analoghi
Analizzatore lessicale o scanner. Lo scanner rappresenta un'interfaccia fra il programma sorgente e l'analizzatore sintattico o parser.

Primi passi con JFlex

Generatori di analizzatori lessicali e sintattici

Analizzatori Lessicali con JLex. Giuseppe Morelli

Linguaggio C: introduzione

1

Unità Didattica 1 Linguaggio C. Fondamenti. Struttura di un programma.

Input/output da file I/O ANSI e I/O UNIX FLUSSI E FILE FLUSSI FLUSSI di TESTO FLUSSI BINARI FILE

POLITECNICO DI TORINO. Laboratorio di Compilatori Corso di Linguaggi e Traduttori. Esercitazione 1. a.a 2010 / Linguaggi?

Unità F1. Obiettivi. Il linguaggio C. Il linguaggio C++ Linguaggio C. Pseudolinguaggio. Primi programmi

Funzioni e. Alessandra Giordani Mercoledì 16 maggio 2012

STORIA E CARATTERISTICHE

Primi passi col linguaggio C

Analisi lessicale (scanner)

Analisi lessicale (scanner)

Elementi lessicali. Lezione 4. La parole chiave. Elementi lessicali. Elementi lessicali e espressioni logiche. Linguaggi di Programmazione I

Input/Output di numeri

Fasi di un Compilatore

Laboratorio di Algoritmi e Strutture Dati

7 - Programmazione procedurale: Dichiarazione e chiamata di metodi ausiliari

Linguaggio C. Generalità sulle Funzioni. Variabili locali e globali. Passaggio di parametri per valore.

Dispensa YACC: generalità

I puntatori. Un puntatore è una variabile che contiene l indirizzo di un altra variabile. puntatore

Le direttive del Preprocessore

Linguaggio C - le strutture di controllo: sequenza, selezione, iterazione

Puntatori. Fondamenti di Programmazione

Il linguaggio C - Introduzione

Formattazione avanzata. I/O Avanzato e File. Formattazione dell output. Formattazione avanzata. Forma completa degli specificatori

Corso di Matematica per la Chimica. Dott.ssa Maria Carmela De Bonis a.a

Strategie di programmazione

Linguaggio C Struttura dei programmi

Alfabeto ed elementi lessicali del linguaggio C

Introduzione a. Funzioni di Ingresso e Uscita. Compilazione

perror: individuare l errore quando una system call restituisce -1

Stringhe e allocazione dinamica della memoria

Tipi di dati scalari (casting e puntatori) Alessandra Giordani Lunedì 10 maggio 2010

Università degli Studi di Cassino Corso di Fondamenti di Informatica Tipi strutturati: Stringhe. Anno Accademico 2010/2011 Francesco Tortorella

Funzioni, Stack e Visibilità delle Variabili in C

Programmazione Orientata agli Oggetti. Emilio Di Giacomo e Walter Didimo

Capitolo 5 - Funzioni

Gestione dei file. Stefano Ferrari. Università degli Studi di Milano Programmazione. anno accademico

Cenni sul preprocessore e il suo utilizzo

Linguaggio C - sezione dichiarativa: costanti e variabili

Linguistica Computazionale

Tipi di dati strutturati e Linguaggio C. Record o strutture Il costruttore struct in C

ESECUZIONE DI PROGRAMMI C SU MACCHINE REALI. Docente: Giorgio Giacinto AA 2008/2009. formalizzazione degli algoritmi in linguaggio C

Linguaggio C. Appunti per il corso di Laboratorio di Algoritmi e Strutture Dati. Stefano Aguzzoli

Programma del corso. Elementi di Programmazione. Introduzione agli algoritmi. Rappresentazione delle Informazioni. Architettura del calcolatore

Debug di un programma

Linguaggi formali e compilazione

Linguaggi di Programmazione

Il linguaggio C. Notate che...

Corso sul linguaggio C Modulo Tipi di dato

IL PRIMO PROGRAMMA IN C

Verificare se una grammatica e LL(1) e costruirne la tabella di parsing. Verificare se una grammatica e LR(0) e costruirne la tabele ACTION e GOTO

Introduzione ai puntatori in C Definizione

Programmazione. Cognome... Nome... Matricola... Prova scritta del 11 luglio 2014

prova.c #include <stdio.h> char funzione(char); codice oggetto del main()

6 - Blocchi e cicli. Programmazione e analisi di dati Modulo A: Programmazione in Java. Paolo Milazzo

Esempio. Le istruzioni corrispondono a quelle di sopra, ma sono scritte in modo simbolico. E indipendente dalla machina

Breve Manuale di Riferimento sulla Sintassi Linguaggi C++ e FORTRAN

Elaborazione di File di Dati. Uso di semplici comandi Espressioni regolari AWK

Rappresentazione con i diagrammi di flusso (Flow - chart)

LA CODIFICA DELLE INFORMAZIONI

Corso di Fondamenti di Informatica Il sistema dei tipi in C++

Il Modello di un Compilatore. La costruzione di un compilatore per un particolare linguaggio di programmazione e' abbastanza complessa.

Scope delle variabili e passaggio parametri. Danilo Ardagna Politecnico di Milano

Linguaggio C++ Linguaggi di terza generazione

ERRATA CORRIGE. void SvuotaBuffer(void); void SvuotaBuffer(void) { if(getchar()!=10) {svuotabuffer();} }

Caratteri e stringhe

VBA è un linguaggio di scripting derivato da Visual Basic, da cui prende il nome. Come ogni linguaggio ha le sue regole.

Informatica! Appunti dal laboratorio 1!

LA SINTASSI DEI LINGUAGGI DI PROGRAMMAZIONE. Ivan Lanese

Argomenti Avanzati.! I puntatori! Stack! Visibilità delle Variabili

Variabili e Istruzioni

Corso di Fondamenti di Informatica

Informatica ALGORITMI E LINGUAGGI DI PROGRAMMAZIONE. Francesco Tura. F. Tura

Lezione 21 e 22. Valentina Ciriani ( ) Laboratorio di programmazione. Laboratorio di programmazione. Lezione 21 e 22

Modularizzazione del software

Espressioni regolari in Javascript (RegExp)

Primo passo: il preprocessor. Il preprocessore. Esempi di direttive al preprocessore: #include. Esempi di direttive al preprocessore: #define

La programmazione in linguaggio C

id+id*id (id+id)*id / - ( + ) * +id +*** (+)id Linguaggi formali Stringhe Linguaggi Grammatiche

Espressione di chiamata di funzione

Funzioni di I/O per numeri. Input e output di valori numerici. Input formattato scanf. Stream preesistenti

Corso di Calcolatori Elettronici Un computer è un dispositivo in grado di eseguire dei calcoli e di prendere delle decisioni logiche.

Lettura da tastiera e scrittura su monitor

Problema: dati i voti di tutti gli studenti di una classe determinare il voto medio della classe.

Introduzione al Linguaggio C Corso di Informatica Laurea in Fisica

Introduzione al C. Introduzione. Linguaggio ad alto livello. Struttura di un programma C

Scrittura formattata - printf

Informatica 1 Tipi e dichiarazioni in C++ C++ - Tipi e dichiarazioni 1

Compilatori-Esempio. Compilatori-Esempio. Analisi dell input. Analisi lessicale. Sintesi ell output

Esercitazione 4. Comandi iterativi for, while, do-while

Linguaggio C: le funzioni. Visibilità variabili e passaggio parametri

Il linguaggio C Il linguaggio C. Caratteristiche del C. Caratteristiche del C. Linguaggi di Programmazione I. Ferdinando Cicalese

Lezione 9: Puntatori a funzioni. Tipi enumerativi e orientati ai bit

Istituto Tecnico Industriale M. M. Milano Polistena. Classe III D a.s. 2015/2016 C++ Guida Base

Unità Didattica 5 Linguaggio C. Stringhe. Accesso a file ASCII. Strutture.

Algoritmi e basi del C Struttura di un programma

Transcript:

Corso di Laurea Magistrale in Ingegneria Informatica A.A. 2011-2012 Linguaggi Formali e Compilatori LEX, FLEX, JLEX Giacomo PISCITELLI

LEX/FLEX/JLEX Poiché la trasformazione di espressioni regolari in automi a stati finiti deterministici e la implementazione di questi ultimi sono processi meccanici (e noiosi), spesso si utilizza un generatore automatico di analizzatori lessicali. Per la generazione di analizzatori lessicali si utilizza spesso il tool LEX, che è un noto generatore di scanner di Unix, progettato specificamente per essere utilizzato insieme allo YACC. Infatti molte assunzioni del codice generato da Lex si sposano bene con quelle dello Yacc. Per esempio l'analizzatore lessicale prodotto da Lex è una funzione C chiamata yylex(), che è esattamente quella che si aspetta Yacc per l'analizzatore lessicale. Lex fu sviluppato da M. E. Lesk and E. Schmidt degli AT&T Bell Laboratories e costruisce uno scanner in C da un insieme di espressioni regolari che definiscono i token. L input è un file contenente token definiti usando delle espressioni regolari. Lex produce un intero scanner module che può essere compilato e linkeditato con altri moduli del compilatore. Politecnico di Bari G. Piscitelli pag. 2 di 35

LEX/FLEX/JLEX FLEX (Fast LEXical analyzer generator), originariamente scritto in C da Vern Paxson nel 1987, è un free software alternativo a Lex e rappresenta una versione più recente e più veloce di Lex. Esso è frequentemente usato con Bison, un parser generator alternativo a sua volta a Yacc. Lex è distribuito con il sistema operativo Unix mentre Flex è un prodotto della Free Software Foundation, Inc. JLEX è una versione Java di Lex. Si genera uno scanner Java (le espressioni regolari sono molto simili a quelle utilizzati da Lex e Flex). Lex, Flex e JLex sono in gran parte non procedurali. Non c'è bisogno di dire come gli strumenti devono eseguire la scansione. Tutto ciò che serve è dire ciò che si vuole scandire, dando la definizione dei token validi. Questo approccio semplifica notevolmente la costruzione di uno scanner, dal momento che la maggior parte dei dettagli di scansione (I/O, buffering, ecc.), sono gestiti automaticamente. Politecnico di Bari G. Piscitelli pag. 3 di 35

FLEX: descrizione e funzionamento Flex è, quindi, un generatore che accetta in ingresso (in un file con suffisso.l, f.e. esempio.l) un insieme di espressioni regolari (rules) e di azioni (actions) associate a ciascuna espressione (sotto forma di codice C), producendo in uscita una routine di riconoscimento lessicale yylex() (contenuta nel file lex.yy.c) in grado di identificare e restituire le singole "parole" che il linguaggio ammette. Il file lex.yy.c, privo di main() (che viene definito implicitamente, se lo scanner funziona da solo, grazie all'opzione di compilazione lfl), contiene la routine di scanning yylex() assieme ad altre routine ausiliari e macro. Il file prodotto viene compilato e fuso con la libreria lfl per generare un eseguibile. lex esempio.l cc lex.yy.c -o esempio -lfl Quando il file eseguibile (esempio) viene mandato in esecuzione, esso analizza il/i file in input per individuare le occorrenze di espressioni regolari conformi a quelle definite. Se ne riconosce una, esegue il codice C associato. Politecnico di Bari G. Piscitelli pag. 4 di 35

I link utili per FLEX http://flex.sourceforge.net/ flex home page http://www.gnu.org/software/flex/manual/html_node/flex_toc.html flex manual http://www.quut.com/c/ansi-c-grammar-l-1998.html ANSI C grammar (LEX specification) Politecnico di Bari G. Piscitelli pag. 5 di 35

FLEX: descrizione e funzionamento Politecnico di Bari G. Piscitelli pag. 6 di 35

FLEX: La struttura del programma generato Flex produce un programma C, privo di main() il cui punto di accesso è dato dalla funzione int yylex(). Tale funzione legge dal file yyin e ricopia sul file yyout il testo non riconosciuto. Se non specificato diversamente nelle azioni (tramite l istruzione return), tale funzione termina solo quando l intero file di ingresso è stato analizzato. Al termine di ogni azione l automa si ricolloca sullo stato iniziale pronto a riconoscere nuovi simboli. Per default, i file yyin e yyout sono inizializzati rispettivamente a stdin e stdout. Il programmatore può alterare questa situazione re-inizializzando tali variabili globali. Politecnico di Bari G. Piscitelli pag. 7 di 35

Espressioni regolari in FLEX 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 questo non è un problema per le grammatiche. 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. Politecnico di Bari G. Piscitelli pag. 8 di 35

Espressioni regolari in FLEX Le espressioni regolari descrivono sequenze di caratteri ASCII ed utilizzano un certo numero di operatori: \ [] ^ -?. * + () $ / {} % <> Lettere e numeri del testo di ingresso sono descritti mediante se stessi: l espressione regolare val1 rappresenta la sequenza v a l 1 nel testo di ingresso I caratteri non alfabetici vengono rappresentati in Lex racchiudendoli tra doppi apici, per evitare ambiguità con gli operatori: l espressione xyz ++ rappresenta la sequenza x y z + + nel testo di ingresso I caratteri non alfabetici possono essere anche descritti facendoli precedere dal carattere \ l espressione xyz\+\+ rappresenta la sequenza x y z + + nel testo di ingresso. Politecnico di Bari G. Piscitelli pag. 9 di 35

Espressioni regolari in FLEX Le classi di caratteri vengono descritte mediante gli operatori [] l espressione [0123456789] rappresenta una cifra nel testo di ingresso. Nel descrivere classi di caratteri, il segno - indica una gamma di caratteri: l espressione [0-9] rappresenta una cifra nel testo di ingresso Per includere il carattere - in una classe di caratteri, questo deve essere specificato come primo o ultimo della serie: l espressione [-+0-9] rappresenta una cifra o un segno nel testo d ingresso. Nelle descrizioni di classi di caratteri, il segno ^ posto all inizio indica una gamma di caratteri da escludere: l espressione [^0-9] rappresenta un qualunque carattere che non sia una cifra nel testo di ingresso L insieme di tutti i caratteri eccetto il fine riga (new line) viene descritto mediante il simbolo. Il carattere di fine riga viene descritto dal simbolo \n Il carattere di tabulazione viene descritto dal simbolo \t Politecnico di Bari G. Piscitelli pag. 10 di 35

Espressioni regolari in FLEX L operatore? indica che l espressione precedente è opzionale: ab?c indica sia la sequenza ac che abc L operatore * indica che l espressione precedente può essere ripetuta 0 o più volte: ab*c indica tutte le sequenze che iniziano per a, terminano per c e hanno all interno un numero qualsiasi di b L operatore + indica che l espressione precedente può essere ripetuta 1 o più volte: ab+c indica tutte le sequenze che iniziano per a, terminano per c e hanno all interno almeno una b. L operatore indica un alternativa tra due espressioni: ab cd indica o la sequenza ab o la sequenza cd Le parentesi tonde ( ) consentono di esprimere la priorità tra operatori: (ab cd+)?ef indica sequenze tipo ef, abef, cdddef. Politecnico di Bari G. Piscitelli pag. 11 di 35

FLEX: principali espressioni regolari supportate x il carattere 'x'. ogni carattere eccetto '\n' [xyz] una classe di caratteri; in questo caso, 'x', 'y' o 'z' [a-z] una classe con un range; ogni carattere compreso tra 'a' e 'z' [^A-Z] una classe negata: ogni carattere NON nella classe r* zero o più r, dove r è un'altra espressione regolare r+ una o più r r? zero o una r r{2,5} tra due a cinque r r{2,} due o più r r{4} esattamente 4 r {nome} l'espansione della definizione di nome (r) rs r s r/s ^r r, parentesizzata per raggruppare concatenazione: r seguita da s alternativa: r oppure s restrizione: r ma solo se seguita da s r ma solo a inizio linea r$ r ma solo a fine linea Politecnico di Bari G. Piscitelli pag. 12 di 35

Formato dell input file di FLEX Un file in ingresso a LEX/FLEX è composto di tre sezioni distinte, separate dal simbolo %%. Sezione 1 % #include constant definition scanner macro % basic definitions Sezione 2 %% Token definitions and actions Sezione 3 %% Support procedures C user code Politecnico di Bari G. Piscitelli pag. 13 di 35

Formato dell input file di FLEX La Sezione 1 (che può anche essere vuota) contiene: - racchiuse tra i caratteri % e %, le #include di libreria, le definizioni di costanti e/o macro personalizzate del programma C che si vuole realizzare; infatti, questa parte di testo verrà letteralmente copiata nel programma C generato; in questa parte, quando lo scanner viene usato in combinazione con il parser, va inserita la #include y.tab.h, che è il file generato dal parser e che contiene la definizione dei token multi-caratteri ai fini dell analisi sintattica; - le definizioni di base usate nella seconda sezione per descrivere una espressione regolare. La Sezione 2 contiene la definizione dei pattern con le relative azioni da intraprendere, sotto forma di coppie pattern azione Le azioni devono iniziare sulla stessa riga in cui termina l espressione regolare e ne sono separate tramite spazi o tabulazioni. La Sezione 3 (che può anche essere vuota) contiene le procedure di supporto di cui il programmatore intende servirsi per associarle alle azioni indicate nella seconda sezione: se è vuota, il separatore %% viene omesso. Politecnico di Bari G. Piscitelli pag. 14 di 35

Formato dell input file di FLEX Ogni riga della prima sezione il cui primo carattere non sia di spaziatura è una definizione: numero [+-]?[0-9]+ L espressione così definita può essere utilizzata nella seconda sezione racchiudendone il nome tra parentesi graffe: {numero} printf( trovato numero\n ); Parti di codice possono essere inserite sia nella prima sezione (inserendole, come si è detto, tra %{ e %}) che nella seconda (inserendolo tra { } immediatamente dopo ogni espressione regolare che si vuole riconoscere), e vengono copiate integralmente nel file di output. Se, in corrispondenza di un pattern, non viene indicate alcuna azione, quando un tale tipo di token viene riconosciuto nel testo scandito, esso viene scartato. Le righe presenti nella sezione delle procedure di supporto (la terza sezione) del programma sorgente sono ricopiate nel file lex.yy.c generato da Lex. Politecnico di Bari G. Piscitelli pag. 15 di 35

Formato dell input file di FLEX Esempio 1 di contenuto del file di input %{ #include <stdio.h> %} %% [0-9]+ printf("numero INTERO\n"); [a-za-z][a-za-z0-9]* printf("identificatore\n"); %% Questo file descrive 2 pattern, cioè 2 particolari tipi di token: [0-9]+ a cui è associata l azione di stampa NUMERO INTERO e [a-za-z][a-za-z0-9]* a cui è associata la stampa IDENTIFICATORE. Si noti la presenza, nella sezione 1, della direttiva #include <stdio.h> necessaria per consentire l utilizzo dell istruzione printf. Questo semplice esempio ipotizza l utilizzo di LEX/FLEX indipendente da YACC/BISON. Politecnico di Bari G. Piscitelli pag. 16 di 35

Formato dell input file di FLEX Esempio 2 di contenuto del file di input int num_lines = 0, num_chars = 0; %% \n num_lines=num_lines+1; num_chars=num_chars+1;. num_chars=num_chars+1; %% main() { yylex(); printf( "# of lines = %d, # of chars = %d\n", num_lines, num_chars ); } Questo scanner conta il numero di caratteri e il numero di linee presenti nel file di input e produce nel file di output il valore dei contatori indicati. Si noti che la prima linea dichiara 2 variabili globali, accessibili sia alla funzione yylex() che al main()dichiarato dopo il secondo %%. Politecnico di Bari G. Piscitelli pag. 17 di 35

Esistono due tipi di ambiguità lessicali: Ambiguità lessicali 1. la parte iniziale di una sequenza di caratteri riconosciuta da un espressione regolare è riconosciuta anche da una seconda espressione regolare; 2. la stessa sequenza di caratteri è riconosciuta da due espressioni regolari distinte. Nel primo caso verrà eseguita l azione associata all espressione regolare che ha riconosciuto la sequenza più lunga. Nel secondo caso sarà eseguita l azione associata all espressione regolare dichiarata per prima nel file sorgente di LEX/FLEX. ESEMPIO Dato il file %% for {return FOR_CMD;} format {return FORMAT_CMD;} [a-z]+ {return GENERIC_ID;} e la stringa di ingresso format, la procedura yylex ritorna il valore FORMAT_CMD, preferendo la seconda regola alla prima - perché descrive una sequenza più lunga, e la seconda regola alla terza -perché definita prima nel file sorgente. Politecnico di Bari G. Piscitelli pag. 18 di 35

Risoluzione delle ambiguità lessicali Date le regole di risoluzione dell ambiguità, è necessario definire prima le regole per le parole chiave e poi quelle per gli identificatori. Il principio di preferenza per le corrispondenze più lunghe può essere pericoloso:.* {return QUOTED_STRING;} cerca di riconoscere il secondo apice il più lontano possibile: cosi, dato il seguente ingresso first quoted string here, second here riconoscerà 36 caratteri invece di 7 Una regola migliore è la seguente: [^ \n]+ {return QUOTED_STRING;} Politecnico di Bari G. Piscitelli pag. 19 di 35

Azioni associate alle espressioni regolari in LEX Ad ogni espressione regolare è associata in LEX un azione che viene eseguita all atto del riconoscimento. Le azioni sono espresse sotto forma di codice C: se tale codice comprende più di una istruzione o occupa più di una linea deve essere racchiuso tra parentesi graffe. L azione più semplice consiste nell ignorare il testo riconosciuto: si esprime un azione nulla con il carattere ;. Il testo riconosciuto viene accumulato nella variabile yytext, definita come puntatore a caratteri. Operando su tale variabile, si possono definire azioni più complesse. Il numero di caratteri riconosciuti viene memorizzato nella variabile yyleng, definita come intero. Esiste un azione di default che viene eseguita in corrispondenza del testo non descritto da nessuna espressione regolare: il testo non riconosciuto viene ricopiato in uscita, carattere per carattere. Politecnico di Bari G. Piscitelli pag. 20 di 35

Esempio di input a LEX Politecnico di Bari G. Piscitelli pag. 21 di 35

Esempio di input a LEX Politecnico di Bari G. Piscitelli pag. 22 di 35

Esempio di input a LEX Politecnico di Bari G. Piscitelli pag. 23 di 35

FLEX: uso combinato con BISON La struttura del programma generato da FLEX Come detto, eseguendo LEX/FLEX si ottiene come risultato il file lex.yy.c, un programma C, privo di main(), che contiene la routine di scanning yylex() assieme ad altre routine ausiliari e macro. Per default, yylex() è dichiarata come: int yylex() {... various definitions and the actions in here... } Quando s intende combinare l analisi lessicale con quella sintattica, il file lex.yy.c (generato dall esecuzione dello scanner), viene normalmente incluso (con una #include) nel sorgente generato da YACC. Infatti molte dichiarazioni, come i token e le strutture dati per comunicare con il parser, vengono dichiarate nel sorgente generato da YACC, y.tab.c. La funzione yylex() viene richiamata ripetutamente dalla funzione principale del parser, yyparse(). Politecnico di Bari G. Piscitelli pag. 24 di 35

Esempio: compilatore BASIC FLEX: uso combinato con BISON bas.l -> regole lessicali bas.y -> regole sintattiche con definizione tokens CC -> comandi per creare il compilatore bas.exe -> compilatore y.tab.h -> definizioni dei tokens per Lex yacc d bas.y # create y.tab.h, y.tab.c lex bas.l # create lex.yy.c cc lex.yy.c y.tab.c obas.exe # compile/link Politecnico di Bari G. Piscitelli pag. 25 di 35

FLEX: uso combinato con BISON Politecnico di Bari G. Piscitelli pag. 26 di 35

Scanner per un linguaggio-giocattolo Pascal-like: sez. 1 La prima sezione compatibile con YACC/BISON: %{ #include "y.tab.h" /* The tokens */ %} DIGIT [0-9] ID [a-z][a-z0-9]* %% definitions, #includes and scanner macros %% C user code Politecnico di Bari G. Piscitelli pag. 27 di 35

Scanner per un linguaggio-giocattolo Pascal-like: sez. 2 La seconda parte del file FLEX fornisce le espressioni regolari per ogni token che deve essere riconosciuto e, in corrispondenza, l azione da compiere, sotto forma di codice C. Le parole chiave o riservate del linguaggio sono stringhe di caratteri minuscoli. Blank, tab e newline sono ignorati. Tutti gli altri simboli costituiti da un solo carattere sono passati al parser così come sono; lo scanner, infatti, li piazza as they are nella stringa yytext. Politecnico di Bari G. Piscitelli pag. 28 di 35

Scanner per un linguaggio-giocattolo Pascal-like: sez. 2 /* scanner for a toy Pascal-like language */ %{ /* need this for the call to atof() below */ #include <math.h> #include "y.tab.h" /* The tokens */ %} DIGIT [0-9] ID [a-z][a-z0-9]* %% {DIGIT}+ { printf( "An integer: %s (%d)\n", yytext, atoi( yytext ) ); } {DIGIT}+"."{DIGIT}* { printf( "A float: %s (%g)\n", yytext, atof( yytext ) ); } if then begin end procedure function { printf( "A keyword: %s\n", yytext ); } Politecnico di Bari G. Piscitelli pag. 29 di 35

Scanner per un linguaggio-giocattolo Pascal-like: sez. 2 {ID} printf( "An identifier: %s\n", yytext ); "+" "-" "*" "/" printf( "An operator: %s\n", yytext ); "{"[^}\n]*"}" /* eat up one-line comments */ [ \t\n]+ /* eat up whitespace */. printf( "Unrecognized character: %s\n", yytext ); %% main( argc, argv ) int argc; char **argv; { ++argv, --argc; /* skip over program name */ if ( argc > 0 ) yyin = fopen( argv[0], "r" ); else yyin = stdin; yylex(); } Politecnico di Bari G. Piscitelli pag. 30 di 35

FLEX: l output Quando viene eseguito lo scanner generato, esso analizza il suo input individuando le stringhe di caratteri che rispettano i pattern specificati. Come già osservato, se viene trovato più di un possibile match, viene assunto quello che considera il maggior numero di caratteri. Nel caso di 2 match della stessa lunghezza, viene scelto quello che corrisponde alla regola che appare per prima nell input file di FLEX. Una volta determinato il match, il corrispondente testo (che rappresenta un token) viene reso disponibile globalmente attraverso il puntatore a carattere yytext, e la sua lunghezza viene globalmente riportata sotto forma dell intero yyleng. Viene quindi eseguita l azione (action) corrispondente al pattern individuate, e si procede alla scansione del successivo testo. Politecnico di Bari G. Piscitelli pag. 31 di 35

FLEX: l output Una volta che un token viene riconosciuto, abbiamo varie possibilità: possiamo ignorarlo (come facciamo per gli spazi bianchi) e passare al token successivo; oppure possiamo ritornare il codice del token riconosciuto. Quando viene ritornato un token, la funzione yylex() termina ma sarà richiamata dal parser quando avrà bisogno di un altro token. Notiamo che può essere necessario fare qualche azione supplementare oltre a ritornare un token o ignorarlo. Possiamo notare che quando incontriamo un newline, incrementiamo il contatore delle linee in input. Molto più importante è il fatto che di certi token occorre conoscere qualcosa di più oltre al loro tipo. Per esempio, di una variabile non basta sapere che è una variabile: occorre sapere quale è. Lex mantiene in un buffer il testo letto dall'input e riconosciuto; tale buffer è accessibile all'utente tramite le variabili char *yytext e int yyleng. Politecnico di Bari G. Piscitelli pag. 32 di 35

FLEX: l output FLEX chiama la function yywrap() al termine del suo input e fornisce la variabile globale char *yytext, che contiene i caratteri del token corrente e la variabile globale int yyleng, che contiene la lunghezza di tale stringa. Se la function yywrap()ritorna il valore 0 (false), significa che la funzione prevede che si debba procedere e imposta yyin a puntare ad un altro input file, facendo sì che lo scanning proceda da tale nuovo file di input. Se la function yywrap()ritorna invece un valore diverso da 0 (true), lo scanner termina e restituisce il valore 0 alla funzione chiamante. Politecnico di Bari G. Piscitelli pag. 33 di 35

Esercizi esemplificativi Scrivere un programma LEX che dato in ingresso un programma C, ne produca in uscita uno equivalente ma privo dei commenti. Si modifichi il programma dell esercizio precedente in modo che riconosca le direttive #include e, quando le incontra, segnali un errore e termini l analisi. Politecnico di Bari G. Piscitelli pag. 34 di 35

JLEX: la versione JAVA di LEX Per produrre lo scanner di applicazioni Java, si può far uso del generatore d analizzatori lessicali conosciuto come JLex. Questo software, scritto interamente in java, produce in uscita delle classi java che implementano i metodi per effettuare l analisi lessicale di una stringa in ingresso. La classe principale che è prodotta è Yylex, la quale contiene il metodo yylex() che preleva e analizza il successivo token in arrivo. Un altro metodo contenuto nella classe è yytext(), esso ritorna il testo riconosciuto da yylex(). Il JLex per funzionare, ha bisogno in ingresso di un file di specifica, contenente tutti i dettagli relativi all analisi lessicale che si vuole realizzare. Politecnico di Bari G. Piscitelli pag. 35 di 35