Introduction to theory of computation