views:

136

answers:

3

Solved: I figured out a clean way to do it with setjmp()/longjmp(), requiring only a minimal wrapper like:

int jump(jmp_buf j, int i) { longjmp(j, i); return 0; }

This allows jump() to be used in conditional expressions. So now the code:

if (A == 0) return;
output << "Nonzero.\n";

Is correctly translated to:

return
((A == 0) && jump(caller, 1)),
(output << "Nonzero.\n"),
0;

Where caller is a jmp_buf back to the point of invocation in the calling function. Clean, simple, and efficient to a degree that is far less implementation-defined than exceptions. Thank you for your help!


Is there a way to emulate the use of flow-control constructs in the middle of an expression? Is it possible, in a comma-delimited expression x, y, for y to cause a return?

Edit: I'm working on a compiler for something rather similar to a functional language, and the target language is C++. Everything is an expression in the source language, and the sanest, simplest translation to the destination language leaves as many things expressions as possible. Basically, semicolons in the target language become C++ commas. In-language flow-control constructs have presented no problems thus far; it's only return. I just need a way to prematurely exit a comma-delimited expression, and I'd prefer not to use exceptions unless someone can show me that they don't have excessive overhead in this situation.

The problem of course is that most flow-control constructs are not legal expressions in C++. The only solution I've found so far is something like this:

try {

    return
    x(),                        // x();
    (1 ? throw Return(0) : 0);  // return 0;

} catch (Return& ret) {

    return ref.value;

}

The return statement is always there (in the event that a Return construct is not reached), and as such the throw has to be wrapped in ?: to get the compiler to shut up about its void result being used in an expression.

I would really like to avoid using exceptions for flow control, unless in this case it can be shown that no particular overhead is incurred; does throwing an exception cause unwinding or anything here? This code needs to run with reasonable efficiency. I just need a function-level equivalent of exit().

+1  A: 

what for? C++ is imperative language. Expressions there are just expressions. Use functional languages if you want to do everything as expressions/functions.

Andrey
+1  A: 

You may want to research cfront, which is a program from the late 80's/early 90's that translated C++ into C (no templates or exceptions back then), because there were few, if any, native C++ compilers.

The way it handled inline functions is very similar to what you are trying to do: lots of trinary (?:) operators, commas, and parentheses. However, it could not convert an inline function with control flow more complex than if/then, e.g. a for or while loop, to an expression, and would have to implement that function as non-inline.

The only way to "prematurely exit a comma-delimited expression" would be with the trinary operator and parentheses. For example:

(
    first thing,
    second thing,
    test expression?
    (
        next thing if successful,
        another thing,
        return value
    )
    :( // How often can you use an emoticon as an operator, anyway?
        something to do if unsuccessful,
        more cleanup,
        return value
    )
)

If the compiler doesn't short-circuit the then and else clauses of the trinary operator, you're out of luck.

Mike DeSimone
Thanks for your help. I ended up solving it a different way. Incidentally, though, I believe the conditional operator is guaranteed to short-circuit.
Jon Purdy
A: 

I get the feeling you just have a functional specification (in terms of pre- and post-conditions, for example) of how the translation process must be performed. Since C++ is not a declarative language, but an imperative one, you have to derive yourself a procedural implementation of that translation process before you start coding. And, as you have already seen, it's not as simple as concatenating all your original expressions using commas.

What you are trying to do is have the C++ compiler do your work for you. This won't work, since C++ is not a declarative language, and its compiler won't dynamically try to interpret what you meant from your specifications. And, if this could work, C++ would have to be just another dynamic declarative language, and you would be probably targeting another static language.

A hint on what could work: Analyze every original expression completely (with its possible side-effects) and only then output code. If your expression is compound (it has sub-expressions), don't output anything until you have analyzed the bigger expression.

Eduardo León