/*******************************************************************************************
* File Name : Lab1.c
* Description : This file is the skeleton for Lab 1.
* Instructions: Complete the state machine as indicated in the comments inside each state.
* Implement the functions declared below and use them to complete the state machine.
* Do not modify any function declaration.
* Do not modify the main function nor any global declaration or definition.
* Any code above line 146 should not be modified.
* The output should look as follows:
* Program started!
* Stack empty or invalid.
* a b c
* a b c 1 2 3
* popped item: 3
* popped item: 2
* a b c 1
* a b c 1 x y z
* a b c 1 x y z
* Program ended!
*******************************************************************************************/
/******************************************************************************************
* Student Name:
* Student Number:
*
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#define STACK_SIZE 200
#define BUFFER_SIZE 10
/**
* Brief: Structure to hold stack index and stack data
*/
typedef struct {
int8_t index;
char stackData[STACK_SIZE];
} stack_t;
/**
* Brief: Enum to represent type of command.
*/
typedef enum {
COMMAND_NONE = 0,
COMMAND_EXIT,
COMMAND_PUSH,
COMMAND_POP,
COMMAND_PRINT,
} command_t;
/**
* Brief: Structure to hold the parameters passed to the state machine
*/
struct StateMachineParameters {
command_t command;
char input[BUFFER_SIZE];
} parameters[] = {
{.command = COMMAND_NONE}, // Run START_STATE
{.command = COMMAND_NONE}, // Run INITIALIZATION_STATE
{.command = COMMAND_PRINT}, // Expect an error message
{.command = COMMAND_PUSH, .input = "abc"},
{.command = COMMAND_PRINT}, // Expect "abc"
{.command = COMMAND_PUSH, .input = "123"},
{.command = COMMAND_PRINT}, // Expect "abc123"
{.command = 100, .input = "qwerty"}, // Parameters should be neglected
{.command = COMMAND_POP}, // Pop out one item: '3'
{.command = COMMAND_POP}, // Pop out one item: '2'
{.command = COMMAND_PRINT}, // Expect "abc1"
{.command = COMMAND_PUSH, .input = "xyz"},
{.command = COMMAND_PRINT}, // Expect "abc1xyz"
{.command = COMMAND_EXIT}, // Expect "abc1xyz"
};
// Function prototypes
int runStateMachine(struct StateMachineParameters parameters);
bool pushIntoStack(char* pStack, int8_t* pStackIndex, char inputData);
bool popFromStack(char* pStack, int8_t* pStackIndex, char* pOutputData);
void printOutStackContents(char* pStack, int8_t stackIndex);
bool isStackEmpty(int8_t stackIndex);
bool isStackFull(int8_t stackIndex);
void resetStack(char* pStack, int8_t* pStackIndex);
int main() {
int i;
for (i = 0; i < sizeof(parameters) / sizeof(parameters[0]); i++) {
runStateMachine(parameters[i]);
runStateMachine(parameters[0]); // Go back to WAIT_FOR_COMMAND_STATE
}
return 0;
}
/**
* Brief: This function runs a state machine that accepts commands as arguments
* in order to push/pop data into/from a stack structure defined locally and displays its contents.
*/
int runStateMachine(struct StateMachineParameters parameters) {
static stack_t stack;
static char inputString[BUFFER_SIZE]; // Stores the user's input string
static enum {
START_STATE,
INITIALIZATION_STATE,
WAIT_FOR_COMMAND_STATE,
PUSH_TO_STACK_STATE,
POP_FROM_STACK_STATE,
PRINT_STACK_CONTENTS_STATE,
FINISH_STATE
} state = START_STATE;
switch (state) {
case START_STATE: {
state = INITIALIZATION_STATE;
break;
}
case INITIALIZATION_STATE: {
// Reset stack then go to wait for command state
resetStack(stack.stackData, &stack.index);
state = WAIT_FOR_COMMAND_STATE;
break;
}
case WAIT_FOR_COMMAND_STATE: {
// Extract the command embedded in the parameter passed and switch to the
// corresponding state as shown below:
// COMMAND_PUSH -> go to PUSH_TO_STACK_STATE
// COMMAND_POP -> go to POP_FROM_STACK_STATE
// COMMAND_PRINT -> go to PRINT_STACK_CONTENTS_STATE
// COMMAND_EXIT -> go to FINISH_STATE
// Program should neglect any other input
switch (parameters.command) {
case COMMAND_PUSH:
state = PUSH_TO_STACK_STATE;
break;
case COMMAND_POP:
state = POP_FROM_STACK_STATE;
break;
case COMMAND_PRINT:
state = PRINT_STACK_CONTENTS_STATE;
break;
case COMMAND_EXIT:
state = FINISH_STATE;
break;
default:
// Neglect invalid commands
break;
}
break;
}
case PUSH_TO_STACK_STATE: {
// Push the data available in input string into the stack
// Check for overflow condition
// After all data is pushed, go back to WAIT_FOR_COMMAND_STATE
strncpy(inputString
, parameters.
input, BUFFER_SIZE
); for (int i
= 0; i
< strlen(inputString
); i
++) { if (!pushIntoStack(stack.stackData, & stack.index, inputString[i])) {
printf("Stack full. Overflow.\n"); state = WAIT_FOR_COMMAND_STATE;
return 0;
}
}
state = WAIT_FOR_COMMAND_STATE;
break;
}
case POP_FROM_STACK_STATE: {
// Pop out one element from the stack and display the popped out data,
// then go back to WAIT_FOR_COMMAND_STATE
char outputData;
if (popFromStack(stack.stackData, &stack.index, &outputData)) {
printf("Popped item: %c\n", outputData
); }
state = WAIT_FOR_COMMAND_STATE;
break;
}
case PRINT_STACK_CONTENTS_STATE: {
// Display the stack contents without popping out the data, however,
// in case the stack is empty, print out a suitable message.
// Then go back to WAIT_FOR_COMMAND_STATE.
printOutStackContents(stack.stackData, stack.index);
state = WAIT_FOR_COMMAND_STATE;
break;
}
case FINISH_STATE: {
// Perform the same steps done in PRINT_STACK_CONTENTS_STATE except exit the state machine instead of
// going back to WAIT_FOR_COMMAND_STATE.
printOutStackContents(stack.stackData, stack.index);
return 0;
}
default:
state = START_STATE;
break;
}
return 0;
}
bool pushIntoStack(char* pStack, int8_t* pStackIndex, char inputData) {
if (*pStackIndex < STACK_SIZE - 1) {
pStack[++(*pStackIndex)] = inputData;
return true;
} else {
return false; // Stack is full
}
}
bool popFromStack(char* pStack, int8_t* pStackIndex, char* pOutputData) {
if (*pStackIndex >= 0) {
*pOutputData = pStack[(*pStackIndex)--];
return true;
} else {
return false; // Stack is empty
}
}
void printOutStackContents(char* pStack, int8_t stackIndex) {
if (stackIndex >= 0) {
for (int i = 0; i <= stackIndex; i++) {
}
}
else {
printf("Stack empty or invalid.\n"); }
}
bool isStackEmpty(int8_t stackIndex) {
return stackIndex == -1;
}
bool isStackFull(int8_t stackIndex) {
return stackIndex == STACK_SIZE - 1;
}
void resetStack(char* pStack, int8_t* pStackIndex) {
*pStackIndex = -1;
memset(pStack
, 0, STACK_SIZE
); }