Lingue come Tcl che hanno sintassi configurabile? [duplicare]

-1

Sto cercando un linguaggio che mi permetta di fare quello che potrei fare con Clipper anni fa, e che posso fare con Tcl, ovvero aggiungere funzionalità in un modo diverso dalla semplice aggiunta di funzioni.

Ad esempio in Clipper / (x) Harbor ci sono i comandi #command, #translate, #xcommand e #xtranslate che permettono cose come questa:

#xcommand REPEAT; 
   => DO WHILE .T. 
#xcommand UNTIL <cond>; 
  =>     IF (<cond>); 
             ;EXIT; 
         ;ENDIF; 
     ;ENDDO 

LOCAL n := 1
REPEAT
    n := n + 1
UNTIL n > 100

Allo stesso modo, in Tcl sto facendo

proc process_range {_for_ project _from_ dat1 _to_ dat2 _by_ slice} {
    set fromDate [clock scan $dat1]
    set toDate   [clock scan $dat2]

    if {$slice eq "day"} then {set incrementor [expr 24 * 60]}
    if {$slice eq "hour"} then {set incrementor 60}

    set method DateRange

    puts "Scanning from [clock format $fromDate -format "%c"] to [clock format $toDate -format "%c"] by $slice"
    for {set dateCursor $fromDate} {$dateCursor <= $toDate} {set dateCursor [clock add $dateCursor $incrementor minutes]} {
        # ...
    }
}
process_range for "client" from "2013-10-18 00:00" to "2013-10-20 23:59" by day

Esistono altri linguaggi che consentono questo tipo di modifica della sintassi, quasi COBOL-esque?

Se ti stai chiedendo perché lo sto chiedendo, è per l'impostazione di cose in modo che altre persone con uno skillset non-as-geek-as-I-am possano dichiarare attività di elaborazione.

    
posta bugmagnet 20.10.2013 - 15:41
fonte

2 risposte

1

Ci sono molte lingue là fuori che sono abbastanza flessibili. Molte lingue (spesso più recenti) sono orgogliose della loro idoneità per i linguaggi specifici del dominio (DSL). Tuttavia, alcuni dei tuoi esempi necessitano di alcuni sistemi macro.

Alcune lingue che utilizzano in modo evidente macro:

  • Lisp e discendenti. Funzionano come sostituzioni ASTA (Abstract Syntax Tree).
  • C, C ++. Il preprocessore C utilizza la sottotitolazione a livello di token ed è meno potente delle macro Lisp. Il tuo primo esempio può essere tradotto direttamente in macro C:

    // untested
    #define repeat for(;;) {
    #define until(cond) if(cond) break; }
    
    auto n = 1;
    repeat {
      n++;
    } until(n > 100)
    

Molte lingue consentono di chiamare le funzioni con parole chiave. Gli esempi includono

  • Lisps come Common Lisp.
  • Smalltalk e discendenti.
  • Python:
  • Alcune lingue hanno una sintassi che consente di simulare argomenti con nome, ad es.

    • molte interfacce della riga di comando:

      git commit --file=foo.txt --message="Some fixes" --author=me
      
    • Qualsiasi lingua con i letterali del dizionario
      • Perl.
      • Javascript: foo.bar({ x: 42, y: somethingElse }) .

Le lingue che hanno funzioni letterali / lambda / chiusure non richiedono macro per definire un nuovo flusso di controllo.

  • Qualsiasi linguaggio funzionale, ad es. Lisps, ML
  • Smalltalk e discendenti. Particolarmente degno di nota è Ruby con i suoi onnipresenti blocchi do ... end .
  • Con sintassi maldestra: C ++ 11, Perl, Javascript.

Ci sono alcune lingue che hanno una visione flessibile degli operatori, in modo che molti segni di punteggiatura come le chiamate di funzione, ecc. possano essere lasciati fuori. Un esempio sarebbe Scala.

    
risposta data 20.10.2013 - 16:20
fonte
4

Le macro Lisp sono probabilmente un buon esempio del tipo di funzionalità che stai cercando. Fondamentalmente ti permettono di estendere la lingua in modi relativamente arbitrari.

In effetti, una macro è una funzione che viene eseguita in fase di compilazione e può produrre qualsiasi codice tu voglia. I Lisps sono adatti a questo tipo di tecnica perché sono omoiconic - il che significa che il codice è esso stesso espresso nelle strutture dati Lisp. Quindi la tua macro ha solo bisogno di produrre una struttura dati che rappresenti il codice che vuoi.

Ecco un esempio di Clojure che aggiunge un ciclo di stile for C alla lingua:

(defmacro for-loop 
  "Runs an imperative for loop, binding sym to init, running code as long as check is true, 
  updating sym according to change"
  ([[sym init check change :as params] & code]
    '(loop [~sym ~init value# nil]
       (if ~check
         (recur ~change (do ~@code))
         value#))))

(for-loop [i, 0, (< i 10), (inc i)]
  (println i))
=> prints the numbers from 0 to 9 inclusive as you would expect

Come puoi vedere, bastano poche righe di codice per aggiungere un nuovo costrutto linguistico.

Un avvertimento: questa è una tecnica potente e dovrebbe essere usata con cura. In generale, non dovresti usare una macro quando una normale funzione farebbe il lavoro.

    
risposta data 20.10.2013 - 16:15
fonte

Leggi altre domande sui tag