aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Moreton2018-08-04 10:28:13 -0600
committerTom Tromey2018-08-04 10:28:13 -0600
commitbc8ff54efee05f4a2769be32046866ed1e152b41 (patch)
treec6dac43f3b9abfc6bde54a9d245c04e5dbb360d5
parent76715f8921dca740880cd22c644a6328cd810846 (diff)
downloademacs-bc8ff54efee05f4a2769be32046866ed1e152b41.tar.gz
emacs-bc8ff54efee05f4a2769be32046866ed1e152b41.zip
Make bignums work better when EMACS_INT is larger than long
* lisp/international/ccl.el (ccl-fixnum): New function. (ccl-embed-data, ccl-embed-current-address, ccl-dump): Use it. * src/alloc.c (make_number): Handle case where EMACS_INT is larger than long. * src/data.c (bignumcompare): Handle case where EMACS_INT is larger than long. (arith_driver): Likewise. Coerce markers. (float_arith_driver): Coerce markers. (Flogcount): Use mpz_sgn. (ash_lsh_impl): Fix bugs. (Fsub1): Fix underflow check. * src/lisp.h (NUMBERP): Don't check BIGNUMP. (CHECK_FIXNUM_OR_FLOAT_COERCE_MARKER): Fix indentation. * test/lisp/international/ccl-tests.el: New file.
-rw-r--r--lisp/international/ccl.el16
-rw-r--r--src/alloc.c28
-rw-r--r--src/data.c96
-rw-r--r--src/lisp.h4
-rw-r--r--test/lisp/international/ccl-tests.el219
5 files changed, 340 insertions, 23 deletions
diff --git a/lisp/international/ccl.el b/lisp/international/ccl.el
index d2f490d59cd..d1b82ceb9ce 100644
--- a/lisp/international/ccl.el
+++ b/lisp/international/ccl.el
@@ -184,11 +184,17 @@
184(defvar ccl-current-ic 0 184(defvar ccl-current-ic 0
185 "The current index for `ccl-program-vector'.") 185 "The current index for `ccl-program-vector'.")
186 186
187;; This is needed because CCL assumes the pre-bigint (wrapping)
188;; semantics of integer overflow.
189(defun ccl-fixnum (code)
190 "Convert a CCL code word to a fixnum value."
191 (- (logxor (logand code #x0fffffff) #x08000000) #x08000000))
192
187(defun ccl-embed-data (data &optional ic) 193(defun ccl-embed-data (data &optional ic)
188 "Embed integer DATA in `ccl-program-vector' at `ccl-current-ic' and 194 "Embed integer DATA in `ccl-program-vector' at `ccl-current-ic' and
189increment it. If IC is specified, embed DATA at IC." 195increment it. If IC is specified, embed DATA at IC."
190 (if ic 196 (if ic
191 (aset ccl-program-vector ic data) 197 (aset ccl-program-vector ic (ccl-fixnum data))
192 (let ((len (length ccl-program-vector))) 198 (let ((len (length ccl-program-vector)))
193 (if (>= ccl-current-ic len) 199 (if (>= ccl-current-ic len)
194 (let ((new (make-vector (* len 2) nil))) 200 (let ((new (make-vector (* len 2) nil)))
@@ -196,7 +202,7 @@ increment it. If IC is specified, embed DATA at IC."
196 (setq len (1- len)) 202 (setq len (1- len))
197 (aset new len (aref ccl-program-vector len))) 203 (aset new len (aref ccl-program-vector len)))
198 (setq ccl-program-vector new)))) 204 (setq ccl-program-vector new))))
199 (aset ccl-program-vector ccl-current-ic data) 205 (aset ccl-program-vector ccl-current-ic (ccl-fixnum data))
200 (setq ccl-current-ic (1+ ccl-current-ic)))) 206 (setq ccl-current-ic (1+ ccl-current-ic))))
201 207
202(defun ccl-embed-symbol (symbol prop) 208(defun ccl-embed-symbol (symbol prop)
@@ -230,7 +236,8 @@ proper index number for SYMBOL. PROP should be
230`ccl-program-vector' at IC without altering the other bit field." 236`ccl-program-vector' at IC without altering the other bit field."
231 (let ((relative (- ccl-current-ic (1+ ic)))) 237 (let ((relative (- ccl-current-ic (1+ ic))))
232 (aset ccl-program-vector ic 238 (aset ccl-program-vector ic
233 (logior (aref ccl-program-vector ic) (ash relative 8))))) 239 (logior (aref ccl-program-vector ic)
240 (ccl-fixnum (ash relative 8))))))
234 241
235(defun ccl-embed-code (op reg data &optional reg2) 242(defun ccl-embed-code (op reg data &optional reg2)
236 "Embed CCL code for the operation OP and arguments REG and DATA in 243 "Embed CCL code for the operation OP and arguments REG and DATA in
@@ -986,7 +993,8 @@ is a list of CCL-BLOCKs."
986(defun ccl-get-next-code () 993(defun ccl-get-next-code ()
987 "Return a CCL code in `ccl-code' at `ccl-current-ic'." 994 "Return a CCL code in `ccl-code' at `ccl-current-ic'."
988 (prog1 995 (prog1
989 (aref ccl-code ccl-current-ic) 996 (let ((code (aref ccl-code ccl-current-ic)))
997 (if (numberp code) (ccl-fixnum code) code))
990 (setq ccl-current-ic (1+ ccl-current-ic)))) 998 (setq ccl-current-ic (1+ ccl-current-ic))))
991 999
992(defun ccl-dump-1 () 1000(defun ccl-dump-1 ()
diff --git a/src/alloc.c b/src/alloc.c
index 1dc1bbb031a..367bb73fc15 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -3815,6 +3815,34 @@ make_number (mpz_t value)
3815 } 3815 }
3816 } 3816 }
3817 3817
3818 /* Check if fixnum can be larger than long. */
3819 if (sizeof (EMACS_INT) > sizeof (long))
3820 {
3821 size_t bits = mpz_sizeinbase (value, 2);
3822 int sign = mpz_sgn (value);
3823
3824 if (bits < FIXNUM_BITS + (sign < 0))
3825 {
3826 EMACS_INT v = 0;
3827 size_t limbs = mpz_size (value);
3828 mp_size_t i;
3829
3830 for (i = 0; i < limbs; i++)
3831 {
3832 mp_limb_t limb = mpz_getlimbn (value, i);
3833 v |= (EMACS_INT) ((EMACS_UINT) limb << (i * GMP_NUMB_BITS));
3834 }
3835 if (sign < 0)
3836 v = -v;
3837
3838 if (!FIXNUM_OVERFLOW_P (v))
3839 {
3840 XSETINT (obj, v);
3841 return obj;
3842 }
3843 }
3844 }
3845
3818 obj = allocate_misc (Lisp_Misc_Bignum); 3846 obj = allocate_misc (Lisp_Misc_Bignum);
3819 b = XBIGNUM (obj); 3847 b = XBIGNUM (obj);
3820 /* We could mpz_init + mpz_swap here, to avoid a copy, but the 3848 /* We could mpz_init + mpz_swap here, to avoid a copy, but the
diff --git a/src/data.c b/src/data.c
index 0deebdca1ae..3d55d9d17d5 100644
--- a/src/data.c
+++ b/src/data.c
@@ -2409,7 +2409,18 @@ bignumcompare (Lisp_Object num1, Lisp_Object num2,
2409 if (FLOATP (num2)) 2409 if (FLOATP (num2))
2410 cmp = mpz_cmp_d (XBIGNUM (num1)->value, XFLOAT_DATA (num2)); 2410 cmp = mpz_cmp_d (XBIGNUM (num1)->value, XFLOAT_DATA (num2));
2411 else if (FIXNUMP (num2)) 2411 else if (FIXNUMP (num2))
2412 cmp = mpz_cmp_si (XBIGNUM (num1)->value, XINT (num2)); 2412 {
2413 if (sizeof (EMACS_INT) > sizeof (long) && XINT (num2) > LONG_MAX)
2414 {
2415 mpz_t tem;
2416 mpz_init (tem);
2417 mpz_set_intmax (tem, XINT (num2));
2418 cmp = mpz_cmp (XBIGNUM (num1)->value, tem);
2419 mpz_clear (tem);
2420 }
2421 else
2422 cmp = mpz_cmp_si (XBIGNUM (num1)->value, XINT (num2));
2423 }
2413 else 2424 else
2414 { 2425 {
2415 eassume (BIGNUMP (num2)); 2426 eassume (BIGNUMP (num2));
@@ -2422,10 +2433,19 @@ bignumcompare (Lisp_Object num1, Lisp_Object num2,
2422 if (FLOATP (num1)) 2433 if (FLOATP (num1))
2423 cmp = - mpz_cmp_d (XBIGNUM (num2)->value, XFLOAT_DATA (num1)); 2434 cmp = - mpz_cmp_d (XBIGNUM (num2)->value, XFLOAT_DATA (num1));
2424 else 2435 else
2425 { 2436 {
2426 eassume (FIXNUMP (num1)); 2437 eassume (FIXNUMP (num1));
2427 cmp = - mpz_cmp_si (XBIGNUM (num2)->value, XINT (num1)); 2438 if (sizeof (EMACS_INT) > sizeof (long) && XINT (num1) > LONG_MAX)
2428 } 2439 {
2440 mpz_t tem;
2441 mpz_init (tem);
2442 mpz_set_intmax (tem, XINT (num1));
2443 cmp = - mpz_cmp (XBIGNUM (num2)->value, tem);
2444 mpz_clear (tem);
2445 }
2446 else
2447 cmp = - mpz_cmp_si (XBIGNUM (num2)->value, XINT (num1));
2448 }
2429 } 2449 }
2430 2450
2431 switch (comparison) 2451 switch (comparison)
@@ -2860,7 +2880,7 @@ arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args)
2860 { 2880 {
2861 /* Using args[argnum] as argument to CHECK_NUMBER... */ 2881 /* Using args[argnum] as argument to CHECK_NUMBER... */
2862 val = args[argnum]; 2882 val = args[argnum];
2863 CHECK_NUMBER (val); 2883 CHECK_NUMBER_COERCE_MARKER (val);
2864 2884
2865 if (FLOATP (val)) 2885 if (FLOATP (val))
2866 return unbind_to (count, 2886 return unbind_to (count,
@@ -2871,7 +2891,15 @@ arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args)
2871 case Aadd: 2891 case Aadd:
2872 if (BIGNUMP (val)) 2892 if (BIGNUMP (val))
2873 mpz_add (accum, accum, XBIGNUM (val)->value); 2893 mpz_add (accum, accum, XBIGNUM (val)->value);
2874 else if (XINT (val) < 0) 2894 else if (sizeof (EMACS_INT) > sizeof (long))
2895 {
2896 mpz_t tem;
2897 mpz_init (tem);
2898 mpz_set_intmax (tem, XINT (val));
2899 mpz_add (accum, accum, tem);
2900 mpz_clear (tem);
2901 }
2902 else if (XINT (val) < 0)
2875 mpz_sub_ui (accum, accum, - XINT (val)); 2903 mpz_sub_ui (accum, accum, - XINT (val));
2876 else 2904 else
2877 mpz_add_ui (accum, accum, XINT (val)); 2905 mpz_add_ui (accum, accum, XINT (val));
@@ -2888,6 +2916,14 @@ arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args)
2888 } 2916 }
2889 else if (BIGNUMP (val)) 2917 else if (BIGNUMP (val))
2890 mpz_sub (accum, accum, XBIGNUM (val)->value); 2918 mpz_sub (accum, accum, XBIGNUM (val)->value);
2919 else if (sizeof (EMACS_INT) > sizeof (long))
2920 {
2921 mpz_t tem;
2922 mpz_init (tem);
2923 mpz_set_intmax (tem, XINT (val));
2924 mpz_sub (accum, accum, tem);
2925 mpz_clear (tem);
2926 }
2891 else if (XINT (val) < 0) 2927 else if (XINT (val) < 0)
2892 mpz_add_ui (accum, accum, - XINT (val)); 2928 mpz_add_ui (accum, accum, - XINT (val));
2893 else 2929 else
@@ -2896,6 +2932,14 @@ arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args)
2896 case Amult: 2932 case Amult:
2897 if (BIGNUMP (val)) 2933 if (BIGNUMP (val))
2898 mpz_mul (accum, accum, XBIGNUM (val)->value); 2934 mpz_mul (accum, accum, XBIGNUM (val)->value);
2935 else if (sizeof (EMACS_INT) > sizeof (long))
2936 {
2937 mpz_t tem;
2938 mpz_init (tem);
2939 mpz_set_intmax (tem, XINT (val));
2940 mpz_mul (accum, accum, tem);
2941 mpz_clear (tem);
2942 }
2899 else 2943 else
2900 mpz_mul_si (accum, accum, XINT (val)); 2944 mpz_mul_si (accum, accum, XINT (val));
2901 break; 2945 break;
@@ -2915,6 +2959,14 @@ arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args)
2915 xsignal0 (Qarith_error); 2959 xsignal0 (Qarith_error);
2916 if (BIGNUMP (val)) 2960 if (BIGNUMP (val))
2917 mpz_tdiv_q (accum, accum, XBIGNUM (val)->value); 2961 mpz_tdiv_q (accum, accum, XBIGNUM (val)->value);
2962 else if (sizeof (EMACS_INT) > sizeof (long))
2963 {
2964 mpz_t tem;
2965 mpz_init (tem);
2966 mpz_set_intmax (tem, XINT (val));
2967 mpz_tdiv_q (accum, accum, tem);
2968 mpz_clear (tem);
2969 }
2918 else 2970 else
2919 { 2971 {
2920 EMACS_INT value = XINT (val); 2972 EMACS_INT value = XINT (val);
@@ -2982,8 +3034,9 @@ float_arith_driver (double accum, ptrdiff_t argnum, enum arithop code,
2982 3034
2983 for (; argnum < nargs; argnum++) 3035 for (; argnum < nargs; argnum++)
2984 { 3036 {
2985 val = args[argnum]; /* using args[argnum] as argument to CHECK_FIXNUM_... */ 3037 /* using args[argnum] as argument to CHECK_NUMBER_... */
2986 CHECK_FIXNUM_OR_FLOAT_COERCE_MARKER (val); 3038 val = args[argnum];
3039 CHECK_NUMBER_COERCE_MARKER (val);
2987 3040
2988 if (FLOATP (val)) 3041 if (FLOATP (val))
2989 { 3042 {
@@ -3277,7 +3330,7 @@ representation. */)
3277 3330
3278 if (BIGNUMP (value)) 3331 if (BIGNUMP (value))
3279 { 3332 {
3280 if (mpz_cmp_si (XBIGNUM (value)->value, 0) >= 0) 3333 if (mpz_sgn (XBIGNUM (value)->value) >= 0)
3281 return make_fixnum (mpz_popcount (XBIGNUM (value)->value)); 3334 return make_fixnum (mpz_popcount (XBIGNUM (value)->value));
3282 mpz_t tem; 3335 mpz_t tem;
3283 mpz_init (tem); 3336 mpz_init (tem);
@@ -3314,8 +3367,10 @@ ash_lsh_impl (Lisp_Object value, Lisp_Object count, bool lsh)
3314 mpz_init (result); 3367 mpz_init (result);
3315 if (XINT (count) >= 0) 3368 if (XINT (count) >= 0)
3316 mpz_mul_2exp (result, XBIGNUM (value)->value, XINT (count)); 3369 mpz_mul_2exp (result, XBIGNUM (value)->value, XINT (count));
3317 else 3370 else if (lsh)
3318 mpz_tdiv_q_2exp (result, XBIGNUM (value)->value, - XINT (count)); 3371 mpz_tdiv_q_2exp (result, XBIGNUM (value)->value, - XINT (count));
3372 else
3373 mpz_fdiv_q_2exp (result, XBIGNUM (value)->value, - XINT (count));
3319 val = make_number (result); 3374 val = make_number (result);
3320 mpz_clear (result); 3375 mpz_clear (result);
3321 } 3376 }
@@ -3325,14 +3380,21 @@ ash_lsh_impl (Lisp_Object value, Lisp_Object count, bool lsh)
3325 mpz_t result; 3380 mpz_t result;
3326 eassume (FIXNUMP (value)); 3381 eassume (FIXNUMP (value));
3327 mpz_init (result); 3382 mpz_init (result);
3328 if (lsh) 3383
3329 mpz_set_uintmax (result, XUINT (value)); 3384 mpz_set_intmax (result, XINT (value));
3330 else 3385
3331 mpz_set_intmax (result, XINT (value));
3332 if (XINT (count) >= 0) 3386 if (XINT (count) >= 0)
3333 mpz_mul_2exp (result, result, XINT (count)); 3387 mpz_mul_2exp (result, result, XINT (count));
3334 else 3388 else if (lsh)
3335 mpz_tdiv_q_2exp (result, result, - XINT (count)); 3389 {
3390 if (mpz_sgn (result) > 0)
3391 mpz_fdiv_q_2exp (result, result, - XINT (count));
3392 else
3393 mpz_fdiv_q_2exp (result, result, - XINT (count));
3394 }
3395 else /* ash */
3396 mpz_fdiv_q_2exp (result, result, - XINT (count));
3397
3336 val = make_number (result); 3398 val = make_number (result);
3337 mpz_clear (result); 3399 mpz_clear (result);
3338 } 3400 }
@@ -3414,7 +3476,7 @@ Markers are converted to integers. */)
3414 else 3476 else
3415 { 3477 {
3416 eassume (FIXNUMP (number)); 3478 eassume (FIXNUMP (number));
3417 if (XINT (number) > MOST_POSITIVE_FIXNUM) 3479 if (XINT (number) > MOST_NEGATIVE_FIXNUM)
3418 XSETINT (number, XINT (number) - 1); 3480 XSETINT (number, XINT (number) - 1);
3419 else 3481 else
3420 { 3482 {
diff --git a/src/lisp.h b/src/lisp.h
index 4208634fa95..b404f9d89aa 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -2778,7 +2778,7 @@ NATNUMP (Lisp_Object x)
2778INLINE bool 2778INLINE bool
2779NUMBERP (Lisp_Object x) 2779NUMBERP (Lisp_Object x)
2780{ 2780{
2781 return INTEGERP (x) || FLOATP (x) || BIGNUMP (x); 2781 return INTEGERP (x) || FLOATP (x);
2782} 2782}
2783 2783
2784INLINE bool 2784INLINE bool
@@ -2947,7 +2947,7 @@ CHECK_INTEGER (Lisp_Object x)
2947 if (MARKERP (x)) \ 2947 if (MARKERP (x)) \
2948 XSETFASTINT (x, marker_position (x)); \ 2948 XSETFASTINT (x, marker_position (x)); \
2949 else \ 2949 else \
2950 CHECK_TYPE (FIXED_OR_FLOATP (x), Qnumber_or_marker_p, x); \ 2950 CHECK_TYPE (FIXED_OR_FLOATP (x), Qnumber_or_marker_p, x); \
2951 } while (false) 2951 } while (false)
2952 2952
2953#define CHECK_NUMBER_COERCE_MARKER(x) \ 2953#define CHECK_NUMBER_COERCE_MARKER(x) \
diff --git a/test/lisp/international/ccl-tests.el b/test/lisp/international/ccl-tests.el
new file mode 100644
index 00000000000..d0c254ce91b
--- /dev/null
+++ b/test/lisp/international/ccl-tests.el
@@ -0,0 +1,219 @@
1(require 'ert)
2(require 'ccl)
3(require 'seq)
4
5
6(ert-deftest shift ()
7 ;; shift left +ve 5628 #x00000000000015fc
8 (should (= (ash 5628 8) 1440768)) ; #x000000000015fc00
9 (should (= (lsh 5628 8) 1440768)) ; #x000000000015fc00
10
11 ;; shift left -ve -5628 #x3fffffffffffea04
12 (should (= (ash -5628 8) -1440768)) ; #x3fffffffffea0400
13 (should (= (lsh -5628 8) -1440768)) ; #x3fffffffffea0400
14
15 ;; shift right +ve 5628 #x00000000000015fc
16 (should (= (ash 5628 -8) 21)) ; #x0000000000000015
17 (should (= (lsh 5628 -8) 21)) ; #x0000000000000015
18
19 ;; shift right -ve -5628 #x3fffffffffffea04
20 (should (= (ash -5628 -8) -22)) ; #x3fffffffffffffea
21
22 ;; shift right -5628 #x3fffffffffffea04
23 (cond
24 ((fboundp 'bignump)
25 (should (= (lsh -5628 -8) -22))) ; #x3fffffffffffffea bignum
26 ((= (logb most-negative-fixnum) 61)
27 (should (= (lsh -5628 -8)
28 (string-to-number
29 "18014398509481962")))) ; #x003fffffffffffea master (64bit)
30 ((= (logb most-negative-fixnum) 29)
31 (should (= (lsh -5628 -8) 4194282))) ; #x003fffea master (32bit)
32 ))
33
34;; CCl program from `pgg-parse-crc24' in lisp/obsolete/pgg-parse.el
35(defconst prog-pgg-source
36 '(1
37 ((loop
38 (read r0) (r1 ^= r0) (r2 ^= 0)
39 (r5 = 0)
40 (loop
41 (r1 <<= 1)
42 (r1 += ((r2 >> 15) & 1))
43 (r2 <<= 1)
44 (if (r1 & 256)
45 ((r1 ^= 390) (r2 ^= 19707)))
46 (if (r5 < 7)
47 ((r5 += 1)
48 (repeat))))
49 (repeat)))))
50
51(defconst prog-pgg-code
52 [1 30 14 114744 114775 0 161 131127 1 148217 15 82167
53 1 1848 131159 1 1595 5 256 114743 390 114775 19707
54 1467 16 7 183 1 -5628 -7164 22])
55
56(defconst prog-pgg-dump
57"Out-buffer must be as large as in-buffer.
58Main-body:
59 2:[read-register] read r0 (0 remaining)
60 3:[set-assign-expr-register] r1 ^= r0
61 4:[set-assign-expr-const] r2 ^= 0
62 6:[set-short-const] r5 = 0
63 7:[set-assign-expr-const] r1 <<= 1
64 9:[set-expr-const] r7 = r2 >> 15
65 11:[set-assign-expr-const] r7 &= 1
66 13:[set-assign-expr-register] r1 += r7
67 14:[set-assign-expr-const] r2 <<= 1
68 16:[jump-cond-expr-const] if !(r1 & 256), jump to 23(+7)
69 19:[set-assign-expr-const] r1 ^= 390
70 21:[set-assign-expr-const] r2 ^= 19707
71 23:[jump-cond-expr-const] if !(r5 < 7), jump to 29(+6)
72 26:[set-assign-expr-const] r5 += 1
73 28:[jump] jump to 7(-21)
74 29:[jump] jump to 2(-27)
75At EOF:
76 30:[end] end
77")
78
79(ert-deftest ccl-compile-pgg ()
80 (should (equal (ccl-compile prog-pgg-source) prog-pgg-code)))
81
82(ert-deftest ccl-dump-pgg ()
83 (with-temp-buffer
84 (ccl-dump prog-pgg-code)
85 (should (equal (buffer-string) prog-pgg-dump))))
86
87(ert-deftest pgg-parse-crc24 ()
88 ;; Compiler
89 (require 'pgg)
90 (should (equal pgg-parse-crc24 prog-pgg-code))
91 ;; Interpreter
92 (should (equal (pgg-parse-crc24-string "foo") (concat [#x4f #xc2 #x55])))
93 (should (equal (pgg-parse-crc24-string "bar") (concat [#x51 #xd9 #x53])))
94 (should (equal (pgg-parse-crc24-string "baz") (concat [#xf0 #x58 #x6a]))))
95
96(ert-deftest pgg-parse-crc24-dump ()
97 ;; Disassembler
98 (require 'pgg)
99 (with-temp-buffer
100 (ccl-dump pgg-parse-crc24)
101 (should (equal (buffer-string) prog-pgg-dump))))
102
103;;----------------------------------------------------------------------------
104;; Program from 'midikbd-decoder in midi-kbd-0.2.el GNU ELPA package
105(defconst prog-midi-source
106 '(2
107 (loop
108 (loop
109 ;; central message receiver loop here.
110 ;; When it exits, the command to deal with is in r0
111 ;; Any arguments are in r1 and r2
112 ;; r3 contains: 0 if no arguments are accepted
113 ;; 1 if 1 argument can be accepted
114 ;; 2 if 2 arguments can be accepted
115 ;; 3 if the first of two arguments has been accepted
116 ;; Arguments are read into r1 and r2.
117 ;; r4 contains the current running status byte if any.
118 (read-if (r0 < #x80)
119 (branch r3
120 (repeat)
121 ((r1 = r0) (r0 = r4) (break))
122 ((r1 = r0) (r3 = 3) (repeat))
123 ((r2 = r0) (r3 = 2) (r0 = r4) (break))))
124 (if (r0 >= #xf8) ; real time message
125 (break))
126 (if (r0 < #xf0) ; channel command
127 ((r4 = r0)
128 (if ((r0 & #xe0) == #xc0)
129 ;; program change and channel pressure take only 1 argument
130 (r3 = 1)
131 (r3 = 2))
132 (repeat)))
133 ;; system common message, we swallow those for now
134 (r3 = 0)
135 (repeat))
136 (if ((r0 & #xf0) == #x90)
137 (if (r2 == 0) ; Some Midi devices use velocity 0
138 ; for switching notes off,
139 ; so translate into note-off
140 ; and fall through
141 (r0 -= #x10)
142 ((r0 &= #xf)
143 (write 0)
144 (write r0 r1 r2)
145 (repeat))))
146 (if ((r0 & #xf0) == #x80)
147 ((r0 &= #xf)
148 (write 1)
149 (write r0 r1 r2)
150 (repeat)))
151 (repeat))))
152
153(defconst prog-midi-code
154 [2 72 4893 16 128 1133 5 6 9 12 16 -2556 32 1024 6660 32 865
155 -4092 64 609 1024 4868 795 20 248 3844 3099 16 240 128 82169
156 224 1275 18 192 353 260 609 -9468 97 -9980 82169 240 4091
157 18 144 1371 18 0 16407 16 1796 81943 15 20 529 305 81 -14588
158 82169 240 2555 18 128 81943 15 276 529 305 81 -17660 -17916 22])
159
160(defconst prog-midi-dump
161"Out-buffer must be 2 times bigger than in-buffer.
162Main-body:
163 2:[read-jump-cond-expr-const] read r0, if !(r0 < 128), jump to 22(+20)
164 5:[branch] jump to array[r3] of length 4
165 11 12 15 18 22
166 11:[jump] jump to 2(-9)
167 12:[set-register] r1 = r0
168 13:[set-register] r0 = r4
169 14:[jump] jump to 41(+27)
170 15:[set-register] r1 = r0
171 16:[set-short-const] r3 = 3
172 17:[jump] jump to 2(-15)
173 18:[set-register] r2 = r0
174 19:[set-short-const] r3 = 2
175 20:[set-register] r0 = r4
176 21:[jump] jump to 41(+20)
177 22:[jump-cond-expr-const] if !(r0 >= 248), jump to 26(+4)
178 25:[jump] jump to 41(+16)
179 26:[jump-cond-expr-const] if !(r0 < 240), jump to 39(+13)
180 29:[set-register] r4 = r0
181 30:[set-expr-const] r7 = r0 & 224
182 32:[jump-cond-expr-const] if !(r7 == 192), jump to 37(+5)
183 35:[set-short-const] r3 = 1
184 36:[jump] jump to 38(+2)
185 37:[set-short-const] r3 = 2
186 38:[jump] jump to 2(-36)
187 39:[set-short-const] r3 = 0
188 40:[jump] jump to 2(-38)
189 41:[set-expr-const] r7 = r0 & 240
190 43:[jump-cond-expr-const] if !(r7 == 144), jump to 59(+16)
191 46:[jump-cond-expr-const] if !(r2 == 0), jump to 52(+6)
192 49:[set-assign-expr-const] r0 -= 16
193 51:[jump] jump to 59(+8)
194 52:[set-assign-expr-const] r0 &= 15
195 54:[write-const-string] write char \"\x00\"
196 55:[write-register] write r0 (2 remaining)
197 56:[write-register] write r1 (1 remaining)
198 57:[write-register] write r2 (0 remaining)
199 58:[jump] jump to 2(-56)
200 59:[set-expr-const] r7 = r0 & 240
201 61:[jump-cond-expr-const] if !(r7 == 128), jump to 71(+10)
202 64:[set-assign-expr-const] r0 &= 15
203 66:[write-const-string] write char \"\x01\"
204 67:[write-register] write r0 (2 remaining)
205 68:[write-register] write r1 (1 remaining)
206 69:[write-register] write r2 (0 remaining)
207 70:[jump] jump to 2(-68)
208 71:[jump] jump to 2(-69)
209At EOF:
210 72:[end] end
211")
212
213(ert-deftest ccl-compile-midi ()
214 (should (equal (ccl-compile prog-midi-source) prog-midi-code)))
215
216(ert-deftest ccl-dump-midi ()
217 (with-temp-buffer
218 (ccl-dump prog-midi-code)
219 (should (equal (buffer-string) prog-midi-dump))))