#include #include #include #include #include "quint.h" #include "tape.h" #include "tm.h" #include "getcmd.h" #include "help.h" /* execute one step of the turing program. */ void one_step(struct qlist *lptr, struct tape *tptr, int nstep, int debug, int *status) { struct quint *doquint; struct cell *cursor; extern struct quint *lastquint, *nextquint; int i, doquint_stat; static int stringlen; if (nstep == 1) /* 'stringlen' is length of descriptor string printed so far*/ stringlen = 0; if (tptr->head == NULL) { *status = NO_TAPE; return; } if (lptr->root == NULL) { *status = NO_QLIST; return; } if (lptr->root->nextptr == NULL) { *status = EMPTY_QLIST; return; } /* find the quintuple to be executed next */ doquint = find_quint(lptr,tm_state,tptr->head->Csymbol,status); doquint_stat = *status; /* display the tape if trace is not 'off' */ if (trace) { if (trace == 2) { /* display machine in inst. descrip. form*/ /* see if we should write the new descriptor on a new line */ stringlen += tptr->tape_len + 9; if (stringlen >= LINESIZE) { stringlen = tptr->tape_len + 9; printf("\n"); } /* write the descriptor */ printf("("); /* move to the left end of the tape: */ cursor = tptr->leftend; /* write tape that is left of the tape head */ while (cursor != tptr->head) { printf("%c",cursor->Csymbol); cursor = cursor->rptr; } /* write machine state */ printf(",%c,",tm_state); /* write tape that is at the tape head and to the right */ while (cursor != NULL) { printf("%c",cursor->Csymbol); cursor = cursor->rptr; } printf(") -> "); } else { /* display tape and tape head only */ show_tape(tptr,status); if (debug) { printf(" state: %c, next quint: ",tm_state); if (doquint != NULL) print_quint(doquint,lptr); else printf("(none)\n"); } } } /* exit if we have entered a final state */ if (doquint == NULL) { if ( doquint_stat == NON_HAVE_STATE ) *status = HALTED_FINAL; else if ( doquint_stat == STATE_BUT_NO_SYM ) *status = HALTED; return; } /* there is a valid quintuple to be executed */ if (debug) { /* check for break points */ if (doquint->brk == 1) { *status = AT_BREAK_POINT; return; } if (nwatchstate > -1) /* check watched variables */ for (i=0; i<=nwatchstate; i++) if (watch_state[i] == doquint->next_state) { *status = AT_STATE_WATCH; return; } if (nwatchsymbol > -1) for (i=0; i<=nwatchsymbol; i++) if (watch_symbol[i] == doquint->next_symbol) { *status = AT_SYMBOL_WATCH; return; } } /* write the new symbol on the tape */ tptr->head->Csymbol = doquint->next_symbol; /* set the machine state */ tm_state = doquint->next_state; /* move the tape head */ if( move_head(tptr, doquint->move) == NULL) { *status = MEM_ERROR; return; } /* increment the quintuple's iteration count */ doquint->num_used++; /* increment the total execution count*/ tm_num_exe++; /* keep track of things */ lastquint = doquint; nextquint = find_quint(lptr,tm_state,tptr->head->Csymbol,status); *status = OK; } /* routine for tm 'step' command */ /**/ void step(struct qlist *lptr, struct tape *tptr, int *status) { int number; /* number of times to execute quintuples */ int i; extern int debug; if ( getifint(&number) == 0 ) /* number of times to step */ number = 1; /* default is to step once */ if (number == 1) one_step(lptr,tptr,1,0,status); /* step without checking break pts.*/ else for (i=1; i<=number; i++) { one_step(lptr,tptr,i,debug,status);/* step while checking break pts.*/ if (*status != OK) break; } if (trace==2) /* clean up output for printing descriptors */ printf("\n"); /* step returns the status from one_step */ } /* execute turing machine instructions up to MAX_STEP in number or till halt state. */ void go(struct qlist *lptr,struct tape *tptr,int *status) { int nstep=0; int break_flag = 0; extern int max_step, debug; while(1) { nstep++; if (nstep >= max_step) while (1) { /* running too long. Ask user if we should stop*/ if (morecmd()) flushcmd("Command stream after 'go' deleted. ","",1); printf("Tape is %d symbols long following %d steps.\n", tptr->tape_len,nstep); getcmd("Shall I continue? [y/n] ", ans); if ( iscmd(ans,"y") ) { nstep = -1; break; } else if ( iscmd(ans,"n") ) { break_flag = 1; while(1) { getcmd("want to view the tape? [y/n] ", ans); if (iscmd(ans,"y") ) { *status = SHOW_TAPE; break; } else if ( iscmd(ans,"n") ) { *status = NO_SHOW_TAPE; break; } else flushcmd("answer 'y' or 'n'.","",1); } break; } else if (iscmd(ans,"#") ) flushcmd("","",0); else flushcmd("answer 'y' or 'n'.","",1); } else { one_step(lptr,tptr,nstep,debug,status); if (*status != OK) break_flag = 1; } if ( break_flag ) break; } if (trace==2) /* clean up on printing descriptors */ printf("\n"); } /* move the tape head according to user request. */ void move(struct tape *tptr, int *status) { int i, number; *status = OK; if (tptr->root == NULL) { *status = NO_TAPE; return; } while(1) { getcmd("move left or right? ",ans); if ( iscmd (ans,"e*xit") || iscmd(ans,"quit") || iscmd(ans,".") ) break; else if ( iscmd (ans,"l*eft") ) /* options: to left 'end' or number of cells. Else number = 1*/ { if (getifcmd("e*nd",ans) == 1) tptr->head = tptr->leftend; else { if (getifint(&number) == 0) number = 1; for (i=1; i<=number; i++) if ( move_head(tptr, 'L') == NULL) { *status = MEM_ERROR; return; } } break; } else if ( iscmd (ans,"r*ight") ) { if (getifcmd("e*nd",ans) == 1) /* move to right end of tape */ { if (tptr->root != NULL) while( (tptr->head->rptr) != NULL ) tptr->head = tptr->head->rptr; } else { if (getifint(&number) == 0) number = 1; for (i=1; i<=number; i++) if ( move_head(tptr, 'R') == NULL) { *status = MEM_ERROR; return; } } break; } else if ( iscmd(ans,"h*elp") || iscmd(ans,"?") ) get_help("tm move"); else if (iscmd(ans,"#") ) flushcmd("","",0); else flushcmd("invalid 'move' response -> ",ans,1); } }