Files

131 lines
3.9 KiB
C
Raw Permalink Normal View History

2026-05-31 14:34:00 -04:00
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "effects.h"
#include "model.h"
// TODO: Complete this table mapping state/events to the target state. Each
// row corresponds to the current state. Each column within that row indicates
// the next state for a given event. If there is no transition defined, that
// entry should be NST ("no state").
static state_t const _transitions[NUM_STATES][NUM_EVENTS]
= { { Command, Term, NST },
{ Arguments, Make_Pipe, Term },
{ Arguments, Make_Pipe, Term },
{ Command, Term, Term },
{ NST, NST, NST } };
// TODO: Create a table mapping states/events to the effect functions. If
// there is no valid transition, the entry here would be NULL because actions
// are function pointers.
static action_t const _effects[NUM_STATES][NUM_EVENTS]
= { { start_command, error_pipe, NULL },
{ append, link_commands, execute },
{ append, link_commands, execute },
{ start_command, error_pipe, error_newline },
{ NULL, NULL, NULL } };
/* Create an instance of an FSM and initialize its fields as appropriate.
Some fields are common to most FSMs (such as an initial state or a
pointer to a transition function). Other fields will be specific to
this fsm_t declaration. Return NULL if any part of the initialization
fails. */
fsm_t *
cmdline_init (void)
{
fsm_t *fsm = calloc (1, sizeof (fsm_t));
fsm->state = Init;
fsm->transition = transition;
return fsm;
}
// TODO: Create a transition function that is specific to this type
// of FSM. This function needs to take an fsm_t* and an event, returning
// both the new state and the effect to perform (the latter is returned
// using a call-by-reference parameter. This function should NOT contain
// any "if" types of statements based on the state or event; it should
// simply lookup these values in the tables defined above.
state_t
transition (struct fsm *fsm, event_t event, action_t *effect)
{
assert (fsm->state < NST);
assert (event < NIL);
*effect = _effects[fsm->state][event];
return _transitions[fsm->state][event];
}
/* Helper function for providing a printable string name for an event */
const char *
event_name (event_t evt)
{
assert (evt <= NIL);
// Event names for printing out
const char *names[] = { "TOKEN", "PIPE", "NEWLINE", "NIL" };
return names[evt];
}
/* Helper function for providing a printable string name for an state */
const char *
state_name (state_t st)
{
assert (st <= NST);
// State names for printing out
const char *names[]
= { "Init", "Command", "Arguments", "Make_Pipe", "Term", "NST" };
return names[st];
}
/* Generic front-end for handling events. Should do nothing more
than calling the FSM's transition function, performing an effect
(if appropriate) and updating the state. Return false if the new
state is the terminal state. */
bool
handle_event (fsm_t *fsm, event_t event)
{
assert (fsm != NULL);
// TODO: Look up the current state/event combination in the
// transition table. Print the following line for debugging
// purposes just for this lab. This should be printed even
// if there is no transition.
action_t effect;
state_t new_state = fsm->transition (fsm, event, &effect);
printf ("[%s.%s -> %s]\n", state_name (fsm->state), event_name (event),
state_name (new_state));
// TODO: If the state/event combination is valid, execute
// the transition and effect function (if there is one).
// If the next state is Term (terminated), return false.
// Otherwise return true.
if (new_state != NST)
{
if (effect != NULL)
{
effect (fsm);
}
fsm->state = new_state;
}
return fsm->state != Term;
}
/* Given a string, return the event type. Do not modify this function. */
event_t
lookup (char *token)
{
if (!strcmp (token, "|"))
return PIPE;
if (!strcmp (token, "NL"))
return NEWLINE;
return TOKEN;
}