You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

339 lines
13 KiB

25 years ago
  1. // read_complex().
  2. // General includes.
  3. #include "cl_sysdep.h"
  4. // Specification.
  5. #include "cl_complex_io.h"
  6. // Implementation.
  7. #include <string.h>
  8. #include "cl_input.h"
  9. #include "cl_real_io.h"
  10. #include "cl_float_io.h"
  11. #include "cl_rational_io.h"
  12. #include "cl_integer_io.h"
  13. #include "cl_integer.h"
  14. #include "cl_I.h"
  15. #include "cl_F.h"
  16. #include "cl_C.h"
  17. #include "cl_abort.h"
  18. #undef floor
  19. #include <math.h>
  20. #define floor cln_floor
  21. // Step forward over all digits, to the end of string or to the next non-digit.
  22. static const char * skip_digits (const char * ptr, const char * string_limit, unsigned int base)
  23. {
  24. for ( ; ptr != string_limit; ptr++) {
  25. var char ch = *ptr;
  26. if ((ch >= '0') && (ch <= '9'))
  27. if (ch < '0' + (int)base)
  28. continue;
  29. else
  30. break;
  31. else {
  32. if (base <= 10)
  33. break;
  34. if (((ch >= 'A') && (ch < 'A'-10+(int)base))
  35. || ((ch >= 'a') && (ch < 'a'-10+(int)base))
  36. )
  37. continue;
  38. else
  39. break;
  40. }
  41. }
  42. return ptr;
  43. }
  44. // Finish reading the "+yi" part of "x+yi" when "x" has already been read.
  45. static const cl_N read_complex_number_rest (const cl_read_flags& flags, const char * string_rest, const char * string, const char * string_limit, const char * * end_of_parse, const cl_R& x);
  46. #define at_end_of_parse(ptr) \
  47. if (end_of_parse) \
  48. { *end_of_parse = (ptr); } \
  49. else \
  50. { if ((ptr) != string_limit) { read_number_junk((ptr),string,string_limit); } }
  51. const cl_N read_complex (const cl_read_flags& flags, const char * string, const char * string_limit, const char * * end_of_parse)
  52. {
  53. // If no string_limit is given, it defaults to the end of the string.
  54. if (!string_limit)
  55. string_limit = string + strlen(string);
  56. if (flags.syntax & syntax_rational) {
  57. // Check for rational number syntax.
  58. var unsigned int rational_base = flags.rational_base;
  59. var const char * ptr = string;
  60. if (flags.lsyntax & lsyntax_commonlisp) {
  61. if (ptr == string_limit) goto not_rational_syntax;
  62. if (*ptr == '#') {
  63. // Check for #b, #o, #x, #nR syntax.
  64. ptr++;
  65. if (ptr == string_limit) goto not_rational_syntax;
  66. switch (*ptr) {
  67. case 'b': case 'B':
  68. rational_base = 2; break;
  69. case 'o': case 'O':
  70. rational_base = 8; break;
  71. case 'x': case 'X':
  72. rational_base = 16; break;
  73. default:
  74. var const char * base_end_ptr =
  75. skip_digits(ptr,string_limit,10);
  76. if (base_end_ptr == ptr) goto not_rational_syntax;
  77. if (base_end_ptr == string_limit) goto not_rational_syntax;
  78. if (!((*base_end_ptr == 'r') || (*base_end_ptr == 'R')))
  79. goto not_rational_syntax;
  80. var cl_I base = read_integer(10,0,ptr,0,base_end_ptr-ptr);
  81. if (!((base >= 2) && (base <= 36))) {
  82. fprint(cl_stderr, "Base must be an integer in the range from 2 to 36, not ");
  83. fprint(cl_stderr, base);
  84. fprint(cl_stderr, "\n");
  85. cl_abort();
  86. }
  87. rational_base = FN_to_UL(base); ptr = base_end_ptr;
  88. break;
  89. }
  90. ptr++;
  91. }
  92. }
  93. var const char * ptr_after_prefix = ptr;
  94. var cl_signean sign = 0;
  95. if (ptr == string_limit) goto not_rational_syntax;
  96. switch (*ptr) {
  97. case '-': sign = ~sign;
  98. case '+': ptr++;
  99. default: break;
  100. }
  101. var const char * ptr_after_sign = ptr;
  102. if (flags.syntax & syntax_integer) {
  103. // Check for integer syntax: {'+'|'-'|} {digit}+ {'.'|}
  104. // Allow final dot only in Common Lisp syntax if there was no #<base> prefix.
  105. if ((flags.lsyntax & lsyntax_commonlisp) && (ptr_after_prefix == string)) {
  106. ptr = skip_digits(ptr_after_sign,string_limit,10);
  107. if (ptr != ptr_after_sign)
  108. if (ptr != string_limit)
  109. if (*ptr == '.') {
  110. ptr++;
  111. if ((ptr == string_limit) || !(((*ptr >= '0') && (*ptr <= '9')) || ((*ptr >= 'A') && (*ptr <= 'Z') && (*ptr != 'I')) || ((*ptr >= 'a') && (*ptr <= 'z') && (*ptr != 'i')) || (*ptr == '.') || (*ptr == '_') || (*ptr == '/')))
  112. return read_complex_number_rest(flags,ptr,string,string_limit,end_of_parse,
  113. read_integer(10,sign,ptr_after_sign,0,ptr-ptr_after_sign));
  114. }
  115. }
  116. ptr = skip_digits(ptr_after_sign,string_limit,rational_base);
  117. if ((ptr == string_limit) || !(((*ptr >= '0') && (*ptr <= '9')) || ((*ptr >= 'A') && (*ptr <= 'Z') && (*ptr != 'I')) || ((*ptr >= 'a') && (*ptr <= 'z') && (*ptr != 'i')) || (*ptr == '.') || (*ptr == '_') || (*ptr == '/')))
  118. return read_complex_number_rest(flags,ptr,string,string_limit,end_of_parse,
  119. read_integer(rational_base,sign,ptr_after_sign,0,ptr-ptr_after_sign));
  120. }
  121. if (flags.syntax & syntax_ratio) {
  122. // Check for ratio syntax: {'+'|'-'|} {digit}+ '/' {digit}+
  123. ptr = skip_digits(ptr_after_sign,string_limit,rational_base);
  124. if (ptr != ptr_after_sign)
  125. if (ptr != string_limit)
  126. if (*ptr == '/') {
  127. var const char * ptr_at_slash = ptr;
  128. ptr = skip_digits(ptr_at_slash+1,string_limit,rational_base);
  129. if (ptr != ptr_at_slash+1)
  130. if ((ptr == string_limit) || !(((*ptr >= '0') && (*ptr <= '9')) || ((*ptr >= 'A') && (*ptr <= 'Z') && (*ptr != 'I')) || ((*ptr >= 'a') && (*ptr <= 'z') && (*ptr != 'i')) || (*ptr == '.') || (*ptr == '_') || (*ptr == '/')))
  131. return read_complex_number_rest(flags,ptr,string,string_limit,end_of_parse,
  132. read_rational(rational_base,sign,ptr_after_sign,0,ptr_at_slash-ptr_after_sign,ptr-ptr_after_sign));
  133. }
  134. }
  135. }
  136. not_rational_syntax:
  137. if (flags.syntax & syntax_float) {
  138. // Check for floating-point number syntax:
  139. // {'+'|'-'|} {digit}+ {'.' {digit}* | } expo {'+'|'-'|} {digit}+
  140. // {'+'|'-'|} {digit}* '.' {digit}+ expo {'+'|'-'|} {digit}+
  141. // {'+'|'-'|} {digit}* '.' {digit}+
  142. var const char * ptr = string;
  143. var const unsigned int float_base = 10;
  144. var cl_signean sign = 0;
  145. if (ptr == string_limit) goto not_float_syntax;
  146. switch (*ptr) {
  147. case '-': sign = ~sign;
  148. case '+': ptr++;
  149. default: break;
  150. }
  151. var const char * ptr_after_sign = ptr;
  152. var const char * ptr_after_intpart = skip_digits(ptr_after_sign,string_limit,float_base);
  153. var cl_boolean have_dot = cl_false;
  154. var const char * ptr_before_fracpart = ptr_after_intpart;
  155. var const char * ptr_after_fracpart = ptr_after_intpart;
  156. ptr = ptr_after_intpart;
  157. if (ptr != string_limit)
  158. if (*ptr == '.') {
  159. have_dot = cl_true;
  160. ptr_before_fracpart = ptr+1;
  161. ptr_after_fracpart = skip_digits(ptr_before_fracpart,string_limit,float_base);
  162. }
  163. ptr = ptr_after_fracpart;
  164. var char exponent_marker;
  165. var cl_boolean have_exponent;
  166. var const char * ptr_in_exponent = ptr;
  167. var const char * ptr_after_exponent = ptr;
  168. if ((ptr == string_limit) || !(((*ptr >= '0') && (*ptr <= '9')) || ((*ptr >= 'A') && (*ptr <= 'Z') && (*ptr != 'I')) || ((*ptr >= 'a') && (*ptr <= 'z') && (*ptr != 'i')) || (*ptr == '.') || (*ptr == '/'))) {
  169. // No exponent.
  170. have_exponent = cl_false;
  171. // Must have at least one fractional part digit.
  172. if (ptr_after_fracpart == ptr_before_fracpart) goto not_float_syntax;
  173. exponent_marker = 'E';
  174. } else {
  175. have_exponent = cl_true;
  176. // Must have at least one digit.
  177. if (ptr_after_sign == ptr_after_intpart)
  178. if (ptr_after_fracpart == ptr_before_fracpart)
  179. goto not_float_syntax;
  180. exponent_marker = ((*ptr >= 'a') && (*ptr <= 'z') ? *ptr - 'a' + 'A' : *ptr);
  181. switch (exponent_marker) {
  182. case 'E':
  183. case 'S': case 'F': case 'D': case 'L':
  184. break;
  185. default:
  186. goto not_float_syntax;
  187. }
  188. }
  189. if (have_exponent) {
  190. ptr++;
  191. if (ptr == string_limit) goto not_float_syntax;
  192. switch (*ptr) {
  193. case '-':
  194. case '+': ptr++;
  195. default: break;
  196. }
  197. ptr_in_exponent = ptr;
  198. ptr_after_exponent = skip_digits(ptr_in_exponent,string_limit,10);
  199. if (ptr_after_exponent == ptr_in_exponent) goto not_float_syntax;
  200. }
  201. ptr = ptr_after_exponent;
  202. var const char * ptr_after_prec = ptr;
  203. var cl_float_format_t prec;
  204. if ((ptr != string_limit) && (*ptr == '_')) {
  205. ptr++;
  206. ptr_after_prec = skip_digits(ptr,string_limit,10);
  207. if (ptr_after_prec == ptr) goto not_float_syntax;
  208. var cl_I prec1 = digits_to_I(ptr,ptr_after_prec-ptr,10);
  209. var uintL prec2 = cl_I_to_UL(prec1);
  210. prec = (float_base==10 ? cl_float_format(prec2)
  211. : (cl_float_format_t)((uintL)((1+prec2)*log((double)float_base)*1.442695041)+1)
  212. );
  213. } else {
  214. switch (exponent_marker) {
  215. case 'S': prec = cl_float_format_sfloat; break;
  216. case 'F': prec = cl_float_format_ffloat; break;
  217. case 'D': prec = cl_float_format_dfloat; break;
  218. case 'L': prec = flags.float_flags.default_lfloat_format; break;
  219. case 'E': prec = flags.float_flags.default_float_format; break;
  220. default: NOTREACHED
  221. }
  222. if (flags.float_flags.mantissa_dependent_float_format) {
  223. // Count the number of significant digits.
  224. ptr = ptr_after_sign;
  225. while (ptr < ptr_after_fracpart && (*ptr == '0' || *ptr == '.')) ptr++;
  226. var uintL num_significant_digits =
  227. (ptr_after_fracpart - ptr) - (ptr_before_fracpart > ptr ? 1 : 0);
  228. var uintL prec2 = (num_significant_digits>=2 ? num_significant_digits-2 : 0);
  229. var cl_float_format_t precx =
  230. (float_base==10 ? cl_float_format(prec2)
  231. : (cl_float_format_t)((uintL)((1+prec2)*log((double)float_base)*1.442695041)+1)
  232. );
  233. if ((uintL)precx > (uintL)prec)
  234. prec = precx;
  235. }
  236. }
  237. floatformatcase(prec
  238. , if (!(flags.syntax & syntax_sfloat)) goto not_float_syntax;
  239. , if (!(flags.syntax & syntax_ffloat)) goto not_float_syntax;
  240. , if (!(flags.syntax & syntax_dfloat)) goto not_float_syntax;
  241. , unused len;
  242. if (!(flags.syntax & syntax_lfloat)) goto not_float_syntax;
  243. );
  244. return read_complex_number_rest(flags,ptr_after_prec,string,string_limit,end_of_parse,
  245. read_float(float_base,prec,sign,ptr_after_sign,0,ptr_after_fracpart-ptr_after_sign,ptr_after_exponent-ptr_after_sign,ptr_before_fracpart-ptr_after_sign));
  246. }
  247. not_float_syntax:
  248. if ((flags.syntax & syntax_complex) && (flags.lsyntax & lsyntax_commonlisp)) {
  249. // Check for complex number syntax:
  250. // '#' {'C'|'c'} '(' realpart {' '}+ imagpart ')'
  251. var const char * ptr = string;
  252. if (ptr == string_limit) goto not_complex_syntax;
  253. if (!(*ptr == '#')) goto not_complex_syntax;
  254. ptr++;
  255. if (ptr == string_limit) goto not_complex_syntax;
  256. if (!((*ptr == 'C') || (*ptr == 'c'))) goto not_complex_syntax;
  257. ptr++;
  258. // Modified flags for parsing the realpart and imagpart:
  259. var cl_read_flags flags_for_parts = flags;
  260. flags_for_parts.syntax = (cl_read_syntax_t)((flags_for_parts.syntax & ~syntax_complex) | syntax_maybe_bad);
  261. var const char * end_of_part;
  262. if (ptr == string_limit) goto not_complex_syntax;
  263. if (!(*ptr == '(')) goto not_complex_syntax;
  264. ptr++;
  265. var cl_R realpart = read_real(flags_for_parts,ptr,string_limit,&end_of_part);
  266. if (end_of_part == ptr) goto not_complex_syntax;
  267. ptr = end_of_part;
  268. if (ptr == string_limit) goto not_complex_syntax;
  269. if (!(*ptr == ' ')) goto not_complex_syntax;
  270. ptr++;
  271. while ((ptr != string_limit) && (*ptr == ' ')) { ptr++; }
  272. var cl_R imagpart = read_real(flags_for_parts,ptr,string_limit,&end_of_part);
  273. if (end_of_part == ptr) goto not_complex_syntax;
  274. ptr = end_of_part;
  275. if (ptr == string_limit) goto not_complex_syntax;
  276. if (!(*ptr == ')')) goto not_complex_syntax;
  277. ptr++;
  278. at_end_of_parse(ptr);
  279. return complex(realpart,imagpart);
  280. }
  281. not_complex_syntax:
  282. bad_syntax:
  283. if (flags.syntax & syntax_maybe_bad) {
  284. ASSERT(end_of_parse);
  285. *end_of_parse = string;
  286. return 0; // dummy return
  287. }
  288. read_number_bad_syntax(string,string_limit);
  289. }
  290. static const cl_N read_complex_number_rest (const cl_read_flags& flags, const char * string_rest, const char * string, const char * string_limit, const char * * end_of_parse, const cl_R& x)
  291. {
  292. unused string;
  293. if ((flags.syntax & syntax_complex) && (flags.lsyntax & lsyntax_algebraic)) {
  294. // Finish reading the "+yi" part of "x+yi".
  295. // We allow "y" to begin with a '-'.
  296. // We also allow the '+' to be replaced by '-', but in this case
  297. // "y" may not begin with a '-'.
  298. // We also allow the syntax "xi" (implicit realpart = 0).
  299. var const char * ptr = string_rest;
  300. if (ptr == string_limit) goto not_complex_syntax;
  301. if ((*ptr == 'i') || (*ptr == 'I')) {
  302. ptr++;
  303. at_end_of_parse(ptr);
  304. return complex(0,x);
  305. }
  306. switch (*ptr) {
  307. case '+': ptr++;
  308. case '-': break;
  309. default: goto not_complex_syntax;
  310. }
  311. // Modified flags for parsing the imagpart:
  312. var cl_read_flags flags_for_part = flags;
  313. flags_for_part.syntax = (cl_read_syntax_t)((flags_for_part.syntax & ~syntax_complex) | syntax_maybe_bad);
  314. var const char * end_of_part;
  315. var const cl_R& realpart = x;
  316. var cl_R imagpart = read_real(flags_for_part,ptr,string_limit,&end_of_part);
  317. if (end_of_part == ptr) goto not_complex_syntax;
  318. ptr = end_of_part;
  319. if (ptr == string_limit) goto not_complex_syntax;
  320. if (!((*ptr == 'i') || (*ptr == 'I'))) goto not_complex_syntax;
  321. ptr++;
  322. at_end_of_parse(ptr);
  323. return complex(realpart,imagpart);
  324. }
  325. not_complex_syntax:
  326. at_end_of_parse(string_rest);
  327. return x;
  328. }