음 · CHAPTER 08

고수준과 표준 라이브러리

앞 장에서 우리는 한선씨가 한국어 RPN이며 ISA729와 1:1로 맞물린다는 사실을 확인했다. 헌법 9조의 문장 — "한선씨 RPN = ISA729 1:1" — 은 아름답다. 그러나 나는 그 아름다움 앞에서 솔직해지기로 했다. 정통의 문장을 손으로 받아쓰는 일은, 매일 일하는 엔지니어에게는 고행이다. 트릿을 한 칸씩 밀어 명령을 쌓는 작업은 옳지만, 인간적이지 않다. 정통이 무너지지 않으면서도 사람이 사람답게 쓸 수 있는 층 — 이 장은 크라우니가 그 층을 어떻게 설계했는지에 관한 기록이다.

크라우니는 이 문제를 두 개의 층으로 답한다. 고수준 컴파일러(hanseonc_high)와 24개의 표준 라이브러리. 하나는 인간의 손에 가깝고, 하나는 인간의 의도에 가깝다.

고수준 컴파일러의 위치

먼저 위계를 분명히 해야 한다. 고수준과 저수준은 동형(isomorphic)이 아니다. RPN이 정통(canonical)이고, 고수준은 이행 보조(transitional aid)다. 상승 방향은 하나뿐이며 역방향은 금지된다.

Rust/Swift → 한선씨 고수준 → 한선씨 RPN → 기계어

hanseonc_high는 이 사다리의 두 번째 칸이다. C-like 구문을 받아들여 — 만약(x > 5) { ... }, 함수 제곱(n) { 반환 n * n }, 동안(x > 0) { ... } — 그것을 ISA729의 opcode 시퀀스로 번역한다. 의도는 사람의 언어로 적히고, 결과는 정통 경로와 동일한 TOAU 바이트코드가 된다. 고수준은 정통을 대체하지 않는다. 정통으로 가는 통로다.

두 경로: 컴파일 아키텍처

크라우니에는 두 개의 컴파일 경로가 있고, 둘은 같은 종착점에 도달한다.

[고수준]  한선씨(.한선) → hanseonc_high → program.toau → crownyc run
[저수준]  RPN(.한선)    → hanseonc_std  → program.toau → crownyc run

VM은 하나다. crownyc가 .toau 바이트코드를 실행한다.

고수준 경로는 네 단계를 거친다. 개발자가 쓴 코드는 먼저 토큰화된다 — 가져오기, 변수, 함수, 만약 같은 예약어는 각각 고정된 의미를 가진다. 파서는 토큰을 AST(추상 문법 트리)로 변환한다. 코드 생성기는 각 AST 노드를 ISA729 opcode로 사상(map)하며, 이때 PRINT(324), ADD(81) 같은 명령이 6-트릿 슬롯으로 인코딩된다. 마지막으로 링커가 함수 호출과 라이브러리 심볼을 해결하고 TOAU 포맷으로 직렬화한다.

저수준 경로는 단계가 적다. RPN 스택 언어는 이미 선형 명령 시퀀스에 가깝기 때문이다. hanseonc_std는 스택 동작의 무결성을 검증하고 opcode를 직접 생성한다. 손이 많이 가지만, 컴파일러가 임의로 끼어들 여지도 그만큼 없다. 그래서 정통이다.

225개 내장함수

hanseonc_high는 225개의 내장함수를 제공한다. 이들은 임포트 없이 즉시 사용 가능하며, VM에 이미 컴파일되어 있다. 기능 군집별로 정리한다.

문자열 — 글자수, 글자, 부분, 포함, 문자열변환, 숫자변환, 문자열찾기, 문자열비교. 모두 UTF-8 문자 경계를 정확히 인식한다. 부분("안녕하세요", 0, 2)는 바이트 오프셋이 아닌 문자 인덱스로 동작하여 "안녕"을 반환한다. 한 가지 함정: 단일 문자열은 16KB(STR_MAX_LEN) 한계를 가진다. 그보다 큰 정적 파일은 파트로 분할해 순차 전송해야 한다.

