Transpile WordMath

25

Nous avons tous vu ces "maths hax" en ligne qui ressemblent à ceci:

Think of a number, divide by 2, multiply by 0, add 8.

Et, par magie, tout le monde se retrouve avec le chiffre 8!


La langue

Définissons un langage de programmation qui utilise la syntaxe du texte ci-dessus, appelé "WordMath". Les scripts WordMath suivent ce modèle:

Think of a number, <commandlist>.

Ce qui signifie essentiellement: prenez un nombre (comme entrée de STDIN) comme accumulateur initial, exécutez toutes les commandes dessus et sortez le résultat.

Les commandes sont séparées par le délimiteur ,(virgule + espace). Les commandes valides sont (notez que cela #représente un entier non négatif :) :

  • add #/ subtract #- Ajouter / soustraire la valeur de l'accumulateur.
  • divide by #/ multiply by #- floordiv / multiplie l'accumulateur par la valeur donnée.
  • subtract from #- Similaire à subtract, mais acc = # - accau lieu deacc = acc - #
  • repeat- refait la dernière commande. Cela ne peut pas être la 1ère commande, mais vous devez prendre en charge plusieurs répétitions consécutives.

Le défi

Votre tâche consiste à créer un programme ou une fonction qui prend un script WordMath valide comme entrée et transpile en un programme complet valide - dans la même langue que votre code.

Par exemple, si mon code est en Python 2 et que le script est:

Think of a number, subtract from 10, add 10, multiply by 2.

Le programme généré peut être:

a = input()
a = 10 - a
a += 10
a *= 2
print(a)

Ou bien:

print(((10-input())+10)*2)

Tant qu'il s'agit d'un programme complet qui prend en entrée STDINet imprime vers STDOUT, ou les équivalents les plus proches de la langue.


Règles

  • Votre programme d'origine peut supposer que l'entrée est toujours un script WordMath valide.
  • Les programmes transpilés ne doivent pas gérer les erreurs mathématiques telles que la division par 0.
  • Les programmes transpilés peuvent supposer que l'entrée représente un entier signé valide, dans la plage d'entiers standard de votre langue.
  • C'est du , donc la solution la plus courte (en octets) l'emporte.
  • Seul le nombre d'octets de votre programme d'origine est important - le code généré peut être aussi long que vous le souhaitez!

Exemples de scripts

Exemple 1:

Think of a number. 

Prenez la saisie, ne faites rien, affichez-la: le programme cat de WordMath.

Exemple 2:

Think of a number, divide by 5, subtract from 9.

N'oubliez pas que «diviser» est la division du plancher, donc pour ce programme 6 -> 8, et 29 -> 4.

Exemple 3:

Think of a number, add 5, add 10, multiply by 2, subtract 15, repeat, divide by 2.

Le programme chat étendu!

Exemple 4:

Think of a number, subtract 1, repeat, repeat.

Prend un nombre et soustrait 3.

FlipTack
la source
Faut-il supporter des répétitions consécutives?
darrylyeo
1
Peut-on utiliser des flottants quand c'est le type par défaut du langage / s'il ne supporte pas les entiers?
Rainer P.
@RainerP. uniquement si le langage ne prend pas en charge les nombres entiers / division entière
FlipTack
1
Quel est le résultat attendu de -5/3? Arrondissons-nous vers 0ou vers l'infini négatif?
Martin Ender
1
@MartinEnder Je dirais arrondir vers l'infini négatif car c'est la division du sol , mais si votre langage implémente une division entière vers 0, c'est bien aussi.
FlipTack

Réponses:

6

05AB1E , 59 56 54 52 octets

„, ¡¦vyDþs.AJá'bK"dmas""/*+-"‡„-f„s-.:«D'rQi®}©}J'rK

Essayez-le en ligne!

Mon cerveau me fait mal comme l'enfer après ça ... Il sort en code 05AB1E comme suit:

  • Think of a Number est supprimé, en raison d'une entrée implicite.
  • Subtract From #caudales à #s-(échange aet bet d' effectuer l' opération).
  • Subtract #convertit en #-.
  • Add #convertit en #+.
  • Multiply by #convertit en #*.
  • Divide by #convertit en #/.
  • Repeat saisit tout ce qui a été stocké en dernier dans le registre et le concatène.

Expliqué:

„, ¡                                                 # Split on ', '.
    ¦                                                # Remove the 'Think of a number'.
     vy                                        }     # Loop through chunks.
       Dþs                                           # Dupe, push only digits, swap.
          .AJá                                       # Acronymify without digits.
              'bK                                    # Remove the `b`.
                 "dmas""/*+-"‡                       # Replace letters with OPs.
                              „-f„s-.:               # Replace '-f' with 's-'.
                                      «              # Concat # with OP.
                                       D'rQ          # Dupe, push 1 if OP='r'.
                                           i®}       # If 'r', push last #OP.
                                              ©      # Store current OP.
                                                J'rK # Join, remove remaining r's.

Exemple:

Contribution:

Think of a number, divide by 2, multiply by 10, add 8, subtract 6, subtract from 9, repeat, repeat, subtract 41.

Sortie:

2/10*8+6-9s-9s-9s-41-

Essayez une solution avec une entrée de 10:

Essayez-le en ligne!

Voir sur google:

Voici un lien vers la même équation saisie dans google.

Urne de poulpe magique
la source
13

Préprocesseur C, 362 octets

