7.1.4(b) L={wcw^R : w in {a,b}*} Idea: Until we read a 'c', for each 'a' read from the input push an 'A' and for each 'b' push a 'B'. The result will be that the string read before the 'c' will be "upside down" on the stack. When a 'c' is read make sure not to alter the stack and then only allow a character to be read from the input if it matches the top stack symbol, at which point it is popped off. After arriving at the bottom of stack symbol, the machine can transition to a final state. If w^R is in fact after the 'c', then this will result in the machine ending in a final state after reading the entire string. States: q0 --- read in the string w and put it on stack in reverse order q1 --- read in w^R qf --- final state Transitions: delta(q0,a,Z) = {(q0,AZ)} ;; for each 'a' push an 'A' on the stack delta(q0,a,A) = {(q0,AA)} delta(q0,a,B) = {(q0,AB)} delta(q0,b,Z) = {(q0,BZ)} ;; for each 'b' push a 'B' on the stack delta(q0,b,A) = {(q0,BA)} delta(q0,b,B) = {(q0,BB)} delta(q0,c,Z) = {(q1,Z)} ;; when a 'c' is read move to state q1 delta(q0,c,A) = {(q1,A)} ;; leaving the stack unaltered delta(q0,c,B) = {(q1,B)} delta(q1,a,A) = {(q1,lambda)} ;; if the input character matches the delta(q1,b,B) = {(q1,lambda)} ;; the top of stack then read it an ;; pop top symbol off stack delta(q1,lambda,Z) = {(qf,lambda)} ;; if we are at the bottom of stack ;; move to final state ;; if input has been read then ;; string will be accepted ************************************************ 7.1.4(d) L={a^n b^{n+m} c^m: n, m >= 0} Idea: Push all A's on the stack, one for each a. When b's start showing up, pop each A for a b. If all A's are popped, push a B for each additional b. Finally pop a B for each c. If the stack is empty exactly when the input is over, then accept. The number of b's must equal the number of a's + number of c's. We alse need a state change for the end of each episode. States: q0 -- reading a's (initial state) q1 -- reading b's and popping A's q2 -- reading b's and pushing B's q3 -- reading c's qf -- final state. delta(q0,a,Z) = {(q0,AZ)} ; push A's while reading a's. delta(q0,b,Z) = {(q2,BZ)} ; no a's. Push b and change to q2. delta(q0,b,A) = {(q1,lambda)} ; first b after some a's. pop A and change to q1. delta(q1,b,A) = {(q1,lambda)} ; other b's. Keep popping A's delta(q1,b,Z) = {(q2,BZ)} ; All A's are popped. Change to q2. Push B. ********************************************* 7.1.4(i) L = {w | n_a(w) + n_b(w) = n_c(w)} Idea: Suppose the stack symbol X represents a or b, and Y represents c. If there are more a's or b's read at any time than the number of c's, the stack will have X's on it. If there are more c's read than a's or b's, the stack will have Y's on it. So when we read a's or b's, if there is alraedy a Y on the stack, pop it. Otherwise push an X. Similarly if we read a c, if there is already an X on the stack, pop it. Otherwise push a Y. States: q0 -- initial state. qf -- final state. delta(q0,a,Z) = {(q0,XZ)} ; push X on seeing a if the stack is empty delta(q0,a,X) = {(q0,XX)} ; or has Xs delta(q0,b,Z) = {(q0,XZ)} ; push X on seeing b if the stack is empty delta(q0,b,X) = {(q0,XX)} ; or has Xs delta(q0,c,Z) = {(q0,YZ)} ; push Y on seeing c if the stack is empty delta(q0,c,Y) = {(q0,YY)} ; or has Ys delta(q0,c,X) = {(q0,lambda)} ; pop X on seeing c delta(q0,a,Y) = {(q0,lambda)} ; pop Y on seeing a delta(q0,b,Y) = {(q0,lambda)} ; pop Y on seeing b delta(q0,lambda,Z) = {(qf,lambda)} ; accept if the stack is empty at the end ***************************************** 7.1.4(k) L = {w : n_a(w) < n_b(w)} Idea: We will use the stack to keep track of how many more b's there are than a's and vice versa. The stack will contain either a sequence of B's or a sequence of A's. If B's are on the stack then the number of B's represents how many more b's have been read in than a's and vice versa if there are A's on the stack. Given such a machine we can transition to a final state whenever there is a B on the top of the stack, indicating that up to that up to that point in the string there are more b's than a's. States: q0 --- keeps track of the excess a's or b's qf --- final state Transitions: delta(q0,a,Z) = {(q0,AZ)} ;; indicates we have seen one more 'a' ;; than b's delta(q0,a,A) = {(q0,AA)} ;; increment the excess a's delta(q0,a,B) = {(q0,lambda)} ;; decrement the excess b's delta(q0,b,Z) = {(q0,BZ)} ;; indicates we have seen one more 'b' ;; than a's delta(q0,b,A) = {(q0,lambda)} ;; decrement the excess a's delta(q0,b,B) = {(q0,BB)} ;; increment the excess b's delta(q0,lambda,B) = {(qf,lambda)} ******************************************* 7.1.17 Notice that the definition of N(M) = {w : (q0,w,z) |-* (p,lambda,lambda)}, for p in Q will accept a string regardless of whether the machine ends up in a final state, so long as the stack is empty. Given a machine M with the language L(M) as given by the standard definition we will show how to create a new machine M' such that N(M')= L(M). We must ensure two things. First, that for ever string w in L(M) that M' is able to read in w while emptying the stack. Second, we must ensure that for every string w for which M' is able to empty the stack that w is in L(M). To do this we will start with the machine M and add a new initial state q' and a new final state qf. We will also add a new stack symbol z'. The initial state will place z' on the bottom of the stack (under z) and then transition to the initial state of M from which operation can proceed normally. From each final state of M we will add lambda transitions to qf. The state qf will only have self transitions that do not read in any input but empty the stack including z'. The idea behind the construction is as follows. For any string w in L(M), the machine M' will be driven to a final state of M after reading all of the input. At that point the machine M' will be able to transition to qf and then empty the stack and hence w will be in N(M') as desired. Now consider any string w in N(M'), meaning that w can be read in by M' while emptying the stack. Since M did not include any transitions that refer to z', and z' is on the bottom of the stack, the only way for M' to empty the stack is for the machine to be in state qf. But since it is only possible to get to qf from a final state of M, it must be the case that w could have also been accepted by M and thus be in L(M). ******************************************* Section 7.2.5 S -> aABB | aAA, A -> aBB | a, B -> bBB | A We first need to convert the grammar to Griebach Normal Form. In this case, the only rule that is not in the proper form is the unit production B -> A. Here it is a simple matter to replace B -> A with B -> aBB | a. The resulting grammar is in Griebach Normal Form and equivalent to the original. So we can now use the straightforward procedure in the book to convert the grammar to a PDA description. Here is a translation: Initial move: delta(q0, lambda, Z) = {(q1, SZ)} Because S -> aABB | aAA delta(q1, a, S) = {(q1, ABB), (q1, AA)} Because A -> aBB | a delta(q1, a, A) = {(q1, BB), (q1, lambda)} Because B -> bBB delta(q1, b, B) = {(q1, BB)} Because B -> aBB | a. delta(q1, a, B) = {(q1, BB), (q1, lambda)} Final move: delta(q1, lambda, Z) = {(q2, lambda)} where q0 is the initial state and q2 is the final state. **************************************** Section 8.2.3 Let h be our homomorphism, which simply gives a mapping from characters of the alphabet to strings. Assume that L is a context-free language. This means that it has a CFG G such that L = L(G). Below we create a new CFG G' such that h(L) = L(G'). Since G' is a CFG we have that h(L) is context free and hence context-free languages are closed under homomorphisms. There are several ways to construct such a G', here I give just one. Let V, T, and P be the variables, terminals, and production rules of the grammar. The idea behind our construction is that G' will treat the terminals of G as variables and will add new rules that will map each of those new variables to terminal strings as specified by the homomorphism. The new grammar G' will generate strings for h(L) by first generating a sequence of non-terminals corresponding to a string in L and then mapping those non-terminals to terminal strings as specified by h. The details of G' are as follows. V' = V union T T' = characters in the range of h P' = P union H where H is the set of rules {a -> h(a) : a \in T}. All other components of G' are the same as G.