key_values {lexer ply lex lex(lexer input(file read()key none for token in lexerif token type ="key"key token value elif token type ="value"if key is noneprint("failed to parsevalue '{ }without keyformat(token value)elsekey_values[keytoken value key none the lexer reads the entire input text and can be used as an iterator that produces one token at each iteration the token type attribute holds the name of the current token--this is one of the names from the tokens list--and the token value holds the matched text--or whatever we replaced it with for each tokenif the token is key we hold it and wait for its valueand if it is value we add it using the current key to the key_values dictionary at the end (not shown)we return the dictionary to the caller just as we did with the playlists py pls regex and pyparsing parsers playlist data parsing handcrafted parser pyparsing parser |in this subsection we will develop ply parser for the format and just as we did in the previous implementationsthe parser will return its results in the form of list of song (collections namedtuple()objectseach of which holds titlea duration in secondsand filename since the format is so simpleply' lexer is sufficient to do all the parsing as before we will create list of tokenseach one corresponding to nonterminal in the bnftokens (" ""info""seconds""title""filename" bnf we haven' got an entry token--this nonterminal is made up of seconds and title instead we define two statescalled entry and filename when the lexer is in the entry state we will try to read the seconds and the titlethat isan entryand when the lexer is in the filename state we will try to read the filename to make ply understand states we must create states variable that is set to list of one or more -tuples the first item in each of the tuples is state name and the second item is the state' typeeither inclusive ( this state is in addition to the current stateor exclusive ( this state is the only active