blandy@awamore.cs.cornell.edu (Jim Blandy) (08/03/88)
# Macros to make DME simulate a universal Turing Machine # This is a DME script. I'm using DME v1.29. # Written by Jim Blandy, 1988 (O I hope the cancel works...) # I thought it might be fun to write. When it worked, my comment was, # "How gross." :-) # Take it as a tribute to Mr. Dillon. # How to work it: # SOURCE this file to load in the bindings. It will bring up two # windows with sample Turing machines in them. # Put your desired input tape on the first line of the buffer. # Leave the second line blank. # Put the name of the initial state on the third line. # Put the source code for the TM at or below the fourth line: # Describe each transition of the tm using the following syntax: # state(symbol)=(write-symbol) direction nextstate # For example, to say "when in state q and reading symbol x, # write a y, move left, and enter state p," write # `q(x)=(y) < p' (without the quotes). # State names can be any non-null alpha-numeric string. # Symbols can be any character (I think...) # Directions can be < (left) or > (right) # Press c-enter (control-keypad enter) to start the TM running; it will # run until it reads a symbol it doesn't know what to do with; # I just tell it to go to states named `accept' or `reject' so # I can tell the difference. # To single-step, # Press c-nk0 (control-keypad zero) to initialize the head. # Press c-nk- (control-keypad minus) to step the TM through one # transition. # A 'Pattern not found' message indicates that the TM has halted; the # state it died in is left on the third line. # I wouldn't recommend trying to flip between single-step and running # modes during the same TM run. Separate runs are okay, of course. # I wouldn't be surprised to hear of a better way to do this; I couldn't # think of one, though. Problems I had to overcome: # I was thinking of defining a key for each state, bound to # a long ifelse string, where each transition was a recursive # call to the next key/state. Unfortunately, DME won't # support recursion past 20 levels, nor will it eliminate # tail recursion. :-) Go for it, Matt! # DME doesn't support marks, i.e. variables referring to a # position in the buffer; these would have been very handy. # There aren't clean ways to insert $scanf into the buffer or # grab the character you're sitting on into $scanf. # No multi-line macros. # Two sample TMs are included at the end of this file; when you source # it, they'll pop up in windows. # Coming soon, to be implemented in DME # A full lisp # Floating point support # :-) # c-nk. - put the character under the cursor in $scanf. (utility routine) # This routine fakes a blank at the end of the line. map c-nk. `ifelse r `` _' left left sc-nk. del del' sc-nk.' # sc-nk. - subroutine for above # the phrase `scanf %1s scanf %c' reads the next character # (even if it's a space) into $scanf; the `scanf %1s' makes # sure the scanf buffer is zero-terminated. :-) map sc-nk. `scanf %1s scanf %c' # c-nk7 - read the symbol under the tape head into $scanf map c-nk7 `goto 1 last find `^' up c-nk.' # c-nk8 - given symbol in $scanf, set line 3 to `state(symbol)' map c-nk8 `goto 3 last `(_)' left left left findr `_' $scanf' # c-nk9 - given current state:symbol pair on line 3, find that transition map c-nk9 `goto 3 first scanf %[~] find $scanf' # c-nk4 - read symbol to write for current transition into $scanf map c-nk4 `c-nk9 find `=(' right right c-nk.' # c-nk5 - replace the character under the write head with $scanf # I go through that findr locution because a 'find-and-replace' # operation seems to be the only way to insert the value of # $scanf into the buffer. map c-nk5 `goto 1 last find `^' up ` _' del left left findr `_' $scanf bs' # c-nk6 - put the cursor on the head direction for the current transition map c-nk6 `c-nk9 find `=(' find `)' right while c=32 right' # c-nk1 - if the cursor is on a <, move the head left; otherwise, move # it right. map c-nk1 `ifelse c=60 `goto 2 first del' `goto 2 first ` ''' # c-nk2 - read the current transition's next state into $scanf map c-nk2 `c-nk9 find `=(' find `)' scanf `)%*[<>]%s'' # c-nk3 - set the current state (line 3) to the contents of $scanf map c-nk3 `goto 3 first remeol ` _' del left left findr `_' $scanf bs' # c-nk- - single-step the TM map c-nk- `c-nk7 c-nk8 c-nk4 c-nk5 c-nk6 c-nk1 c-nk2 c-nk3' # c-nk0 - initialize the TM map c-nk0 `goto 2 first remeol `^'' # c-ENTER - the whole shebang. Given a setup as described above, # go until you run out of transitions. map c-ENTER `c-nk0 repeat -1 `c-nk-'' # ==================== Sample TM #1 ==================== topedge 0 height 100 newwindow chfilename `add' `1111+111' return return `start' return return `start(1) =(1) > start start(+)=(1) > 2nd' return `2nd(1) =(1) > 2nd 2nd( ) =( ) < wipelast' return `wipelast(1)=( ) > done' return `# sample Turing machine #1 - given a string like 11111+111 (two' return `# numbers written in base 1), leave their sum on the tape. For' return `# the above the result would be 11111111.' return' top # ==================== Sample TM #2 ==================== topedge 100 newwindow chfilename `anbn' `aaaaabbbbb' return return `start' return return `start(a)=(X) > findb start( )=( ) > accept' return `findb(a)=(a) > findb findb(Y)=(Y) > findb findb(b)=(Y) < findX' return `findX(Y)=(Y) < findX findX(a)=(a) < findX findX(X)=(X) > nexta' return `nexta(a)=(X) > findb nexta(Y)=(Y) > accept' return `# sample Turing machine #2 - accepts if the string consists of a group' return (# of a's followed by the same number of b's, rejects otherwise) return (# (halting in any state but `accept' means a rejection) ) return top -- Jim Blandy - blandy@crnlcs.bitnet "And now," cried Max, "let the wild rumpus start!"