/* Computation of FIRST stets */

#include "pgenheaders.h"
#include "grammar.h"
#include "token.h"

extern int Py_DebugFlag;

/* Forward */
static void calcfirstset(grammar *, dfa *);

void
addfirstsets(grammar *g)
{
       int i;
       dfa *d;

       if (Py_DebugFlag)
               printf("Adding FIRST sets ...\n");
       for (i = 0; i < g->g_ndfas; i++) {
               d = &g->g_dfa[i];
               if (d->d_first == NULL)
                       calcfirstset(g, d);
       }
}

static void
calcfirstset(grammar *g, dfa *d)
{
       int i, j;
       state *s;
       arc *a;
       int nsyms;
       int *sym;
       int nbits;
       static bitset dummy;
       bitset result;
       int type;
       dfa *d1;
       label *l0;

       if (Py_DebugFlag)
               printf("Calculate FIRST set for '%s'\n", d->d_name);

       if (dummy == NULL)
               dummy = newbitset(1);
       if (d->d_first == dummy) {
               fprintf(stderr, "Left-recursion for '%s'\n", d->d_name);
               return;
       }
       if (d->d_first != NULL) {
               fprintf(stderr, "Re-calculating FIRST set for '%s' ???\n",
                       d->d_name);
       }
       d->d_first = dummy;

       l0 = g->g_ll.ll_label;
       nbits = g->g_ll.ll_nlabels;
       result = newbitset(nbits);

       sym = (int *)PyObject_MALLOC(sizeof(int));
       if (sym == NULL)
               Py_FatalError("no mem for new sym in calcfirstset");
       nsyms = 1;
       sym[0] = findlabel(&g->g_ll, d->d_type, (char *)NULL);

       s = &d->d_state[d->d_initial];
       for (i = 0; i < s->s_narcs; i++) {
               a = &s->s_arc[i];
               for (j = 0; j < nsyms; j++) {
                       if (sym[j] == a->a_lbl)
                               break;
               }
               if (j >= nsyms) { /* New label */
                       sym = (int *)PyObject_REALLOC(sym,
                                               sizeof(int) * (nsyms + 1));
                       if (sym == NULL)
                               Py_FatalError(
                                   "no mem to resize sym in calcfirstset");
                       sym[nsyms++] = a->a_lbl;
                       type = l0[a->a_lbl].lb_type;
                       if (ISNONTERMINAL(type)) {
                               d1 = PyGrammar_FindDFA(g, type);
                               if (d1->d_first == dummy) {
                                       fprintf(stderr,
                                               "Left-recursion below '%s'\n",
                                               d->d_name);
                               }
                               else {
                                       if (d1->d_first == NULL)
                                               calcfirstset(g, d1);
                                       mergebitset(result,
                                                   d1->d_first, nbits);
                               }
                       }
                       else if (ISTERMINAL(type)) {
                               addbit(result, a->a_lbl);
                       }
               }
       }
       d->d_first = result;
       if (Py_DebugFlag) {
               printf("FIRST set for '%s': {", d->d_name);
               for (i = 0; i < nbits; i++) {
                       if (testbit(result, i))
                               printf(" %s", PyGrammar_LabelRepr(&l0[i]));
               }
               printf(" }\n");
       }

       PyObject_FREE(sym);
}