Saturday, Debtember 26, 2015
The Psychotherapy of Racter, or The Further Descent Into Madness of Sean Conner
Now that I have some downtime, perhaps it's time to revisit the idea of natively compiling the Racter source code. How hard could that be?
Please don't answer that.
Anyway, I have a copy of Racter, so with that and what little information exists in the Racter FAQ, I should be able to reverse engineer the “source code” and get something working.
I've made some progress (I'm using Lua and LPeg for this). I'm only twelve lines in, but here's what I've been able to figure out, starting with the initial file Racter loads:
IV.IF Interview with INRAC IBM 6-4-85 initial transient file 1 2 52 SECTION 1 hello 5 34 SECTION 2 sue 5 18 A :LOADIV :OUTRACTER >2= >3= ?51= />51=Smith # XA Hello, I'm Racter. ?40= \# You are? ?? #*1B X Are you $40 ? ?? # X ?no,not \# >1=R ?i'm,am,is /# Who are you then? ?? :F=0 # X ?yes \# ?-:but /# >1=R #*1B X \# You are $40 $51 ? ?? ?yes /#*2SAME ?i'm,is /# #*1XC B ?i \# >1=R ?don't,won't \# *1COY ?? #*1B X ?a,an,the \?called \?am,i'm,is,me,as,it's \# :F+1 >2=F ?-:2= # X /# ?CAP \# >2=F :F+1 >4=F ?4= \#*1XB #*1DO X /# *1DUH ?? #*1B XB ?CAP+1 />3=F # X >1=2 ?CAP \>2=C,2 # C *1Xcall $2 , then? ?? ?no,not,Q /?-:why /# #*1DO X >1=R ?CAP \# #*1B XC What's your name then? :F=0 ?? #*1B Xcall I may call you Xcall You are Xcall Your name is DO Hello, $2 . I believe you're interviewing me. # X ?2=40 \# >40=40,51 # X ?40= /# Are you continuing $40 <'s interview? # X /# ?? ?no,not,don't /# #*2DIF X ?40= /# Then we'll forget about $40 and start over. # X :ZAP :PUTIV # EXIT >40=2 ?3= \>51=3 What would you like to know? #*2GO COY Come on, what's your name? COY You must have a name - what is it? COY Your name, please . COY I have to call you something - what shall it be? DUH I didn't get that . *1WHO DUH I don't understand . *1WHO DUH Eh? *1COY WHO Who ? WHO Who are you ? DIFA Well, $2 , $40 and I >4=40 >40=2 ?3= \>51=3 #*2A SAME Hi, $40 . >4=You ?52= /# How are things in $52 ? # x We # A ?20= />20=various,things # x were talking about $20 last time. # x ?10=VERBQ \?10= />3=whether \>3=10 # x $4 had just asked D $3 $19 . # CONT Shall we continue? ?? ?z \# #*1XA x ?why /?not /# ?no,not \# #*2QUIT x Excellent! # GO Excuse me a minute while I attend to some # x business - I'll be right back. I'm # x ?42= />42=Oz # x ?19= />19=I,have,to,rest,now # x :PUTIV # X %KEY %VOCAB1 %VOCAB2 %VOCAB3 %BILL %IV1 %RAPT %RAPT2 back. *15A QUIT You want to quit? ?no,not \# Well, goodbye then. X That's good. #*2GO
The first four lines are the file header, and every source file contains this. The first line is the original input file along with a comment. The second line is the starting section in this file, in this case, we start with section 1. The next line is the number of sections defined in the file, so we know we have a total of two sections. The fourth line is the total number of “code” lines to load in. More on this in a bit.
Then we have the section headers, in this case there are two of them.
SECTION 1 hello 5 34 SECTION 2 sue 5 18
It can also look like:
SEC 1 hello 5 34 SEC 2 sue 5 18
Yup,
the TION
of SECTION
is optional.
Sigh.
Anyway,
we start with SECTION
,
followed by the section number followed by text that as far as I can tell,
is not used and therefore,
is a comment.
I'm pretty sure the next number is an indication of how to parse the lines of “code” in this section
(“5” appears to be more “executable” code than anything,
while other sections appear to be more data) and the final number is the number of “code lines” making up this section.
For this file, if you add 34
(the number of lines in section 1)
and 18
(the number of lines in section 2)
you get 52,
which is the value in the overall file header.
And after the section headers,
we have the code that comprises all the sections of the file.
The code to parse the header and section portions was easy enough to write. I'm now in the process of parsing the rest and right now, I'm almost two lines in.
A :LOADIV :OUTRACTER >2= >3= ?51= />51=Smith # XA Hello, I'm Racter. ?40= \# You are? ?? #*1B
Each line is, for lack of a better term, a subroutine, but there are exceptions. Each line starts with a label and here we see the first line with the label of “A” and the second line with a label of “XA”.
The first line (“A”) starts with :LOADIV
,
which loads the saved data from the previous session.
:OUTRACTER
then creates the output file RACTER.OUT
that is a transcript of the session currently running.
>2=
assigns variable 2 to an empty string
(yup,
I don't have named variables).
And likewise, >3=
assigns variable 3 with an empty string.
The next bit,
?51=
compares variable 51 to an empty string.
The “/” is the “if true” statement so />51=Smith
assigns variable 51 to “Smith” if it initially was empty.
The last character,
#
,
means we continue on excuting with the next line.
I can parse this line and it generates the following Lua code:
function() loadiv() outracter() VARS[2] = "" VARS[3] = "" local equal = VARS[51] == "" if equal then VARS[51] = "Smith" end return gotonext(1,2) -- goto line 2 of section 1 end
The reason I'm doing:
local equal = VARS[51] == "" if equal then VARS[51] = "Smith" end
and not:
if VARS[51] == "" then VARS[51] = "Smith" end
is that it's easier to code the “long way around” for now. More on this below.
Now the second line (“XA”).
We have “Hello, I'm Racter.”
This is text to be displayed.
Then we have another variable being compared to an empty string,
?40=
.
And here we have the “if false” statement,
\#
,
which means if variable 40 isn't an empty string we go to the next line.
If variable 40 is empty,
then we display “You are?”
The ??
means we accept input from the user,
and finally we randomly go to one of the lines labeled “B” in section 1
(no, really—it's that messed up).
In Lua,
this would look something like:
function() display("Hello, I'm Racter. ") local equal = VARS[40] == "" if not equal then return gotonext(1,3) -- goto line 3 of section 1 end display("You are? ") getinput() return gotonext(1,"B") end
(I'm still working on parsing line two) Now, I mentioned that “/” is “if true” and “\” is “if false” and that I'm doing a roundabout way of generating the code. That's not only because you have code like:
?50=foo />40=bar
or
?50=foo \>40=baz
but
?50=foo />40=bar \>40=baz
and
?50=foo \>40=baz />40=bar
I'm running under the rule of “make it right, then make it fast.” Parsing this mess is hard enough as it is, and I'm still not quite done parsing line two properly yet.
Ah, the things i do for fun.