Stampa, Incremento, Decremento, Alias ​​- Interpret Prindeal


30

Prindeal (pronunciato prin-dee-al ) è un nuovo linguaggio di programmazione esoterico che ha solo quattro comandi: pr int , in crement , de crement e al ias . Nonostante il suo minimalismo, in Prindeal è possibile eseguire complesse operazioni matematiche combinando abilmente i quattro comandi.

Il tuo compito in questa sfida di golf del codice è quello di scrivere il programma più breve in grado di eseguire il codice Prindeal.

Le specifiche sono lunghe ma ho cercato di renderlo il più chiaro possibile e credo che se fai lo sforzo di imparare Prindeal lo troverai abbastanza elegante!


Intrepreting Prindeal

Pre-elaborazione

Prima che un programma Prindeal possa essere interpretato, queste cose devono essere rimosse da esso in questo ordine:

  1. Qualunque cosa dopo un #segno alla fine della linea è attiva, più lo #stesso. (Questi sono commenti.)
  2. Spazio bianco finale su qualsiasi riga.
  3. Linee completamente vuote.

Ad esempio, il programma Prindeal

p cat #The next line has 7 trailing spaces.
p dog       

#p mouse

verrebbe preelaborato

p cat
p dog

D'ora in poi supponiamo che questo passaggio di preelaborazione sia stato eseguito.

variabili

Dobbiamo rapidamente definire le variabili prima di mostrare come vengono utilizzate.

Le variabili (e i riferimenti alle variabili) sono quelli che vengono passati agli argomenti dei comandi Prindeal. Le variabili sono sempre globali , quindi le modifiche a una variabile, indipendentemente da dove si verificano, si riflettono ovunque.

Ogni variabile contiene un numero intero di precisione arbitraria non negativa (0, 1, 2, 3, ...). Non è necessario pre-inizializzare le variabili: iniziano sempre con il valore 0 la prima volta che vengono utilizzate o richieste.

Un nome di variabile può essere qualsiasi stringa non vuota di caratteri alfanumerici e di sottolineatura che non inizia con una cifra - [a-zA-Z_][0-9a-zA-Z_]*in regex . Sono case sensitive, quindi spiny_lumpsuck3re Spiny_lumpsuck3rsono variabili diverse.

Esecuzione

Prindeal è un linguaggio di programmazione imperativo . Quando viene eseguito un programma Prindeal, le sue istruzioni vengono eseguite dall'alto verso il basso in ordine e quindi il programma termina.

Ogni riga non indentata in un programma Prindeal è un'istruzione che comporta l'esecuzione di un singolo comando che può o meno accettare argomenti.

Le linee rientrate si verificano solo dopo i comandi alias . In particolare, dopo ogni comando alias si verificano esattamente tre righe rientrate con spazi singoli e sono considerate parte di esso. Quindi le dichiarazioni alias sono davvero lunghe quattro righe. (Potrebbero essere una riga, quattro è semplicemente più leggibile.)

Dichiarazioni non alias

Con l'eccezione di alias , ogni affermazione in un programma Prindeal ha la forma:

[command name] [argument 1] [argument 2] [argument 3] ...

Potrebbe esserci un numero arbitrario di argomenti (incluso nessuno). Ogni argomento è sempre una variabile o (come vedremo quando discuteremo di alias ) un riferimento a una variabile .

Una volta eseguita l'esecuzione, ogni istruzione viene contrassegnata come un errore o un successo a seconda che si siano verificati errori o meno. (Questo è davvero importante solo quando usiamo l' alias .)

La stampa , l' incremento e il decremento integrati sono istruzioni con il modulo precedente. Ecco cosa fanno:

  1. print ha il nome del comando pe accetta un argomento. Stampa il nome della variabile passata e il suo valore (in decimale) separato da "=", quindi una nuova riga. Viene sempre segnalato come un successo .

    Ad esempio, il programma Prindeal

    p _MyVariable_321
    p screaming_hairy_armadillo
    

    sarebbe uscita

    _MyVariable_321 = 0
    screaming_hairy_armadillo = 0
    

    perché tutte le variabili iniziano da 0. (Sono richiesti gli spazi prima e dopo il segno di uguale.)

  2. increment ha il nome del comando ie accetta un argomento. Aumenta il valore della variabile passata di 1. Viene sempre contrassegnato come un successo .

    Ad esempio, il programma

    i alpaca
    p alpaca
    i alpaca
    p alpaca
    

    sarebbe uscita

    alpaca = 1
    alpaca = 2
    

    Nota come è alpacastato incrementato da 0 a 1 anche se non era mai stato effettuato prima.

  3. decrement ha il nome del comando de accetta un argomento. Se la variabile passata è diversa da zero il suo valore viene decrementato di 1 e l'istruzione viene contrassegnata come riuscita . Se la variabile passata è 0, non viene fatto nulla e l'istruzione viene contrassegnata come un errore .

    Ad esempio, il programma

    i malamute
    p malamute
    d malamute    #success
    p malamute
    d malamute    #failure
    p malamute
    d akita       #failure
    p akita
    

    sarebbe uscita

    malamute = 1
    malamute = 0
    malamute = 0
    akita = 0
    

    Si noti che il decremento di una variabile con valore 0 è l'unico modo per produrre un errore .

L' istruzione alias e i comandi con alias

Il comando alias ha una sintassi speciale ed è il più potente perché può essere utilizzato per definire nuovi comandi. Il nome del comando alias è ae un'istruzione alias ha la forma:

a [name of new command]
 [statement A]
 [statement B]
 [statement C]

Dove ognuno [statement X]rappresenta una qualsiasi dichiarazione non alias , ovvero qualcosa con il modulo [command name] [argument 1] [argument 2] [argument 3] ....

Il nome del comando con alias [name of new command]può essere qualsiasi stringa non vuota di caratteri alfanumerici e di sottolineatura che non inizia con una cifra - [a-zA-Z_][0-9a-zA-Z_]*in regex.

(Questo è lo stesso set di nomi delle variabili ma i comandi e le variabili con alias sono cose diverse utilizzate in luoghi diversi . Una variabile può essere denominata come un comando senza conseguenze negative.)

Quando viene eseguita un'istruzione alias , viene aggiunto un nuovo comando accanto ai quattro p i d acomandi originali . Il nuovo comando può essere utilizzato come [command name]istruzioni in e chiamato con argomenti proprio come qualsiasi altro comando non alias .

Quando viene eseguita un'istruzione con un nome di comando alias, vengono eseguite esattamente altre due istruzioni dalla sua istruzione alias originale :

  • [statement A] è sempre gestito
  • [statement B]viene eseguito se è [statement A]stato un successo
  • [statement C]viene eseguito se si [statement A]è verificato un errore

Le dichiarazioni A, B e C vengono sempre eseguite pigramente , ovvero vengono valutate al volo nel momento in cui vengono eseguite.

