Implementa Anyfix Notation!


16

Nella notazione con prefisso, l'operatore precede gli argomenti, quindi è possibile immaginare che l'operatore chiami next()che viene chiamato ricorsivamente. Nella notazione infissa, l'operatore passa tra gli argomenti, quindi puoi immaginarlo semplicemente come un albero di analisi. Nella notazione postfix, l'operatore segue gli argomenti, quindi puoi solo immaginarlo come basato sullo stack.

In ogni notazione di correzione, l'operatore può andare ovunque * . Se un operatore si presenta e non ci sono abbastanza argomenti, allora l'operatore attende fino a quando non ci sono abbastanza argomenti. Per questa sfida, devi implementare un valutatore anyfix di base. (Nota che anyfix è un linguaggio ricreativo che ho abbandonato e che puoi giocare qui o controllare qui )

Dovrai supportare i seguenti comandi:

(Arity 1)

  • duplicare
  • negativo

(Arity 2)

  • aggiunta
  • moltiplicazione
  • uguaglianza: restituisce 0o 1.

È possibile scegliere di utilizzare cinque simboli diversi dagli spazi bianchi per questi comandi. A scopo dimostrativo, userò "come duplicato, ×come moltiplicazione e +come aggiunta.

Per i letterali, devi solo supportare numeri interi non negativi, ma l'interprete deve essere in grado di contenere tutti i numeri interi (all'interno dell'intervallo (ragionevole) di numeri interi della tua lingua).

Diamo un'occhiata a un esempio: 10+5. La memoria dovrebbe comportarsi come uno stack, non una coda. Quindi, per prima cosa, lo stack inizia alle []e l'elenco degli operatori in coda inizia alle []. Quindi, 10viene valutato il valore letterale che rende lo stack [10]. Successivamente, +viene valutato l'operatore , che richiede due argomenti. Tuttavia, esiste solo un argomento nello stack, quindi l'elenco degli operatori in coda diventa ['+']. Quindi, 5viene valutato il valore letterale che rende lo stack [10, 5]. A questo punto, l'operatore '+'può essere valutato così com'è, creando lo stack [15]e la coda [].

Il risultato finale dovrebbe essere [15]per + 10 5, 10 + 5e 10 5 +.

Diamo un'occhiata a un esempio più difficile: 10+". Lo stack e la coda iniziano come []e []. 10viene valutato per primo il che rende lo stack [10]. Successivamente, +viene valutato, che non modifica lo stack (perché non ci sono argomenti sufficienti) e rende la coda ['+']. Quindi, "viene valutato. Questo può essere eseguito immediatamente così com'è, facendo lo stack [10, 10]. +ora può essere valutato in modo che lo stack diventi [20]e la coda []. Il risultato finale è [20].

Che dire dell'ordine delle operazioni?

Diamo un'occhiata a ×+"10 10. Lo stack e la coda iniziano entrambi come []:

  • ×: Lo stack rimane invariato e la coda diventa ['×'].
  • +: Lo stack rimane invariato e la coda diventa ['×', '+'].
  • ": Lo stack rimane invariato e la coda diventa ['×', '+', '"'].
  • 10: Lo stack diventa [10]. Anche se ×dovrebbe essere il primo operatore a essere valutato in quanto appare per primo, "può essere eseguito immediatamente e nessuno degli operatori prima di esso può, quindi viene valutato. Lo stack diventa [10, 10]e la coda ['×', '+']. ×ora può essere valutato, il che rende lo stack [100]e la coda ['+'].
  • 10: Lo stack diventa [100, 10], il che consente +di essere valutato. Lo stack diventa [110]e la coda [].

Il risultato finale è [110].

I comandi utilizzati in queste dimostrazioni sono coerenti con quelli del linguaggio anyfix; tuttavia, l'ultimo esempio non funzionerà a causa di un bug nel mio interprete. (Dichiarazione di non responsabilità: i tuoi invii non verranno utilizzati nell'interprete anyfix)

Sfida

Seleziona un set di 5 caratteri non numerici non bianchi e crea un interprete anyfix secondo le specifiche sopra. Il tuo programma può emettere l'array singolare o il valore da esso contenuto; è garantito che la pila di valori conterrà un solo valore alla fine dell'esecuzione e che la coda degli operatori sarà vuota alla fine dell'esecuzione.

Questo è quindi vince il codice più breve in byte.

Casi test

Per questi casi di test, il duplicato è ", il negativo è -, l'addizione è +, la moltiplicazione è ×e l'uguaglianza è =.

