<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <HTML> <HEAD> <META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9"> <TITLE> A Guide to the S-Lang Language: Error Handling</TITLE> <LINK HREF="slang-15.html" REL=next> <LINK HREF="slang-13.html" REL=previous> <LINK HREF="slang.html#toc14" REL=contents> </HEAD> <BODY> <A HREF="slang-15.html">Next</A> <A HREF="slang-13.html">Previous</A> <A HREF="slang.html#toc14">Contents</A> <HR> <H2><A NAME="s14">14. Error Handling</A></H2> <P> <P>Many intrinsic functions signal errors in the event of failure. User defined functions may also generate an error condition via the <CODE>error</CODE> function. Depending upon the severity of the error, it can be caught and cleared using a construct called an <EM>error-block</EM>. <P> <H2><A NAME="ss14.1">14.1 Error-Blocks</A> </H2> <P> <P>When the interpreter encounters a recoverable run-time error, it will return to top-level by <EM>unwinding</EM> its function call stack. Any error-blocks that it encounters as part of this unwinding process will get executed. Errors such as syntax errors and memory allocation errors are not recoverable, and error-blocks will not get executed when such errors are encountered. <P>An error-block is defined using the syntax <BLOCKQUOTE><CODE> <PRE> ERROR_BLOCK { statement-list } </PRE> </CODE></BLOCKQUOTE> where <EM>statement-list</EM> represents a list of statements that comprise the error-block. A simple example of an error-block is <BLOCKQUOTE><CODE> <PRE> define simple (a) { ERROR_BLOCK { message ("error-block executed"); } if (a) error ("Triggering Error"); message ("hello"); } </PRE> </CODE></BLOCKQUOTE> Executing this function via <CODE>simple(0)</CODE> will result in the message <CODE>"hello"</CODE>. However, calling it using <CODE>simple(1)</CODE> will generate an error that will be caught, but not cleared, by the error-block and the <CODE>"error-block executed"</CODE> message will result. <P>Error-blocks are never executed unless triggered by an error. The only exception to this is when the user explicitly indicates that the error-block in scope should execute. This is indicated by the special keyword <CODE>EXECUTE_ERROR_BLOCK</CODE>. For example, <CODE>simple</CODE> could be recoded as <BLOCKQUOTE><CODE> <PRE> define simple (a) { variable err_string = "error-block executed"; ERROR_BLOCK { message (err_string); } if (a) error ("Triggering Error"); err_string = "hello"; EXECUTE_ERROR_BLOCK; } </PRE> </CODE></BLOCKQUOTE> Please note that <CODE>EXECUTE_ERROR_BLOCK</CODE> does not initiate an error condition; it simply causes the error-block to be executed and control will pass onto the next statement following the <CODE>EXECUTE_ERROR_BLOCK</CODE> statement. <P> <H2><A NAME="ss14.2">14.2 Clearing Errors</A> </H2> <P> <P>Once an error has been caught by an error-block, the error can be cleared by the <CODE>_clear_error</CODE> function. After the error has been cleared, execution will resume at the next statement at the level of the error block following the statement that generated the error. For example, consider: <BLOCKQUOTE><CODE> <PRE> define make_error () { error ("Error condition created."); message ("This statement is not executed."); } define test () { ERROR_BLOCK { _clear_error (); } make_error (); message ("error cleared."); } </PRE> </CODE></BLOCKQUOTE> Calling <CODE>test</CODE> will trigger an error in the <CODE>make_error</CODE> function, but will get cleared in the <CODE>test</CODE> function. The call-stack will unwind from <CODE>make_error</CODE> back into <CODE>test</CODE> where the error-block will get executed. As a result, execution resumes after the statement that makes the call to <CODE>make_error</CODE> since this statement is at the same level as the error-block that cleared the error. <P>Here is another example that illustrates how multiple error-blocks work: <BLOCKQUOTE><CODE> <PRE> define example () { variable n = 0, s = ""; variable str; ERROR_BLOCK { str = sprintf ("s=%s,n=%d", s, n); _clear_error (); } forever { ERROR_BLOCK { s += "0"; _clear_error (); } if (n == 0) error (""); ERROR_BLOCK { s += "1"; } if (n == 1) error (""); n++; } return str; } </PRE> </CODE></BLOCKQUOTE> Here, three error-blocks have been declared. One has been declared outside the <CODE>forever</CODE> loop and the other two have been declared inside the <CODE>forever</CODE> loop. Each time through the loop, the variable <CODE>n</CODE> is incremented and a different error-block is triggered. The error-block that gets triggered is the last one encountered, since that will be the one in scope. On the first time through the loop, <CODE>n</CODE> will be zero and the first error-block in the loop will get executed. This error block clears the error and execution resumes following the <CODE>if</CODE> statement that triggered the error. The variable <CODE>n</CODE> will get incremented to <CODE>1</CODE> and, on the second cycle through the loop the second <CODE>if</CODE> statement will trigger an error causing the second error-block to execute. This time, the error is not cleared and the call-stack unwinds out of the <CODE>forever</CODE> loop, at which point the error-block outside the loop is in scope, causing it to execute. This error-block prints out the values of the variables <CODE>s</CODE> and <CODE>n</CODE>. It will clear the error and execution resumes on the statement <EM>following</EM> the <CODE>forever</CODE> loop. The result of this complicated series of events is that the function will return the string <CODE>"s=01,n=1"</CODE>. <P> <P> <HR> <A HREF="slang-15.html">Next</A> <A HREF="slang-13.html">Previous</A> <A HREF="slang.html#toc14">Contents</A> </BODY> </HTML>