def read_actor_dictionary(actorfile):
    """ Reads a TABARI-style actor dictionary. """
    """
	Actor dictionary list elements:
	Actors are stored in a dictionary of a list of pattern lists keyed on the first word
	of the phrase. The pattern lists are sorted by length.
	The individual pattern lists begin with an integer index to the tuple of possible codes
	(that is, with the possibility of date restrictions) in PETRglobals.ActorCodes,
	followed by the connector from the key, and then a series of 2-tuples containing the
	remaining words and connectors. A 2-tuple of the form ('', ' ') signals the end of the
	list. <14.02.26: Except at the moment these are just 2-item lists, not tuples, but
	this could be easily changed and presumably would be more efficient: these are not
	changed so they don't need to be lists.<>

	Connector:
		blank: words can occur between the previous word and the next word
		_ (underscore): words must be consecutive: no intervening words

	The codes with possible date restrictions are stored as lists in a [genuine] tuple in
	PETRglobals.ActorCodes in the following format where
	'ordate' is an ordinal date:
		[code] : unrestricted code
		[0,ordate,code] : < restriction
		[1,ordate,code] : > restriction
		[2,ordate,ordate, code] : - (interval) restriction
	If PETRglobals.WriteActorRoot is True, the final element of a PETRglobals.ActorCodes
	list is the text of the actor at the beginning of the synonym list.

	Synonyms simply use the integer code index to point to these tuples.

	STRICT FORMATTING OF THE ACTOR DICTIONARY
	[With some additional coding, this can be relaxed, but anything following these
	rules should read correctly]
	Basic structure is a series of records of the form
		[primary phrase]
		[optional synonym phrases beginning with '+']
		[optional date restrictions beginning with '\t']

	Material that is ignored
	1. Anything following ';' (this is the old KEDS/TABARI format and should probably
	   be replaced with '#' for consistency
	2. Any line beginning with '#' or <!
	3. Any null line (that is, line consisting of only \n

	A "phrase string" is a set of character strings separated by either blanks or
	underscores.

	A "code" is a character string without blanks

	A "date" has the form YYYYMMDD or YYMMDD. These can be mixed, e.g.
		JAMES_BYRNES_  ; CountryInfo.txt
			[USAELI 18970101-450703]
			[USAGOV 450703-470121]

	Primary phrase format:
	phrase_string  { optional [code] }
		if the code is present, it becomes the default code if none of the date restrictions
		are satisfied. If it is not present and none of the restrictions are satisfied,
		this is equivalent to a null code

	Synonym phrase
	+phrase_string

	Date restriction
	\t[code restriction]
	where restriction -- everything is interpret as 'or equal' -- takes the form
	<date : applies to times before date
	>date : applies to times after date
	date-date: applies to times between dates

	A date restriction of the form
	\t[code]
	is the same as a default restriction.


	== Example ===
	# .actor file produced by translate.countryinfo.pl from CountryInfo.120106.txt
	# Generated at: Tue Jan 10 14:09:48 2012
	# Version: CountryInfo.120106.txt

	AFGHANISTAN_  [AFG]
	+AFGHAN_
	+AFGANISTAN_
	+AFGHANESTAN_
	+AFGHANYSTAN_
	+KABUL_
	+HERAT_

	MOHAMMAD_ZAHIR_SHAH_  ; CountryInfo.txt
		[AFGELI 320101-331108]
		[AFGGOV 331108-730717]
		[AFGELI 730717-070723]

	ABDUL_QADIR_  ; CountryInfo.txt
	+NUR_MOHAMMAD_TARAKI_  ; CountryInfo.txt
	+HAFIZULLAH_AMIN_  ; CountryInfo.txt
		[AFGELI 620101-780427]
		[AFGGOV 780427-780430]
		[AFGELI]

	HAMID_KARZAI_  [AFGMIL]; CountryInfo.txt
	+BABRAK_KARMAL_  ; CountryInfo.txt
	+SIBGHATULLAH_MOJADEDI_  ; CountryInfo.txt
		[AFGGOV 791227-861124]
		[AFGGOV 791227-810611]

	"""

    dateerrorstr = "String in date restriction could not be interpreted; line skipped"

    logger = logging.getLogger('petr_log')
    logger.info("Reading " + actorfile)
    open_FIN(actorfile, "actor")

    # location where codes for current actor will be stored
    codeindex = len(PETRglobals.ActorCodes)
    # list of codes -- default and date restricted -- for current actor
    curlist = []

    line = read_FIN_line()
    while len(line) > 0:  # loop through the file
        if '---STOP---' in line:
            break
        if line[0] == '\t':  # deal with date restriction
            # print "DR:",line,   # debug
            try:
                brack = line.index('[')
            except __HOLE__:
                logger.warning(dateerrorstr)
                line = read_FIN_line()
                continue
            part = line[brack + 1:].strip().partition(' ')
            code = part[0].strip()
            rest = part[2].lstrip()
            if '<' in rest or '>' in rest:
                # find an all-digit string: this is more robust than the TABARI
                # equivalent
                ka = 1
                while (ka < len(rest)) and (not rest[ka].isdigit()):
                    # if this fails the length test, it will be caught as
                    # DateError
                    ka += 1
                kb = ka + 6
                while (kb < len(rest)) and (rest[kb].isdigit()):
                    kb += 1
                try:
                    ord = dstr_to_ordate(rest[ka:kb])
                except DateError:
                    logger.warning(dateerrorstr)
                    line = read_FIN_line()
                    continue

                if rest[0] == '<':
                    curlist.append([0, ord, code])
                else:
                    curlist.append([1, ord, code])
            elif '-' in rest:
                part = rest.partition('-')
                try:
                    pt0 = part[0].strip()
                    ord1 = dstr_to_ordate(pt0)
                    part2 = part[2].partition(']')
                    pt2 = part2[0].strip()
                    ord2 = dstr_to_ordate(pt2)
                except DateError:
                    logger.warning(dateerrorstr)
                    line = read_FIN_line()
                    continue
                if ord2 < ord1:
                    logger.warning(
                        "End date in interval date restriction is less than starting date; line skipped")
                    line = read_FIN_line()
                    continue
                curlist.append([2, ord1, ord2, code])
            else:  # replace default code
                # list containing a single code
                curlist.append([code[:code.find(']')]])

        else:
            if line[0] == '+':  # deal with synonym
                #				print "Syn:",line,
                part = line.partition(';')  # split on comment, if any
                actor = part[0][1:].strip() + ' '
            else:  					# primary phrase with code
                if len(curlist) > 0:
                    if PETRglobals.WriteActorRoot:
                        curlist.append(rootactor)
