← SEARCHABLE ARCHIVE
Nand2Tetris · 2026-05-22

Nand2Tetris — 12장

Jack 운영체제

INTERACTIVE READING MODE →

// Math.jack
// OS 구현 예시
// Jack의 모든 * 와 / 는 이 함수들로 컴파일되므로 음수와 0 나누기까지 처리해야 한다
// multiply는 shift-and-add, divide는 shift-and-subtract 로 구현함

class Math {
    static Array twoToThe;

    function void init() {
        var int i, v;
        let twoToThe = Array.new(16);
        let i = 0;
        let v = 1;
        while (i < 16) {
            let twoToThe[i] = v;
            let v = v + v;
            let i = i + 1;
        }
        return;
    }

    function int abs(int x) {
        if (x < 0) { return -x; }
        return x;
    }

    function boolean bit(int x, int i) {
        return ~((x & twoToThe[i]) = 0);
    }

    function int multiply(int x, int y) {
        var int sum, shifted, j;
        var boolean negative;

        let negative = false;
        if (x < 0) { let x = -x; let negative = ~negative; }
        if (y < 0) { let y = -y; let negative = ~negative; }

        let sum = 0;
        let shifted = x;
        let j = 0;

        while (j < 16) {
            if (Math.bit(y, j)) { let sum = sum + shifted; }
            let shifted = shifted + shifted;   // 좌측 1비트 시프트
            let j = j + 1;
        }

        if (negative) { return -sum; }
        return sum;
    }

    // 절댓값 나눗셈. y를 두 배로 키우며 내려가 O(log n) 이다.
    function int divideAbs(int x, int y) {
        var int q;

        if ((y > x) | (y < 0)) { return 0; }   // y < 0 은 두 배 키우다 넘친 경우

        let q = Math.divideAbs(x, y + y);
        if ((x - ((q + q) * y)) < y) { return q + q; }
        return (q + q) + 1;
    }

    function int divide(int x, int y) {
        var int q;
        var boolean negative;

        if (y = 0) { do Sys.error(3); }        // 0으로 나누기

        let negative = false;
        if (x < 0) { let x = -x; let negative = ~negative; }
        if (y < 0) { let y = -y; let negative = ~negative; }

        let q = Math.divideAbs(x, y);
        if (negative) { return -q; }
        return q;
    }
}
// String.jack
// 문자열 객체 일부 구현
// 내부 배열에 문자를 저장하고 length를 따로 관리함

class String {
    field Array data;
    field int length;
    field int capacity;

    constructor String new(int maxLength) {
        let capacity = maxLength;
        let length = 0;
        let data = Array.new(maxLength);
        return this;
    }

    method void dispose() {
        do data.dispose();
        do Memory.deAlloc(this);
        return;
    }

    method int length() {
        return length;
    }

    method String appendChar(char c) {
        let data[length] = c;
        let length = length + 1;
        return this;
    }

    method char charAt(int index) {
        return data[index];
    }
}
// Array.jack
// Array.new는 Heap에서 size만큼 메모리를 할당함
// Jack 배열은 사실상 base address를 가진 메모리 블록임

class Array {
    function Array new(int size) {
        return Memory.alloc(size);
    }

    method void dispose() {
        do Memory.deAlloc(this);
        return;
    }
}