Ho letto Regular Expression Matching: the Virtual Machine Approach e ora provo ad analizzare un'espressione regolare e creare una macchina virtuale da esso. Il tokenizer funziona e crea i token. Dopo questo passo, creo la notazione polacca inversa dal flusso di token così alla fine hoMacchina virtuale da espressione regolare
a b c | |
dall'espressione regolare a|(b|c)
. Bene, ora il passo dove ho attaccato: Voglio ottenere un array
0: split 1, 3
1: match 'a'
2: jump 7
3: split 4, 6
4: match 'b'
5: jump 7
6: match 'c'
7: noop
dal flusso sopra. E non ho capito bene ... Io uso un array di output e uno stack per le posizioni iniziali di ciascun token. In primo luogo, i 3 valori vengono aggiunti all'output (e sono le posizioni iniziali nello stack).
output stack
------------------- ------
0: match 'a' 0: 0
1: match 'b' 1: 1
2: match 'c' 2: 2
Con |
, ho pop le ultime 2 posizioni dalla pila e inserire split
e jump
nelle posizioni specifiche. I valori sono calcolati in base alla lunghezza della pila corrente e alla quantità di elementi che aggiungo. Alla fine, aggiungo la nuova posizione iniziale dell'ultimo elemento allo stack (rimane lo stesso in questo caso).
output stack
------------------- ------
0: match 'a' 0: 0
1: split 2, 4 1: 1
2: match 'b'
3: jump 5
4: match 'c'
Sembra ok. Ora, il prossimo |
viene estratto ...
output stack
------------------- ------
0: split 1, 3 0: 0
1: match 'a'
2: jump 7
3: split 2, 4
4: match 'b'
5: jump 5
6: match 'c'
Ed ecco il problema. Devo aggiornare tutti gli indirizzi che ho calcolato prima (righe 3 e 5). Non è quello che voglio. Suppongo che gli indirizzi relativi abbiano lo stesso problema (almeno se i valori sono negativi).
Quindi la mia domanda è, come creare un vm da regex. Sono sulla strada giusta (con il modulo rpn) o c'è un altro (e/o più semplice) modo?
L'array di output viene archiviato come array di numeri interi. Il split
-command ha bisogno in realtà 3 voci, jump
ha bisogno di due, ...
un tag regex-virtual-machine sarebbe più preciso – 1010
Ho un progetto molto simile e io non ti credo avere una possibilità senza ricalcolare. Se si pensa ad una struttura ad albero, è possibile ricominciare in modo ricorsivo un '|' -node con l'output di 'split', elaborare il primo figlio, emettere il' jump', elaborare il secondo figlio e dopo il ritorno, aggiornare gli indirizzi su 'split' e' jump'. È facile all'interno di un albero - ma è ancora ricalcolo. –