Path: utzoo!utgpu!jarvis.csri.toronto.edu!rutgers!sun-barr!newstop!sun!amdahl!twg-ap!dwh From: dwh@twg-ap.UUCP (Dave Hamaker) Newsgroups: comp.lang.c Subject: Re: "arithmetic if":: Re: Feature for the next C version Message-ID: <359@twg-ap.UUCP> Date: 12 Aug 89 02:46:45 GMT References: <18868@mimsy.UUCP> Organization: The Wollongong Group, Palo Alto, CA. Lines: 115 In reference to a discussion which began from an expressed wish for something like the Fortran "Arithmetic IF" statement (for its clarity when you want to do different things with the <, ==, > cases of a test), in article <18868@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) describes Mesa's "SELECT" as a real world example of a language construct that is a generalization of C's "switch." One of my pet ideas concerns the generalization of things like "switch." There's one wrinkle to the idea which may be hard to do with current compiler technology. I just don't know enough about compilers to tell. But, there's a good chance some of you on the net do know, and would be willing to enlighten us. Applying the idea to switch gives: switch (lhs) { case (rhs1): statements case (rhs2): statements ... case (rhsN): statements default: statements } where: the "(lhs)" can be omitted; if present, "lhs" is an expression, or a *part* of one; ("lhs" stands for "left-hand side"); the "rhs's" are also expressions, or *parts* of same; the parentheses around a "rhs" may be omitted if it does not contain a colon (":"); ("rhs" stands for "right-hand side"); neither the "lhs", nor any "rhs", may contain part of a: character constant, string constant, parenthesized sub-expression, or any other token (this could be relaxed, but it probably would not be wise to do so). If "lhs" is a complete (non-null) expression, for each "rhs" which is a complete expression, the text of "lhs" and "rhs" are concatenated around the text of an "==" operator and the result is evaluated as an expression. Otherwise, the text of "lhs" and "rhs" are just concatenated and evaluated as an expression. Control is transferred to the first case with a non-zero (true) expression value, otherwise to the "default" label, if present, or the statement following the switch construct, if not (but see my "aside"). If "lhs" is a complete expression and all "rhs's" are constants, "lhs" must be evaluated exactly once; otherwise, "lhs" (or parts of it) may be evaluated more than once, and the constructed case expressions may be evaluated in any order (even in parallel) and need not all be evaluated, at the complete discretion of the compiler. This means that case expressions with side effects cause undefined results. Note also that duplicate case expressions are legal, but that unreachable cases which are detectable at compile time certainly deserve warning diagnostics. With this, we could write things like: switch (x) { case > 0: signum = 1; break; case 0: signum = 0; break; case < 0: signum = -1; break; } and: switch (p < ) { case .1: ... case .5: ... default: ... } Now, it seems pretty straightforward to me to compile the construct as follows: First, reserve space for a jump instruction. Second, follow this with code generated for the "statements" as the case construct is scanned. As this is done, remember the "lhs" and the "rhs's," and remember where in the generated code each "rhs" points to. Classify the "lhs" and each "rhs" as to whether or not it is a valid expression (by trying to parse them). Further classify each valid "rhs" expression as to whether or not it is a constant expression. Third, when the end of the switch is reached, reserve space for another jump instruction. Fourth, follow this with code generated to evaluate the expressions constructed from the "lhs" and "rhs's" and to jump to the proper point in the generated code associated with each case label. Finally, fill in the first reserved jump slot to go to the evaluation code, and fill in the second reserved jump slot to transfer to the end of the switch. The wrinkle I'm worried about is: is this notion of saving some program text aside, concatenating expressions out of them and then "reparsing" the internally constructed expressions something you can build with current compiler-construction tools? Comments from those in the know? Aside: If I had my druthers, I'd have switches without a default case give undefined results when no case matches. It would be a promise to the compiler that one of the cases will match, allowing generation of "leaner" code in that event (perhaps with a warning, which would also help catch when you mistype "default"). I like sharp tools, but it would not be appropriate to change this sort of thing in an existing construct (perhaps a syntax for specifying no default could be added). -Dave Hamaker dwh@twg.com ...!sun!amdahl!twg-ap!dwh