Maciej Stachowiak wrote:
You could probably define a rigorous transform to apply to a swtich()
statement that turns it into a series of if / else clauses (possibly
duplicating later cases if there is no break) and apply the usual if
rule to that transform to get case statements into the attribute grammar
more formally.
I've been thinking about this for a few days. I think it wouldn't be
wise. The transformation gets complicated by conditional breaks:
if (p()) break;
or worse, breaks inside of loops:
L: switch (x) {
case 1:
while (p()) {
...
if (q()) break L;
...
}
...
}
This idea of a "break-elimination transformation" is analogous to a
CPS-transformation. To implement conditional breaks, you're either going
to have to explicitly represent an "escape continuation" as an extra
functional argument, or you're going to have to encode some instances of
`break' with an exception or return-to-label. Even if it works out, it's
going to be an awfully complex way to specify the behavior of `switch'.
To specify tail position, only unconditional breaks would introduce tail
positions (otherwise, tail position becomes not a syntactic property but
a runtime property). IOW, a statement immediately preceding an
unconditional break from a switch block would be in tail position.
But as Waldemar said, this creates an incongruity similar to
tail-recursive `return': some instances of `break' would introduce tail
positions, and some wouldn't, leading to different control behavior.
Specifically, in the tail-calling cases:
g(); break;
has the unintuitive behavior of *first* breaking out of the switch-block
and *then* evaluating g().
Maciej Stachowiak wrote:
>
> I don't think you can represent tail position in a switch statement
> with your "attribute grammar" notion, but it's clear to me that the
> statement immediately before a break statement, or else the last
> statement in the last case or default clause, is in tail position.
You should always be able to express tail position in an attribute
grammar; it's an inherited attribute based on the syntactic structure of
a program.
David Sarah-Hopwood wrote:
You mean that these are in tail position iff the switch statement is.
(This *is* possible to express directly with an attribute grammar,
but it is a bit tedious, so I will only work out the details if asked.)
What the heck, I gave it a go. :)
// case clauses inherit information about the switch block
Statement ::= L: switch (expr) { CaseClause1 ... CaseClausen }
CaseClause1.insideSwitch = { tail: Statement.tail,
label: L.label }
...
CaseClausen.insideSwitch = { tail: Statement.tail,
label: L.label }
// unlabelled switch block
Statement ::= switch (expr) { CaseClause1 ... CaseClausen }
CaseClause1.insideSwitch = { tail: Statement.tail, label: null }
...
CaseClausen.insideSwitch = { tail: Statement.tail, label: null }
// case clause bodies inherit information about the switch block
// a statement immediately preceding an unconditional break is tail
CaseClause ::= case expr: stmt1 ... stmtn
stmt1.insideSwitch = CaseClause.insideSwitch
...
stmtn.insideSwitch = CaseClause.insideSwitch
stmtn-1.tail = CaseClause.insideSwitch.tail &&
stmtn.isUnconditionalBreak
// if it matches the switch label it's an unconditional break
Statement ::= break L
Statement.isUnconditionalBreak =
Statement.insideSwitch &&
Statement.insideSwitch.tail &&
L.label == Statement.insideSwitch.label
// or if it's the default label it's an unconditional break
Statement ::= break
Statement.isUnconditionalBreak = true
// a statement immediately preceding an unconditional break is tail
Statement ::= { stmt1 ... stmtn }
stmtn-1.tail = Statement.insideSwitch &&
Statement.insideSwitch.tail &&
stmtn.isUnconditionalBreak
As I say, I'm not really in favor of this semantics. I think it's too
complicated and bifurcates the meaning of `break'. The fact is if you write:
case 1:
if (p()) {
f();
g();
break;
}
// fall through
case 2:
then the call to g() is in tail position, but the `break' is inarguably
a jump. Put differently, the `switch' construct is inherently imperative
(just ask Tom Duff!). A more functional multiple-case dispatch form
would be like Scheme's `cond' or ML/Haskell `case'. God, we need macros.
Dave
_______________________________________________
Es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss