| ... | ... | @@ -13,12 +13,11 @@ |
| 13 | 13 | #include <stdio.h> |
| 14 | 14 | |
| 15 | 15 | #define WHITESPACE \ |
| 16 | | ' ': \ |
| 16 | ' ': \ |
| 17 | 17 | case '\n' |
| 18 | 18 | |
| 19 | | #define DIGIT \ |
| 20 | | '0': \ |
| 21 | | case '1': \ |
| 19 | #define DIGIT_NON_ZERO \ |
| 20 | '1': \ |
| 22 | 21 | case '2': \ |
| 23 | 22 | case '3': \ |
| 24 | 23 | case '4': \ |
| ... | ... | @@ -27,10 +26,14 @@ |
| 27 | 26 | case '7': \ |
| 28 | 27 | case '8': \ |
| 29 | 28 | case '9' |
| 29 | #define DIGIT \ |
| 30 | '0': \ |
| 31 | case DIGIT_NON_ZERO |
| 30 | 32 | |
| 31 | 33 | #define ALPHA_EXCEPT_C \ |
| 32 | | 'a': \ |
| 34 | 'a': \ |
| 33 | 35 | case 'b': \ |
| 36 | /*case 'c':*/ \ |
| 34 | 37 | case 'd': \ |
| 35 | 38 | case 'e': \ |
| 36 | 39 | case 'f': \ |
| ... | ... | @@ -94,7 +97,11 @@ enum TokenizeState { |
| 94 | 97 | TokenizeStateStart, |
| 95 | 98 | TokenizeStateSymbol, |
| 96 | 99 | TokenizeStateSymbolFirst, |
| 97 | | TokenizeStateNumber, |
| 100 | TokenizeStateZero, // "0", which might lead to "0x" |
| 101 | TokenizeStateNumber, // "123", "0x123" |
| 102 | TokenizeStateFloatFraction, // "123.456", "0x123.456" |
| 103 | TokenizeStateFloatExponentUnsigned, // "123.456e", "123e", "0x123p" |
| 104 | TokenizeStateFloatExponentNumber, // "123.456e-", "123.456e5", "123.456e5e-5" |
| 98 | 105 | TokenizeStateString, |
| 99 | 106 | TokenizeStateSawStar, |
| 100 | 107 | TokenizeStateSawSlash, |
| ... | ... | @@ -172,6 +179,16 @@ static void end_token(Tokenize *t) { |
| 172 | 179 | assert(t->cur_tok); |
| 173 | 180 | t->cur_tok->end_pos = t->pos + 1; |
| 174 | 181 | |
| 182 | // normalize number literal parsing stuff |
| 183 | if (t->cur_tok->id == TokenIdNumberLiteral) { |
| 184 | if (t->cur_tok->exponent_marker_pos == 0) { |
| 185 | t->cur_tok->exponent_marker_pos = t->cur_tok->end_pos; |
| 186 | } |
| 187 | if (t->cur_tok->decimal_point_pos == 0) { |
| 188 | t->cur_tok->decimal_point_pos = t->cur_tok->exponent_marker_pos; |
| 189 | } |
| 190 | } |
| 191 | |
| 175 | 192 | char *token_mem = buf_ptr(t->buf) + t->cur_tok->start_pos; |
| 176 | 193 | int token_len = t->cur_tok->end_pos - t->cur_tok->start_pos; |
| 177 | 194 | |
| ... | ... | @@ -218,6 +235,26 @@ static void end_token(Tokenize *t) { |
| 218 | 235 | t->cur_tok = nullptr; |
| 219 | 236 | } |
| 220 | 237 | |
| 238 | static bool is_exponent_signifier(uint8_t c, int radix) { |
| 239 | if (radix == 16) { |
| 240 | return c == 'p' || c == 'P'; |
| 241 | } else { |
| 242 | return c == 'e' || c == 'E'; |
| 243 | } |
| 244 | } |
| 245 | static int get_digit_value(uint8_t c) { |
| 246 | if ('0' <= c && c <= '9') { |
| 247 | return c - '0'; |
| 248 | } |
| 249 | if ('A' <= c && c <= 'Z') { |
| 250 | return c - 'A' + 10; |
| 251 | } |
| 252 | if ('a' <= c && c <= 'z') { |
| 253 | return c - 'a' + 10; |
| 254 | } |
| 255 | return -1; |
| 256 | } |
| 257 | |
| 221 | 258 | void tokenize(Buf *buf, Tokenization *out) { |
| 222 | 259 | Tokenize t = {0}; |
| 223 | 260 | t.out = out; |
| ... | ... | @@ -245,9 +282,15 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 245 | 282 | t.state = TokenizeStateSymbol; |
| 246 | 283 | begin_token(&t, TokenIdSymbol); |
| 247 | 284 | break; |
| 248 | | case DIGIT: |
| 285 | case '0': |
| 286 | t.state = TokenizeStateZero; |
| 287 | begin_token(&t, TokenIdNumberLiteral); |
| 288 | t.cur_tok->radix = 10; |
| 289 | break; |
| 290 | case DIGIT_NON_ZERO: |
| 249 | 291 | t.state = TokenizeStateNumber; |
| 250 | 292 | begin_token(&t, TokenIdNumberLiteral); |
| 293 | t.cur_tok->radix = 10; |
| 251 | 294 | break; |
| 252 | 295 | case '"': |
| 253 | 296 | begin_token(&t, TokenIdStringLiteral); |
| ... | ... | @@ -701,10 +744,102 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 701 | 744 | break; |
| 702 | 745 | } |
| 703 | 746 | break; |
| 747 | case TokenizeStateZero: |
| 748 | switch (c) { |
| 749 | case 'b': |
| 750 | t.cur_tok->radix = 2; |
| 751 | break; |
| 752 | case 'o': |
| 753 | t.cur_tok->radix = 8; |
| 754 | break; |
| 755 | case 'x': |
| 756 | t.cur_tok->radix = 16; |
| 757 | break; |
| 758 | default: |
| 759 | // reinterpret as normal number |
| 760 | t.pos -= 1; |
| 761 | t.state = TokenizeStateNumber; |
| 762 | continue; |
| 763 | } |
| 764 | break; |
| 704 | 765 | case TokenizeStateNumber: |
| 766 | { |
| 767 | if (c == '.') { |
| 768 | t.cur_tok->decimal_point_pos = t.pos; |
| 769 | t.state = TokenizeStateFloatFraction; |
| 770 | break; |
| 771 | } |
| 772 | if (is_exponent_signifier(c, t.cur_tok->radix)) { |
| 773 | t.cur_tok->exponent_marker_pos = t.pos; |
| 774 | t.state = TokenizeStateFloatExponentUnsigned; |
| 775 | break; |
| 776 | } |
| 777 | if (c == '_') { |
| 778 | tokenize_error(&t, "invalid character: '%c'", c); |
| 779 | break; |
| 780 | } |
| 781 | int digit_value = get_digit_value(c); |
| 782 | if (digit_value >= 0) { |
| 783 | if (digit_value >= t.cur_tok->radix) { |
| 784 | tokenize_error(&t, "invalid character: '%c'", c); |
| 785 | } |
| 786 | // normal digit |
| 787 | } else { |
| 788 | // not my char |
| 789 | t.pos -= 1; |
| 790 | end_token(&t); |
| 791 | t.state = TokenizeStateStart; |
| 792 | continue; |
| 793 | } |
| 794 | break; |
| 795 | } |
| 796 | case TokenizeStateFloatFraction: |
| 797 | { |
| 798 | if (is_exponent_signifier(c, t.cur_tok->radix)) { |
| 799 | t.cur_tok->exponent_marker_pos = t.pos; |
| 800 | t.state = TokenizeStateFloatExponentUnsigned; |
| 801 | break; |
| 802 | } |
| 803 | if (c == '_') { |
| 804 | tokenize_error(&t, "invalid character: '%c'", c); |
| 805 | break; |
| 806 | } |
| 807 | int digit_value = get_digit_value(c); |
| 808 | if (digit_value >= 0) { |
| 809 | if (digit_value >= t.cur_tok->radix) { |
| 810 | tokenize_error(&t, "invalid character: '%c'", c); |
| 811 | } |
| 812 | // normal digit |
| 813 | } else { |
| 814 | // not my char |
| 815 | t.pos -= 1; |
| 816 | end_token(&t); |
| 817 | t.state = TokenizeStateStart; |
| 818 | continue; |
| 819 | } |
| 820 | break; |
| 821 | } |
| 822 | case TokenizeStateFloatExponentUnsigned: |
| 823 | switch (c) { |
| 824 | case '+': |
| 825 | case '-': |
| 826 | t.state = TokenizeStateFloatExponentNumber; |
| 827 | break; |
| 828 | default: |
| 829 | // reinterpret as normal exponent number |
| 830 | t.pos -= 1; |
| 831 | t.state = TokenizeStateFloatExponentNumber; |
| 832 | continue; |
| 833 | } |
| 834 | break; |
| 835 | case TokenizeStateFloatExponentNumber: |
| 705 | 836 | switch (c) { |
| 706 | 837 | case DIGIT: |
| 707 | 838 | break; |
| 839 | case ALPHA: |
| 840 | case '_': |
| 841 | tokenize_error(&t, "invalid character: '%c'", c); |
| 842 | break; |
| 708 | 843 | default: |
| 709 | 844 | t.pos -= 1; |
| 710 | 845 | end_token(&t); |
| ... | ... | @@ -750,7 +885,11 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 750 | 885 | break; |
| 751 | 886 | case TokenizeStateSymbol: |
| 752 | 887 | case TokenizeStateSymbolFirst: |
| 888 | case TokenizeStateZero: |
| 753 | 889 | case TokenizeStateNumber: |
| 890 | case TokenizeStateFloatFraction: |
| 891 | case TokenizeStateFloatExponentUnsigned: |
| 892 | case TokenizeStateFloatExponentNumber: |
| 754 | 893 | case TokenizeStateSawStar: |
| 755 | 894 | case TokenizeStateSawSlash: |
| 756 | 895 | case TokenizeStateSawPercent: |