Welcome to the CHICKEN Scheme pasting service
bitstring.scm added by klgg213498 on Thu Oct 18 21:04:05 2012
;; bitstirng module implements the subset of Erlang bit syntax.
;;
;; Basic syntax description
;; (bitmatch vector-or-bitstring
;; (pattern1 .. patternN -> expression)
;; ...
;; (else expression))
;;
;; Notes:
;; - else block is optional.
;; - default endianes bigendian.
;; - default count 8 bits.
;; - if nothing matches and else guard didnt specified 'bitstring-match-failure
;; exception will thrown.
;;
;; Variable binding:
;; ( let NAME )
;; ( let NAME : bitstring)
;; ( let NAME : count )
;; ( let NAME : count : big)
;; ( let NAME : count : little)
;;
;; Compare with integer value:
;; ( value )
;; ( value : count )
;; ( value : count : big )
;; ( value : count : little )
;;
;; Guard condition, continue evaluate only when expression returns #t.
;; (check expression)
;;
(module bitstring
(bitmatch
make-bitstring
bitstring-length
bitstring-of-any
bitstring-of-vector
bitstring-read
bitstring-share
bitstring-compare
bitstring->list
bitstring->integer-big
bitstring->integer-little
integer->bitstring-big
integer->bitstring-little
bitstring->half
bitstring->single)
(import scheme chicken extras)
(define-syntax bitmatch
(syntax-rules ()
((_ value patterns ...)
(call-with-current-continuation
(lambda (k)
(or (bitmatch2 ('secret-params value k) patterns ...)))))))
(define-syntax bitmatch2
(syntax-rules (else)
((_ ('secret-params value k))
(abort (list 'bitstring-match-failure)))
((_ ('secret-params value k) (else expression))
(k expression))
((_ ('secret-params value k) (pattern ...) rest ...)
(or
(let ((stream (bitstring-of-any value)))
(bitmatch1 ('secret-params stream k) pattern ...))
(bitmatch2 ('secret-params value k) rest ...)))))
(define-syntax bitmatch1
; CAUTION: use ##core#let during macro expansion !!!
(syntax-rules (let big little bitstring check float : ->)
; read 16 bit float
((_ ('secret-params stream k) (let name : 16 : float) rest ...)
(and-let* ((tmp (bitstring-read stream 16))
(name (bitstring->half tmp)))
(bitmatch1 ('secret-params stream k) rest ...)))
; read 32 bit float
((_ ('secret-params stream k) (let name : 32 : float) rest ...)
(and-let* ((tmp (bitstring-read stream 32))
(name (bitstring->single tmp)))
(bitmatch1 ('secret-params stream k) rest ...)))
; rewrite => (let name : 8 : big)
((_ ('secret-params stream k) (let name : big) rest ...)
(bitmatch1 ('secret-params stream k) (let name : 8: big) rest ...))
; rewrite => (let name : 8 : little)
((_ ('secret-params stream k) (let name : little) rest ...)
(bitmatch1 ('secret-params stream k) (let name : 8: little) rest ...))
; match rest value
((_ ('secret-params stream k) (let name : bitstring) -> rest ...)
(and-let* ((count (bitstring-length stream))
(name (bitstring-read stream count)))
(bitmatch1 ('secret-params stream k) -> rest ...)))
; rewrite => (let name : count : big)
((_ ('secret-params stream k) (let name : count) rest ...)
(bitmatch1 ('secret-params stream k) (let name : count : big) rest ...))
; bind named integer
((_ ('secret-params stream k) (let name : count : big) rest ...)
(and-let* ((tmp (bitstring-read stream count))
(name (bitstring->integer-big tmp)))
(bitmatch1 ('secret-params stream k) rest ...)))
((_ ('secret-params stream k) (let name : count : little) rest ...)
(and-let* ((tmp (bitstring-read stream count))
(name (bitstring->integer-little tmp)))
(bitmatch1 ('secret-params stream k) rest ...)))
; bind named bitstring
((_ ('secret-params stream k) (let name : count : bitstring) rest ...)
(and-let* ((name (bitstring-read stream count)))
(bitmatch1 ('secret-params stream k) rest ...)))
; rewrite => (let name : 8 big)
((_ ('secret-params stream k) (let name) rest ...)
(bitmatch1 ('secret-params stream k) (let name : 8 : big) rest ...))
; compare bigendian values
((_ ('secret-params stream k) (value : count : big) rest ...)
(and-let* ((tmp (bitstring-read stream count))
(value2 (bitstring->integer-big tmp)))
(and
(equal? value value2)
(bitmatch1 ('secret-params stream k) rest ...))))
; compare littleendian values
((_ ('secret-params stream k) (value : count : little) rest ...)
(and-let* ((tmp (bitstring-read stream count))
(value2 (bitstring->integer-little tmp)))
(and
(equal? value value2)
(bitmatch1 ('secret-params stream k) rest ...))))
; rewrtie to => (value : 8 : big)
((_ ('secret-params stream k) (value : count) rest ...)
(bitmatch1 ('secret-params stream k) (value : count : big) rest ...))
; compare 8 bit integer or bitstring
((_ ('secret-params stream k) (value) rest ...)
(cond
((integer? value)
(bitmatch1 ('secret-params stream k) (value : 8 : big) rest ...))
((char? value)
(bitmatch1 ('secret-params stream k) ((char->integer value) : 8 : big) rest ...))
(else
(and-let* ((tmp1 (bitstring-of-any value))
(tmp2 (bitstring-read stream (bitstring-length tmp1))))
(and
(bitstring-compare tmp1 tmp2)
(bitmatch1 ('secret-params stream k) rest ...))))))
; user guard expression
((_ ('secret-params stream k) (check condition) rest ...)
(and
condition
(bitmatch1 ('secret-params stream k) rest ...)))
; user expression
((_ ('secret-params stream k) -> expression)
(and
(zero? (bitstring-length stream))
(k expression)))
; empty expression body
((_ ('secret-params stream k))
(abort (list 'bitstring-empty-pattern)))
((_ ('secret-params stream k) err1)
(abort (list 'bitstring-malformed-pattern `err1)))
; unrecognized value
((_ ('secret-params stream k) err1 rest ...)
(abort (list 'bitstring-malformed-pattern `err1)))))
;;;;;;;;;;;;;;;;;;;;;;
;; bitstring
(define-record bitstring
offset ; offset in bits
numbits ; length of the bitstring in bits
buffer) ; vector
(define-record-printer (bitstring x out)
(fprintf out ""
(bitstring-offset x)
(bitstring-numbits x)
(bitstring-buffer x)))
(define (bitstring-length bs)
(- (bitstring-numbits bs) (bitstring-offset bs)))
(define (bitstring-reserve numbits)
(let* ((n (quotient numbits 8))
(rem (remainder numbits 8))
(aligned-size (if (zero? rem) n (+ 1 n))))
(make-bitstring 0 numbits (make-vector aligned-size 0))))
(define (bitstring-of-any x)
(cond
((bitstring? x)
x) ;FIXME: make copy of x
((string? x)
(let ((tmp (map (lambda (c) (char->integer c)) (string->list x))))
(bitstring-of-vector (list->vector tmp))))
((vector? x)
(bitstring-of-vector x))))
(define (bitstring-of-vector v)
(let* ((size (vector-length v))
(numbits (* 8 size)))
(make-bitstring 0 numbits v)))
(define (bitstring->list bs)
(reverse
(bitstring-fold
(lambda (offset n b acc)
(let ((byte (arithmetic-shift b (- n 8))))
(append (list byte) acc)))
'()
bs)))
(define (bitstring-compare a b)
(and
(= (bitstring-length a) (bitstring-length b))
(equal? (bitstring->list a) (bitstring->list b))))
(define (bitstring-load-byte bitstring index)
(vector-ref (bitstring-buffer bitstring) index))
(define (bitstring-load-word bitstring index)
(bitwise-ior
(arithmetic-shift (bitstring-load-byte bitstring index) 8)
(bitstring-load-byte bitstring (+ index 1))))
(define (bitstring-store-byte bitstring index value)
(vector-set! (bitstring-buffer bitstring) index (bitwise-and #xFF value)))
(define (bitstring-fold func init-value bitstring)
(let* ((offset (bitstring-offset bitstring))
(count (bitstring-numbits bitstring))
(shift (remainder offset 8)))
(if (zero? shift)
(bitstring-fold-aligned func init-value bitstring offset count)
(bitstring-fold-shifted func init-value bitstring offset count shift))))
(define (bitstring-fold-aligned func init-value bitstring from to)
(let loop ((offset from)
(index (quotient from 8))
(acc init-value))
(let ((n (min 8 (- to offset))))
(if (<= n 0)
acc
(loop (+ offset n) (+ 1 index)
(func offset n (bitstring-load-byte bitstring index) acc))))))
(define (bitstring-fold-shifted func init-value bitstring from to shift)
(let loop ((offset from)
(index (quotient from 8))
(acc init-value))
(let ((n (min 8 (- to offset))))
(cond
((<= n 0)
acc)
((< 8 (+ n shift))
; read splitted bits as word with shift
(let* ((word (bitstring-load-word bitstring index))
(drift (- shift 8))
(byte (bitwise-and (arithmetic-shift word drift) #xFF)))
(loop (+ offset n) (+ 1 index) (func offset n byte acc))))
(else ; read rest bits
(let* ((tmp (bitstring-load-byte bitstring index))
(drift (remainder offset 8))
(byte (bitwise-and (arithmetic-shift tmp drift) #xFF)))
;(print (sprintf "tmp:~X n:~A dritf:~A byte:~X shift:~A" tmp n drift byte shift))
(loop (+ offset n) (+ 1 index) (func offset n byte acc))))))))
(define (integer-fold func init-value read-byte count)
(let loop ((offset 0)
(index 0)
(acc init-value))
(let ((n (min 8 (- count offset))))
(cond
((<= n 0)
acc)
(else
(loop (+ offset n) (+ 1 index)
(func index n (read-byte offset n) acc)))))))
(define (bitstring->integer-little bitstring)
(bitstring-fold
(lambda (offset n b acc)
(let ((bits (arithmetic-shift b (- n 8))))
(bitwise-ior (arithmetic-shift bits offset) acc)))
0
bitstring))
(define (bitstring->integer-big bitstring)
(bitstring-fold
(lambda (offset n b acc)
(let ((bits (arithmetic-shift b (- n 8)))
(count (bitstring-numbits bitstring)))
;(print "offset: " offset (sprintf " b: ~X" b) " n: " n)
(bitwise-ior (arithmetic-shift bits (- count offset n)) acc)))
0
bitstring))
(define (integer->bitstring-little value count)
(integer-fold
(lambda (index n b acc)
(bitstring-store-byte acc index (arithmetic-shift b (- 8 n)))
acc)
(bitstring-reserve count)
(lambda (offset n)
(bitwise-and (arithmetic-shift value (- offset)) #xFF))
count))
(define (integer->bitstring-big value count)
(integer-fold
(lambda (index n b acc)
(bitstring-store-byte acc index b)
acc)
(bitstring-reserve count)
(lambda (offset n)
(let* ((r (- count offset n))
(b (arithmetic-shift value (- r))))
(arithmetic-shift (bitwise-and b #xFF) (- 8 n))))
count))
(define (bitstring->half bs)
(let ((s (bitstring-read bs 1))
(e (bitstring-read bs 5))
(m (bitstring-read bs 10)))
(make-half-float
(bitstring->integer-big s)
(bitstring->integer-big e)
(bitstring->integer-big m))))
(define (make-half-float signbit exponent mantissa)
;(newline)
;(print "s: " signbit " e: " exponent " m: " mantissa)
(cond
((and (zero? exponent) (zero? mantissa))
(if (zero? signbit) +0. -0.))
((= exponent 31)
(if (zero? mantissa)
(if (zero? signbit) +inf.0 -inf.0)
(if (zero? signbit) +nan.0 -nan.0)))
(else
(let ((e (- exponent 15))
(m (bitwise-ior #x400 mantissa)))
(let loop ((i 10) (s 1.) (f 0.))
(let* ((x (arithmetic-shift 1 i))
(b (bitwise-and m x)))
(if (or (zero? i))
(* f (expt 2 e) (if (zero? signbit) 1. -1.))
(loop (- i 1) (/ s 2) (if (zero? b) f (+ f s))))))))))
(define (make-single-float signbit exponent mantissa)
(cond
((and (zero? exponent) (zero? mantissa))
(if (zero? signbit) +0. -0.))
((= exponent 255)
(if (zero? mantissa)
(if (zero? signbit) +inf.0 -inf.0)
(if (zero? signbit) +nan.0 -nan.0)))
(else
(let ((e (- exponent 127))
(m (bitwise-ior #x800000 mantissa)))
(let loop ((i 23) (s 1.) (f 0.))
(let* ((x (arithmetic-shift 1 i))
(b (bitwise-and m x)))
(if (or (zero? i))
(* f (expt 2 e) (if (zero? signbit) 1. -1.))
(loop (- i 1) (/ s 2) (if (zero? b) f (+ f s))))))))))
(define (bitstring->single bs)
(let ((s (bitstring-read bs 1))
(e (bitstring-read bs 8))
(m (bitstring-read bs 23)))
(make-single-float
(bitstring->integer-big s)
(bitstring->integer-big e)
(bitstring->integer-big m))))
(define (bitstring-share bs from to)
(let ((numbits (bitstring-numbits bs)))
(and
(<= from to)
(<= to numbits)
(make-bitstring from to (bitstring-buffer bs)))))
(define (bitstring-read bs count)
(let* ((from (bitstring-offset bs))
(to (+ from count))
(shared (bitstring-share bs from to)))
(if shared
(begin
(bitstring-offset-set! bs to)
shared)
#f)))
);module