Advertisement
Guest User

Untitled

a guest
Jul 4th, 2020
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scheme 6.13 KB | None | 0 0
  1. ;;;; Representation independent Interpreter for simple Forth subset
  2. ;;;;
  3.  
  4. (add-to-load-path ".")
  5.  
  6. (library (interpreter)
  7.   (export eval-program make-primitive-environment)
  8.   (import (rnrs)
  9.           (environment)
  10.           (stack)
  11.           (program))
  12.  
  13.   (define primitive-bindings
  14.     (lambda ()
  15.       "return a list of bindings for the primitive environment"
  16.       (list (cons '+ (lambda (program) (eval-arithmetic-op + program)))
  17.             (cons '* (lambda (program) (eval-arithmetic-op * program)))
  18.             (cons '- (lambda (program) (eval-arithmetic-op - program)))
  19.             (cons '/ (lambda (program) (eval-arithmetic-op / program)))
  20.             (cons 'dup duplicate)
  21.             (cons 'swap swap)
  22.             (cons 'over over)
  23.             (cons 'drop drop)
  24.             (cons ': bind))))
  25.  
  26.   (define make-primitive-environment
  27.     (lambda ()
  28.       "return the environment of primitive bindings"
  29.       (let ((env (make-empty-environment)))
  30.         (let ((extend-env (lambda (id-value-pair)
  31.                             (let ((id (car id-value-pair))
  32.                                   (value (cdr id-value-pair)))
  33.                               (extend-environment id value env)))))
  34.           (map extend-env (primitive-bindings))))))
  35.  
  36.   (define eval-program
  37.     (lambda (program)
  38.       "return a program P where P's stack cannot be simplified further given
  39. P's environment"
  40.       (let ((stack (get-stack program))
  41.             (env (get-environment program)))
  42.         (if (empty? stack)
  43.             program
  44.             (let ((first-element (first stack))
  45.                   (new-stack (tail stack)))
  46.               (let ((operator (environment-lookup first-element env))
  47.                     (new-program (make-program new-stack env)))
  48.                 (if operator
  49.                     (eval-program (apply-operator operator new-program))
  50.                     program)))))))
  51.  
  52.   (define apply-operator
  53.     (lambda (operator program)
  54.       "return a program P which results from applying operator to program"
  55.       (if (procedure? operator)
  56.           (eval-program (operator program))
  57.           (eval-program (push-on-program-stack operator program)))))
  58.  
  59.   (define drop
  60.     (lambda (program)
  61.       "return a new program P whose stack S is the tail of program's stack"
  62.       (let ((stack (get-stack program)))
  63.         (if (empty? stack)
  64.             (error "Cannot call drop on an empty stack")
  65.             (make-program stack (get-environment program))))))
  66.  
  67.   (define duplicate
  68.     (lambda (program)
  69.       "return a new program P where P's stack is the stack of the input program
  70. with the element at the head duplicated.
  71. Precondition: program's stack is not empty"
  72.       (let ((stack (get-stack program)))
  73.         (if (empty? stack)
  74.             "Not enough arguments in stack for duplicate"
  75.             (let ((element (first stack)))
  76.               (push-on-program-stack element program))))))
  77.  
  78.   (define swap
  79.     (lambda (program)
  80.       "return a new program P where the first two values of P's stack is
  81. the first two of program's but swapped.
  82. Precondition: program's stack has at least two elements"
  83.       (let ((stack (get-stack program)))
  84.         (if (not (contains-at-least-two? stack))
  85.             (error "stack must have at least 2 elements for swap to work")
  86.             (let ((a (first stack))
  87.                   (b (second stack))
  88.                   (tail-tail (tail (tail stack))))
  89.               (make-program (push a (push b tail-tail))
  90.                             (get-environment program)))))))
  91.   (define over
  92.     (lambda (program)
  93.       "return a new program P such that the P's stack S is the second element
  94. of program's stack, and P's tail is program's stack"
  95.       (let ((stack (get-stack program)))
  96.         (if (not (contains-at-least-two? stack))
  97.             (error "Over expects a stack with at least 2 elements")
  98.             (push-on-program-stack (second stack) program)))))
  99.  
  100.   ;;; Evaluating arithmetic operations
  101.   ;;; let us reperesent programs as follows <stack, environment>
  102.   ;;; op program -> program
  103.   ;;; let
  104.   ;;;   R = program, and
  105.   ;;;   <(a b rest), env> = R
  106.   ;;;   in
  107.   ;;; if a is a number then,
  108.   ;;;   if b is a number then,
  109.   ;;;     let
  110.   ;;;       c = b `op` a
  111.   ;;;     in
  112.   ;;;      return <(c rest),env>
  113.   ;;;     end-let
  114.   ;;;   else if b is a symbol then,
  115.   ;;;     let
  116.   ;;;       <(e gs), env2> = evaluate <(b rest), env>
  117.   ;;;     in
  118.   ;;;       eval-arithmetic-op op <(a e gs), env2>
  119.   ;;;     end-let
  120.   ;;; else if a is a symbol,
  121.   ;;;     let
  122.   ;;;       Pa = evaluate R
  123.   ;;;       in
  124.   ;;;     eval-aritmetic-op op Pa
  125.  
  126.   (define eval-arithmetic-op
  127.     (lambda (op program)
  128.       "return a program P which results from applying op to program.
  129. Precondition: the stack S in program must have at least two elements."
  130.       (let ((stack (get-stack program)))
  131.         (if (not (contains-at-least-two? stack))
  132.             (error "Arithmetic operations require at least 2 operands")
  133.             (let ((a (first stack)))
  134.               (if (number? a)
  135.                   (let ((b (second stack)))
  136.                     (if (number? b)
  137.                         (push-on-program-stack (op b a) (drop (drop program)))
  138.                         (let ((program-2 (eval-program (drop program))))
  139.                           (eval-arithmetic-op  op (push-on-program-stack a program-2)))))
  140.                   (eval-arithmetic-op op (eval-program program))))))))
  141.  
  142.   (define bind
  143.     (lambda (program)
  144.       "let the binding be of the following format: id value.
  145. return a new program P such that id is bound to value in P's environment,
  146. and P's stack is the resulting stack after the bining statement is removed from
  147. program's stack"
  148.       (let ((stack (get-stack program)))
  149.         (if (not (and (eq? ': (first stack))
  150.                       (eq? '! (third (tail stack)))))
  151.             (error "Syntax error, binding syntax is `: id value !`")
  152.             (let ((id (second stack))
  153.                   (value (third stack))
  154.                   (new-stack (tail (tail (tail (tail stack)))))
  155.                   (env (get-environment program)))
  156.               (make-program new-stack env)))))))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement