Can goto() statements be avoided in this program -- pls place code?

This is a Keypad-LCD-EEPROM based academic project in which a 10-digit code (consisting of any combination of 0, 1, ..., 9) is entered. After the entry, # key will store the code in EEPROM; b key will bring back the code from EEPOM and will show on LCD; * key will delete the code from buffer and EEPROM.

Fig-1: Hardware Block Diagram


Fig-2: Flow Chart for the Control Program

:Simple C Codes for Fig-2: (Tested and found working except filtering out of *, #, a, b, c, d from being printed)

#include<EEPROM.h>
#include<Keypad.h>
#include<LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

const byte rows = 4, cols = 4;
char storage[11];   //including space for null-byte
char storageB[11];
int adr = 0x0010;
int arrayTracker = 0;
byte flag11 = 0x00;
byte flag2 = 0x00;
byte flag3 = 0x00;
char input;

char keys[rows][cols] = {
 
 {'1','2','3','a'},
 {'4','5','6','b'},
 {'7','8','9','c'},
 {'*','0','#','d'}
};

byte rPins[rows] = {9,8,7,6}, cPins[cols] = {5,4,3,2};

Keypad keypad = Keypad(makeKeymap(keys),rPins,cPins,rows,cols);

void setup()
{
 lcd.init();
 lcd.backlight();
 lcd.print("Enter 10-digit..");
 lcd.setCursor(0,1);
}

void loop()
{
  L0: input = keypad.getKey(); //L0:
  if(input)
  {                         //L1:
    if(flag2==0x00)         //L1:
    {                 //L2:
      if(flag11==0x00)//L2:      
      {//L3:
        filterDigit();      //L3: do not print *, #, a, b, c, d
        lcd.write(input);   //show digit on LCD
        storage[arrayTracker] = input;  //save digit
        if(arrayTracker == 9)  //L4
        {//L5:
          arrayTracker++;       //L5
          storage[arrayTracker] = 0x00; //null-byte
          flag11 = 0x01;
          goto L0;
        }
        else
        {     //L5A:
          arrayTracker++;   //L5A:
          goto L0;
        }
      }
      else
      {          //L3A:
        if(input == '#')    //to save in EEPROM
        {   //L3Y:
          EEPROM.put(adr, storage); //save 10-digit code in EEPROM
          delay(1000);
          lcd.setCursor(0, 1);
          lcd.print("Saved in EEPROM");
          flag2 = 0x01;
          goto L0;    //L3Y:
        }
      } 
      //----------L3 : if-else--------------------
    }

    else
    {
      if(input == '*')      //L2A:
      {  //3X:
        //delete code from array and EEPROM
        for(int i=0; i<11; i++)
        {
          storage[i] = 0x00;
          storageB[i] = 0x00;
        }
        EEPROM.put(adr, storage);   //all digits are 0s
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Codes Deleted!");
        lcd.setCursor(0, 1);
        EEPROM.get(adr, storageB);
        lcd.print(storageB);
        flag3 = 0x01;
        goto L0;
      }
      else   
      {  //L3XA:
        if(flag3 == 0x00)
        {  //L4X:
          if(input == 'b')
          {//L5X:
            //read from EEPROM and show on LCD
            EEPROM.get(adr, storageB);
            lcd.clear();
            lcd.setCursor(0, 0);
            lcd.print("Code from EEPROM");
            lcd.setCursor(0, 1);
            lcd.print(storageB);
          } 
         }
       }
     }     
   }
}

void filterDigit()
{
  
}

people should not use goto() statement at all anymore so it's definitely possible to not use it.

why don't you use state machine for this concept. it is much easier to read and manage.

GolamMostafa:
This is a Keypad-LCD-EEPROM based academic project in which a 10-digit code (consisting of any combination of 0, 1, ..., 9) is entered. After the entry, # key will store the code in EEPROM; b key will bring back the code from EEPOM and will show on LCD; * key will delete the code from buffer and EEPROM.

Fig-1: Hardware Block Diagram


Fig-2: Flow hart for the Control Program

:Simple C Codes for Fig-2: (Tested and found working except filtering out of *, #, a, b, c, d from being printed)

#include<EEPROM.h>

#include<Keypad.h>
#include<LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

const byte rows = 4, cols = 4;
char storage[11];   //including space for null-byte
char storageB[11];
int adr = 0x0010;
int arrayTracker = 0;
byte flag11 = 0x00;
byte flag2 = 0x00;
byte flag3 = 0x00;
char input;

char keys[rows][cols] = {

{'1','2','3','a'},
{'4','5','6','b'},
{'7','8','9','c'},
{'*','0','#','d'}
};

byte rPins[rows] = {9,8,7,6}, cPins[cols] = {5,4,3,2};

Keypad keypad = Keypad(makeKeymap(keys),rPins,cPins,rows,cols);

void setup()
{
lcd.init();
lcd.backlight();
lcd.print("Enter 10-digit..");
lcd.setCursor(0,1);
}

void loop()
{
 L0: input = keypad.getKey(); //L0:
 if(input)
 {                         //L1:
   if(flag2==0x00)         //L1:
   {                 //L2:
     if(flag11==0x00)//L2:      
     {//L3:
       filterDigit();      //L3: do not print *, #, a, b, c, d
       lcd.write(input);   //show digit on LCD
       storage[arrayTracker] = input;  //save digit
       if(arrayTracker == 9)  //L4
       {//L5:
         arrayTracker++;       //L5
         storage[arrayTracker] = 0x00; //null-byte
         flag11 = 0x01;
         goto L0;
       }
       else
       {     //L5A:
         arrayTracker++;   //L5A:
         goto L0;
       }
     }
     else
     {          //L3A:
       if(input == '#')    //to save in EEPROM
       {   //L3Y:
         EEPROM.put(adr, storage); //save 10-digit code in EEPROM
         delay(1000);
         lcd.setCursor(0, 1);
         lcd.print("Saved in EEPROM");
         flag2 = 0x01;
         goto L0;    //L3Y:
       }
     }
     //----------L3 : if-else--------------------
   }

else
   {
     if(input == '*')      //L2A:
     {  //3X:
       //delete code from array and EEPROM
       for(int i=0; i<11; i++)
       {
         storage[i] = 0x00;
         storageB[i] = 0x00;
       }
       EEPROM.put(adr, storage);   //all digits are 0s
       lcd.clear();
       lcd.setCursor(0, 0);
       lcd.print("Codes Deleted!");
       lcd.setCursor(0, 1);
       EEPROM.get(adr, storageB);
       lcd.print(storageB);
       flag3 = 0x01;
       goto L0;
     }
     else  
     {  //L3XA:
       if(flag3 == 0x00)
       {  //L4X:
         if(input == 'b')
         {//L5X:
           //read from EEPROM and show on LCD
           EEPROM.get(adr, storageB);
           lcd.clear();
           lcd.setCursor(0, 0);
           lcd.print("Code from EEPROM");
           lcd.setCursor(0, 1);
           lcd.print(storageB);
         }
        }
      }
    }    
  }
}

void filterDigit()
{
 
}

Have you written any code using 'State Machine' techniques?

Or code that has functions other than setup() or loop()?

Do you know what a flag is and how it can be used to control code execution?

Have you ever used switch/case.

I expect that you will appreciate the complexity of this particular Keypad being managed by a Smart Library. I could not find any other control structures other than if-else to control the described behavior of the Keypad. There are nested if-else structures which have created problem on the easy exit to the beginning of Keypad polling/scanning. Use of goto statements have taken care of the affairs; but, I am trying to avoid its use as there are a lot of gross complains against it.

I am a bit reluctant to use the state machine concept as the behavior of the system is not being controlled by any of the past events; rather, it creates some run-time variables that control the future behavior of the system; for example, the flags.

I would like to manage the system using simple C codes as it is an academic project and is meant mainly for the undergraduate level pupils.

Thanks for the interest and guidance.

Have you written any code using 'State Machine' techniques?

Or code that has functions other than setup() or loop()?

Do you know what a flag is and how it can be used to control code execution?

Have you ever used switch/case.

1. I have designed Sequential Machines using FSM.
2. Yes.
3. Yes.
4. Yes.

Can goto() statements be avoided in this program

Yes.

-- pls place code?

Replace "goto L0;" with "return;".

It’s inconvenient to convert code into a State Machine, especially when the program is large.

Suggest you spend some time to consider doing this.

In the future slap your hand when you type 'goto'. :wink:

Replace "goto L0;" with "return;".

O Lovely! It works! It works!! It works!!! +!!!

I thought (I did not try) about using of return; but, I refrained myself as I couldn't convince (myself) why should I use a return statement when I have not called upon any subroutine. I would highly appreciate if you kindly write few lines justifying the use of return statement when I am already in a routine -- the loop(). What would happen if I would use exit() or break;.

GolamMostafa:
I would highly appreciate if you kindly write few lines justifying the use of return...

Not an anachronism.

What would happen if I would use exit()...

Program terminates (yes, that's essentially what happens on an Arduino).

...or break;.

Compilation error. (if is not a looping structure)

GolamMostafa:
as I have not called upon any subroutine..

I'm not sure the term "subroutine" really applies in C++. loop() is a function. loop() is called by the main() function, which is hidden in the Arduino core library but I know you are aware of it from our previous discussion of serialEvent(). So if the term did apply then loop() would be a subroutine.

GolamMostafa:
justifying the use of return statement when I am already in a routine -- the loop().

Let's dig out our old friend main():

int main(void)
{
 init();

 initVariant();

#if defined(USBCON)
 USBDevice.attach();
#endif
 
 setup();
    
 for (;;) {
 loop();
 if (serialEventRun) serialEventRun();
 }
        
 return 0;
}

So when you use the return statement in loop() it returns to main(), does the stupid serialEventRun() thing, then starts the next for loop, which calls loop() again. That takes you back to the top of the loop function.

GolamMostafa:
What would happen if I would use exit()

You exit the program. Since there is nowhere to exit to on your microcontroller everything just hangs after that. Give it a try.

GolamMostafa:
or break;.

break is for use in for, while, or do…while loop or switch...case so you would get a compiler error "error: break statement not within loop or switch".

So if the term did apply then loop() would be a subroutine.

So when you use the return statement in loop() it returns to main(), does the stupid serialEventRun() thing, then starts the next for loop, which calls loop() again. That takes you back to the top of the loop function.

You exit the program. Since there is nowhere to exit to on your microcontroller everything just hangs after that. Give it a try.

Everything -- so nice! so beautiful!! so logical!!!

+!

I'm not convinced that the "goto L0" statements you have in there now are even necessary - they are all at the "end" of if/else clauses where the code path if they're omitted goes past the remaining code anyway.
That's essentially equiv to re-drawing the flowchart so the various side exits go down instead of sideways and up (and the bottom just goes back up, anyway.)

Sort of:

I am a bit reluctant to use the state machine concept as the behavior of the system is not being controlled by any of the past events; rather, it creates some run-time variables that control the future behavior of the system; for example, the flags.

Isn't it -almost- exactly the opposite?

Regards.

I think this is one of those cases (no pun intended) where the notation, in this case a flowchart, adversely affects the approach to structuring of the code, and encourages poor solutions.

I'm not convinced that the "goto L0" statements you have in there now are even necessary - they are all at the "end" of if/else clauses where the code path if they're omitted goes past the remaining code anyway.

I hope that you have noticed the challenge of maintaining the indentations in a program like this (my version) which contains nested if-else structures. So, I have relied upon the goto~~()~~ statements as a quick tools to solve my problem first; then comes the issue of optimization and quality.

GolamMostafa:
I hope that you have noticed the challenge of maintaining the indentations in a program like this (my version) which contains nested if-else structures.

Ctrl + T and the challenge is no more.

Ctrl + T and the challenge is no more.

There are so many little things that make life meaningful!

So, I have relied upon the goto() statements

Please stop writing "goto" as though it were a function - it isn't.

I hope that you have noticed the challenge of maintaining the indentations in a program like this (my version) which contains nested if-else structures.

If the nesting gets too tough, it might be time to consider "re-factoring" your program:

void loop() {
  input = keypad.getKey(); //L0:
  if(input) {                         //L1:
    if(flag2==0x00) {
      process_flag200();
    } else {
      if(input == '*') {
        process_asterix();
      } else if(flag3 == 0x00 && input == 'b') {
        process_b();
      }
    }
  }
}

If the nesting gets too tough, it might be time to consider "re-factoring" your program:

Thanks+; this is an excellent control structure which uses functions, and it has removed all the clumsy codes of my original program. I have taken it as an exercise, and I will report outcome once available.