; # ABNF rules for GCode in Kodachi.
;
; This grammar is based primarily on the document:
;   Kramer TR, Proctor FM and Messina E (2000)
;     The NIST RS274NGC Interpreter - Version 3. NISTIR 6556.
;     Section 3.3 - Format of a Line
;
; In keeping with Kramer (2000), all whitespace outside of comments must be
; stripped BEFORE this grammar is considered. Comments are defined completely
; by the comment-inline and comment-eol rules. Because GCode permits whitespace
; to occur anywhere, such pre-stripping is necessary to make the grammar
; succinct.
;
; For the format of ABNF, please consult RFC5234.
; ABNF summary:
;    a b       - a followed by b
;    a / b     - a or b
;    [a]       - a single occurrence of a is optional
;    *a        - zero or more instances of a
;    1*a       - one or more instances of a
;    <n>*<m>a  - minimum of <n> and maximum of <m> instances of a
;    
; GCode is assumed to consist of ASCII characters.
;
; Not all of the GCode specification is permitted. In particular; the following
; features of GCode are included:
;    - optional block delete character (a slash "/")
;    - optional line numbers
;    - inline comments delimited by parentheses
;    - end of line comments; preceded by a semicolon
;    - control words

; A GCode file consists of zero or more lines.
; Lines in the middle of the file must be terminated by an eol character.
; The last line in the file can optionally be terminated by an eol.
gcode = *(line eol)
        [(line [eol])]

; Each line has:
line = [block-delete-char]      ; An optional block delete character
       [line-num]               ; An optional line number
       *(word / comment-inline) ; Any number of words or inline comments
       [comment-eol]            ; An optional end-of-line comment

; An end of line marker is a carriage return or line feed or both
eol = (CR [LF]) / (LF [CR])

; Printable characters and white space inside parentheses is a comment
comment-inline = "(" *comment-inline-char ")"
; An inline comment character is any character excluding a closing parenthesis
comment-inline-char = HTAB / %d32-40 / %d42-126
; Comments can start with a semicolon and extend for the rest of the line
; (NB: These comments are common in 3D printer GCode, but do not appear in
;  Kramer 2000.)
comment-eol = ";" *comment-eol-char
; A semi-colon delimited comment can contain any printable character
comment-eol-char = HTAB / %d32-126

; A word is a letter other than N followed by a real value
word      = word-char number
word-char = %x41-4D / %x4F-5A / %x61-6D / %x6F-7A

; A number consists of:
;  1. An optional plus or minus sign, followed by
;  2. Zero to many digits, followed by
;  3. An optional decimal point and zero to many digits.
; A number must have a digit somewhere. Consequently, a number can have a
; digit preceding the decimal point (lnumber) or following the decimal point
; (rnumber).
number  = ["+" / "-"] (lnumber / rnumber)
lnumber = 1*DIGIT ["."  *DIGIT]  ; must have digit on LHS of "."
rnumber =          "." 1*DIGIT   ; must have digit on RHS of "."

; A line number is the letter N followed by an integer (with no sign) between
; 0 and 99999 written with no more than five digits.
line-num = ("N" / "n") 1*5DIGIT

; A block delete character is a slash.
block-delete-char = "/"
