authorgravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2015-12-15 12:52:10-07:00
committergravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2015-12-15 13:15:24-07:00
log2f15babbd35c8ba66261221dd345260cbfabe039
tree25998e31c6d86f4c947b7da3f6c862b74b1b7141
parentfe94ca8d1049c196d2db114562dc065ffc57b46c

better radix handling in float parsing. base 10 still doesn't work.


1 files changed, 59 insertions(+), 29 deletions(-)

src/parser.cpp+59-29
......@@ -585,10 +585,13 @@ static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool
585585}
586586
587587static unsigned long long parse_int_digits(ParseContext *pc, int digits_start, int digits_end, int radix,
588 unsigned long long initial_value, bool *overflow) {
589 unsigned long long x = initial_value;
588 int skip_index, bool *overflow)
589{
590 unsigned long long x = 0;
590591
591592 for (int i = digits_start; i < digits_end; i++) {
593 if (i == skip_index)
594 continue;
592595 uint8_t c = *((uint8_t*)buf_ptr(pc->buf) + i);
593596 unsigned long long digit = get_digit_value(c);
594597
......@@ -625,7 +628,7 @@ static void parse_number_literal(ParseContext *pc, Token *token, AstNodeNumberLi
625628 if (token->decimal_point_pos == token->end_pos) {
626629 // integer
627630 unsigned long long whole_number = parse_int_digits(pc, whole_number_start, whole_number_end,
628 token->radix, 0, &num_lit->overflow);
631 token->radix, -1, &num_lit->overflow);
629632 if (num_lit->overflow) return;
630633
631634 num_lit->data.x_uint = whole_number;
......@@ -641,12 +644,6 @@ static void parse_number_literal(ParseContext *pc, Token *token, AstNodeNumberLi
641644 }
642645 } else {
643646 // float
644 // TODO: trim leading and trailing zeros in the significand digit sequence
645 unsigned long long significand_as_int = parse_int_digits(pc, whole_number_start, whole_number_end,
646 token->radix, 0, &num_lit->overflow);
647 if (num_lit->overflow) return;
648
649 int exponent = 0;
650647 if (token->decimal_point_pos < token->exponent_marker_pos) {
651648 // fraction
652649 int fraction_start = token->decimal_point_pos + 1;
......@@ -655,15 +652,44 @@ static void parse_number_literal(ParseContext *pc, Token *token, AstNodeNumberLi
655652 // TODO: error for empty fraction part
656653 return;
657654 }
655 }
658656
659 // TODO: check for where the fraction got too precise instead of just saying overflow
660 significand_as_int = parse_int_digits(pc, fraction_start, fraction_end,
661 token->radix, significand_as_int, &num_lit->overflow);
662 if (num_lit->overflow) return;
657 // trim leading and trailing zeros in the significand digit sequence
658 int significand_start = whole_number_start;
659 for (; significand_start < token->exponent_marker_pos; significand_start++) {
660 if (significand_start == token->decimal_point_pos)
661 continue;
662 uint8_t c = *((uint8_t*)buf_ptr(pc->buf) + significand_start);
663 if (c != '0')
664 break;
665 }
666 int significand_end = token->exponent_marker_pos;
667 for (; significand_end - 1 > significand_start; significand_end--) {
668 if (significand_end - 1 <= token->decimal_point_pos) {
669 significand_end = token->decimal_point_pos;
670 break;
671 }
672 uint8_t c = *((uint8_t*)buf_ptr(pc->buf) + significand_end - 1);
673 if (c != '0')
674 break;
675 }
663676
664 // adjust the exponent to compensate for us effectively moving
665 // the decimal point all the way to the right
666 exponent = -(fraction_end - fraction_start);
677 unsigned long long significand_as_int = parse_int_digits(pc, significand_start, significand_end,
678 token->radix, token->decimal_point_pos, &num_lit->overflow);
679 if (num_lit->overflow) return;
680
681 int exponent_in_bin_or_dec = 0;
682 if (significand_end > token->decimal_point_pos) {
683 exponent_in_bin_or_dec = token->decimal_point_pos + 1 - significand_end;
684 if (token->radix == 2) {
685 // already good
686 } else if (token->radix == 8) {
687 exponent_in_bin_or_dec *= 3;
688 } else if (token->radix == 10) {
689 // already good
690 } else if (token->radix == 16) {
691 exponent_in_bin_or_dec *= 4;
692 } else zig_unreachable();
667693 }
668694
669695 if (token->exponent_marker_pos < token->end_pos) {
......@@ -674,7 +700,6 @@ static void parse_number_literal(ParseContext *pc, Token *token, AstNodeNumberLi
674700 // TODO: error for empty exponent part
675701 return;
676702 }
677
678703 bool is_exponent_negative = false;
679704 uint8_t c = *((uint8_t*)buf_ptr(pc->buf) + exponent_start);
680705 if (c == '+') {
......@@ -690,16 +715,17 @@ static void parse_number_literal(ParseContext *pc, Token *token, AstNodeNumberLi
690715 }
691716
692717 unsigned long long specified_exponent = parse_int_digits(pc, exponent_start, exponent_end,
693 10, 0, &num_lit->overflow);
718 10, -1, &num_lit->overflow);
694719 // TODO: this check is a little silly
695720 if (specified_exponent >= LONG_LONG_MAX) {
696721 num_lit->overflow = true;
697722 return;
698723 }
724
699725 if (is_exponent_negative) {
700 exponent -= specified_exponent;
726 exponent_in_bin_or_dec -= specified_exponent;
701727 } else {
702 exponent += specified_exponent;
728 exponent_in_bin_or_dec += specified_exponent;
703729 }
704730 }
705731
......@@ -707,16 +733,20 @@ static void parse_number_literal(ParseContext *pc, Token *token, AstNodeNumberLi
707733 uint64_t exponent_bits;
708734 if (significand_as_int != 0) {
709735 // normalize the significand
710 int significand_magnitude = __builtin_clzll(1) - __builtin_clzll(significand_as_int);
711 exponent += significand_magnitude;
712 if (!(-1023 <= exponent && exponent < 1023)) {
713 num_lit->overflow = true;
714 return;
715 }
736 if (token->radix == 10) {
737 zig_panic("TODO: decimal floats");
738 } else {
739 int significand_magnitude_in_bin = __builtin_clzll(1) - __builtin_clzll(significand_as_int);
740 exponent_in_bin_or_dec += significand_magnitude_in_bin;
741 if (!(-1023 <= exponent_in_bin_or_dec && exponent_in_bin_or_dec < 1023)) {
742 num_lit->overflow = true;
743 return;
744 }
716745
717 // this should chop off exactly one 1 bit from the top.
718 significand_bits = ((uint64_t)significand_as_int << (52 - significand_magnitude)) & 0xfffffffffffffULL;
719 exponent_bits = exponent + 1023;
746 // this should chop off exactly one 1 bit from the top.
747 significand_bits = ((uint64_t)significand_as_int << (52 - significand_magnitude_in_bin)) & 0xfffffffffffffULL;
748 exponent_bits = exponent_in_bin_or_dec + 1023;
749 }
720750 } else {
721751 // 0 is all 0's
722752 significand_bits = 0;