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
Scarica

GtkSourceView