зеркало из https://github.com/github/ruby.git
parse.y: parse_numeric
* parse.y (parse_numeric): extract from parser_yylex(). git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@46842 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
88d4f46f5e
Коммит
5000ed38f4
480
parse.y
480
parse.y
|
@ -6938,6 +6938,245 @@ parser_prepare(struct parser_params *parser)
|
|||
space_seen && !ISSPACE(c) && \
|
||||
(ambiguous_operator(op, syn), 0)))
|
||||
|
||||
static int
|
||||
parse_numeric(struct parser_params *parser, int c)
|
||||
{
|
||||
int is_float, seen_point, seen_e, nondigit;
|
||||
int suffix;
|
||||
|
||||
is_float = seen_point = seen_e = nondigit = 0;
|
||||
lex_state = EXPR_END;
|
||||
newtok();
|
||||
if (c == '-' || c == '+') {
|
||||
tokadd(c);
|
||||
c = nextc();
|
||||
}
|
||||
if (c == '0') {
|
||||
#define no_digits() do {yyerror("numeric literal without digits"); return 0;} while (0)
|
||||
int start = toklen();
|
||||
c = nextc();
|
||||
if (c == 'x' || c == 'X') {
|
||||
/* hexadecimal */
|
||||
c = nextc();
|
||||
if (c != -1 && ISXDIGIT(c)) {
|
||||
do {
|
||||
if (c == '_') {
|
||||
if (nondigit) break;
|
||||
nondigit = c;
|
||||
continue;
|
||||
}
|
||||
if (!ISXDIGIT(c)) break;
|
||||
nondigit = 0;
|
||||
tokadd(c);
|
||||
} while ((c = nextc()) != -1);
|
||||
}
|
||||
pushback(c);
|
||||
tokfix();
|
||||
if (toklen() == start) {
|
||||
no_digits();
|
||||
}
|
||||
else if (nondigit) goto trailing_uc;
|
||||
suffix = number_literal_suffix(NUM_SUFFIX_ALL);
|
||||
return set_integer_literal(rb_cstr_to_inum(tok(), 16, FALSE), suffix);
|
||||
}
|
||||
if (c == 'b' || c == 'B') {
|
||||
/* binary */
|
||||
c = nextc();
|
||||
if (c == '0' || c == '1') {
|
||||
do {
|
||||
if (c == '_') {
|
||||
if (nondigit) break;
|
||||
nondigit = c;
|
||||
continue;
|
||||
}
|
||||
if (c != '0' && c != '1') break;
|
||||
nondigit = 0;
|
||||
tokadd(c);
|
||||
} while ((c = nextc()) != -1);
|
||||
}
|
||||
pushback(c);
|
||||
tokfix();
|
||||
if (toklen() == start) {
|
||||
no_digits();
|
||||
}
|
||||
else if (nondigit) goto trailing_uc;
|
||||
suffix = number_literal_suffix(NUM_SUFFIX_ALL);
|
||||
return set_integer_literal(rb_cstr_to_inum(tok(), 2, FALSE), suffix);
|
||||
}
|
||||
if (c == 'd' || c == 'D') {
|
||||
/* decimal */
|
||||
c = nextc();
|
||||
if (c != -1 && ISDIGIT(c)) {
|
||||
do {
|
||||
if (c == '_') {
|
||||
if (nondigit) break;
|
||||
nondigit = c;
|
||||
continue;
|
||||
}
|
||||
if (!ISDIGIT(c)) break;
|
||||
nondigit = 0;
|
||||
tokadd(c);
|
||||
} while ((c = nextc()) != -1);
|
||||
}
|
||||
pushback(c);
|
||||
tokfix();
|
||||
if (toklen() == start) {
|
||||
no_digits();
|
||||
}
|
||||
else if (nondigit) goto trailing_uc;
|
||||
suffix = number_literal_suffix(NUM_SUFFIX_ALL);
|
||||
return set_integer_literal(rb_cstr_to_inum(tok(), 10, FALSE), suffix);
|
||||
}
|
||||
if (c == '_') {
|
||||
/* 0_0 */
|
||||
goto octal_number;
|
||||
}
|
||||
if (c == 'o' || c == 'O') {
|
||||
/* prefixed octal */
|
||||
c = nextc();
|
||||
if (c == -1 || c == '_' || !ISDIGIT(c)) {
|
||||
no_digits();
|
||||
}
|
||||
}
|
||||
if (c >= '0' && c <= '7') {
|
||||
/* octal */
|
||||
octal_number:
|
||||
do {
|
||||
if (c == '_') {
|
||||
if (nondigit) break;
|
||||
nondigit = c;
|
||||
continue;
|
||||
}
|
||||
if (c < '0' || c > '9') break;
|
||||
if (c > '7') goto invalid_octal;
|
||||
nondigit = 0;
|
||||
tokadd(c);
|
||||
} while ((c = nextc()) != -1);
|
||||
if (toklen() > start) {
|
||||
pushback(c);
|
||||
tokfix();
|
||||
if (nondigit) goto trailing_uc;
|
||||
suffix = number_literal_suffix(NUM_SUFFIX_ALL);
|
||||
return set_integer_literal(rb_cstr_to_inum(tok(), 8, FALSE), suffix);
|
||||
}
|
||||
if (nondigit) {
|
||||
pushback(c);
|
||||
goto trailing_uc;
|
||||
}
|
||||
}
|
||||
if (c > '7' && c <= '9') {
|
||||
invalid_octal:
|
||||
yyerror("Invalid octal digit");
|
||||
}
|
||||
else if (c == '.' || c == 'e' || c == 'E') {
|
||||
tokadd('0');
|
||||
}
|
||||
else {
|
||||
pushback(c);
|
||||
suffix = number_literal_suffix(NUM_SUFFIX_ALL);
|
||||
return set_integer_literal(INT2FIX(0), suffix);
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
switch (c) {
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
nondigit = 0;
|
||||
tokadd(c);
|
||||
break;
|
||||
|
||||
case '.':
|
||||
if (nondigit) goto trailing_uc;
|
||||
if (seen_point || seen_e) {
|
||||
goto decode_num;
|
||||
}
|
||||
else {
|
||||
int c0 = nextc();
|
||||
if (c0 == -1 || !ISDIGIT(c0)) {
|
||||
pushback(c0);
|
||||
goto decode_num;
|
||||
}
|
||||
c = c0;
|
||||
}
|
||||
seen_point = toklen();
|
||||
tokadd('.');
|
||||
tokadd(c);
|
||||
is_float++;
|
||||
nondigit = 0;
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
case 'E':
|
||||
if (nondigit) {
|
||||
pushback(c);
|
||||
c = nondigit;
|
||||
goto decode_num;
|
||||
}
|
||||
if (seen_e) {
|
||||
goto decode_num;
|
||||
}
|
||||
nondigit = c;
|
||||
c = nextc();
|
||||
if (c != '-' && c != '+' && !ISDIGIT(c)) {
|
||||
pushback(c);
|
||||
nondigit = 0;
|
||||
goto decode_num;
|
||||
}
|
||||
tokadd(nondigit);
|
||||
seen_e++;
|
||||
is_float++;
|
||||
tokadd(c);
|
||||
nondigit = (c == '-' || c == '+') ? c : 0;
|
||||
break;
|
||||
|
||||
case '_': /* `_' in number just ignored */
|
||||
if (nondigit) goto decode_num;
|
||||
nondigit = c;
|
||||
break;
|
||||
|
||||
default:
|
||||
goto decode_num;
|
||||
}
|
||||
c = nextc();
|
||||
}
|
||||
|
||||
decode_num:
|
||||
pushback(c);
|
||||
if (nondigit) {
|
||||
char tmp[30];
|
||||
trailing_uc:
|
||||
snprintf(tmp, sizeof(tmp), "trailing `%c' in number", nondigit);
|
||||
yyerror(tmp);
|
||||
}
|
||||
tokfix();
|
||||
if (is_float) {
|
||||
int type = tFLOAT;
|
||||
VALUE v;
|
||||
|
||||
suffix = number_literal_suffix(seen_e ? NUM_SUFFIX_I : NUM_SUFFIX_ALL);
|
||||
if (suffix & NUM_SUFFIX_R) {
|
||||
char *point = &tok()[seen_point];
|
||||
size_t fraclen = toklen()-seen_point-1;
|
||||
type = tRATIONAL;
|
||||
memmove(point, point+1, fraclen+1);
|
||||
v = rb_cstr_to_inum(tok(), 10, FALSE);
|
||||
v = rb_rational_new(v, rb_int_positive_pow(10, fraclen));
|
||||
}
|
||||
else {
|
||||
double d = strtod(tok(), 0);
|
||||
if (errno == ERANGE) {
|
||||
rb_warningS("Float %s out of range", tok());
|
||||
errno = 0;
|
||||
}
|
||||
v = DBL2NUM(d);
|
||||
}
|
||||
return set_number_literal(v, type, suffix);
|
||||
}
|
||||
suffix = number_literal_suffix(NUM_SUFFIX_ALL);
|
||||
return set_integer_literal(rb_cstr_to_inum(tok(), 10, FALSE), suffix);
|
||||
}
|
||||
|
||||
static int
|
||||
parser_yylex(struct parser_params *parser)
|
||||
{
|
||||
|
@ -7401,8 +7640,7 @@ parser_yylex(struct parser_params *parser)
|
|||
lex_state = EXPR_BEG;
|
||||
pushback(c);
|
||||
if (c != -1 && ISDIGIT(c)) {
|
||||
c = '+';
|
||||
goto start_num;
|
||||
return parse_numeric(parser, '+');
|
||||
}
|
||||
return tUPLUS;
|
||||
}
|
||||
|
@ -7459,245 +7697,9 @@ parser_yylex(struct parser_params *parser)
|
|||
lex_state = EXPR_DOT;
|
||||
return '.';
|
||||
|
||||
start_num:
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
{
|
||||
int is_float, seen_point, seen_e, nondigit;
|
||||
int suffix;
|
||||
|
||||
is_float = seen_point = seen_e = nondigit = 0;
|
||||
lex_state = EXPR_END;
|
||||
newtok();
|
||||
if (c == '-' || c == '+') {
|
||||
tokadd(c);
|
||||
c = nextc();
|
||||
}
|
||||
if (c == '0') {
|
||||
#define no_digits() do {yyerror("numeric literal without digits"); return 0;} while (0)
|
||||
int start = toklen();
|
||||
c = nextc();
|
||||
if (c == 'x' || c == 'X') {
|
||||
/* hexadecimal */
|
||||
c = nextc();
|
||||
if (c != -1 && ISXDIGIT(c)) {
|
||||
do {
|
||||
if (c == '_') {
|
||||
if (nondigit) break;
|
||||
nondigit = c;
|
||||
continue;
|
||||
}
|
||||
if (!ISXDIGIT(c)) break;
|
||||
nondigit = 0;
|
||||
tokadd(c);
|
||||
} while ((c = nextc()) != -1);
|
||||
}
|
||||
pushback(c);
|
||||
tokfix();
|
||||
if (toklen() == start) {
|
||||
no_digits();
|
||||
}
|
||||
else if (nondigit) goto trailing_uc;
|
||||
suffix = number_literal_suffix(NUM_SUFFIX_ALL);
|
||||
return set_integer_literal(rb_cstr_to_inum(tok(), 16, FALSE), suffix);
|
||||
}
|
||||
if (c == 'b' || c == 'B') {
|
||||
/* binary */
|
||||
c = nextc();
|
||||
if (c == '0' || c == '1') {
|
||||
do {
|
||||
if (c == '_') {
|
||||
if (nondigit) break;
|
||||
nondigit = c;
|
||||
continue;
|
||||
}
|
||||
if (c != '0' && c != '1') break;
|
||||
nondigit = 0;
|
||||
tokadd(c);
|
||||
} while ((c = nextc()) != -1);
|
||||
}
|
||||
pushback(c);
|
||||
tokfix();
|
||||
if (toklen() == start) {
|
||||
no_digits();
|
||||
}
|
||||
else if (nondigit) goto trailing_uc;
|
||||
suffix = number_literal_suffix(NUM_SUFFIX_ALL);
|
||||
return set_integer_literal(rb_cstr_to_inum(tok(), 2, FALSE), suffix);
|
||||
}
|
||||
if (c == 'd' || c == 'D') {
|
||||
/* decimal */
|
||||
c = nextc();
|
||||
if (c != -1 && ISDIGIT(c)) {
|
||||
do {
|
||||
if (c == '_') {
|
||||
if (nondigit) break;
|
||||
nondigit = c;
|
||||
continue;
|
||||
}
|
||||
if (!ISDIGIT(c)) break;
|
||||
nondigit = 0;
|
||||
tokadd(c);
|
||||
} while ((c = nextc()) != -1);
|
||||
}
|
||||
pushback(c);
|
||||
tokfix();
|
||||
if (toklen() == start) {
|
||||
no_digits();
|
||||
}
|
||||
else if (nondigit) goto trailing_uc;
|
||||
suffix = number_literal_suffix(NUM_SUFFIX_ALL);
|
||||
return set_integer_literal(rb_cstr_to_inum(tok(), 10, FALSE), suffix);
|
||||
}
|
||||
if (c == '_') {
|
||||
/* 0_0 */
|
||||
goto octal_number;
|
||||
}
|
||||
if (c == 'o' || c == 'O') {
|
||||
/* prefixed octal */
|
||||
c = nextc();
|
||||
if (c == -1 || c == '_' || !ISDIGIT(c)) {
|
||||
no_digits();
|
||||
}
|
||||
}
|
||||
if (c >= '0' && c <= '7') {
|
||||
/* octal */
|
||||
octal_number:
|
||||
do {
|
||||
if (c == '_') {
|
||||
if (nondigit) break;
|
||||
nondigit = c;
|
||||
continue;
|
||||
}
|
||||
if (c < '0' || c > '9') break;
|
||||
if (c > '7') goto invalid_octal;
|
||||
nondigit = 0;
|
||||
tokadd(c);
|
||||
} while ((c = nextc()) != -1);
|
||||
if (toklen() > start) {
|
||||
pushback(c);
|
||||
tokfix();
|
||||
if (nondigit) goto trailing_uc;
|
||||
suffix = number_literal_suffix(NUM_SUFFIX_ALL);
|
||||
return set_integer_literal(rb_cstr_to_inum(tok(), 8, FALSE), suffix);
|
||||
}
|
||||
if (nondigit) {
|
||||
pushback(c);
|
||||
goto trailing_uc;
|
||||
}
|
||||
}
|
||||
if (c > '7' && c <= '9') {
|
||||
invalid_octal:
|
||||
yyerror("Invalid octal digit");
|
||||
}
|
||||
else if (c == '.' || c == 'e' || c == 'E') {
|
||||
tokadd('0');
|
||||
}
|
||||
else {
|
||||
pushback(c);
|
||||
suffix = number_literal_suffix(NUM_SUFFIX_ALL);
|
||||
return set_integer_literal(INT2FIX(0), suffix);
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
switch (c) {
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
nondigit = 0;
|
||||
tokadd(c);
|
||||
break;
|
||||
|
||||
case '.':
|
||||
if (nondigit) goto trailing_uc;
|
||||
if (seen_point || seen_e) {
|
||||
goto decode_num;
|
||||
}
|
||||
else {
|
||||
int c0 = nextc();
|
||||
if (c0 == -1 || !ISDIGIT(c0)) {
|
||||
pushback(c0);
|
||||
goto decode_num;
|
||||
}
|
||||
c = c0;
|
||||
}
|
||||
seen_point = toklen();
|
||||
tokadd('.');
|
||||
tokadd(c);
|
||||
is_float++;
|
||||
nondigit = 0;
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
case 'E':
|
||||
if (nondigit) {
|
||||
pushback(c);
|
||||
c = nondigit;
|
||||
goto decode_num;
|
||||
}
|
||||
if (seen_e) {
|
||||
goto decode_num;
|
||||
}
|
||||
nondigit = c;
|
||||
c = nextc();
|
||||
if (c != '-' && c != '+' && !ISDIGIT(c)) {
|
||||
pushback(c);
|
||||
nondigit = 0;
|
||||
goto decode_num;
|
||||
}
|
||||
tokadd(nondigit);
|
||||
seen_e++;
|
||||
is_float++;
|
||||
tokadd(c);
|
||||
nondigit = (c == '-' || c == '+') ? c : 0;
|
||||
break;
|
||||
|
||||
case '_': /* `_' in number just ignored */
|
||||
if (nondigit) goto decode_num;
|
||||
nondigit = c;
|
||||
break;
|
||||
|
||||
default:
|
||||
goto decode_num;
|
||||
}
|
||||
c = nextc();
|
||||
}
|
||||
|
||||
decode_num:
|
||||
pushback(c);
|
||||
if (nondigit) {
|
||||
char tmp[30];
|
||||
trailing_uc:
|
||||
snprintf(tmp, sizeof(tmp), "trailing `%c' in number", nondigit);
|
||||
yyerror(tmp);
|
||||
}
|
||||
tokfix();
|
||||
if (is_float) {
|
||||
int type = tFLOAT;
|
||||
VALUE v;
|
||||
|
||||
suffix = number_literal_suffix(seen_e ? NUM_SUFFIX_I : NUM_SUFFIX_ALL);
|
||||
if (suffix & NUM_SUFFIX_R) {
|
||||
char *point = &tok()[seen_point];
|
||||
size_t fraclen = toklen()-seen_point-1;
|
||||
type = tRATIONAL;
|
||||
memmove(point, point+1, fraclen+1);
|
||||
v = rb_cstr_to_inum(tok(), 10, FALSE);
|
||||
v = rb_rational_new(v, rb_int_positive_pow(10, fraclen));
|
||||
}
|
||||
else {
|
||||
double d = strtod(tok(), 0);
|
||||
if (errno == ERANGE) {
|
||||
rb_warningS("Float %s out of range", tok());
|
||||
errno = 0;
|
||||
}
|
||||
v = DBL2NUM(d);
|
||||
}
|
||||
return set_number_literal(v, type, suffix);
|
||||
}
|
||||
suffix = number_literal_suffix(NUM_SUFFIX_ALL);
|
||||
return set_integer_literal(rb_cstr_to_inum(tok(), 10, FALSE), suffix);
|
||||
}
|
||||
return parse_numeric(parser, c);
|
||||
|
||||
case ')':
|
||||
case ']':
|
||||
|
|
Загрузка…
Ссылка в новой задаче