Transpile WordMath


25

우리는 모두 다음과 같은 온라인 "maths hax"를 보았습니다.

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

그리고 마술로 모든 사람은 숫자 8로 끝납니다!


언어

위의 텍스트 구문 인 "WordMath"를 사용하는 프로그래밍 언어를 정의 해 봅시다. WordMath 스크립트는 다음 템플릿을 따릅니다.

Think of a number, <commandlist>.

이는 기본적으로 다음을 의미합니다. (STDIN의 입력으로) 숫자를 초기 누산기로 가져 와서 모든 명령을 수행하고 결과를 출력합니다.

명령은 구분 기호 ,(쉼표 + 공백)로 구분됩니다. 유효한 명령은 다음과 같습니다 (음이 #아닌 정수 를 나타냄) .

  • add #/ subtract #-누산기에서 값을 더하거나 뺍니다.
  • divide by #/ multiply by #- floordiv 주어진 값만큼 / 곱셈 누산기.
  • subtract from #-와 비슷 subtract하지만 acc = # - acc대신acc = acc - #
  • repeat-마지막 명령을 다시 수행하십시오. 이것은 첫 번째 명령이 될 수 없지만 연속 된 여러 반복을 지원해야합니다.

도전

당신의 작업은 입력으로 유효한 WordMath 스크립트를 받아 프로그램이나 기능을 작성하는 것입니다 transpiles 코드가에있는 동일한 언어로 - 유효한 전체 프로그램으로.

예를 들어, 내 코드가 Python 2이고 스크립트는 다음과 같습니다.

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

출력 된 프로그램은 다음과 같습니다.

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

또는 대안으로 :

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

프로그램 이 언어 또는 가장 가까운 언어로 입력 하거나 STDIN인쇄 하는 전체 프로그램 인STDOUT.


규칙

  • 원래 프로그램은 입력이 항상 유효한 WordMath 스크립트라고 가정 할 수 있습니다.
  • 변환 된 프로그램은 0으로 나누기와 같은 수학적 오류를 처리 할 필요가 없습니다.
  • 변환 된 프로그램은 입력이 사용자 언어의 표준 정수 범위 내에서 유효한 부호있는 정수를 나타내는 것으로 가정 할 수 있습니다.
  • 이것은 이므로 가장 짧은 솔루션 (바이트)이 이깁니다.
  • 원래 프로그램의 바이트 수만 중요합니다-출력 코드는 원하는 길이만큼 길 수 있습니다!

스크립트 예

예 1 :

Think of a number. 

입력을 받고 아무것도하지 말고 표시하십시오 : WordMath의 고양이 프로그램.

예 2 :

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

"나누기"는이 프로그램의 6 -> 8경우 바닥 나누기라는 점을 기억하십시오 29 -> 4.

예 3 :

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

고양이 연장 프로그램!

예 4 :

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

숫자를 빼고 뺍니다 .3.


연속 반복을 지원해야합니까?
darrylyeo

1
언어의 기본 유형 인 정수를 지원하지 않는 경우 float를 사용할 수 있습니까?
Rainer P.

@RainerP. 언어가 정수 / 정수 나누기를 지원하지 않는 경우에만
FlipTack

1
예상되는 결과는 -5/3무엇입니까? 0음의 무한대 쪽으로 또는 반올림합니까?
Martin Ender

1
@MartinEnder 바닥 나누기 이므로 음의 무한대로 돌리고 싶습니다 . 그러나 언어가 0으로 정수 나누기를 구현하면 괜찮습니다.
FlipTack

답변:


6

05AB1E , 59 56 54 52 바이트

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

온라인으로 사용해보십시오!

그 후 내 뇌가 지옥처럼 아프다. 그것은 다음과 같이 05AB1E 코드로 출력된다.

  • Think of a Number 암시 적 입력으로 인해 제거됩니다.
  • Subtract From #은밀한 #s-(교환 ab작업 수행).
  • Subtract #로 변환합니다 #-.
  • Add #로 변환합니다 #+.
  • Multiply by #로 변환합니다 #*.
  • Divide by #로 변환합니다 #/.
  • Repeat 레지스터에 마지막으로 저장된 것을 잡고 연결합니다.

설명 :

„, ¡                                                 # 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.

예:

입력:

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

산출:

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

10의 입력으로 솔루션을 사용해보십시오.

온라인으로 사용해보십시오!

구글에서 참조하십시오 :

다음은 Google에 입력 한 것과 동일한 방정식에 대한 링크입니다.


13

C 전 처리기, 362 바이트

ALMOST가 C 전 처리기 에서이 작업을 수행했지만 반복 명령이 구현하기가 너무 어렵다는 것이 밝혀졌습니다. 대신 전처리기를 사용하여 입력을 배열로 바꾸고 추가 코드로 해석합니다.

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",_);}

입력은 "input.wm"에 제공되거나 해당 라인의 소스에 덤프되어야합니다. 나는 약간의 해키와 약간의 도전 규칙에 반하기 때문에 바이트 수를 내 카운트에 포함 시켰으므로 적합합니다.

어쨌든 컴파일러가 찾을 수있는 WordMath 소스를 input.wm에 덤프하면 WordMath 소스의 기능을 수행하는 실행 파일을 생성하라는 경고와 함께 그대로 컴파일 할 수 있어야합니다.


2
참고 : 불행히도 반복으로 끝내면 일부 컴파일러에서 실패합니다. 왜냐하면 그들은 0 다음에 공백을 던지고 길 잃은 마침표를보고 그것으로 무엇을 해야할지 모르기 때문입니다.
LambdaBeta

영리하고 감동합니다.
cat

7

레티 나, 170 바이트

누가 이걸보고 싶지 않을까요?!

Retina 솔루션을 보는 것이 얼마나 멋진 지 생각하고 신속하게 만들기로 결정했습니다. 한 시간 밖에 걸리지 않았습니다. 평소와 같이 바이트 수는 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

온라인으로 사용해보십시오

결과는 결과 프로그램을 테스트 할 때 복사해서는 안되는 후행 줄 바꿈이 있습니다. Retina의 표준 정수 범위 (단항)는 지원하지 않으므로 프로그램은 음수를 지원 하지 않습니다.

설명:

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

수학 프로그램 :

더하다:

시작 부분에 하나의 수를 추가하십시오. 추가 5 :

^
1111

덜다:

처음부터 하나의 숫자를 제거하십시오. 빼기 5 :

^11111

빼기 :

입력을 1s로 교체하십시오 x. 고정 번호 옆에 두십시오. 을 반복해서 제거하십시오 x1. 10에서 빼기 :

1
x
$
1111111111
+`x1

곱하기 :

모든 1것을 특정 수로 교체하십시오 . 3을 곱하십시오.

1
111

으로 나누기:

이것은 Integer Division에 대한 나의 Retina 프로그램을 사용합니다 . 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
$*

이것이 어떻게 작동하는지 모르겠습니다. 빼기 명령에 어떤 입력을 시도해도 결과가 깨집니다 (출력에 줄 바꿈이 누락 되었습니까?). 또한 이것이 부정적인 입력이나 부정적인 중간 결과를 처리하는 방법을 보지 못합니다.
Martin Ender

@MartinEnder이 단순화 된 프로그램이 출력에 두 가지를 제공하는 이유를 설명하면 빼기를 고칠 수 있습니다. retina.tryitonline.net/#code=JArCtjE&input=dGVzdAo
mbomb007

$문자열의 맨 끝 또는 후행 줄 바꿈 앞에 일치 하기 때문 입니다. \z전자 만 원하면 필요 합니다.
Martin Ender

4

GNU awk, 139 바이트

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

기도:

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

테스트 사례 :

$> 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;

4

하스켈 232 231 바이트

물론 함수형 프로그래머는 프로그램을 나타내는 문자열이 아닌 함수를 반환하는 것을 선호하지만 여기로 이동합니다.

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

비고 : 우리는 항상 0을 추가하는 것으로 시작합니다. 그렇지 않으면 사소한 WordMath 프로그램의 변환 read은 사용되는 유형을 유추하기에 충분한 정보를 제공하지 않습니다 . subtract from n로 구현 될 수는 (n-)있지만 ((-)n)더 균일하게 사용 합니다. 의 경우 subtract ni를 복사 subtract내가 작성하지 않아도 입력에서,하지만 난 끝에 누락 된 공간을 보완 할 필요가있다. repeat기본 작업으로 사용됩니다. 비어있는 초기 이전 작업과 함께 처음 네 단어를 쉽게 무시할 수 있습니다.

사용 예 :

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

다른 예제는 다음과 같은 결과를 제공합니다.

"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"

궁금한 점은 문자열 대신 반환하는 함수를 어떻게 생성하는 것입니까?
Cyoce

함수형 프로그래밍 언어에서 함수를 만들고 구성하는 것은 문자열을 만들고 추가하는 것보다 어렵지 않습니다. h처럼 보이고 h s n r|x<-s.read.init$n=x%r.x첫 번째 인수로 함수가 호출 될 수 있습니다 h(+)n r(그리고 flip올바른 연산자 순서를 얻으려면 어딘가에 있어야합니다) _%_=id. 주요 기능은 모든 상용구를 피할 수 있습니다 t l=id%words l. -카레 덕분에 통역사로 여겨 질 수 있으며, 그 아이디어는 더 쉽고 짧은 해결책으로 이어질 수 있습니다.
Christian Sievers

4

파이썬 2, 263 258 260 221 바이트

이것은 아마도 수 여전히 훨씬 짧습니다.

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(','))

온라인으로 사용해보십시오

마지막 명령어는 끝에을 가지고 있기 때문에 임의의 숫자를 부동 소수점으로 만들기 때문에 //대신을 사용 합니다 . 따라서 나눗셈의 일관성을 유지하기 위해 정수 나누기를 사용합니다./.

테스트 케이스 출력 :

print input()
print 9.-((input())//5)
print ((((((input())+5)+10)+10)-15)-15)//2.
print (((input())-1)-1)-1

당신의 큰 블록을 변경하는 경우 if에들 o(나는 일을해야한다고 생각하는) 다음에 : o=[[o+[['+-'['s'in c],'//']['v'in c],'*']['m'in c]+n,n+'-'+o]['f'in c],'input()']['T'in c]당신은 224에 그것을 아래로 얻을 수 있습니다
카데

@ Kade 그래, 여전히 읽을 수 있었다. 가질 수 없습니다.
mbomb007

@Cyoce 아니오, 람다를 부르는 행위는 아마도 절약하는 것보다 더 많은 비용이들 것입니다. 지불하기 위해 호출 당 4 또는 5 바이트를 저장해야합니다.
mbomb007

4

비 펀지, 342 305 바이트

>~$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

온라인으로 사용해보십시오!

산출

생성하는 코드는 &(입력 값) 명령으로 시작하여 .(출력 값) 및 @(종료) 명령으로 끝납니다 . 그 사이 <number><operation>에는 연산+(더하기), -(빼기), /(나누기), *(곱하기) 및 \-(빼기 ) 형식의 다양한 계산이 있습니다 .

그 요구에보다 큰 것을 수동으로 계산할 수 있도록 비 펀지 만, 범위는 0 ~ 9의 숫자 리터럴을 지원하기 때문에 자체는 조금 복잡하다. 우리는 이미 문자 단위로 숫자를 읽고 있기 때문에 각 숫자를 읽을 때 숫자를 쌓기 만하면됩니다 155+*2+55+*3+. 예 를 들어 123은 (((1 * 10) + 2) * 10) + 3입니다.

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-.@

설명

Befunge는 문자열을 조작하는 기능이 없으므로 대부분의 구문 분석은 문자를 세어 처리합니다. 우리는 처음 18자를 건너 뛰기 시작 합니다. 숫자 문구 의 생각 (쉼표 또는 마침표)을지나갑니다. 다음 문자가 줄 바꿈 또는 EOF 형식이면 출력 루틴으로 바로 이동하고, 그렇지 않으면 명령 목록을 계속 찾습니다.

명령을 구문 분석하기 위해 숫자 또는 구분 기호에 도달 할 때까지 문자 수를 계속 계산합니다. 분리자인 경우 특수한 경우로 처리하는 반복 명령이어야합니다. 숫자이면 출력 버퍼에 추가하고 더 많은 숫자를 계속 찾습니다. 숫자가 출력 될 때마다 우리는 앞에 접두사 55+*를 붙이고 (총 10을 곱하기 위해) 접미사를 붙이십시오 +(총에 더하기 위해). 숫자가 끝나면 명령 문자를 추가합니다.

명령이 어떻게 결정되는지에 관해서는, 우리가 첫 번째 자리에있는 문자의 수를 차지은 7. 모듈로 추가 에 대해 (다음 공간을 포함)이 4 빼기 는 2의를 위해, 에 의해 분열 이 들어, 3의 곱으로 는 5입니다 그리고위한 에서 빼기 그것의 0으로 에서 빼기 가 필요하기 때문에 약간의 추가 처리가 필요합니다 \-명령 콤보를하지만, 다른 사람들은 단지 테이블에서 적절한 명령 문자를 조회하기 위해 자신의 값을 사용합니다.

이 프로세스는 각 명령에 대해 반복되어 출력을 8 행의 사전 구성된 문자열로 구성합니다. 추가 명령이 추가 될 때마다 문자열에 닫는 따옴표를 추가하여 항상 올바르게 종료되도록합니다. 그런 다음 입력의 끝에 도달하면이 문자열을 "실행"하여 스택에 푸시 한 다음 표준 출력 시퀀스를 따라 출력합니다.


3

자바 스크립트 (ES6), 163 바이트

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)`

시도 해봐:

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)
*/


