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.