The Boston Diaries

The ongoing saga of a programmer who doesn't live in Boston, nor does he even like Boston, but yet named his weblog/journal “The Boston Diaries.”

Go figure.

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.

Obligatory Picture

[It's the most wonderful time of the year!]

Obligatory Links

Obligatory Miscellaneous

You have my permission to link freely to any entry here. Go ahead, I won't bite. I promise.

The dates are the permanent links to that day's entries (or entry, if there is only one entry). The titles are the permanent links to that entry only. The format for the links are simple: Start with the base link for this site: http://boston.conman.org/, then add the date you are interested in, say 2000/08/01, so that would make the final URL:

http://boston.conman.org/2000/08/01

You can also specify the entire month by leaving off the day portion. You can even select an arbitrary portion of time.

You may also note subtle shading of the links and that's intentional: the “closer” the link is (relative to the page) the “brighter” it appears. It's an experiment in using color shading to denote the distance a link is from here. If you don't notice it, don't worry; it's not all that important.

It is assumed that every brand name, slogan, corporate name, symbol, design element, et cetera mentioned in these pages is a protected and/or trademarked entity, the sole property of its owner(s), and acknowledgement of this status is implied.

Copyright © 1999-2019 by Sean Conner. All Rights Reserved.