Крайне неэффективно вычислять ПЕРВЫЕ наборы по одному, поскольку они взаимозависимы. Например, чтобы вычислить ПЕРВЫЙ набор из A
, вам также необходимо вычислить ПЕРВЫЙ набор из B
, а затем, поскольку B
может получить строку emoty, вам необходим ПЕРВЫЙ набор из Q
.
Большинство алгоритмов вычисляют их все параллельно, используя некоторые варианты алгоритма транзитивного замыкания. Вы можете сделать это с помощью поиска в глубину, который, кажется, является тем, что вы пытаетесь, но может быть проще реализовать алгоритм наименьшей фиксированной точки, описанный в книге Дракона (и Википедия .
В любом случае, вам, вероятно, будет проще сначала вычислить NULLABLE (то есть, какие нетерминалы получают пустое множество). Для этого существует простой алгоритм линейного времени (линейный по размеру грамматики), который, опять же, легко найти.
Если вы выполняете эту работу как часть класса, вы, вероятно, найдете соответствующие алгоритмы в своих материалах курса. Кроме того, вы можете найти копию книги Дракона или других подобных учебников.