Contributed by Simon Michaels. http://joyful.com/Ledger

fromStream: aStream " Parse a Ledger file. example: 2007/10/7 longs drugs expenses:business:phone $20 assets:cash $50 assets:wells-fargo:checking $0 grammar: ledgerfile = entry* entry = descriptionline, transactionline+ descriptionline = date, space, description, newline transactionline = space, accountname, space, amount, newline accountname = string [:, string]* amount = currency, quantity currency = $ quantity = number " | space space2 cr notcr date description descriptionline accountname amount transactionline transactionlines entry ledger spaceandamount | space := ' +' regex. space2 := ' +' regex. cr := Character cr asString. notcr := '[^' , cr , ']'. date := '(\d\d\d\d)/(\d\d?)/(\d\d?)' regex. description := ('(\w' , notcr , '*)') regex. accountname := ('[^: ' , cr , ']+(:[^: ' , cr , ']+)*') regex. amount := '\$\d+(\.\d+)?' regex. descriptionline := [aStream match: date and: space and: description and: cr action: [:l | LedgerEntry withDate: l first description: l third]]. spaceandamount := [aStream match: space2 and: amount action: [:l | l]]. transactionline := [aStream match: space and: accountname andMaybe: spaceandamount and: cr action: [:l | LedgerTransaction withAccount: l second amount: l fourth]]. transactionlines := [aStream matchOneOrMore: transactionline action: [:l | l]]. entry := [aStream match: descriptionline and: transactionlines and: cr action: [:l | l first transactions: l second]]. ledger := aStream matchZeroOrMore: entry action: [:l | Ledger withEntries: l]. ^ ledger