J'AI PRESQUE fait en sorte que cela fonctionne dans le préprocesseur C, mais la commande de répétition s'avère beaucoup trop difficile à implémenter. Au lieu de cela, j'ai utilisé le préprocesseur pour transformer l'entrée en un tableau qui est ensuite interprété par un code supplémentaire.

main(){int c[]={
#define Think 
#define of
#define a
#define number 0
#define add 1,
#define subtract 2,
#define from 0,3,
#define multiply 4,
#define divide 5,
#define by
#define repeat 6, 0
#include "input.wm"
,'$'};int _,l,v;scanf("%d", &_);for(int i=1;c[i]-'$';++i){c[i]!=6?l=c[i],v=c[++i]:++i;l==1?_+=v:l==2?_-=v:l==3?_=v-_:l==4?_*=v:_/=v;}printf("%d",_);}

L'entrée doit être fournie dans "input.wm" ou simplement vidée dans la source sur cette ligne. J'ai inclus ses octets dans mon décompte car je pense que c'est un peu hacky et légèrement contre les règles du défi, donc ça ne fait que convenir.

Quoi qu'il en soit, une fois que vous avez vidé votre source WordMath dans input.wm où un compilateur peut le trouver, vous devriez être en mesure de le compiler, tel quel, avec des avertissements pour produire un exécutable qui fait ce que dit la source WordMath.

LambdaBeta
la source
2
Remarque: cela échoue malheureusement avec certains compilateurs lorsque vous terminez par répéter. En effet, ils jettent un espace après le 0, puis voient une période parasite et ne savent pas quoi en faire.
LambdaBeta du
intelligent, je suis impressionné.
cat
7

Rétine, 170 octets

Parce que qui ne voudrait pas voir ça?!

J'ai pensé à quel point ce serait génial de voir une solution Retina, et j'ai décidé de la créer rapidement. Cela n'a pris qu'une heure. Comme d'habitude, le nombre d'octets suppose le codage ISO 8859-1.

S`, 
\.

T.*
.*¶$$*
\;+`(.*)¶rep.*(¶?)
$1¶$1$2
\d+
$*
.*f.* (1*)
1¶x¶$¶$1¶+`x1¶
m.* 
1¶
di.* (1*)
^¶$1 ¶^(1+) (\1)+1*$¶x$$#+¶1+ 1*¶x0¶x\d+¶$$*
s.* (1*)
^$1¶
a.* 
^¶
\z
¶1

Essayez-le en ligne

La sortie a un retour à la ligne qui ne doit pas être copié lors du test du programme résultant. Le programme ne prend pas en charge les négatifs, car la plage d'entiers standard de Retina (en unaire) ne le fait pas.

Explication:

S`,                 # Split input on ", " putting each command on its own line
\.                  # Remove the period

T.*                 # Think of a number -> .*\n$* (replaces input with unary)
.*¶$$*
\;+`(.*)¶rep.*(¶?)  # Loop, replacing "repeat" with the line before it
$1¶$1$2
\d+                 # Replace all numbers with their unary representation
$*
.*f.* (1*)          # Replace "subtract from " with a subtract from program
1¶x¶$¶$1¶+`x1¶
m.*                 # Replace "multiply by " with a multiply program
1¶
di.* (1*)           # Replace "divide by " by my integer division program
^¶$1 ¶^(1+) (\1)+1*$¶x$$#+¶1+ 1*¶x0¶x\d+¶$$*
s.* (1*)            # Replace "subtract " with a subtraction program
^$1¶
a.*                 # Replace "add " with an addition program
^¶
\z                  # At the end, add a stage to change unary into decimal
¶1

Programmes mathématiques:

Ajouter:

Ajoutez le nombre de uns au début. Ajouter 5:

^
1111

Soustraire:

Supprimez le nombre de ceux du début. Soustrayez 5:

^11111

Soustraire de:

Remplacez l'entrée 1s par xs. Mettez à côté du nombre fixe. Supprimer à plusieurs reprises x1. Soustrayez de 10:

