sicp.io
5.5.5 · 컴파일 코드 예제

컴파일된 재귀 코드는 모든 호출과 복귀 이동을 명시한다.

entry와 base-case 레이블, 저장된 continuation과 인자, 공유 after-call 지점, continue를 통한 간접 복귀를 가진 완전한 factorial 컨트롤러를 살펴보고 실행합니다.

생각해 볼 질문

재귀 소스 프로시저의 암묵적인 호출 스택을 어떤 기계 상태가 대신할까요?

  • 재귀 프로시저 하나의 전체 조립 명령 목록 읽기
  • entry·after-call·base-case·done 레이블 구분하기
  • 재귀 호출 전에 caller continuation과 살아 있는 인자 저장하기
  • 돌아온 값에 곱하기 전에 상태 복원하기
  • continue 레지스터를 통해 간접 복귀하기
  • entry 수·명령 수·최대 스택 깊이·마지막 스택 균형 재기

컴파일 목록은 factorial-entry에서 시작합니다. base가 아닌 호출은 continue와 n을 저장하고 n을 줄인 뒤 after-factorial을 새 복귀 주소로 설치하고 같은 entry로 다시 이동합니다. base case는 val에 1을 넣고 continue로 복귀하며 after-factorial은 caller 상태를 복원하고 n과 반환 val을 곱한 뒤 다시 복귀합니다.

계측 실행은 n = 5와 done을 가리키는 continue로 시작합니다. n = 0을 포함해 entry 여섯 번이 관찰되고, 미완료 호출 다섯 개가 값 두 개씩 보존하므로 최대 스택 깊이는 10입니다. halt 전에 열 값이 모두 복원됩니다. 가져온 66개 명령과 정확한 컨트롤러 목록은 이 유한 컴파일 프로시저를 측정합니다.

SICP 코드UTF-8 6,732 / 1,048,576바이트
예제
결과
출력
진단
실행 추적0 / 0 개 이벤트
    실행은 브라우저 안에서 이루어지며 프로그램 결과와 실행 추적을 보여줍니다.
    예상 결과

    목록은 (((factorial-entry . 0) (after-factorial . 8) (base-case . 12) (done . 14)) 15 (perform test branch save save assign assign goto restore restore assign goto assign goto halt))를 반환합니다. 실행은 (15 complete 120 66 10 #t (5 4 3 2 1 0))을 반환합니다.

    실행 추적에서 볼 점

    재귀 이동 전 continue가 done에서 after-factorial로 바뀌는 과정을 따라가세요. base case 뒤에는 같은 after-call 코드를 통한 간접 복귀 다섯 번이 이어집니다. save 두 개씩을 나중 restore와 맞추고 마지막 goto가 done에 닿기 전에 깊이가 10에서 0으로 돌아오는지 확인하세요.

    직접 해보기

    프로그램을 수정하고 결과를 비교해 보세요.

    재귀 Fibonacci나 거듭제곱 프로시저를 같은 명시적인 목록으로 옮기세요. 각 재귀 호출 뒤에도 살아 있어야 할 레지스터를 밝히고 대표 입력의 최대 스택 깊이를 예상하세요.

    힌트 보기

    재귀 결과가 돌아온 뒤 필요한 continuation과 값만 저장하세요. 재귀 호출이 두 번이면 첫 번째 반환값도 두 번째 호출 동안 보존해야 합니다.

    이 수업 완료하기

    이 장의 총 23개 수업 중 0개 완료0%