La sintassi dei linguaggi di programmazione dipende dalla loro implementazione?

12

Anche se, la mia domanda potrebbe essere del tutto irrilevante, ma ho percepito un modello tra la maggior parte dei linguaggi di programmazione e le loro implementazioni ufficiali.

I linguaggi interpretati (interpretati da byte?) come Python, Lua ecc. di solito hanno una sintassi estremamente leggera e facile e generalmente non sono di tipo o non richiedono che lo sviluppatore scriva esplicitamente i tipi di variabile in codice sorgente;

I linguaggi compilati come C, C ++, Pascal ecc. di solito hanno una sintassi rigorosa, generalmente hanno tipi e per lo più richiedono più tempo per codice / sviluppo

Le lingue le cui implementazioni ufficiali sono JIT-Compiled come Java / C # di solito rappresentano un compromesso unico tra i due precedenti con alcune delle migliori caratteristiche di entrambi.

Alcuni dei più moderni linguaggi di programmazione compilati come D e Vala (e l'implementazione GNU GJC di Java) sono forse un'eccezione a questa regola e assomigliano alla sintassi e alle caratteristiche dei linguaggi JIT-compilati come Java e C #.

La mia prima domanda è, è davvero rilevante? O è solo una coincidenza che le lingue più interpretate abbiano una sintassi semplice, quelle con JIT hanno una sintassi moderata e caratteristiche ecc.

In secondo luogo, se questa non è una coincidenza, allora perché è così? Ad esempio, alcune funzionalità possono essere implementate solo in un linguaggio di programmazione se si è, per esempio, JIT-Compilandolo?

    
posta ApprenticeHacker 21.12.2011 - 07:24
fonte

5 risposte

17

Non esiste alcuna connessione tra semantica e sintassi. I linguaggi compilati omoiconici come Scheme hanno una sintassi piuttosto minimalista. I meta-linguaggi compilati di basso livello come Forth sono ancora più semplici di così. Alcuni linguaggi compilati molto tipicamente sono costruiti su una sintassi banale (pensa ML, Haskell). OTOH, la sintassi di Python è molto pesante, in termini di una serie di regole di sintassi.

E sì, la digitazione non ha nulla a che fare con la sintassi, è sul lato semantico di una lingua, a meno che non sia qualcosa di pervertito come C ++, dove non si può nemmeno analizzare senza avere tutte le informazioni di digitazione disponibili.

Una tendenza generale è che i linguaggi che si sono evoluti troppo a lungo e non contenevano alcuna protezione di progettazione contro le deviazioni di sintassi prima o poi si sarebbero evoluti in abomini sintattici.

    
risposta data 21.12.2011 - 09:25
fonte
6

Per lo più questa è una coincidenza.

I linguaggi di programmazione si sono evoluti nel tempo e la tecnologia dei compilatori e degli interpreti è migliorata. L'efficienza dell'elaborazione sottostante (ossia il tempo di compilazione, l'overhead di interpretazione, il tempo di esecuzione ecc.) È anche meno importante in quanto le piattaforme di elaborazione mainstream sono cresciute al potere.

La sintassi della lingua ha ha un impatto - ad esempio, Pascal è stato progettato con molta attenzione in modo da poter utilizzare un compilatore a passaggio singolo, vale a dire un passaggio sull'origine e un codice macchina excutable. Ada d'altra parte non ha prestato attenzione a questo, e i compilatori Ada sono notoriamente difficili da scrivere - la maggior parte richiede più di un passaggio. (Un ottimo compilatore Ada che ho utilizzato molti anni fa era un compilatore a 8 passaggi. Come puoi immaginare, è stato molto lento.)

Se guardi a linguaggi vecchi come Fortran (compilato) e BASIC (interpretato o compilato) hanno / hanno una sintassi molto severa e regole semantiche. [Nel caso di BASIC, questo non è Bills vecchio BASIC, è necessario tornare prima di quello all'originale.]

D'altra parte, guardando altre cose più vecchie come APL (un sacco di divertimento) questo ha avuto una digitazione dinamica, di sorta. Inoltre è stato generalmente interpretato ma potrebbe essere compilato anche.

La sintassi clemente è difficile - se ciò significa che hai cose che sono opzionali o che puoi dedurre, significa che il linguaggio ha una ricchezza sufficiente da poter essere abbattuto. Poi di nuovo, BASIC ha avuto tanti anni fa quando la dichiarazione "LET" divenne opzionale!

Molte delle idee che ora vedi (ad esempio, digitazione senza tipizzazione o dinamica) sono in realtà molto vecchie, per la prima volta negli anni '70 o all'inizio degli anni '80. Il modo in cui vengono utilizzati e le lingue in cui queste idee sono usate sono cambiate e cresciute. Ma fondamentalmente, gran parte di ciò che è nuovo è in realtà roba vecchia vestita con abiti nuovi.

Ecco alcuni esempi in cima alla mia testa:

  • APL: digitazione dinamica. Generalmente interpretato. È venuto dagli anni '60 / '70.
  • BASIC: digitazione strong o dinamica. Interpretato o compilato. Anni '70 e molti altri.
  • Fortran: strong tipizzazione. Compilato. Anni '60 o precedenti.
  • Algol68: strong tipizzazione. Compilato. 1960.
  • PL / 1: strong tipizzazione. Compilato. 1960.
  • Pascal: strong tipizzazione. Compilato. 1970. (Ma negli anni '80 c'erano compilatori P-System molto simili ai compilatori JIT!)
  • Alcune implementazioni di Fortran e altri di DEC nei primi giorni sono state parzialmente compilate e parzialmente interpretate.
  • Smalltalk: digitazione dinamica. Compilato in bytecode che viene interpretato. 1980.
  • Prolog: più stranezza. Funzionale. Compilato (Turbo Prolog, nessuno?). 1980.
  • C: strong (ah ah) digitando. Compilato. 1960's..today.
  • Ada: digitazione strong. Compilato. 1980.
  • Perl: digitazione dinamica. (strong sintassi). Interpretato. Anni '90 (?).

Potrei andare avanti.

  • Angolo Nitpickers: molti linguaggi interpretati vengono tokenizzati o "byte compilati" nel momento in cui la fonte viene caricata / letta. Questo rende molto più semplice la successiva operazione dell'interprete. A volte è possibile salvare la versione del codice compilata in byte. A volte non puoi. È ancora interpretato.

Aggiornamento: perché non ero abbastanza chiaro.

La digitazione può variare notevolmente.

La tipizzazione statica fissa in fase di compilazione è comune (ad esempio, C, Ada, C ++, Fortan, ecc. ecc.). Qui è dove si dichiara una COSA di un TIPO ed è così per sempre.

È anche possibile avere una digitazione dinamica, in cui la cosa preleva il tipo che gli viene assegnato. Ad esempio, PHP e alcuni primi BASIC e APL, dove si assegnerebbe un intero a una variabile e da quel momento in poi era un tipo intero. Se in seguito hai assegnato una stringa, era un tipo di stringa. E così via.

E poi c'è una digitazione libera, ad esempio PHP, dove puoi fare cose veramente bizzarre come assegnare un numero intero (quotato, quindi una stringa) ad una variabile e poi aggiungere un numero ad esso. (es. '5' + 5 risulterebbe in 10). Questa è la terra del bizzarro, ma anche a volte molto molto utile.

TUTTAVIA queste sono funzionalità progettate in una lingua. L'implementazione rende solo questo possibile.

    
risposta data 21.12.2011 - 08:08
fonte
2

Penso che sia il contrario: l'implementazione dipende dalla sintassi. Ad esempio, se la sintassi consente la riflessione, l'implementazione deve fornire un runtime che supporti tale.

    
risposta data 21.12.2011 - 09:43
fonte
2

In genere sono d'accordo con quick_now in quanto la tua osservazione è principalmente un risultato della storia. Detto questo, il ragionamento di base si riduce a qualcosa del genere:

The more modern a language is, the more comfortable it should be to use.

(Non una citazione in realtà, solo la mia stessa formulazione.) Quando scrivo comfortable qui, mi riferisco a ciò che hai chiamato best features of both . Più precisamente, non voglio parlare a favore o contro la tipizzazione statica / dinamica o la sintassi strict / lenient. Invece, è importante vedere l'attenzione rivolta agli sviluppatori e aumentare il loro livello di comfort quando si lavora con la lingua.

Ecco alcuni motivi, che non sono stati menzionati nelle risposte precedenti, che potrebbero fornirti alcune idee sul perché osservi queste cose (e sono tutte basate sulla storia della programmazione dello sviluppo di lanugage):

  • Abbiamo centinaia di lanugages di programmazione in questi giorni. Quando ne esce uno nuovo, come può trovare un vasto pubblico? Questo è il motivo principale per cui le nuove lingue cercano sempre di aumentare il livello di comfort degli sviluppatori. Se la lingua può fare lo stesso di una più vecchia, ma può farlo molto più facile / più semplice / più elegante / ecc. potresti prendere in considerazione la possibilità di cambiare.

  • La curva di apprendimento va di pari passo con quella. In passato avevamo poche lingue e investendo tempo per imparare ne valeva la pena. Anche se questo significava investire un sacco di tempo. Il comfort è di nuovo aumentato, se ti viene in mente un linguaggio che gli sviluppatori possono imparare molto rapidamente. Complessità di qualsiasi tipo (ad es. Complicata sintassi implicita) sono dannose per questo e, di conseguenza, si riducono sempre più nei nuovi linguaggi.

  • I progressi tecnologici (una ragione storica diretta qui) sono responsabili del fatto che i compilatori di compilatori possono ora concentrarsi maggiormente sul comfort degli sviluppatori. Nei primi giorni, eravamo felici di poter costruire un compilatore. Tuttavia, ciò implicava spesso pesanti restrizioni. Con l'aumento del know-how tecnologico, siamo stati in grado di rimuovere nuovamente queste restrizioni.

Quindi, in generale, i linguaggi di programmazione e i compilatori hanno visto uno sviluppo simile a quello delle tipiche applicazioni per utenti finali:

  1. Fase iniziale: è una cosa interessante da avere, ma la tecnologia all'avanguardia funziona a malapena a costo di comfort / usabilità / che non lo è.
  2. Miglioramento tecnologico: possiamo costruire queste cose in modo più robusto, più veloce e più facile.
  3. Il focus si rivolge all'utente: analogamente al movimento Web 2.0 incentrato sull'esperienza utente, i nuovi linguaggi di programmazione si concentrano sulla prospettiva dello sviluppatore.
risposta data 21.12.2011 - 09:45
fonte
0

Un dato linguaggio di programmazione può o meno esporre o limitare sufficienti informazioni semantiche per un compilatore per dedurre come ridurlo a codice eseguibile senza decisioni di runtime aggiunte ("che tipo è questa variabile?", ecc.) Alcune lingue sono esplicitamente progettato per rendere obbligatorio o facile determinare questo vincolo.

Man mano che i compilatori diventano più intelligenti, potrebbero essere in grado di indovinare o profilare informazioni sufficienti a generare codice eseguibile per i percorsi più probabili anche per le lingue che non sono state progettate esplicitamente per esporre o limitare tali decisioni.

Tuttavia, le lingue in cui il codice (evalString ()) può essere creato o immesso in fase di runtime (e altre cose che il compilatore non può dedurre o indovinare) potrebbero richiedere che un interprete o compilatore JIT sia disponibile in fase di runtime, anche con i tentativi per pre-compilarli.

In passato, un linguaggio di programmazione e la sua implementazione si sarebbero evoluti in modo da adattarsi ad alcuni vincoli hardware, come se l'interprete potesse adattarsi in 4k o 16k, o se il compilatore potesse finire in meno di un minuto di tempo della CPU . Man mano che le macchine diventano più veloci, è diventato possibile compilare (ri) compilare programmi precedentemente interpretati con la stessa rapidità con cui il programmatore può colpire la chiave di ritorno, o interpretare codice sorgente del programma precedentemente compilato più velocemente di quanto l'hardware leggermente più vecchio possa eseguire eseguibili compilati ottimizzati.

    
risposta data 21.12.2011 - 13:02
fonte

Leggi altre domande sui tag