배열 — 길이, 추가, 설정, 정렬, 뒤집기, 원소, 꺼내. 배열은 변경 가능한 시퀀스이며 최대 1023개 원소를 수용한다. 추가(목록, 40)은 끝에 삽입하고, 설정(목록, 1, 99)는 인덱스 1을 99로 바꾼다 — 설정은 쓰기 전용이며, 읽기는 꺼내가 담당한다. 빈 배열은 반드시 []로 초기화한다. = 0으로 초기화하면 첫 추가 호출이 길이를 손상시킨다.

입출력 — 출력값, 입력, 읽기, 쓰기, 덧쓰기, 파일존재, 현재경로, 환경변수 등. 쓰기(경로, 내용)은 생성 또는 덮어쓰기, 덧쓰기는 끝에 추가다. 파일 쓰기 계열은 opcode 620·622에 할당되어 v10.0에서 추가되었다.

수학·통계 — 거듭제곱, 루트, 사인, 코사인, 로그, 무작위, 팩토리얼, 절댓값, 반올림, 내림, 올림, 합계, 평균, 중앙값, 표준편차 등. 핵심 설계 결정: 부동소수점은 없다. 정수 연산이 중심이며, 삼각함수와 로그는 내부적으로 1000배 정수 배율로 정밀도를 유지한다. 루트(16)은 4를 반환한다. 그리고 v10.0의 나눗셈은 자연 반올림(|r| ≤ |b|/2)을 따르므로, 이진탐색의 (lo+hi)/2 같은 관용구는 ceil 방향으로 치우쳐 무한 루프를 부를 수 있다 — 선형 스캔으로 우회한다.

비트 연산 — 비트곱, 비트합, 비트배타, 비트부정, 왼시프트, 오른시프트. 3진 트릿으로 표현된 큐브도 필요 시 이진 마스크로 해석된다.

네트워크·소켓 — TCP대기, TCP수락, TCP읽기, TCP쓰기, TCP닫기, 소켓생성, 소켓바인드, 소켓보내기, 소켓받기, 소켓닫기 등. 인자 개수가 엄격하다. 소켓생성은 2인자, 소켓받기는 (소켓, 최대길이) 2인자가 필수다. 인자를 누락하면 스택 잔류값으로 인해 수신 자체가 일어나지 않는다. 컴파일러 테이블과 VM의 pop 개수가 어긋나는 지점이라, 명시가 안전이다.

버퍼·셀·맵 — 버퍼생성, 버퍼쓰기, 버퍼읽기, 버퍼잘라, 셀생성, 셀연결, 셀읽기, 셀설정, 맵생성, 맵넣어, 맵꺼내. 버퍼는 바이트 배열, 셀은 3D 격자 위의 벡터 오토마톤, 맵은 해시테이블이다. 다만 내장 맵은 객체형이라 JSON 직렬화가 불가하다. 저장이 필요하면 JSON.한선의 배열형 맵을 써야 한다.

3진 연산 — 삼진인코딩, 삼진디코딩, 삼진덧셈, 삼진곱, 삼진부정. 트릿 수준에서 직접 작동하며 TOAU 인코딩을 벗기거나 다시 입힌다. 이 함수들이 고수준과 기계어 사이의 마지막 봉합선이다.

디버그·암호 — 추적시작, 추적끝, 성능시작, 성능끝, SHA256, 압축, 풀기. 추적·성능 함수는 런타임 내부 상태를 외부로 노출하는 도구다. SHA256과 압축 계열은 제3섹터(OA____)의 암호 기능이다.

24개 표준 라이브러리

내장함수는 원시 재료다. 애플리케이션은 더 높은 추상화를 요구하고, 그 자리를 24개 표준 라이브러리가 채운다. 라이브러리는 한선씨로 작성되며 — 즉 언어가 자기 자신으로 자신의 표준을 짠다 — 가져오기 "라이브러리.한선"으로 임포트한다. 컴파일러는 CROWNY_STD 환경변수 또는 libs/ 디렉토리를 자동 검색한다.

