Beginner

Operators in SNOBOL

Learn arithmetic, comparison, and pattern operators in SNOBOL - including how comparisons work as success/failure predicates with Docker-ready examples

Operators are how you combine values into expressions. In most languages this is straightforward: + adds, == compares, && joins booleans. SNOBOL takes a different path that reflects its pattern-directed heritage.

SNOBOL has familiar arithmetic operators, but it has no comparison operators and no boolean operators in the usual sense. Instead, comparisons are predicate functions that either succeed or fail — and that success or failure drives program flow through goto labels, just as pattern matching does. There is also a whole family of pattern operators (alternation, concatenation, value assignment) that exist nowhere else in mainstream programming.

This tutorial covers four groups of operators:

  1. Arithmetic+, -, *, /, **, and precedence
  2. Concatenation — joining values by writing them side by side
  3. Comparison — predicate functions like GT, EQ, IDENT that succeed or fail
  4. Pattern operators| (alternation), . (value assignment), and match-replace

A crucial rule throughout: binary operators must have a blank on each side. A + B is addition; A+B is an error, and A - B differs from the concatenation A -B. Whitespace is significant in SNOBOL.

Arithmetic Operators

SNOBOL supports the usual arithmetic operators plus exponentiation with **. Division between two integers is integer division — it truncates toward zero.

Create a file named arithmetic.sno:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
*       Arithmetic operators in SNOBOL
*       Binary operators MUST have a blank on each side
        A = 17
        B = 5
        OUTPUT = "Addition: " (A + B)
        OUTPUT = "Subtraction: " (A - B)
        OUTPUT = "Multiplication: " (A * B)
        OUTPUT = "Division: " (A / B)
        OUTPUT = "Exponentiation: " (A ** B)
        OUTPUT = "Negation: " (- A)
        OUTPUT = "Precedence (2 + 3 * 4): " (2 + 3 * 4)
        OUTPUT = "Grouped ((2 + 3) * 4): " ((2 + 3) * 4)
END

The parentheses around each calculation group the arithmetic so its result can be concatenated onto the label string. Note that 17 / 5 yields 3, not 3.4 — integer division discards the remainder. Multiplication and exponentiation bind tighter than addition, so 2 + 3 * 4 is 14, while parentheses force (2 + 3) * 4 to 20.

Concatenation

SNOBOL has no + or . operator for joining strings. Instead, you simply write two values next to each other, separated by a blank. This juxtaposition is the concatenation operator, and it is one of the most-used operators in the language.

Create a file named concatenation.sno:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
*       Concatenation joins values with a blank between them
        FIRST = "Code"
        SECOND = "Archaeology"
        OUTPUT = FIRST SECOND
        OUTPUT = FIRST " " SECOND
*       Numbers are concatenated as text, not added
        OUTPUT = 12 34
*       Mix a variable into a string
        VERSION = 4
        OUTPUT = "SNOBOL" VERSION
END

FIRST SECOND produces CodeArchaeology with no gap — the blank between operands is syntax, not data. To get an actual space in the output you must concatenate a space literal: FIRST " " SECOND. And because concatenation is text-based, 12 34 becomes the string 1234, not the sum 46. This is the opposite of the arithmetic operators, where blanks separate operands that get combined numerically.

Comparison Operators (Predicate Functions)

Here SNOBOL diverges sharply from modern languages. There is no ==, <, or >. Comparisons are predicate functions: they return the null string and succeed when the relation holds, and they fail otherwise. You react to that success or failure with the :S(label) and :F(label) goto fields — the same mechanism SNOBOL uses for pattern matching.

PredicateMeaning
EQ(X, Y)numeric equal
NE(X, Y)numeric not equal
LT, LE, GT, GEnumeric <, <=, >, >=
IDENT(X, Y)objects are identical (string equality)
DIFFER(X, Y)objects differ

Create a file named comparison.sno:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
*       Comparison operators are predicate functions.
*       Each one SUCCEEDS or FAILS instead of returning true/false.
        X = 10
        Y = 20
*       Numeric comparisons: EQ NE LT LE GT GE
        OUTPUT = GT(Y, X) "GT: Y is greater than X"      :F(L2)
L2      OUTPUT = LE(X, Y) "LE: X is <= Y"                :F(L3)
L3      OUTPUT = EQ(X, 10) "EQ: X equals 10"             :F(L4)
L4      OUTPUT = NE(X, Y) "NE: X is not equal to Y"      :F(STR)
*       String comparisons: IDENT (same) and DIFFER
STR     OUTPUT = DIFFER("cat", "dog") "DIFFER: cat <> dog"  :F(L6)
L6      OUTPUT = IDENT("cat", "cat") "IDENT: cat = cat"     :F(END)
END

