Explanation for Ex1 :
I'm starting with $L1$
$L1= \{w\in\{a,b\}^*|n_a(w)=n_b(w)\}$
Well, I hope you know, Operation PUSH() and POP() on STACK.
How we identify the string which belong in language $L1$; pseudocode is :
- Take an empty STACK.
- PUSH each 'a' on STACK; whenever you found in string.
- POP single 'a' from STACK for each 'b'; whenever you found in string.
- If you reach end of string, and final STACK is empty, then given string is in language $L1$; else not.
Note that if the string starts with 'b' then you must exchange a and b on above pseudocode.
$\text{Since you can identify strings of L1 using single STACK, hence given language is context free.}$
Your grammar is correct for $L1$. Similarly you can find the language $L2$ is also context free, by replacing 'c' with 'b'.
Note that languages $L1$ and $L2$ can not be regular, since we can't do matching without STACK. Both languages are DCFL.
Now take language $L=\{w\in\{a,b,c\}^*|n_a(w)=n_b(w)=n_c(w)\}$
For three alphabet, we can't do matching with single STACK. We need atleast two STACKs; pseudocode is :
- Take two stack; STACK1 and STACK2.
- PUSH each 'a' on STACK1; whenever you found in string.
- PUSH each 'b' on STACK2; whenever you found in string.
- POP single 'a' from STACK1 and POP single 'b' from STACK1 for each 'c'; whenever you found in string.
- If both STACKs are empty, then given string is in language $L$; else not.
Note that if the string starts with 'b' or 'c' then you must exchange a and b or a and c respectively on above pseudocode.
$\text{Since you can identify strings of L using TWO STACK, hence given language is context sensitive.}$
Explanation for Ex2 :
$L = \{a^nb^mc^nd^m | n, m > 0\}$ is not context free, since we can't identify the strings of $L$ using single STACK; pseudocode is :
- Take two stack; STACK1 and STACK2.
- PUSH each 'a' on STACK1; whenever you found in string.
- PUSH each 'b' on STACK2; whenever you found in string.
- POP single 'a' from STACK1 for each 'c'; whenever you found in string.
- POP single 'b' from STACK2 for each 'd'; whenever you found in string.
- If both STACKs are empty, then given string is in language $L$; else not.
Grammar for $L$ is :
$$
\begin{align*}
&S \to XY \\
&X \to aXC | aC \\
&Y \to BYd | Bd \\
&CB \to BC \\
&aB \to ab \\
&bB \to bb \\
&Cd \to cd \\
&Cc \to cc \\
\end{align*}
$$
$\text{Note that above grammar for $L$ is context sensitive.}$
Explanation for Ex3 :
I'm taking language $L2$ first, $L2=\{a^nb^n|n\geq0\}$
Pumping lemma for regular languages
Let L = {ambm | m ≥ 1}.
Then L is not regular.
Proof: Let n be as in Pumping Lemma.
Let w = anbn.
Let w = xyz be as in Pumping Lemma.
Thus, xy2z ∈ L, however, xy2z contains more a’s than b’s.
You need a stack for matching; pseudocode is :
- Take an empty STACK.
- PUSH each 'a' on STACK; whenever you found in string.
- POP single 'a' from STACK; whenever you found in string.
- If you reach end of string, and final STACK is empty, then given string is in language $L2$; else not.
Strings of $L1 =\{ab, aabb, aaabbb,....,a^nb^n\}$ and grammar for $L1$ is :
$$S→aSb | ab$$
Strings of $L2 =\{\in, ab, aabb, aaabbb,....,a^nb^n\}$ and grammar for $L2$ is :
$$S→aSb | \in$$
Therefore, $$L2= \{\in + L1\}$$
$\text{Both $L1$ and $L2$ are DCFL, since we need STACK for matching. We can't matching in NFA/DFA.}$