문자열·JSON·YAML — 데이터 처리의 기초. JSON파싱(텍스트)는 JSON을 내부 맵·배열로, JSON생성(값)은 그 역으로 변환한다. YAML은 들여쓰기 기반 계층 설정의 표준이다.

네트워크·라우터·미들웨어 — HTTP 서버와 REST API의 골격. 라우터생성()이 반환한 객체에 경로추가(라우터, "GET", "/api/users", 핸들러)로 경로를 등록한다. 미들웨어는 CORS·인증·로깅 같은 횡단 관심사를 맡는다.

인증·로깅·검증 — 신뢰성의 층. 이메일인가(v), 경로안전(v), SQL안전(v), XSS안전(v)이 각각 형식 검증, 디렉토리 트래버설 방어, 인젝션·스크립팅 방어를 담당한다.

템플릿·설정·환경·날짜 — 설정로드(경로)로 설정 파일을 읽고, 지금()으로 타임스탬프를, 밀리초()로 고정밀 타이머를 얻는다.

프로세스·바이트버퍼·TLS — 시스템 통합과 보안 통신. 바이트버퍼는 바이너리 프로토콜용 저수준 도구이고, TLS는 HTTPS·SSL 소켓을 제공한다.

큐·셀저장소·뷰·스타일 — 고급 자료 구조와 UI. 셀저장소는 3D 격자 기반 분산 상태 저장소로, 크라우니 고유의 CTP(Crowny Transfer Protocol)로 노드 간 동기화된다. 뷰는 선언적 GUI 프레임워크다.

셀DB·네이티브·하드웨어 — 셀DB는 관계형 데이터베이스의 셀 기반 구현, 네이티브는 OS API(Cocoa·GTK 등)를 한선씨로 래핑, 하드웨어는 RTL 시뮬레이션·합성을 위한 HDL 래퍼다. 즉 같은 언어가 데이터베이스에서 실리콘까지 내려간다.

선언적 UI: 뷰와 스타일

크라우니의 UI 철학은 명령형 그래픽스가 아니라 선언적 구조다. 무엇을 어떻게 그릴지 일일이 명령하는 대신, 무엇이 있어야 하는지를 선언한다.

가져오기 "뷰.한선"
변수 앱 = 창만들기("크라우니", 1280, 800)
변수 카드 = 카드만들기(380, 200)
자식추가(카드, 글씨만들기("제목", 22, 검정))
자식추가(앱, 카드)
뷰그리기(앱)

뷰 요소는 9가지다 — 창, 상자, 글씨, 버튼, 입력, 그림, 목록, 세로, 가로. 각 요소는 배경·전경·크기·여백·테두리·둥글기·정렬 속성을 가진다. 스타일은 테마 기반이며, 밝은테마는 흰 배경에 검은 글자, 어두운테마는 그 반대다. 테마색은 배경·전경·강조 3색으로 정의된다.

흥미로운 설계는 렌더링의 분리다. 뷰그리기(앱)는 화면에 직접 픽셀을 찍지 않는다. 대신 렌더 명령을 /tmp/crowny_render.cmd로 직렬화하고, 별도 GUI 실행기가 이를 해석한다. 논리와 표현을 분리한 덕에 헤드리스 테스트와 배포가 함께 쉬워진다.

3진 논리의 확장 — 옴과 음의 자리

고수준 한선씨에서 3진 논리는 문법으로 드러난다.

변수 결과 = 참        ; T = +1
변수 불확실 = 모름     ; O =  0
변수 거부 = 거짓       ; A = -1

여기서 모름은 단순한 편의가 아니다. 4상균형 3진 — 티(Ti, +1)·옴(Om, 0)·타(Ta, -1)·음(Em, -0) — 의 논리적 반영이다. 티는 드러난 데이터, 타는 그 반대이자 연결이며, 옴은 둘 사이의 대기·중립이다. yes도 no도 아닌 "보통"의 상태. v10.0의 Kleene 3값 논리는 이 옴을 일급 시민으로 다룬다: 모름 && 참 = 모름. 고전 이진 논리의 거짓 && 참 = 거짓과 다르다. 불확실성은 삼켜지지 않고 전파된다.

