RegEx Parser written in Prolog
Asked Answered
M

2

7

I've been banging my head against the wall on this homework problem for a few hours now. We have to parse a regular expression with Prolog. For the most part, the predicates I have work, but there's a few regular expression and string combos which cause them to run out of stack space in SWI-Prolog. Here's a sample with two of the Regex string combinations, one that works and one that doesn't:

star(star(char(a))), []
star(star(char(a))), [a]

The first one works and the second one runs out of stack.

Here's the predicates I'm using:

re_match(epsilon, []).
re_match(char(Letter), [Letter]).
re_match(star(_), []).
re_match(seq(Rx1, Rx2), List) :- append(List1, List2, List),  re_match(Rx2, List2),  re_match(Rx1, List1).
re_match(alt(Rx1, Rx2), List) :- re_match(Rx1, List); re_match(Rx2, List).
re_match(star(Rx), List) :- append(List1, List2, List), re_match(Rx, List1), re_match(star(Rx), List2).

I'm not sure what change I need to make to get it to work right, but I'm not sure what else to do.

Also, changing List :- append(List1, List2, List) to [H|T] does not evaluate to true for one of the examples.

Martijn answered 22/1, 2011 at 7:18 Comment(1)
I can report that it works just fine in GNU Prolog...Opportuna
O
5

I don't have access to SWI Prolog right now, but here is a guess:

Try changing

re_match(star(Rx), List) :- append(List1, List2, List),
                            re_match(Rx, List1),
                            re_match(star(Rx), List2).

to

re_match(star(Rx), List) :- append([H|List1], List2, List),
                            re_match(Rx, [H|List1]),
                            re_match(star(Rx), List2).

to force re_match to "eat something" when it iterates on the star construct.

Opportuna answered 22/1, 2011 at 8:5 Comment(0)
T
6

Consider using DCG notation for better readability and to more easily reason about termination properties:

:- op(100, xf, *).

rexp(eps)      --> [].
rexp([T])      --> [T].
rexp(_*)       --> [].
rexp(R*)       --> rexp(R), rexp(R*).
rexp(s(R1,R2)) --> rexp(R1), rexp(R2).
rexp((R1|R2))    --> ( rexp(R1) ; rexp(R2) ).

Example using length/2 to generate increasingly longer lists to generate strings that are matched by the regexp:

?- length(Ls, _), phrase(rexp(s(([a]|[b]),[c]*)), Ls).
Ls = [a] ;
Ls = [b] ;
Ls = [a, c] ;
Ls = [b, c] ;
Ls = [a, c, c] ;
etc.
Teratology answered 22/1, 2011 at 10:5 Comment(3)
The termination argument is invalid. Counterexample: phrase(rexp(eps*),[a]). The list is of fixed length, but still the goal does not terminate.Electrotherapy
I guess it would be also posible to use the (.,.) notation, right? Or was there a particular reason for the choice of the s(.,.) notation?Cormophyte
@j4nbur53: I tend to avoid using ',' as functor, since , (comma) is already so overloaded in Prolog: it separates predicate arguments, list elements and denotes conjunction.Teratology
O
5

I don't have access to SWI Prolog right now, but here is a guess:

Try changing

re_match(star(Rx), List) :- append(List1, List2, List),
                            re_match(Rx, List1),
                            re_match(star(Rx), List2).

to

re_match(star(Rx), List) :- append([H|List1], List2, List),
                            re_match(Rx, [H|List1]),
                            re_match(star(Rx), List2).

to force re_match to "eat something" when it iterates on the star construct.

Opportuna answered 22/1, 2011 at 8:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.