1
x
$
1111111111
+`x1

Multiplier par:

Remplacez chacun 1par un certain nombre d'entre eux. Multipliez par 3:

1
111

Diviser par:

Cela utilise mon programme Retina pour Integer Division . Divisez par 2:

^                   # Place the fixed divisor before the dividend
11 
^(.+) (\1)+.*$      # Match the divisor, followed by each occurrence in the dividend.
x$#+                # Replace with the number of matches. Trailing ones are dropped
.+ .*               # If there are still two numbers, the result is zero
x0
x\d+                # Replace result (marked with an 'x') with unary
$*
mbomb007
la source
J'ai peur de ne pas voir comment cela peut fonctionner. Quelles que soient les entrées que j'essaie pour les commandes de soustraction, j'obtiens des résultats cassés (y a-t-il des sauts de ligne manquants dans la sortie?). Je ne vois pas non plus comment cela gère les entrées négatives ou les résultats intermédiaires négatifs.
Martin Ender
@MartinEnder Je peux corriger la soustraction si vous expliquez pourquoi ce programme simplifié en donne deux dans la sortie. retina.tryitonline.net/#code=JArCtjE&input=dGVzdAo
mbomb007
Parce que $correspond à la toute fin de la chaîne ou devant un saut de ligne de fin. Vous en avez besoin \zsi vous ne voulez que le premier.
Martin Ender
4

GNU awk, 139 octets

BEGIN{RS="[,.]";c="{}{";ORS=";"}
/ad/{c="+="$2}
/c/{c="-="$2}
/om/{c="="$3"-$0"}
/l/{c="*="$3}
/v/{c="=int($0/"$3")"}
!NF{c="}1"}
$0="$0"c

Invocation:

$> awk `awk -f wordmath <<< "Think of a number, add 1, repeat, repeat."` <<< 0
$> 3

Cas de test:

$> awk -f wordmath <<< "Think of a number."  
$> $0{}{;$0}1;

$> awk -f wordmath <<< "Think of a number, divide by 5, subtract from 9."
$> $0{}{;$0=int($0/5);$0=9-$0;$0}1;

$> awk -f wordmath <<< "Think of a number, add 5, add 10, multiply by 2, subtract 15, repeat, divide by 2."
$> $0{}{;$0+=5;$0+=10;$0*=2;$0-=15;$0-=15;$0=int($0/2);$0}1;
Rainer P.
la source
4

Haskell, 232 231 octets

Bien sûr, un programmeur fonctionnel préférerait retourner une fonction plutôt qu'une chaîne représentant un programme, mais c'est parti:

t l="main=getLine>>=print."++""%words l++"(0+).read"
x%((o:_):f:n:r)|o=='m'=h"*"n r|o=='d'=h"`div`"n r|f=="from"=h"(-)"n r
x%(s:n:r)|s=="add"=h"+"n r|s!!0=='s'=h s(' ':n)r
x%(_:r)=x%r++x
_%_=""
h s n r|x<-'(':s++init n++")."=x%r++x

Remarques: Nous commençons toujours par ajouter zéro, sinon la transpilation du programme trivial WordMath ne donnerait pas suffisamment d'informations pour déduire le type auquel il readest utilisé.subtract from npourrait être mis en œuvre en tant que (n-), mais j'utilise ((-)n)pour plus d'uniformité. Dans le cas de la subtract ncopie subtractde l'entrée, je n'ai donc pas à l'écrire, mais je dois compenser l'espace manquant à la fin. repeatest utilisé comme opération par défaut; avec une opération précédente initiale vide, cela permet d'ignorer facilement les quatre premiers mots.

Exemple d'utilisation:

*Main> t "Think of a number. "
"main=getLine>>=print.(0+).read" 

Les autres exemples donnent les résultats suivants:

"main=getLine>>=print.((-)9).(`div`5).(0+).read"
"main=getLine>>=print.(`div`2).(subtract 15).(subtract 15).(*2).(+10).(+5).(0+).read"  
"main=getLine>>=print.(subtract 1).(subtract 1).(subtract 1).(0+).read"
Christian Sievers
la source
Juste curieux, comment généreriez-vous une fonction à retourner au lieu d'une chaîne?
Cyoce
Dans un langage de programmation fonctionnel, la création et la composition d'une fonction n'est pas plus difficile que la création et l'ajout d'une chaîne. hpourrait ressembler à quelque chose h s n r|x<-s.read.init$n=x%r.xet être appelée avec le premier argument d'une fonction comme h(+)n r(et il doit y en avoir quelque flippart pour obtenir l'ordre d'opérateur correct), le cas de base est _%_=id. La fonction principale peut éviter tout le passe-partout et être juste t l=id%words l. - Grâce au curry, il pourrait être considéré comme un interprète, et cette idée pourrait conduire à une solution plus facile et / ou plus courte.
Christian Sievers
4

Python 2, 263 258 260 221 octets

Cela pourrait probablement être encore beaucoup plus court.

def r(s,o="",p=""):c=s.pop(0);c=[c,p]['re'in c];n=c.split()[-1];o=[[o+[['+-'['s'in c],'//']['v'in c],'*']['m'in c]+n,n+'-'+o]['f'in c],'input()']['T'in c];return s and r(s,"(%s)"%o,c)or o
lambda s:"print "+r(s.split(','))

Essayez-le en ligne

J'utilise à la //place de /, car la dernière instruction aura un .à la fin, faisant de n'importe quel nombre un flottant. Donc, pour garder la division cohérente, j'utilise la division entière.

Sortie des cas de test:

print input()
print 9.-((input())//5)
print ((((((input())+5)+10)+10)-15)-15)//2.
print (((input())-1)-1)-1
mbomb007
la source
Si vous modifiez ce gros bloc de ifs pour oce qui suit (ce qui, je pense, devrait fonctionner):, o=[[o+[['+-'['s'in c],'//']['v'in c],'*']['m'in c]+n,n+'-'+o]['f'in c],'input()']['T'in c]vous pouvez le réduire à 224.
Kade
@Kade Ouais, c'était encore lisible. Je ne peux pas avoir ça.
mbomb007
@Cyoce Non, l'acte même d'appeler le lambda coûterait probablement plus cher qu'il n'en sauve. Il faudrait économiser 4 ou 5 octets par appel pour payer.
mbomb007
4

Befunge, 342 305 octets

>~$1 +:89+`#v_801p
  v_^#`+85~$<
1+>~:5+88+/3-!#v_$
v`"/":~p8p10+1<>>:"/"`!|
 "+"\5+8p4+:1+^:p11:g10<  >:"+"\2+8p:"*"\3+8p:
_$7%:01g\!#v_\2-7g\:1+:01v^p8+1\"5":p8\"5":g10
#8\"\"$#:0#<^v<p8p8\<g80p<>\#+$#12#p
-/+* >:#,_@  #^p8g10<
".@"<^"&"
10<v0<\g8-\g11:<:p1>#1+g11:p10+g
-:^>1g\-8p1-::#^_$8g^  >$$01g11g

