extension.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /* Copyright (c) 1993-2007 by Richard Kelsey and Jonathan Rees.
  2. See file COPYING. */
  3. /* Implementation of the vm-extension opcode. This is completely
  4. optional; nothing in the standard system uses these features.
  5. The vm-extension opcode is being phased out. New code should use the
  6. external-call opcode to call C procedures.
  7. */
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <stdlib.h>
  11. #include <math.h>
  12. #include <signal.h>
  13. #include <errno.h>
  14. #include "scheme48.h"
  15. #define GREATEST_FIXNUM_VALUE ((1 << 29) - 1)
  16. #define LEAST_FIXNUM_VALUE (-1 << 29)
  17. #define CHANNEL_INDEX(x) EXTRACT_FIXNUM(STOB_REF(x, 1))
  18. #define FOR_INPUT 1
  19. #define FOR_OUTPUT 2
  20. typedef struct {
  21. char b[sizeof(double)];
  22. } unaligned_double;
  23. typedef union {
  24. double f;
  25. unaligned_double b;
  26. } float_or_bytes;
  27. extern long s48_Sextension_valueS; /* how values are returned */
  28. /* return status values */
  29. #define EXT_ST_OKAY 0
  30. #define EXT_ST_EXCEPTION 1
  31. #define EXT_RETURN(value) {s48_Sextension_valueS = (value); return EXT_ST_OKAY; }
  32. #define EXT_EXCEPTION return EXT_ST_EXCEPTION
  33. /******************************************/
  34. s48_value
  35. s48_extended_vm (long key, s48_value value)
  36. {
  37. double x, y;
  38. switch (key) {
  39. /* Cases 0 through 19 are reserved for the mobot system. */
  40. case 0: /* read jumpers on 68000 board */
  41. EXT_RETURN(S48_UNSAFE_ENTER_FIXNUM(0));
  42. /* Floating point */
  43. #define FLOP 100
  44. #define FLOP2(i) case FLOP+(i): \
  45. if (!S48_STOB_P(value) || S48_STOB_DESCRIPTOR_LENGTH(value) != 2) \
  46. EXT_EXCEPTION;
  47. #define FLOP3(i) case FLOP+(i): \
  48. if (!S48_STOB_P(value) || S48_STOB_DESCRIPTOR_LENGTH(value) != 3) \
  49. EXT_EXCEPTION;
  50. #define get_arg(args,i) S48_STOB_REF(args,(i))
  51. #define get_string_arg(args,i) (S48_UNSAFE_EXTRACT_STRING(get_arg(args,i)))
  52. #define get_float_arg(args, i, var) EXTRACT_FLOAT(get_arg(args, i), var)
  53. #define set_float_arg(args, i, val) SET_FLOAT(get_arg(args, i), val)
  54. #define EXTRACT_FLOAT(stob, var) \
  55. { s48_value temp_ = (stob); \
  56. float_or_bytes loser_; \
  57. if (!S48_STOB_P(temp_)) EXT_EXCEPTION; \
  58. loser_.b = *(unaligned_double*)(&S48_STOB_REF(temp_, 0)); \
  59. (var) = loser_.f; }
  60. #define SET_FLOAT(stob, val) \
  61. { s48_value temp_ = (stob); \
  62. float_or_bytes loser_; \
  63. if (!S48_STOB_P(temp_)) EXT_EXCEPTION; \
  64. loser_.f = (double)(val); \
  65. *(unaligned_double*)(&S48_STOB_REF(temp_, 0)) = loser_.b; }
  66. FLOP2(0) { /* fixnum->float */
  67. s48_value arg = get_arg(value, 0);
  68. if (!S48_FIXNUM_P(arg)) EXT_RETURN(S48_FALSE);
  69. set_float_arg(value, 1, S48_UNSAFE_EXTRACT_FIXNUM(arg));
  70. EXT_RETURN(S48_TRUE);}
  71. FLOP2(1) { /* string->float */
  72. static char* buf = NULL;
  73. static size_t max_size = 0;
  74. size_t len = s48_string_length(get_arg(value, 0));
  75. if (len + 1 > max_size)
  76. {
  77. max_size = ((len > 40) ? (len + 1) : 41);
  78. buf = realloc(buf, max_size);
  79. if (buf == NULL)
  80. EXT_RETURN(S48_FALSE);
  81. }
  82. s48_copy_string_to_latin_1(get_arg(value, 0), buf);
  83. buf[len] = '\0';
  84. set_float_arg(value, 1, atof(buf));
  85. EXT_RETURN(get_arg(value, 1));
  86. }
  87. FLOP2(2) { /* float->string */
  88. extern size_t s48_double_to_string(char *buf, double v);
  89. static char buf[40];
  90. int i;
  91. size_t len;
  92. get_float_arg(value, 0, x);
  93. len = s48_double_to_string(buf, x);
  94. s48_copy_latin_1_to_string_n(buf, len, get_arg(value,1));
  95. EXT_RETURN(S48_UNSAFE_ENTER_FIXNUM(len));
  96. }
  97. /* exp log sin cos tan asin acos atan1 atan2 sqrt */
  98. FLOP2(3) {
  99. get_float_arg(value, 0, x);
  100. set_float_arg(value, 1, exp(x));
  101. EXT_RETURN(S48_UNSPECIFIC);}
  102. FLOP2(4) {
  103. get_float_arg(value, 0, x);
  104. set_float_arg(value, 1, log(x));
  105. EXT_RETURN(S48_UNSPECIFIC);}
  106. FLOP2(5) {
  107. get_float_arg(value, 0, x);
  108. set_float_arg(value, 1, sin(x));
  109. EXT_RETURN(S48_UNSPECIFIC);}
  110. FLOP2(6) {
  111. get_float_arg(value, 0, x);
  112. set_float_arg(value, 1, cos(x));
  113. EXT_RETURN(S48_UNSPECIFIC);}
  114. FLOP2(7) {
  115. get_float_arg(value, 0, x);
  116. set_float_arg(value, 1, tan(x));
  117. EXT_RETURN(S48_UNSPECIFIC);}
  118. FLOP2(8) {
  119. get_float_arg(value, 0, x);
  120. set_float_arg(value, 1, asin(x));
  121. EXT_RETURN(S48_UNSPECIFIC);}
  122. FLOP2(9) {
  123. get_float_arg(value, 0, x);
  124. set_float_arg(value, 1, acos(x));
  125. EXT_RETURN(S48_UNSPECIFIC);}
  126. FLOP2(10) { /* atan 1 */
  127. get_float_arg(value, 0, x);
  128. set_float_arg(value, 1, atan(x));
  129. EXT_RETURN(S48_UNSPECIFIC);}
  130. FLOP3(11) { /* atan 2 */
  131. get_float_arg(value, 0, y);
  132. get_float_arg(value, 1, x);
  133. set_float_arg(value, 2, atan2(y, x));
  134. EXT_RETURN(S48_UNSPECIFIC);}
  135. FLOP2(12) {
  136. get_float_arg(value, 0, x);
  137. set_float_arg(value, 1, sqrt(x));
  138. EXT_RETURN(S48_UNSPECIFIC);}
  139. FLOP2(13) { /* floor */
  140. get_float_arg(value, 0, x);
  141. set_float_arg(value, 1, floor(x));
  142. EXT_RETURN(S48_UNSPECIFIC);}
  143. case FLOP+14: { /* integer? */
  144. EXTRACT_FLOAT(value, x);
  145. EXT_RETURN(S48_ENTER_BOOLEAN(fmod(x, 1.0) == 0.0)); }
  146. case FLOP+15: { /* float->fixnum */
  147. EXTRACT_FLOAT(value, x);
  148. if (x <= (double)GREATEST_FIXNUM_VALUE
  149. && x >= (double)LEAST_FIXNUM_VALUE)
  150. {
  151. EXT_RETURN(S48_UNSAFE_ENTER_FIXNUM((long)x)); }
  152. else
  153. EXT_RETURN(S48_FALSE);}
  154. FLOP3(16) { /* quotient */
  155. double z;
  156. get_float_arg(value, 0, x);
  157. get_float_arg(value, 1, y);
  158. if (fmod(x, 1.0) != 0.0 || fmod(y, 1.0) != 0.0) EXT_EXCEPTION;
  159. if (y == 0.0) EXT_EXCEPTION;
  160. z = x / y;
  161. set_float_arg(value, 2, z < 0.0 ? ceil(z) : floor(z));
  162. EXT_RETURN(S48_UNSPECIFIC);}
  163. FLOP3(17) { /* remainder */
  164. get_float_arg(value, 0, x);
  165. get_float_arg(value, 1, y);
  166. if (fmod(x, 1.0) != 0.0 || fmod(y, 1.0) != 0.0) EXT_EXCEPTION;
  167. if (y == 0.0) EXT_EXCEPTION;
  168. /* "fmod(double x, double y) returns the floating-point remainder
  169. (f) of the division of x by y, where f has the same sign as x,
  170. such that x=iy+f for some integer i, and |f| < |y|." */
  171. set_float_arg(value, 2, fmod(x, y));
  172. EXT_RETURN(S48_UNSPECIFIC);}
  173. default:
  174. EXT_EXCEPTION;
  175. }
  176. }