0

Я пытаюсь написать интерпретатор для простого языка программирования на Схеме. Прямо сейчас, я пишу процедуру для обработки 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 не равен нулю. Я потратил много времени на отладку, но не могу найти ошибку. Любая помощь в определении моей ошибки была бы весьма признательна.

+1

Не смотря слишком много на ваш код, я советую вам использовать разграниченные продолжения, чтобы охватить объем вашей реализации 'break'. –

+1

@AlexisKing Или, если весь цикл интерпретируется в одной и той же функции, можно полностью исключить 'call/cc', если цикл (Scheme-level) принимает дополнительный параметр, который может принимать значения' 'break' и '' continue' (например). Условие проверки затем оценивается только в том случае, если режим '' continue'. –

+0

переформатируйте свой код с помощью '(define (func args ...) ...' и named let '(пусть name ((aa) (bb) (cc)) ...)', и он получит гораздо больше компактный и читаемый. Кроме того, для меня он помогает писать '(call/cc (lambda (exit) ...' в одной строке, увеличивая следующие строки под 'call/cc', а не под' lambda', но это немного неортодоксальным. –

ответ

1

Я не изучил ваш код в деталях, но я заметил одно. У вас был параметр с именем cond как для вашей основной функции, так и для внешнего цикла. Это затмит встроенный макрос cond, который вы пытались использовать во внутреннем цикле.

Фактически, это само по себе объясняет, почему ваш (second-break-cont state) всегда вызывается. Выражение cond больше не является вызовом макроса, а является обычным вызовом функции, поэтому все выражения внутри вычисляются.

Вы должны назвать свой параметр чем-то иным, чем cond.