Updates to 1992/buzzard.2

Rename buzzard.2.README buzzard.2.README.md (perhaps buzzard.2.md would
be better?).

Format fixes in README.md.
This commit is contained in:
Cody Boone Ferguson committed 2023-04-09 10:55:03 -07:00
1 parent 6cb76a5b78
commit ddf8c5be37
2 files changed
+156 -134

No files matched your search

+144 -129
View File
@@ -1,58 +1,73 @@
# Best Language Tool: # Best Language Tool:
Sean Barrett Sean Barrett
Software Construction Company Software Construction Company
430 Southwest Parkway, #1906 430 Southwest Parkway, #1906
College Station, TX 77840 College Station, TX 77840
USA USA
## To build: ## To build:
make all ```sh
make all
```
## To run: ## To run:
First: First:
make first ```sh
make first
```
Second: Second:
echo help | cat third help.th - | ./first ```sh
cat third demo5.th | ./first echo help | cat third help.th - | ./first
cat third demo5.th | ./first
```
Third: Third:
cat third help.th - | ./first ```sh
cat third help.th - | ./first
```
NOTE: Wait until Ok is printed and the type: NOTE: Wait until 'Ok' is printed and the type:
2 3 + . cr ```
2 3 + . cr
Yes you should really type the 2 letters: cr. ```
Yes you should really type the 2 letters: `cr`.
Fourth: Fourth:
Sorry, this is third! ```
Sorry, this is third!
```
## Alternate code: ## Alternate code:
An alternate version of this entry, `buzzard.2.alt.c`, is provided. This alternate code An alternate version of this entry, [buzzard.2.alt.c](buzzard.2.alt.c), is
does not contain a fix that the author notes below. provided. This alternate code does not contain a fix that the author notes
below.
To compile this alternate version: To compile this alternate version:
make alt ```sh
make alt
```
Use `buzzard.2.alt` as you would `buzzard.2` above. Use `buzzard.2.alt` as you would `buzzard.2` above.
## Judges' comments ## Judges' comments:
Have fun! Have fun!
## Author's comments ## Author's comments:
What it does: ### What it does:
`first` implements a relatively primitive stack machine. How `first` implements a relatively primitive stack machine. How
primitive? It supplies 13 visible primitives: 3 arithmetic, primitive? It supplies 13 visible primitives: 3 arithmetic,
@@ -88,152 +103,152 @@ included, but it only works on ASCII systems.
Do not expect to be able to do anything interesting with first. Do not expect to be able to do anything interesting with first.
To do something interesting, you need to feed first the file To do something interesting, you need to feed first the file
third first. In unix, you can do [third](third) first. In unix, you can do
% cat third help.th - | ./first ```sh
% cat third help.th - | ./first
```
to do this. Hopefully most operating systems will provide a to do this. Hopefully most operating systems will provide a way to do this. It
way to do this. It may take some time for this to complete may take some time for this to complete (I seem to remember it taking several
(I seem to remember it taking several minutes on an 8086 PC); minutes on an 8086 PC); `THIRD` will prompt you when it is finished. The file
THIRD will prompt you when it is finished. The file third has [third](third) has not been obfuscated, due to sheer kindness on the author's
not been obfuscated, due to sheer kindness on the author's part. part.
For more information on what you can do once you've piped For more information on what you can do once you've piped [third](third) into
THIRD into first, type 'help' and consult FORTH manuals for first, type 'help' and consult FORTH manuals for further reference. Six sample
further reference. Six sample THIRD programs are included THIRD programs are included in the files demo[1-6].th.
in the files demo[1-6].th. buzzard.2.README has more [buzzard.2.README.md](buzzard.2.README.md) has more information.
information.
Keep in mind that you are still running first, and Keep in mind that you are still running first, and are for the most part limited
are for the most part limited by first's tokenizer by `first`'s tokenizer (notably, unknown words will attempt to be parsed as
(notably, unknown words will attempt to be parsed as integers.) It is possible to build a new parser that parses by hand, reading a
integers.) It is possible to build a new parser that single character at a time; however, such a parser cannot easily use the
parses by hand, reading a single character at a time; existing dictionary, and so would have to implement its own, thus requiring
however, such a parser cannot easily use the existing reimplementing all of first and third a second time--I did not care to tackle
dictionary, and so would have to implement its own, this project.
thus requiring reimplementing all of first and third
a second time--I did not care to tackle this project.
### Compiling: ### Compiling:
`first` is reasonably portable. You may need to adjust the `first` is reasonably portable. You may need to adjust the size of the buffers
size of the buffers on smaller machines; `m[]` needs to be on smaller machines; `m[]` needs to be at least 2000 long, though.
at least 2000 long, though.
I say `first` is portable mainly because it uses native types. I say `first` is portable mainly because it uses native types. Unlike
Unlike FORTH, which traditionally allows byte and multi-byte [FORTH](https://en.wikipedia.org/wiki/Forth_(programming_language), which
operations, all operations are performed on C `int`s. That traditionally allows byte and multi-byte operations, all operations are
means first code is only as portable as the same code would performed on C `int`s. That means first code is only as portable as the same
be in C. As in C, the result of dividing -1 by 2 is machine code would be in C. As in C, the result of dividing -1 by 2 is machine (or
(or rather compiler) dependent. rather compiler) dependent.
### How is first obfuscated? ### How is first obfuscated?
`first` is obfuscated in several ways. Some minor obfuscations `first` is obfuscated in several ways. Some minor obfuscations like
like `&w[&m[1]][s]` for `s+m[w+1]` were in the original source `&w[&m[1]][s]` for `s+m[w+1]` were in the original source but are no longer
but are no longer because, apparently, ANSI doesn't allow it because, apparently, ANSI doesn't allow it (gcc -ansi -pedantic doesn't mind it,
(gcc -ansi -pedantic doesn't mind it, though.) though.)
Other related obfuscations are still present. The top of the
stack is cached in a variable, which increases performance
massively if the compiler can figure out to keep it in a register;
it also obfuscates the code. (Unfortunately, the top of stack
is a global variable and neither gcc nor most bundled compilers
seem to register allocate it.)
More significant are the design obfuscations. `m[0]` is the Other related obfuscations are still present. The top of the stack is cached in
"dictionary pointer", used when compiling words, and `m[1]` is a variable, which increases performance massively if the compiler can figure out
the return stack index. Both are used as integer offsets into to keep it in a register; it also obfuscates the code. (Unfortunately, the top
m. Both are kept in m, instead of as separate pointers, of stack is a global variable and neither gcc nor most bundled compilers seem to
because they are then accessible to first programs, which is a register allocate it.)
crucial property of first. Similarly the way words are stored
in the dictionary is not obvious, so it can be difficult to
follow exactly what the compiler words are doing.
Assuming you've waded through all that, you still have More significant are the design obfuscations. `m[0]` is the "dictionary
to penetrate the most significant obfuscation. Traditionally, pointer", used when compiling words, and `m[1]` is the return stack index. Both
the question is whether a reader can answer the question "what are used as integer offsets into `m`. Both are kept in `m`, instead of as
will this do when I run it". A reader who has deciphered first separate pointers, because they are then accessible to first programs, which is
to this point may think they know the answer to this question, a crucial property of first. Similarly the way words are stored in the
but they may not know the answer to the more important question, dictionary is not obvious, so it can be difficult to follow exactly what the
"what will this program do when given the right input?" FORTH compiler words are doing.
aficionados, and especially FORTH implementers, may recognize
the similarity of the internal compiler format to many FORTH Assuming you've waded through all that, you still have to penetrate the most
internal representations, and, being aware that FORTH interpreters significant obfuscation. Traditionally, the question is whether a reader can
can often by self-compiling, may be suspicious that this program answer the question "what will this do when I run it". A reader who has
can compile FORTH, or a significant subset of it, or at least be deciphered first to this point may think they know the answer to this question,
capable of doing so if fed the right input. Of course, the name but they may not know the answer to the more important question, "what will this
"THIRD" should be a dead giveaway, if the name "first" wasn't. program do when given the right input?" FORTH aficionados, and especially FORTH
(These numbers were largely chosen because they were five letters implementers, may recognize the similarity of the internal compiler format to
long, like "FORTH", and would not require truncation to five many FORTH internal representations, and, being aware that FORTH interpreters
letters, which would be a dead giveaway. Besides, THIRD represents can often be self-compiling, may be suspicious that this program can compile
a step backwards, in more ways than one.) FORTH, or a significant subset of it, or at least be capable of doing so if fed
the right input. Of course, the name "THIRD" should be a dead giveaway, if the
name "first" wasn't. (These numbers were largely chosen because they were five
letters long, like "FORTH", and would not require truncation to five letters,
which would be a dead giveaway. Besides, THIRD represents a step backwards, in
more ways than one.)
### What exactly is `first`, then? ### What exactly is `first`, then?
`first` is a tiny interpreter which implements a sufficient `first` is a tiny interpreter which implements a sufficient pseudo-subset of
pseudo-subset of FORTH to allow it to bootstrap a relatively FORTH to allow it to bootstrap a relatively complete version of FORTH (based
complete version of FORTH (based loosely on forth79), which loosely on forth79), which I call THIRD. Complete relative to what, I'm not
I call THIRD. Complete relative to what, I'm not sure. sure.
I believe first is close to the smallest amount of code possible I believe first is close to the smallest amount of code possible to get this
to get this effect *using forth-style primitives*, and still have effect *using forth-style primitives*, and still have some efficiency (it is
some efficiency (it is possible to get by without multiplication possible to get by without multiplication if you have addition, obviously). In
if you have addition, obviously). In the design file, design, the design file, design, I give a justification for why each primitive in first
I give a justification for why each primitive in first was included. was included.
THIRD is sorta slow, because first has so few primitives that THIRD is sorta slow, because first has so few primitives that many things that
many things that are primitives in FORTH (like swap) take a are primitives in FORTH (like swap) take a significant amount of time in THIRD.
significant amount of time in THIRD.
When you get the 'Ok.' message from third, try out some sample When you get the 'Ok.' message from third, try out some sample FORTH code (first
FORTH code (first has no way of knowing if keyboard input is has no way of knowing if keyboard input is waiting, so it can't actually prompt
waiting, so it can't actually prompt you in a normal way. It you in a normal way. It only prints 'Ok.' after you define a word).
only prints 'Ok.' after you define a word).
2 3 + . cr ( add 2 and 3, and print it and a newline.) ```sh
2 3 + . cr
```
and THIRD responds (which adds 2 and 3, and print the result and a newline.)
5 THIRD responds:
```
5
```
Now try: Now try:
: test 11 1 do i . loop cr ; ```
test : test 11 1 do i . loop cr ;
test
```
and THIRD responds and THIRD responds
1 2 3 4 5 6 7 8 9 10 ```
1 2 3 4 5 6 7 8 9 10
```
When in THIRD, you can see how much space you're currently When in `THIRD`, you can see how much space you're currently
using by typing using by typing:
here . ```
here .
```
The number THIRD replies is the number of machine words (ints) The number THIRD replies with is the number of machine words (ints) that the
that the dictionary (the first code) takes up, plus the dictionary (the first code) takes up, plus the 512 ints for the return stack.
512 ints for the return stack. If you compile the basic If you compile the basic THIRD system without the help word (strings take up one
THIRD system without the help word (strings take up one int per character in the string!), you should find that you're using around 1000
int per character in the string!), you should find that ints (plus the return stack).
you're using around 1000 ints (plus the return stack).
Thus THIRD gives you a relatively complete FORTH system in Thus THIRD gives you a relatively complete FORTH system in less than 700 chars
less than 700 chars of C source + about 1000 ints of of C source + about 1000 ints of memory--and it's portable too (you could copy
memory--and it's portable too (you could copy over the over the THIRD memory dump to another machine, in theory). If the above numbers
THIRD memory dump to another machine, in theory). If the seem to you to be mixing apples and oranges (C source and compiled THIRD code),
above numbers seem to you to be mixing apples and oranges note that you should in theory be able to stick the compiled THIRD code into the
(C source and compiled THIRD code), note that you should C source.
in theory be able to stick the compiled THIRD code into
the C source.
Software Construction Company gets credit for rekindling Software Construction Company gets credit for rekindling my interest in FORTH
my interest in FORTH and thus indirectly inspiring me and thus indirectly inspiring me to write this program.
to write this program.
## Copyright and CC BY-SA 4.0 License: ## Copyright and CC BY-SA 4.0 License:
@@ -3,11 +3,16 @@ buzzard.2.design description of FIRST (design documentation of THIRD)
third implementation of THIRD in FIRST third implementation of THIRD in FIRST
help.th online listing of THIRD primitives help.th online listing of THIRD primitives
FIRST demos: use 'first < {demo}'
# FIRST demos:
Use `first < {demo}`.
demo1.1st prints Hello World! assuming ASCII demo1.1st prints Hello World! assuming ASCII
THIRD demos: use 'cat third {demo} | first' # THIRD demos:
Use `cat third {demo} | first`.
demo1.th prints Hello World! regardless of character set demo1.th prints Hello World! regardless of character set
demo2.th demonstrates a simple loop demo2.th demonstrates a simple loop
@@ -16,7 +21,9 @@ demo4.th recursive factorial calculating on the way up
demo5.th recursive factorial calculating on the way down demo5.th recursive factorial calculating on the way down
demo6.th demonstrates switching from compiler to execution mode demo6.th demonstrates switching from compiler to execution mode
Interactive THIRD: use 'cat third - | first'. # Interactive THIRD:
To include the primitive on-line help, use Use `cat third - | first`.
'cat third help.th - | first'.
To include the primitive on-line help, use
`cat third help.th - | first`.