kiselgra/c-mera

Hex literals

nihofm opened this issue · 5 comments

I wanted to write the following code:

n = n & 0x00ff00ff;

but was only able to make it work using the comment-hack:

(set n (& n (comment "0x00ff00ff" :prefix "" :linebreak nil)))

Or did I miss something? I also couldn't find something appropriate grepping through the test source code.
When using a hack-macro, the code gets a bit more tidy:

(set n (& n (hack "0x00ff00ff")))

yet support for hex literals would be nice..

You can simply use common lisp style hex literals:

#x00ff00ff

Note, however, that they are not emitted as hex literals to the generated code, but plainly as integers:

16711935

This is hard to get around if you want to have C-style hex literals.

You could, of course, write a simple hex macro:

(defmacro hex (x)
  (lisp
     (let* ((verbose-atoms (reverse (loop with i = x
                                          while (> i 0)
                                          collect (mod i 16)
                                          do (setf i (floor (/ i 16))))))
            (chars '(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9 #\a #\b #\c #\d #\e #\f))
            (hex-atoms (mapcar (lambda (x) (elt chars x))
                               verbose-atoms))
            (hex-str (format nil "0x~{~a~}" hex-atoms)))
       `(comment ,hex-str :prefix "" :linebreak nil))))

So then

(+ 0 (hex #x00ff00ff))

would generate

0 + 0xff00ff

But still, speaking correct-tree-wise, having the literal in the lisp-code, only, is more "correct".

You would be able to keep the prefix (and be more concise) if you would accept symbols in the macro (you can get a string via symbol-name). I guess the processing would even be simpler.

(hex '00ff00ff)

Actually, yes, much simpler :)

(defmacro hex2 (x)
  `(comment ,(format nil "0x~a" (string-downcase (symbol-name (eval x)))) :prefix "" :linebreak nil))

Then

(+ 0 (hex2 '00ff00ff))

Yields

0 + 0x00ff00ff

The hex2-macro breaks when trying to use it with numbers only though, e.g. (hex2 '33445566).
So I settled for

(function vandercorput ((uint32_t n) (uint32_t scramble)) -> (inline float)
  (set n (\| (<< n 16) (>> n 16))
       n (\| (<< (& n (hex #x00ff00ff)) 8) (>> (& n (hex #xff00ff00)) 8))
       n (\| (<< (& n (hex #x0f0f0f0f)) 4) (>> (& n (hex #xf0f0f0f0)) 4))
       n (\| (<< (& n (hex #x33333333)) 2) (>> (& n (hex #xcccccccc)) 2))
       n (\| (<< (& n (hex #x55555555)) 1) (>> (& n (hex #xaaaaaaaa)) 1))
       n (^ n scramble))
  (return (/ (& (>> n 8) (hex #xffffffff)) (cast float (<< 1 24)))))

Works nicely and the code is way more readable than the (comment ...) version.
Nice, thanks!