생각해 볼 질문
어떤 컴파일러 결정은 소스 문법에 달리고 어떤 결정은 요청한 target 레지스터와 linkage에 달릴까요? 컴파일 전에 지원하는 모든 소스 형식 분류하기 전용 컴파일러에 target 레지스터와 linkage 전달하기 needs, modifies, statements로 명령열 표현하기 보수적인 레지스터 계약을 유지하며 수열 합성하기 조건 제어용 레이블 만들기 lambda 본문을 원시 소스로 남기지 않고 저장할 코드로 컴파일하기 compile은 문법 디스패치만 맡습니다. 전용 컴파일러는 자기 값과 변수와 인용과 조건식과 lambda와 수열과 적용이 target에 도달하는 방법을 정합니다. end-with-linkage는 제어 이동 없음, continue를 통한 return, 직접 label goto 가운데 하나를 덧붙입니다.
명령열은 statements와 함께 보수적인 needs·modifies 집합을 가집니다. append-sequences는 순서를 유지하며 이 계약을 합칩니다. 조건식 예제는 재귀적으로 컴파일한 술어와 두 갈래 주위에 레이블과 linkage를 놓습니다. lambda 컴파일러는 본문을 재귀 컴파일해 그 명령 데이터를 표현된 compiled procedure에 저장합니다.
SICP 코드 UTF-8 7,888 / 1,048,576바이트
( begin
( define ( tagged-list? expression tag )
( and ( pair? expression ) ( eq? ( car expression ) tag ) ) )
( define ( self-evaluating? expression )
( or ( number? expression )
( string? expression )
( boolean? expression ) ) )
( define ( quoted? expression ) ( tagged-list? expression ' quote ) )
( define ( if? expression ) ( tagged-list? expression ' if ) )
( define ( lambda? expression ) ( tagged-list? expression ' lambda ) )
( define ( begin? expression ) ( tagged-list? expression ' begin ) )
( define ( expression-class expression )
( cond ( ( self-evaluating? expression ) ' self )
( ( symbol? expression ) ' variable )
( ( quoted? expression ) ' quote )
( ( if? expression ) ' if )
( ( lambda? expression ) ' lambda )
( ( begin? expression ) ' begin )
( ( pair? expression ) ' application )
( else ' unknown ) ) )
( define ( contains? item items )
( cond ( ( null? items ) #f )
( ( eq? item ( car items ) ) #t )
( else ( contains? item ( cdr items ) ) ) ) )
( define ( adjoin item items )
( if ( contains? item items )
items
( append items ( list item ) ) ) )
( define ( union left right )
( if ( null? right )
left
( union ( adjoin ( car right ) left )
( cdr right ) ) ) )
( define ( difference left right )
( cond ( ( null? left ) ' ( ) )
( ( contains? ( car left ) right )
( difference ( cdr left ) right ) )
( else
( cons ( car left )
( difference ( cdr left ) right ) ) ) ) )
( define ( make-sequence needs modifies statements )
( list needs modifies statements ) )
( define ( sequence-needs sequence ) ( car sequence ) )
( define ( sequence-modifies sequence ) ( cadr sequence ) )
( define ( sequence-statements sequence ) ( caddr sequence ) )
( define empty-sequence ( make-sequence ' ( ) ' ( ) ' ( ) ) )
( define ( append-sequences first second )
( make-sequence
( union ( sequence-needs first )
( difference ( sequence-needs second )
( sequence-modifies first ) ) )
( union ( sequence-modifies first )
( sequence-modifies second ) )
( append ( sequence-statements first )
( sequence-statements second ) ) ) )
( define label-counter 0 )
( define ( new-label prefix )
( set! label-counter ( + label-counter 1 ) )
( list prefix label-counter ) )
( define ( linkage-sequence linkage )
( cond ( ( eq? linkage ' next ) empty-sequence )
( ( eq? linkage ' return )
( make-sequence
' ( continue )
' ( )
' ( ( goto ( reg continue ) ) ) ) )
( else
( make-sequence
' ( )
' ( )
( list ( list ' goto
( list ' label linkage ) ) ) ) ) ) )
( define ( end-with-linkage sequence linkage )
( append-sequences sequence
( linkage-sequence linkage ) ) )
( define ( compile-self expression target linkage )
( end-with-linkage
( make-sequence
' ( )
( list target )
( list ( list ' assign target
( list ' const expression ) ) ) )
linkage ) )
( define ( compile-variable expression target linkage )
( end-with-linkage
( make-sequence
' ( env )
( list target )
( list
( list ' assign target
( list ' op
' lookup-variable-value
( list ' const expression )
' ( reg env ) ) ) ) )
linkage ) )
( define ( compile-quote expression target linkage )
( compile-self ( cadr expression ) target linkage ) )
( define ( compile-operands operands )
( define ( loop remaining result )
( if ( null? remaining )
result
( loop
( cdr remaining )
( append-sequences
result
( append-sequences
( compile ( car remaining ) ' val ' next )
( make-sequence
' ( argl val )
' ( argl )
' ( ( assign argl
( op append-argument
( reg argl )
( reg val ) ) ) ) ) ) ) ) ) )
( loop operands
( make-sequence
' ( )
' ( argl )
' ( ( assign argl ( const ( ) ) ) ) ) ) )
( define ( compile-application expression target linkage )
( end-with-linkage
( append-sequences
( compile ( car expression ) ' proc ' next )
( append-sequences
( compile-operands ( cdr expression ) )
( make-sequence
' ( proc argl )
( list target )
( list
( list ' assign target
' ( op apply-procedure
( reg proc )
( reg argl ) ) ) ) ) ) )
linkage ) )
( define ( compile-if expression target linkage )
( let ( ( alternative-label ( new-label ' false-branch ) )
( after-label ( new-label ' after-if ) ) )
( end-with-linkage
( make-sequence
' ( env continue )
( union ( list target ) ' ( val proc argl continue ) )
( append
( sequence-statements
( compile ( cadr expression ) ' val ' next ) )
( append
' ( ( test ( op false? ( reg val ) ) ) )
( append
( list ( list ' branch
( list ' label alternative-label ) ) )
( append
( sequence-statements
( compile ( caddr expression )
target
' next ) )
( append
( list
( list ' goto ( list ' label after-label ) )
( list ' label alternative-label ) )
( append
( sequence-statements
( compile ( cadddr expression )
target
' next ) )
( list ( list ' label after-label ) ) ) ) ) ) ) ) )
linkage ) ) )
( define ( compile-sequence expressions target linkage )
( cond ( ( null? expressions ) empty-sequence )
( ( null? ( cdr expressions ) )
( compile ( car expressions ) target linkage ) )
( else
( append-sequences
( compile ( car expressions ) ' val ' next )
( compile-sequence
( cdr expressions )
target
linkage ) ) ) ) )
( define ( compile-lambda expression target linkage )
( let ( ( parameters ( cadr expression ) )
( body-code
( compile-sequence ( cddr expression )
' val
' return ) ) )
( end-with-linkage
( make-sequence
' ( env )
( list target )
( list
( list ' assign target
( list ' op
' make-compiled-procedure
( list ' const parameters )
( list ' const
( sequence-statements body-code ) )
' ( reg env ) ) ) ) )
linkage ) ) )
( define ( compile expression target linkage )
( cond ( ( self-evaluating? expression )
( compile-self expression target linkage ) )
( ( symbol? expression )
( compile-variable expression target linkage ) )
( ( quoted? expression )
( compile-quote expression target linkage ) )
( ( if? expression )
( compile-if expression target linkage ) )
( ( lambda? expression )
( compile-lambda expression target linkage ) )
( ( begin? expression )
( compile-sequence ( cdr expression )
target
linkage ) )
( ( pair? expression )
( compile-application expression target linkage ) )
( else
( error "unknown compiler expression" expression ) ) ) )
( map expression-class
' ( 42
x
( quote ok )
( if x 1 2 )
( lambda ( x ) ( + x 1 ) )
( begin 1 2 )
( + 1 2 ) ) )
) 코드 실행Ctrl/⌘ Enter 파일 열기 코드 저장 코드 복사 편집기 지우기
예제 컴파일러가 지원하는 소스 종류 분류하기 val target과 return linkage로 조건식 컴파일하기
실행은 브라우저 안에서 이루어지며 프로그램 결과와 실행 추적을 보여줍니다. 예상 결과 디스패치 프로그램은 (self variable quote if lambda begin application)을 반환합니다. 조건식 컴파일러는 ((env continue) (val proc argl continue) 15 (assign test branch assign assign assign assign assign assign assign goto label assign label goto) 2)를 반환합니다.
실행 추적에서 볼 점 두 번째 프로그램에서 술어 컴파일과 생성된 test·branch를 구분하세요. 이어 연산자가 proc으로, 피연산자가 val과 argl로 가는 과정과 alternative·after-if 레이블, 마지막 continue return을 따라가세요. needs와 modifies는 보수적인 레지스터 이동 계약을 제공합니다.
직접 해보기 프로그램을 수정하고 결과를 비교해 보세요. begin과 if를 담은 lambda를 proc target과 이름 붙은 linkage로 컴파일하세요. 바깥 클로저 생성 수열과 저장된 본문 명령을 따로 살펴보세요.
힌트 보기 lambda 본문은 항상 val target과 return linkage로 컴파일됩니다. 바깥 target과 linkage는 compiled procedure를 만드는 식을 설명합니다.