Essayez-le en ligne!

Sortie

Le code qu'il génère commence par une commande &(valeur d'entrée) et se termine par les commandes .(valeur de sortie) et @(sortie). Entre les deux, nous avons les différents calculs sous la forme <number><operation>, où l' opération peut être +(ajouter), -(soustraire), /(diviser par), *(multiplier par) et\- (soustraire de).

Le nombre lui-même est un peu compliqué, car Befunge ne prend en charge que les littéraux numériques compris entre 0 et 9, donc tout ce qui est plus grand doit être calculé manuellement. Puisque nous lisons déjà les nombres caractère par caractère, nous construisons simplement le nombre au fur et à mesure que chaque chiffre est lu, donc par exemple, 123 devient 155+*2+55+*3+, c'est-à-dire (((1 * 10) + 2) * 10) + 3.

Exemples

Input:  Think of a number.
Output: &.@

Input:  Think of a number, divide by 5, subtract from 9.
Output: &5/9\-.@

Input:  Think of a number, add 5, add 10, multiply by 2, subtract 15, repeat, divide by 2.
Output: &5+155+*0++2*155+*5+-155+*5+-2/.@

Input:  Think of a number, subtract 1, repeat, repeat.
Output: &1-1-1-.@

Explication

Befunge n'a pas la capacité de manipuler les chaînes en tant que telles, donc la plupart de l'analyse est gérée par le comptage des caractères. Nous commençons simplement par sauter les 18 premiers caractères, ce qui nous permet de dépasser le nombre phrase (plus une virgule ou un point). Ensuite, si le caractère suivant est une forme de saut de ligne ou d'EOF, nous allons directement à la routine de sortie, sinon nous continuons à chercher une liste de commandes.

Pour analyser une commande, nous continuons simplement à compter les caractères jusqu'à atteindre un chiffre ou un séparateur. S'il s'agit d'un séparateur, ce doit être la commande de répétition que nous traitons comme un cas spécial. S'il s'agit d'un chiffre, nous l'ajoutons à notre tampon de sortie et continuons à rechercher d'autres chiffres. Chaque fois qu'un chiffre est sorti, nous le préfixons avec 55+*(pour multiplier le total jusqu'à présent par 10) et le suffixe avec +(pour l'ajouter au total). Une fois les chiffres terminés, nous ajoutons le caractère de commande.

Quant à la façon dont la commande est déterminée, nous prenons le nombre de caractères jusqu'au premier chiffre modulo 7. Pour ajouter ceci est 4 (y compris l'espace suivant), pour soustraire c'est 2, pour diviser par c'est 3, pour multiplier par c'est 5 , et pour soustraire de 0, la soustraire de nécessite un peu de manipulation supplémentaire car elle a besoin du \-combo de commandes, mais les autres utilisent simplement leur valeur pour rechercher le caractère de commande approprié dans une table.

Ce processus est répété pour chaque commande, créant la sortie dans une chaîne préconstruite à la ligne 8. Chaque fois qu'une commande supplémentaire est ajoutée, nous ajoutons également un guillemet de fermeture à la chaîne pour nous assurer qu'elle est toujours correctement terminée. Ensuite, lorsque nous atteignons finalement la fin de notre entrée, nous «exécutons» simplement cette chaîne pour la pousser sur la pile, puis la suivons avec une séquence de sortie standard pour tout écrire.

James Holderness
la source
3

JavaScript (ES6), 163 octets

w=>w.split`, `.map(l=>(o={a:'+',s:'-',m:'*',d:'/'}[a=l[0]])?p=(x=l.split` `.pop(),l[9]=='f'?x+`-n`:`n`+o+x+`|0`):a<'r'?'n=+prompt()':p).join`
n=`+`
console.log(n)`

Essayez-le:

f=w=>w.split`, `.map(l=>(o={a:'+',s:'-',m:'*',d:'/'}[a=l[0]])?p=(x=l.split` `.pop(),l[9]=='f'?x+`-n`:`n`+o+x+`|0`):a<'r'?'n=+prompt()':p).join`
n=`+`
console.log(n)`

const program = f('Think of a number, add 5, add 10, multiply by 2, subtract 15, repeat, divide by 2.')
document.write('<pre>' + program + '</pre>' )

eval(program)

/*
Outputs:

n=+prompt()
n=n+5|0
n=n+10|0
n=n*2|0
n=n-15|0
n=n-15|0
n=n/2.|0
console.log(n)
*/

darrylyeo
la source
3

Vim 208 171 168 168 octets

Ajout de la possibilité de faire plusieurs répétitions d'affilée selon @ Flp.Tkc, mais de jouer suffisamment d'octets pour que je puisse encore réduire le nombre d'octets.