Al termine dell'esecuzione, il comando alias viene contrassegnato con lo stesso flag di esito positivo o negativo dell'istruzione B o C, a prescindere dal fatto che uno sia stato eseguito . (le stesse dichiarazioni alias non devono essere contrassegnate in quanto non possono verificarsi all'interno di se stesse).

Alias ​​Esempio 1

Supponiamo di voler un nuovo comando che incrementi la variabile frogdue volte. Questa affermazione alias lo raggiunge:

a increment_frog_twice
 i frog
 i frog
 d frog

L'istruzione A ( i frog) viene sempre eseguita e sempre contrassegnata come un successo, quindi anche l'istruzione B ( i frog) viene sempre eseguita e la variabile frog viene quindi incrementata di 2. Il increment_frog_twicecomando viene sempre contrassegnato come un successo perché l'istruzione B viene sempre eseguita e B è sempre un successo . L'istruzione C ( d frog) non viene mai eseguita.

Quindi l'output a

a increment_frog_twice
 i frog
 i frog
 d frog
p frog
increment_frog_twice
p frog

sarebbe

frog = 0
frog = 2

Possiamo generalizzare questo esempio in modo che ogni variabile possa essere incrementata due volte dando al comando alias un argomento.

All'interno di un'istruzione alias gli interi positivi 1, 2, 3, ecc. Rappresentano gli argomenti 1st, 2nd, 3rd, ecc. Passati nel comando alias. (Questi argomenti potrebbero essere semplici variabili o riferimenti a variabili stesse). Questi numeri possono apparire solo all'interno degli argomenti delle dichiarazioni A, B e C in un'istruzione alias . Non ha senso che appaiano altrove.

Alias ​​Esempio 2

Questo generalizza l'ultimo esempio: ogni variabile passata increment_twiceverrà incrementata di 2 perché 1è un riferimento al primo argomento passato:

a increment_twice
 i 1
 i 1
 d 1 #never reached
p toad
increment_twice toad
p toad

L'output di questo programma sarebbe

toad = 0
toad = 2

Potremmo quindi alias un altro comando che accetta due argomenti e li chiama increment_twiceentrambi:

a increment_twice
 i 1
 i 1
 d 1 #never reached
a increment_both_twice
 increment_twice 1
 increment_twice 2
 d 1 #never reached
increment_both_twice platypus duck
p platypus
p duck

L'output qui sarebbe

platypus = 2
duck = 2

È importante rendersi conto che i comandi con alias possono essere ricorsivi, poiché è qui che sta il loro vero potere. Ad esempio, possiamo eseguire un comando che imposta qualsiasi variabile passata su 0:

Alias ​​Esempio 3

Il set_to_zerocomando accetta un argomento e imposta la sua variabile su 0 e viene contrassegnato come successo al termine:

a set_to_zero
 d 1
 set_to_zero 1
 i _dummy_
i oryx
i oryx
i oryx
p oryx
set_to_zero oryx
p oryx

L'output di questo programma sarebbe

oryx = 3
oryx = 0

Quello che sta succedendo è che quando set_to_zero oryxviene eseguito, d 1diminuisce con successo oryxda 3 a 2, quindi set_to_zero 1viene chiamato, il che equivale a richiamare di set_to_zero oryxnuovo. Quindi il processo si ripete fino a quando non d 1si verifica un errore , arrestando la ricorsione e incrementando la _dummy_variabile in modo da produrre un successo .


Sfida

Scrivi un programma in grado di eseguire il codice Prindeal esattamente come descritto sopra. Prendi il codice Prindeal in via stdin, dalla riga di comando o come file di testo. Stampa l'output del programma Prindeal su stdout o l'alternativa più vicina alla tua lingua.

In alternativa, è possibile scrivere una funzione che accetta il codice come stringa e stampa o restituisce la stringa di output.

Inoltre, puoi presumere che:

  • Il codice Prindeal di input conterrà solo nuove righe e ASCII stampabili e (facoltativamente) che termina con una riga vuota.
  • Il codice di input sarà Prindeal valido, ben formato e sintatticamente corretto.
  • L'esecuzione del codice non produrrà loop infiniti né riferimenti non validi a comandi che non sono stati definiti o argomenti che non sono stati forniti.
  • I nomi dei comandi p, i, d, e anon saranno mai alias sopra. (Si può non supporre che le variabili non avranno questi nomi.)

Inoltre, non importa se i valori delle variabili non sono numeri interi di precisione arbitraria poiché verranno testati solo numeri inferiori a circa 1000. Va anche bene se la tua lingua ha limiti di ricorsione (come Python ) che i programmi Prindeal più complessi potrebbero incontrare finché il programma di test qui sotto funziona.

Programma di test

Ecco un grande programma Prindeal che costruisce le operazioni di addizione, moltiplicazione ed esponenziazione attraverso l'uso di variabili fittizie (a partire _dalla convenzione) e molti alias helper:

#Command Definitions:
a s             #flag as a success
 i _
 d _
 d _
a f             #flag as a failure
 d _
 d _
 d _
a z             #1 = zero
 d 1
 z 1
 s
a n             #1 = one
 z 1
 i 1
 s
a move          #2 += 1, 1 = zero
 moveH 1 2
 move 1 2
 s
a moveH         #move helper
 d 1
 i 2
 f
a dupe          #2 += 1, 3 += 1, 1 = zero
 dupeH1 1 2 3
 dupe 1 2 3
 s
a dupeH1        #dupe helper
 d 1
 dupeH2 2 3
 f
a dupeH2        #dupe helper
 i 1
 i 2
 s
a copy          #2 = 1
 z 2
 copyH 1 2
 s
a copyH         #copy helper
 dupe 1 2 _copy
 move _copy 1
 s
a addTo         #1 += 2
 copy 2 _add
 #testing comments #
 move _add 1#in weird places # just because #
 s
#it's a g##d idea
###
a add           #1 = 2 + 3
 #its a good idea
 z 1
 addH 1 2 3
 s
##

#
a addH          #add helper
#this is a comment
 addTo 1 2 #as is this
 addTo 1 3
 s
a mul           #1 = 2 * 3
 mulH1 1 2
 mulH2 1 3
 s
a mulH1         #mul helper
 z 1
 copy 2 _mul
 s
a mulH2         #mul helper
 mulH3 1 2
 mulH2 1 2
 s
a mulH3         #mul helper
 d _mul
 addTo 1 2
 f
a mulBy         #1 *= 2
 mul _mulBy 1 2
 copy _mulBy 1
 s
a pow           #1 = 2^3
 powH1 1 3
 powH2 1 2
 s
a powH1         #pow helper
 n 1
 copy 2 _pow
 s
a powH2         #pow helper
 powH3 1 2
 powH2 1 2
 s
a powH3         #pow helper
 d _pow
 mulBy 1 2
 f

#Running Tests:
p A
p B
p C
n A         #A = 1
n B         #B = 1
add C A B   #C = A + B = 1 + 1 = 2
p ____
p A
p B
p C
add B A C   #B = A + C = 1 + 2 = 3
p ____
p A
p B
p C
mul d B C   #d = B * C = 3 * 2 = 6
p ____
p d
mulBy d B   #d = d * B = 6 * 3 = 18
p ____
p d
d A         #A = A - 1 = 1 - 1 = 0
mulBy d A   #d = d * A = 18 * 0 = 0
p ____
p d
pow A C B   #A = C ^ B = 2 ^ 3 = 8
p ____
p A
p B
p C
pow A B C   #A = B ^ C = 3 ^ 2 = 9
p ____
p A
p B
p C
pow C A B   #C = A ^ B = 9 ^ 3 = 729
p ____
p A
p B
p C

(Se stai giocando con questo codice, tieni presente che molti dei comandi falliranno se la stessa variabile viene fornita più volte come argomento. Questo può essere facilmente risolto ma il codice risultante è più lungo.)

L'interprete Prindeal dovrebbe essere in grado di produrre l'output esatto:

A = 0
B = 0
C = 0
____ = 0
A = 1
B = 1
C = 2
____ = 0
A = 1
B = 3
C = 2
____ = 0
d = 6
____ = 0
d = 18
____ = 0
d = 0
____ = 0
A = 8
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 729

punteggio

Vince il codice più breve in byte. Tiebreaker va inoltrato prima.

Bonus brownie: scrivi un programma interessante in Prindeal. Ho implementato addizione e moltiplicazione, puoi fare sottrazione o divisione?


Oh amico, penso che una volta lascerò il Pyth da solo, e tirerò fuori un Lisp! Una domanda: funzioni e variabili vivono in spazi dei nomi completamente diversi, giusto? Quindi posso incrementare p, e quindi p p, quale stamperebbe 1, giusto?
orlp

@orlp Correct. (Ci sono alcune note al riguardo.)
Calvin's Hobbies,

2
Non posso essere il solo a pensare a PRNDL quando vedo il nome della lingua.
Downgoat,

Esiste un numero massimo di argomenti che verranno passati a un comando con alias?
Zach Gates,

@ZachGates Nope
Calvin's Hobbies

Risposte:


9

Pyth, 162 136 byte

JfTmchcd\#).zKHW<ZlJI!e=T@J~+Z1=@Tk)=k0 .x=J+]h=Nm.xL@Tskd@K=NhT+]+tN0>J~Z0,=Y.x@H=eT0?qN\pps[Td\=dYb)?xGN?qN\iXHThY?YXTH_1=k1XKT:JZ=+Z3

Dimostrazione.

Golfato 26 caratteri incorporando variabili e cambiando da Ie Ebasato sul flusso di controllo ?e .xbasato sul flusso di controllo.

Per la prima volta in assoluto, ho esaurito le variabili in Pyth. Ogni singola variabile in Pyth ( bdkGHNTYe JK) era in uso e volevo usarla bcome una nuova riga. Fortunatamente, sono stato in grado di usare Ndue cose completamente diverse in diverse parti del programma, e quindi funziona ancora.

Ungolfed (corri con -m):

JfTmchcd\#).z
KH
W<ZlJ
  I!e=T@J~+Z1
    =@Tk)
  =k0
     .x
      =J+]h=Nm.xL@Tskd@K=NhT+]+tN0>J~Z0
      ,
        =Y.x@H=eT0
        ?qN\p
          ps[Td\=dYb)
          ?xGN
            ?qN\i
              XHThY
              ?Y
                XTH_1
                =k1
            XKT:JZ=+Z3

