docs: def _mkpda(self, nonterms, productions, productions_struct, terminals, splitstring=1):
          """
          This function generates a PDA from a CNF grammar as described in:
            -  http://www.oit.edu/faculty/sherry.yang/CST229/Lectures/7_pda.pdf
            -  http://www.eng.utah.edu/~cs3100/lectures/l18/pda-notes.pdf
  
          If all of the grammar productions are in the Chomsky Normal Form,
          then follow the template for constructing a pushdown symautomata:
  
          1. Start
          2. Push S
          3. Pop
          4. Case:
              Nonterminal A: For every production rule of this form: A: BC, Push C and then Push B
  
          Args:
               nonterms (list): Non terminals list
               productions (dict): productions in the CNF form:
                                      A -> a or A -> b0b1, or S -> e
               productions_struct (dict):  productions in the CNF form in structure form
                                      object.a for A -> a,
                                      object.b0 and object.b1 for A -> b0b1
                                      and object.type where type is
                                          1 for A-->a and 2 for A-->b0b1
               terminals (list): All terminals
               splitstring (bool): If enabled an extra space is added after each symbol.
          Returns:
              PDA: The generated PDA
          """
          pda = PDA(self.alphabet)
          pda.nonterminals = nonterms
          pda.terminals = terminals
  
          pda.s[pda.n] = PDAState()
          pda.s[pda.n].id = pda.n
          pda.s[pda.n].sym = '@closing'
          pda.s[pda.n].type = 1
          pda.s[pda.n].trans[1] = [0]
  
          pda.n = pda.n + 1
          pda.s[pda.n] = PDAState()
          pda.s[pda.n].id = pda.n
          pda.s[pda.n].type = 1
          pda.s[pda.n].sym = nonterms[0]
          pda.s[pda.n].trans[2] = [0]
  
          pda.n = pda.n + 1
          pda.s[pda.n] = PDAState()
          pda.s[pda.n].id = pda.n
          pda.s[pda.n].type = 2
          pda.s[pda.n].trans[0] = ['@closing']
  
          counter = 0
          i = 0
          while i < len(nonterms):
              j = 0
              while j < len(productions[nonterms[i]]):
                  if productions_struct[counter].type == 1:
                      # ADD AND CONNECT STATE
                      pda.n = pda.n + 1
                      pda.s[pda.n] = PDAState()
                      pda.s[pda.n].id = pda.n
                      if pda.n not in pda.s[2].trans:
                          pda.s[2].trans[pda.n] = []
                      pda.s[2].trans[pda.n].append(nonterms[i])
  
                      if splitstring == 0:
  
                          # FILL NEW STATE  READ
                          pda.s[pda.n].type = 3
                          pda.s[pda.n].trans[2] = [productions_struct[counter].a]
  
                      else:
                          # THE FOLLOWIN SWITCH IS DUE TO THE REQUIREMENT OF
                          # HAVING STRINGS SPLITTED TO SYMBOLS AND CAN INTERSECT
                          # WITH DFA
  
                          if productions_struct[counter].a not in terminals or \
                                          len(productions_struct[counter].a) == 1:
                              # FILL NEW STATE  READ
                              pda.s[pda.n].type = 3
                              pda.s[pda.n].trans[pda.n + 1] = [productions_struct[counter].a.lower()]
                              pda.n = pda.n + 1
                              pda.s[pda.n] = PDAState()
                              pda.s[pda.n].id = pda.n
                              pda.s[pda.n].type = 3
                              pda.s[pda.n].trans[2] = [' ']
  
                          else:
                              pda.s[pda.n].type = 3
                              pda.s[pda.n].trans[pda.n + 1] = \
                                  [productions_struct[counter].a[0].lower()]
                              k = 1
                              while k < len(productions_struct[counter].a) - 1:
                                  pda.n = pda.n + 1
                                  pda.s[pda.n] = PDAState()
                                  pda.s[pda.n].id = pda.n
                                  pda.s[pda.n].type = 3
                                  pda.s[pda.n].trans[pda.n +1] = \
                                      [productions_struct[counter].a[k].lower()]
                                  k = k + 1
                              pda.n = pda.n + 1
                              pda.s[pda.n] = PDAState()
                              pda.s[pda.n].id = pda.n
                              pda.s[pda.n].type = 3
  
                              pda.s[pda.n].trans[pda.n + 1] = \
                                  [productions_struct[counter].a[-1].lower()]
                              pda.n = pda.n + 1
                              pda.s[pda.n] = PDAState()
                              pda.s[pda.n].id = pda.n
                              pda.s[pda.n].type = 3
                              pda.s[pda.n].trans[2] = [' ']
  
                  else:
                      # ADD AND CONNECT PUSH STATE
                      pda.n = pda.n + 1
                      pda.s[pda.n] = PDAState()
                      pda.s[pda.n].id = pda.n
                      if pda.n not in pda.s[2].trans:
                          pda.s[2].trans[pda.n] = []
                      pda.s[2].trans[pda.n].append(nonterms[i])
  
                      # FILL NEW STATE
                      pda.s[pda.n].type = 1
                      pda.s[pda.n].sym = productions_struct[counter].b1
                      pda.s[pda.n].trans[(pda.n) + 1] = [0]
  
                      # ADD AND CONNECT PUSH STATE (ALREADY CONNECTED)
                      pda.n = pda.n + 1
                      pda.s[pda.n] = PDAState()
                      pda.s[pda.n].id = pda.n
  
                      # FILL NEW STATE
                      pda.s[pda.n].type = 1
                      pda.s[pda.n].sym = productions_struct[counter].b0
                      pda.s[pda.n].trans[2] = [0]
  
                  j = j + 1
                  counter = counter + 1
  
              i = i + 1
          return pda