3

208 171 168 바이트

@ Flp.Tkc에 따라 행에서 여러 번 반복 할 수있는 기능이 추가되었지만 바이트 수를 줄일 수있는 충분한 바이트를 골라냅니다.

: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

인쇄 할 수없는 문자 :

: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^[^[

테스트 케이스 출력 :

  1. cw^R=^R" ^[ TryItOnline
  2. cw^R=((^R" /5) *-1+9) ^[ TryItOnline
  3. cw^R=((((((^R" +5) +10) *2) -15) -15) /2) ^[ TryItOnline

이것은 여러 번의 연속 반복에서는 작동하지 않는 것 같습니다.
FlipTack

@ Flp.Tkc 고정, 감사합니다! 나는 그것을 일찍 알아 차리지 못했습니다.
nmjcman101

2

lex, 246 바이트

%{
#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는 C를 대상으로하므로 C 컴파일러는이를 실행 파일로 컴파일해야합니다. 렉서 라이브러리 ( ll)도 연결해야합니다. 이것은 바이트 페널티를 추가 할 수 있지만 그렇다면 얼마나 많은 바이트인지 확실하지 않습니다.

이 프로그램은 변환 된 단어 수 식을 평가하는 lex 프로그램 (사양에 따라)을 출력합니다. 사이의 코드 %{와는 %}단지 "transpiler"입니다 :

#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 */

%%줄 사이에는 정규 표현식 / 작업 부분이 있습니다. 일치하는 첫 번째 규칙은 T( "Think ...")로 프리앰블을 빌드합니다 (lex 프로그램은 최소한 rule 섹션을 포함해야하며 yytext마지막으로 일치하는 텍스트이므로 규칙은 사용자 입력으로 누적기를 시드합니다. ).

일치하는 모든 입력을 제외한 프로그램을 폐기하고, 다른 규칙 ( ad, fr최대 re) 가능한 최소 일치 고유로서 함께 wordmath 식 절을 처리한다. 대부분의 c경우 표현식 접두어로 설정 되며, 호출 n될 때 읽은 마지막 정수 사이에 연결 됩니다 O(예 : "add 9"를 읽으면 접두사가 +=, v to 9이고 호출 O이 출력됩니다 n+=9;). . 흥미로운 점은 "8에서 빼기"는 규칙 sfr규칙 이 모두 일치하지만 O숫자에서만 호출되므로 올바른 규칙 n=-n+8;이 출력을 얻는 유일한 표현식이라는 것입니다. re"반복"단지 통화에 대한 규칙O다시, 마지막으로 생성 된 표현식을 출력합니다 (그리고 이후의 일치는 clobber하기 때문에 yytext"반복"을 지원하기 때문에 [0-9]+규칙 의 정수 변환 이 필요한 이유입니다 ). 마지막으로 마침표는 프로그램 트레일러가 출력되도록하며, 어큐뮬레이터 만 출력 %%하고 출력 lex 프로그램의 끝을 나타내는 쌍으로 닫힙니다 .

참고 : 기본 트랜스 파일러 프로그램 또는 출력 프로그램이 종료되지 않습니다. 배관 입력이 작동하거나 EOF (ctrl-D)를 제공합니다. 첫 번째 입력 후에 종료가 필요한 경우 exit ()를 추가 할 수 있습니다.

빌드 / 실행하려면

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
%

시험 1 :

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

시험 2 :

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

시험 3 :

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

시험 4 :

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

2

Pyth, 69 67 바이트

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

를 입력 "quoted string"하고 결과를 인쇄 하는 프로그램입니다 .

테스트 스위트

작동 원리

Pyth에는 접두사 연산자가 있으므로 기본 산술 연산은을 사용하여 수행되는 (operator)(operand1)(operand2)반면 사전 초기화 된 변수 Q는 입력을 제공합니다. 따라서 변환 된 WordMath 프로그램은 문자열로 시작하여 'Q'각 단계에서 연산자를 추가 한 다음 필요에 따라 피연산자를 앞에 추가하거나 추가하여 구성됩니다.

J\Q설정 J문자열의 transpiled 프로그램 문자열,'Q'

tcQ\, 입력을 쉼표로 나누고 첫 번째 요소 ( '' Think of a number') 를 버립니다.

V 이를 위해 N:

  • Iq@N1\r 의 문자 N[1]'r'(반복) 인 경우 :
    • =NZ집합 NZ(이전 값을 N루프의 끝 부분에 설정)
  • x"asdm"@N1 의 인덱스를 찾기 N[1]에서 "asdm"(추가, 빼기, 나누기, 곱하기)
  • @"+-/*" 로 색인 "+-/*"하여 필요한 연산자를 제공하십시오.
  • ,J-eCN)\.[J, -eCN)\.]번째 요소 인 두 요소 목록을 생성합니다 . 여기서 두 번째 요소는 N공백 에서 분리 된 마지막 요소이며 '.'문자가 제거 된 (피연산자)
  • qh@cN)1\fN공백 에서 분할 의 두 번째 요소의 첫 문자 가 'f'(빼기) 인 경우 :
    • .> 두 요소 목록의 요소 교체
  • + 연산자와 두 요소 목록을 하나의 목록으로 병합
  • =JjdJ공백에 결합 된 것으로 설정
  • =ZN 설정 ZN

J 인쇄 J


좋은 대답을 한 사람 ... 05AB1E에서 시험해 보라고 영감을주었습니다. 예상보다 더 위협적이었습니다.
Magic Octopus Urn

2

, 58 바이트

너무 나쁜 나는 아직 그 역 빼기 연산자를 구현하지 않았습니다.

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

프로그램은 stdin에서 WordMath 스크립트를 가져 와서 Pip 코드를 stdout으로 출력합니다. 비슷하게 출력되는 코드는 stdin에서 숫자를 가져 와서 결과를 stdout으로 출력합니다. 온라인으로 사용해보십시오!

계략

다음과 같은 입력의 경우 :

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

우리는 다음과 같은 출력을 원합니다.

YqYy*3Yy+1

다음과 같이 작동합니다.

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

언 골프 + 설명

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

프로그램의 기본 구조는 입니다 (쉼표 공간) 에서 ( stdin의 행) {...}Mq^k을 분할 하고 각 요소에 함수를 적용합니다.qkM

함수 안에서는 repeat케이스 를 처리하는 것으로 시작합니다 . Pip에서 가장 짧은 테스트는 sNa(명령에 공백이 있는지)있는 것 같습니다 . 그렇다면 우리는 a; 그렇지 않은 경우 p이전 명령을 저장하는를 사용하십시오. 해당 값 ap(다음에) 다시 지정하십시오 .

반환 값으로는리스트를 사용하는데,리스트의 기본 출력 형식은 모든 것을 하나로 연결하는 것이기 때문입니다. 결과는 항상로 시작합니다 Y. 다음으로 작업을위한 조회 테이블이 필요합니다.

의 길이 관찰 add (4), subtract (9), divide by (10), multiply by (12) 및 subtract from (14) 모두 별개. 또한 mod 7을 취했을 때 여전히 구별된다는 것을 관찰하십시오. 따라서, 우리는 그것들을 7 요소리스트 (5 개의 코드 스 니펫과 2 개의 플레이스 홀더를 포함)로 색인하여 각 WordMath 명령을 적절한 Pip 코드 (숫자에 맞게 설계됨)에 매핑 할 수 있습니다 단순히 끝에 연결할 수 있습니다) :

  • 0 : -y+( subtract from)
  • 1 : 자리 표시 자
  • 2 : y-( subtract)
  • 3 : y//( divide by)
  • 4 : y+( add)
  • 5 : y*( multiply by)
  • 6 : 자리 표시 자

색인의 경우 정규식을 사용하여 명령에서 첫 번째 숫자의 색인을 가져옵니다 a@?`\d`. 우리는 또한 y나중에 사용할 수 있도록 정규 표현식을 작성합니다. 조회 테이블은 문자열 "-y+ y- y// y+ y* "s(공백) 으로 분할하여 생성됩니다 .

우리는 여전히 첫 번째 항목을 처리해야하며 이는 코드로 변환되어야합니다 Yq. 이후 Think of a number의 숫자를 포함하지 않는의 @?운영자은 nil을 반환합니다. 조회 테이블에 대한 색인으로 nil을 사용하면 nil도 리턴됩니다. Nil은 거짓이므로, 이 경우에는 작업 대신에 add |'q를 사용 하기 만하면 q됩니다.

반환 된 목록의 마지막 요소는 숫자 자체입니다. 우리는 이것을 통해 이것을 얻습니다 a@y(앞에서 yan 어 둔 숫자 정규식 명령으로 모든 일치 항목을 찾으십시오). 이것은 자릿수 목록을 반환하지만 다시 출력 할 때 모든 목록이 연결되므로 문제가되지 않습니다. 첫 번째 항목의 경우 a@y숫자와 일치하지 않고 빈 목록을 제공하므로 출력에 아무것도 추가되지 않습니다.

예를 들어

입력

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

지도 표현은 목록을 제공합니다

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

연결되면 출력되는

YqY-y+20Yy+2Yy+2

2

파이썬 (2) , 154 (153) 146 바이트

프로세스에서 여러 바이트를 수정하고 저장했습니다. ^ __ ^

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"

온라인으로 사용해보십시오!

Pip 답변 과 동일한 전략을 기반으로합니다 . 파이썬 관련 기능 :

  • Think of .분할하기 전에 문자열에서 닫힘 이 제거됩니다 ( input()[9:-1]). 메인 루프에서 처리하기에는 너무 성가신 시간입니다. 처음 9자를 제거하면 다른 이유로 도움이됩니다 (아래 참조).
  • 숫자를 정규식으로 검색하여 각 명령의 길이를 얻는 대신 (파이썬에서는 비싸기 때문에 import re) rfind(" ")명령의 마지막 공간을 찾는 데 사용 합니다. 이를 사용하여 repeat사례 를 확인할 수도 있습니다 .
  • 파이썬에는 Pip의 주기적 색인이 없으므로 색인 모드 7을 명시 적으로 가져와야합니다. 반면에 인덱스 모드 7이 6이 아니기 때문에 조회 테이블에서 마지막 더미 값을 제거 할 수 있습니다.
  • 처음으로 "명령" a number은 공간의 색인이 1입니다. 이 색인은 룩업 테이블의 다른 구멍을 편리하게 채 웁니다. 메인 루프에서 입력 스테이지를 처리 ​​할 때 발생하는 다른 문제는 +c[s:]부분 이었습니다 x=input() number. 이 문제를 해결하기 위해 공백으로 시작하지만 초기 는 모든 일반 명령에 대해 c[0]<"a"다음 과 같이 문자열을 곱합니다 .1c0a number

1

WinDbg, 449 388 바이트

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 바이트

LambdaBeta의 사용에서 영감을 얻었습니다#define . 이러한 접근 방식의 수정합니다 WordMath 구문이 약간 ( ,.공백으로 구분 된 다른 단어처럼해야하며, ,따르지 않는 repeat), 그리고 수정 된 WordMath 구문이 유효 WinDbg는 코드가되도록 별칭을 만듭니다. 마지막 줄은 입력을 수정 된 구문으로 변환하여 질문에서 요구하는 내용을 수행합니다.

메모리 주소에서 문자열을 설정하고 의사 레지스터 $t0를 해당 주소 로 설정하면 입력이 이루어집니다 . 참고 :이 intat 을 덮어 쓰므로 0x2000000문자열을 시작하면 부분적으로 덮어 씁니다. $t0덮어 씁니다.

이 코드는 문자열 설정 전후에 실행되었는지에 따라 별칭을 생성하므로 출력 코드가 달라집니다 (별칭 또는 불일치). 불행히도 공백을 구분하지 않고 별칭을 올바르게 확장하는 방법을 찾지 못했습니다 (즉, WordMath 스크립트를 먼저 변환하지 않고 직접 실행할 수 없음을 의미합니다).

작동 방식 :

* $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 " ."

이 코드를 한 번 실행하기 전에 문자열을 입력하는 샘플 출력 (결과 프로그램은 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

이 코드가 한 번 실행 된 후 문자열을 입력 한 샘플 출력 (문자열을 입력 할 때 별칭이 확장되어 결과 프로그램이 예쁘지 않음) :

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

약간 수정 된 WordMath 구문을 사용하는 샘플 출력 :

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

0

스칼라, 338 바이트

이데온에서 직접 해보십시오

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)")}

설명:

// 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)")
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.