Don't Jump Around

Filed under: FANUC TP Programming TP+

I hate to disagree with the wise words of House of Pain, but excessive jumping around is the most common issue I see when reviewing others’ TP code. Labels and jump-statements come natural in a language that doesn’t support actual code-blocks for simple if-statements. Within just a few minutes of programming, a beginner sees an IF (...),JMP LBL[X] and decides that this is how FANUC programming is done.

Randall Munroe from xkcd sums up the potential for catastrophe when using GOTO statements (TP’s JMP) in this comic:

xkcd GOTO

Unfortunately you can’t avoid them completely. TP only supports FOR and SELECT control structures, and it only supports them in a very limited fashion. IF-statements require jumps, there’s no such thing as an ELSE in TP so you have to do it with a jump, and WHILE-loops don’t exist; their functionality has to be done with a couple labels and a jump.

Here’s how each of these control structures is implemented in TP on the left and a more fully-featured programming language implementation (TP+) on the right:

  ! TPP                     ;      # TP+
  ! ----------------------- ;      # ----------------------
   ;
   ;                               the_input    := DI[1]
   ;                               the_register := R[1]
   ;
  ! simple if statement     ;      # simple if statement
  ! ----------------------- ;      # ----------------------
  IF DI[1]=OFF,JMP LBL[100] ;      if the_input
  ! DI[1] is ON ;                    # the_input is ON
  LBL[100] ;                       end
   ;
  ! if-else block           ;      # if-else block
  ! ----------------------- ;      # ----------------------
  IF DI[1]=OFF,JMP LBL[100] ;      if the_input
  ! DI[1] is ON ;                    # the_input is ON
  JMP LBL[101] ;                   else
  LBL[100] ;                         # the_input is OFF
  ! DI[1] is OFF ;                 end
  LBL[101] ;
   ;
  ! while loop              ;      # while loop
  ! ----------------------- ;      # ----------------------
  LBL[100] ;                       while the_input
  IF DI[1]=OFF,JMP LBL[101] ;        # the_input is on
  ! DI[1] is ON ;                  end
  JMP LBL[100] ;
  LBL[101] ;
   ;
  ! select statement        ;      # select statement
  ! ----------------------- ;      # ---------------------
  SELECT R[1]=1,JMP LBL[100] ;     case the_register
         =2,JMP LBL[101] ;           when 1
         ELSE,JMP LBL[102] ;           # the_register == 1
   ;                                 when 2
  LBL[100] ;                           # the_register == 2
  ! R[1]=1 ;                         else
  JMP LBL[103] ;                       # the_register is not 1 or 2
   ;                               end
  LBL[101] ;
  ! R[1]=2 ;
  JMP LBL[103] ;
   ;
  LBL[102] ;
  ! R[1] is not 1 or 2 ;
  JMP LBL[103] ;
   ;
  LBL[103] ;

Which side is easier to read? Which side makes it easier to make a mistake by jumping to an incorrect label?

Here’s an example of a bad main routine that’s similar to a lot of programs I see:


  LBL[1] ;
  IF (...some string of conditions...),JMP LBL[100] ;
  IF (...some other conditions...),JMP LBL[100] ;
  IF (...something else...),JMP LBL[200]
   ;
  LBL[2] ;
  IF (...another thing...),JMP LBL[300] ;
   ;
  IF (..a couple of condition...),CALL SOME_ROUTINE ;
   ;
  LBL[100] ;
  ! do something ;
  IF (.....),JMP LBL[2] ;
   ;
  LBL[200] ;
  IF (...),JMP LBL[100] ;
   ;
  ! do something else ;
  JMP LBL[1] ;
   ;
  LBL[300] ;
  ! one more thing ;
  IF (...),JMP LBL[999] ;
  JMP LBL[1] ;
   ;
  LBL[999] ;

That code is not an exaggeration. Can anyone tell me what the hell this program is supposed to do? Probably not. This is the part where the dinosaur comes in and bites your head off.

I would argue that you should almost only use labels when implementing these simple control structures. If you are jumping around in your code for any other reason, there’s probably a better way to do it.

I pretty much only use labels and jumps in the following situations:

  1. Implementing non-existant control structures explained earlier
  2. Implementing guards to protect the robot or equipment from bad decisions
  3. Error recovery without using separate routines

Item #2 could probably be considered a standard control structure, and maybe item #3 is actually a good candidate for refactoring. So there you have it: only use labels and jumps when implementing control structures like if-else statements, while loops, complex for loops and more complicated select-case statements that don’t exist in TP. If you want to save yourself some pain, just let TP+ implement those features for you. (But maybe not quite just yet… I still consider TP+ to be in the alpha development stage.)


Want posts like this delivered right to your inbox?

If you liked this post, please sign up for my mailing list!