Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting context-free grammar to pushdown automata in Prolog

Tags:

prolog

dcg

I need to get the delta function of a non-deterministic pushdown automaton from a context-free grammar in DCG form, and the algorithm for doing this is very simple:


For every rule A --> B in the grammar, add a transition [q1, lambda, A] --> [B] to the delta function.

For every rule E --> c in the grammar, add a transition [q1, c, c] --> [lambda] to the delta function.

Add the transitions [q0, lambda, z0] --> [q1, S*z0] and [q1, lambda, z0] --> [q2, z0] to the delta function.

Every uppercase letter is a non-terminal symbol, and every lowercase letter is a terminal symbol. lambda is the empty string, S is the initial symbol of the grammar, * is the concatenation operator and z0 is the symbol on the top of the stack.


This means the grammar

S --> A*b | B | y
A --> w*x | x
B --> A*b

generates a pushdown automaton with the delta function

[q0, lambda, z0] --> [q1, S*z0]
[q1, lambda, S] --> [q1, A*b]
[q1, lambda, S] --> [q1, B]
[q1, lambda, S] --> [q1, y]
[q1, lambda, A] --> [q1, w*x]
[q1, lambda, A] --> [q1, x]
[q1, lambda, B] --> [q1, A*b]
[q1, b, b] --> [q1, lambda]
[q1, w, w] --> [q1, lambda]
[q1, x, x] --> [q1, lambda]
[q1, y, y] --> [q1, lambda]
[q1, lambda, z0] --> [q2, z0]

I have to implement this algorithm in Prolog (getting a grammar from user and returning the delta function) and I'm confused because this is my first time using a logic programming language.

I thought I could maybe translate the grammar into its predicate form and then "iterating" over all the predicates, and somehow adding the already "traversed" predicates to a list, so I can process this list and return the delta function. But I think this is some sort of really complicated imperative way of doing things and using Prolog for this would be pointless.

Maybe there's a more elegant solution for this problem, so I'd like to know if such solution exists.

like image 634
user1002327 Avatar asked Dec 11 '25 20:12

user1002327


1 Answers

Here a possible coding

g2nfa(Grammar, Delta) :-
    maplist(transitions, Grammar, DeltaT),
    append(DeltaT, DeltaF),
    Initial = (q0, lambda, z0 --> q1, 'S'*z0),
    Final = (q1, lambda, z0 --> q2, z0),
    append([[Initial], DeltaF, [Final]], Delta).

transitions(Sym --> Alternatives, Transitions) :-
    phrase(transition(Sym, Alternatives), Transitions).

transition(Sym, A|As) --> state(Sym, A), !, transition(Sym, As).
transition(Sym, A) --> state(Sym, A).
state(Sym, A) --> [(q1, lambda, Sym --> q1, A)].

test :-
    g2nfa([( 'S' --> 'A'*b | 'B' | y ),
           ( 'A' --> w*x | x ),
           ( 'B' --> 'A'*b )
          ], T), maplist(writeln, T).

that seems to satisfy your requirements

?- test.
q0,lambda,z0-->q1,S*z0
q1,lambda,S-->q1,A*b
q1,lambda,S-->q1,B
q1,lambda,S-->q1,y
q1,lambda,A-->q1,w*x
q1,lambda,A-->q1,x
q1,lambda,B-->q1,A*b
q1,lambda,z0-->q2,z0
true.

so you can work out the syntactic details. Note that the second rewrite rule (For every rule E --> c in the grammar, add a transition [q1, c, c] --> [lambda] to the delta function.) has not been applied in your sample.

like image 155
CapelliC Avatar answered Dec 14 '25 15:12

CapelliC



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!