Input -> Output
1+2×3 -> 9
1"+"+ -> 4
2"××" -> 16
3"×+" -> 18
3"+×" -> 36
123"= -> 1 ("= always gives 1)
1+2=3 -> 1
1"=2+ -> 3
1-2-+ -> -3
-1-2+ -> 3 (hehe, the `-1` becomes `+1` at the `-` rather than making the `2` a `-1`)
+×"10 10 -> 200 (after the 10 is duplicated (duplication is delayed), 10 + 10 is performed and then 20 * 10, giving 200)

Regole

  • Si applicano scappatoie standard
  • Puoi prendere l'interprete ufficiale anyfix e giocarlo a golf se lo desideri. Aspettati di perdere orribilmente.

L'input verrà dato come una stringa e l'output come una matrice, un singolo intero, fuori dalla rappresentazione di stringa di entrambi. Si può presumere che l'input conterrà solo spazi, cifre e i 5 caratteri scelti.

* Non attualmente


2
Vai ovunque * ™.
Jonathan Allan,

Qual è il risultato dell'operatore di uguaglianza? 0e 1?
Felix Palmen,

1
@JonathanAllan vedi sopra; Ho rimosso un comando rip
HyperNeutrino il

1
@RickHitchcock Certo.
HyperNeutrino,

1
Probabilmente dovresti includere ×+"10 10nei casi di test, o qualsiasi altro esempio che sia 1) usando uno spazio bianco e 2) ritardando l'uso dell'operatore duplicato (due cose che mi sono perso del tutto).
Arnauld,

Risposte:


5

JavaScript (ES6), 204 203 200 byte

Restituisce un numero intero.

e=>e.replace(/\d+|\S/g,v=>{for((1/v?s:v>','?u:b)[U='unshift'](v);!!u[0]/s[0]?s[U](u.pop()>'c'?s[0]:-S()):!!b[0]/s[1]?s[U](+eval(S(o=b.pop())+(o<'$'?'==':o)+S())):0;);},s=[],u=[],b=[],S=_=>s.shift())|s

Personaggi usati:

  • +: aggiunta
  • *: moltiplicazione
  • #: uguaglianza
  • d: duplicare
  • -: negativo

Casi test

Formattato e commentato

e => e.replace(                     // given an expression e, for each value v matching
  /\d+|\S/g, v => {                 // a group of digits or any other non-whitespace char.
    for(                            //   this loop processes as many operators as possible
      (                             //   insert v at the beginning of the relevant stack:
        1 / v ? s : v > ',' ? u : b //     either value, unary operator or binary operator
      )[U = 'unshift'](v);          //     (s[], u[] or b[] respectively)
      !!u[0] / s[0] ?               //   if there's at least 1 value and 1 unary operator:
        s[U](                       //     unshift into s[]:
          u.pop() > 'c' ?           //       for the duplicate operator:
            s[0]                    //         a copy of the last value
          :                         //       else, for the negative operator:
            -S()                    //         the opposite of the last value
        ) :                         //     end of unshift()
      !!b[0] / s[1] ?               //   if there's at least 2 values and 1 binary operator:
        s[U](                       //     unshift into s[]:
          +eval(                    //       the result of the following expression:
            S(o = b.pop()) +        //         the last value, followed by the
            (o < '$' ? '==' : o) +  //         binary operator o with '#' replaced by '=='
            S()                     //         followed by the penultimate value
          )                         //       end of eval()
        ) : 0;                      //     end of unshift()
    );                              //   end of for()
  },                                // end of replace() callback
  s = [],                           // initialize the value stack s[]
  u = [],                           // initialize the unary operator stack u[]
  b = [],                           // initialize the binary operator stack b[]
  S = _ => s.shift()                // S = helper function to shift from s[]
) | s                               // return the final result

Non pensare che funzioni per -1+-2. Restituisce 3 invece di -3.
Rick Hitchcock,

1
@RickHitchcock La mia comprensione è che il 2 ° -deve essere applicato -1immediatamente.
Arnauld,

Penserei che il secondo -sarebbe andato d'accordo con il 2fatto che arriva dopo un altro operatore. Forse @HyperNeutrino può chiarire. L'operatore negativo può essere ambiguo in alcune situazioni.
Rick Hitchcock,

3

JavaScript (ES6), 162 152 143 150 byte

(s,N=s.replace(/(-?\d+)-|-(-)/g,'- $1 ').match(/(- ?)*?\d+|R/g))=>+eval(`R=${N[0]>'9'?N[1]:N[0]},${s.match(/[+*=]/g).map((o,i)=>'R=R'+o+'='+N[i+1])}`)

