On this page:
2.1 Main Entry Points
2.2 A Minimal Backend Example
2.3 Backend Helpers
2.4 Useful Runtime Parameters
2.5 When to Use the Backend

2 Using the Backend Directly🔗ℹ

Most users should stay at the source-language level and use #lang intercal or #lang reader "intercal.rkt". The repository also exposes the lower level backend used by the reader. That backend is useful for:

  • frontend and runtime regression tests,

  • macro-expansion inspection,

  • debugging semantic mismatches in the evaluator, and

  • writing small programs directly in the normalized S-expression form.

These interfaces live in "sick.rkt". They are developer-facing APIs, not the main end-user surface of the package, but they are important enough to document because the test suite, tutorial material, and debugging workflow all use them.

2.1 Main Entry Points🔗ℹ

syntax

(sick-program line ...)

Compiles a normalized INTERCAL program without automatically appending "syslib.i".

This is useful when you want a minimal runtime test or when you are already working directly in the normalized S-expression form produced by "ick-normalize.rkt".

syntax

(sick-program/syslib line ...)

Like sick-program, but automatically loads "syslib.i" and any additional library files required by referenced labels, such as "pit/floatlib.i".

This is the form used by the normal source-language frontend, since real INTERCAL programs rely on syslib helpers for arithmetic and control support.

syntax

(sick-program-core line-ir ...)

Consumes the fully lowered IR used internally by the backend.

This form is primarily for compiler debugging. Handwritten programs should normally use sick-program or sick-program/syslib instead.

2.2 A Minimal Backend Example🔗ℹ

(call-with-values
 (lambda ()
   (parameterize ([sick-capture-output #t])
     (sick-program
      (10 (do (assign 0.1 (mesh 1))))
      (20 (do (read-out 0.1)))
      (30 (please (give-up))))))
 list)

This corresponds to the INTERCAL program:

DO .1 <- #1

DO READ OUT .1

PLEASE GIVE UP

The backend example is useful when you want to isolate runtime semantics without involving the lexer and parser.

2.3 Backend Helpers🔗ℹ

procedure

(mesh rn)  exact-integer?

  rn : (or/c exact-integer? symbol?)
Converts a numeric literal or Roman-numeral symbol into the integer value used by the backend IR.

This is mainly useful in handwritten sick-program tests, where (mesh 10) and (mesh 'X) both denote the same INTERCAL constant.

procedure

(clean-intercal-source str)  string?

  str : string?
Normalizes a raw INTERCAL source string into the cleaned source text consumed by the lexer and parser.

This step merges continuation lines, keeps only parseable INTERCAL statements, and preserves the upstream-style prefix forms accepted by the frontend. It is useful when debugging reader behavior independently of runtime semantics.

2.4 Useful Runtime Parameters🔗ℹ

The backend exposes several parameters that are especially helpful while testing or debugging:

  • sick-capture-output: when true, READ OUT accumulates values and returns them as multiple values instead of only printing.

  • sick-debug: enables runtime tracing.

  • sick-debug-lines and sick-debug-vars: restrict tracing to specific lines or variables.

  • sick-break-lines and sick-break-repeat: stop execution at selected lines or after a repeated control-flow state.

  • sick-max-steps: aborts a run after a bounded number of executed steps.

For example:

(parameterize ([sick-capture-output #t]
               [sick-max-steps 1000])
  (call-with-values
   (lambda ()
     (sick-program
      (10 (do (assign 0.1 (mesh 1))))
      (20 (do (read-out 0.1)))
     (30 (please (give-up)))))
   list))

parameter

(sick-capture-output)  boolean?

(sick-capture-output capture?)  void?
  capture? : boolean?
Controls whether READ OUT accumulates its emitted values and returns them as multiple values. The reader disables this for normal #lang intercal execution so programs print normally without building an in-memory result list.

parameter

(sick-debug)  boolean?

(sick-debug enabled?)  void?
  enabled? : boolean?
Enables runtime tracing. When true, the evaluator prints control-flow and state events to the error port.

parameter

(sick-debug-lines)  (or/c #f (listof exact-integer?))

(sick-debug-lines maybe-lines)  void?
  maybe-lines : (or/c #f (listof exact-integer?))
Restricts tracing to selected runtime line numbers.

parameter

(sick-debug-vars)  (or/c #f (listof symbol?))

(sick-debug-vars maybe-vars)  void?
  maybe-vars : (or/c #f (listof symbol?))
Restricts tracing to selected variables.

parameter

(sick-break-lines)  (or/c #f (listof exact-integer?))

(sick-break-lines maybe-lines)  void?
  maybe-lines : (or/c #f (listof exact-integer?))
Stops execution before selected runtime lines and emits the current debug snapshot.

parameter

(sick-break-repeat)  (or/c #f exact-positive-integer?)

(sick-break-repeat maybe-count)  void?
  maybe-count : (or/c #f exact-positive-integer?)
Stops execution when the same control-flow state repeats the configured number of times. This is useful for catching tight loops before they produce huge traces.

parameter

(sick-max-steps)  (or/c #f exact-positive-integer?)

(sick-max-steps maybe-limit)  void?
  maybe-limit : (or/c #f exact-positive-integer?)
Bounds execution by total runtime steps. This is the safest way to inspect intentionally non-terminating programs such as "pit/primes.i".

2.5 When to Use the Backend🔗ℹ

Use the backend directly when you want to:

  • write a focused runtime regression test,

  • inspect the macro-generated Racket code for a small fragment,

  • test syslib-driven control flow without going through the textual frontend, or

  • debug a pit program by progressively narrowing the problem to the evaluator.