Last time, the code generated for try/except/else/finally was presented. Here it is again, but with some minor edits of the Python source code to reduce the number of lines and also with Python code comments moved in each assembly language source file for better correlation to the relevant machine code.
try:
pass # main code suite
except:
pass # except code suite
else:
pass # else code suite
finally:
pass # finally code suite
00177 ; 00001 try:
023B 20 0691 [6] 00178 jsr PushExceptionContext
023E A9 4C [2] 00179 lda #L00000&$FF
0240 85 4F [3] 00180 sta ExceptionHandler
0242 A9 02 [2] 00181 lda #L00000>>8
0244 85 50 [3] 00182 sta ExceptionHandler+1
00183 ; 00002 pass # main code suite
0246 20 06AB [6] 00184 jsr PopExceptionContext
0249 4C 0255 [3] 00185 jmp L00001
00186 ; 00003 except:
024C 00187 L00000
024C 20 06AB [6] 00188 jsr PopExceptionContext
00189 ; 00004 pass # except code suite
024F 20 025B [6] 00190 jsr L00002
0252 4C 025C [3] 00191 jmp L00003
00192 ; 00005 else:
0255 00193 L00001
00194 ; 00006 pass # else code suite
0255 20 025B [6] 00195 jsr L00002
0258 4C 025C [3] 00196 jmp L00003
00197 ; 00007 finally:
025B 00198 L00002
00199 ; 00008 pass # finally code suite
025B 60 [6] 00200 rts
025C 00201 L00003
Moving the call of the finally code to the bottom allows saving an instance of the instruction for each except clause
00177 ; 00001 try:
023B 20 068E [6] 00178 jsr PushExceptionContext
023E A9 4C [2] 00179 lda #L00000&$FF
0240 85 4F [3] 00180 sta ExceptionHandler
0242 A9 02 [2] 00181 lda #L00000>>8
0244 85 50 [3] 00182 sta ExceptionHandler+1
00183 ; 00002 pass # main code suite
0246 20 06A8 [6] 00184 jsr PopExceptionContext
0249 4C 0252 [3] 00185 jmp L00001
00186 ; 00003 except:
024C 00187 L00000
024C 20 06A8 [6] 00188 jsr PopExceptionContext
00189 ; 00004 pass # except code suite
024F 4C 0256 [3] 00190 jmp L00003
00191 ; 00005 else:
0252 00192 L00001
00193 ; 00006 pass # else code suite
0252 4C 0256 [3] 00194 jmp L00003
00195 ; 00007 finally:
0255 00196 L00002
00197 ; 00008 pass # finally code suite
0255 60 [6] 00198 rts
0256 00199 L00003
0256 20 0255 [6] 00200 jsr L00002
More importantly, this seemingly trivial transformation creates significant opportunities for a dumb single-pass compiler with but one lexical token of lookahead to eliminate unneeded elements.
To begin with, consider the case in which the else clause is not present,
00177 ; 00001 try:
023B 20 06A9 [6] 00178 jsr PushExceptionContext
023E A9 4C [2] 00179 lda #L00000&$FF
0240 85 4F [3] 00180 sta ExceptionHandler
0242 A9 02 [2] 00181 lda #L00000>>8
0244 85 50 [3] 00182 sta ExceptionHandler+1
00183 ; 00002 pass # main code suite
0246 20 06C3 [6] 00184 jsr PopExceptionContext
0249 4C 0253 [3] 00185 jmp L00001
00186 ; 00003 except:
024C 00187 L00000
024C 20 06C3 [6] 00188 jsr PopExceptionContext
00189 ; 00004 pass # except code suite
024F 4C 0253 [3] 00190 jmp L00001
00191 ; 00005 finally:
0252 00192 L00002
00193 ; 00006 pass # finally code suite
0252 60 [6] 00194 rts
0253 00195 L00001
0253 20 0252 [6] 00196 jsr L00002
And the case in which the finally clause is not present.
00177 ; 00001 try:
023B 20 06A5 [6] 00178 jsr PushExceptionContext
023E A9 4C [2] 00179 lda #L00000&$FF
0240 85 4F [3] 00180 sta ExceptionHandler
0242 A9 02 [2] 00181 lda #L00000>>8
0244 85 50 [3] 00182 sta ExceptionHandler+1
00183 ; 00002 pass # main code suite
0246 20 06BF [6] 00184 jsr PopExceptionContext
0249 4C 0252 [3] 00185 jmp L00001
00186 ; 00003 except:
024C 00187 L00000
024C 20 06BF [6] 00188 jsr PopExceptionContext
00189 ; 00004 pass # except code suite
024F 4C 0252 [3] 00190 jmp L00003
00191 ; 00005 else:
0252 00192 L00001
00193 ; 00006 pass # else code suite
0252 00194 L00003
Note that an empty finally subroutine will be generated if the compiler detects in the try clause a return or a raise statement or a break or continue statement which transfers the flow of control out of the try clause.
Now consider the case in which else and finally are absent. This is one of the two minimal forms of structured exception handling allowed in Python and is perhaps the most common use.
00177 ; 00001 try:
023B 20 06A2 [6] 00178 jsr PushExceptionContext
023E A9 4C [2] 00179 lda #L00000&$FF
0240 85 4F [3] 00180 sta ExceptionHandler
0242 A9 02 [2] 00181 lda #L00000>>8
0244 85 50 [3] 00182 sta ExceptionHandler+1
00183 ; 00002 pass # main code suite
0246 20 06BC [6] 00184 jsr PopExceptionContext
0249 4C 024F [3] 00185 jmp L00001
00186 ; 00003 except:
024C 00187 L00000
024C 20 06BC [6] 00188 jsr PopExceptionContext
00189 ; 00004 pass # except code suite
024F 00190 L00001
The other minimal form has only the try and finally clauses.
00177 ; 00001 try:
023B 20 06B2 [6] 00178 jsr PushExceptionContext
023E A9 4C [2] 00179 lda #L00000&$FF
0240 85 4F [3] 00180 sta ExceptionHandler
0242 A9 02 [2] 00181 lda #L00000>>8
0244 85 50 [3] 00182 sta ExceptionHandler+1
00183 ; 00002 pass # main code suite
0246 20 06CC [6] 00184 jsr PopExceptionContext
0249 4C 025A [3] 00185 jmp L00001
024C 00186 L00000
024C 20 06CC [6] 00187 jsr PopExceptionContext
024F 20 0259 [6] 00188 jsr L00002
0252 A6 52 [3] 00189 ldx Exception
0254 A5 53 [3] 00190 lda Exception+1
0256 4C 06AB [3] 00191 jmp Raise
00192 ; 00003 finally:
0259 00193 L00002
00194 ; 00004 pass # finally code suite
0259 60 [6] 00195 rts
025A 00196 L00001
025A 20 0259 [6] 00197 jsr L00002
In this case, any exceptions are reraised after the finally clause has been executed.
Not too shabby for a dumb single-pass compiler…