all the advancing methods use this private method to actually advance the parser' position this means that the code to keep the line and column numbers up-to-date is kept in one place def advance_to_position(selfposition)while self pos positionself _advance_by_one(this method advances to given index position in the textagain using the private _advance_by_one(method def advance_up_to(selfcharacters)while (self pos len(self textand self text[self posnot in characters and self text[self posisspace())self _advance_by_one(if not self pos len(self text)return false if self text[self posin charactersreturn true raise lexerror("expected '{ }but got '{ }'format(charactersself text[self pos])this method advances over whitespace until the character at the current position is one of those in the given string of characters it differs from the other advance methods in that it can fail (since it might reach nonwhitespace character that is not one of the expected characters)it returns boolean to indicate whether it succeeded class lexerror(exception)pass this exception class is used internally by the parser we prefer to use custom exception rather thansayvalueerrorbecause it makes it easier to distinguish our own exceptions from python' when debugging data data(texttryparse(dataexcept lexerror as errraise valueerror("error {{ }}:{ }{ }formatdata location()err)return data stack[ the top-level parsing is quite simple we create an instance of the data class based on the text we want to parse and then we call the parse(function (which we will see in momentto perform the parsing if an error occurs custom lexerror is raisedwe simply convert this to valueerror to insulate any caller