############################################################################ # # File: turing.icn # # Subject: Program to simulate a Turing machine # # Author: Gregg M. Townsend # # Date: November 14, 1994 # ############################################################################ # # This file is in the public domain. # ############################################################################ # # This program simulates the operation of an n-state Turing machine, # tracing all actions. The machine starts in state 1 with an empty tape. # # A description of the Turing machine is read from the file given as a # command-line argument, or from standard input if none is specified. # Comment lines beginning with '#' are allowed, as are empty lines. # # The program states must be numbered from 1 and must appear in order. # Each appears on a single line in this form: # # sss. wdnnn wdnnn # # sss is the state number in decimal. The wdnnn fields specify the # action to be taken on reading a 0 or 1 respectively: # # w is the digit to write (0 or 1) # d is the direction to move (L/l/R/r, or H/h to halt) # nnn is the next state number (0 if halting) # # Sample input file: # # 1. 1r2 1l3 # 2. 1l1 1r2 # 3. 1l2 1h0 # # One line is written for each cycle giving the cycle number, current # state, and an image of that portion of the tape that has been visited # so far. The current position is indicated by reverse video (using # ANSI terminal escape sequences). # # Input errors are reported to standard error output and inhibit # execution. # # Bugs: # # Transitions to nonexistent states are not detected. # Reverse video should be parameterizable or at least optional. # There is no way to limit the number of cycles. # Infinite loops are not detected. (Left as an exercise... :-) # # Reference: # # Scientific American, August 1984, pp. 19-23. A. K. Dewdney's # discussion of "busy beaver" turing machines in his "Computer # Recreations" column motivated this program. The sample above # is the three-state busy beaver. # ############################################################################ # # Links: options # ############################################################################ link options record action(wrt, mov, nxs) global machine, lns, lno, errs global cycle, tape, posn, state, video procedure main(args) local opts opts := options(args, "v") video := \opts["v"] rdmach(&input) # read machine description if errs > 0 then stop("[execution suppressed]") lns := **machine # initialize turing machine tape := "0" posn := 1 cycle := 0 state := 1 while state > 0 do { # execute dumptape() transit(machine[state][tape[posn]+1]) cycle +:= 1 } dumptape() end # dumptape - display current tape contents on screen procedure dumptape() if cycle < 10 then writes(" ") writes(cycle, ". [", right(state, lns), "] ", tape[1:posn]) if \video then write("\e[7m", tape[posn], "\e[m", tape[posn + 1:0]) else { write(tape[posn:0]) write(repl(" ", 6 + *state + posn), "^") } end # transit (act) - transit to the next state performing the given action procedure transit(act) tape[posn] := act.wrt if act.mov == "R" then { posn +:= 1 if posn > *tape then tape ||:= "0" } else if act.mov == "L" then { if posn = 1 then tape := "0" || tape else posn -:= 1 } state := act.nxs return end # rdmach (f) - read machine description from the given file procedure rdmach(f) local nstates, line, a0, a1, n machine := list() nstates := 0 lno := 0 errs := 0 while line := trim(read(f), ' \t') do { lno +:= 1 if *line > 0 & line[1] ~== "#" then line ? { tab(many(' \t')) n := tab(many(&digits)) | 0 if n ~= nstates + 1 then warn("sequence error") nstates := n tab(many('. \t')) a0 := tab(many('01LRHlrh23456789')) | "" tab(many(' \t')) a1 := tab(many('01LRHlrh23456789')) | "" pos(0) | (warn("syntax error") & next) put(machine, [mkact(a0), mkact(a1)]) } } lno := "" if *machine = errs = 0 then warn("no machine!") return end # mkact (a) - construct the action record specified by the given string procedure mkact(a) local w, m, n w := a[1] | "9" m := map(a[2], &lcase, &ucase) | "X" (any('01', w) & any('LRH', m)) | warn("syntax error") n := integer(a[3:0]) | (warn("bad nextstate"), 0) return action (w, m, n) end # warn (msg) - report an error in the machine description procedure warn(msg) write(&errout, "line ", lno, ": ", msg) errs +:= 1 return end