global defs

record nonterm(name)

procedure main()
   local line
   defs := table()
   while line := read() do
      (define | generate)(line)
end

procedure define(line)
   return line ?
      defs[(="<",tab(find(">::=")))] := (move(4),alts(tab(0)))
end

procedure alts(defn)
   local alist
   alist := []
   defn ? while put(alist,syms(tab(many(~'|')))) do move(1)
   return alist
end

procedure syms(alt)
   local slist
   slist := []
   alt ? while put(slist,tab(many(~'<')) |
      nonterm(2(="<",tab(upto('>')),move(1))))
   return slist
end

procedure generate(line)
   local goal, count
   line ? {
      ="<" &
      goal := tab(upto('>')) &
      move(1) &
      count := tab(0)
      }
   every write(gener(goal)) \ count
   return
end

procedure gener(goal)
   local pending, genstr, symbol
   repeat {
      pending := [nonterm(goal)]
      genstr := ""
      while symbol := get(pending) do
         if type(symbol) == "string" then genstr ||:= symbol
         else pending := ?defs[symbol.name] ||| pending
      suspend genstr
      }
end
