2010-08-27 11 views
5

Ho pensato di fare la mia lingua (praticità: è un esperimento mentale). Una delle idee che mi sono venute in mente è la variazione semantica del linguaggio. Scriveresti essenzialmente espressioni regolari semantiche, da sostituire con codice equivalente. Puoi vederlo in una forma un po 'meno diretta in D- hanno mixin di stringhe che si convertono in codice D. Tranne che li avrei fatti implicitamente e in modo più circolare.Variazione semantica in lingua

In questo momento, ho origine da C++. Quindi se si considera:

string a, b, c, d; 
// do stuff 
a = b + c + d; 

Questo codice restituisce vari provvisori. Anche se hai riferimenti di rvalue, creerai dei provvisori, saranno semplicemente riutilizzati in modo più efficiente. Ma esistono ancora e continuano a perdere prestazioni. Stavo pensando, nel caso più semplice, a come questi potrebbero essere eliminati. Potresti scrivere un'espressione regolare semantica che la convertirà nella forma più ottimizzata.

string a, b, c, d; 
// do stuff 
a.resize(b.size() + c.size() + d.size()); 
a = b; a += c; a += d; 

Se ho implementato std :: string, potrei riuscire a scrivere qualcosa ancora più velocemente. La chiave di questo è che sono impliciti: quando si utilizza la classe std :: string, gli assiomi scritti dallo std :: string implementer possono influenzare qualsiasi codice std :: string. Si potrebbe semplicemente rilasciarlo in una base di codice C++ esistente, ricompilare e ottenere la più rapida concatenazione di stringhe che il tuo implementatore di std :: string possa concepire gratuitamente.

Al momento, le ottimizzazioni che si possono fare sono limitate, perché si ha solo il contesto che il linguaggio consente, in questo caso, l'overloading dell'operatore in C++ prende solo due argomenti, questo e arg. Ma un regs semantico potrebbe prendere praticamente tutto il contesto di cui avresti mai potuto avere bisogno - dal momento che puoi dettare ciò che corrisponde - e persino corrispondere a caratteristiche linguistiche che non esistono nella lingua ospite. Ad esempio, sarebbe banale per lo scambio di

string a; 
a.size; 

per

string a; 
a.size(); 

se si voleva rubare C Proprietà #. È possibile abbinare le definizioni di classe e implementare la riflessione di compilazione o di esecuzione, ecc.

Ma, voglio dire, potrebbe diventare confuso. Se c'è stato un bug, o cosa è stato fatto dietro le quinte non riflette il codice che è stato scritto, potrebbe essere una cagna totale da rintracciare, e non ho considerato come sarebbe stato implementato in profondità. Cosa ne pensate della mia proposta di lingua?

Oh uomo, scegliendo i tag giusti. Ummm ....

Modifica: volevo anche violare l'ambito dei limiti, per quanto riguarda una risposta che ho avuto. Il semplice fatto è che la regex semantica non ha limiti (meno i dettagli di implementazione che potrebbero dover essere aggiunti). Ad esempio, si potrebbe trasformare l'espressione

int i; 
cin >> i; 
int lols[i]; 

in

int i; 
cin >> i; 
std::variable_array<int>(alloca(sizeof(int) * i), i); 

La semantica di alloca rendere la manipolazione con i modelli impossibile- si deve scrivere una macro se si desidera che il sopra. In C++ 03 o C++ 0x, non è possibile incapsulare i propri VLA.

Inoltre, le regex semantiche possono corrispondere al codice che non richiama effettivamente alcun lavoro in fase di compilazione. Ad esempio, è possibile associare ogni membro di una definizione di classe e utilizzarlo per creare un sistema di riflessione. Questo è anche impossibile in C++ fino ad oggi.

+0

Qualche idea su come potrebbe essere la sintassi di corrispondenza del modello? –

+0

Al momento non ho molta idea, ma non è complicato: scrivi un po 'di codice che assomiglia al codice che vuoi sostituire e un po' di codice che assomiglia al codice che vuoi usare. – Puppy

risposta

1

Se si utilizza Google per qualcosa come "modello di espressione C++", in realtà il C++ ha già capacità simili. A seconda di cosa ti è venuta in mente per la sintassi, la tua idea potrebbe rendere questo codice più facile da comprendere (i modelli di espressione certamente non sono banali) ma almeno per me non è del tutto chiaro che stai aggiungendo molto (se non altro) in il modo di capacità veramente nuove.

+0

Ti riferisci al modo in cui, ad esempio, boost :: lambda funziona? Inoltre, ho visto cose come quella libreria che calcola le aree di forme disegnate negli operatori in fase di compilazione. Ma non è la stessa cosa, perché in primo luogo posso definire la mia interfaccia come qualsiasi cosa mi piaccia (entro i limiti della ragione), mentre le interfacce dei template di espressione sono decisamente non banali. In secondo luogo, non sto parlando di fare il comportamento di runtime al compiletime, o anche viceversa, ma sostituire un comportamento di compilazione/runtime con un altro dello stesso tipo che è preferibile in qualche altro wasy. – Puppy

