Skip to content
This repository was archived by the owner on Dec 7, 2019. It is now read-only.

Compound Data Types

Jonathan50 edited this page Aug 2, 2017 · 8 revisions

Do-it does not have any compound data types built in. But it isn't very hard to implement some yourself, using the C library procedure malloc, and the do-it primitives peek and poke.

Here is an example program, implementing pairs (aka cons cells):

(defvar word-size 4) ; how many bytes can fit into a register

;;; The pair constructor
(defproc cons (car cdr)
  (defvar pair (malloc (* word-size 2)))
  (set-car pair car)
  (set-cdr pair cdr)
  pair)

;;; Pair mutators
(defproc set-car (pair car) (poke pair car))
(defproc set-cdr (pair cdr) (poke (+ pair word-size) cdr))

;;; Pair selectors
(defproc car (pair) (peek pair))
(defproc cdr (pair) (peek (+ pair word-size)))

Pairs have two word-sized fields, so cons allocates 2 words (8 bytes on 32-bit systems). Car returns the first word and cdr returns the second and set-car replaces the first and set-cdr replaces the second.

Then pairs can be used:

(defvar x (cons 1 2))
(car x)                ; ===> 1
(cdr x)                ; ===> 2
(set-car x 42)
(set-cdr x 1337)
(car x)                ; ===> 42
(cdr x)                ; ===> 1337
(free x)               ; free the memory used by the pair

Here is a Scheme macro for creating data structures:

(defmacro defstruct (const . fields)
  (define (enumerate lst)
    (define (helper lst idx)
      (if (null? lst)
          '()
          (cons idx (helper (cdr lst) (+ idx 1)))))
    (helper lst 0))
  (let* ((word-size 4)
         (field-names (map car fields))
         (field-count (length fields))
         (field-indices (enumerate fields))
         (getters field-names)
         (setters (map cadr fields)))
    `(begin
       (defproc ,const ,field-names
         (defvar obj (malloc (* ,word-size ,field-count)))
         ,@(map (lambda (setter field-name)
                  `(,setter obj ,field-name))
                setters field-names)
         obj)
       ,@(map
          (lambda (getter idx)
            `(defproc ,getter (obj)
               (peek (+ obj (* ,idx ,word-size)))))
          getters field-indices)
       ,@(map
          (lambda (setter idx)
            `(defproc ,setter (obj1 obj2)
               (poke (+ obj1 (* ,idx ,word-size)) obj2)))
          setters field-indices))))

The above pair structure could then be defined like this:

(defstruct cons
  (car set-car)
  (cdr set-cdr))

and used simply like this:

(defproc write-list (list)
  (while (> list 0)
    (printf "%d " (car list))
    (set list (cdr list)))
  (newline))

(write-list
 (cons 1 (cons 2 (cons 3 (cons 4 0)))))

These examples can be found in the example folder.

Clone this wiki locally