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
Location:
icGREP/icgrep-devel/icgrep/re
Files:
6 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
  • icGREP/icgrep-devel/icgrep/re/re_parser.h

    r5180 r5206  
    119119    virtual RE * parse_RE();
    120120
    121     virtual RE * parse_alt();
     121    RE * parse_alt();
     122
     123    virtual RE * parse_alt_with_intersect(RE* reToBeIntersected);
    122124
    123125    RE * parse_seq();
    124126
     127    RE * parse_seq_with_intersect(RE* reToBeIntersected);
     128
    125129    virtual RE * parse_next_item();
    126130
     
    144148
    145149    virtual RE * parsePropertyExpression();
     150    RE * parseRegexPropertyValue(const std::string& propName, const std::string& regexValue);
    146151
    147152    Name * parseNamePatternExpression();
     
    150155    RE * makeWordBoundary();
    151156    RE * makeWordNonBoundary();
     157    RE * makeReBoundary(RE * wordC);
     158    RE * makeReNonBoundary(RE * wordC);
    152159    RE * makeWordBegin();
    153160    RE * makeWordEnd();
     
    179186
    180187    static std::string canonicalize(const cursor_t begin, const cursor_t end);
     188    bool isCharAhead(char c);
    181189
    182190protected:
     
    190198    NameMap                     mNameMap;
    191199    Memoizer                    mMemoizer;
     200    RE_Syntax                   mReSyntax;
    192201};
    193202
  • icGREP/icgrep-devel/icgrep/re/re_parser_bre.cpp

    r5181 r5206  
    3333    }
    3434
    35     RE * RE_Parser_BRE::parse_alt() {
     35    RE * RE_Parser_BRE::parse_alt_with_intersect(RE *reToBeIntersected) {
    3636        std::vector<RE *> alt;
    3737        for (;;) {
    38             alt.push_back(parse_seq());
     38            alt.push_back(parse_seq_with_intersect(reToBeIntersected));
    3939
    4040            if (!isEscapedCharAhead('|')) {
     
    188188    }
    189189
    190     inline bool RE_Parser_BRE::isCharAhead(char c) {
    191         if (mCursor.remaining() < 2) {
    192             return false;
    193         }
    194         auto nextCursor = mCursor.pos() + 1;
    195         return *nextCursor == c;
    196     }
    197 
    198190    inline std::pair<int, int> RE_Parser_BRE::parse_range_bound() {
    199191        int lower_bound = 0, upper_bound = 0;
     
    297289        }
    298290        if (*mCursor == '=') {
     291            // We have a property-name = value expression
    299292            const auto prop_end = mCursor.pos();
    300293            mCursor++;
    301             const auto val_start = mCursor.pos();
    302             while (mCursor.more()) {
    303                 if (isEscapedCharAhead('}') || *mCursor == ':') {
    304                     break;
    305                 }
    306                 ++mCursor;
    307             }
    308             // We have a property-name = value expression
    309             return createName(canonicalize(start, prop_end), canonicalize(val_start, mCursor.pos()));
     294            auto val_start = mCursor.pos();
     295            if (*val_start != '\\' || !isCharAhead('/')) {
     296                // property-value is normal string
     297                while (mCursor.more()) {
     298                    if (isEscapedCharAhead('}') || *mCursor == ':') {
     299                        break;
     300                    }
     301                    ++mCursor;
     302                }
     303                return createName(canonicalize(start, prop_end), canonicalize(val_start, mCursor.pos()));
     304            } else {
     305                // property-value is another regex
     306                ++mCursor;
     307                auto previous = val_start;
     308                auto current = (++mCursor).pos();
     309                val_start = current;
     310
     311                while (true) {
     312                    if (*current == '/' && *previous == '\\') {
     313                        break;
     314                    }
     315
     316                    if (!mCursor.more()) {
     317                        ParseFailure("Malformed property expression");
     318                    }
     319
     320                    previous = current;
     321                    current = (++mCursor).pos();
     322                }
     323                ++mCursor;
     324                return parseRegexPropertyValue(canonicalize(start, prop_end), canonicalize(val_start, previous));
     325            }
    310326        }
    311327        return createName(canonicalize(start, mCursor.pos()));
  • icGREP/icgrep-devel/icgrep/re/re_parser_bre.h

    r5180 r5206  
    1313    class RE_Parser_BRE : public RE_Parser  {
    1414    public:
    15         RE_Parser_BRE(const std::string & regular_expression) : RE_Parser(regular_expression)  {
    16 
     15        RE_Parser_BRE(const std::string & regular_expression) : RE_Parser(regular_expression) {
     16            mReSyntax = RE_Syntax::BRE;
    1717        }
    1818
     
    2020        virtual bool isSetEscapeChar(char c) override;
    2121        virtual bool isUnsupportChartsetOperator(char c) override;
    22         virtual RE * parse_alt() override;
     22        virtual RE * parse_alt_with_intersect(RE* reToBeIntersected) override;
    2323        virtual RE * parse_next_item() override ;
    2424        virtual RE * parse_escaped() override;
     
    3232    private:
    3333        bool isEscapedCharAhead(char c);
    34         bool isCharAhead(char c);
     34
    3535    };
    3636}
  • icGREP/icgrep-devel/icgrep/re/re_parser_ere.h

    r5180 r5206  
    1212    class RE_Parser_ERE : public RE_Parser  {
    1313    public:
    14         RE_Parser_ERE(const std::string & regular_expression) : RE_Parser(regular_expression)  {
    15 
     14        RE_Parser_ERE(const std::string & regular_expression) : RE_Parser(regular_expression) {
     15            mReSyntax = RE_Syntax::ERE;
    1616        }
    1717
  • icGREP/icgrep-devel/icgrep/re/re_parser_pcre.h

    r5180 r5206  
    1414        RE_Parser_PCRE(const std::string & regular_expression) : RE_Parser(regular_expression) {
    1515            fSupportNonCaptureGroup = true;
     16            mReSyntax = RE_Syntax ::PCRE;
    1617        }
    1718    protected:
Note: See TracChangeset for help on using the changeset viewer.