:map s :s;\v
c4wcw="s, s\w* \w+ (\d+); *-1+\1);g
s, ([adms]).{-}(\d+); \1\2);g
qws(\S+), r\w+;\1 \1
@wq@ws.*;\=tr(submatch(0),'adms','+/*-')
qq])T=i(@qq@qx$xA

TryItOnline

Caractères non imprimables:

:map s :s;\v
c4wcw^V^R=^V^R"^[s, s\w* \w+ (\d+); *-1+\1);g
s, ([adms]).{-}(\d+); \1\2);g
qws(\S+), r\w+;\1 \1
@wq@ws.*;\=tr(submatch(0),'adms','+/*-')
qq])T=i(^[@qq@qx$xA
^V^[^[

Sortie des cas de test:

  1. cw^R=^R" ^[ TryItOnline
  2. cw^R=((^R" /5) *-1+9) ^[ TryItOnline
  3. cw^R=((((((^R" +5) +10) *2) -15) -15) /2) ^[ TryItOnline
nmjcman101
la source
Cela ne semble pas fonctionner pour plusieurs répétitions consécutives.
FlipTack
@ Flp.Tkc corrigé, merci! Je ne l'avais pas remarqué plus tôt.
nmjcman101
2

lex, 246 octets

%{
#define P printf
#define O P("n%s%d;",c,v);
int v;char*c;
%}
%%
T {P("%%%%\n.* {int n=atoi(yytext);");}
ad {c="+=";}
fr {c="=-n+";}
s {c="-=";}
v {c="/=";}
l {c="*=";}
re {O}
[0-9]+ {v=atoi(yytext);O}
\. P("printf(\"%%d\",n);}\n%%%%");
. ;
%%

lex cible C, donc un compilateur C devrait le compiler en quelque chose d'exécutable. La bibliothèque lexer ( ll) devrait également être liée. Cela peut ajouter une octet-pénalité, mais je ne sais pas combien d'octets si c'est le cas.

Le programme génère un programme Lex (par spécification) qui évalue l'expression de mot de passe transpilée. Le code entre%{ et %}est pour le "transpilateur" uniquement:

#define P printf              /* for brevity */
#define O P("n%s%d;",c,v)     /* expression builder, calls P = printf */
int v;char*c;                 /* v=most recent integer read */
                              /* c=the expression infix */

Entre les deux %% lignes se trouve la partie regex / action. La première règle à mettre en correspondance serait T("Pensez ...") qui construit le préambule (les programmes lex doivent commencer à contenir au moins la section de règle, etyytext est le dernier texte correspondant, donc la règle essentiellement l'accumulateur avec l'entrée de l'utilisateur ).

Le programme supprime toutes les entrées à l'exception de celles qui correspondent, et les autres règles ( ad,fr jusqu'à re) gérer les clauses d'expression wordmath avec comme match d'un minimum possible d'être unique. Dans la plupart de ces cas, il définit cune expression infixe, qui est concaténée entre net le dernier entier lu lors de l' Oappel (ainsi, par exemple, la lecture de "ajouter 9" définira l'infixe sur +=, v sur 9et l'appel à Osortira n+=9;) . (Un côté intéressant est que "soustraire de 8" entraînera la correspondance entre sles frrègles et les règles, mais comme elle On'est appelée qu'au numéro, la règle appropriée n=-n+8;est la seule expression qui obtient la sortie). lere règle pour "répéter" n'appelle queOencore une fois, qui génère la dernière expression créée (et puisque les correspondances ultérieures vont s'encombrer yytext, la prise en charge de "répétition" est la raison pour laquelle la conversion entière dans la la fin de programme paire indiquant la fin du programme lex de sortie.[0-9]+était requise). Enfin, une période entraîne la sortie de la bande-annonce du programme, qui sort simplement l'accumulateur et se ferme avec le%%

Remarque: ni le programme principal de transpiler ni le programme de sortie ne se termineront. L'entrée de tuyauterie fonctionnerait ou fournirait EOF (ctrl-D). Si la terminaison est requise après la première entrée, exit () s peut être ajouté.

Pour construire / exécuter:

Build the main program:
% lex -o wordmath.yy.c wordmath.l
% cc -o wordmath wordmath.yy.c -ll

Execute to create a specific transpiled program:
% echo "This is a number, add 8, subtract 5, repeat." | ./wordmath > program.l

Build the transpiled program:
% lex -o program.yy.c program.l
% cc -o program program.yy.c -ll

Execute the transpiled program (with input 3, called via a pipe or inline):
% echo 3 | ./program
1
% ./program
3
1
^D
%

Test 1:

%%
.* {int n=atoi(yytext);printf("%d",n);}
%%

Test 2:

%%
.* {int n=atoi(yytext);n/=5;n=-n+9;printf("%d",n);}
%%

Test 3:

%%
.* {int n=atoi(yytext);n+=5;n+=10;n*=2;n-=15;n-=15;n/=2;printf("%d",n);}
%%

Test 4:

%%
.* {int n=atoi(yytext);n-=1;n-=1;n-=1;printf("%d",n);}
%%
ryounce
la source
2

Pyth, 69 67 octets

J\QVtcQ\,Iq@N1\r=NZ)=Jjd+@"+-/*"x"asdm"@N1.>,J-ecN)\.qh@cN)1\f=ZN)J

Un programme qui prend en entrée un "quoted string" et imprime le résultat.

Suite de tests

Comment ça marche

Pyth a des opérateurs de préfixe, donc les opérations arithmétiques de base sont effectuées en utilisant (operator)(operand1)(operand2), tandis que la variable pré-initialisée Qdonne l'entrée. Par conséquent, un programme WordMath transpilé est construit en commençant par la chaîne 'Q', et à chaque étape, en ajoutant l’opérateur, puis en ajoutant ou en ajoutant l’opérande comme nécessaire.

J\QDéfinissez J, la chaîne de programme transpilée, sur la chaîne'Q'

tcQ\, Fractionnez l'entrée sur des virgules et jetez le premier élément (qui est 'Think of a number' )

V Car Nen cela:

  • Iq@N1\r Si le caractère à N[1]est'r' (répétez):
    • =NZDéfini Nsur Z(valeur précédente de N, définie à la fin de la boucle for)
  • x"asdm"@N1 Trouver l'index de N[1]dans"asdm" (additionner, soustraire, diviser, multiplier)
  • @"+-/*" Indexer avec cela dans "+-/*", donnant l'opérateur requis
  • ,J-eCN)\.Produire la liste à deux éléments [J, -eCN)\.], où le deuxième élément est le dernier élément de Nfractionnement sur un espace avec tous les '.'caractères supprimés (opérande)
  • qh@cN)1\f Si le premier caractère du deuxième élément de la Ndivision sur un espace est 'f'(soustraire de):
    • .> Échangez les éléments de la liste à deux éléments
  • + Fusionner l'opérateur et la liste à deux éléments en une seule liste
  • =Jjd Défini Jsur celui joint sur les espaces
  • =ZN Réglez ZsurN

J Impression J

TheBikingViking
la source
Nice answer man ... M'a inspiré à essayer dans 05AB1E, qui ... était plus intimidant que prévu.
Magic Octopus Urn
2

Pépin , 58 octets

Dommage que je n'ai pas encore implémenté cet opérateur de soustraction inverse.

{p:a:sNa?ap['Y("-y+  y- y// y+ y* "^sa@?Y`\d`)|'qa@y]}Mq^k

Le programme prend un script WordMath de stdin et sort le code Pip vers stdout. Le code qui est sorti, de la même manière, prend un nombre de stdin et sort le résultat vers stdout.Essayez-le en ligne!

Stratégie

Pour une entrée comme celle-ci:

Think of a number, multiply by 3, add 1.

nous voulons une sortie comme celle-ci:

YqYy*3Yy+1

qui fonctionne comme suit:

Yq    Yank a line of stdin into y
Yy*3  Compute y*3 and yank result into y
Yy+1  Compute y+1 and yank result into y
      Last expression is autoprinted

Non golfé + explication

{
 p : a : sNa ? a p
 [
  'Y
  ("-y+  y- y// y+ y* "^s a@?Y`\d`) | 'q
  a@y
 ]
} M q^k

La structure de base du programme est {...}Mq^k, qui se divise q(une ligne de stdin) sur k(espace virgule) etM applique une fonction à chaque élément.

À l'intérieur de la fonction, nous commençons par traiter le repeatcas. Le test le plus court dans Pip semble être sNa(y a-t-il un espace dans la commande). Si oui, nous voulons utiliser a; sinon, utilisez p, qui stocke la commande précédente. Attribuez cette valeur à aet également àp (pour la prochaine fois).

Pour notre valeur de retour, nous utilisons une liste, ce qui est bien car le format de sortie par défaut pour les listes est de tout concaténer ensemble. Le résultat commence toujours parY . Ensuite, nous avons besoin d'une table de recherche pour les opérations.

Notez que les longueurs de add (4), subtract (9), divide by (10), multiply by (12) et subtract from (14) sont toutes distinctes. Observez en outre qu'ils sont toujours distincts lorsqu'ils sont pris mod 7. Ainsi, nous pouvons les utiliser pour indexer dans une liste de sept éléments (contenant cinq extraits de code et deux espaces réservés) pour mapper chaque commande WordMath au code Pip approprié (conçu de sorte que le nombre peut être simplement enchaîné à la fin):

  • 0: -y+( subtract from)
  • 1: espace réservé
  • 2: y-( subtract)
  • 3: y//( divide by)
  • 4: y+( add)
  • 5: y*( multiply by)
  • 6: espace réservé

Pour les indices, nous utilisons regex pour obtenir l'index du premier chiffre de la commande: a@?`\d` . Nous avons également récupéré l'expression régulière ypour une utilisation future. La table de recherche est générée en fractionnant la chaîne "-y+ y- y// y+ y* "surs (espace).

Nous devons encore gérer la première entrée, qui devrait se traduire par le code Yq. Puisque Think of a numberne contient pas de chiffres, l' @?opérateur retourne nil. L'utilisation de nil comme index dans la table de recherche renvoie également nil. Nil est faux, donc tout ce que nous devons faire est d'ajouter |'qà utiliser qau lieu d'une opération dans ce cas.

Le dernier élément de la liste renvoyée est le numéro lui-même. Nous l'obtenons via a@y(trouver toutes les correspondances dans la commande de l'expression rationnelle numérique que nous avons tirée plus tôt). Cela renvoie une liste de chiffres, mais encore une fois, ce n'est pas un problème car toutes les listes seront concaténées lors de la sortie. Pour la première entrée, a@yne correspond à aucun chiffre et donne une liste vide, ce qui n'ajoute rien à la sortie.

Par exemple

Avec entrée

Think of a number, subtract from 20, add 2, repeat.

l'expression de la carte donne la liste

[["Y";"q";[]]; ["Y";"-y+";[2;0]]; ["Y";"y+";[2]]; ["Y";"y+";[2]]]

qui, une fois concaténé, produit

YqY-y+20Yy+2Yy+2
DLosc
la source
2

Python 2 , 154 153 146 octets

Correction, et même enregistré plusieurs octets dans le processus. ^ __ ^

for c in input()[9:-1].split(","):s=c.rfind(" ");p=o=s and"x="+"-x+ input() x- x// x+ x*".split()[s%7]+c[s:]*(c[0]<"a")or p;print o
print"print x"

Essayez-le en ligne!

Basé sur la même stratégie que ma réponse Pip . Fonctionnalités spécifiques à Python:

  • Think of et la fermeture .sont supprimées de la chaîne avant splitting ( input()[9:-1]). La période était trop embêtante pour être gérée dans la boucle principale. La suppression des neuf premiers caractères aide pour une raison différente (voir ci-dessous).
  • Au lieu d'obtenir la longueur de chaque commande en recherchant régulièrement un chiffre (cher en Python parce que import re), nous utilisons rfind(" ")pour trouver le dernier espace dans la commande. Nous pouvons également l'utiliser pour vérifier le repeatcas.
  • Python n'a pas l'indexation cyclique de Pip, nous devons donc prendre l'index mod 7 explicitement. D'un autre côté, cela signifie que nous pouvons supprimer la dernière valeur fictive de la table de recherche, car l'index mod 7 n'est jamais 6.
  • La "commande" la première fois est a number, dans laquelle se trouve l'index de l'espace 1. Cet index remplit commodément l'autre trou de la table de recherche. L'autre problème avec le traitement de l'étage d'entrée dans la boucle principale était la +c[s:]partie qui en résulterait x=input() number. Pour résoudre ce problème, nous multiplions les chaînes par c[0]<"a": 1pour toutes les commandes régulières, dans lesquelles ccommence par un espace, mais 0pour l'initiale a number.
DLosc
la source
1

WinDbg, 449 388 octets

as, }@$t1
as. }0;?@$t0
asThink n10;ed8<<22;r$t0=dwo(8<<22);r$t1=0;.do{
aSa " "
asQ .printf";r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0
as/c add Q +"
aSby " "
as/c divide Q /"
asfrom 0;r$t0=-@$t0+
as/c multiply Q *"
aSnumber " "
aSof " "
asrepeat +1
as/c subtract Q -"
.for(r$t9=1;by(@$t0);r$t0=@$t0+1){j44!=by(@$t0) .printf"%c",by(@$t0);.if116!=by(@$t0-1){.printf" , "}};.printf"\b ."

-61 octets en définissant un alias pour le code répété

Inspiré par l' utilisation de LambdaBeta#define . Cette approche modifie légèrement la syntaxe WordMath ( ,et .doit être délimitée par un espace comme les autres mots, et ,ne suit pas repeat), et crée un alias tel que la syntaxe WordMath modifiée est un code WinDbg valide. La dernière ligne fait ce que la question demande et transpose en convertissant l'entrée dans la syntaxe modifiée.

L'entrée est effectuée en définissant une chaîne à une adresse mémoire et en définissant le pseudo-registre $t0à cette adresse. Remarque: cela écrasera le intat 0x2000000, donc si vous commencez votre chaîne là-bas, elle sera partiellement écrasée. $t0sera également écrasé.

Parce qu'il crée des alias, selon que ce code s'est exécuté avant ou après avoir défini la chaîne, le code de sortie sera différent (aliasé ou non). Malheureusement, je n'ai pas trouvé de moyen pour que les alias se développent correctement sans être délimités par des espaces (ce qui signifie que le script WordMath ne pouvait pas simplement être exécuté directement sans être d'abord transformé).

Comment ça marche:

* $t1 is used for repeating and $t0 is used to read the input and hold the accumulator
* Alias , to }@$t1 -- closing do-while loop and allowing repeat
as , }@$t1