#                    print(curlist)
                    PETRglobals.ActorCodes.append(
                        tuple(curlist))  # store code from previous entry
                    """print(PETRglobals.ActorCodes[-1])
                    thelist = PETRglobals.ActorCodes[-1]
                    for item in thelist:
                        if not isinstance(item,list):
                            print('== Actor',item)"""
                    codeindex = len(PETRglobals.ActorCodes)
                    curlist = []
                if '[' in line:  # code specified?
                    part = line.partition('[')
                    # list containing a single code
                    curlist.append([part[2].partition(']')[0].strip()])
                else:
                    # no code, so don't update curlist
                    part = line.partition(';')
                actor = part[0].strip() + ' '
                rootactor = actor
            nounlist = make_noun_list(actor)
            keyword = nounlist[0][0]
            phlist = [codeindex, nounlist[0][1]] + nounlist[1:]
            # we don't need to store the first word, just the connector
            if keyword in PETRglobals.ActorDict:
                PETRglobals.ActorDict[keyword].append(phlist)
            else:
                PETRglobals.ActorDict[keyword] = [phlist]
            if isinstance(phlist[0], str):
                # save location of the list if this is a primary phrase
                curlist = PETRglobals.ActorDict[keyword]

        line = read_FIN_line()

    close_FIN()
#    <14.11.20: does this need to save the final entry? >

    # sort the patterns by the number of words
    # for lockey in list(PETRglobals.ActorDict.keys()):
    #    PETRglobals.ActorDict[lockey].sort(key=len, reverse=True)
dataset/ETHPy150Open openeventdata/petrarch/petrarch/PETRreader.py/read_actor_dictionary