1:- module(regex_engine_pp, [engine_match/5]).    2:- use_module(library(regex/state)).    3
    4% regular expression interpreter
    5
    6% engine_match(RE, Selected, S, Unmatched) is true if RE matches
    7% a string Prefix such that S = [Prefix|Unmatched], and
    8% Selected is the list of substrings of Prefix that matched
    9% the parenthesized components of RE.
   10
   11engine_match(union(RE1, _RE2), State0, State) -->
   12    engine_match(RE1, State0, State).
   13engine_match(union(_RE1, RE2), State0, State) -->
   14    engine_match(RE2, State0, State).
   15
   16engine_match(conc(RE1, RE2), State0, State) -->
   17    engine_match(RE1, State0, State1),
   18    engine_match(RE2, State1, State).
   19
   20% match a specific number of times
   21engine_match(count(RE,N0,M0), State0, State) -->
   22    { N0 > 0 },
   23    engine_match(RE, State0, State1),    % try for minimum matches
   24    { succ(N, N0) },
   25    { succ(M, M0) },
   26    engine_match(count(RE,N,M), State1, State).
   27engine_match(count(RE,0,M0), State0, State) -->
   28    { M0 > 0 },
   29    engine_match(RE, State0, State1),    % prefer more matches
   30    { succ(M, M0) },
   31    engine_match(count(RE,0,M), State1, State).
   32engine_match(count(_,0,_), State, State) -->
   33    { true }.
   34
   35% Match a capturing group
   36engine_match(group(RE), State0, State, S, U) :-
   37    push_capture(P, State0, State1),
   38    engine_match(RE, State1, State, S, U),
   39    append(P, U, S).
   40
   41% Match a named group. Try saving the capture under a name; otherwise,
   42% treat the group as a numbered capture.
   43engine_match(named_group(Name,RE), State0, State, S, U) :-
   44    push_capture(Name=P,State0,State1),
   45    engine_match(RE, State1, State, S, U),
   46    append(P, U, S).
   47
   48engine_match(any, State, State) -->
   49    [C],
   50    {
   51        ( C = 0'\n ->
   52            singleline_mode(State)
   53        ; % not a new line ->
   54            true
   55        )
   56    }.
   57
   58% matches both regular characters and metacharacters
   59engine_match(char(C), State, State) -->
   60    [C0],
   61    { adjust_case(State, C0, C) }.
   62
   63engine_match(eos, State, State, [], []).
   64
   65engine_match(neg_set(Set), State, State) -->
   66    [C0],
   67    { adjust_case(State,C0,C) },
   68    { \+ char_set_member(C, Set) }.
   69
   70engine_match(pos_set(Set), State, State) -->
   71    [C0],
   72    { adjust_case(State,C0,C) },
   73    { char_set_member(C, Set) }.
   74
   75
   76char_set_member(C, [char(C) | _]).
   77char_set_member(C, [range(C1, C2) | _]) :-
   78    C1 =< C,
   79    C =< C2.
   80char_set_member(C, [_|T]) :-
   81    char_set_member(C, T)