* Alias . to }0;?@$t0 -- close do-while loop and evaluate $t0 (accumulator)
as . }0;?@$t0

* Alias Think to (note this is one line)
as Think n10;               * Set base 10
         ed 8<<22;          * Read ints to address 0x2000000. Enter nothing to exit input mode
         r$t0 = dwo(8<<22); * Set $t0 = first int
         r$t1=0;.do{        * Open do-while

* Alias a to nothing
aS a " "

* Alias add to (note one line):
as add ;                       * Close previous statement
       r$t1=1;.do{r$t1=@$t1-1; * Open do-while (once) loop
       r$t0=@$t0+              * Add number to $t0

* Alias by to nothing
aS by " "

* Alias divide to (note one line):
as divide ;                       * Close previous statement
          r$t1=1;.do{r$t1=@$t1-1; * Open do-while (once) loop
          r$t0=@$t0/              * Divide next number from $t0

* Alias from to (note one line):
as from 0;         * Preceding subtract statement subtracts 0
       r$t0=-@$t0+ * Subtract $t0 from next number

* Alias multiply to (note one line):
as multiply ;                       * Close previous statement
            r$t1=1;.do{r$t1=@$t1-1; * Open do-while (once) loop
            r$t0=@$t0*              * Multiply next number with $t0

* Alias number to nothing
aS number " "

* Alias of to nothing
aS of " "

* Alias repeat to +1 making do-while (once) loops into do-while (once)+1
as repeat +1

* Alias subtract to (note one line):
as subtract ;                       * Close previous statement
            r$t1=1;.do{r$t1=@$t1-1; * Open do-while (once) loop
            r$t0=@$t0-              * Subtract next number from $t0


.for (r$t9=1; by(@$t0); r$t0=@$t0+1) * Enumerate the string
{
    j 44!=by(@$t0)                   * If not comma
        .printf "%c",by(@$t0);       * Print the char
    * implicit else
        .if 116!=by(@$t0-1)          * Else if the previous char is not t
        {
          .printf " , "              * Print the comma with spaces around it
        }
};
.printf "\b ."                       * Replacing ending "." with " ."

Exemple de sortie, en entrant la chaîne avant d'exécuter une fois ce code (le programme résultant ressemble à WordMath):

0:000> r$t0=8<<22
0:000> eza8<<22"Think of a number, add 5, add 10, multiply by 2, subtract 15, repeat, divide by 2."
0:000> as, }@$t1
0:000> as. }0;?@$t0
0:000> asThink n10;ed8<<22;r$t0=dwo(8<<22);r$t1=0;.do{
0:000> aSa " "
0:000> asadd ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0+
0:000> aSby " "
0:000> asdivide ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0/
0:000> asfrom 0;r$t0=-@$t0+
0:000> asmultiply ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0*
0:000> aSnumber " "
0:000> aSof " "
0:000> asrepeat +1
0:000> assubtract ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0-
0:000> .for(r$t9=1;by(@$t0);r$t0=@$t0+1){j44!=by(@$t0) .printf"%c",by(@$t0);.if116!=by(@$t0-1){.printf" , "}};.printf"\b ."
Think of a number ,  add 5 ,  add 10 ,  multiply by 2 ,  subtract 15 ,  repeat divide by 2 }0;?@$t0

0:000> Think of a number ,  add 5 ,  add 10 ,  multiply by 2 ,  subtract 15 ,  repeat divide by 2 }0;?@$t0
base is 10
02000000 6e696854 18
18
02000004 666f206b 

Evaluate expression: 18 = 00000012

Exemple de sortie, en entrant la chaîne après que ce code a été exécuté une fois (les alias sont développés lors de la saisie de la chaîne, de sorte que le programme résultant n'est pas aussi joli):

0:000> r$t0=8<<22
0:000> eza8<<22"Think of a number, add 5, add 10, multiply by 2, subtract 15, repeat, divide by 2."
0:000> as, }@$t1
0:000> as. }0;?@$t0
0:000> asThink n10;ed8<<22;r$t0=dwo(8<<22);r$t1=0;.do{
0:000> aSa " "
0:000> asadd ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0+
0:000> aSby " "
0:000> asdivide ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0/
0:000> asfrom 0;r$t0=-@$t0+
0:000> asmultiply ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0*
0:000> aSnumber " "
0:000> aSof " "
0:000> asrepeat +1
0:000> assubtract ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0-
0:000> .for(r$t9=1;by(@$t0);r$t0=@$t0+1){j44!=by(@$t0) .printf"%c",by(@$t0);.if116!=by(@$t0-1){.printf" , "}};.printf"\b ."
n10;ed8<<22;r$t0=dwo(8<<22);r$t1=0;.do{     number ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0+ 5 ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0+ 10 ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0*   2 ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0- 15 ,  repeat ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0/   2 }0;?@$t0

0:000> n10;ed8<<22;r$t0=dwo(8<<22);r$t1=0;.do{     number ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0+ 5 ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0+ 10 ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0*   2 ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0- 15 ,  repeat ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0/   2 }0;?@$t0
base is 10
02000000 3b30316e 26
26
02000004 3c386465 

Evaluate expression: 26 = 0000001a

Quelques exemples de sortie supplémentaires, en utilisant simplement la syntaxe WordMath légèrement modifiée:

0:000> Think of a number , add 1 , repeat repeat repeat divide by 3 .
base is 10
02000000 0000001a 3
3
02000004 3c386465 

Evaluate expression: 2 = 00000002


0:000> Think of a number , divide by 5 , subtract from 9 .
base is 10
02000000 00000003 29
29
02000004 3c386465 

Evaluate expression: 4 = 00000004
Lait
la source
0

Scala, 338 octets

Essayez-le vous-même chez ideone

s=>{val n=(_:String)filter(_.isDigit)toInt;(Seq("").tail/:s.split(",").tail)((a,&)=> &match{case&if&contains "v"=>a:+"x/="+n(&)
case&if&contains "d"=>a:+"x+="+n(&)
case&if&contains "y"=>a:+"x*="+n(&)
case&if&contains "f"=>a:+"x="+n(&)+"-x"
case&if&contains "s"=>a:+"x-="+n(&)
case p=>a:+a.last})mkString("var x=readInt;",";",";print(x)")}

Explication:

// define a function with a parameter s
s => {
    // define a function with a String parameter to extract a number from a string
    val n =
        // filter out the chars that arent't digits
        (_: String) filter (_.isDigit)
        // and parse the number
        toInt;
    // take the tail of a list with an empty string,
    // which is the empty list of type Seq[String].
    // This is the start value for the fold...
    (Seq("").tail /:
        // ... of the tail of the sentence splitted at commas
        s.split(",").tail
    ) (
        // This is the function for the fold.
        // a is the accumulator (the list), and the current element is called &
        (a, &) => & match {
            // if & contains a "v", append "x/=" + n(&) to a.
            case & if & contains "v" => a :+ "x/=" + n(&)
            // the other cases are similar
            case & if & contains "d" => a :+ "x+=" + n(&)
            case & if & contains "y" => a :+ "x*=" + n(&)
            case & if & contains "f" => a :+ "x=" + n(&) + "-x"
            case & if & contains "s" => a :+ "x-=" + n(&)
            // for the repeat, apppend the last value of a to a
            case p                   => a :+ a.last
        }
     )
     // make a string out of the parts by joining them with semicolons,
     // prepending "var x=readInt;" and appending ";print(x)"
     mkString("var x=readInt;", ";", ";print(x)")
}
corvus_192
la source