meeting log January 30, 2001
Tyson Dowd
trd@cs.mu.OZ.AU
Fri, 2 Feb 2001 14:14:38 +1100
On 31-Jan-2001, linas@linas.org <linas@linas.org> wrote:
>
>
> I have not read the whole of this log yet. But the following caught my
> eye, and I have to address dres' reservations:
>
> An error stack is about as close as you can come to having exceptions in
> C. Here's how it works. (This example uses macros, please pardon the
> sin)
>
>
> typedef enum { BadDog=23, ...} ErrType;
>
> ErrType pop_error(void);
> void push_error(ErrType);
>
> void some_low_func (..)
> {
> if(something bad) { THROW (BadDog); }
> }
>
> void some_user_func(..)
> {
> TRY {
> some_low_func();
> }
> CATCH {
> case BadDog:
> printf ("Bad Dog! Sit in the corner!!!\n");
> break;
> }
> }
Exceptions also involve more complicated control transfer. Consider:
/* this is the same as your function */
void some_low_func (..)
{
if(something bad) { THROW (BadDog); }
}
/* a new function in the middle */
void some_mid_func (..)
{
...
some_low_func();
...
(other code, possibly throwing different exceptions)
...
}
void some_user_func(..)
{
TRY {
some_mid_func();
}
CATCH {
case BadDog:
printf ("Bad Dog! Sit in the corner!!!\n");
break;
}
}
You have to transfer control from the exception in some_low_func through
some_mid_func into some_user_func. some_mid_func might do arbitrary
amounts of computation after calling some_low_func, so you can't rely on
it to return to some_user_func to trigger the exception catch clauses
without writing explicit code to do this, or putting a TRY/CATCH in
every function.
You actually need to use setjmp/longjmp to get this to work like
C++/Java exceptions. `return' is not flexible enough to implement
exceptions in this manner.
> and the 'magic macros' that make this work:
>
> #define THROW(ERR) { push_error(ERR); return; }
> #define TRY /* no-op */
> #define CATCH {ErrType e; while (e=pop_error()) { switch (e) {
This is still pseudocode, but something like:
/* try: add a new jump_buf to the stack */
#define TRY
{
push_new_jump_buf_onto_error_stack();
if (setjmp(error_stack.jump_buf) == 0) {
/* catch: must directly follow a try, removes the jump_buf from the stack
if the try succeeds, otherwise it provides the else case to setjmp,
which handles any errors that get to here. */
#define CATCH
pop_jump_buf_from_error_stack();
} else {
pop_jump_buf_from_error_stack();
ErrType current_exception;
while (current_exception = pop_error()) {
switch (e) {
/* endcatch just closes off the braces, and if the catch didn't handle the
error then it re-throws it. */
#define ENDCATCH
default:
RETHROW();
}
}
}
}
/* throw: just puts the error on the error stack and then goes to the
topmost jump buf. */
#define THROW(ERR)
{
push_error(ERR);
longjmp(error_stack.env, 1);
}
/* rethrow: throws the current exception again */
#define RETHROW
{
throw(current_exception)
}
I haven't tested this (but I can if you want to use it).
> I've got some parens matching problems here, and its a little
> oversimplified, but its hopefully obvious now that C++/Java exceptions
> are nothing more than an error stack with some syntatic sugar.
>
> So dres: you said you wished for C exceptions?
--
Tyson Dowd #
# Surreal humour isn't everyone's cup of fur.
trd@cs.mu.oz.au #
http://www.cs.mu.oz.au/~trd #