PageRenderTime 54ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/cln-1.3.2/src/rational/input/cl_RA_read.cc

#
C++ | 153 lines | 129 code | 10 blank | 14 comment | 112 complexity | 12b8b7669d710c4cd8177de6311191d7 MD5 | raw file
Possible License(s): GPL-2.0
  1. // read_rational().
  2. // This file contains a slimmed down version of read_real().
  3. // It does not pull in all the floating-point, complex and transcendental
  4. // function code.
  5. // General includes.
  6. #include "base/cl_sysdep.h"
  7. // Specification.
  8. #include "cln/rational_io.h"
  9. // Implementation.
  10. #include <cstring>
  11. #include <sstream>
  12. #include "cln/input.h"
  13. #include "cln/integer.h"
  14. #include "cln/integer_io.h"
  15. #include "integer/cl_I.h"
  16. #include "cln/exception.h"
  17. namespace cln {
  18. // Step forward over all digits, to the end of string or to the next non-digit.
  19. static const char * skip_digits (const char * ptr, const char * string_limit, unsigned int base)
  20. {
  21. for ( ; ptr != string_limit; ptr++) {
  22. var char ch = *ptr;
  23. if ((ch >= '0') && (ch <= '9'))
  24. if (ch < '0' + (int)base)
  25. continue;
  26. else
  27. break;
  28. else {
  29. if (base <= 10)
  30. break;
  31. if (((ch >= 'A') && (ch < 'A'-10+(int)base))
  32. || ((ch >= 'a') && (ch < 'a'-10+(int)base))
  33. )
  34. continue;
  35. else
  36. break;
  37. }
  38. }
  39. return ptr;
  40. }
  41. #define at_end_of_parse(ptr) \
  42. if (end_of_parse) \
  43. { *end_of_parse = (ptr); } \
  44. else \
  45. { if ((ptr) != string_limit) { throw read_number_junk_exception((ptr),string,string_limit); } }
  46. const cl_RA read_rational (const cl_read_flags& flags, const char * string, const char * string_limit, const char * * end_of_parse)
  47. {
  48. ASSERT((flags.syntax & ~(syntax_rational|syntax_maybe_bad)) == 0);
  49. // If no string_limit is given, it defaults to the end of the string.
  50. if (!string_limit)
  51. string_limit = string + ::strlen(string);
  52. if (flags.syntax & syntax_rational) {
  53. // Check for rational number syntax.
  54. var unsigned int rational_base = flags.rational_base;
  55. var const char * ptr = string;
  56. if (flags.lsyntax & lsyntax_commonlisp) {
  57. if (ptr == string_limit) goto not_rational_syntax;
  58. if (*ptr == '#') {
  59. // Check for #b, #o, #x, #nR syntax.
  60. ptr++;
  61. if (ptr == string_limit) goto not_rational_syntax;
  62. switch (*ptr) {
  63. case 'b': case 'B':
  64. rational_base = 2; break;
  65. case 'o': case 'O':
  66. rational_base = 8; break;
  67. case 'x': case 'X':
  68. rational_base = 16; break;
  69. default:
  70. var const char * base_end_ptr =
  71. skip_digits(ptr,string_limit,10);
  72. if (base_end_ptr == ptr) goto not_rational_syntax;
  73. if (base_end_ptr == string_limit) goto not_rational_syntax;
  74. if (!((*base_end_ptr == 'r') || (*base_end_ptr == 'R')))
  75. goto not_rational_syntax;
  76. var cl_I base = read_integer(10,0,ptr,0,base_end_ptr-ptr);
  77. if (!((base >= 2) && (base <= 36))) {
  78. std::ostringstream buf;
  79. fprint(buf, "Base must be an integer in the range from 2 to 36, not ");
  80. fprint(buf, base);
  81. throw runtime_exception(buf.str());
  82. }
  83. rational_base = FN_to_UV(base); ptr = base_end_ptr;
  84. break;
  85. }
  86. ptr++;
  87. }
  88. }
  89. var const char * ptr_after_prefix = ptr;
  90. var cl_signean sign = 0;
  91. if (ptr == string_limit) goto not_rational_syntax;
  92. switch (*ptr) {
  93. case '-': sign = ~sign;
  94. case '+': ptr++;
  95. default: break;
  96. }
  97. var const char * ptr_after_sign = ptr;
  98. if (flags.syntax & syntax_integer) {
  99. // Check for integer syntax: {'+'|'-'|} {digit}+ {'.'|}
  100. // Allow final dot only in Common Lisp syntax if there was no #<base> prefix.
  101. if ((flags.lsyntax & lsyntax_commonlisp) && (ptr_after_prefix == string)) {
  102. ptr = skip_digits(ptr_after_sign,string_limit,10);
  103. if (ptr != ptr_after_sign)
  104. if (ptr != string_limit)
  105. if (*ptr == '.') {
  106. ptr++;
  107. if ((ptr == string_limit) || !(((*ptr >= '0') && (*ptr <= '9')) || ((*ptr >= 'A') && (*ptr <= 'Z') && (*ptr != 'I')) || ((*ptr >= 'a') && (*ptr <= 'z') && (*ptr != 'i')) || (*ptr == '.') || (*ptr == '_') || (*ptr == '/'))) {
  108. at_end_of_parse(ptr);
  109. return read_integer(10,sign,ptr_after_sign,0,ptr-ptr_after_sign);
  110. }
  111. }
  112. }
  113. ptr = skip_digits(ptr_after_sign,string_limit,rational_base);
  114. if ((ptr == string_limit) || !(((*ptr >= '0') && (*ptr <= '9')) || ((*ptr >= 'A') && (*ptr <= 'Z') && (*ptr != 'I')) || ((*ptr >= 'a') && (*ptr <= 'z') && (*ptr != 'i')) || (*ptr == '.') || (*ptr == '_') || (*ptr == '/'))) {
  115. at_end_of_parse(ptr);
  116. return read_integer(rational_base,sign,ptr_after_sign,0,ptr-ptr_after_sign);
  117. }
  118. }
  119. if (flags.syntax & syntax_ratio) {
  120. // Check for ratio syntax: {'+'|'-'|} {digit}+ '/' {digit}+
  121. ptr = skip_digits(ptr_after_sign,string_limit,rational_base);
  122. if (ptr != ptr_after_sign)
  123. if (ptr != string_limit)
  124. if (*ptr == '/') {
  125. var const char * ptr_at_slash = ptr;
  126. ptr = skip_digits(ptr_at_slash+1,string_limit,rational_base);
  127. if (ptr != ptr_at_slash+1)
  128. if ((ptr == string_limit) || !(((*ptr >= '0') && (*ptr <= '9')) || ((*ptr >= 'A') && (*ptr <= 'Z') && (*ptr != 'I')) || ((*ptr >= 'a') && (*ptr <= 'z') && (*ptr != 'i')) || (*ptr == '.') || (*ptr == '_') || (*ptr == '/'))) {
  129. at_end_of_parse(ptr);
  130. return read_rational(rational_base,sign,ptr_after_sign,0,ptr_at_slash-ptr_after_sign,ptr-ptr_after_sign);
  131. }
  132. }
  133. }
  134. }
  135. not_rational_syntax:
  136. if (flags.syntax & syntax_maybe_bad) {
  137. ASSERT(end_of_parse);
  138. *end_of_parse = string;
  139. return 0; // dummy return
  140. }
  141. throw read_number_bad_syntax_exception(string,string_limit);
  142. }
  143. } // namespace cln