diff --git a/src/c_tokenizer.cpp b/src/c_tokenizer.cpp index 0988c659b..00977e0f3 100644 --- a/src/c_tokenizer.cpp +++ b/src/c_tokenizer.cpp @@ -598,7 +598,8 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) { ctok->octal_index = 1; break; case 'x': - zig_panic("TODO hex"); + ctok->state = CTokStateStrHex; + ctok->cur_char = 0; break; case 'u': zig_panic("TODO unicode"); @@ -610,6 +611,54 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) { return mark_error(ctok); } break; + case CTokStateStrHex: { + uint8_t value = 0; + switch (*c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + value = *c - '0'; + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + value = (*c - 'a') + 10; + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + value = (*c - 'A') + 10; + break; + default: + c -= 1; + add_char(ctok, ctok->cur_char); + continue; + } + // TODO @mul_with_overflow + if (((long)ctok->cur_char) * 16 >= 256) { + zig_panic("TODO str hex mul overflow"); + } + ctok->cur_char = (uint8_t)(ctok->cur_char * (uint8_t)16); + // TODO @add_with_overflow + if (((long)ctok->cur_char) + (long)(value) >= 256) { + zig_panic("TODO str hex add overflow"); + } + ctok->cur_char = (uint8_t)(ctok->cur_char + value); + break; + } case CTokStateStrOctal: switch (*c) { case '0': @@ -632,28 +681,12 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) { ctok->cur_char = (uint8_t)(ctok->cur_char + (uint8_t)(*c - '0')); ctok->octal_index += 1; if (ctok->octal_index == 3) { - if (ctok->cur_tok->id == CTokIdStrLit) { - add_char(ctok, ctok->cur_char); - ctok->state = CTokStateString; - } else if (ctok->cur_tok->id == CTokIdCharLit) { - ctok->cur_tok->data.char_lit = ctok->cur_char; - ctok->state = CTokStateExpectEndQuot; - } else { - zig_unreachable(); - } + add_char(ctok, ctok->cur_char); } break; default: c -= 1; - if (ctok->cur_tok->id == CTokIdStrLit) { - add_char(ctok, ctok->cur_char); - ctok->state = CTokStateString; - } else if (ctok->cur_tok->id == CTokIdCharLit) { - ctok->cur_tok->data.char_lit = ctok->cur_char; - ctok->state = CTokStateExpectEndQuot; - } else { - zig_unreachable(); - } + add_char(ctok, ctok->cur_char); continue; } break; @@ -748,6 +781,7 @@ found_end_of_macro: case CTokStateString: case CTokStateExpSign: case CTokStateFloatExpFirst: + case CTokStateStrHex: case CTokStateStrOctal: return mark_error(ctok); } diff --git a/src/c_tokenizer.hpp b/src/c_tokenizer.hpp index 6267ea876..8eea6c56c 100644 --- a/src/c_tokenizer.hpp +++ b/src/c_tokenizer.hpp @@ -68,6 +68,7 @@ enum CTokState { CTokStateExpSign, CTokStateFloatExp, CTokStateFloatExpFirst, + CTokStateStrHex, CTokStateStrOctal, CTokStateNumLitIntSuffixU, CTokStateNumLitIntSuffixL, diff --git a/test/parsec.zig b/test/parsec.zig index 96f1cceaf..9b1bffcb5 100644 --- a/test/parsec.zig +++ b/test/parsec.zig @@ -285,6 +285,18 @@ pub fn addCases(cases: &tests.ParseCContext) { \\pub const @"comptime" = struct_comptime; ); + cases.add("macro defines string literal with hex", + \\#define FOO "aoeu\xab derp" + \\#define FOO2 "aoeu\x0007a derp" + \\#define FOO_CHAR '\xfF' + , + \\pub const FOO = c"aoeu\xab derp"; + , + \\pub const FOO2 = c"aoeuz derp"; + , + \\pub const FOO_CHAR = 255; + ); + cases.add("macro defines string literal with octal", \\#define FOO "aoeu\023 derp" \\#define FOO2 "aoeu\0234 derp"