Updates and fixes in 1991/brnstnd

Make sorta.README a markdown file (sorta.README.md) and update
formatting for it.

Typo fixes and formatting fixes in README.md.
This commit is contained in:
Cody Boone Ferguson committed 2023-04-09 08:08:38 -07:00
1 parent ececfced3e
commit 68c57a4bb1
2 files changed
+128 -129

No files matched your search

+88 -85
View File
@@ -1,11 +1,13 @@
# Best Of Show: # Best Of Show:
Daniel J. Bernstein Daniel J. Bernstein
New York University New York University
## To build: ## To build:
make all ```sh
make all
```
[Cody Boone Ferguson](/winners.html#Cody_Boone_Ferguson) fixed this for modern [Cody Boone Ferguson](/winners.html#Cody_Boone_Ferguson) fixed this for modern
systems. There were two invalid operands to binary expression (`char *` and systems. There were two invalid operands to binary expression (`char *` and
@@ -18,20 +20,22 @@ were resolved with the comma operator. Thank you Cody for your assistance!
## Try: ## Try:
./brnstnd < sorta.i2+2 ```sh
./brnstnd < sorta.iwhosort ./brnstnd < sorta.i2+2
./brnstnd < sorta.iwhosort
```
See also the other `sorta.*` files. See also the other `sorta.*` files.
## Judges' comments ## Judges' comments:
For info on more examples, read the sorta.README file. For info on more examples, read the [sorta.README.md](sorta.README.md) file.
The author wished to win the "most useful program" award and The author wished to win the "most useful program" award and documented this in
documented this in the source code. The judges were unmoved the source code. The judges were unmoved by this blatant attempt to influence
by this blatant attempt to influence the contest and rejected the contest and rejected this idea... so we gave it the `Best of Show`
this idea... so we gave it the Best of Show award instead!! instead!!
NOTE: One should remove the final trailing newline to obtain the NOTE: One should remove the final trailing newline to obtain the
original source file. This step is not needed to compile original source file. This step is not needed to compile
@@ -40,7 +44,7 @@ this entry.
To have a chance to compile under a modern CPP, we had to To have a chance to compile under a modern CPP, we had to
replace `#D` with `#define`. replace `#D` with `#define`.
## Author's comments ## Author's comments:
This is an interpreter for the programming language SORTA, a systems This is an interpreter for the programming language SORTA, a systems
and numerical programming language with features sorta from C, sorta and numerical programming language with features sorta from C, sorta
@@ -59,104 +63,103 @@ instance, not to mention infinite-depth tail recursion.
SORTA ignores its arguments (though it makes them available to the SORTA ignores its arguments (though it makes them available to the
script); it takes all commands, character by character, from its script); it takes all commands, character by character, from its
standard input. Unrecognized commands are repeated with a ?. standard input. Unrecognized commands are repeated with a '?'.
SORTA maintains an ``i stack'' for integers and an ``s stack'' for SORTA maintains an `i stack` for integers and an `s stack` for strings. It also
strings. It also keeps track of ``programs,'' one for each character. keeps track of `programs`, one for each character. Operations are silently
Operations are silently ignored if the relevant stacks are too low, ignored if the relevant stacks are too low, except as noted for `s`, `S`, and
except as noted for s, S, and !. If the i stack or s stack (or the stack `!`. If the `i stack` or `s stack` (or the stack of buffered macro commands)
of buffered macro commands) grows too high, SORTA will exit silently grows too high, SORTA will exit silently with exit code 2. (Compile parameter
with exit code 2. (Compile parameter -Do=250 controls what ``too high'' `-Do=250` controls what 'too high' means; you should not make `o` larger than
means; you should not make o larger than 250.) I don't think it's 250.) I don't think it's possible to crash the interpreter.
possible to crash the interpreter.
Here, then, is the SORTA programming language. All non-digits delimit Here, then, is the SORTA programming language. All non-digits delimit
numeric constants. Spaces and newlines are ignored except as numeric numeric constants. Spaces and newlines are ignored except as numeric
delimiters. delimiters.
Basic operations: ### Basic operations:
q: quit - `q`: quit
number: push that number on top of the i stack - `number`: push that number on top of the i stack
"string": push that string on top of the s stack, no length limit - `"string"`: push that string on top of the s stack, no length limit
[string]: push that string on top of the s stack, no length limit - `[string]`: push that string on top of the s stack, no length limit
#: make top of i stack non-destructively in ASCII, push result onto s stack - `#`: make top of i stack non-destructively in ASCII, push result onto s stack
`: print top of s stack non-destructively - ` ` `: print top of s stack non-destructively
$: print top of s stack non-destructively without newline - `$`: print top of s stack non-destructively without newline
d: drop (pop) top of i stack - `d`: drop (pop) top of i stack
D: dup (duplicate) top of i stack - `D`: dup (duplicate) top of i stack
': dup top of s stack - `'`: dup top of s stack
s: pop top of i stack. If it is n, swap (n+1)th-top of i stack with top. - `s`: pop top of i stack. If it is `n`, swap `(n+1)`th-top of `i` stack with top.
1s, for example, swaps the top two elements; 2s swaps the top with `1s`, for example, swaps the top two elements; `2s` swaps the top with the
the third down; etc. This always pops the top of the i stack, even third down; etc. This always pops the top of the `i stack`, even upon
upon failure. failure.
S: pop top of i stack, then act just like s but upon s stack - `S`: pop top of `i stack`, then act just like `s` but upon `s stack`
l: pop top of s stack, push its length onto i stack - `l`: pop top of `s stack`, push its length onto `i stack`
a: push argc onto i stack - `a`: push argc onto i stack
A: pop top of i stack, push argv[i] on top of s stack - `A`: pop top of `i stack`, push `argv[i]` on top of `s stack`
T: concatenate top two elements of s stack - `T`: concatenate top two elements of `s stack`
_: negate top of i stack - ` _ `: negate top of i stack
+: pop top two elements of i stack, add, push back sum - `+`: pop top two elements of i stack, add, push back sum
*: pop top two elements of i stack, multiply, push back product - ` * `: pop top two elements of i stack, multiply, push back product
/: pop top two elements of i stack, divide, push back quotient - `/`: pop top two elements of i stack, divide, push back quotient
>: pop top two elements of i stack, compare, push back 1 or 0 as in C - `>`: pop top two elements of i stack, compare, push back 1 or 0 as in C
&: pop top two elements of i stack, nand, push back bitwise result - `&`: pop top two elements of i stack, nand, push back bitwise result
Note that nand is sufficient to construct all bitwise operations, Note that nand is sufficient to construct all bitwise operations, as
as demonstrated by icalc below. demonstrated by icalc below.
System operations: ### System operations:
o: pop top of s stack and top two of i stack; open(s1,i2,i1); leave - `o`: pop top of `s stack` and top two of `i stack`; `open(s1,i2,i1);` leave
result on i stack result on `i stack`
O: pop top of i stack, close() it - `O`: pop top of `i stack`, `close()` it
u: pop top of i stack, dup() it, push result back on - `u`: pop top of `i stack`, `dup()` it, push result back on
F: fork(), push result on i stack. This is not always safe while SORTA - `F`: `fork()`, push result on `i stack`. This is not always safe while SORTA is
is reading keyboard input or a script, as the forked programs share reading keyboard input or a script, as the forked programs share file
file descriptors. It is always safe inside a program (see below). descriptors. It is always safe inside a program (see below).
P: pipe(), push two ends <p0> <p1> onto i stack. In case of trouble, - `P`: `pipe()`, push two ends `<p0> <p1>` onto `i stack`. In case of trouble,
push <?> <-1> onto i stack. `push <?> <-1>` onto `i stack`.
w: wait(), push successful result (or -1 if no children) on i stack - `w`: `wait()`, push successful result (or -1 if no children) on `i stack`
!: execvp() top of the s stack. Arguments are the next things down on - `!`: `execvp()` top of the `s stack`. Arguments are the next things down on
the s stack, in reverse order from popping; the first character of the s stack, in reverse order from popping; the first character of
each string is lopped off. There must be an empty string somewhere each string is lopped off. There must be an empty string somewhere
in the s stack to terminate the argument list. If the execve() in the s stack to terminate the argument list. If the execve()
fails, any operation involving current members of the s stack has fails, any operation involving current members of the s stack has
undefined effects, and -1 is pushed onto the i stack. undefined effects, and -1 is pushed onto the i stack.
High-level language operations: ### High-level language operations:
:x: copy the top of the s stack into a program labeled by character x - :x: copy the top of the s stack into a program labeled by character x
=x: pop the top of the i stack. If it was nonzero, execute the program - =x: pop the top of the i stack. If it was nonzero, execute the program
labeled by character x. Note that a digit at the end of a program labeled by character x. Note that a digit at the end of a program
will merge with any digits after =x; in that case you usually want will merge with any digits after =x; in that case you usually want
to add a space at the end of the program. to add a space at the end of the program.
Common idioms: To drop the top of the s stack, ld. To do a <, 1s>. To Common idioms: To drop the top of the s stack, ld. To do a <, 1s>. To
unconditionally execute the program labeled by character x, 1=x (or any unconditionally execute the program labeled by character x, 1=x (or any
nonzero number followed by =x). To print the top of the i stack nonzero number followed by =x). To print the top of the i stack
non-destructively, #` (or #$ if you don't want the newline). To non-destructively, `# ` ` (or `#$` if you don't want the newline). To
subtract, _+. To do mod or and or any of the other missing operations, subtract, `_+`. To do mod or and or any of the other missing operations,
combine the available operations as illustrated below. To introduce a combine the available operations as illustrated below. To introduce a
comment, [ this is a comment string which is promptly eliminated ]ld. comment, `[ this is a comment string which is promptly eliminated ]ld`.
SORTA's requirements: it wants fork(), execvp(), open(), SORTA's requirements: it wants `fork()`, `execvp()`, `open()`,
close(), dup(), pipe(), and wait(), so it obviously won't even compile `close()`, `dup()`, `pipe()`, and `wait()`, so it obviously won't even compile
on a non-UNIX machine. It also assumes that you have a size-256 on a non-UNIX machine. It also assumes that you have a size-256
character set and that the characters between '0' and '9' are exactly character set and that the characters between `'0'` and `'9'` are exactly
the digits in order. It does *not* depend on ASCII, despite the code the digits in order. It does *not* depend on ASCII, despite the code
appearance. Also note that SORTA does not attempt to declare malloc(), appearance. Also note that SORTA does not attempt to declare `malloc()`,
so you will get some warnings about illegal pointer combinations. Also so you will get some warnings about illegal pointer combinations. Also
note that there are unreached statements in SORTA. note that there are unreachable statements in SORTA.
While the program source of course depends highly on #defines for While the program source of course depends highly on `#define`s for
obfuscation, I like to think that this code has those little touches, obfuscation, I like to think that this code has those little touches,
those professionally sharpened edges that mark true software those professionally sharpened edges that mark true software
engineering. Observe, for instance, how i and s are the string and engineering. Observe, for instance, how `i` and `s` are the string and
integer stacks respectively. It's these little things that make you integer stacks respectively. It's these little things that make you
feel at home in an otherwise utterly useless piece of code. They're feel at home in an otherwise utterly useless piece of code. They're
what make an obfuscation work. what make an obfuscation work.
The character pool (``I'' after cpp) makes it rather painful to The character pool (`I` after cpp) makes it rather painful to
see the effect of commands at a glance. I can just imagine people see the effect of commands at a glance. I can just imagine people
spending hours bouncing between the pool and the rest of the code, spending hours bouncing between the pool and the rest of the code,
or accidentally changing the pool without realizing its importance. or accidentally changing the pool without realizing its importance.
@@ -173,8 +176,8 @@ everywhere will make people think of ASCII, even though the code is
not ASCII-dependent. What's your first thought when you see not ASCII-dependent. What's your first thought when you see
several arrays[256]? This is pretty standard obfuscation otherwise. several arrays[256]? This is pretty standard obfuscation otherwise.
I like the way that unbalanced macro braces can throw off the I like the way that unbalanced macro braces can throw off the
reader in ``if(c>0){y+1]=z[c];'', and I had fun covering the reader in `if(c>0){y+1]=z[c];`, and I had fun covering the
alphabet with #defines, but that's nothing special. alphabet with `#define`s, but that's nothing special.
Possible future extensions to SORTA include string extraction and Possible future extensions to SORTA include string extraction and
matching, reading from files into strings, and encrypting the string matching, reading from files into strings, and encrypting the string
@@ -1,25 +1,25 @@
The 'sorta' scripts described below can sorta be found in this directory. The `sorta` scripts described below can sorta be found in this directory.
# [sorta.i2+2](sorta.i2+2)
sorta.i2+2
----------
2 2+#` [ about as basic as you can get ]ld 2 2+#` [ about as basic as you can get ]ld
This script takes 2, adds 2 to it, and prints the result (with a This script takes 2, adds 2 to it, and prints the result (with a
newline). I get 5 on the hand-held Sinclair under ZYNIX. Let me know if newline). I get 5 on the hand-held Sinclair under ZYNIX. Let me know if
your machine produces a different result so that I can send you patches. your machine produces a different result so that I can send you patches.
sorta.iarg0 # [sorta.iarg0](sorta.iarg0)
-----------
0A` [ take arg 0, print it ] 0A` [ take arg 0, print it ]
This is self-explanatory. This is self-explanatory.
sorta.icalc # [sorta.icalc](sorta.icalc)
-----------
[D2sD3s]:Dld [ input m n, output m n m n ]ld [D2sD3s]:Dld [ input m n, output m n m n ]ld
@@ -56,18 +56,18 @@ sorta.icalc
1=D 1s# " | "T 1s#T " is "T D&1sD&& #T$ld " (" 1=2 ")"T `ld 1=D 1s# " | "T 1s#T " is "T D&1sD&& #T$ld " (" 1=2 ")"T `ld
1=D 1s# " ^ "T 1s#T " is "T 1=D&2sD&1sD&&&D& #T$ld " (" 1=2 ")"T `ld 1=D 1s# " ^ "T 1s#T " is "T 1=D&2sD&1sD&&&D& #T$ld " (" 1=2 ")"T `ld
icalc shows off SORTA's understanding of integer arithmetic. You can run `icalc` shows off SORTA's understanding of integer arithmetic. You can run
it with up to two arguments; the arguments have default values of 27182 it with up to two arguments; the arguments have default values of 27182
and 3145. Notice that sorta doesn't have a language primitive for and 3145. Notice that sorta doesn't have a language primitive for
converting a string to a number, yet icalc is performing arithmetic on converting a string to a number, yet `icalc` is performing arithmetic on
its arguments. Can you see how? (Hint: Try sorta "2 2+" 3 < sorta.icalc. its arguments. Can you see how? (Hint: Try `./brnstnd "2 2+" 3 < sorta.icalc`.
Look at program A.) icalc also provides a useful binary output routine, Look at program A.) `icalc` also provides a useful binary output routine,
and if you can't remember offhand that D2sD3s&2sD&1sD&&&D& means xor, and if you can't remember offhand that `D2sD3s&2sD&1sD&&&D&` means xor,
you can just look it up here. you can just look it up here.
sorta.idup # [sorta.idup](sorta.idup)
-----------
[ld#1_+1=y]:x [ld#1_+1=y]:x
[uD1+=x]:y [uD1+=x]:y
@@ -77,8 +77,7 @@ This script prints out the maximum file descriptor available from
repeated dup()s---usually NOFILE - 1. Can you see how it works? repeated dup()s---usually NOFILE - 1. Can you see how it works?
sorta.iecho # [sorta.iecho](sorta.iecho)
-----------
[" "$ld]:sld [ print a space ]ld [" "$ld]:sld [ print a space ]ld
[1s1+DA$ld1s1_+D=sD=x]:xld [ given n (argc-n), print args ]ld [1s1+DA$ld1s1_+D=sD=x]:xld [ given n (argc-n), print args ]ld
@@ -89,8 +88,8 @@ interpretation. (Note that, unlike some shells' echo, /bin/echo prints a
newline even with no arguments.) Try sorta foo bar < iecho. newline even with no arguments.) Try sorta foo bar < iecho.
sorta.ifact1 # [sorta.ifact1](sorta.ifact1)
------------
1#`ld2*#`ld3*#`ld4*#`ld5*#`ld6*#`ld7*#`ld8*#`ld9*#`ld10*#`ld 1#`ld2*#`ld3*#`ld4*#`ld5*#`ld6*#`ld7*#`ld8*#`ld9*#`ld10*#`ld
@@ -98,32 +97,31 @@ This is a very straightforward factorial program: Take 1, print it,
multiply by 2, print it, multiply by 3, print it, etc. multiply by 2, print it, multiply by 3, print it, etc.
sorta.ifact2 # [sorta.ifact2](sorta.ifact2)
------------
[1+D2s*#`ld1s]:f [1+D2s*#`ld1s]:f
1 0 1 0
1=f 1=f 1=f 1=f 1=f 1=f 1=f 1=f 1=f 1=f 1=f 1=f 1=f 1=f 1=f 1=f 1=f 1=f 1=f 1=f
ifact1 does a lot of repeated work. ifact2 takes advantage of this by `ifact1` does a lot of repeated work. `ifact2` takes advantage of this by
keeping the current n! n on the stack. Each call to routine f (1=f) keeping the current `n!` n on the stack. Each call to routine f (1=f)
increments n by 1 and prints out the factorial. increments n by 1 and prints out the factorial.
sorta.ifact3 # [sorta.ifact3](sorta.ifact3)
------------
[1+D2s*#`ld1s]:f [ given (n-1)! (n-1), print n!, put n! n ] [1+D2s*#`ld1s]:f [ given (n-1)! (n-1), print n!, put n! n ]
[2s1=f2s1_+D0>=x]:x [ given n n! x, print (n+1)! through (n+x)! ] [2s1=f2s1_+D0>=x]:x [ given n n! x, print (n+1)! through (n+x)! ]
0 1 10 1=x 0 1 10 1=x
Finally, ifact3 removes all the redundancy from ifact2, and exhibits Finally, `ifact3` removes all the redundancy from `ifact2`, and exhibits
proper documentation of stack routines. You can replace the 10 by proper documentation of stack routines. You can replace the 10 by
anything in this version. anything in this version.
sorta.iio # [sorta.iio](sorta.iio)
---------
[ a simple example of interpreting code on the fly ]ld [ a simple example of interpreting code on the fly ]ld
@@ -132,8 +130,8 @@ sorta.iio
Notice that "2 2+" is a literal string inside the program. Notice that "2 2+" is a literal string inside the program.
sorta.irot13 # [sorta.irot13](sorta.irot13)
------------
"[] [.tr] " "[] [.tr] "
["]".[a-m][n-z][A-M][N-Z]"[" ]TTT ["]".[n-z][a-m][N-Z][A-M]"[" ]TTT ["]".[a-m][n-z][A-M][N-Z]"[" ]TTT ["]".[n-z][a-m][N-Z][A-M]"[" ]TTT
@@ -145,17 +143,17 @@ sorta.irot13
0 'o D0 1s>=hld 0 'o D0 1s>=hld
0Ou1=x [ in a more complex spawner, this would be done under a fork ]ld 0Ou1=x [ in a more complex spawner, this would be done under a fork ]ld
Despite its name, irot13 is meant to show how to exec a program with Despite its name, `irot13` is meant to show how to exec a program with
redirection from within sorta. You run it as sorta blah < irot13; it redirection from within sorta. You run it as `./brnstnd blah < irot13`; it
opens blah and runs a (BSD-style) tr command to rotate all letters by 13 opens `blah` and runs a (BSD-style) `tr` command to rotate all letters by 13
spots. 1A 0 0 o opens argv[1]; the ' keeps the filename around for spots. `1A 0 0 o` opens `argv[1]`; the ` ' ` keeps the filename around for
subroutine h to print a nice error message if necessary. 0Ou closes subroutine `h` to print a nice error message if necessary. `0Ou` closes
stdout and replaces it with the new descriptor. Finally, subroutine x stdout and replaces it with the new descriptor. Finally, subroutine `x`
executes the tr. executes the `tr`.
sorta.isleep # [sorta.isleep](sorta.isleep)
------------
["" "+sleep" "+5" "sleep" !q]:S [F0>1_+=S]:s ["" "+sleep" "+5" "sleep" !q]:S [F0>1_+=S]:s
"forking sleep 5..."`ld "forking sleep 5..."`ld
@@ -167,22 +165,20 @@ sorta.isleep
This script illustrates the classic fork-exec-wait. This script illustrates the classic fork-exec-wait.
sorta.itailrec # [sorta.itailrec](sorta.itailrec)
--------------
[3*#" "T$ldD=f]:f [3*#" "T$ldD=f]:f
1=f 1=f
The sole purpose of this script is to prove that sorta can do infinite The sole purpose of this script is to prove that sorta can do infinite
tail recursion (in this case, in program f). Do sorta < itailrec | more tail recursion (in this case, in program `f`). Do `./brnstnd < itailrec | more`
and watch the powers of 3 (mod your computer's word size) flow by. and watch the powers of 3 (mod your computer's word size) flow by.
sorta.iwhosort # [sorta.iwhosort](sorta.iwhosort)
--------------
[0Ou "" "+-u" "sort" !q]:S [F0>1_+=S]:s [0Ou "" "+-u" "sort" !q]:S [F0>1_+=S]:s
[1Ou "" "+-u" "who" !q]:W [F0>1_+=W]:w [1Ou "" "+-u" "who" !q]:W [F0>1_+=W]:w
P1=wO1=sOww P1=wO1=sOww
This final example is a simple pipeline, who | sort. This final example is a simple pipeline, `who | sort`.