Download presentation
Presentation is loading. Please wait.
1
More on Your Project Program arguments:
./garnet foo.g Compile foo.g to produce foo.c and executable foo ./garnet –e Read input from stdin, and evaluate it, producing any output on stdout
2
Handling Return Expressions
Your program must handle expressions of the form return x, where x is some expression. This is difficult to do, because the return may appear in a context in which you cannot execute a C return statement (such as in the middle of an && or || expression) To do this sort of return you’ll need to use setjmp and longjmp.
3
setjmp/longjmp int setjmp(jmp_buf env); void longjmp(jmp_buf env, int val); setjmp saves its stack environment in env for later use by longjmp and returns value 0. The type jmp_buf is essentially an array containing values necessary to restore the stack to the context in effect at the time of the setjmp call. longjmp restores the stack to the one in effect at the time setjmp was called with argument env. After then longjmp call is made, program execution continues as if setjmp return the value val. The caller of setjmp must not have returned in the interim! If longjmp is called with val == 0, then execution continues after the call as if setjmp returned 1. That is, longjmp cannot be effectively called with val == 0!
4
Simple setjmp/longjmp Example
#include <setjmp.h> #include <iostream> | |int Ret_val; using namespace std; int main() { jmp_buf this_jmp; Ret_val = 2; cout << "set Ret_val to " << Ret_val << endl; int longjmpdone = setjmp(this_jmp); cout << "setjump returned " << longjmpdone << endl; if (!longjmpdone) { // Do the code that we want to execute before the longjmp // Ret_val = 5; // Now jump to the setjmp point // longjmp(this_jmp,1); Ret_val = 3; } cout << "Ret_val is now " << Ret_val << endl; } Output: set Ret_val to 2 setjump returned 0 setjump returned 1 Ret_val is now 5 → → → → → → → → → →
5
More complex setjmp/longjmp Example
#include <setjmp.h> #include <stack> #include <iostream> class jumpcontainer { public: jmp_buf *j; jumpcontainer(jmp_buf &j_init) { j = &j_init; } jmp_buf *get() { return j; } }; int Ret_val; using namespace std; stack<jumpcontainer> return_stack; |int main() { jmp_buf this_jmp; // Imagine this is the code that implements the call to a // method. // Here you do whatever is necessary to set up the evaluation // of the body. // Ret_val = 2; cout << "set Ret_val to " << Ret_val << endl; // Now you make the setjmp/longjmp wrapper // int longjmpdone = setjmp(this_jmp); cout << "setjump returned " << longjmpdone << endl; if (!longjmpdone) { // Push the return point onto the return_stack // return_stack.push(jumpcontainer(this_jmp)); // Evaluate body in the new environment // Typically you'd do this by executing something like // Ret_val = body->eval(); Ret_val = 5; // Any return expression will generate code like this: // jmp_buf *ret_jmp = return_stack.top().get(); longjmp(*ret_jmp,1); // If a return wasn't executed, then the code will // fall through this case and the Ret_val assigned // will have been gotten from the eval of the body // // Remove the longjmp call, and you'll see that we // get value 2 out Ret_val = 2; } // We only get here by returning (either explicitly or implicitly), // so pop the return stack! // return_stack.pop(); cout << << "Ret_val is now " Ret_val << endl; } → → // → → → → → → Output: set Ret_val to 2 setjump returned 0 setjump returned 1 Ret_val is now 5 Output: set Ret_val to 2 setjump returned 0 Ret_val is now 2 → → → → → → → → → →
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.