Ai! Jack!v2026.04.01-f12
← 홈GeekNews 인기

1024바이트로 Python 인터프리터 만들기

원문 보기GeekNews에서 보기
5 pointsby neo미국

AI 분석

•매크로나 라이브러리 편법 없이 C 소스 1024바이트로 Python 문법 일부 실행
•별도 토큰화·AST·바이트코드 생성 없이 즉시 실행하며 반복문·함수 호출은 소스 위치 이동 후 재파싱
•실무보다는 극단적인 크기 제약에서 인터프리터 구조를 단순화하는 학습 사례로 유용

검증 정보

출처
austinhenley.com
피드
GeekNews 인기
수집/분석 기준
2026. 9. 8. 오전 9:00
원문 확인
원문 열기

본문

•매크로나 라이브러리 편법 없이 C 소스 1024바이트 에 Python 문법 일부를 실행하는 인터프리터를 담음
•토큰화·AST·바이트코드 생성 대신 소스를 파싱하면서 즉시 실행 하며, 반복문과 함수 호출은 소스 위치를 이동해 다시 파싱하는 방식으로 처리함
•정수 연산, 비교, 들여쓰기 블록, 조건문, 반복문, 재귀 함수 호출 등을 지원하지만, 변수 이름은 소문자 한 글자 로 제한되고 오류 처리는 전혀 없음
•읽기 쉬운 버전의 4800바이트 이상 코드를 GNU C89 특성과 코드 골프 기법 으로 압축했으며, 두 버전 모두 GitHub에 공개함
•처음에는 512바이트를 목표로 했다가 계산기에 가까운 결과에 그쳐 목표를 늘렸으며, 끝내 성공했지만 방금 고친 코드도 이해하기 어려워 당분간 코드 골프는 다시 하지 않겠다고 마무리

512바이트 계산기에서 1024바이트 Python으로

•주말에 직접 코드를 작성하며 매크로나 라이브러리 편법 없이 C로 작은 Python 인터프리터를 만드는 도전에서 출발함
•Python 전체 대신 Python처럼 보이는 문법 을 구현 대상으로 삼음
•예제 FizzBuzz는 def buzz() , for n in range(101) , 중첩 if · else , print 와 함수 호출로 구성됨
• def , 콜론, 들여쓰기, 괄호 없는 if 조건식이 Python다운 형태를 만듦
•문법의 일부만 구현하는 것 외에도 추가 제약이 필요했음
•첫 시도에는 Teeny Tiny 컴파일러 등을 만들 때 사용한 재귀 하강 파서 방식을 적용함
• 1 + 2 에서 x = 1 + 2 * 3 , if x > y: z = 3 순으로 확장했지만, 결과는 목표와 달리 계산기에 가까웠고 이미 512바이트를 넘었음
•Python다운 요소를 다시 추린 뒤 목표를 1024바이트 로 늘리고, 먼저 동작하게 만든 다음 크기를 줄이기로 함

소스를 직접 실행하는 파서

