
Sorry but this page is written in Korean. If you cannot read Korean text, please visit this page.
공백 문자(whitespace), 그러니까 공백, 탭, 줄바꿈 문자로만 이루어진 프로그래밍 언어인 Whitespace 0.3의 완전한 구현과 몇 가지 툴을 모은 프로그램입니다. 더불어 이 프로그램은 제가 처음으로 모양을 갖춰서 만든 코드이기도 합니다. -- 아시는 분은 아시겠지만 스쿨 럼블(School Rumble)의 츠카모토 텐마(塚本天満)입니다 :D -- Whitespace에 대한 자세한 내용은 공식 홈페이지나 한국어 위키백과의 글을 참고하세요.
여담입니다만, 처음에는 인터프리터만 만들려 했습니다. 그래서 인터프리터를 만들고 나서 틀을 짰는데 틀에 코드를 다 넣고도 한참 남길래, 한 번 Whitespace 어셈블러를 넣어 보기로 작정하였습니다만 (Whitespace는 공백 문자만으로 이루어진 언어라서 그냥 편집하기에 매우 힘듭니다. 그래서 Whitespace와 1대 1로 대응되는 명령들을 미리 써서 작업한 후 나중에 공백 문자로 변환해서 코드를 편집하는데 이 때 사용하는 "중간 언어"를 Whitespace 어셈블리 언어라 합니다.) 코드를 다 짜고 보니까 코드 크기가 두 배가 되어 버렸습니다. -_-; 덕분에 틀을 다시 짜고 난리를 쳤는데 아무튼 결과물이 좋으니까 저야 만족이지요.
덧붙임: 이거 보고 제가 텐마 양의 팬이라고 하시는 분이 있는데 전 어디까지나 야쿠모를 더 좋아합니다-_-; 다만 적당한 이미지나 장면을 찾기 힘들어서 텐마 이미지로 대신 만든 거라고요. 정말이에요;;
코드 맨 처음부터 맨 끝까지 공백 하나도 빠짐 없이 정확하게 갖다 써야 동작합니다. (특히 첫 글자가 공백이 아니라 작은 따옴표라는 것을 주의하세요)
' 20041208\
';from string import*;\
d=replace;R=(d(d(d(d(d(d(d(d(d(d(
d(d(d(d(d(d(d(d(d("def N#:?p=[0]?whV p["
"H]<2:p+=[r#]?^turn((p[1]H)%3H)*^duce(F x,y:x*"
"2+y,p[2:H],0)\ndef L#:?p=(0,)?whV p[H]<2:p=p+(r#,)?"
"^turn p[1:H]\ndef M(l):?v=^duce(F a,b:a*2+b,l,0L)?if 7&"
"Jl)C v==0:^turn'label%d_%s'%(Jl)&3,hex(v)[2:HQ?else:^turn " ###############################
"j([`chr(v>>k&255)`[1:H]fC k $ range(Jl)-8,H,-8)Q\nfrom sys imp" # TokigunStudio presents #
"Ct*;from Str$gIO impCt*;X='push,dup,copy,swap,pop,slide,add,sub,m" # Whitespace 0.3 Implementation #
"ul,div,mod,stCe,^trieve,c""all,jmp"",jz,jn,^t,halt,putchar,putP,getch" # by Kang Seonghoon (Tokigun) #
"ar,getP'.splR(',~;Y='E,02" "0,010," "021,022,012,1E0,1E1,1E2,1010,1011" ## ###########################
",110,111,201,202,210,211," "212,2" "22,12E,1201,1210,1211'.splR(',~;Z" # # tokigun@gmail.com
"='101EEEEE2222EEE';v=argv" "[1:];" "n,=Jv)B[v[0][0]=='-'B{'-c':1,'-d'" ##
":2,'--':0}.get(v.pop""(0)," "3)C " "0]C[3];j=''.jo$;x=exR\nif n>2 C[1"
",2,2][n]!=Jv):prP'To""kig" "unS" "tudio WhRespace 0.3 Implementati"
"onGby Kang Seonghoon" " <" "tok" "igun@gmail.com>GGUsage: python "
"%s <fV>G C: pytho" "n " "%s" " [-c|-d] <$fV> <outfV>GGno ar"
"g\\texecute whRespac" "e" "" " c""ode.G-c\\tcompV whRespa"
"ce assembly code.G-d" "" "\\tdecomp" "V whRespace assembly c"
"ode.G'%(argv[0],arg" "v[0Q"";x(0)\n" "try:s=fV(v[0],'r~.^ad#;f=n B fV(v[1"
"],'w~;v=tupA(v)\nex" "cept:" "pr" "P'c" "an" "not o" "pen fV.';x" "(1)\nif"
" n""==1:?prP'co""m""pV"" ' '" "%s " "t" "o %s.." ".'%v,;N=" "F n:n"
" " "B('\\t '[n>" + "" "0]" "+N(a" "" "" "bs(" "" "n)/2)[1:" "H]+' '"
"" "'\\t'[n%2]" "" "+'" "G~C'G';L=" "" "F " "" "l:j([j([" "' \\"
"" "t'[Cd" "(v" "" ")>>" "" "k&1]fC k " "" "$ " "" "range(7,H" ",H)"
"QfC ""v " "$ " "" "lQ+'G'?" "fC l $ s." "" "splRl$es#" ":"
"? l" "" "=" +"(" "" "';'$ l" " B l[:l.f" "$d(';~]C l)" "."
"sp" "" + "l" "R#;Jl)" "B':'==l" "[" "0][H]B f.wrRe" ""
"(" + "" "'G " "'+" "L(l.pop(0)[:HQ)"
"?" + "" "" " " "if Jl):p=X.$dex(l["
"" + "" "" "" "0].lower#);p+1 B Jl)>("
"" + "" "" r"Z[p]>'0~B f.wrRe(j([' \tG'"
"" "[" "P(k)]fC k $ Y[p]Q+(Z[p]>'0'B"
"" "(0" ",F a:N(P" "(a)),L)[P(Z[pQ](l[1QC'~)?f.clo"
"se#" ";prP'done" ".';x(0)\nelif n:prP'decompV %s to"
" %s..." "'\45" +"v,\ns=Str$gIO(j([{32:'0',9:'1',10:'"
"2'}.get(" "C" "d(c),'~fC c $ sQ);r=F:P(s.^ad(1));W"
"=F h:h==s.^" "a" "d(Jh))C s.seek(i,0);c=[];p={}\nwhV[N"
"one]!=c[H:]:?i=s" ".t" "ell#?if W('2E~:l=L#;p[l]=Jc);n B f.wr"
"Re(M(l)+':G~?else:v=" "^d" "uce(F a,b:a C W(Y[bQB(b,(P,N,L)[P(Z[bQ"
"]#),range(23),0);c+=[v];n B v B f" ".wrRe(' '+X[v[0]]+(Z[v[0]]>'0'B(' '+("
"0,str,M)[P(Z[v[0]Q](v[1Q)C'" "~+'G~\nif n:f.close#;prP'done.';x(0)\ns"
"=[];h={};q=[];u=s.append;U=" "F:Js)B s.pop#;i=k=0;c.pop#\nwhV i<Jc)B k"
"H8:?k,v=c[i];i+=1?if k==0:u(" 'v)"1:n=D;u(n);u(n)?elif(k==2)&(v>0):u(s['
'-vQ"3:n=D;m=D;u(n);u(m)"4:D"' '5:s[-vH:H]=[]"6:u(D+D)"7:u(-D+D)"8:u(D*'
'D)"9:n=D;u(D//n)"10:n=D;u(D%' 'n)"11:n=D;h[D]=n"12:u(h.get(D,0))"13:'
'q+=[i];i=p[v]"14:i=p[v]"1' '5 B D==0:i=p[v]"16 B D<0:i=p[v]"17 '
'B Jq):i=q.pop#"19:stdo' "u" 't.wrRe(chr(D))"20:stdout.wrRe'
'(str(D))"21:h[D' "" "]=" 'Cd(std$.^ad(1))"22: ? v='
"''? whV('" "" "0" "'+v[v[0:1]=='-':Q.i"
"sdigR" "" "#" ":v+=std$.^ad(1)?"
" h" "" +"[D]=P(v" "[:H]+'0~/10",""
"~", "" "')"),"^", "r" "e"),"V","iA")
,"" "" "R" ,"it"),"Q","]"
"" "" "" ")"),"P","$t"),
"" "" +"J","An("), "" "H","-1" ),"G",
"" "\\n"),"F"'' "" ,"" "lambda"),"E",""
"" "" "" "0" "" "" "0"),"D","U#"),""
"" "" "" "C" "" ,"" "or"),"B","and")+
"" "" "" ,"" "" "" "A","le"),"?","\n"
"" "" "" "" "" "" " "),"$","in"),"#",
"" "" "" "" "" "" "()"),'"',"\12 eli"
"" "" "" "f" "" "" "" " k=="));exec("from"
"" "" "" "" "" "" " sys import*\nif['"
"" "" "" "" "" +"" "--source']==argv[1"
"" ":2" "" "" "]" ":print'# TokigunSt"
"" "u" "" "" "" "dio Whitespace Imp"
"" "" "" "" "" "lementation\\n\\n'"
"" "" "" "" "" "+R\nelse:exec R\n")
덧붙임: 처음에 올리고 나서 맘에 안 드는 부분이나 이상한 곳이 있어서 조금 조금씩 수정한 곳이 있습니다. 물론 기능은 바뀌지 않았지만 (아, 오타 수정한 건 있습니다 -_-) 혹시나 이상하게 생각하실 지도 몰라서 미리 적어 둡니다 :)
일단 이 프로그램을 실행하기 위해서는 파이썬 인터프리터가 필요합니다. 2.3 이상 버전에서 동작하며 그 아래 버전은 실행되지 않는다는 것을 확인했습니다 (-_-;;)
파이썬 인터프리터를 python라고 가정합시다. 다른 인자 없이 실행하면 다음과 같은 사용법 화면이 나옵니다:
$ python tenma.py TokigunStudio Whitespace 0.3 Implementation by Kang Seonghoon <tokigun@gmail.com> Usage: python tenma.py <file> or: python tenma.py [-c|-d] <infile> <outfile> no arg execute whitespace code. -c compile whitespace assembly code. -d decompile whitespace assembly code.
이 프로그램을 인터프리터로 주려면 파일 이름을 인자로 주면 됩니다. 파일 이름이 -로 시작하면 첫 인자에 가짜 인자인 --를 먼저 주면 됩니다.
$ python tenma.py hello.ws Hello, world of spaces!
컴파일러는 첫 인자를 -c로, 디컴파일러는 -d로 준 후 뒤에 입력 파일과 출력 파일 이름을 인자로 주면 실행할 수 있습니다.
$ python tenma.py -d hello.ws temp.wsa decompile hello.ws to temp.wsa... done. $ python tenma.py -c temp.wsa temp.ws compile temp.wsa to temp.ws... done. $ python tenma.py temp.ws Hello, world of spaces!
이 프로그램에 있는 마지막 기능은 이 프로그램의 실제 코드를 출력하는 기능입니다. --source 인자를 주면 됩니다.
$ python tenma.py --source
# TokigunStudio Whitespace Implementation
def N():
p=[0]
while p[-1]<2:p+=[r()]
return((p[1]-1)%3-1)*reduce(lambda x,y:x*2+y,p[2:-1],0)
def L():
p=(0,)
while p[-1]<2:p=p+(r(),)
...중략...
elif k==21:h[U()]=ord(stdin.read(1))
elif k==22:
v=''
while('0'+v[v[0:1]=='-':]).isdigit():v+=stdin.read(1)
h[U()]=int(v[:-1]+'0')/10
이 인터프리터는 Whitespace 0.3 공식 인터프리터와 몇 가지 동작에서 차이가 있습니다:
이들은 물론 고칠 수는 있지만 귀찮아서 안 합니다. :p