# # # # # # # # # # # # # # # # # # # # # # # # # # # #
#  Framework provided by Daan de Graaf(UvA)           #
#  For Automaten en Formele Talen                     #
#  Under Guidance of Inge Bethke(UvA)                 #
#  Last edited 2018-04-05 by Bas van den Heuvel (UvA) #
# # # # # # # # # # # # # # # # # # # # # # # # # # # #


class Rule():
    def __init__(self, _lhs, _rhs, _id):
        '''Initializes grammar rule: LHS -> [RHS]'''
        self.lhs = _lhs
        self.rhs = _rhs
        self.id = _id


class CFG(object):
    def __init__(self, grammar):
        self.input_grammar = grammar
        if len(grammar) == 0:
            exit('Empty grammar found')
        self.rules = {}
        self.readGrammar()
        self.symbols = set(symbol
                           for rule in self.rules.values()
                           for symbol in [rule.lhs] + rule.rhs)
        self.nonTerminals = set(rule.lhs for rule in self.rules.values())
        self.terminals = self.symbols - self.nonTerminals

    def isNonTerminal(self, element):
        if element in self.nonTerminals:
            return True
        return False

    def isTerminal(self, element):
        if element in self.terminals:
            return True
        return False

    def show(self):
        for rule in self.rules.values():
            print('{' + str(rule.id) + '} ' + rule.lhs + ' -> ' +
                  ' '.join(rule.rhs))

    def readGrammar(self):
        lines = self.input_grammar.strip().split('\n')
        for line_number in range(len(lines)):
            line = lines[line_number]
            rule = line.split('->')
            if len(rule) != 2:
                exit('GrammarError: Check "->" in grammar on line ' +
                     str(line_number + 1))
            LHS = rule[0].strip().split('} ')
            rule_num = LHS[0][1:]
            LHS = LHS[1]
            try:
                rule_num = int(rule_num)
            except Exception:
                exit('GrammarError: Problem found in brackets on line ' +
                     str(line_number + 1))

            rhs = rule[1].strip()
            if len(rhs) == 0:
                exit('GrammarError: No right hand side on line ' +
                     str(line_number + 1))
            symbols = rhs.split(' ') if rhs else []
            RHS = []
            for symbol in symbols:
                RHS.append(symbol)
            rule = Rule(LHS, RHS, rule_num)
            self.rules[rule_num] = rule