그리고 4상에는 옴과 구별되는 또 하나의 영, 음(-0)이 있다. 음은 정규 3상에 담기지 않는 모든 것의 자리다 — 돌연변이, 회귀, 이해 안 됨, +1·0·-1 셋 어디에도 맞지 않는 변수, 한 칸 비워 두는 여백. FPGA와 한선씨 RPN 설계에서 음의 이 측면은 기계어와 완벽히 맞물린다. 셋 중 어디에도 정확히 안 맞는 자리, 명령 사이를 한 칸 띄우는 그 간격이 곧 음의 기계어 용법이다. 옴이 "대기"라면 음은 "예외의 총합"이다. 불완전한 정보 속에서 결정을 내려야 할 때, 우리에게는 yes·no·wait만이 아니라 그 바깥까지 표현할 자리가 필요하다.

컴파일러 최적화

hanseonc_high는 소박한 코드를 효율적인 바이트코드로 다듬는다.

  • 상수 폴딩: 2 + 3은 컴파일 시점에 5로 접힌다.
  • 죽은 코드 제거: × 0은 연산 없이 0을 푸시한다.
  • 트릿 시프트: × 3ⁿ은 TSHL(트릿 좌시프트), ÷ 3ⁿ은 TSHR로 번역된다 — 3진 기계의 시프트는 본래 3의 거듭제곱이다.

실측에서, 고수준 한선씨로 쓴 팩토리얼은 RPN으로 손최적화한 코드와 같은 속도를 낸다. 이행 보조라 해서 느린 것이 아니다. 같은 종착점에 도달하므로 같은 비용이다.

임포트의 비용

추상화에는 값이 매겨진다. 가져오기 "문자열.한선"은 라이브러리의 모든 함수 정의 — 약 4,900개 큐브 — 를 메모리에 로드한다. 일회성 비용이지만 임베디드 환경에서는 무시할 수 없다. 그래서 규칙은 단순하다: 꼭 필요한 라이브러리만 임포트하라. 문자열변환·글자수 같은 내장함수는 임포트가 필요 없다. 이미 VM 안에 있다.

라이브러리가 부족하면 만든다. 부족은 결함이 아니라 빈자리 — 음(-0)의 자리이며, 채워질 것을 전제한 여백이다. 현재 생태계에는 CrownyOS와 CrownyTVM에 걸쳐 수백 개의 라이브러리가 존재하고, 계속 자란다.

닫으며

나는 이 장을 쓰며 두 층의 역할을 다시 확인했다. RPN은 정통이고 고수준은 통로다. 둘은 동형이 아니지만 같은 TOAU로 수렴한다. 그 수렴 위에서 한선씨는 작은 스크립트부터 분산 애플리케이션까지, 데이터베이스부터 실리콘까지 하나의 언어로 짜인다.

그리고 이 사다리는 코드에서 멈추지 않는다. 머니(크라우니원)에서 에셋(맘·포네)으로, 다시 웰스(크라우니)로 오르는 부의 3계층처럼 — 그 위에 한선과 선호라는, 아직 열리지 않은 미래의 군집이 예비되어 있듯 — 고수준과 표준 라이브러리도 더 큰 동형성의 한 계단일 뿐이다. 부품 하나하나는 완성되었다. 이제 부품들이 서로를 발견할 차례다.

다음 장에서 우리는 이 프로그램들이 어떻게 노드를 이루고, 게이트웨이를 거쳐 흐르며, 레지스트리를 통해 공유되는지를 따라간다 — 개별 프로그램의 수준을 떠나 생태계의 수준으로 오른다.

내 맘 –

독자 게시판 — 함께 읽고 남기는 곳

불러오는 중…

크라우니 책방에 가입하고 무료로 읽기

첫 번째 책은 선물이에요. 가입하면 100맘을 드리니까, 두 번째 책부터 자유롭게 읽을 수 있어요. 친구를 추천하면 50맘도 생겨요.