Let's implement a simple program in SNOBOL on MTS to print today's date in different formats.
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
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.
Full source code for this program is on github.