3
Adoro il fatto che ancora non riesco a dire cosa fa anche con esso non golfato ...
Jerry Jeremiah,

Bene, questo conclude che Pyth non è completo di Turing ...
Erik the Outgolfer

8

Python 2, 600 584 397 373 byte

Questa è la mia soluzione di riferimento golfizzata. Chiunque è invitato a migliorarlo o a seguirne la logica nella propria risposta, purché sia ​​data l'attribuzione.

La parte chiara è che non viene eseguita alcuna ricorsione, quindi non avrà mai problemi con il limite di ricorsione di Python. Ad esempio, il programma Countup Prindeal di Sp può essere eseguito indefinitamente.

p=filter(len,[l.split('#')[0].split()for l in input().split('\n')]);m={};v={};i=0
while i<len(p):
 s=p[i]
 if'('in`s`:s=s[f]
 n,f=s[0],0
 if n in m:a,b,c=([s[int(g)]if g.isdigit()else g for g in t]for t in m[n]);p=[a,(b,c)]+p[i+1:];i=0;continue
 s=s[1]
 q=v.get(s,0)
 if'd'>n:m[s]=p[i+1:i+4];i+=3
 elif'i'<n:print s,'=',q
 elif'd'<n:v[s]=q+1
 elif q:v[s]-=1
 else:f=1
 i+=1

È un programma che accetta la stringa di programma tra virgolette con newline sfuggite, ad es
'p _MyVariable_321\np screaming_hairy_armadillo'.

Ho preso vari spunti di golf dalle risposte di Sp e Pietu . Grazie ragazzi :)


6

Python 3, 345 336 335 328 byte

a=0
A={}
V={}
def f(l):
 if l[0]in"d p i":c,u=l;U=V[u]=V.get(u,0)+"pi".find(c);S=U<0;V[u]+=S;c<"p"or print(u,"=",U)
 else:d=lambda q:[w.isdigit()and l[int(w)]or w for w in A[l[0]][q]];S=f(d(1+f(d(0))))
 return S
for z in open("P"):
 l=z.split("#")[0].split()
 if"a "==z[:2]:a,s,*x=3,l[1]
 elif l*a:x+=l,;a-=1;A[s]=x
 elif l:f(l)

(-6 byte grazie a @orlp)

Ancora golf. Presuppone che il programma sia memorizzato in un file denominato P.

Inserendo le chiamate fall'interno della lambda dsi risparmierebbero alcuni byte, ma si farebbe sì che l'ultimo caso di test raggiungesse la profondità massima di ricorsione.

Alcuni programmi Prindeal

L'inutile programma di sottrazione

Ecco un inutile programma di sottrazione . È inutile perché, anche se sottrae correttamente, non restituisce successo / fallimento di conseguenza.

L'output dovrebbe essere:

a = 15
b = 6
__________ = 0
a = 9
b = 6

countup

a helper
 p 1
 countup 1
 i success

a countup
 i 1
 helper 1
 d failure

countup n

