본문 바로가기
카테고리 없음

Wave로 아무것도 없이 Hello World 출력하기

by lunastev 2025. 7. 11.
SMALL

Wave는 기본적으로 표준 함수가 전혀 없습니다. 현재 println()print() 함수가 존재하긴 하지만, 이는 개발 중 테스트를 위한 임시 함수일 뿐, 공식적인 함수는 아닙니다. Wave에 공식적으로 존재하는 함수는 import() 함수 뿐 입니다.

하지만 아무런 기반 없이 처음부터 만들라고 하면 여러분은 이 언어를 사용하지 않겠죠. Wave는 표준 라이브러리를 지원하기 때문에 표준 라이브러리 함수를 사용하면 됩니다. 하지만 표준 라이브러리를 사용하지 못하는 베어메탈 환경의 경우에는 이와 같이 처음부터 하나하나 다 코딩을 해야하다는 사실입니다.


개요

오늘은 Wave로 아무것도 없이 Hello World를 출력을 해보도록 하겠습니다.

Wave 컴파일러에는 문법적인 부분만 지원합니다. 즉 syscall() 같은 함수적인 부분은 존재하지 않습니다. import() 함수 외에는 존재하지 않습니다.

Wave에는 인라인 어셈블리라는 구문이 존재하며 asm {} 이런식으로 작성합니다.

Wave에서 사용하는 인라인 어셈블리 문법의 기본 형식을 간단히 살펴보겠습니다.


인라인 어셈블리 문법

asm {
    "어셈블리 명령어"         // 한 줄씩 실제 어셈블리 코드
    ...
    in("레지스터") 값        // 입력 레지스터 매핑
    out("레지스터") 변수     // 출력 레지스터 매핑
}

1. "..." 문자열: 어셈블리 명령어

  • 실제 CPU에서 실행되는 어셈블리 코드 문자열
  • 한 줄에 한 명령어, 여러 줄도 가능
  • 예: "mov rax, 1", "syscall"

2. in("rdi") s: 입력값 전달

  • Wave 변수 s의 값을 레지스터 rdi에 넣겠다는 뜻
  • "rdi"는 x86-64에서 첫 번째 syscall 인자 (표준 규약 기준)

in("레지스터") 표현식
-> 컴파일러가 해당 표현식 값을 지정된 레지스터에 로드

3. out("rax") ret: 출력값 받기

  • syscall의 결과값은 보통 rax에 저장됨
  • out("rax") ret는 -> rax 값을 Wave 변수 ret에 저장하라는 의미

out("레지스터") 변수
-> 지정된 레지스터 값을 Wave 변수로 가져옴


이제 Hello World를 아무것도 없이 구현을 해보도록 하겠습니다.

Wave의 버전은 v0.1.3-pre-beta-nightly-2025-07-11 이상에서만 가능하며 정식 버전은 v0.1.3-pre-beta에서 가능합니다. 하지만 v0.1.3-pre-beta 이후에도 큰 문법은 변하지 않지만 일부 문법이 변형이 될 수 있기 때문에 v0.1.3-pre-beta 계열의 버전에서 동작하시는 것을 추천드립니다.

일단 가장 중요한 것은 문자열의 길이를 재는것입니다.

보통 프로그래밍 언어에서 len() 함수를 가지고 문자열 길이를 잽니다. 아까 말했듯이 Wave 컴파일러에는 import() 함수 말고는 함수가 없기 때문에 직접 len() 함수를 만들어야 합니다.

fun len(s: str) -> i32 {
    var count: i32 = 0;
    while (s[count] != 0) {
        count = count + 1;
    }
    return count;
}

이것은 표준 라이브러리에 들어가는 len() 함수이며 문자열의 길이를 재는 함수입니다.


fun println_s(s: ptr<i8>) {
    var l: i32 = len(s);
    var ret: ptr<i8>;
    asm {
        "mov rax, 1"
        "syscall"
        in("rdi") 1
        in("rsi") s
        in("rdx") l
        out("rax") ret
    }

    var nl: ptr<i8> = "\n";
    var one: i32 = 1;
    asm {
        "mov rax, 1"
        "syscall"
        in("rdi") 1
        in("rsi") nl
        in("rdx") one
        out("rax") ret
    }
}

현재 Wave 컴파일러 내에는 println()이라는 Wave를 효과적이게 테스트 할 수 있는 함수가 존재합니다. 이 함수랑 혼돈이 가지 않도록 println_s() 함수를 만들도록 하겠습니다.


import("println");

fun main() {
    var a: i32 = 10;
    println_s("Hello World");
}

import() 함수를 사용해서 println.wave 파일을 불러옵니다. 만약 main.wave 파일에 len() 함수랑 println_s() 함수가 같이 있다면 import() 함수를 쓰지 않아도 됩니다.


이것을 실행해보면

hello

이렇게 Hello World가 출력되게 됩니다.


아직 Wave에는 완성된 표준 라이브러리가 없지만, 성장 가능성은 충분합니다. 컴파일러가 제공하는 기능들을 잘 활용하면 지금도 멋진 프로그램을 만들 수 있다고 믿습니다.

LIST