SNOBOL - Date formats
Let’s implement a simple program in SNOBOL on MTS to print today’s date in different formats.
The problem
The problem is quite simple: take today’s date and display it in ISO format (eg 2015-10-11) and a human readable format (eg Sunday, October 11, 2015). Further details and implementations in other languages can be found on Rosetta Code.
Getting today’s date
There’s a built in function in SNOBOL to return the date as an eight character string. Interestingly, the SNOBOL 4 Programming Language says this returns ‘MM/DD/YY’ but on MTS it returns ‘MM-DD-YY’. Let’s get this and store in a variable.
NOW = DATE()
Breaking the date into components
We take the date and extract the month, day and year using SNOBOL’s pattern matching facility and assign it to variables DAY, MONTH, and YEAR.
PART = SPAN("0123456789")
SEP = "-"
NOW (PART . MONTH) SEP (PART . DAY) SEP (PART . YEAR)
Y2K strikes again
The value returned from DATE() has a two digit year, so let’s assume we are running this in the 21st century.
CENTURY = 2000
CYEAR = YEAR + CENTURY
Displaying in ISO format
So displaying the date in ISO format is now simply a case of concatenating the day, month and four digit year and then outputting it.
ISO = CYEAR SEP MONTH SEP DAY
OUTPUT = ISO
Day of the week
We now turn to the human readable form but there is a slight problem - we need to know which day of the week it is, eg Monday, and there is no facility in SNOBOL to calculate this. There may be a MTS external library we could call to get this, but instead we will use Gauss’ algorithm to derive the day as a number from 0 (Sunday) to 6 (Saturday).
* GYEAR is the 4 digit year, unless Jan or Feb then subtract 2
* GMONTH is MONTH-2 modulus 12, Jan is 11, Feb is 12
GT(MONTH, 2) :S(G1)F(G2)
G1 GYEAR = CYEAR
GMONTH = MONTH - 2 :(GX)
G2 GYEAR = CYEAR - 1
EQ(MONTH, 1) :S(G3)F(G4)
G3 GMONTH = 11 :(GX)
G4 GMONTH = 12 :(GX)
GX WDAY = REMDR(DAY, 7)
* Calculate the month term
MT = (2.6 * GMONTH) - 0.2
* Add the month term - the 0.00005 is needed due to lack of FP precision
WDAY = WDAY + REMDR(CONVERT(MT + 0.00005, 'INTEGER'), 7)
WDAY = WDAY + 5 * REMDR(REMDR(GYEAR, 4), 7)
WDAY = WDAY + 4 * REMDR(REMDR(GYEAR, 100), 7)
WDAY = WDAY + 6 * REMDR(REMDR(GYEAR, 400), 7)
WDAY = REMDR(WDAY, 7)
Month and day names
We will need a way of translating a month and day number into a name, eg January or Monday. SNOBOL’s arrays can be used for this. Note that the DAYS array is indexed from 0 to 6 instead of 1 to 7.
MONTHS = ARRAY("12")
MONTHS<1> = "January"
MONTHS<2> = "February"
* ...
MONTHS<11> = "November"
MONTHS<12> = "December"
DAYS = ARRAY("0:6")
DAYS<0> = "Sunday"
DAYS<1> = "Monday"
* ...
DAYS<5> = "Friday"
DAYS<6> = "Saturday"
Displaying in readable format
We now have all the components to display the date in readable format.
READABLE = DAYS<WDAY> ", " MONTHS<MONTH> " " DAY ", " CYEAR
OUTPUT = READABLE
Running the program
Here’s what the output of the program looks like.
# $run *snobol4 5=date.sn
# Execution begins 21:09:05
SNOBOL4 (VERSION 3.10, APRIL 1, 1973)
(MTS IMPLEMENTATION MAY 1, 1975)
0 SYNTACTIC ERROR(S) IN SOURCE PROGRAM
2015-10-11
Sunday, October 11, 2015
NORMAL TERMINATION AT LEVEL 0
LAST STATEMENT EXECUTED WAS 53
SNOBOL4 STATISTICS SUMMARY
38 MS. COMPILATION TIME
1 MS. EXECUTION TIME
41 STATEMENTS EXECUTED, 0 FAILED
21 ARITHMETIC OPERATIONS PERFORMED
1 PATTERN MATCHES PERFORMED
0 REGENERATIONS OF DYNAMIC STORAGE
0 READS PERFORMED
2 WRITES PERFORMED
0.02 MS. AVERAGE PER STATEMENT EXECUTED
# Execution terminated 21:09:05 T=0.045
Final thoughts on SNOBOL
Using SNOBOL feels close to modern scripting languages such as Perl, Python or Ruby. I really like the pattern matching facilities where you can do things like EXPR = TERM | *EXPR OP TERM which is much more powerful than regular expressions; I don’t think there is any modern language that has this built in. The lack of control flow processing apart from GOTO is annoying; later versions of the language such as SPITBOL addressed this. I imagine that it was also rather slow when running on a mainframe, especially as it had to be compiled each time it was run.
I don’t think SNOBOL is much in use today, but the maintainer of SPITBOL is still active.
Further information
Full source code for this program is on github.