penny-bin-0.6.0.0: doc/ledger-grammar.org
* Terminals
AllPoints = { c | c >= U+0000, c <= U+10ffff }
Invalid = { c | c >= U+D800, c <= U+DFFF }
Unicode = { x ∈ AllPoints | x ∉ Invalid }
Newline = { U+000A }
Space = { U+0020 }
Tab = { U+0009 }
White = { Space Tab }
NonNewline = { x ∈ Unicode | x ∉ Newline }
NonNewlineNonSpace = { x ∈ NonNewline | x ∉ White }
UpperCaseAscii = { x | x >= 'A', x <= 'Z' }
LowerCaseAscii = { x | x >= 'a', x <= 'z' }
Digit = { x | x >= '0', x <= '9' }
NonAscii = { x ∈ NonNewline | x > U+007f }
Letter = UpperCaseAscii ∪ LowerCaseAscii ∪ NonAscii
Dollar = { '$' }
Colon = { ':' }
OpenCurly = { '{' }
CloseCurly = { '}' }
OpenSquare = { '[' }
CloseSquare = { ']' }
DoubleQuote = { '"' }
Period = { '.' }
Hash = { '#' }
ThinSpace = { U+2009 }
DateSep = { '/', '-' }
Plus = { '+' }
Minus = { '-' }
LessThan = { '<' }
GreaterThan = { '>' }
OpenParen = { '(' }
CloseParen = { ')' }
Semicolon = { ';' }
Apostrophe = { U+0027 }
Tilde = { '~' }
Underscore = { '_' }
Asterisk = { '*' }
AtSign = { '@' }
* Accounts
** Level 1 Accounts
Level 1 Accounts can have nearly any character, including
spaces. However, when they appear in a ledger file, they must be
quoted. There is no need to quote them when they appear on the command
line, as each command-line argument is already isolated.
Lvl1AcctChar = { x ∈ NonNewline | x ∉ CloseCurly, x ∉ Colon }
<lvl1SubAcct> ::= Lvl1AcctChar+
<lvl1FirstSubAcct> ::= <lvl1SubAcct>
<lvl1OtherSubAcct> ::= Colon <lvl1SubAcct>
<lvl1Acct> ::= <lvl1FirstSubAcct> <lvl1OtherSubAcct>*
<quotedLvl1Acct> ::= OpenCurly <lvl1Acct> CloseCurly
** Level 2 Accounts
Level 2 Accounts contain a more restrictive range of characters than
Level 1 Accounts. The first sub-account must begin with a letter or
with any non-ASCII value. All other characters may be nearly any
character except a space or asterisk. Level 2 Accounts are not quoted.
Lvl2AcctOtherChar = { x ∈ NonNewline | x ∉ White, x ∉ Colon, x ∉ Asterisk,
x ∉ GreaterThan, X ∉ LessThan }
<lvl2FirstSubAcct> ::= Letter Lvl2AcctOtherChar*
<lvl2OtherSubAcct> ::= Colon Lvl2AcctOtherChar+
<lvl2Acct> ::= <lvl2FirstSubAcct> <lvl2OtherSubAcct>*
** Ledger file accounts
When an account appears in a ledger file it can be a quoted Level 1
Account or a Level 2 Account.
<ledgerAcct> ::= <quotedLvl1Acct> | <lvl2Acct>
* Commodities
** Level 1 Commodities
Level 1 Commodities can have a broad selection of characters,
including spaces; but they must be quoted when they appear in a ledger
file. They are not quoted when they appear on a command line.
Lvl1CmdtyChar = { x ∈ NonNewline | x ∉ DoubleQuote }
<lvl1Cmdty> ::= Lvl1CmdtyChar+
<quotedLvl1Cmdty> ::= DoubleQuote <lvl1Cmdty> DoubleQuote
** Level 2 Commodities
Level 2 Commodities must begin with a letter, a dollar sign, or a
non-ASCII character. They are not quoted. All other characters may be
any non-space character.
Lvl2CmdtyFirstChar = Letter ∪ Dollar
Lvl2CmdtyOtherChar = { x ∈ NonNewline | x ∉ White }
<lvl2Cmdty> ::= Lvl2CmdtyFirstChar Lvl2CmdtyOtherChar*
** Level 3 Commodities
In Level 3 Commodities, all characters must be letters or the $
symbol. They are not quoted.
Lvl3CmdtyChar = Letter ∪ Dollar
<lvl3Cmdty> ::= Lvl3CmdtyChar+
* Quantities
<digitGroup> ::= ThinSpace Digit+
<digitSequence> ::= Digit+ <digitGroup>*
<digitPostSequence> ::= Period <digitSequence>?
<quantity> ::= Period <digitSequence>
| <digitSequence> <digitPostSequence>?
* Amounts
An amount is a commodity and a quantity.
<leftCmdtyLvl1Amt> ::= <quotedLvl1Cmdty> White* <quantity>
<leftCmdtyLvl3Amt> ::= <lvl3Cmdty> White* <quantity>
<leftSideCmdtyAmt> ::= <leftCmdtyLvl1Amt> | <leftCmdtyLvl3Amt>
<rightSideCmdty> ::= <quotedLvl1Cmdty> | <lvl2Cmdty>
<rightSideCmdtyAmt> ::= <quantity> White* <rightSideCmdty>
<amount> ::= <leftSideCmdtyAmt> | <rightSideCmdtyAmt>
* Comments
Comments are not associated with any transaction or price; they stand
alone.
<comment> ::= Hash NonNewline* Newline White*
* DateTime
The grammar does not restrict texts to valid dates or times; a later
phase must validate the dates and times.
<year> ::= Digit Digit Digit Digit
<month> ::= Digit Digit
<day> ::= Digit Digit
<date> ::= <year> DateSep <month> DateSep <day>
<hours> ::= Digit Digit?
<minutes> ::= Colon Digit Digit
<seconds> ::= Colon Digit Digit
<time> ::= <hours> <minutes> <seconds>?
<tzSign> ::= Plus | Minus
<tzNumber> ::= Digit Digit Digit Digit
<timeZone> ::= <tzSign> <tzNumber>
<timeWithZone> ::= <time> White* <timeZone>?
<dateTime> ::= <date> White* <timeWithZone>?
* Entries
An entry is a debit or credit and an amount.
<debit> ::= LessThan
<credit> ::= GreaterThan
<drCr> ::= <debit> | <credit>
<entry> ::= <drCr> White* <amount>
* Flag
Flags are surrounded by square braces.
FlagChar = { x ∈ NonNewline | x ∉ CloseSquare }
<flag> ::= OpenSquare FlagChar* CloseSquare
* Memos
Memos are associated with a particular transaction or posting.
** Posting memo
<postingMemoLine> ::= Apostrophe NonNewline* Newline White*
<postingMemo> ::= <postingMemoLine>+
** Transaction memo
<transactionMemoLine> ::= Semicolon NonNewline* Newline White*
<transactionMemo> ::= <transactionMemoLine>+
* Number
Numbers are surrounded by parentheses.
NumberChar = { x ∈ NonNewline | x ∉ CloseParen }
<number> ::= OpenParen NumberChar* CloseParen
* Payees
** Level 1 payees
These allow the most latitide in the range of characters, but they
must be quoted with tildes if in a ledger file.
QuotedPayeeChar = { x ∈ NonNewline | x ∉ Tilde }
<lvl1Payee> ::= QuotedPayeeChar*
<quotedLvl1Payee> ::= Tilde <lvl1Payee> Tilde
** Level 2 payees
Their first character must be a letter.
<lvl2Payee> ::= Letter NonNewline*
* Prices
A price has a DateTime, a From commodity, and a To amount.
<fromCmdty> ::= <quotedLvl1Cmdty> | <lvl2Cmdty>
<price> ::= AtSign White* <dateTime> White*
<fromCmdty> White+ <amount> Newline White*
* Tags
Each tag is preceded by an asterisk. The tag text consists of letters,
digits, and underscores.
TagChar = { x ∈ NonNewlineNonSpace | x ∉ Asterisk, x ∉ GreaterThan,
x ∉ LessThan }
<tag> ::= Asterisk TagChar* White*
<tags> ::= <tag>+
* Top Line
This is the first line of a transaction. It also includes the
transaction memo.
<topLinePayee> ::= <quotedLvl1Payee> | <lvl2Payee>
<topLineFlagNum> ::= <flag>? White* <number>?
| <number>? White* <flag>?
<topLine> ::= <transactionMemo>? <dateTime> White*
<topLineFlagNum> White* <topLinePayee>? Newline White*
* FlagNumberPayee
<numberPayee> ::= <number> White* <quotedLvl1Payee>?
<payeeNumber> ::= <quotedLvl1Payee> White* <number>?
<afterFlag> ::= <numberPayee> | <payeeNumber>
<flagFirst> ::= <flag> White* <afterFlag>?
<flagPayee> ::= <flag> White* <quotedLvl1Payee>?
<payeeFlag> ::= <quotedLvl1Payee> White* <flag>?
<afterNumber> ::= <flagPayee> | <payeeFlag>
<numberFirst> ::= <number> White* <afterNumber>?
<numberFlag> ::= <number> White* <flag>?
<flagNumber> ::= <flag> White* <number>?
<afterPayee> ::= <numberFlag> <flagNumber>
<payeeFirst> ::= <quotedLvl1Payee> White* <afterPayee>?
<flagNumPayee> ::= <flagFirst> | <numberFirst> | <payeeFirst>
* Posting
<postingAcct> ::= <quotedLvl1Acct> | <lvl2Acct>
<posting>
::= <flagNumPayee>? White* <postingAcct> White*
<tags>? White* <entry>? White* Newline White* <postingMemo>?
White*
* Transaction
A transaction always has at least two postings. In addition, the
postings must be balanced; however, this restriction is not in the
grammar. As a corollary, at most one posting can appear without an
entry; this restriction also is not in the grammar.
<transaction> ::= <topLine> <posting> <posting> <posting>*
* Blank line
<blankLine> ::= Newline White*
* Item
<item> ::= <comment> | <price> | <transaction> | <blankLine>
* Ledger
<ledger> ::= White* <item>*