Analizzatore lessicale Legge la stringa in input e la trasforma in un flusso di token da sottoporre all analizzatore sintattico. Le frasi di un linguaggio sono stringhe di token (simboli atomici). Richieste per l analizzatore lessicale: 1. Rimuovere spazi, tabulazioni, a capo,... 2. Raccogliere i digit in interi, in modo che nella parsificazione i numeri siano trattati come elementi atomici: 3 + 25 2 <num, 3> <+, > < num, 25> <-, > < num, 2>
3. Riconoscere parole chiave e identificatori: count = count + inc id = id + id Per l analisi sintattica non è importante conoscere i lessemi associati ad ogni identificatore, ma lo è per la traduzione. Quando in input viene identificato un lessema, esso viene memorizzato nella symbol table e il puntatore alla entry nella symbol table diventa un attributo del token id. Le parole chiave di solito soddisfano le regole per la costruzione degli identificatori, quindi serve un meccanismo per decidere quando un lessema forma una parola chiave o un identificatore. È più facile se le parole chiave sono riservate: un lessema è un id solo se non è una keyword.
input lettura di un carattere ritorno indietro di un carattere Analizzatore lessicale token e attributi Parsificatore L analizzatore lessicale e il parsificatore formano una coppia produttore consumatore: l analizzatore produce i token e il parsificatore li consuma. Come dimensionare il buffer? Di solito il buffer contiene un token: l interazione può essere implementata con una chiamata da parte del parsificatore della procedura di analisi lessicale, che ritorna i token su richiesta.
Anche per l input di solito viene usato un buffer in cui viene letto un blocco di caratteri alla volta. lettura di un carattere ritorno indietro di un carattere Analizzatore lessicale Restituzione di un token al chiamante tokenval Variabile globale che contiene il valore dell attributo L analizzatore restituisce la codifica del token, di solito un numero maggiore della codifica dei caratteri (256...)
function lexan begin while true do c := readcar if c = or tab then do nothing else if c = newline then lineno := lineno + 1 else if isdigit (c) then costruisci il numero formato da c e dai digit successivi in tokenval return il token num else if isalfa (c) then identifica c e lettere e digit successivi come lessema aggiorna la symbol table... return il token id else tokenval := NONE return c
function lexan begin while true do c := readchar if c = or tab then do nothing else if c = newline then lineno := lineno + 1 else if isdigit (c) then tokenval := c c := readchar while isdigit (c) do tokenval := tokenval * 10 + c c := readchar c := prechar return num...
Operazioni sulla symbol table: insert(s, t): ritorna l indice della nuova entry per la stringa s, token t. lookup(s): ritorna l indice della entry per la stringa s, oppure 0 se la stringa non viene trovata. Si può inizializzare la symbol table con le parole riservate: Insert ( Div, div)
esempio di implementazione: 0 1 2 3 4 ptr token attributi div id id D i v eos c o u n t eos i n c eos
function lexan var lexbuf: array [1.. 100] of char c: char begin while true do c := readchar if c = or tab then do nothing else if c = newline then lineno := lineno + 1 else if isdigit (cc) then...... return num else if c è una lettera then metti cc e lettere e digit successivi in lexbuf aggiorna la symbol table tokenval := il puntatore al lessema return il token id else if c = eof then return DONE else tokenval := NONE return c (l intero che codifica il carattere c)
else if isalpha (c) then b := 0 while isalnum (c) do lexbuf [b] := c c := readchar b := b + 1 if b >= BSIZE then error ( errore di compilazione ) lexbuf [b] := eos c := prechar p := lookup (lexbuf) if p = 0 then p := insert (lexbuf, id) tokenval := p return symtable [p].token
Esempio di traduzione Tradurre in forma postfissa una sequenza di espressioni separate da ; Le espressioni consistono di numeri, identificatori e degli operatori +, -, *, /, Div e Mod. id rappresenta una sequenza non vuota di lettere e digit che iniziano con una lettera. L attributo lessema del token id dà la stringa di caratteri che formano il token. L attributo val del token num fornisce l intero rappresentato da num.
list E ; list list ε E E + T E E-T E T T T * F T T / F T T div F T T mod F T F F ( E ) F id F num print ( + ) print ( - ) print ( * ) print ( / ) print ( Div ) print ( Mod ) print (id.lessema) print (num.val)
list E ; list list ε E E + T E E-T E T T T * F T T / F T T div F T T mod F T F F ( E ) F id F num list E ; list list ε E T R R + T R - T R R ε T F R R * F R / F R R div F R R mod F R R ε F ( E ) F id F num
init lexan symbol parser error emitter main begin init parse {termina con successo}
init: inizializza la symbol table con le keyword error: procedure error (m) print (lineno, m) exit {termina senza successo} lexan: analizzatore lessicale precedente
procedure parse begin cc := lexan list if cc = DONE then successo list E ; list list ε { (, id, num} {DONE} procedure list begin if cc = ( or cc = id or cc = num then cc := lexan E if cc = ; then cc := lexan else error ( errore di sintassi ) list else if cc = DONE then do nothing else error ( errore di sintassi )
procedure parse begin cc := lexan list if cc = DONE then successo procedure list begin if cc = ( or cc = id or cc = num then cc := lexan E if cc = ; then cc := lexan else error ( errore di sintassi ) list else if cc = DONE then do nothing else error ( errore di sintassi ) procedure parse begin cc := lexan while cc DONE do E if cc = ; then cc := lexan else error ( errore di sintassi ) { successo }
Gui(E T R ) = {(, id, num} Gui(R - T R ) = {-} Gui(R + T R ) = {+} Gui(R ε) = {;, )} procedure E begin if cc = ( or cc = id or cc = num then cc := lexan T R else errore ( ) procedure R begin if cc = + or - then cc := lexan T R else if cc = ; or cc = ) then do nothing else errore ( )
procedure E begin T while (cc = + or cc = - ) do cc := lexan T Gui(T T R ) = {(, id, num} Gui(R div F R ) = {div} Gui(R * F R ) = {*} Gui(R mod F R ) = {mod} Gui(R / F R ) = {/} Gui(R ε) = {+, -, ;, )} procedure T begin F while (cc = * or cc = / or cc = div or cc = mod) do cc := lexan F
Gui(F (E) ) = { ( } Gui(F num ) = {num} Gui(F id ) = {id} procedure F begin if cc = ( then cc := lexan E if cc = ) then cc := lexan else error ( errore di sintassi ) else if cc = num then cc := lexan else if cc = id then cc := lexan else error ( errore di sintassi )
list E ; list list ε E T R R + T R R -T R R ε T F R R * F R R / F R R div F R R mod F R R ε F ( E ) F id F num list E ; list list ε E T R R + T {print ( + )} R R - T {print ( - )} R R ε T F R R * F {print ( * )} R R / F {print ( / )} R R div F {print ( Div )} R R mod F {print ( Mod )} R R ε F ( E ) F id {print (id.lessema)} F num {print (num.val)}
procedure E var t begin T while (cc = + or cc = - ) do t := cc cc := lexan T emit (t, NONE)
procedure T var t begin F while (cc = * or cc = / or cc = div or cc = mod) do t := cc cc := lexan F emit (t, NONE)
procedure F begin if cc = ( then cc := lexan E if cc = ) then cc := lexan else error ( errore di sintassi ) else if cc = num then emit (num, tokenval) cc := lexan else if cc = id then emit (id, tokenval) cc := lexan else error ( errore di sintassi )
procedure emit (t, tval) begin if t = + or t = - or t = * or t = / then print (t) else if t = div then print (Div) else if t = mod then print (Mod) else if t = num then print (tval) else if t = id then print (symtable[tval].ptr)