•CPython 은 토큰화, 추상 구문 트리(AST) 생성, 분석·최적화, 바이트코드 생성과 실행을 거치지만, 이 구현은 그런 처리 단계를 거의 사용하지 않음
•실행 상태는 소수의 전역 변수와 고정 길이 배열 에 저장함
• char src[999] 에 대부분의 공백을 제거한 소스를 보관함
• int vars[256] 하나에 변수와 함수 이름에 대응하는 값을 저장함
• pos , ch , line_start 로 다음 문자 위치, 현재 문자, 현재 줄 시작 위치를 추적함
•표현식은 재귀 하강 방식으로 파싱하면서 계산 함
•덧셈·뺄셈 파서는 하위 항을 계산한 뒤 연산자를 따라 값을 누적함
• 오류 처리는 전혀 없으며 , 입력 코드가 올바르다는 여러 가정에 의존함
•키워드가 정확하게 입력됐다고 가정하고 첫 글자를 확인한 뒤 나머지를 고정 길이만큼 건너뜀
• for 에서는 or 와 inrange( 를, while 에서는 hile 을, if 에서는 f 를 건너뜀
•토큰 경계도 올바르다고 가정하며, 들여쓰기와 문자열 리터럴 내부를 제외한 대부분의 공백을 제거함
•변수 이름은 소문자 한 글자 로 제한해 문자 값을 vars 의 인덱스로 직접 사용함

들여쓰기와 소스 위치로 구현한 제어 흐름

•블록 실행 함수는 들여쓰기가 줄어들 때까지 실행하며, 줄어들면 현재 줄 시작으로 위치를 되돌리고 호출자에게 제어를 반환함
•다음 줄 처리는 호출자가 맡고, 블록의 재귀적 실행에는 C 호출 스택 을 사용함
• while 과 for 는 조건식의 소스 위치를 저장하고, 본문 실행 후 그 위치로 돌아가 매 반복마다 다시 파싱 함
•별도의 컴파일 결과는 보관하지 않음
•함수 정의 시 심벌 테이블에 함수 본문의 소스 위치 를 기록함
•호출할 때는 호출자 위치를 저장하고 함수 본문으로 이동해 실행함
•본문이 끝나면 호출자 위치를 복원함
•이 방식으로 중간 표현 없이도 반복문과 함수 호출을 처리하며, 인터프리터가 유지해야 할 상태도 매우 적음

코드 골프로 1024바이트에 맞추기

•코드 골프 경험이 많지 않은 상태에서 Tips for golfing in C 를 참고해 크기를 줄임
•이름과 공백을 줄이는 것 외에도 GNU C89에 특화된 기능 과 다음 기법을 활용함
•변수·함수 이름을 한 글자로 바꾸고, 컴파일러가 libc 를 링크한다고 가정함
•임시값을 전역 변수에 저장하고 전역 변수의 0 초기화 를 활용함
•C89의 암시적 int 선언과 함수 반환형을 이용함
•호출 스택에 보존해야 하는 임시값은 함수 매개변수에 저장함
•문자 리터럴 대신 ASCII 값을 쓰고, 삼항·쉼표 연산자를 활용함
•논리 연산 대신 비트 연산을 사용함
•덧셈·뺄셈 파서는 ASCII 값 계산 을 활용해 e(){for(z=t();c-43u<3;)y=44-c,z+=y*t();return z;} 로 압축함
•줄 끝까지 건너뛰는 재귀 함수는 단락 평가 를 이용해 Y(){c&&c-10&&Y(G());} 로 줄임
• c 로 소스 끝을, c-10 으로 줄바꿈 여부를 검사하고 && 로 if 를 대체함
• G();Y(); 대신 Y(G()); 를 사용해 한 바이트를 더 절약함
•최종 압축본은 정확히 1024바이트 , 읽기 쉬운 버전은 4800바이트 이상임
•크기에 맞추기 위해 원래 구현했던 여러 기능을 삭제함
•다음 삭제 후보는 비교 표현식이었으며, 비교 연산이 없어도 if n%15: 처럼 정수의 참·거짓 판정은 가능함
•FizzBuzz 실행만 목표로 삼으면 800바이트 미만도 가능할 것으로 예상했으며, 추가 압축 기법의 여지도 남아 있음

최종 지원 기능과 제약

• 정수 변수·리터럴과 대입 을 지원함
•변수 이름은 한 글자로 제한됨
• 산술·비교 표현식 을 지원하되 범위에 제한이 있음
• + , - , * , % 의 연산자 우선순위를 처리함
•단항 + · - 는 표현식 시작에서만 동작함
• < , > , <= , >= , == 를 지원하며, 비교는 표현식당 하나만 가능함
•정수의 참·거짓 판정도 지원함
• 조건문과 반복문 을 실행할 수 있음
• if · else 를 지원함
• while 과 for x in range(y) 는 각각 else 블록도 사용할 수 있음
• 인수 없는 함수 정의와 재귀 호출 을 지원함
•들여쓰기로 블록을 구분하지만 별도 스코프는 없음
•` print` 와 주석 을 지원함
• print 는 문자열 리터럴 하나 또는 정수 표현식 하나를 출력함

공개 코드와 압축 과정의 부담

•읽기 쉬운 버전과 1024바이트 압축본은 모두 GitHub의 python1024 에 공개돼 있음
• 변경 내용을 따라가기 어려웠던 코드 골프
•압축 중인 코드와 원본을 오가며 불과 2분 전에 바꾼 내용을 다시 파악해야 해서 작업이 상당히 번거로웠음
•가까운 시일 내에는 코드 골프 도전을 다시 하지 않을 생각임

댓글 1개

neo

Hacker News 의견들

•코드가 너무 과감하게 편법을 써서 웃음이 남. 지원하는 문법 범위에서 오류 검사까지 하는 작은 C 컴파일러 C4와는 다르고, 소스가 무조건 올바르다고 가정하며 온갖 지름길을 택하는 Sector C보다도 더함.

이 “Python”은 첫 글자만으로 키워드를 판별 함. f 는 무조건 for [x] in range[y] 형태이고 다른 for 문은 지원하지 않으며, w 는 while , i 는 if , d 는 def , p 는 print( 로 간주함.

게다가 글에 실린 코드가 GitHub의 “읽기 쉬운” 버전보다 주석이 많아서, 동작을 이해하려면 글까지 읽어야 함. Tiny Python이라기엔 너무 단순 한 듯함. 몇 KB만 더 허용해서 최소한 리스트와 딕셔너리는 지원하면 좋겠음. Lisp도 가능한 기능임!

• w = 4 처럼 단순한 코드도 실패한다는 뜻인가? 내 취향에는 너무 과한 편법임. 내가 택할 방식은 아니지만, 들인 노력과 읽기 쉬운 글은 높이 평가함. 내가 최근 몇 달간 직접 작성한 코드보다도 사람이 쓴 코드가 더 많기도 함!
•성능을 포기할 수 있다면 선형 탐색으로 딕셔너리 를 구현해서 제대로 된 해시 테이블보다 코드량을 훨씬 줄일 수 있음.
•옛날 Apple II BASIC 이 떠오름. 변수 이름은 마음대로 지어도 실제로는 처음 두 글자만 의미가 있었음.
• JavaScript 코드 축소 에 쓰이는 기법들과 상당히 닮아 보임.
•실제 운영 환경에서 이런 것이 필요하다면 Snek 이 있음. https://sneklang.org/ 은 플래시와 RAM이 몇 KB뿐인 프로세서를 대상으로 하는 작은 내장형 언어임.
•Forth도 있음.
•다만 Snek을 소스에서 컴파일하거나 수정하기는 상당히 어려움 . 여러 플랫폼용 파일과 Python으로 작성한 맞춤형 파서 Lola 대신, POSIX 같은 기준 환경용 단일 C 파일이면 좋겠음.
•프로그래머로 10년 넘게 일했는데 이 글을 읽고서야 코드 골프 라는 분야를 알게 됐다니 놀라움. 프로젝트도 멋지고, 사람이 직접 만들었다는 점이 마음에 듦.
•대표적인 예가 donut.c 임. 처음 봤을 때 정말 놀랐음.

https://www.a1k0n.net/2006/09/15/obfuscated-c-donut.html

•내가 가장 좋아하는 코드는 이것임. https://www.cise.ufl.edu/~manuel/obfuscate/pi.c .
•https://beta.dwitter.net 과 https://github.com/nanochess 를 둘러보길 권함.

더 큰 규모를 보고 싶다면 https://phoboslab.org/log/2021/09/q1k3-making-of 도 있음. 개인적으로는 여전히 https://www.pouet.net/prod.php?which=1221 에 애착이 감.

•https://codegolf.stackexchange.com 도 살펴보길 권함.
•정확히는 C 소스가 1,024바이트 이고, 컴파일된 바이너리는 그 몇 배 크기이며 Python의 극히 작은 일부만 구현함.

반복문은 소스의 앞부분으로 돌아가 매번 다시 파싱하는 방식인데, DOS의 .bat 처리도 이렇게 작동함. Unix 계열 셸에서도 같은지는 그 “기능”을 활용할 일이 없어 모르겠음.

C4 외에 살펴볼 만한 고밀도 인터프리터로 J Incunabulum 도 있음. 의도적으로 코드 골프를 한 것은 아니라 크기는 조금 더 큼. https://www.jsoftware.com/ioj/iojATW.htm .

더 넓게 보면 배열 프로그래밍 문화에서는 이 정도 코드 밀도를 평범하게 여기는 듯함. https://news.ycombinator.com/item?id=45800777 .

• Bash는 줄을 버퍼링 하므로 실행 위치 뒤쪽의 코드를 수정하는 방식은 잘 작동하지 않지만, 스크립트가 자기 파일 끝에 내용을 계속 추가해서 무한히 실행되게 할 수 있음.
•같은 저자가 쓴 아주 작은 컴파일러 만들기 도 있음.

https://news.ycombinator.com/item?id=36102460

•인터프리터로 실행할 수 있으면서 실용적인 최소 크기의 튜링 완전 VM 은 무엇일지 궁금함. Python 인터프리터를 낮은 수준의 표현으로 변환해 실행할 brainfuck 구현이나, 비타입 람다 대수 또는 SKI 결합자 인터프리터가 특히 하드웨어 부트스트래핑 에 유용할 듯함.

SectorLisp 같은 것을 생각하고 있음. https://justine.lol/sectorlisp/ .

• 기계어 명령어 하나 면 충분함. https://en.wikipedia.org/w/index.php?title=One-instruction_s... .
• 실용성과 코드 크기 사이의 균형 이 필요함. 둘은 대체로 상충하며, 유용한 코드를 만드는 데 코드 크기가 중요한 척도인 경우는 드물고 이런 코드 골프도 보통 실용성이 주목적은 아님.

물론 자원이 극히 제한된 임베디드 시스템은 예외이며, 그곳에서는 C와 어셈블리에 사실상 적수가 없음.

•과거에는 완전한 BASIC 인터프리터를 32KB 미만 으로 배포했다는 점을 생각하면 흥미로움.
• Turbo Pascal보다 큰 것들 을 모은 글도 있음.

https://prog21.dadgum.com/116.html

•1970~80년대 Microsoft BASIC은 4~8KB 였음.
• Tiny BASIC은 4KB 미만 이고, 최소 기능의 Forth도 약 4KB임.
•“생각할 수 있는 가장 기본적인 코드인 1 + 2 로 시작했다”는 대목부터 납득하기 어려움. 그걸 어떻게 512~1,024바이트 안에 넣었다는 것인가? print(3 * * 1000) 도 해봤는가?
• 진짜 Python은 아님 . 본질적으로 Python의 일부 문법을 닮게 만든 별도 언어임.

그래도 내가 작고 투박한 장난감 Python 구현을 만든다면 임의 정밀도 정수나 거듭제곱 연산자 는 아마 구현하지 않을 것 같음. 적어도 첫 버전에서는 제외할 듯함.

• Justine Tunney의 SectorLISP 와 같은 취지로 보여서 멋짐.

https://justine.lol/sectorlisp/

• SectorLISP는 어디까지 덜어내도 Lisp인가 라는 중요한 질문을 구현에 담고 있지만, 이 인터프리터는 그렇지 않음. SectorLISP가 Lisp의 본질만 남기는 구현을 목표로 한다면, Python-1024는 최소한의 코드로 Python을 흉내 내는 것 이 목표로 보임.
• sectorC 도 있음. https://github.com/xorvoid/sectorc .

덧붙여, sectorC로 python1024를 컴파일할 수 있을지 궁금함.

관련 아이템