def exclusiveOr(expr):
    exclusiveList = []
    temp = []
    for char in expr:
        if (char == '|'):
            exclusiveList.append(temp)
            temp = []
            continue
        temp.append(char)
    exclusiveList.append(temp)

    #build FA in each elements in list
    faList = []
    for expr in exclusiveList:
        faList.append(exprToFA(expr))

    counter = 1
    list_end_subFA = []
    fa = FA({0}, set(), {}, 0, {0})
    fa.delta[(fa.q0, '')] = set()  #to prevent key error

    for sub_fa in faList:
        subFA = sub_fa.copy()
        subFA.Q = {i + counter for i in subFA.Q}
        new_delta = {}

        #update delta of subFA
        for i in subFA.delta:
            new_delta[(i[0] + counter,
                       i[1])] = {j + counter
                                 for j in subFA.delta[i]}
        subFA.delta = new_delta

        #update all attr of SubFA
        subFA.q0 += counter
        subFA.F = {list(subFA.F)[0] + counter}

        #join sigma and Q
        fa.Sigma = fa.Sigma | subFA.Sigma
        fa.Q = fa.Q | subFA.Q

        #connect transition
        fa.delta[(fa.q0, '')].add(subFA.q0)  #add empty move to join 2 FA
        fa.delta = {**fa.delta, **subFA.delta}  #combine dict
        list_end_subFA.append(list(subFA.F)[0])  #keep end state(s)

        #update counter
        counter = len(fa.Q)
    #connect to same end state
    fa.Q.add(counter)
    for end in list_end_subFA:  #set new end state
        fa.delta[(end, '')] = {counter}
    fa.F = {counter}

    return fa.copy()
def exprToFA(expr_list):
    fa = FA({0}, set(), {}, 0, {0})
    if ('*' in expr_list):
        return star(expr_list[0])
    elif ('|' in expr_list):
        return exclusiveOr(expr_list)

    for char in expr_list:
        if (type(char) == type(FA())):
            fa = join(fa, char)
        else:
            fa = concat(fa, char)
    return fa.copy()