Implementazione di un motore per
la colorazione della sintassi in
GtkSourceView
Relatore:
Riccardo Sisto
Candidati:
Emanuele Aina
Marco Barisione
GtkSourceView
Widget di testo per GTK 2 con funzionalità
avanzate per la programmazione
Limiti del motore attuale
Impossibilità di gestire strutture annidate
#if 0
# if A
# endif
#endif
nessuna
colorazione
// FIXME: commento
printf ("hello \n world");
#if 0
Limiti del motore attuale
JavaScript dentro HTML:
<script language="javascript">
if (a<b)
language = "stringa";
variabile = "stringa";
</script>
<script language="javascript">
if (a<b)
language = "stringa";
variabile = "stringa";
</script>
Obiettivi
Gestire costrutti complessi
Linguaggi all'interno di altri linguaggi (JavaScript
in HTML)
Semplicità nella descrizione dei linguaggi
Non deve essere necessario programmare
Buone prestazioni
Nell'uso interattivo non devono essere visibili
rallentamenti
Tecnologie esistenti
Colorer
Kate
Esposizione dell’implementazione nelle descrizioni dei linguaggi
Scintilla
Eccessiva complessità
Necessità di scrivere un lexer in C per ogni linguaggio
VIM
Descrizioni basate su un motore di scripting
L’analisi è eseguita solo su una porzione del testo
Nuovo motore: annidamenti
Corretta gestione di strutture annidate
#if 0
# if A
# endif
#endif
nessuna
colorazione
#if 0
#if A
Nuovo motore: contesti
Contesto: porzione di testo con significato
sintattico
Esempi: commenti, stringhe o parole chiave
Espressioni regolari
Flessibilità nel riconoscimento di porzioni di testo
Impossibilità di riconoscere costrutti complicati
Mancanza di ricorsività
Regolano le transizioni fra un contesto e l'altro
XML
Standard W3C
Estensibile
Il significato degli elementi è definito dallo
sviluppatore
Ampia diffusione e supporto
Validazione automatica
DTD
Schema
Relax NG
Contesti semplici
Non contengono sotto-contesti
Identificati da un'unica espressione regolare
<context id="include">
<match>
^#include ".*?"
</match>
</context>
Contesti contenitore
Delimitati da un'espressione regolare di inizio e
da una di fine
<context id="string">
<start>"</start>
<end>"</end>
<include>
<context id="escape">
<match>\\.</match>
Contesti keyword
Lista di parole chiave
<context id="keywords">
<keyword>for</keyword>
<keyword>if</keyword>
[…]
</context>
Internamente sono contesti semplici
Contesti sub-pattern
Non sono veri contesti
Identificano una porzione di un'espressione regolare
•
•
Corrispondono ad un "sub-pattern" di una espressione
regolare
Numerati a partire da 1
Possono essere contenuti in contesti semplici
<context id="include">
<match>#include ("[^"]*")</match>
<include>
<context sub-pattern="1"/>
Estensione dei contesti
I contesti possono estendere il genitore
"hello \" world"
escape
string
Non sempre è ciò che si vuole
<script> // Commento </script>
Attributo extend-parent del tag <context>
Stili
Separazione tra presentazione e descrizione
Nome visibile all'utente
Associazione a stili predefiniti
<style id="comment"
name="Comment"
map-to="def:comment"/>
Associazione dello stile al contesto con l'attributo
style-ref
Più contesti possono usare lo stesso stile
Riuso del codice
Definire espressioni regolari usate frequentemente
Riferimento a contesti già definiti (attributo ref)
Più contesti contengono lo stesso sotto-contesto
Importazione di altre descrizioni
Tag <define-regex id="nome">
Riferimento all'espressione regolare con \%{nome}
C++ aggiunge solo alcune keyword al C
def.lang contiene alcune definizioni comuni
Analisi
Viene analizzata una riga per volta
Ad ogni carattere si verifica se vi è una transizione dal contesto
corrente verso un altro contesto
Contesti contenitore
Il motore entra nel contesto quando trova l'espressione iniziale in
<start>
Il motore esce dal contesto quando trova l'espressione finale in
<end>
Contesti semplici
Il motore si sposta dopo la corrispondenza in <match>
Esempio di analisi
#if 0
# if A
# endif
#endif
/* […]
* FIXME
* […]
*/
c
if0
comment
Stato corrente: c comment
if0 if-in-if0
fixme
if-in-if0
fixme
Albero degli stati
L'insieme degli stati per ogni posizione nel testo è
rappresentato da un albero
c [0; 57]
if0 [0; 29]
comment [30; 57]
if-in-if0 [6; 22]
fixme [40; 45]
Alla posizione 25 lo stato è: c if0
Accelerazione dell'analisi
Ricerca delle corrispondenze ancorata o meno
Prima implementazione:
Per ogni carattere provate tutte le possibili transizione
Seconda implementazione:
Fusione di tutte le possibili transizioni in un'unica
espressione regolare
Suddivisione in due fasi:
•
•
Ricerca della posizione della prima transizione
Ricerca della destinazione della transizione
Miglioramento di un ordine di grandezza
Modifiche al testo
Non è possibile rianalizzare l'intero file ad ogni
modifica
Riciclare i contesti presenti prima della modifica
I contesti che precedono la riga modificata vengono
riciclati così come sono
La riga viene rianalizzata
Quando lo stato vecchio e quello nuovo coincidono si
possono riciclare tutti i contesti successivi
Esempio di modifica del testo
a = 42 / primo */ + 1 /* secondo */;
decimal [4; 6]
error [15; 17]
c [0; 36]
decimal [20; 21]
comment [22; 35]
Esempio di modifica del testo
a = 42 /* primo */ + 1 /* secondo */;
c [0; ?]
decimal [4; 6]
error [15 +1; 17 +1]
c [0; 36 +1]
decimal [20 +1; 21 +1]
comment [22 +1; 35 +1]
Esempio di modifica del testo
a = 42 /* primo */ + 1 /* secondo */;
c [0; ?]
decimal [4; 6]
error [16; 18]
c [0; 37]
decimal [21; 22]
comment [23; 36]
Esempio di modifica del testo
a = 42 /* primo */ + 1 /* secondo */;
c [0; ?]
decimal [4; 6]
decimal [4; 6]
error [16; 18]
c [0; 37]
decimal [21; 22]
comment [23; 36]
Esempio di modifica del testo
a = 42 /* primo */ + 1 /* secondo */;
decimal [4; 6]
c [0; ?]
comment [7; ?]
decimal [4; 6]
error [16; 18]
c [0; 37]
decimal [21; 22]
comment [23; 36]
Esempio di modifica del testo
a = 42 /* primo */ + 1 /* secondo */;
decimal [4; 6]
c [0; ?]
comment [7; ?]
decimal [4; 6]
error [16; 18]
c [0; 37]
decimal [21; 22]
comment [23; 36]
Esempio di modifica del testo
a = 42 /* primo */ + 1 /* secondo */;
decimal [4; 6]
c [0; ?]
comment [7; 18]
decimal [4; 6]
error [16; 18]
c [0; 37]
decimal [21; 22]
comment [23; 36]
Esempio di modifica del testo
a = 42 /* primo */ + 1 /* secondo */;
decimal [4; 6]
c [0; ?]
comment [7; 18]
decimal [4; 6]
error [16; 18]
c [0; 37]
decimal [21; 22]
comment [23; 36]
Esempio di modifica del testo
a = 42 /* primo */ + 1 /* secondo */;
decimal [4; 6]
c [0; ?]
comment [7; 18]
decimal [4; 6]
error [16; 18]
c [0; 37]
decimal [21; 22]
comment [23; 36]
Esempio di modifica del testo
a = 42 /* primo */ + 1 /* secondo */;
decimal [4; 6]
comment [7; 18]
c [0; 37]
decimal [21; 22]
comment [23; 36]
Conclusioni
Buone prestazioni
Non si notano rallentamenti su macchine datate
•
Descrizione dei linguaggi semplice
Portatile PIII@450MHz
Già realizzati: C, C++, JavaScript, HTML, XML,
LaTeX
Supporto del vecchio formato di descrizione dei
linguaggi
Sviluppi futuri
Supporto di nuovi linguaggi
Test di uso reale in Gedit, MonoDevelop, Meld
Integrazione nel ramo ufficiale e quindi in
GNOME
Eliminazione del vecchio motore
Trasformazione dinamica del vecchio formato
mediante il foglio di stile XSLT già scritto