Domanda

Oltre a fare qualsiasi lavoro reale, ho un prurito. Il mio prurito è scrivere un motore di visualizzazione che imiti da vicino un sistema di template da un'altra lingua (Template Toolkit / Perl). Questo è uno di quelli se avessi il tempo / lo faccio per imparare qualcosa di nuovo tipo di progetti.

Ho passato del tempo a guardare CoCo / R e ANTLR e, onestamente, mi fa male al cervello, ma parte di CoCo / R sta sprofondando. Sfortunatamente, la maggior parte degli esempi riguarda la creazione di un compilatore che legge il codice sorgente , ma nessuno sembra comprendere come creare un processore per i modelli.

Sì, sono la stessa cosa, ma non riesco a capire come definire la lingua per i modelli in cui la maggior parte dei sorgenti è l'html, piuttosto che il codice reale che viene analizzato ed eseguito.

Ci sono buone risorse per principianti là fuori per questo tipo di cose? Ho preso un ganer a Spark, che non sembrava avere la grammatica nel repository.

Forse è eccessivo, e si potrebbe semplicemente provare a sostituire la sintassi del modello con c # nel file e compilarlo. http://msdn.microsoft.com/en-us/magazine/ cc136756.aspx # S2

Se fossi nei miei panni e non fossi un esperto di creazione linguistica, da dove inizieresti?

È stato utile?

Soluzione

La grammatica Spark è implementata con un linguaggio specifico di dominio piuttosto fluente.

È dichiarato in pochi livelli. Le regole che riconoscono la sintassi html sono dichiarate in MarkupGrammar.cs : si basano su regole grammaticali copiate direttamente dalle specifiche xml.

Le regole di markup si riferiscono a un sottoinsieme limitato di regole di sintassi csharp dichiarate in CodeGrammar.cs - quelli sono un sottoinsieme perché Spark deve solo riconoscere abbastanza csharp per adattare le virgolette singole attorno alle stringhe in virgolette doppie, abbinare parentesi graffe, ecc.

Le singole regole stesse sono di tipo ParseAction < !> lt; TValue <> gt!; delegato che accetta una Position e restituisce un ParseResult . ParseResult è una classe semplice che contiene l'elemento di dati TValue analizzato dall'azione e una nuova istanza Position che è stata avanzata oltre il contenuto che ha prodotto TValue.

Non è molto utile da solo finché non si introduce un piccolo numero di operatori , come descritto in Grammatica di espressione di analisi , che può combinare singole azioni di analisi per creare espressioni molto dettagliate e solide sulla forma di diversi costrutti di sintassi.

La tecnica di utilizzo di un delegato come azione di analisi proviene dal post di un blog di Luke H Combinatori di parser monadici che usano C # 3.0 . Ho anche scritto un post su Creazione di un dominio specifico Lingua per l'analisi .

È anche del tutto possibile, se lo si desidera, fare riferimento all'assembly Spark.dll ed ereditare una classe dalla CharGrammar di base per creare una grammatica completamente nuova per una particolare sintassi. È probabilmente il modo più rapido per iniziare a sperimentare questa tecnica, e un esempio di ciò può essere trovato in CharGrammarTester.cs .

Altri suggerimenti

Passaggio 1. Utilizzare le espressioni regolari (sostituzione regexp) per dividere la stringa del modello di input in un elenco di token, ad esempio dividere

hel<b>lo[if foo]bar is [bar].[else]baz[end]world</b>!

a

write('hel<b>lo')
if('foo')
write('bar is')
substitute('bar')
write('.')
else()
write('baz')
end()
write('world</b>!')

Passaggio 2. Converti l'elenco dei token in un albero di sintassi:

* Sequence
** Write
*** ('hel<b>lo')
** If
*** ('foo')
*** Sequence
**** Write
***** ('bar is')
**** Substitute
***** ('bar')
**** Write
***** ('.')
*** Write
**** ('baz')
** Write
*** ('world</b>!')

class Instruction {
}
class Write : Instruction {
  string text;
}
class Substitute : Instruction {
  string varname;
}
class Sequence : Instruction {
  Instruction[] items;
}
class If : Instruction {
  string condition;
  Instruction then;
  Instruction else;
}

Passaggio 3. Scrivi una funzione ricorsiva (chiamata interprete), che può camminare sul tuo albero ed eseguire le istruzioni lì.

Un altro approccio alternativo (invece dei passaggi 1-3) se la tua lingua supporta eval () (come Perl, Python, Ruby): usa una sostituzione regexp per convertire il modello in una stringa in grado di eval () in la lingua host ed esegui eval () per creare un'istanza del modello.

Ci sono così tante cose da fare. Ma funziona con una semplice istruzione GET più un test. È un inizio.

http://github.com/claco/tt.net/

Alla fine, ho già avuto troppo tempo in ANTLR per provare il metodo di loudejs. Volevo dedicare un po 'più di tempo all'intero processo piuttosto che al parser / lexer. Forse nella versione 2 posso provare il modo Spark quando il mio cervello capisce le cose un po 'di più.

Vici Parser (precedentemente noto come LazyParser.NET) è un open-source tokenizer / template parser / expression parser che può aiutarti a iniziare.

Se non è quello che stai cercando, potresti avere qualche idea guardando il codice sorgente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top