Introduction to Languages and the Theory of Computation