Sto scrivendo un parser per un linguaggio di markup che ho creato (scrivendo in python, ma non è molto pertinente a questa domanda - infatti se questa sembra una cattiva idea, mi piacerebbe un suggerimento per un percorso migliore).
Sto leggendo i parser qui: link , e sto lavorando alla scrittura del lexer che dovrebbe , se ho capito bene, dividi il contenuto in token. Quello che ho difficoltà a capire è quali tipi di token dovrei usare o come crearli. Ad esempio, i tipi di token nell'esempio a cui mi sono collegato sono:
- STRING
- IDENTIFIER
- NUMERO
- WHITESPACE
- COMMENTO
- EOF
- Molti simboli come {e (contano come il proprio tipo di token
Il problema che sto avendo è che i tipi di token più generali mi sembrano un po 'arbitrari. Ad esempio, perché STRING è un tipo di token separato rispetto a IDENTIFIER. Una stringa può essere rappresentata come STRING_START + (IDENTIFIER | WHITESPACE) + STRING_START.
Questo potrebbe anche avere a che fare con le difficoltà della mia lingua. Ad esempio, le dichiarazioni delle variabili sono scritte come {var-name var value}
e distribuite con {var-name}
. Sembra che '{'
e '}'
siano i propri token, ma sono VAR_NAME e VAR_VALUE tipi di token idonei, oppure entrambi rientrano in IDENTIFIER? Inoltre, VAR_VALUE può effettivamente contenere spazi bianchi. Lo spazio bianco dopo var-name
viene utilizzato per indicare l'inizio del valore nella dichiarazione .. qualsiasi altro spazio bianco è parte del valore. Questo spazio bianco diventa il proprio token? Lo spazio bianco ha solo questo significato in questo contesto. Inoltre, {
potrebbe non essere l'inizio di una dichiarazione di variabile .. dipende dal contesto (c'è di nuovo quella parola!). {:
avvia una dichiarazione di nome e {
può anche essere usato come parte di un certo valore.
La mia lingua è simile a Python in quanto i blocchi sono creati con indentazione. Stavo leggendo su come Python usa il lexer per creare token INDENT e DEDENT (che servono più o meno come farebbero {
e }
in molti altri linguaggi). Python afferma di essere privo di contesto, il che significa che almeno il lexer non dovrebbe preoccuparsi di dove si trova nello stream durante la creazione di token. In che modo il lexer di Python sa che sta creando un token INDENT di una lunghezza specifica senza conoscere i caratteri precedenti (ad esempio che la riga precedente era una nuova riga, quindi inizia a creare gli spazi per INDENT)? Chiedo perché ho bisogno di sapere anche questo.
La mia ultima domanda è la più stupida: perché è ancora più necessario un lexer? Mi sembra che il parser possa andare personaggio per carattere e capire dove si trova e cosa si aspetta. Il lexer aggiunge il vantaggio della semplicità?