+0

Niente più modifiche :(In terzo luogo, ci sono molti meno limiti.Ad esempio, un reg di semantico ha il potere di abbinare costrutti a cui non è associato un lavoro in fase di compilazione, come una definizione di classe. con un modello o incapsulare un VLA? Non puoi fare nessuna di queste cose. – Puppy

1

(Attenzione: la risposta Mammoth avanti)

Credo che si chiama una macro;) Beh, almeno al di fuori del mondo C/C++ (dove "macro" si riferisce a questa sostituzione gravemente limitato il preprocessore fornisce). E non è molto nuovo. Anche se penso che un sistema macro efficace e potente possa aggiungere più potenza a una lingua rispetto a qualsiasi altra funzionalità (dato che conserviamo abbastanza primitive che non è semplicemente turing-completene, ma utile per la programmazione reale), in quanto un programmatore sufficientemente intelligente può aggiungere quasi tutte le funzionalità che potrebbero rivelarsi utili in futuro o per un dominio specifico senza aggiungere (ulteriori) regole alla lingua.

L'idea di base è di analizzare un programma in una rappresentazione sopra una stringa con il codice sorgente, ad esempio AST o parse tree. Tali alberi forniscono maggiori informazioni sul programma e un altro programma può camminare su questo albero e modificarlo. Ad esempio, sarebbe possibile cercare un nodo VariableDeclaration, verificare se dichiara un semplice vecchio array di T e sostituirlo con un nuovo nodo VariableDeclaration che invece dichiara uno std::variable_array di T. Ad esempio, questo può essere perfezionato fornendo il pattern matching per l'albero, rendendo più facile la metaprogrammazione. Una procedura potente, se e solo se il programmatore può far fronte a questo livello di astrattezza e sa come usarlo.

Si noti che quando parlo di "corrispondenza di modelli", parlo della corrispondenza del modello nella programmazione funzionale, non delle espressioni regolari. Le espressioni regolari sono insufficienti per dare un senso ai linguaggi irregolari, questo include circa ogni linguaggio utile - semplicemente permettendo espressioni di dimensioni abnormi, comprese parentesi equilibrate, esclude le espressioni regolari. Vedi la risposta accettata su What is 'Pattern Matching' in functional languages? per un'eccellente introduzione all'abbinamento dei pattern e magari imparare un linguaggio funzionale come Haskell o O'Caml se solo per imparare come usarlo e come elaborare gli alberi (e ci sono un sacco di altre fantastiche funzionalità !).

Ora nella lingua che proponi: Onestamente, dubito che sarebbe utile. Lo stesso C++ è un perfetto esempio di come non progettare un linguaggio (a meno che non si voglia avere successo): prendi uno esistente, resta compatibile con le versioni precedenti = mantieni tutto (comprese le cose cattive) e aggiungi un sacco di nuove funzionalità che sono abbastanza complessi da soli, quindi li modificano migliaia di volte e aggiungono un centinaio di casi speciali per lavorare più o meno con la sintassi e la semantica della lingua esistente. Rende il successo più probabile (se la lingua con cui hai iniziato è già popolare), ma finisci con una bestia arcana e inelegante. Detto questo, mi piacerebbe davvero vedere un linguaggio non-Lisp che consente macro di tale potenza.

Il modo giusto (o almeno migliore) sarebbe ripensare ogni singolo bit, dalla semantica di base alla sintassi esatta, integrarlo con ciò che si desidera aggiungere e modificare tutte le parti del linguaggio appena formato fino a quando l'intera immagine sembra giusta. Nel tuo caso, questo avrebbe un estremamente conveniente effetto collaterale: Facilità di analisi. Ovviamente, l'origine deve essere analizzata prima che le macro possano essere applicate, poiché riguardano se stesse con un albero, non con frammenti di stringhe. Ma C++ è molto difficile da analizzare. Come, letteralmente, il linguaggio più difficile da usare nell'uso comune.

Oh, mentre ci siamo: i macros stessi possono rendere miserabile la vita dei nostri strumenti preferiti (IDE con completamento automatico e suggerimenti di chiamata, analisi del codice statico, ecc. Pp). Rendere il senso di un pezzo di codice è abbastanza difficile, ma diventa anche peggio se questo codice verrà trasformato in modo abituale, e possibilmente molto pesante, prima che raggiunga il modulo che viene eseguito. In generale, gli strumenti di analisi del codice non sono in grado di gestire le macro. L'intera area è così difficile che è clever people make up new languages for research on it and write papers on it neither of us can comprehend. Quindi tieni presente che le macro hanno aspetti negativi.