È possibile implementare l'overloading dell'operatore con variabile arity?

2

Implementazione dell'overloading dell'operatore per es. + (più) non è terribilmente difficile se sai che è un operatore binario. Uno può solo analizzare expression + expression

Ma cosa succede se il programmatore può scegliere se + è binario, unario (prefisso / postfix), parte di un ternario o qualcos'altro? Per es.

  • .. ? .. : ..
  • ..²
  • .. | .. | .. | .. | ..
  • .. 大 .. 小 ..
  • 不 ..

Il problema sembra essere che l'arity dovrebbe essere noto al tempo di analisi, ma non lo è, è noto solo dopo l'intera compilazione / transpolazione.

Alcune idee:

  • Penso che l'intero tipo di problema vada via passando alla sintassi simile a Lisp (non ancora abbastanza familiare con Lisp), ma lo renderò difficile dicendo che la sintassi deve essere un po 'come quella di C esempi.
  • Una sorta di restrizione come avere sovraccarichi nella parte superiore / in un file separato in modo che possano essere compilati per primi.
  • (Forse Arity deve essere corretto per ogni simbolo - in realtà non risponde alla domanda).

C'è un modo che non è terribile?

Diventa più possibile assumendo che gli operatori possano essere distinti dagli altri identificatori nella fase di analisi (ad esempio altri identificatori sono alfanumerici)?

    
posta Mark 19.08.2017 - 17:34
fonte

2 risposte

4

Se un linguaggio supporta operatori definiti dall'utente (al contrario del sovraccarico di operatori esistenti), allora la lingua è generalmente strutturata in modo tale che l'arità, l'associatività e la precedenza siano note al tempo di analisi!

Ovviamente, questo impedisce anche di usare un generatore di parser run-of-the-mill, ma ci sono alternative (come scrivere un parser a mano).

Un operatore deve essere dichiarato prima viene utilizzato. Questo è simile al modo in cui le funzioni C / C ++ devono essere dichiarate prima di essere chiamate.

Esempio: Haskell. Qui gli operatori possono essere dichiarati liberamente da una serie di caratteri consentiti. Puoi specificare l'associatività, l'arità e il livello di precedenza con una dichiarazione come infixr 5 ** . Altrimenti, gli operatori sono dichiarati come funzioni ordinarie, ad es. %codice%. Quando gli operatori sono racchiusi da uno o entrambi i lati con parentesi, perdono la loro arità, ad es. possiamo scrivere equivalentemente (++) a b = concat a b , a + b , (a +) b , (+ b) a .

Esempio: Scala. Negli operatori di Scala sono solo metodi normali e non è necessario richiamare metodi con notazione a punti: quindi (+) a b equivale a a.m(b) . Quindi se definiamo un metodo chiamato a m b possiamo scrivere ++ . Alcuni operatori sono più speciali e possono essere sovraccaricati solo con metodi appositamente denominati, ad es. l'operatore di chiamata di funzione con il metodo a ++ b . Il livello di precedenza di un operatore è determinato dal primo carattere nell'operatore. Quindi gli operatori apply() , + e +* hanno tutti la stessa precedenza.

Esempio: Perl6. La lingua Perl6 include un potente motore di grammatica. Nuove regole possono essere aggiunte alla grammatica al volo, ad esempio dichiarando una subroutine come operatore. Un operatore viene sempre dichiarato con un'arità, quindi +| , multi sub prefix:<++>($x) e multi sub infix:<++>($x, $y) possono coesistere come operatori diversi. Gli operatori non sono limitati ai simboli ma possono anche contenere lettere. Tutto sommato, il sistema operativo di questo linguaggio è estremamente complesso e flessibile.

    
risposta data 19.08.2017 - 18:27
fonte
2

Non hai menzionato la lingua.

In Swift, c'è prima una sintassi per le sequenze di caratteri che potrebbero essere operatori. Ad esempio, "+" è un operatore non perché è incorporato nella lingua, ma perché è implementato come parte della libreria standard.

In secondo luogo, esiste una sintassi che determina se un operatore è un operatore unario o binario. In A + B o A + B il "+" è un operatore binario, in A * + B è un operatore unario. (A * + B avrebbe un operatore binario * +).

Con questa sintassi, l'operatore viene trovato e quindi viene trattato in modo molto simile a una chiamata di funzione. Se l'operatore non viene trovato, è proprio come la sintassi della chiamata della funzione per un nome di funzione non definito. (Ho omesso la precedenza dell'operatore e l'associatività sinistra o destra, definite per operatore).

Quindi puoi facilmente definire un operatore unario * + per esempio, e un operatore binario * +, e il compilatore non ha problemi a tenerli separati. (I principianti Swift sono spesso sorpresi dal fatto che a + b o a + b non si compilano).

    
risposta data 19.08.2017 - 18:42
fonte

Leggi altre domande sui tag