* complex.c (string_to_c_strict, string_to_c): rewrote without regexp.

* rational.c (string_to_r_strict, string_to_r): ditto.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37702 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
tadf 2012-11-17 15:19:55 +00:00
Родитель 20039668dd
Коммит 47fe9b79a3
3 изменённых файлов: 439 добавлений и 293 удалений

Просмотреть файл

@ -1,3 +1,8 @@
Sun Nov 18 00:14:46 2012 Tadayoshi Funaba <tadf@dotrb.org>
* complex.c (string_to_c_strict, string_to_c): rewrote without regexp.
* rational.c (string_to_r_strict, string_to_r): ditto.
Sat Nov 17 23:53:05 2012 Tadayoshi Funaba <tadf@dotrb.org>
* complex.c (make_patterns): should not accept extra sign.

375
complex.c
Просмотреть файл

@ -1496,159 +1496,263 @@ numeric_to_c(VALUE self)
return rb_complex_new1(self);
}
static VALUE comp_pat0, comp_pat1, comp_pat2, a_slash, a_dot_and_an_e,
null_string, underscores_pat, an_underscore;
#include <ctype.h>
#define WS "\\s*"
#define DIGITS "(?:[0-9](?:_[0-9]|[0-9])*)"
#define NUMERATOR "(?:" DIGITS "?\\.)?" DIGITS "(?:[eE][-+]?" DIGITS ")?"
#define DENOMINATOR DIGITS
#define NUMBER "[-+]?" NUMERATOR "(?:\\/" DENOMINATOR ")?"
#define NUMBERNOS NUMERATOR "(?:\\/" DENOMINATOR ")?"
#define PATTERN0 "\\A" WS "(" NUMBER ")@(" NUMBER ")" WS
#define PATTERN1 "\\A" WS "([-+])?(" NUMBERNOS ")?[iIjJ]" WS
#define PATTERN2 "\\A" WS "(" NUMBER ")(([-+])(" NUMBERNOS ")?[iIjJ])?" WS
static void
make_patterns(void)
static int
read_sign(const char **s,
char **b)
{
static const char comp_pat0_source[] = PATTERN0;
static const char comp_pat1_source[] = PATTERN1;
static const char comp_pat2_source[] = PATTERN2;
static const char underscores_pat_source[] = "_+";
int sign = '?';
if (comp_pat0) return;
comp_pat0 = rb_reg_new(comp_pat0_source, sizeof comp_pat0_source - 1, 0);
rb_gc_register_mark_object(comp_pat0);
comp_pat1 = rb_reg_new(comp_pat1_source, sizeof comp_pat1_source - 1, 0);
rb_gc_register_mark_object(comp_pat1);
comp_pat2 = rb_reg_new(comp_pat2_source, sizeof comp_pat2_source - 1, 0);
rb_gc_register_mark_object(comp_pat2);
a_slash = rb_usascii_str_new2("/");
rb_gc_register_mark_object(a_slash);
a_dot_and_an_e = rb_usascii_str_new2(".eE");
rb_gc_register_mark_object(a_dot_and_an_e);
null_string = rb_usascii_str_new2("");
rb_gc_register_mark_object(null_string);
underscores_pat = rb_reg_new(underscores_pat_source,
sizeof underscores_pat_source - 1, 0);
rb_gc_register_mark_object(underscores_pat);
an_underscore = rb_usascii_str_new2("_");
rb_gc_register_mark_object(an_underscore);
if (**s == '-' || **s == '+') {
sign = **b = **s;
(*s)++;
(*b)++;
}
return sign;
}
#define id_match rb_intern("match")
#define f_match(x,y) rb_funcall((x), id_match, 1, (y))
static int
read_digits(const char **s, int strict,
char **b)
{
int us = 1;
#define id_gsub_bang rb_intern("gsub!")
#define f_gsub_bang(x,y,z) rb_funcall((x), id_gsub_bang, 2, (y), (z))
if (!isdigit((unsigned char)**s))
return 0;
while (isdigit((unsigned char)**s) || **s == '_') {
if (**s == '_') {
if (strict) {
if (us)
return 0;
}
us = 1;
}
else {
**b = **s;
(*b)++;
us = 0;
}
(*s)++;
}
if (us)
do {
(*s)--;
} while (**s == '_');
return 1;
}
static int
read_num(const char **s, int strict,
char **b)
{
if (**s != '.') {
if (!read_digits(s, strict, b))
return 0;
}
if (**s == '.') {
**b = **s;
(*s)++;
(*b)++;
if (!read_digits(s, strict, b)) {
(*b)--;
return 0;
}
}
if (**s == 'e' || **s == 'E') {
**b = **s;
(*s)++;
(*b)++;
read_sign(s, b);
if (!read_digits(s, strict, b)) {
(*b)--;
return 0;
}
}
return 1;
}
static int
read_den(const char **s, int strict,
char **b)
{
if (!read_digits(s, strict, b))
return 0;
return 1;
}
static int
read_rat_nos(const char **s, int strict,
char **b)
{
if (!read_num(s, strict, b))
return 0;
if (**s == '/') {
**b = **s;
(*s)++;
(*b)++;
if (!read_den(s, strict, b)) {
(*b)--;
return 0;
}
}
return 1;
}
static int
read_rat(const char **s, int strict,
char **b)
{
read_sign(s, b);
if (!read_rat_nos(s, strict, b))
return 0;
return 1;
}
static int
isimagunit(int c)
{
return (c == 'i' || c == 'I' ||
c == 'j' || c == 'J');
}
VALUE rb_cstr_to_rat(const char *, int);
static VALUE
string_to_c_internal(VALUE self)
str2num(char *s)
{
VALUE s;
s = self;
if (RSTRING_LEN(s) == 0)
return rb_assoc_new(Qnil, self);
if (strchr(s, '/'))
return rb_cstr_to_rat(s, 0);
if (strpbrk(s, ".eE")) {
double d = rb_cstr_to_dbl(s, 0);
return DBL2NUM(d);
}
return rb_cstr_to_inum(s, 10, 0);
}
static int
read_comp(const char **s, int strict,
VALUE *ret, char **b)
{
VALUE m, sr, si, re, r, i;
int po;
char *bb;
int sign;
VALUE num, num2;
m = f_match(comp_pat0, s);
if (!NIL_P(m)) {
sr = rb_reg_nth_match(1, m);
si = rb_reg_nth_match(2, m);
re = rb_reg_match_post(m);
po = 1;
}
if (NIL_P(m)) {
m = f_match(comp_pat1, s);
if (!NIL_P(m)) {
sr = Qnil;
si = rb_reg_nth_match(1, m);
if (NIL_P(si))
si = rb_usascii_str_new2("");
{
VALUE t;
bb = *b;
t = rb_reg_nth_match(2, m);
if (NIL_P(t))
t = rb_usascii_str_new2("1");
rb_str_concat(si, t);
sign = read_sign(s, b);
if (isimagunit(**s)) {
(*s)++;
num = INT2FIX((sign == '-') ? -1 : + 1);
*ret = rb_complex_raw2(ZERO, num);
return 1; /* e.g. "i" */
}
re = rb_reg_match_post(m);
po = 0;
if (!read_rat_nos(s, strict, b)) {
**b = '\0';
num = str2num(bb);
*ret = rb_complex_raw2(num, ZERO);
return 0; /* e.g. "1/" */
}
**b = '\0';
num = str2num(bb);
if (isimagunit(**s)) {
(*s)++;
*ret = rb_complex_raw2(ZERO, num);
return 1; /* e.g. "3i" */
}
if (NIL_P(m)) {
m = f_match(comp_pat2, s);
if (NIL_P(m))
return rb_assoc_new(Qnil, self);
sr = rb_reg_nth_match(1, m);
if (NIL_P(rb_reg_nth_match(2, m)))
si = Qnil;
if (**s == '@') {
(*s)++;
bb = *b;
if (!read_rat(s, strict, b)) {
num = rb_complex_raw2(num, ZERO);
return 0; /* e.g. "1@x" */
}
**b = '\0';
num2 = str2num(bb);
*ret = rb_complex_polar(num, num2);
return 1; /* e.g. "1@2" */
}
if (**s == '-' || **s == '+') {
bb = *b;
sign = read_sign(s, b);
if (isimagunit(**s))
num2 = INT2FIX((sign == '-') ? -1 : + 1);
else {
VALUE t;
if (!read_rat_nos(s, strict, b)) {
*ret = rb_complex_raw2(num, ZERO);
return 0; /* e.g. "1+xi" */
}
**b = '\0';
num2 = str2num(bb);
}
if (!isimagunit(**s)) {
*ret = rb_complex_raw2(num, ZERO);
return 0; /* e.g. "1+3x" */
}
(*s)++;
*ret = rb_complex_raw2(num, num2);
return 1; /* e.g. "1+2i" */
}
/* !(@, - or +) */
{
*ret = rb_complex_raw2(num, ZERO);
return 1; /* e.g. "3" */
}
}
si = rb_reg_nth_match(3, m);
t = rb_reg_nth_match(4, m);
if (NIL_P(t))
t = rb_usascii_str_new2("1");
rb_str_concat(si, t);
}
re = rb_reg_match_post(m);
po = 0;
}
r = INT2FIX(0);
i = INT2FIX(0);
if (!NIL_P(sr)) {
if (strchr(RSTRING_PTR(sr), '/'))
r = f_to_r(sr);
else if (strpbrk(RSTRING_PTR(sr), ".eE"))
r = f_to_f(sr);
else
r = f_to_i(sr);
}
if (!NIL_P(si)) {
if (strchr(RSTRING_PTR(si), '/'))
i = f_to_r(si);
else if (strpbrk(RSTRING_PTR(si), ".eE"))
i = f_to_f(si);
else
i = f_to_i(si);
}
if (po)
return rb_assoc_new(rb_complex_polar(r, i), re);
else
return rb_assoc_new(rb_complex_new2(r, i), re);
}
static int
parse_comp(const char *s, int strict,
VALUE *num)
{
char *buf, *b;
buf = ALLOCA_N(char, strlen(s) + 1);
b = buf;
while (isspace((unsigned char)*s))
s++;
if (!read_comp(&s, strict, num, &b))
return 0;
while (isspace((unsigned char)*s))
s++;
if (strict)
if (*s != '\0')
return 0;
return 1;
}
static VALUE
string_to_c_strict(VALUE self)
{
VALUE a = string_to_c_internal(self);
if (NIL_P(RARRAY_PTR(a)[0]) || RSTRING_LEN(RARRAY_PTR(a)[1]) > 0) {
VALUE s = f_inspect(self);
const char *s;
VALUE num;
rb_must_asciicompat(self);
s = RSTRING_PTR(self);
if (memchr(s, 0, RSTRING_LEN(self)))
rb_raise(rb_eArgError, "string contains null byte");
if (!parse_comp(s, 1, &num)) {
VALUE ins = f_inspect(self);
rb_raise(rb_eArgError, "invalid value for convert(): %s",
StringValuePtr(s));
}
return RARRAY_PTR(a)[0];
StringValuePtr(ins));
}
#define id_gsub rb_intern("gsub")
#define f_gsub(x,y,z) rb_funcall((x), id_gsub, 2, (y), (z))
return num;
}
/*
* call-seq:
@ -1674,19 +1778,16 @@ string_to_c_strict(VALUE self)
static VALUE
string_to_c(VALUE self)
{
VALUE s, a, backref;
const char *s;
VALUE num;
backref = rb_backref_get();
rb_match_busy(backref);
rb_must_asciicompat(self);
s = f_gsub(self, underscores_pat, an_underscore);
a = string_to_c_internal(s);
s = RSTRING_PTR(self);
rb_backref_set(backref);
(void)parse_comp(s, 0, &num);
if (!NIL_P(RARRAY_PTR(a)[0]))
return RARRAY_PTR(a)[0];
return rb_complex_new1(INT2FIX(0));
return num;
}
static VALUE
@ -2054,8 +2155,6 @@ Init_Complex(void)
rb_define_method(rb_cNilClass, "to_c", nilclass_to_c, 0);
rb_define_method(rb_cNumeric, "to_c", numeric_to_c, 0);
make_patterns();
rb_define_method(rb_cString, "to_c", string_to_c, 0);
rb_define_private_method(CLASS_OF(rb_cComplex), "convert", nucomp_s_convert, -1);

Просмотреть файл

@ -1956,145 +1956,185 @@ float_rationalize(int argc, VALUE *argv, VALUE self)
return rb_rational_new2(p, q);
}
static VALUE rat_pat, an_e_pat, a_dot_pat, underscores_pat, an_underscore;
#define WS "\\s*"
#define DIGITS "(?:[0-9](?:_[0-9]|[0-9])*)"
#define NUMERATOR "(?:" DIGITS "?\\.)?" DIGITS "(?:[eE][-+]?" DIGITS ")?"
#define DENOMINATOR DIGITS
#define PATTERN "\\A" WS "([-+])?(" NUMERATOR ")(?:\\/(" DENOMINATOR "))?" WS
static void
make_patterns(void)
{
static const char rat_pat_source[] = PATTERN;
static const char an_e_pat_source[] = "[eE]";
static const char a_dot_pat_source[] = "\\.";
static const char underscores_pat_source[] = "_+";
if (rat_pat) return;
rat_pat = rb_reg_new(rat_pat_source, sizeof rat_pat_source - 1, 0);
rb_gc_register_mark_object(rat_pat);
an_e_pat = rb_reg_new(an_e_pat_source, sizeof an_e_pat_source - 1, 0);
rb_gc_register_mark_object(an_e_pat);
a_dot_pat = rb_reg_new(a_dot_pat_source, sizeof a_dot_pat_source - 1, 0);
rb_gc_register_mark_object(a_dot_pat);
underscores_pat = rb_reg_new(underscores_pat_source,
sizeof underscores_pat_source - 1, 0);
rb_gc_register_mark_object(underscores_pat);
an_underscore = rb_usascii_str_new2("_");
rb_gc_register_mark_object(an_underscore);
}
#define id_match rb_intern("match")
#define f_match(x,y) rb_funcall((x), id_match, 1, (y))
#define id_split rb_intern("split")
#define f_split(x,y) rb_funcall((x), id_split, 1, (y))
#include <ctype.h>
static VALUE
string_to_r_internal(VALUE self)
static int
read_sign(const char **s)
{
VALUE s, m;
int sign = '?';
s = self;
if (RSTRING_LEN(s) == 0)
return rb_assoc_new(Qnil, self);
m = f_match(rat_pat, s);
if (!NIL_P(m)) {
VALUE v, ifp, exp, ip, fp;
VALUE si = rb_reg_nth_match(1, m);
VALUE nu = rb_reg_nth_match(2, m);
VALUE de = rb_reg_nth_match(3, m);
VALUE re = rb_reg_match_post(m);
if (**s == '-' || **s == '+') {
sign = **s;
(*s)++;
}
return sign;
}
static int
read_digits(const char **s, int strict,
VALUE *num, int *count)
{
VALUE a;
int us = 1;
if (!strpbrk(RSTRING_PTR(nu), "eE")) {
ifp = nu; /* not a copy */
exp = Qnil;
if (!isdigit((unsigned char)**s))
return 0;
*num = ZERO;
while (isdigit((unsigned char)**s) || **s == '_') {
if (**s == '_') {
if (strict) {
if (us)
return 0;
}
us = 1;
}
else {
a = f_split(nu, an_e_pat);
ifp = RARRAY_PTR(a)[0];
if (RARRAY_LEN(a) != 2)
*num = f_mul(*num, INT2FIX(10));
*num = f_add(*num, INT2FIX(**s - '0'));
if (count)
(*count)++;
us = 0;
}
(*s)++;
}
if (us)
do {
(*s)--;
} while (**s == '_');
return 1;
}
static int
read_num(const char **s, int numsign, int strict,
VALUE *num)
{
VALUE ip, fp, exp;
*num = rb_rational_raw2(ZERO, ONE);
exp = Qnil;
else
exp = RARRAY_PTR(a)[1];
if (**s != '.') {
if (!read_digits(s, strict, &ip, NULL))
return 0;
*num = rb_rational_raw2(ip, ONE);
}
if (!strchr(RSTRING_PTR(ifp), '.')) {
ip = ifp; /* not a copy */
fp = Qnil;
}
else {
a = f_split(ifp, a_dot_pat);
ip = RARRAY_PTR(a)[0];
if (RARRAY_LEN(a) != 2)
fp = Qnil;
else
fp = RARRAY_PTR(a)[1];
if (**s == '.') {
int count = 0;
(*s)++;
if (!read_digits(s, strict, &fp, &count))
return 0;
{
VALUE l = f_expt10(INT2NUM(count));
*num = f_mul(*num, l);
*num = f_add(*num, fp);
*num = f_div(*num, l);
}
}
v = rb_rational_new1(f_to_i(ip));
if (**s == 'e' || **s == 'E') {
int expsign;
if (!NIL_P(fp)) {
char *p = RSTRING_PTR(fp);
long count = 0;
VALUE l;
(*s)++;
expsign = read_sign(s);
if (!read_digits(s, strict, &exp, NULL))
return 0;
if (expsign == '-')
exp = f_negate(exp);
}
while (*p) {
if (rb_isdigit(*p))
count++;
p++;
if (numsign == '-')
*num = f_negate(*num);
if (!NIL_P(exp)) {
VALUE l = f_expt10(exp);
*num = f_mul(*num, l);
}
l = f_expt10(LONG2NUM(count));
v = f_mul(v, l);
v = f_add(v, f_to_i(fp));
v = f_div(v, l);
return 1;
}
if (!NIL_P(si) && *RSTRING_PTR(si) == '-')
v = f_negate(v);
if (!NIL_P(exp))
v = f_mul(v, f_expt10(f_to_i(exp)));
#if 0
if (!NIL_P(de) && (!NIL_P(fp) || !NIL_P(exp)))
return rb_assoc_new(v, rb_usascii_str_new2("dummy"));
#endif
if (!NIL_P(de))
v = f_div(v, f_to_i(de));
return rb_assoc_new(v, re);
static int
read_den(const char **s, int strict,
VALUE *num)
{
if (!read_digits(s, strict, num, NULL))
return 0;
return 1;
}
return rb_assoc_new(Qnil, self);
static int
read_rat_nos(const char **s, int sign, int strict,
VALUE *num)
{
VALUE den;
if (!read_num(s, sign, strict, num))
return 0;
if (**s == '/') {
(*s)++;
if (!read_den(s, strict, &den))
return 0;
if (!(FIXNUM_P(den) && FIX2LONG(den) == 1))
*num = f_div(*num, den);
}
return 1;
}
static int
read_rat(const char **s, int strict,
VALUE *num)
{
int sign;
sign = read_sign(s);
if (!read_rat_nos(s, sign, strict, num))
return 0;
return 1;
}
static int
parse_rat(const char *s, int strict,
VALUE *num)
{
while (isspace((unsigned char)*s))
s++;
if (!read_rat(&s, strict, num))
return 0;
while (isspace((unsigned char)*s))
s++;
if (strict)
if (*s != '\0')
return 0;
return 1;
}
static VALUE
string_to_r_strict(VALUE self)
{
VALUE a = string_to_r_internal(self);
if (NIL_P(RARRAY_PTR(a)[0]) || RSTRING_LEN(RARRAY_PTR(a)[1]) > 0) {
VALUE s = f_inspect(self);
const char *s;
VALUE num;
rb_must_asciicompat(self);
s = RSTRING_PTR(self);
if (memchr(s, 0, RSTRING_LEN(self)))
rb_raise(rb_eArgError, "string contains null byte");
if (!parse_rat(s, 1, &num)) {
VALUE ins = f_inspect(self);
rb_raise(rb_eArgError, "invalid value for convert(): %s",
StringValuePtr(s));
}
return RARRAY_PTR(a)[0];
StringValuePtr(ins));
}
#define id_gsub rb_intern("gsub")
#define f_gsub(x,y,z) rb_funcall((x), id_gsub, 2, (y), (z))
if (RB_TYPE_P(num, T_FLOAT))
rb_raise(rb_eFloatDomainError, "Infinity");
return num;
}
/*
* call-seq:
@ -2120,27 +2160,31 @@ string_to_r_strict(VALUE self)
static VALUE
string_to_r(VALUE self)
{
VALUE s, a, a1, backref;
const char *s;
VALUE num;
backref = rb_backref_get();
rb_match_busy(backref);
rb_must_asciicompat(self);
s = f_gsub(self, underscores_pat, an_underscore);
a = string_to_r_internal(s);
s = RSTRING_PTR(self);
rb_backref_set(backref);
(void)parse_rat(s, 0, &num);
a1 = RARRAY_PTR(a)[0];
if (!NIL_P(a1)) {
if (RB_TYPE_P(a1, T_FLOAT))
if (RB_TYPE_P(num, T_FLOAT))
rb_raise(rb_eFloatDomainError, "Infinity");
return a1;
}
return rb_rational_new1(INT2FIX(0));
return num;
}
#define id_to_r rb_intern("to_r")
#define f_to_r(x) rb_funcall((x), id_to_r, 0)
VALUE
rb_cstr_to_rat(const char *s, int strict) /* for complex's internal */
{
VALUE num;
(void)parse_rat(s, strict, &num);
if (RB_TYPE_P(num, T_FLOAT))
rb_raise(rb_eFloatDomainError, "Infinity");
return num;
}
static VALUE
nurat_s_convert(int argc, VALUE *argv, VALUE klass)
@ -2369,8 +2413,6 @@ Init_Rational(void)
rb_define_method(rb_cFloat, "to_r", float_to_r, 0);
rb_define_method(rb_cFloat, "rationalize", float_rationalize, -1);
make_patterns();
rb_define_method(rb_cString, "to_r", string_to_r, 0);
rb_define_private_method(CLASS_OF(rb_cRational), "convert", nurat_s_convert, -1);