On Thu, Jul 21, 2005 at 02:43:13PM -0700, Ned Freed wrote:
As to the idea of actually using formal grammar for this sort of thing, been
there, done that, bad idea. Having been on the receiving end of questions
for
RFC 1521 issues, I can tell you that using subgrammars (or whatever the
correct
term for this is) creates about 10X more confusion than clarity.
Too bad, but I guess a paragraph like
All Sieve commands, including extensions, MUST be words of the following
generic grammar with the start symbol "start". They SHOULD be specified
using a specific grammar, though.
is not going to help most people a lot, despite specifying *exactly*
the same as RFC 3028.
The simple fact of the matter is that people just aren't that good at
extracting usage information from ABNF. THis isn't to say we should not
have a
precise definition of the overall syntax in ABNF - implementors at the very
least need it - but using ABNF to provide usage information' goes too far.
I built a full ABNF for my implementation to move as much as possible
from semantic analysis to syntactic analysis, but that is just one
possible approach. I append my implementation notes, but they are
not meant as suggested change to the draft, but to illustrate the step
between RFC 3028 and actual code. The { } specification is pretty
weak and just "worked for me".
I am pretty sure others use the generic ABNF for syntactic analysis,
following straightforward RFC 3028. That is well possible and it does
not need a specific grammar.
The
form we use now is simple, easy to read, and gets the job done.
Once "Syntax" is replaced by "Usage", it is fine with me and I shall
agree to the next released draft.
Michael
----------------------------------------------------------------------
The grammar is specified in ABNF with two extensions to describe tagged
arguments that can be reordered and grammar extensions: { } denotes a
sequence of symbols that may appear in any order. Example:
options = a b c
start = { options }
is equivalent to:
start = ( a b c ) / ( a c b ) / ( b a c ) / ( b c a ) / ( c a b ) / ( c b a )
The symbol =) is used to append to a rule:
start = a
start =) b
is equivalent to
start = a b
All Sieve commands, including extensions, MUST be words of the following
generic grammar with the start symbol "start". They SHOULD be specified
using a specific grammar, though.
argument = string-list / number / tag
arguments = *argument [test / test-list]
block = "{" commands "}"
commands = *command
string = quoted-string / multi-line
string-list = "[" string *("," string) "]" / string
test = identifier arguments
test-list = "(" test *("," test) ")"
command = identifier arguments ( ";" / block )
start = command
The basic Sieve commands are specified using the following grammar, which
language is a subset of the generic grammar above. The start symbol is
"start".
address-part = ":localpart" / ":domain" / ":all"
comparator = ":comparator" string
match-type = ":is" / ":contains" / ":matches"
string = quoted-string / multi-line
string-list = "[" string *("," string) "]" / string
address-test = "address" { [address-part] [comparator] [match-type] }
string-list string-list
test-list = "(" test *("," test) ")"
allof-test = "allof" test-list
anyof-test = "anyof" test-list
exists-test = "exists" string-list
false-test = "false"
true=test = "true"
header-test = "header" { [comparator] [match-type] }
string-list string-list
not-test = "not" test
relop = ":over" / ":under"
size-test = "size" relop number
block = "{" commands "}"
if-command = "if" test block *( "elsif" test block ) [ "else" block ]
stop-command = "stop" { stop-options } ";"
stop-options =
keep-command = "keep" { keep-options } ";"
keep-options =
discard-command = "discard" { discard-options } ";"
discard-options =
redirect-command = "redirect" { redirect-options } string ";"
redirect-options =
require-command = "require" { require-options } string-list ";"
require-options =
test = address-test / allof-test / anyof-test / exists-test
/ false-test / true-test / header-test / not-test
/ size-test
command = if-command / stop-command / keep-command
/ discard-command / redirect-command
commands = *command
start = *require-command commands
The extensions "envelope" and "fileinto" are specified using the following
grammar extension.
envelope-test = "envelope" { [comparator] [address-part] [match-type] }
string-list string-list
test =/ envelope-test
fileinto-command = "fileinto" { fileinto-options } string ";"
fileinto-options =
command =/ fileinto-command
The extension "copy" is specified as:
fileinto-options =) ":copy"
redirect-options =) ":copy"
And so on ...