diff -r e020a14e21be -r af5d8e985502 jitcraft/Scanner.cpp --- a/jitcraft/Scanner.cpp Sun Jul 01 11:25:36 2012 -0700 +++ b/jitcraft/Scanner.cpp Sun Jul 01 14:52:57 2012 -0700 @@ -137,6 +137,114 @@ return number; } +static inline bool +IsHexDigit(char c) +{ + return IsDigit(c) || + (c >= 'a' && c <= 'f') || + (c >= 'A' && c <= 'F'); +} + +// Based on the logic for litchar() in sc2.c. +int +Scanner::readEscapeCode() +{ + char c = getChar(); + if (c == '\\') + return c; + + switch (c) { + case 'a': + return '\a'; + case 'b': + return '\b'; + case 'e': + return 27; // Apparently \e is non-standard. + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case '\v': + return '\v'; + + case 'x': + { + unsigned digits = 0; + char r = 0; + + c = getChar(); + while (IsHexDigit(c) && digits < 2) { + if (IsDigit(c)) + c = (c << 4) + (c - '0'); + else + c = (c << 4) + (tolower(c) - 'a' + 10); + digits++; + c = getChar(); + } + + // Swallow a trailing ';' + if (c != ';') + putChar(c); + + return r; + } + + case '\'': + case '\"': + case '%': + return c; + + default: + { + if (IsDigit(c)) { + // \ddd + char r = 0; + while (IsDigit(c)) { + r = r * 10 + (c - '0'); + c = getChar(); + } + + // Swallow a trailing ; + if (c != ';') + putChar(c); + + return r; + } + assert(false); + return INT_MAX; + } + } +} + +TokenKind +Scanner::stringLiteral() +{ + literal_.clear(); + + for (;;) { + char c = getChar(); + if (c == '\"') + break; + if (c == '\r' || c == '\n' || c == '\0') { + assert(false); + return TOK_ERROR; + } + if (c == '\\') { + int code = readEscapeCode(); + if (code == INT_MAX) + return TOK_ERROR; + c = char(code); + } + literal_ += c; + } + + return TOK_STRING_LITERAL; +} + TokenKind Scanner::numberLiteral(char first) { @@ -335,6 +443,9 @@ case '\n': break; + case '"': + return stringLiteral(); + default: if (c >= '0' && c <= '9') return numberLiteral(c);