summaryrefslogtreecommitdiff
path: root/ipl/progs/turing.icn
diff options
context:
space:
mode:
Diffstat (limited to 'ipl/progs/turing.icn')
-rw-r--r--ipl/progs/turing.icn175
1 files changed, 175 insertions, 0 deletions
diff --git a/ipl/progs/turing.icn b/ipl/progs/turing.icn
new file mode 100644
index 0000000..57ab464
--- /dev/null
+++ b/ipl/progs/turing.icn
@@ -0,0 +1,175 @@
+############################################################################
+#
+# 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 := "<EOF>"
+ 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