One of the driving motivations behind the creation of rejig was my dismay over the nonstandard R47 character set, coupled with a presumption that no one will volunteer to undertake the huge task of resolving all the discrepancies. After much discussion on the forum, that appears to be an accurate view.
And that’s perfectly fine! Unlike the R47 project proper, rejig doesn’t have a choice in this matter: its default output format is UTF-8 plaintext, where we cannot count on any particular font being used. It must of necessity conform to the Unicode standard.
The solution is to accept R47 programs in byte code form, then translate them into proper Unicode.
Character Sets
The idealized form of all text strings within rejig is pure UTF-8. Just as the R47 instruction set provides our lingua franca for ops and their arg types, Unicode provides our lingua franca for alpha string code points. Everything below raises to this form on input, then lowers from this form on output.
R47 — We need not repeat the problem statement from the start of this article, nor go into details better covered elsewhere. It suffices to point out that the C47 custom font contains hundreds of glyphs with no match to what Unicode provides, and because the overlapping remainder is but a small subset of Unicode, the reverse is abundantly true. The nonstandard R47 charset therefore cannot be the
rejigalpha string lingua franca.HP-42S — Its extensions to ASCII include near-total overrides of the control character range below 0x20, plus a few nonstandard overwrites starting at 0x7F. Free42/Plus42 then continue this at 0x82 and above.
HP-41C — Pure 7-bit ASCII, without any of the above extensions.
printers — These offer various character sets, where even the first-party HP 82240A lacks a strict subset relationship with the HP-42S, even though it was purpose-designed as a companion device. A single example will show this: the HP-42S puts its non-ASCII
÷glyph in place of ASCII NUL (0x00) while the printer puts it at 0x81. That code point is rendered in turn asʏon the calculator, used when it wants to indicate the Y slot in the stack, as when there is no menu up, allowing it to show the lowest two levels of the stack. Problem is, if you then go back to the printer and look for a matching small-capsʏcharacter, it isn’t there, preventing a circular mapping throughrejig.One has to wonder why the 82240A printer has glyphs not in the HP-42S character set at all, but presuming there is a good reason, why is it not a superset of the HP-42S scheme? Or, if that was impossible for some reason, why not establish a simple mapping like “set the high bit,” thus reflecting the control character overrides up into the 8-bit ASCII extension range? Even an awkward “add 0x81” rule would have worked here, but as we see, that one breaks down at a different mismatch at HP-42S 0x04, which is not the same as 0x04 + 0x81 = 0x85 on the printer. (We’ll get back to this one shortly.)
For now, it is important to realize that this is not an isolated, cherry-picked example; it’s merely the first of many. This mess continues everywhere you look. One big irony here is that Unicode was in its design phase right around the same time as the HP-42S. If HP was aware of this development, they plainly disregarded it.
Instead, HP perpetuated the decades-long view that 7-bit ASCII was enough for everyone — inherited from the HP-41C — by commandeering the top bit as a flag on the first character of alpha strings to indicate that it be taken as an extended opcode, with what follows taken as args to that op. (Free42 calls these “special strings.”)
What all this means in consequence, within the rejig sphere, is that this is an illegal program line:
42α ‘«quote?»’
Why? The leading guillemet is encoded as the nonstandard Free42 character 0x88, and because it has the top bit set, it is misinterpreted as a VIEW IND op! Wishing to keep end users from falling into this trap, rejig screams and dies when you try this.
While I could choose to allow this within rejig as a form of synthetic programming, I thought that was a crock on the HP-41C, an opinion HP appears to agree with given how much effort they went to in shutting that pathway down in the HP-42S. I refuse to reopen that door to chaos within rejig for non-HP-41C targets. Indeed, it’s one reason I hesitated for so long to add HP-41C support at all.
A related coding ambiguity happens when leading an alpha string with the ⊢ character. Since this is how the HP-42S signals an “alpha append” operation, rejig diagnoses this condition as a fatal error for the same basic reason as above. It remains perfectly legal to put that non-ASCII character in the middle of an alpha string, or at the end. Getting it to appear at the start of an alpha string is possible, but it suffices to say that rejig supports the hacky construction required.
It gets weirder: HP gave that append-alpha op byte code 0x7F, which ASCII instead assigned for good and proper reasons to the DEL (rubout) character. HP then went and added a rubout-looking character (▒) at 0x04, overriding the spot ASCII assigned to the EoT, entered on any ASCII terminal as Ctrl-D. This is why that particular keystroke exits any sensible CLI app, from command shells onward. The thing is, sending that character to the 82240A will neither end the printing session nor display a rubout character in a teletype fashion, overwriting a prior printed character. No, it advances the paper one line while leaving the printhead where it is! This is the behavioral definition of line feed, ASCII LF, 0x10, yet HP in its wisdom defined 0x10 as having the effect of CR-LF on the 82240A, both advancing the paper one line and sending the printhead back to the start of the line.
(It should not surprise me to learn that HP’s engineering departments were packed with autists who never spoke to each other even when working on companion products whose manuals reference one another, but here we have the proof.)
I will close out this section with what little reassurance I can offer, given the circumstances: rejig does its best to hide this four-way fight from those of you innocent bystanders just trying to get useful work done. What I cannot promise is that you will never someday find yourself beyond the margins, gawping with dismay at all this mess. Sorry; how it is.
Practical Transformations
The best user experience for typing Unicode is on macOS, and even there, getting exactly the right character isn’t always easy. We therefore provide an assortment of transformations within rejig to ease manual program entry:
arrows: In place of the
→used in canonical op names likeacre→ha, you may use ASCII approximations like->. Although that one also works with R47 register indirection, you may instead prefer HP-42SINDsyntax.Other arrow mappings
rejigsupports include=>in place of⇒, and<>in place of the⇄for swaps.By popular acclamation,
rejigdoes support the hideousRvalias forR↓, andR^forR↑. I have resisted extending this to less-popular ops spelled with arrows, but in places compatibility demands it. The main class is the HP-42S styleX↑2spelling for𝑥²and the like; theX^2alias works here, which brings us to…superscripts/subscripts: Unicode defines a large number of these, but that offering does not cover the entire Latin + Greek alphabet. For instance, there is a superscript “x” character in Unicode allowing one to render the common calculator function yˣ in plain Unicode, but there is no subscript “Q” needed to render the R47’s `x_(Q1)` function.
rejiguses what Unicode provides by preference, with fallbacks to LaTeX math notation:a_bmeans `a_b`, andc^dmeans `c^d`. Multi-letter super/subscripts must be given in parens becausea_bcrenders as `a_bc` in LaTeX; givea_(bc)to produce the desired effect: `a_(bc)`There are extensive aliases for these in
rejig, allowing you to type ASCII/LaTeX equivalents such aslog10(x)for `log_(10)(x)` orarctan(x)for `tan^(-1)(x)`.The
--to html[-strict]output modes translate this notation into MathML for viewing in any modern browser.operators: We use proper math symbols by preference, but where that takes us outside the ASCII range, we offer aliases inspired by programming languages:
!=for≠,*for×, and so forth. Note that we do not use<>to mean inequality as in BASIC and Pascal, as we already used that for swaps and do not wish to create a language ambiguity.math italics:
rejigprefers Unicode mathematical italic letters in UTF-8 output, and it will happily accept them on UTF-8 input, but it also offers plain ASCII aliases. Thecos(𝑥)function is canonical, but we also acceptcos(x), and since we do case-insensitive matching on ASCII letters, it means we also acceptCOS(X), plus the plainCOS. We eschew case-folding for other alphabets to avoid confusing Σ with σ, or worse, confusing ASCII X with Greek 𝛸, the uppercase letter chi.roots: When one wishes to go beyond cubes and cube roots, Unicode starts to become tricky enough that it isn’t worth the bother. Thus why the R47’s `root(x)(y)` function is spelled
root(x)(y)byrejigper LaTeX notation. Prior versions usedroot(x,y)for this, but that encourages experienced programmers to violate the no-spaces rule by misspelling it “root(x, y)”.constants: The R47 spells out references to the built-in constants as “
# 29 mPL mass.planck” but this, too, violates the no-spaces rule. Inrejig, you just give one of the two alternative names: eitherm_(PL)ormass.planckin this example. Note that this also invokes the subscript transformation.
These are used not only in expressing P47 byte codes in rejig but may also be used in end user programs, honored in parsing. Because rejig converts all input to a canonical form, you can use it to “upgrade” a plain ASCII version of a program using the in-place reformatting feature.
File Encoding
Text inputs must be Unicode, in any of these encodings:
- UTF-8 is the default path, taken when there is no BOM
- BOM-prefixed UTF-8; the BOM is a semantic nullity, stripped with no effect relative to the default case
- UTF-16 and UTF-32, LE or BE, as signaled by the BOM
We do not make any attempt to handle UTF-7, nor legacy 8-bit ASCII extensions like CP1252 or ISO-8859.
The --from/to options utf8 and unicode are synonyms. The sole consequence of specifying --from utf8 while giving non-UTF-8 Unicode input is that rejig issues a warning; decoding continues.
Windows CR+LF line endings are accepted on input, but text output prefers the Unix LF style.
(You may now wish to return to the rejig home page.)
License
This work is © 2026 by Warren Young and is licensed under CC BY-NC-SA 4.0