Я пытаюсь написать интерпретатор для простого языка программирования на Схеме. Прямо сейчас, я пишу процедуру для обработки while-loops с операторами break. Чтобы подойти к этой проблеме, я использую call/cc.Написание интерпретатора для языка с перерывами
Когда язык разбирается, это выглядит следующим образом:
var x = 0;
while (x < 10) {
x = x - 1;
break;
x = x + 100;
}
return x;
превращается в
((var x 0) (while (< x 10) (begin (= x (- x 1)) (break) (= x (+ x 100)))) (return x))
Мой подход к интерпретации этих заявлений заключается в следующем:
(define while_break
(lambda (cond body state)
(call/cc
(lambda (break-cont)
(letrec
((Mstate_loop (lambda (cond body state)
; Need second loop
(if (eq? (M_Bool cond state) #t)
(call/cc
(lambda (second-break-cont)
(letrec
((Body_loop (lambda (body_line state)
(cond
((null? body_line) (second-break-cont state))
; Conditions to exit the loop
((eq? (first_line body_line) 'break) (second-break-cont state))
; If this is the last line, run it and break
((null? (rest_of_lines body_line)) (second-break-cont (M_State body_line state)))
; Otherwise, run the next line
(else (Body_loop (rest_of_lines body_line) (M_State (first_line body_line) state)))))))
(Body_loop body state))))
(break-cont state)
))))
(Mstate_loop cond body state))
))))
(define first_line car)
(define rest_of_lines cdr)
Где (M_State) возвращает текущее состояние, обновленное для отражения оператора (например, состояние ((x) (2))) представляет x = 2. (M_State '(var x 5)' ((x) (2))) вернется ((x) (5)).)
Когда я положил это через отладчик, line ((null? body_line) (состояние второго прерывания). всегда вызывает второй прерыватель, хотя body_line не равен нулю. Я потратил много времени на отладку, но не могу найти ошибку. Любая помощь в определении моей ошибки была бы весьма признательна.
Не смотря слишком много на ваш код, я советую вам использовать разграниченные продолжения, чтобы охватить объем вашей реализации 'break'. –
@AlexisKing Или, если весь цикл интерпретируется в одной и той же функции, можно полностью исключить 'call/cc', если цикл (Scheme-level) принимает дополнительный параметр, который может принимать значения' 'break' и '' continue' (например). Условие проверки затем оценивается только в том случае, если режим '' continue'. –
переформатируйте свой код с помощью '(define (func args ...) ...' и named let '(пусть name ((aa) (bb) (cc)) ...)', и он получит гораздо больше компактный и читаемый. Кроме того, для меня он помогает писать '(call/cc (lambda (exit) ...' в одной строке, увеличивая следующие строки под 'call/cc', а не под' lambda', но это немного неортодоксальным. –