Leggermente non golfato:

(s,
 N=s.replace(/(-?\d+)-|-(-)/g,'- $1 ').      //change postfix negatives to prefix,
                                             //and change "--" to "- - "
     match(/(- ?)*?\d+|R/g)                  //grab numbers and duplicates
)=>+eval(`R=${N[0] > '9' ?  N[1] : N[0]},    //handle a delayed duplicate
          ${s.match(/[+*=]/g).               //grab the operators
              map((o,i)=>'R=R'+o+'='+N[i+1]) //create a comma-separated list of assignments
           }
         `)

Spiegazione

Sto usando *per la moltiplicazione e Rper i duplicati. Gli altri operatori sono gli stessi della domanda.

N diventa l'array dei numeri (inclusi i duplicati).

Il replacegestisce il caso in cui il segno negativo arriva dopo il numero. Ad esempio, cambierà 1-in - 1e -1-in - -1.

All'interno di eval, s.matchcrea la matrice di operatori binari. Si noti che questo avrà sempre uno in meno di elementi N.

Il risultato della funzione è evalla mappatura dei numeri e degli operatori.

Ecco cosa viene modificato evalper ciascuno dei casi di test:

0+2*3        R=0,R=R+=2,R=R*=3        = 6 
1+2*3        R=1,R=R+=2,R=R*=3        = 9 
1R+R+        R=1,R=R+=R,R=R+=R        = 4 
2R**R        R=2,R=R*=R,R=R*=R        = 16 
3R*+R        R=3,R=R*=R,R=R+=R        = 18 
3R+*R        R=3,R=R+=R,R=R*=R        = 36 
123R=        R=123,R=R==R             = 1 
1+2=3        R=1,R=R+=2,R=R==3        = 1 
1R=2+        R=1,R=R==R,R=R+=2        = 3 
1-2-+        R=- 1,R=R+=- 2           = -3 
-1-2+        R=1,R=R+=2               = 3 
*+R10 10     R=10,R=R*=10,R=R+=10     = 110 
+*R10 10     R=10,R=R+=10,R=R*=10     = 200 
-1+--2       R=-1,R=R+=- -2           = 1 
-1+-2        R=-1,R=R+=-2             = -3 

L'operatore virgola in un'espressione JavaScript restituisce il risultato della sua ultima espressione, quindi maprestituisce automaticamente un'espressione utilizzabile.

Il +segno è necessario prima evaldi cambiare truein 1e falsein 0.

L'uso Rcome variabile e l'operatore duplicato semplifica notevolmente le mapsottoespressioni della parola.

Casi test:


2
Non penso che le replaceopere funzionino come previsto. Questo ritorna 3per -1+--2e penso che 1sarebbe corretto (le 1modifiche firmano tre volte prima che ci sia un secondo argomento per il +disponibile, risultante -1 + 2).
Felix Palmen,

Ottima cattura, @FelixPalmen. Ora risolto.
Rick Hitchcock,

2

JavaScript, 321 311 byte

_="f=a=>(a.replace(/\\d+|./g,mq!~(b='+*=\"- '.indexOf(a))|b>2j3j4j5&&o+aw1/y?(y*=-1wcz:1/y?oywcz:hz,rql.map(z=>m(lki,1)[0],i)),hq1/s[1]?sk0,2,+eval(`y${a=='='?a+a:a}s[1]`)):cz,cqlki,0,a),s=[],l=[],e='splice'),s)z(a,i)ys[0]w)^r``:q=z=>os.unshift(k[e](j?b-";for(i of"jkoqwyz")with(_.split(i))_=join(pop());eval(_)

Provalo online!

I cinque caratteri sono gli stessi della domanda, tranne *per la moltiplicazione.
Lo script viene compresso utilizzando RegPack . Lo script originale viene archiviato nella variabile _dopo la valutazione.


Non pensare che funzioni per -1+-2. Restituisce 3 invece di -3.
Rick Hitchcock,

@RickHitchcock. Perché credi che dovrebbe tornare -3invece di 3?

Potrei fraintendere l'operatore negativo. Generalmente lo -1 + -2è -3, ma dovrebbe essere analizzato come --1 + 2invece?
Rick Hitchcock,

1
@RickHitchcock. Sono abbastanza sicuro che il risultato sia 3. Prima 2ancora di arrivare in pila, il secondo -viene valutato e quindi abbiamo quello 1 2 +che è davvero 3. Ah, e probabilmente anche tu devi modificare la tua risposta.

