Changeset 4305


Ignore:
Timestamp:
Nov 17, 2014, 8:33:22 PM (4 years ago)
Author:
cameron
Message:

Support for ICU, Perl backslash escape codepoint sequences; non-codepoint escapes to follow

Location:
icGREP/icgrep-devel
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • icGREP/icgrep-devel/QA/greptest.xml

    r4269 r4305  
    381381<grepcase regexp="[wxy]{2}{3}{2}" datafile="bounded_charclass" grepcount="3"/>
    382382<grepcase regexp="=([a-z][c-z])*;" datafile="bounded_charclass" grepcount="12"/>
     383<grepcase regexp="[\u0061-\u007A]{6}" datafile="bounded_charclass" grepcount="21"/>
     384<grepcase regexp="[\o{142}-d]{2}" datafile="bounded_charclass" grepcount="3"/>
     385<grepcase regexp="[\x61-\U0000007A]{6}" datafile="bounded_charclass" grepcount="21"/>
    383386
    384387<grepcase regexp="^D[zabcdefoy]g" datafile="RangeAltSeqMatchStarKplusWhileNotOptAny" grepcount="7"/>
     
    409412<grepcase regexp="'...'" datafile="LU_test" grepcount="0"/>
    410413<grepcase regexp="\u{1e20}" datafile="LU_test" grepcount="1"/>
     414<grepcase regexp="\u1e20" datafile="LU_test" grepcount="1"/>
     415<grepcase regexp="\U00001e20" datafile="LU_test" grepcount="1"/>
     416<grepcase regexp="\o{17040}" datafile="LU_test" grepcount="1"/>
    411417<grepcase regexp="\u{1e21}" datafile="LU_test" grepcount="0"/>
     418<grepcase regexp="\u1e21" datafile="LU_test" grepcount="0"/>
     419<grepcase regexp="\U00001e21" datafile="LU_test" grepcount="0"/>
     420<grepcase regexp="\o{17041}" datafile="LU_test" grepcount="0"/>
    412421<grepcase regexp="\p{Lu}" datafile="LU_test" grepcount="2"/>
    413422<grepcase regexp="'\p{Lu}'" datafile="LU_test" grepcount="1"/>
  • icGREP/icgrep-devel/icgrep/re/re_parser.cpp

    r4304 r4305  
    195195    throw_incomplete_expression_error_if_end_of_stream();
    196196    switch (*_cursor) {
    197         case '(': case ')': case '*': case '+':
    198         case '.': case '?': case '[': case '\\':
    199         case ']': case '{': case '|': case '}':
    200             return makeCC(*_cursor++);
    201         case 'u':
    202             return makeCC(parse_hex());
    203197        case 'P':
    204198            return makeDiff(makeAny(), parse_unicode_category());
    205199        case 'p':
    206200            return parse_unicode_category();
     201                default:
     202                        return makeCC(parse_escaped_codepoint());
    207203    }
    208204    throw ParseFailure("Illegal backslash escape!");
     
    351347    }
    352348    if (*_cursor == '\\') {
    353         if (++_cursor == _end) {
    354             throw ParseFailure("Unknown charset escape!");
    355         }
    356         switch (*_cursor) {
    357             case '(': case ')': case '*': case '+':
    358             case '.': case '?': case '[': case '\\':
    359             case ']': case '{': case '|': case '}':
    360             case '-':
    361                 if (_allow_escapes_within_charset) {
    362                     literal = *_cursor++;
    363                     return true;
    364                 }
    365                 break;
    366             case 'u':
    367                 literal = parse_hex();
    368                 return true;
    369             // probably need to pass in the CC to handle \w, \s, etc...
    370         }
    371         throw ParseFailure("Unknown charset escape!");
     349                _cursor++;
     350                literal = parse_escaped_codepoint();
     351                return true;
    372352    }
    373353    else {
     
    390370}
    391371
    392 unsigned RE_Parser::parse_hex() {
    393     if (++_cursor != _end && *_cursor == '{') {
    394         unsigned value = 0;
    395         for (++_cursor; _cursor != _end; ++_cursor) {
    396             const char t = *_cursor;
    397             if (t == '}') {
    398                 ++_cursor;
    399                 return value;
    400             }
    401             value *= 16;
    402             if (t >= '0' && t <= '9') {
    403                 value |= (t - '0');
    404             }
    405             else if ((t | 32) >= 'a' && (t | 32) <= 'f') {
    406                 value |= ((t | 32) - 'a') + 10;
    407             }
    408             else {
    409                 break;
    410             }
    411         }
    412     }
    413     throw ParseFailure("Bad Unicode hex notation!");
    414 }
     372
     373// A backslash escape was found, and various special cases (back reference,
     374// quoting with \Q, \E, sets (\p, \P, \d, \D, \w, \W, \s, \S), grapheme
     375// cluster \X have been ruled out.
     376// It may be one of several possibilities or an error sequence.
     377// 1. Special control codes (\a, \b, \e, \f, \n, \r, \t, \v)
     378// 2. General control codes c[@-_a-z?]
     379// 3. Restricted octal notation 0 - 0777
     380// 4. General octal notation o\{[0-7]+\}
     381// 5. General hex notation x\{[0-9A-Fa-f]+\}
     382// 6. An error for any unrecognized alphabetic escape
     383// 7. An escaped ASCII symbol, standing for itself
     384
     385unsigned RE_Parser::parse_escaped_codepoint() {
     386        unsigned cp_value;
     387        throw_incomplete_expression_error_if_end_of_stream();
     388        switch (*_cursor) {
     389                case 'a': ++_cursor; return 0x07; // BEL
     390                case 'b': ++_cursor; return 0x08; // BS
     391                case 'e': ++_cursor; return 0x1B; // ESC
     392                case 'f': ++_cursor; return 0x0C; // FF
     393                case 'n': ++_cursor; return 0x0A; // LF
     394                case 'r': ++_cursor; return 0x0D; // CR
     395                case 't': ++_cursor; return 0x09; // HT
     396                case 'v': ++_cursor; return 0x0B; // VT
     397                case 'c': // Control-escape based on next char
     398                        ++_cursor;
     399                        throw_incomplete_expression_error_if_end_of_stream();
     400                        // \c@, \cA, ... \c_, or \ca, ..., \cz
     401                        if (((*_cursor >= '@') && (*_cursor <= '_')) || ((*_cursor >= 'a') && (*_cursor <= 'z'))) {
     402                                cp_value = static_cast<unsigned>(*_cursor & 0x1F);
     403                                _cursor++;
     404                                return cp_value;
     405                        }
     406                        else if (*_cursor++ == '?') return 0x7F;  // \c? ==> DEL
     407                        else throw("Illegal \\c escape sequence");
     408                case '0': // Octal escape:  0 - 0377
     409                        ++_cursor;
     410                        return parse_octal_codepoint(0,3);
     411                case 'o':
     412                        ++_cursor;
     413                        throw_incomplete_expression_error_if_end_of_stream();
     414                        if (*_cursor == '{') {
     415                                ++_cursor;
     416                                cp_value = parse_octal_codepoint(1, 7);
     417                                if (_cursor == _end || *_cursor++ != '}') throw ParseFailure("Malformed octal escape sequence");
     418                                return cp_value;
     419                        }
     420                        else {
     421                                throw ParseFailure("Malformed octal escape sequence");
     422                        }
     423                case 'x':
     424                        ++_cursor;
     425                        throw_incomplete_expression_error_if_end_of_stream();
     426                        if (*_cursor == '{') {
     427                          ++_cursor;
     428                          cp_value = parse_hex_codepoint(1, 6);
     429                          if (_cursor == _end || *_cursor++ != '}') throw ParseFailure("Malformed hex escape sequence");
     430                          return cp_value;
     431                        }
     432                        else {
     433                                return parse_hex_codepoint(1,2);  // ICU compatibility
     434                        }
     435                case 'u':
     436                        ++_cursor;
     437                        throw_incomplete_expression_error_if_end_of_stream();
     438                        if (*_cursor == '{') {
     439                                ++_cursor;
     440                                cp_value = parse_hex_codepoint(1, 6);
     441                                if (_cursor == _end || *_cursor++ != '}') throw ParseFailure("Malformed hex escape sequence");
     442                                return cp_value;
     443                        }
     444                        else {
     445                                return parse_hex_codepoint(4,4);  // ICU compatibility
     446                        }
     447                case 'U':
     448                        ++_cursor;
     449                        return parse_hex_codepoint(8,8);  // ICU compatibility
     450                default:
     451                        if (((*_cursor >= 'A') && (*_cursor <= 'Z')) || ((*_cursor >= 'a') && (*_cursor <= 'z')))
     452                                throw ParseFailure("Undefined or unsupported escape sequence");
     453                        else return static_cast<unsigned>(*_cursor++);
     454        }
     455}
     456
     457
     458unsigned RE_Parser::parse_octal_codepoint(int mindigits, int maxdigits) {
     459        unsigned value = 0;
     460        int count = 0;
     461        while (_cursor != _end && count < maxdigits) {
     462                const char t = *_cursor;
     463                if (t < '0' || t > '7') {
     464                        break;
     465                }
     466                value = value * 8 | (t - '0');
     467                ++_cursor;
     468                ++count;
     469        }
     470        if (count < mindigits) throw ParseFailure("Octal sequence has too few digits");
     471        if (value > CC::UNICODE_MAX) throw ParseFailure("Octal value too large");
     472        return value;
     473}
     474
     475unsigned RE_Parser::parse_hex_codepoint(int mindigits, int maxdigits) {
     476        unsigned value = 0;
     477        int count = 0;
     478        while (_cursor != _end && isxdigit(*_cursor) && count < maxdigits) {
     479                const char t = *_cursor;
     480                if (isdigit(t)) {
     481                        value = (value * 16) | (t - '0');
     482                }
     483                else { 
     484                        value = (value * 16) | ((t | 32) - 'a') + 10;
     485                }
     486                ++_cursor;
     487                ++count;
     488        }
     489        if (count < mindigits) throw ParseFailure("Hexadecimal sequence has too few digits");
     490        if (value > CC::UNICODE_MAX) throw ParseFailure("Hexadecimal value too large");
     491        return value;
     492}
     493
    415494
    416495inline void RE_Parser::throw_incomplete_expression_error_if_end_of_stream() const {
  • icGREP/icgrep-devel/icgrep/re/re_parser.h

    r4256 r4305  
    5454    bool parse_charset_literal(unsigned & literal);
    5555
    56     unsigned parse_hex();
     56    unsigned parse_escaped_codepoint();
     57
     58    unsigned parse_hex_codepoint(int mindigits, int maxdigits);
     59
     60    unsigned parse_octal_codepoint(int mindigits, int maxdigits);
    5761
    5862    unsigned parse_int();
Note: See TracChangeset for help on using the changeset viewer.