#include /* malloc */ #include #include /* toupper */ #include #include #include "getcmd.h" #include "tape.h" #include "tm.h" /* Create a new cell, initialized to a blank. */ struct cell *new_cell(int *status) { struct cell *new = malloc(sizeof(struct cell)); if (new == NULL) { if (status != NULL) *status = OUT_OF_MEMORY; return NULL; } new->Csymbol = ' '; new->lptr = new->rptr = NULL; return new; } void delete_tape(struct tape *tptr) { struct cell *cursor; if (tptr->root == NULL) return; /* move to the left end of the tape: */ cursor = tptr->leftend; if (tptr->tape_len >= 10000) printf("Freeing %d tape cells...\n", tptr->tape_len); /* move along the tape to the right deleting each cell: */ while (1) { if (cursor->rptr == NULL ) break; cursor = cursor->rptr; free(cursor->lptr); } /* delete the last cell */ free(cursor); tptr->tape_len = 0; tptr->root = tptr->head = tptr->leftend = NULL; } /* return NULL if malloc fails */ struct cell *init_tape(struct tape *tptr) { if (tptr->root != NULL) delete_tape(tptr); tptr->leftend = tptr->head = tptr->root = new_cell(NULL); if (tptr->head == NULL) return(NULL); tptr->head->lptr = NULL; tptr->head->rptr = NULL; tptr->tape_len = 0; return(tptr->root); } /* head is off right end of tape. Add a new blank. */ /* return NULL if malloc fails. */ struct cell *make_rcell(struct tape *tptr) { if (tptr->head->rptr == NULL) tptr->head->rptr = new_cell(NULL); if (tptr->head->rptr == NULL) return(NULL); tptr->head->rptr->lptr = tptr->head; tptr->head->rptr->rptr = NULL; (tptr->tape_len)++; return(tptr->head->rptr); } /* head is off left end of tape. Add a new blank. return NULL if malloc fails */ struct cell *make_lcell(struct tape *tptr) { tptr->head->lptr = new_cell(NULL); if (tptr->head->lptr == NULL) return(NULL); tptr->head->lptr->lptr = NULL; tptr->head->lptr->rptr = tptr->head; (tptr->tape_len)++; tptr->leftend = tptr->head->lptr; return(tptr->head->lptr); } /* move the tape head one cell left or right. If the tape head was */ /* at the end of the tape, add a blank. */ /* Returns NULL if adding a blank fails. */ /**/ struct cell *move_head(struct tape *tptr, char ch) { if (tptr->root == NULL) return(NULL); if (ch=='L') { if ( tptr->head->lptr == NULL ) if ( make_lcell(tptr) == NULL ) return(NULL); return(tptr->head = tptr->head->lptr); } else if (ch == 'R') { if ( tptr->head->rptr == NULL ) if ( make_rcell(tptr) == NULL ) return(NULL); return(tptr->head = tptr->head->rptr); } else return(tptr->head); /* no motion */ } /* show the tape. Indicate the location of the tape head with a '^', and show the machine state. */ /* */ void show_tape(struct tape *tptr, int *status) { struct cell *cursor; if (tptr->root == NULL) { *status = NO_TAPE; return; } /* move to the left end of the tape: */ cursor = tptr->leftend; /* move along the tape to the right displaying each cell: */ while( (cursor->rptr) != NULL ) { printf("%c",cursor->Csymbol); cursor = cursor->rptr; } printf("%c",cursor->Csymbol); printf("\n"); /* go to a new line */ /* move again to the left end of the tape: */ cursor = tptr->leftend; /* write blanks until the tape head is located, then write '^': */ while( (cursor->rptr) != NULL ) { if ( cursor != tptr->head ) { printf(" "); cursor = cursor->rptr; } else { printf("^\n"); break; } } if ( (cursor->rptr) == NULL ) printf("^\n"); *status = OK; } /* get a new tape from standard input. */ void get_new_tape(struct tape *tptr, int *status) { int i; char ch, new_tape[ANS_LENGTH]; /* deletes old tape, creates a blank cell */ if ( init_tape(tptr) == NULL) { *status = MEM_ERROR; return; } tptr->tape_len = 1; getcmd("enter tape (as a string): ",new_tape); if (new_tape[0]!='\0') /* else tape is the single blank cell */ { tptr->head->Csymbol = new_tape[0]; /* covers first blank cell */ i = 0; while( new_tape[++i]!='\0' ) { if ( move_head(tptr,'R') == NULL ) { *status = MEM_ERROR; return; } tptr->head->Csymbol = new_tape[i]; } tptr->head = tptr->leftend; } *status = OK; return; }