Creazione di una sorta di 'compilatore in lingua'

3

Non sto dicendo che voglio creare un compilatore completamente nuovo che sia completamente indipendente. Sto utilizzando C # Windows Form e voglio che gli utenti siano in grado di scrivere la sintassi del filtro in una casella di testo con la mia applicazione gestita in un linguaggio di query di base, ad esempio:

inCategory(Animals)
where(animal.age > 40)
take animal;

È fondamentalmente una versione semplificata di LINQ. Ma voglio che questa logica sia racchiusa in una classe separata, quindi posso dire qualcosa del genere:

var dataQuery = FilterCompiler.Compile(filterTextBox.Text);
dataQuery.Execute();

Non sto dicendo 'gimee the code', ma un po 'di psuedocode / struttura logica di base per questo' compilatore 'sarebbe bello dato che io sono un po' ignorante su questo argomento. Ad esempio,

  • Che tipo di analisi del testo dovrebbe fare questo FilterCompiler ?
  • Quale sarebbe il tipo di dataQuery ?
  • Questo richiederebbe qualche conoscenza della grammatica del compilatore?
  • Dovrei usare qualsiasi codice non gestito?
  • Come posso mantenere la compilazione il più indipendente possibile in modo che non dipenda troppo dal tipo di dati che ho? Attualmente ho una lista, ma le cose cambiano, potrei avere un database con le informazioni al suo interno presto.
posta naiveai 03.12.2014 - 17:18
fonte

5 risposte

4

Sfortunatamente non è così semplice, hai alcune opzioni ...

Coco / R

Se non hai intenzione di fare un linguaggio complesso e supporta solo poche parole chiave personalizzate, ti suggerirei qualcosa come Coco / R . L'ho usato diverse volte in passato per creare parser per tutti i tipi di progetti.

Il suo significato è che crei un file di grammatica che descrive la tua lingua e ti consente di collegare le tue funzioni quando vengono trovati determinati token. Questo può essere un po 'più difficile perché sembra che il tuo linguaggio di esempio comprenda i concetti di Oggetti e Coco / R in realtà crei classi da compilare. Ciò significa che dovrai costruire questo tipo di cose nel parser e / o usare le interfacce. Stai anche facendo aritmetica, il che significa che dovrai scrivere un valutatore di espressioni.

Compila con classi .NET

Un'altra opzione è quella di non creare effettivamente la tua sintassi ma usare qualcosa come le classi incorporate di .NET per compilare il codice. Questo ti risparmia molto lavoro (leggi tonnellate di lavoro) ma perdi la flessibilità di creare il tuo linguaggio semplicistico. Ulteriori informazioni possono essere trovate qui .

Reflection.Emit

Un'altra opzione che probabilmente sarebbe la più complessa e non vale la pena sarebbe scrivere IL usando il reflection e poi compilare quel codice in una funzione dinamica ed eseguirlo. Avresti molte tracce ed errori, assicurandoti di generare un IL valido che non si arresti e crei degli strani errori che sono quasi impossibili da rintracciare. Ci sono molti vantaggi da questo, l'utente può scrivere codice complesso che potrebbe interagire con i propri oggetti (come un vero linguaggio di scripting) e sarebbe facile estenderlo una volta che il framework è stato costruito. Maggiori informazioni possono essere trovate qui

Se personalmente dovessi sceglierne uno, verrebbe da quello che mi serviva. Se stavo sviluppando questo per la mia azienda, probabilmente andrei con Reflection.Emit e se avessi bisogno di qualcosa su cui lavorare in questo momento e velocemente avrei usato le librerie .NET per compilare solo il codice C # in un dominio app che poi avrei semplicemente esegui. Se il linguaggio avesse solo un piccolo sottoinsieme di funzionalità, probabilmente andrei con Coco / R, ma ho molta esperienza con esso e non ci sarebbe alcuna curva di apprendimento per me.

Ci scusiamo per la terribile formattazione, sono ancora piuttosto nuovo per MD.

    
risposta data 03.12.2014 - 17:49
fonte
15

