_A=None
from typing import Optional,Iterator,Tuple,List
from parso.python.tokenize import tokenize
from parso.utils import parse_version_string
from parso.python.token import PythonTokenTypes
class NFAArc:
	def __init__(A,next_,nonterminal_or_string):A.next=next_;A.nonterminal_or_string=nonterminal_or_string
	def __repr__(A):return'<%s: %s>'%(A.__class__.__name__,A.nonterminal_or_string)
class NFAState:
	def __init__(A,from_rule):A.from_rule=from_rule;A.arcs=[]
	def add_arc(C,next_,nonterminal_or_string=_A):B=next_;A=nonterminal_or_string;assert A is _A or isinstance(A,str);assert isinstance(B,NFAState);C.arcs.append(NFAArc(B,A))
	def __repr__(A):return'<%s: from %s>'%(A.__class__.__name__,A.from_rule)
class GrammarParser:
	'\n    The parser for Python grammar files.\n    '
	def __init__(A,bnf_grammar):B=bnf_grammar;A._bnf_grammar=B;A.generator=tokenize(B,version_info=parse_version_string('3.9'));A._gettoken()
	def parse(A):
		while A.type!=PythonTokenTypes.ENDMARKER:
			while A.type==PythonTokenTypes.NEWLINE:A._gettoken()
			A._current_rule_name=A._expect(PythonTokenTypes.NAME);A._expect(PythonTokenTypes.OP,':');B,C=A._parse_rhs();A._expect(PythonTokenTypes.NEWLINE);yield(B,C)
	def _parse_rhs(A):
		B,C=A._parse_items()
		if A.value!='|':return B,C
		else:
			D=NFAState(A._current_rule_name);E=NFAState(A._current_rule_name)
			while True:
				D.add_arc(B);C.add_arc(E)
				if A.value!='|':break
				A._gettoken();B,C=A._parse_items()
			return D,E
	def _parse_items(A):
		C,B=A._parse_item()
		while A.type in(PythonTokenTypes.NAME,PythonTokenTypes.STRING)or A.value in('(','['):D,E=A._parse_item();B.add_arc(D);B=E
		return C,B
	def _parse_item(B):
		if B.value=='[':B._gettoken();A,C=B._parse_rhs();B._expect(PythonTokenTypes.OP,']');A.add_arc(C);return A,C
		else:
			A,C=B._parse_atom();D=B.value
			if D not in('+','*'):return A,C
			B._gettoken();C.add_arc(A)
			if D=='+':return A,C
			else:return A,A
	def _parse_atom(A):
		if A.value=='(':A._gettoken();B,C=A._parse_rhs();A._expect(PythonTokenTypes.OP,')');return B,C
		elif A.type in(PythonTokenTypes.NAME,PythonTokenTypes.STRING):B=NFAState(A._current_rule_name);C=NFAState(A._current_rule_name);B.add_arc(C,A.value);A._gettoken();return B,C
		else:A._raise_error('expected (...) or NAME or STRING, got %s/%s',A.type,A.value)
	def _expect(A,type_,value=_A):
		C=type_;B=value
		if A.type!=C:A._raise_error('expected %s, got %s [%s]',C,A.type,A.value)
		if B is not _A and A.value!=B:A._raise_error('expected %s, got %s',B,A.value)
		B=A.value;A._gettoken();return B
	def _gettoken(A):B=next(A.generator);A.type,A.value,A.begin,C=B
	def _raise_error(B,msg,*C):
		A=msg
		if C:
			try:A=A%C
			except:A=' '.join([A]+list(map(str,C)))
		D=B._bnf_grammar.splitlines()[B.begin[0]-1];raise SyntaxError(A,('<grammar>',B.begin[0],B.begin[1],D))