sicp.io
5.5.7 · 컴파일 코드와 평가기의 연결

하나의 apply 경계가 서로 다른 두 프로시저 표현을 연결한다.

평가기와 컴파일 코드가 하나의 환경 모형과 인자 규약과 프로시저 디스패치 경계를 공유하면 평가기는 컴파일 프로시저를 호출하고 컴파일 코드는 해석 프로시저를 호출할 수 있습니다.

생각해 볼 질문

해석 프로시저와 컴파일 프로시저가 같은 객체인 척하지 않으면서 서로 호출하려면 어떤 런타임 합의가 필요할까요?

  • 해석 프로시저와 컴파일 프로시저를 서로 다른 태그 표현으로 유지하기
  • 하나의 어휘 환경과 인자 목록 순서 규약 공유하기
  • 원시·해석·컴파일 프로시저를 하나의 apply 경계로 보내기
  • 평가기에서 컴파일 코드 호출하기
  • 컴파일 코드에서 해석 프로시저 호출하기
  • 두 방향의 실제 표현 디스패치 순서 기록하기
  • 환경과 인자와 디스패치 규약으로 공유 apply 경계 설명하기

공유 전역 환경은 포장된 원시 프로시저와 double이라는 해석 프로시저와 add-three라는 컴파일 프로시저를 저장합니다. evaluate가 만드는 해석 클로저의 본문은 식 데이터로 남습니다. compile-expression이 만드는 컴파일 클로저의 본문은 스택 기계 명령 목록입니다. 두 표현은 눈에 보이게 다르지만 모두 매개변수와 어휘 환경을 가지고 같은 순서의 인자 목록을 받습니다.

apply-any가 인터페이스입니다. 평가기의 적용은 연산자와 피연산자를 평가한 뒤 이 경계에 도달합니다. 컴파일된 call 명령은 VM 스택에서 프로시저와 인자를 꺼낸 뒤 같은 경계에 도달합니다. 평가기에서 컴파일 코드로 가는 실행은 (compiled primitive)을 기록합니다. add-three가 컴파일 코드로 들어간 뒤 덧셈이 원시 프로시저를 호출하기 때문입니다. 컴파일 코드에서 평가기로 가는 실행은 (interpreted primitive)을 기록합니다. 컴파일 코드가 double을 호출한 뒤 해석 본문이 원시 곱셈을 사용하기 때문입니다. 수업 모형은 두 방향의 정확한 교차 호출 계약을 기록합니다.

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

    프로그램은 ((evaluator-to-compiled 8 (compiled primitive)) (compiled-to-evaluator 14 (interpreted primitive) #t) (representations #t #t))을 반환합니다. 두 디스패치 목록은 선택한 실행에서 실제로 들어간 프로시저 표현을 기록합니다.

    실행 추적에서 볼 점

    먼저 평가기가 add-three를 조회해 apply-any의 compiled 분기로 들어가고 컴파일 클로저의 VM 조회와 원시 덧셈 호출로 이어지는 경로를 따라가세요. 다음에는 double을 호출하는 컴파일 call 명령이 interpreted 분기로 들어가 환경을 확장하고 식 본문을 평가한 뒤 원시 곱셈으로 가는 경로를 따라가세요. 두 경로가 같은 전역 환경과 인자 순서 규약을 공유하면서도 interpreted와 compiled 태그를 구분하는지 확인하세요.

    직접 해보기

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

    add-three를 호출하는 해석 프로시저와 double을 호출하는 컴파일 프로시저를 하나씩 추가하세요. 두 wrapper를 호출하기 전에 중첩 디스패치 로그를 예상하세요.

    힌트 보기

    각 wrapper는 자기 표현을 시간 순서 경로의 앞에 하나 더 붙입니다. 바깥 호출부터 시작해 본문이 들어가는 표현을 따라가세요.

    이 수업 완료하기

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