Probabilmente hai ragione. Tu e Arnauld ottenete la stessa risposta e ho chiesto chiarimenti all'OP. Ti voterei di nuovo se potessi.
Rick Hitchcock,

1

Haskell , 251 byte

(#([],[]))
(x:r)#(o,n)|x>'9'=r#h(o++[x],n)|[(a,t)]<-lex$x:r=t#h(o,read a:n)
_#(o,n:_)=n
h=e.e
e(o:s,n:m:r)|o>'N'=e(s,g[o]n m:r)
e(o:s,n:r)|o=='D'=e(s,n:n:r)|o=='N'=e(s,-n:r)
e(o:s,n)|(p,m)<-e(s,n)=(o:p,m)
e t=t
g"a"=(+)
g"m"=(*)
g"q"=(((0^).abs).).(-)

Provalo online! Utilizza i seguenti caratteri: aper aggiunta, mper moltiplicazione, qper uguaglianza, Dper duplicato e Nper negazione. (Volevo usare eper l'uguaglianza, ma ho lexriscontrato il problema che analizza 2e3come un numero.) Esempio di utilizzo: (#([],[])) "2a3 4m"rendimenti 20.


1

6502 codice macchina (C64), 697 byte

00 C0 A2 00 86 29 86 26 86 27 86 28 86 4B 86 4C 86 CC 20 E4 FF F0 FB C9 0D F0
10 C9 20 30 F3 A6 27 9D B7 C2 20 D2 FF E6 27 D0 E7 C6 CC A9 20 20 1C EA A9 0D
20 D2 FF 20 95 C0 20 09 C1 20 95 C0 A6 26 E4 27 F0 4E BD B7 C2 E6 26 C9 20 F0
E8 C9 2D D0 09 A6 4C A9 01 9D B7 C3 D0 32 C9 22 D0 09 A6 4C A9 02 9D B7 C3 D0
25 C9 2B D0 09 A6 4C A9 81 9D B7 C3 D0 18 C9 2A D0 09 A6 4C A9 82 9D B7 C3 D0
0B C9 3D D0 0D A6 4C A9 83 9D B7 C3 E6 28 E6 4C D0 A3 4C 8A C2 A6 29 F0 6F A4
28 F0 6B CA F0 4B C6 28 A6 4B E6 4B BD B7 C3 F0 F5 30 14 AA CA D0 0B 20 7B C2
20 E1 C1 20 4D C2 D0 D9 20 5C C2 D0 D4 29 0F AA CA D0 0B 20 6D C2 20 08 C2 20
4D C2 D0 C3 CA D0 0B 20 6D C2 20 16 C2 20 4D C2 D0 B5 20 6D C2 20 F4 C1 20 4D
C2 D0 AA A4 4B B9 B7 C3 F0 02 10 AC C8 C4 4C F0 0F B9 B7 C3 F0 F6 30 F4 AA A9
00 99 B7 C3 F0 A6 60 A0 00 A6 26 E4 27 F0 15 BD B7 C2 C9 30 30 0E C9 3A 10 0A
E6 26 99 37 C4 C8 C0 05 D0 E5 C0 00 F0 08 A9 00 99 37 C4 20 39 C2 60 A2 FF E8
BD 37 C4 D0 FA A0 06 88 CA 30 0A BD 37 C4 29 0F 99 37 C4 10 F2 A9 00 99 37 C4
88 10 F8 A9 00 8D 3D C4 8D 3E C4 A2 10 A0 7B 18 B9 BD C3 90 02 09 10 4A 99 BD
C3 C8 10 F2 6E 3E C4 6E 3D C4 CA D0 01 60 A0 04 B9 38 C4 C9 08 30 05 E9 03 99
38 C4 88 10 F1 30 D2 A2 06 A9 00 9D 36 C4 CA D0 FA A2 10 A0 04 B9 38 C4 C9 05
30 05 69 02 99 38 C4 88 10 F1 A0 04 0E 3D C4 2E 3E C4 B9 38 C4 2A C9 10 29 0F
99 38 C4 88 10 F2 CA D0 D6 C0 05 F0 06 C8 B9 37 C4 F0 F6 09 30 9D 37 C4 E8 C8
C0 06 F0 05 B9 37 C4 90 F0 A9 00 9D 37 C4 60 A9 FF 45 FC 85 9F A9 FF 45 FB 85
9E E6 9E D0 02 E6 9F 60 A2 00 86 9F A5 FB C5 FD D0 07 A5 FC C5 FE D0 01 E8 86
9E 60 A5 FB 18 65 FD 85 9E A5 FC 65 FE 85 9F 60 A9 00 85 9E 85 9F A2 10 46 FC
66 FB 90 0D A5 FD 18 65 9E 85 9E A5 FE 65 9F 85 9F 06 FD 26 FE CA 10 E6 60 20
33 C1 A6 29 AD 3D C4 9D 3F C4 AD 3E C4 9D 3F C5 E6 29 60 A6 29 A5 9E 9D 3F C4
A5 9F 9D 3F C5 E6 29 60 A6 29 BD 3E C4 9D 3F C4 BD 3E C5 9D 3F C5 E6 29 60 C6
29 A6 29 BD 3F C4 85 FD BD 3F C5 85 FE C6 29 A6 29 BD 3F C4 85 FB BD 3F C5 85
FC 60 A6 29 BD 3E C5 10 13 20 7B C2 20 E1 C1 20 4D C2 A9 2D 20 D2 FF A6 29 BD
3E C5 8D 3E C4 BD 3E C4 8D 3D C4 20 8B C1 A9 37 A0 C4 4C 1E AB

Demo online

Utilizzo sys49152 , quindi immettere l'espressione anyfix e premere Invio.

  • vicino a nessun controllo degli errori, quindi aspettati output divertenti su espressioni non valide.
  • il simbolo per la moltiplicazione è *, tutti gli altri come suggerito.
  • la lunghezza massima di input è di 256 caratteri, non ci possono essere più di 127 operatori in coda.
  • La routine di input non gestisce i caratteri di controllo, quindi non digitare male;)
  • gli interi sono firmati a 16 bit, l'overflow si avvolgerà silenziosamente.
  • il conteggio dei byte è un po 'grande perché questa CPU non conosce nemmeno la moltiplicazione e l'OS / ROM C64 non fornisce alcuna aritmetica intera o conversione da / verso stringhe decimali.

Ecco il codice sorgente dell'assembler in stile ca65 leggibile .


1

VB.NET (.NET 4.5) 615 576 byte

-39 byte grazie a Felix Palmen passando \r\na\n

Richiede Imports System.Collections.Generic(incluso nel conteggio byte)

Dim s=New Stack(Of Long),q=New List(Of String),i=Nothing,t=0,c=0
Function A(n)
For Each c In n
If Long.TryParse(c,t)Then
i=i &"0"+t
Else
If c<>" "Then q.Add(c)
If i<>A Then s.Push(i)
i=A
End If
If i=A Then E
Next
If i<>A Then s.Push(i)
E
A=s
End Function
Sub E()
c=s.Count
If c=0Then Exit Sub
For Each op In q
If op="-"Or op="d"Or c>1Then
Select Case op
Case"*"
s.Push(s.Pop*s.Pop)
Case"+"
s.Push(s.Pop+s.Pop)
Case"="
s.Push(-(s.Pop=s.Pop))
Case"-"
s.Push(-s.Pop)
Case"d"
s.Push(s.Peek)
End Select
q.Remove(op)
E
Exit Sub
End If
Next
End Sub

Il punto di ingresso è Funzione A, che accetta una stringa come input e restituisce a Stack(Of Long).

simboli:

  • Aggiunta - +
  • Moltiplicazione - *
  • Uguaglianza - =
  • Negazione - -
  • Duplicazione - d

Panoramica:

La funzione Aaccetta l'input e lo tokenizza. Usa a Long?per eseguire un totale parziale per numeri interi a più cifre, il che Nothingsignifica che al momento non stiamo leggendo un numero intero.

La subroutine Eprende lo stack di numeri interi e la coda di operatori e valuta la notazione anyfix. Si chiama ricorsivamente fino a quando non rimangono più azioni.

Dichiaro tutti i parametri globali in una volta sola per salvare byte sia sulla dichiarazione che sul passaggio dei parametri.

Il valore restituito da Aviene impostato assegnando un valore alla variabile corrispondente A.

VB Trueè equivalente a -1, quindi l'operazione deve annullare il risultato per ottenere il valore corretto.

Provalo online!


suggerisci di aggiungere Provalo online!
Felix Palmen,

tra l'altro, con Imports, ottengo solo un conteggio di byte 576- potresti aver contato male?
Felix Palmen,

@FelixPalmen ho contato \r\ninvece di \n, quindi è lì che sta la discrepanza.
Brian J,

@FelixPalmen Aggiunto TIO, grazie per avermelo ricordato! :) (Oh, non avevo capito che ce l'hai già fatta per questo post)
Brian J
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.