Quello che stai cercando di creare è noto come DSL autonomo (con una sintassi e un interprete separati), al contrario di uno incorporato (che condivide la sintassi con una lingua host).

Ciò richiederà le competenze necessarie per creare un interprete semplice, come minimo.

Nella sua forma più semplice, ciò comporta quanto segue:

  1. Lettura nel testo.
  2. Esecuzione dell'analisi lessicale, che interrompe il testo di input in entità specifiche del linguaggio specifiche note come token . Questo passaggio è spesso indicato come lexing.
  3. Esecuzione dell'analisi sintattica, che costruisce alberi di espressioni dal flusso di token. Questo passaggio viene spesso definito parsing.
  4. Interpretazione, che accetta gli alberi di espressione (nel tuo caso, questo sarebbe un albero di oggetti) e quindi esegue le azioni indicate dalla semantica della tua lingua.

I passaggi 2-3 non sono comunemente fatti tramite codice scritto a mano, tranne nel caso di interpreti di lingue in piena regola. I framework o generatori di codice, come lex e yacc per C, sono di gran lunga il metodo di implementazione più comune.

I compilatori: Principi, strumenti e tecniche (affettuosamente chiamato The Dragon Book per il tema delle sue copertine) è una fonte molto apprezzata su questo tipo di passaggi.

Per inciso, tutto questo sembra una grande quantità di lavoro per ciò che vuoi veramente realizzare, specialmente dal momento che Microsoft ha incluso un linguaggio di espressione semplice sulla struttura DataTable utilizzata da ADO.NET (vedi qui per ulteriori informazioni: collegamento ). Costruire un DSL rivolto all'utente per filtrare sembra eccessivo. Se hai bisogno di griglie complesse e funzionalità simili, sarebbe probabilmente più efficiente guardare un fornitore di componenti come DevExpress o Telerik.

    
risposta data 03.12.2014 - 17:28
fonte
3

What sort of text analysis would this FilterCompiler need to do?

Dovrebbe essere in grado di interpretare l'input e capire cosa è buono / cattivo. Consiglierei di seguire l'approccio standard di lexer / parser, poiché è ben noto e robusto di fronte all'incertezza (leggi: input dell'utente).

What would be the type of dataQuery?

Func<T, T> (dove T è qualsiasi enumerabile con cui stai lavorando) probabilmente.

Would I need to use any unmanaged code?

Assolutamente no.

.NET ha una libreria molto carina per compilare i delegati al volo per cose specifiche come questa: Alberi di espressione . È anche possibile utilizzare la riflessione per sapere quali proprietà / campi sono identificativi legali. Risolvere gli identificatori negli oggetti di riflessione e quindi costruire gli alberi di espressione è tanto semplice quanto queste cose.

    
risposta data 03.12.2014 - 17:34
fonte
2

Molte delle risposte sopra suggeriscono l'uso di parser generatori (che sono programmi forniti con una descrizione della tua lingua e che producono codice che puoi compilare per analizzarlo). In realtà vorrei raccomandare contro questo approccio. Spesso può essere complicato capire cosa non funziona quando tali parser falliscono e convincerli a produrre messaggi di errore sensati è una forma d'arte propria.

Per le lingue semplici, può essere effettivamente più facile codificare manualmente il proprio parser di discesa ricorsivo. Ecco un semplice esempio per iniziare .

    
risposta data 08.12.2014 - 14:36
fonte
1

Sembra che quello che vuoi sia un interprete di script nel tuo codice, per impostare un linguaggio specifico per il dominio. Come una delle note dei commenti, c'è un libro sul fare questo per codice .NET, usando il linguaggio Boo, che può essere usato come linguaggio compilato a sé stante o come interprete su un programma CLR esistente. Boo non è molto diffuso, ma è open source e ha un sacco di utili funzionalità specifiche per metaprogramming e creazioni DSL, e se hai seguito quella strada non avresti bisogno di creare il tuo parser.

    
risposta data 03.12.2014 - 18:07
fonte

Leggi altre domande sui tag