Conta verso l'alto e stampa nper sempre. Potrebbe eventualmente funzionare come test per la velocità dell'interprete (attenzione ai lunghi traceback sull'interruzione della tastiera).


2
Tutti su questa domanda hanno perso questo golf, non capisco perché. l[:(l+"#").find("#")]e tutte le sue varianti possono essere sostituite da una semplice l.split('#')[0].
orlp,

@orlp Era così concentrato su findche ho dimenticato che potevi splitanche solo se #non ci fosse. Grazie :)
Sp3000,

6

JavaScript (ES6), 273 258

Modifica bug corretti e aggiunta una vera suite di test.

Senza contare spazi iniziali e newline.

Sicuramente si può giocare a golf un po 'di più.

Troppo stanco per scrivere una spiegazione ora, penso che sia un buon esempio di utilizzo di chiusure per mantenere in vita valori temporanei (parametri).

Prova a eseguire lo snippet su qualsiasi browser compatibile con EcmaScript 6 (in particolare Chrome non MSIE. Ho testato su Firefox, Safari 9 potrebbe andare)

F=p=>(
  p=p.match(/^[^#\n]+/gm).filter(r=>r.trim(o='',v=[])),
  s={
    '':_=>1,
    p:a=>o+=a+` = ${v[a]||0}\n`,
    i:a=>v[a]=-~v[a],
    d:a=>v[a]&&v[a]--,
    a:(n,j)=>s[n]=(u,t,a)=>x(p[!x(p[j+1],0,a,1)+j+2],0,a,1)
  },
  p.map(x=(r,i,w,l,a=r.split(/ +/).slice(l).map(x=>-x?w[x]:x))=>s[a[0]](a[1],i,a)),
  o
)

// TEST

$('#O tr').each(function() {
  var $cells = $(this).find('td')
  var prg = $cells.eq(0).text()
  console.log(prg)
  var output = F(prg)
  $cells.eq(1).text(output)
})
#O td { vertical-align:top; white-space: pre; border: 1px solid #888; font-family:monospace }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<table>
<tr><th>Program</th><th>Outpout</th></tr>
<tbody id=O>  
<tr><td>p _MyVariable_321
p screaming_hairy_armadillo</td><td></td></tr>
<tr><td>i alpaca
p alpaca
i alpaca
p alpaca</td><td></td></tr>
<tr><td>i malamute
p malamute
d malamute    #success
p malamute
d malamute    #failure
p malamute
d akita       #failure
p akita</td><td></td></tr>
<tr><td>a increment_frog_twice
 i frog
 i frog
 d frog
p frog
increment_frog_twice
p frog</td><td></td></tr>
<tr><td>a increment_twice
 i 1
 i 1
 d 1 #never reached
a increment_both_twice
 increment_twice 1
 increment_twice 2
 d 1 #never reached
increment_both_twice platypus duck
p platypus
p duck</td><td></td></tr>
<tr><td>a set_to_zero
 d 1
 set_to_zero 1
 i _dummy_
i oryx
i oryx
i oryx
p oryx
set_to_zero oryx
p oryx</td><td></td></tr>
<tr><td>#Command Definitions:
a s             #flag as a success
 i _
 d _
 d _
a f             #flag as a failure
 d _
 d _
 d _
a z             #1 = zero
 d 1
 z 1
 s
a n             #1 = one
 z 1
 i 1
 s
a move          #2 += 1, 1 = zero
 moveH 1 2
 move 1 2
 s
a moveH         #move helper
 d 1
 i 2
 f
a dupe          #2 += 1, 3 += 1, 1 = zero
 dupeH1 1 2 3
 dupe 1 2 3
 s
a dupeH1        #dupe helper
 d 1
 dupeH2 2 3
 f
a dupeH2        #dupe helper
 i 1
 i 2
 s
a copy          #2 = 1
 z 2
 copyH 1 2
 s
a copyH         #copy helper
 dupe 1 2 _copy
 move _copy 1
 s
a addTo         #1 += 2
 copy 2 _add
 #testing comments #
 move _add 1#in weird places # just because #
 s
#it's a g##d idea
###
a add           #1 = 2 + 3
 #its a good idea
 z 1
 addH 1 2 3
 s
##

#
a addH          #add helper
#this is a comment
 addTo 1 2 #as is this
 addTo 1 3
 s
a mul           #1 = 2 * 3
 mulH1 1 2
 mulH2 1 3
 s
a mulH1         #mul helper
 z 1
 copy 2 _mul
 s
a mulH2         #mul helper
 mulH3 1 2
 mulH2 1 2
 s
a mulH3         #mul helper
 d _mul
 addTo 1 2
 f
a mulBy         #1 *= 2
 mul _mulBy 1 2
 copy _mulBy 1
 s
a pow           #1 = 2^3
 powH1 1 3
 powH2 1 2
 s
a powH1         #pow helper
 n 1
 copy 2 _pow
 s
a powH2         #pow helper
 powH3 1 2
 powH2 1 2
 s
a powH3         #pow helper
 d _pow
 mulBy 1 2
 f

#Running Tests:
p A
p B
p C
n A         #A = 1
n B         #B = 1
add C A B   #C = A + B = 1 + 1 = 2
p ____
p A
p B
p C
add B A C   #B = A + C = 1 + 2 = 3
p ____
p A
p B
p C
mul d B C   #d = B * C = 3 * 2 = 6
p ____
p d
mulBy d B   #d = d * B = 6 * 3 = 18
p ____
p d
d A         #A = A - 1 = 1 - 1 = 0
mulBy d A   #d = d * A = 18 * 0 = 0
p ____
p d
pow A C B   #A = C ^ B = 2 ^ 3 = 8
p ____
p A
p B
p C
pow A B C   #A = B ^ C = 3 ^ 2 = 9
p ____
p A
p B
p C
pow C A B   #C = A ^ B = 9 ^ 3 = 729
p ____
p A
p B
p C  
</td><td></td></tr>
</tbody>
</table>


Ho aggiunto altri commenti al programma di test e sembra che non abbiano funzionato.
Hobby di Calvin il

@ Calvin'sHobbies una prima, rapida patch
edc65

3

C # 6, 653 byte

Ecco la mia voce, in mezzo a un mare di Python ...

class P{string[]l;string r="";Dictionary<string,int>v=new Dictionary<string,int>();Dictionary<string,int>s=new Dictionary<string,int>();public string R(string t){l=t.Split('\n');for(int i=0;i<l.Length;i++){var z=l[i].Split(' ');if(z[0]=="a"){s.Add(z[1],i);i+=3;}else E(i, null);}return r;}bool E(int n,string[]p){var z=l[n].Split(' ');var a=z.Skip(1).Select(x=>Char.IsDigit(x[0])?p[int.Parse(x)-1]:x).ToArray();if(a.Length>0&&!v.ContainsKey(a[0]))v[a[0]]=0;if (z[0]=="p")r+=$"{a[0]} = {v[a[0]]}\n";else if(z[0]=="i")v[a[0]]++;else if(z[0]=="d")if(v[a[0]]>0)v[a[0]]--;else return false;else{var y=s[z[0]];return E(y+1,a)?E(y+2,a):E(y+3,a);}return true;}}

Ampliato e commentato:

class Prindeal
{
    string[] lines;
    string result = "";
    Dictionary<string, int> variables = new Dictionary<string, int>();
    Dictionary<string, int> statements = new Dictionary<string, int>();

    public string Run(string text)
    {
        lines = text.Split('\n');

        for (int i = 0; i < lines.Length; i++)
        {
            // Split on spaces to get the statement and any arguments
            var z = lines[i].Split(' ');

            // Are we defining a new statement?
            if (z[0] == "a")
            {
                // Add to the statements dictionary, step over definition statements
                statements.Add(z[1], i);
                i += 3;
            }
            else
            {
                // Execute the statement
                Execute(i, null);
            }
        }

        return result;
    }

    bool Execute(int lineNumber, string[] parameters)
    {
        // Split on spaces to get the statement and any arguments
        var z = lines[lineNumber].Split(' ');

        // Parse the arguments - if it's a number, get the corresponding 
        // parameter from the calling statement
        var arguments = z.Skip(1).Select(
            x => Char.IsDigit(x[0]) ? 
            parameters[int.Parse(x) - 1] : 
            x)
            .ToArray();

        // If the first argument isn't already in the variables dict, add it
        if (arguments.Length > 0 && !variables.ContainsKey(arguments[0])) variables[arguments[0]] = 0;

        // Print statement, using string interpolation
        if (z[0] == "p")
            result += $"{arguments[0]} = {variables[arguments[0]]}\n";
        // Increment statement
        else if (z[0] == "i")
            variables[arguments[0]]++;
        // Decrement statement
        else if (z[0] == "d")
            if (variables[arguments[0]] > 0)
                variables[arguments[0]]--;
            else
                return false;
        else
        {
            // Get the line number to jump to
            var y = statements[z[0]];

            // Execute A ? B : C
            return Execute(y + 1, arguments) ? Execute(y + 2, arguments) : Execute(y + 3, arguments);
        }

        // If we reach this point, it's from a 'p', 'i' or 'd' statement which has succeeded
        return true;
    }
}

Per usarlo, basta creare un'istanza della classe e chiamare il R()metodo, ad esempio:

string prindealText = new StreamReader("prindeal.txt").ReadToEnd();
Console.WriteLine(new P().R(prindealText));

3

Lisp comune, 758 646 619

(progn(set-macro-character #\#(get-macro-character #\;))(setf(readtable-case *readtable*):invert)(#3=defun v(s)(if(boundp s)(eval s)0))(#3# i(s)(set s(1+ (v s))))(#3# d(s)(and(plusp(v s))(set s(1-(v s)))))(#3# p(s)(format t"~A = ~A~%"s(v s)))(defmacro a(n . p)`(#3#,(cadr n)(&rest g)(if,@p)))(#3# k(s)(typecase s(integer`(nth,(1- s)g))(symbol `',s)(t(list*(car s)(mapcar 'k(cdr s))))))(#3# r()(prog(l p q)$(setf p()l(make-string-input-stream(or(read-line()()())(return))))@(when(setf p(read l()()))(push p q)(go @))(if q(return(k(reverse q)))(go $))))(do ((x(r)(r)))((not x))(eval(if(eq(car x)'a)`(,@x,(r),(r),(r))x))))

Inseriscilo file.lispe chiama ad esempio sbcl --script file.lisp; l'input viene letto dal flusso di input standard.

Questa versione analizza un superset di Prindeal: senza troppe difficoltà, puoi accedere a tutti i Common Lisp da una fonte Prindeal. Considero questa una caratteristica dell'interprete.

Versione commentata

;; copy-readtable is only used during development, so that I do not 
;; mess with my running environment. The real code starts with the
;; progn below, which is superfluous of course inside a let.
(let ((*readtable* (copy-readtable)))

  ;; I use PROGN in the golfed version so that I can have the whole
  ;; program as a unique tree. This allows me to define reader 
  ;; variables like #3=defun in order to gain a few bytes by writing
  ;; #3# instead of defun. Reader variables are removed in
  ;; this human-friendly version.
  (progn
    ;; Let # point to the same reader function as ;
    ;; Of course, ; is still usable as a comment delimiter
    (set-macro-character #\#
                         (get-macro-character #\;))

    ;; :invert does what is necessary to enable case-sensitive reading
    ;; and printing of symbols
    (setf (readtable-case *readtable*) :invert)

    ;; value of symbol, or zero
    (defun v(s)(if(boundp s)(eval s)0))

    ;; increment
    (defun i(s)(set s(1+ (v s))))

    ;; decrement
    (defun d(s)(and(plusp(v s))(set s(1-(v s)))))

    ;; print
    (defun p(s)(format t"~A = ~A~%"s(v s)))

    ;; alias: wrap an "if" inside a "defun".
    ;; YES, that means you can redefine ANY lisp function with "a" !
    ;; A safer version would properly intern symbols in a dedicated package.
    ;;
    ;; Notice the G variable.  We take advantage of the "unhygienic"
    ;; (what a bad adjective) nature of macros to create a context
    ;; where G is bound to the argument list. The same G is referenced
    ;; implicitely later.
    (defmacro a(n . p)`(defun,(cadr n)(&rest g)(if,@p)))

    ;; Canonicalize expressions:
    ;;
    ;; - if s is a symbol, return s quoted. All functions manipulate
    ;; symbols in order to allow the undeclared use of variables. With
    ;; symbols, we can check for boundness.
    ;;
    ;; - if s is an integer, then we are inside an alias definition. The
    ;; integer is replaced by an access to the s'th element of the
    ;; implicit argument list G using (nth (1- s) g). G will be bound
    ;; when the expressions is injected in the defun corresponding to
    ;; the alias, or else an error will be signaled: either because G
    ;; is unbound, or because you defined a variable named G which is
    ;; by construction not a list. Since we do not sanitize properly
    ;; the input, you could bind G globally to a list, but that would be
    ;; nasty.
    ;; 
    ;; - Finally, if s is a list, apply k to all but the first
    ;; elements of s.  The first element is a symbol but we do not
    ;; need to quote it because we want to call the function
    ;; associated with the symbol. Due to the Lisp-2-ness
    ;; of Common Lisp, functions and variables can coexist
    ;; with the same name.
    ;;
    (defun k(s)(typecase s
                 (integer`(nth,(1- s)g))
                 (symbol`',s)
                 (t(list*(car s)(mapcar #'k(cdr s))))))

    ;; Reader function
    (defun r()
      (prog (l ; current line, as an input-stream reading a string
             p ; current read form
             q ; whole line and return value, as a list
             )

         ;; PROG includes an implicit TAGBODY. Below, $ and @ are
         ;; labels for GO statements (gotos).

       $ (setf
          ;; emtpy p
          p ()

          ;; Read a whole line and if we do not fail, build an input
          ;; stream to read from it.
          l (make-string-input-stream
             (or (read-line()()()) ;; try to read a line,
                 (return)          ;; but return from prog if we reach
                                   ;; the end of file.
                 )))
       @ (when (setf p (read l()()))
           ;; Read a lisp expression, put it in p and if p is not nil
           ;; push it into q.  A nil could happen at the end of the
           ;; line or if someone (you know who) inserted an empty list
           ;; in the file being read.
           ;; 
           ;; Thanks to the readtable which now handles comments
           ;; and spaces for us, nothing needs to be done here to
           ;; preprocess the input.

           (push p q) (go @))

         ;; If we read an empty line, q can be nil. In this case, go
         ;; back to $ and read another line. If q is not nil, reverse
         ;; it (we pushed, remember), canonicalize it and return the
         ;; result.
         (if q (return(k(reverse q))) (go $)))
      )

    ;; Read/eval loop.  When reading "(a name)", we read the three
    ;; next lines and append them to the first so that it builds a
    ;; call the the alias definition macro a. Otherwise, just eval x.
    (do((x(r)(r))((not x))
      (eval (if (eq(car x'a))
                `(,@x,(r),(r),(r))
                x)))))

Esempio

~$ sbcl --script file.lisp < testfile

A = 0
B = 0
C = 0
____ = 0
A = 1
B = 1
C = 2
____ = 0
A = 1
B = 3
C = 2
____ = 0
d = 6
____ = 0
d = 18
____ = 0
d = 0
____ = 0
A = 8
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 729

Se sostituiamo evalcon printnel ciclo read / eval, allora possiamo vedere cosa viene valutato:

(a 's (i '_) (d '_) (d '_)) 
(a 'f (d '_) (d '_) (d '_)) 
(a 'z (d (nth 0 g)) (z (nth 0 g)) (s)) 
(a 'n (z (nth 0 g)) (i (nth 0 g)) (s)) 
(a 'move (moveH (nth 0 g) (nth 1 g)) (move (nth 0 g) (nth 1 g)) (s)) 
(a 'moveH (d (nth 0 g)) (i (nth 1 g)) (f)) 
(a 'dupe (dupeH1 (nth 0 g) (nth 1 g) (nth 2 g))
   (dupe (nth 0 g) (nth 1 g) (nth 2 g)) (s)) 
(a 'dupeH1 (d (nth 0 g)) (dupeH2 (nth 1 g) (nth 2 g)) (f)) 
(a 'dupeH2 (i (nth 0 g)) (i (nth 1 g)) (s)) 
(a 'copy (z (nth 1 g)) (copyH (nth 0 g) (nth 1 g)) (s)) 
(a 'copyH (dupe (nth 0 g) (nth 1 g) '_copy) (move '_copy (nth 0 g)) (s)) 
(a 'addTo (copy (nth 1 g) '_add) (move '_add (nth 0 g)) (s)) 
(a 'add (z (nth 0 g)) (addH (nth 0 g) (nth 1 g) (nth 2 g)) (s)) 
(a 'addH (addTo (nth 0 g) (nth 1 g)) (addTo (nth 0 g) (nth 2 g)) (s)) 
(a 'mul (mulH1 (nth 0 g) (nth 1 g)) (mulH2 (nth 0 g) (nth 2 g)) (s)) 
(a 'mulH1 (z (nth 0 g)) (copy (nth 1 g) '_mul) (s)) 
(a 'mulH2 (mulH3 (nth 0 g) (nth 1 g)) (mulH2 (nth 0 g) (nth 1 g)) (s)) 
(a 'mulH3 (d '_mul) (addTo (nth 0 g) (nth 1 g)) (f)) 
(a 'mulBy (mul '_mulBy (nth 0 g) (nth 1 g)) (copy '_mulBy (nth 0 g)) (s)) 
(a 'pow (powH1 (nth 0 g) (nth 2 g)) (powH2 (nth 0 g) (nth 1 g)) (s)) 
(a 'powH1 (n (nth 0 g)) (copy (nth 1 g) '_pow) (s)) 
(a 'powH2 (powH3 (nth 0 g) (nth 1 g)) (powH2 (nth 0 g) (nth 1 g)) (s)) 
(a 'powH3 (d '_pow) (mulBy (nth 0 g) (nth 1 g)) (f)) 
(p 'A) 
(p 'B) 
(p 'C) 
(n 'A) 
(n 'B) 
(add 'C 'A 'B) 
(p '____) 
(p 'A) 
(p 'B) 
(p 'C) 
(add 'B 'A 'C) 
(p '____) 
(p 'A) 
(p 'B) 
(p 'C) 
(mul 'd 'B 'C) 
(p '____) 
(p 'd) 
(mulBy 'd 'B) 
(p '____) 
(p 'd) 
(d 'A) 
(mulBy 'd 'A) 
(p '____) 
(p 'd) 
(pow 'A 'C 'B) 
(p '____) 
(p 'A) 
(p 'B) 
(p 'C) 
(pow 'A 'B 'C) 
(p '____) 
(p 'A) 
(p 'B) 
(p 'C) 
(pow 'C 'A 'B) 
(p '____) 
(p 'A) 
(p 'B) 
(p 'C)

macroexpansion

Se scegliamo la seguente definizione di alias:

(a 'powH2 (powH3 (nth 0 g) (nth 1 g)) (powH2 (nth 0 g) (nth 1 g)) (s))

... possiamo vedere i riferimenti a una variabile denominata gche non si trova da nessuna parte nell'ambito lessicale. Ma dopo l'espansione macro, ecco il codice attuale in fase di valutazione:

(defun powH2 (&rest g)
  (if (powH3 (nth 0 g) (nth 1 g))
      (powH2 (nth 0 g) (nth 1 g))
      (s))) 

Ora, si griferisce all'elenco degli argomenti della funzione che viene definita.


2

Python 2, 486 byte

Questa è la soluzione di riferimento che ho golfato di più (attualmente -98 byte).

import sys;sys.setrecursionlimit(2000)
def r(s):
 n=s[0]
 if n in A:f=lambda i:r([s[int(t)]if'0'<t[0]<':'else t for t in A[n][i]]);return f(1+(f(0)or 0))
 k=s[1]
 if'i'<n:print k,'=',V.get(k,0)
 elif'd'<n:V[k]=-~V[k]if k in V else 1
 elif'a'<n:
    if~-(k in V)or V[k]<1:return 1
    V[k]-=1
 else:A[k]=s[2:]
A={};V={};c=filter(bool,([l,l[:l.find('#')]]['#'in l]for l in input().split('\n')))
while c:
 s=c[0].split();c=c[1:]
 if'a'!=s[0]:r(s)
 else:r(['a',s[1]]+map(str.split,c[:3]));c=c[3:]

Modifiche (che ricordo):

  • conversione automatica booleana-intero ( [l,l[:l.find('#')]]['#'in l]).
  • imposta o incrementa in un'istruzione ( V[k]=-~V[k]if k in V else 1)
  • più alias a espressioni più lunghe ( k=s[1])
  • nessun contatore nel loop principale, cancellando invece l'elenco di input
  • printaggiunta automatica di spazi ( print k,'=',V.get(k,0))
  • controllo cifre 1-9 ( '0'<t[0]<':')
  • capovolgendo i valori di ritorno di raround per salvare returns
  • rimuovere la ripetizione di taglio e divisione ( map(str.split,c[:3])))

1

Python 3, 1322 byte

golfed:

import re,sys;sys.setrecursionlimit(2000);F,L=filter,list
class P:
 N,O,F=0,{},{}
 def __init__(S,c):
  S.B,S.E={"p":S.P,"i":S.I,"d":S.D,"a":S.L},dict(enumerate(F(None,[i.split('#')[0].rstrip()for i in c.splitlines()])))
  while S.N in S.E:S.X(S.E[S.N])
 def V(S, v, y, z=0):
  if re.match("[\w_][\d\w_]*",v):
   if not v in y:
    if z is not None:y[v]=z
    else:return False
   return True
  return False
 def A(S):S.N+=1
 def P(S,v):
  if S.V(v,S.O):print("{0} = {1}".format(v, S.O[v]));return True
  return False
 def I(S,v):
  if S.V(v, S.O):S.O[v]+=1;return True
  return False
 def D(S,v):
  if S.V(v,S.O)and S.O[v]>0:S.O[v]-=1;return True
  return False
 def L(S,v):
  e=[]
  if S.V(v,S.F,e):
   for i in range(3):S.A();e.append(S.E[S.N].lstrip())
   return True
  return False
 def C(S,c,v):
  def R(Z,v):
   for i in re.findall("\s(\d+)", Z):Z=Z.replace(" %s"%i," %s"%v[int(i)-1])
   return Z
  Q,m,f=map(lambda l:R(l,v),S.F[c])
  if S.X(Q,False):return S.X(m,False)
  return S.X(f,False)
 def X(S,Z,C=True):
  u=re.match("\s?([\w_][\d\w_]*)\s?([\w_][\d\w ]*)?",Z)
  if u:
   c,v=map(lambda i:''if i is None else i,u.groups());v=L(F(None,v.split(' ')))
   if S.V(c,S.F,None):
    T=S.C(c, v)
    if C:S.A()
   elif S.V(c,S.B,None):
    T=S.B[c](*v)
    if C:S.A()
   else:return False
   return T
  return False

Ungolfed:

import re

class Prindeal:
    iline = 0
    local = {}
    udef = {}
    content  = {}

    def __init__(self, c):
        self.built = {
            "p": self.print,
            "i": self.increment,
            "d": self.decrement,
            "a": self.alias,
        }
        self.content = dict(enumerate(filter(None, [i.split('#')[0].rstrip()for i in c.splitlines()])))
        while self.iline in self.content:
            self.execute_line(self.content[self.iline])

    def validate_name(self, varname, stack, default=0):
        if re.match("[\w_][\d\w_]*", varname):
            if not varname in stack:
                if default is not None:
                    stack[varname] = default
                else:
                    return False
            return True
        return False

    def advance_stack(self):
        self.iline += 1

    def print(self, varname):
        if self.validate_name(varname, self.local):
            print("{0} = {1}".format(varname, self.local[varname]))
            return True
        return False

    def increment(self, varname):
        if self.validate_name(varname, self.local):
            self.local[varname] += 1
            return True
        return False

    def decrement(self, varname):
        if self.validate_name(varname, self.local) and self.local[varname] > 0:
            self.local[varname] -= 1
            return True
        return False

    def alias(self, aliasname):
        indexed_lines = []
        if self.validate_name(aliasname, self.udef, indexed_lines):
            for i in range(3):
                self.advance_stack()
                indexed_lines.append(self.content[self.iline].lstrip())
            return True
        return False

    def execute_alias(self, cmd, variables):
        def parse_args(line, variables):
            for i in re.findall("\s(\d+)", line):
                line = line.replace(" %s" % i, " %s" % variables[int(i) - 1])
            return line
        init, success, failure = map(lambda l: parse_args(l, variables), self.udef[cmd])
        if self.execute_line(init, False):
            return self.execute_line(success, False)
        return self.execute_line(failure, False)

    def execute_line(self, line, cont=True):
        valid_execution = re.match("\s?([\w_][\d\w_]*)\s?([\w_][\d\w ]*)?", line)
        if valid_execution:
            cmd, variables = map(lambda i: '' if i is None else i, valid_execution.groups())
            variables = list(filter(None, variables.split(' ')))
            if self.validate_name(cmd, self.udef, None):
                temp = self.execute_alias(cmd, variables)
                if cont:
                    self.advance_stack()
            elif self.validate_name(cmd, self.built, None):
                temp = self.built[cmd](*variables)
                if cont:
                    self.advance_stack()
            else:
                return False
            return temp
        return False

Uso:

P(c)

Dov'è cil contenuto del testo.

Esempi:

Sono accettate stringhe a linea singola:

  • P("p cat")
  • P("p dog\ni dog\np dog")

Sono accettate anche stringhe a più righe:

P("""
p dog
i dog
p dog
""")

O:

P("""p dog
i dog
p dog""")

Eccetera.

Gli appunti:

Funziona correttamente per tutti i casi di test, ma raggiunge il limite di ricorsione su:

pow C A B   #C = A ^ B = 9 ^ 3 = 729

Da qui il sys.setrecursionlimit(2000).


1
Utilizzerà alcuni byte ma non potresti usare sys.setrecursionlimit () per farlo funzionare correttamente con l'alias pow?
Corwin,

Potrei, ma OP ha affermato che linguaggi come Python (che hanno limiti di ricorsione) sono accettati così come sono. Tuttavia, aggiungerò la correzione se richiesto dall'OP. @Corwin
Zach Gates,

Giusto. Perso quello nelle specifiche. @ZachGates
Corwin,

1

Python - 695 688 byte

def p(v):print v,"=",w.get(v,0)
def i(v):w[v]=w.get(v,0)+1
def d(v):
 if v in w:
<TAB>w[v]-=1
<TAB>if not w[v]:del w[v]
 else:return 1
def a(n,b,d,h):
 def g(*a):
<TAB>i=1;f=b;s=d;t=h
<TAB>for v in a:v=q+v+q;k=q+j(i)+q;f=c(f,k,v);s=c(s,k,v);t=c(t,k,v);i+=1
<TAB>y=u(t,e)if u(f,e)else u(s,e);i=1;return y
 e[n]=g
q="'";w=x={};u=eval;e={'a':a,'d':d,'i':i,'p':p};import sys;l=sys.stdin.readlines();r="";j=str;c=j.replace;sys.setrecursionlimit(2000)
for h in l:
 h = h.strip()
 if not h:continue
 l = h.split();f=l[0];n=f+"("
 if "#" in f:continue
 for g in l[1:]:
<TAB>b=g.find("#")+1
<TAB>if b:g=g[:b-1]
<TAB>if g:n+="'%s',"%g
<TAB>if b:break
 if x:x-=1;d+='"%s)",'%n
 else:x=(f=="a")*3;d=n
 if not x:d+=")\n";r+=d
exec r in e

<TAB> è un carattere di tabulazione letterale.


1

C ++, 1111 byte

Questo è C ++, il più idiomatico possibile.
Ciò significa renderlo più C ++ - ish e meno C-ish.
Ciò significa anche che è più grande del programma C equivalente.
Penso che C ++ sia in concorrenza con Java per la libreria standard dettagliata.
Si compila con VS2013 e g ++ 4.9.2 (con -std = c ++ 11)

#include<array>
#include<iostream>
#include<map>
#include<regex>
#include<sstream>
#include<stack>
#define B std::
#define a first
#define b second
#define c(s);else if(x.a==s)
#define d(n)B getline(B cin,r##n)
#define e(n)r##n=B regex_replace(r##n,q,"$1");
#define f(n)do{d(n);e(n)}while(r##n.empty());
#define g B string
#define h B istream_iterator<g>
#define i p.top().a
#define j p.empty()
#define k B pair
#define u continue;
#define w B back_inserter
typedef B vector<g>s;typedef B array<g,3>A;typedef k<k<long,A>,s>t;B map<g,A>m;B map<g,long>n;B stack<t>p;B regex q("^ *(.*?) *(#.*)?$");int main(){g r0,r1,r2,r3;while(d(0)){e(0)if(r0.empty())u p.push(t{{0,{{r0,"",""}}},{}});bool z;while(!j){k<g,s>x;B istringstream ss(i.b[i.a]);ss>>x.a;B copy(h(ss),h(),w(x.b));s o;B transform(B begin(x.b),B end(x.b),w(o),[](g y){int v=atoi(y.c_str());return v>0?p.top().b[v-1]:y;});z=true;if(0)c("")c("p")B cout<<o[0]<<" = "<<n[o[0]]<<B endl c("i")n[o[0]]++c("d")n[o[0]]-=(z=n[o[0]])c("a"){f(1)f(2)f(3)m.insert(B make_pair(o[0],A{{r1,r2,r3}}));}else{p.push(t{{0,m[x.a]},o});u}while(!j&&i.a)p.pop();if(!j)i.a+=1+!z;}}}

Di seguito è riportato l'originale. Se qualcuno può pensare a un modo per renderlo più idiomatico e più breve allo stesso tempo, per favore fatemelo sapere.

#include <array>
#include <iostream>
#include <map>
#include <regex>
#include <sstream>
#include <stack>

typedef std::vector<std::string> List;
typedef std::pair<std::string, List> Statement;
typedef std::array<std::string, 3> Alias;
typedef std::pair<long, Alias> IndexedAlias;
typedef std::pair<IndexedAlias, List> Item;

std::map<std::string, Alias> aliases;
std::map<std::string, long> variables;
std::stack<Item> stack;
std::regex re("^ *(.*?) *(#.*)?$");

int main()
{
    std::string line, line1, line2, line3;
    while (std::getline(std::cin, line)) // control-Z to exit
    {
        line = std::regex_replace(line, re, "$1");
        if (line.empty()) continue;
        stack.push(Item{ { 0, { { line, "", "" } } }, {} });

        bool flag;
        while (!stack.empty())
        {
            Statement statement;
            std::istringstream ss(stack.top().first.second[stack.top().first.first]);
            ss >> statement.first;
            std::copy(std::istream_iterator<std::string>(ss), std::istream_iterator<std::string>(), std::back_inserter(statement.second));

            List arguments;
            std::transform(std::begin(statement.second), std::end(statement.second), std::back_inserter(arguments),
                [](std::string arg){ int i = atoi(arg.c_str()); return i > 0 ? stack.top().second[i - 1] : arg; });

            flag = true;
            if (statement.first == "")
                ;
            else if (statement.first == "p")
                std::cout << arguments[0] << " = " << variables[arguments[0]] << std::endl;
            else if (statement.first == "i")
                variables[arguments[0]]++;
            else if (statement.first == "d")
                variables[arguments[0]] -= (flag = variables[arguments[0]]);
            else if (statement.first == "a")
            {
                do { std::getline(std::cin, line1); line1 = std::regex_replace(line1, re, "$1"); } while (line1.empty());
                do { std::getline(std::cin, line2); line2 = std::regex_replace(line2, re, "$1"); } while (line2.empty());
                do { std::getline(std::cin, line3); line3 = std::regex_replace(line3, re, "$1"); } while (line3.empty());
                aliases.insert(std::make_pair(arguments[0], Alias{ { line1, line2, line3 } }));
            }
            else
            {
                stack.push(Item{ { 0, aliases[statement.first] }, arguments });
                continue;
            }

            while (!stack.empty() && stack.top().first.first) stack.pop();
            if (!stack.empty()) stack.top().first.first += 1 + !flag;
        }
    }

    std::cout << "-- Variables --" << std::endl;
    std::transform(std::begin(variables), std::end(variables), std::ostream_iterator<std::string>(std::cout, "\n"),
        [](std::map<std::string, long>::value_type pair){ std::ostringstream ss; ss << pair.first << " = " << pair.second; return ss.str(); });
    std::cout << "-- Aliases --" << std::endl;
    std::transform(std::begin(aliases), std::end(aliases), std::ostream_iterator<std::string>(std::cout, "\n"),
        [](std::map<std::string, Alias>::value_type pair){ std::ostringstream ss; ss << pair.first << " = [1]:" << pair.second[0] << " [2]:" << pair.second[1] << " [3]:" << pair.second[1]; return ss.str(); });
    std::cout << "---------------" << std::endl;

    return 0;
}

0

Haskell, 1009

Ho fatto del mio meglio per giocare a golf; il mio codice non golfizzato consisteva di oltre 3.000 caratteri. A questo punto non ricordo cosa fanno tutte le funzioni, quindi giocare a golf significa più indovinare cosa lo romperà e cosa no.

import qualified Data.Map as M
import Control.Monad.State.Lazy
import Data.List
type A=M.Map String
data P=P(A Int)(A([String]->StateT P IO Int))
a f=evalStateT f(P M.empty$M.fromList[("i",\(b:_)->(+1)%b),("d",\(b:_)->pred%b),("p",\(b:_)->i b>>= \v->liftIO(putStrLn$b++"="++show v)>>q 1)])
e(k:l)=do{(P v a)<-get;put.P v$M.insert k(m l)a;q 1}
g t s f= \a->t a>>= \b->if b>0then s a else f a
f%k=f<$>i k>>= \v->if v<0then k#0>>q 0else k#v>>q 1
i k=get>>= \(P v _)->q$M.findWithDefault 0 k v
k#v=get>>= \(P b a)->put$P(M.insert k v b)a
l k=get>>= \(P _ a)->q$a M.!k
f s=let(f:a)=r s in($a)<$>l f>>=id
m(t:s:f:_)=g(k t)(k s)(k f)
k s=let(f:b)=r s in\a->($(map((\y z->if all(\c->c>'/'&&c<':')z then y!!(read z-1)else z)a)b))<$>l f>>=id
n=dropWhileEnd(==' ').takeWhile(not.(=='#')).dropWhile(==' ')
o[]=[]
o(l:ls)|(head.r$l)=="a"=(l:take 3 ls):(o$drop 3 ls)|1>0=[l]:o ls
p s|length s>1=e$(n.tail.head$s):tail s|1>0=f.head$s
q=return
main=join$a.(\s->mapM_ p(o.filter(not.null).map n.lines$s))<$>getContents
r=words
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.