Tim Showalter <tjs+(_at_)andrew(_dot_)cmu(_dot_)edu> writes:
It reduces complexity; it seperates command/argument checking from
syntactic analysis (making both simpler) while maintaining
extensibility. (You've still got the same amount of *work*, it's just
simpler. :-)
No, this is wrong. Where before I had a parser that could check the types
of my arguments, I now have to write another layer.
Nope - you *can* do your semantic checking in your parser, even
under this scheme. I'd argue that this makes your parser needlessly
complex and hard to maintain, when the work's better split up and done
at a higher level, but that's just my opinion.
if (...) { ... }
fileinto ...
else { ... }
True - you need to keep track of the previous action, not just the
previous control-structure.
Real languages just make the else part of the control structure. I want
that.
Why do they have to be joined at the syntax level, though? (Real
languages have a fixed set of control structures, which is suboptimal
for Sieve).
(It'd be nice if actions could take the results of tests in their
arguments; then the distinction between control-structure and action
could vanish... but as is, it's only a few extra states in one's
parser DFA to keep track of whether the current command's been
restricted to being a control-structure or not; it's not a big deal.)
There's an important difference between control-structures and actions.
Since you no longer know how many arguments any given thing takes, the
end-of-statement token is either a block or a semicolon.
Here's how I'd write it:
argument = token / "(" [WSP] test [WSP] ")"
command = identifier WSP [argument *(WSP argument)] [WSP] (block / ";")
token = string / number / tag / token-list
token-list = "[" [WSP] [token *([WSP] "," [WSP] token)] [WSP] "]"
(That's also making "lists" a generic container, not only used for
strings; I'm not sure it's useful or not, but some extension may want
it someday.)
)Rob