Read each line carefully: GT(Y, X) runs first. Because 20 > 10, it succeeds and returns the null string, which concatenates with the message to produce the output. If a predicate had failed, the whole assignment would fail (nothing would be printed) and the :F(...) field would jump to the next test. This is how SNOBOL expresses boolean logic — not with && and ||, but by chaining predicates through success and failure paths.

Pattern Operators

Patterns are first-class values in SNOBOL, and they have their own operators. The most important are alternation (|, meaning “either/or”), concatenation (blank, just like with strings), and value assignment (., which captures the matched substring into a variable). A bare pattern match in a statement also performs replacement when followed by = value.

Create a file named pattern_operators.sno:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
*       Pattern operators build and apply patterns
*       Alternation (|): match "cat", "dog", or "bird"
        ANIMAL = "cat" | "dog" | "bird"
        "I have a dog" ANIMAL . FOUND               :S(SHOW1)F(NAMES)
SHOW1   OUTPUT = "Found animal: " FOUND
*       Concatenation of patterns + value assignment (.)
NAMES   FULLNAME = "John Smith"
        FULLNAME BREAK(" ") . GIVEN " " REM . FAMILY
        OUTPUT = "First name: " GIVEN
        OUTPUT = "Last name: " FAMILY
*       Match-and-replace loop: swap every "-" for "/"
        DATE = "2026-05-26"
SWAP    DATE "-" = "/"                              :S(SWAP)
        OUTPUT = "Reformatted: " DATE
END

Three operators are at work here:

  • | (alternation) builds a pattern matching any of cat, dog, or bird. The subject "I have a dog" matches dog, the match succeeds, and :S(SHOW1) runs.
  • . (value assignment) captures matched text. BREAK(" ") . GIVEN matches everything up to the first space and stores it in GIVEN; REM . FAMILY captures the remainder. The pattern is the concatenation of BREAK(" "), a literal space, and REM.
  • Match-replace DATE "-" = "/" finds the first - and substitutes /. Because each replacement succeeds, :S(SWAP) loops back until no - remains and the match finally fails, falling through to the output line.

Running with Docker

Run each example with the SNOBOL interpreter image. The -v $(pwd):/app -w /app flags mount your current directory so the interpreter can find the file.

1
2
3
4
5
6
7
8
# Pull the official image
docker pull esolang/snobol:latest

# Run each example
docker run --rm -v $(pwd):/app -w /app esolang/snobol:latest snobol arithmetic.sno
docker run --rm -v $(pwd):/app -w /app esolang/snobol:latest snobol concatenation.sno
docker run --rm -v $(pwd):/app -w /app esolang/snobol:latest snobol comparison.sno
docker run --rm -v $(pwd):/app -w /app esolang/snobol:latest snobol pattern_operators.sno

Expected Output

Running arithmetic.sno:

Addition: 22
Subtraction: 12
Multiplication: 85
Division: 3
Exponentiation: 1419857
Negation: -17
Precedence (2 + 3 * 4): 14
Grouped ((2 + 3) * 4): 20

Running concatenation.sno:

CodeArchaeology
Code Archaeology
1234
SNOBOL4

Running comparison.sno:

GT: Y is greater than X
LE: X is <= Y
EQ: X equals 10
NE: X is not equal to Y
DIFFER: cat <> dog
IDENT: cat = cat

Running pattern_operators.sno:

Found animal: dog
First name: John
Last name: Smith
Reformatted: 2026/05/26

Key Concepts

  • Binary operators need blanksA + B is addition, but A+B is an error and A B is concatenation. Whitespace is part of the syntax.
  • Concatenation is juxtaposition — write values side by side to join them. There is no dedicated + or . string operator, and 12 34 concatenates to 1234 rather than adding.
  • Division truncates — integer divided by integer yields a truncated integer (17 / 5 is 3), so be deliberate about expecting fractional results.
  • Comparisons succeed or failGT, LT, EQ, NE, IDENT, and DIFFER are predicate functions, not operators. They return the null string on success and fail otherwise, and you branch with :S(...)/:F(...).
  • No boolean operators — SNOBOL has no && or ||. Logic is expressed by chaining predicates through success/failure paths and by pattern alternation |.
  • Pattern operators are first-class| (alternation), blank (concatenation), and . (value assignment) build patterns, while match-with-= performs substitution. These operators, not arithmetic, are the heart of the language.

Running Today

All examples can be run using Docker:

docker pull esolang/snobol:latest
Last updated:

Comments

Loading comments...

Leave a Comment

2000 characters remaining