Ignore:
Timestamp:
Nov 7, 2016, 3:54:09 PM (3 years ago)
Author:
xwa163
Message:
  1. Extend Regex Syntax, include: (a) RL2.6 of UTS#18, support regex in property value. e.g. \p{script=/.*hir.*/} (b) Support syntax of property expression when parsing boundary. e.g. \b{greek} (c) Extend property expression in non capture group. e.g. (?\p{upper}:\p{greek}\p{script=hira})
  2. Add related test cases
File:
1 edited

Legend:

Unmodified
Added
Removed
  • icGREP/icgrep-devel/icgrep/re/re_parser.cpp

    r5182 r5206  
    6868    , mCursor(regular_expression)
    6969    , mCaptureGroupCount(0)
     70    , mReSyntax(RE_Syntax::PCRE)
    7071    {
    7172
     
    8788
    8889RE * RE_Parser::parse_alt() {
     90    return parse_alt_with_intersect(nullptr);
     91}
     92
     93RE * RE_Parser::parse_alt_with_intersect(RE* reToBeIntersected) {
    8994    std::vector<RE *> alt;
    9095    for (;;) {
    91         alt.push_back(parse_seq());
     96        alt.push_back(parse_seq_with_intersect(reToBeIntersected));
    9297        if (*mCursor != '|') {
    9398            break;
     
    102107
    103108RE * RE_Parser::parse_seq() {
     109    return parse_seq_with_intersect(nullptr);
     110}
     111
     112RE * RE_Parser::parse_seq_with_intersect(RE* reToBeIntersected) {
    104113    std::vector<RE *> seq;
    105114    for (;;) {
     
    111120            }
    112121            break;
     122        }
     123        if (reToBeIntersected) {
     124            re = makeIntersect(reToBeIntersected, re);
    113125        }
    114126        re = extend_item(re);
     
    250262                    return parse_next_item();
    251263                }
     264            case '\\': {
     265                ++mCursor;
     266                if (*mCursor == 'p' || *mCursor == 'P') {
     267                    RE* reToBeIntersected = parseEscapedSet();
     268                    if (*mCursor == ':') {
     269                        ++mCursor;
     270                        group_expr = parse_alt_with_intersect(reToBeIntersected);
     271                        fModeFlagSet = modeFlagSet;
     272                        break;
     273                    } else {  // if *_cursor == ')'
     274                        ++mCursor;
     275                        return parse_next_item();
     276                    }
     277                }
     278                break;
     279            }
    252280            default:
    253281                ParseFailure("Illegal (? syntax.");
     
    382410                return complemented ? makeWordNonBoundary() : makeWordBoundary();
    383411            } else {
    384                 switch (*++mCursor) {
    385                     case 'g':
    386                         re = complemented ? makeZeroWidth("NonGCB") : makeZeroWidth("GCB");
    387                         break;
    388                     case 'w': ParseFailure("\\b{w} not yet supported.");
    389                     case 'l': ParseFailure("\\b{l} not yet supported.");
    390                     case 's': ParseFailure("\\b{s} not yet supported.");
    391                     default: ParseFailure("Unrecognized boundary assertion");
    392                 }
    393                 if (*++mCursor != '}') {
    394                     ParseFailure("Malformed boundary assertion");
    395                 }
    396                 ++mCursor;
     412                ++mCursor;
     413                if (isCharAhead('}')) {
     414                    switch (*mCursor) {
     415                        case 'g':
     416                            re = complemented ? makeZeroWidth("NonGCB") : makeZeroWidth("GCB");
     417                            ++mCursor;
     418                            ++mCursor;
     419                            break;
     420                        case 'w': ParseFailure("\\b{w} not yet supported.");
     421                        case 'l': ParseFailure("\\b{l} not yet supported.");
     422                        case 's': ParseFailure("\\b{s} not yet supported.");
     423//                        default: ParseFailure("Unrecognized boundary assertion");
     424                    }
     425                }
     426                if (!re) {
     427                    auto propExpr = parsePropertyExpression();
     428                    if (*mCursor++ != '}') {
     429                        ParseFailure("Malformed boundary assertion");
     430                    }
     431                    re = complemented ? makeReNonBoundary(propExpr) : makeReBoundary(propExpr);
     432                }
    397433                return re;
    398434            }
     
    529565}
    530566
     567bool RE_Parser::isCharAhead(char c) {
     568    if (mCursor.remaining() < 2) {
     569        return false;
     570    }
     571    auto nextCursor = mCursor.pos() + 1;
     572    return *nextCursor == c;
     573}
     574
    531575RE * RE_Parser::parsePropertyExpression() {
    532576    const auto start = mCursor.pos();
     
    543587    }
    544588    if (*mCursor == '=') {
     589        // We have a property-name = value expression
    545590        const auto prop_end = mCursor.pos();
    546591        mCursor++;
    547         const auto val_start = mCursor.pos();
    548         while (mCursor.more()) {
    549             bool done = false;
    550             switch (*mCursor) {
    551                 case '}': case ':':
    552                     done = true;
    553             }
    554             if (done) {
    555                 break;
    556             }
    557             ++mCursor;
    558         }
    559         // We have a property-name = value expression
    560         return createName(canonicalize(start, prop_end), canonicalize(val_start, mCursor.pos()));
     592        auto val_start = mCursor.pos();
     593        if (*val_start != '/') {
     594            // property-value is normal string
     595            while (mCursor.more()) {
     596                bool done = false;
     597                switch (*mCursor) {
     598                    case '}': case ':':
     599                        done = true;
     600                }
     601                if (done) {
     602                    break;
     603                }
     604                ++mCursor;
     605            }
     606            return createName(canonicalize(start, prop_end), canonicalize(val_start, mCursor.pos()));
     607        } else {
     608            // property-value is another regex
     609            auto previous = val_start;
     610            auto current = (++mCursor).pos();
     611            val_start = current;
     612
     613            while (true) {
     614                if (*current == '/' && *previous != '\\') {
     615                    break;
     616                }
     617
     618                if (!mCursor.more()) {
     619                    ParseFailure("Malformed property expression");
     620                }
     621
     622                previous = current;
     623                current = (++mCursor).pos();
     624            }
     625            ++mCursor;
     626            return parseRegexPropertyValue(canonicalize(start, prop_end), canonicalize(val_start, current));
     627        }
    561628    }
    562629    return createName(canonicalize(start, mCursor.pos()));
     630}
     631
     632RE * RE_Parser::parseRegexPropertyValue(const std::string& propName, const std::string& regexValue) {
     633    auto regexValueForGrep = "^" + regexValue + "$";
     634    RE* propValueRe = RE_Parser::parse(regexValueForGrep, fModeFlagSet, mReSyntax);
     635    GrepEngine engine;
     636    engine.grepCodeGen("NamePattern", propValueRe, false, false, GrepType::PropertyValue);
     637    auto grepValue = engine.grepPropertyValues(propName);
     638
     639    auto grepValueSize = grepValue.size();
     640    if (!grepValueSize) {
     641        ParseFailure("regex " + regexValue + " match no property values");
     642    } else if (grepValueSize == 1) {
     643        // handle right value
     644        return createName(std::string(propName), std::string(grepValue[0]));
     645    } else {
     646        std::vector<re::RE*> valueRes;
     647        for (auto iter = grepValue.begin(); iter != grepValue.end(); ++iter) {
     648            valueRes.push_back(createName(std::string(propName), std::string(*iter)));
     649        }
     650
     651        return makeAlt(valueRes.begin(), valueRes.end());
     652    }
    563653}
    564654
     
    581671   
    582672    GrepEngine engine;
    583     engine.grepCodeGen("NamePattern", embedded, false, false, true);
     673    engine.grepCodeGen("NamePattern", embedded, false, false, GrepType::NameExpression);
    584674    CC * codepoints = engine.grepCodepoints();
    585675   
     
    9721062
    9731063           
    974                        
     1064
    9751065                           
    9761066RE * RE_Parser::makeWordBoundary() {
    9771067    Name * wordC = makeWordSet();
    978     return makeAlt({makeSeq({makeNegativeLookBehindAssertion(wordC), makeLookAheadAssertion(wordC)}),
    979                     makeSeq({makeLookBehindAssertion(wordC), makeNegativeLookAheadAssertion(wordC)})});
     1068    return makeReBoundary(wordC);
    9801069}
    9811070
    9821071RE * RE_Parser::makeWordNonBoundary() {
    9831072    Name * wordC = makeWordSet();
    984     return makeAlt({makeSeq({makeNegativeLookBehindAssertion(wordC), makeNegativeLookAheadAssertion(wordC)}),
    985                     makeSeq({makeLookBehindAssertion(wordC), makeLookAheadAssertion(wordC)})});
     1073    return makeReNonBoundary(wordC);
     1074}
     1075
     1076inline RE * RE_Parser::makeReBoundary(RE * re) {
     1077    return makeAlt({makeSeq({makeNegativeLookBehindAssertion(re), makeLookAheadAssertion(re)}),
     1078                    makeSeq({makeLookBehindAssertion(re), makeNegativeLookAheadAssertion(re)})});
     1079}
     1080inline RE * RE_Parser::makeReNonBoundary(RE * re) {
     1081    return makeAlt({makeSeq({makeNegativeLookBehindAssertion(re), makeNegativeLookAheadAssertion(re)}),
     1082                    makeSeq({makeLookBehindAssertion(re), makeLookAheadAssertion(re)})});
    9861083}
    9871084
Note: See TracChangeset for help on using the changeset viewer.