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"
``````

We now have all the components to display the date in readable format.

``````        READABLE = DAYS<WDAY> ", " MONTHS<MONTH> " " DAY ", " CYEAR
``````

## 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
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.