Exceptions/Catch an exception thrown in a nested call: Difference between revisions

m (→‎{{header|Lasso}}: Corrected output)
Line 303:
 
=={{header|C}}==
 
{{incomplete|C|Whot! No bar() ?}}
C doesn't have an exception handling. But <i>that</i>mechanism, won'tso stopwe crazyhave people.to
decide what we want from an exception.
 
1. Return from a function with an error added to exception context.
2. Detect that a exception was thrown by checking the context after a function call.
3. Recover an error type and message.
4. Return from a function after throwing/catching an exception in a way which allows cleanup code to be called (vs. jumping outside the function).
 
In conclusion, try/throw/catch keywords are not available in C, nor is
their functionality, so while the following code tries to fulfill the task's
requirements, no attempt is made to minic them. The goal has been to provide
some modicum level of usefulness for someone actually looking at this for
ideas for their own code.
 
U0 and U1 are boring for debugging purposes. Added something to help with that.
 
<lang C>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ucontext.h>
 
typedef struct exception {
#define try push_handler(); if (!exc_string)
int extype;
#define catch(e) pop_handler(e); for (; exc_string; exc_string = 0)
char what[128];
} exception;
 
typedef struct exception_ctx {
ucontext_t *exc;
exception * exs;
int exc_depth = 0;
int size;
int exc_alloc = 0;
int pos;
const char * exc_string;
} exception_ctx;
 
exception_ctx * Create_Ex_Ctx(int length) {
void throw(const char *str)
const int safety = 8; // alignment precaution.
{
char * tmp = (char*) malloc(safety+sizeof(exception_ctx)+sizeof(exception)*length);
exc_string = str;
setcontextif (exc! +tmp) exc_depthreturn - 1)NULL;
exception_ctx * ctx = (exception_ctx*)tmp;
ctx->size = length;
ctx->pos = -1;
ctx->exs = (exception*) (tmp + sizeof(exception_ctx));
return ctx;
}
 
void Free_Ex_Ctx(exception_ctx * ctx) {
void push_handler()
free(ctx);
{
exc_string = 0;
if (exc_alloc <= exc_depth) {
exc_alloc += 16;
exc = realloc(exc, sizeof(ucontext_t) * exc_alloc);
}
getcontext(exc + exc_depth++);
}
 
int Has_Ex(exception_ctx * ctx) {
void pop_handler(const char *e)
return (ctx->pos >= 0) ? 1 : 0;
{
exc_depth --;
if (exc_string && strcmp(e, exc_string)) {
if (exc_depth > 0)
throw(exc_string);
fprintf(stderr, "Fatal: unhandled exception %s\n", exc_string);
exit(1);
}
}
 
int Is_Ex_Type(exception_ctx * exctx, int extype) {
/* try out the exception system */
return (exctx->pos >= 0 && exctx->exs[exctx->pos].extype == extype) ? 1 : 0;
}
 
void Pop_Ex(exception_ctx * ctx) {
if (ctx->pos >= 0) --ctx->pos;
}
 
const char * Get_What(exception_ctx * ctx) {
if (ctx->pos >= 0) return ctx->exs[ctx->pos].what;
return NULL;
}
 
int Push_Ex(exception_ctx * exctx, int extype, const char * msg) {
void baz() {
staticif int count(++exctx->pos == exctx->size) 0;{
// Use last slot and report error.
switch (count++) {
case 0: throw("U0")--exctx->pos;
casefprintf(stderr, 1"*** Error: throw("U1Overflow in exception context.\n");
case 2: throw("U2");
}
snprintf(exctx->exs[exctx->pos].what, sizeof(exctx->exs[0].what), "%s", msg);
exctx->exs[exctx->pos].extype = extype;
return -1;
}
 
//////////////////////////////////////////////////////////////////////
void foo()
 
{
exception_ctx * GLOBALEX = NULL;
printf(" foo: calling baz\n");
enum { U0_DRINK_ERROR = 10, U1_ANGRYBARTENDER_ERROR };
try { baz(); }
 
catch("U0") {
void baz(int n) {
printf(" foo: got exception U0; handled and dandy\n");
if (! n) {
Push_Ex(GLOBALEX, U0_DRINK_ERROR , "Drink Error. Insufficient drinks in bar Baz.");
return;
}
else {
Push_Ex(GLOBALEX, U1_ANGRYBARTENDER_ERROR , "Bartender Error. Bartender kicked customer out of bar Baz.");
return;
}
}
 
void bar(int n) {
printf(" foo: finished\n");
fprintf(stdout, "Bar door is open.\n");
baz(n);
if (Has_Ex(GLOBALEX)) goto bar_cleanup;
fprintf(stdout, "Baz has been called without errors.\n");
bar_cleanup:
fprintf(stdout, "Bar door is closed.\n");
}
 
intvoid mainfoo() {
intfprintf(stdout, i"Foo entering bar.\n");
for bar(i = 0); i < 3; i++) {
while (Is_Ex_Type(GLOBALEX, U0_DRINK_ERROR)) {
printf("main: calling foo: %d\n", i);
fprintf(stderr, "I am foo() and I deaall wrth U0 DriNk Errors with my own bottle... GOT oNE! [%s]\n", Get_What(GLOBALEX));
try { foo(); }
catchPop_Ex("U1"GLOBALEX) {;
printf("main: Someone threw U1; handled and dandy\n");
}
}
if (Has_Ex(GLOBALEX)) return;
fprintf(stdout, "Foo left the bar.\n");
fprintf(stdout, "Foo entering bar again.\n");
bar(1);
while (Is_Ex_Type(GLOBALEX, U0_DRINK_ERROR)) {
fprintf(stderr, "I am foo() and I deaall wrth U0 DriNk Errors with my own bottle... GOT oNE! [%s]\n", Get_What(GLOBALEX));
Pop_Ex(GLOBALEX);
}
if (Has_Ex(GLOBALEX)) return;
fprintf(stdout, "Foo left the bar.\n");
}
 
 
int main(int argc, char ** argv) {
exception_ctx * ctx = Create_Ex_Ctx(5);
GLOBALEX = ctx;
 
foo();
if (Has_Ex(ctx)) goto main_ex;
 
fprintf(stdout, "No errors encountered.\n");
 
main_ex:
while (Has_Ex(ctx)) {
fprintf(stderr, "*** Error: %s\n", Get_What(ctx));
Pop_Ex(ctx);
}
Free_Ex_Ctx(ctx);
return 0;
}
}</lang>Output:<lang>main: calling foo: 0
 
foo: calling baz
 
foo: got exception U0; handled and dandy
</lang>
foo: finished
Output:
main: calling foo: 1
<lang>Foo entering bar.
foo: calling baz
Bar door is open.
main: Someone threw U1; handled and dandy
Bar door is closed.
main: calling foo: 2
I am foo() and I deaall wrth U0 DriNk Errors with my own bottle... GOT oNE! [Drink Error. Insufficient drinks in bar Baz.]
foo: calling baz
Foo left the bar.
Unhandled exception U2</lang>
Foo entering bar again.
Disclaimer: this is pure hackery, and any kind of bad thing could happen with it. You are not seriously going to use it.
Bar door is open.
Bar door is closed.
*** Error: Bartender Error. Bartender kicked customer out of bar Baz.
</lang>
 
=={{header|C++}}==
Anonymous user