Stack-Oriented Programming
en.wikipedia.org
en.wikipedia.org
One of the interesting aspects of the game was the way the CPU was limited to a very small number of instructions per tick. At most you would get 50. So if you had a complex task that had to be executed in one tick, like filling the screen with bullets before your robot shut down due to lack of power, the way to do it was to preload all of the arguments onto the stack, wait for the tick to turn over, then call all of the functions at once. Basically allowing you to bank processing time for the turn you needed it.
The programs that uses the SPL-bomb tactic usually tried to catch all the enemy processes (slowed down to uselessness by the SPL-bomb) in the same place before finishing them off with a DAT.
You can see the different versions collected here: https://corewar.co.uk/standards/
https://hackaday.com/tag/forth/ (mainly this: https://hackaday.com/2017/08/04/take-the-blue-pill-and-go-fo... )
I find this and you can run the whole thing on my MacBook in 5 minutes. It is great:
Given the ease with which Forth can be ported to other platforms and architectures, I often wonder why there's no C-to-Forth translator - it seems like it would be just about the easiest way to bootstrap things.
https://en.bitcoin.it/wiki/Script
https://github.com/bitcoin/bitcoin/blob/master/src/script/sc...
As another example, Pascal p-code (UCSD p-code) is also stack-based:
https://en.wikipedia.org/wiki/P-code_machine
The Java Virtual Machine (JVM) also uses an operand stack:
For anyone interested, Book by Loeliger [1] and "Moving Forth" series [2] are essential readings on this topic.
[1]: https://archive.org/details/R.G.LoeligerThreadedInterpretive...
A core question, though, is why? Is tab-oriented programming have a wikipedia page where programs are written predominantly using tab stops instead of spaces? It's honestly a very similar sort of distinction to make.
1. I'm trying not to stray too far into all turing complete languages are turing complete and thus difference is meaningless land.
Rather, the key characteristic is that there is an important implicit feature available, namely the stack (or, as for example in the case of PostScript, several stacks), by which arguments can be passed along.
As a consequence, you get a form of compositionality of language elements that is not available in languages that lack this feature: A language element may consume, change and create entities on the stack, and the next language element can pick them up implicitly.
This often allows very concise and elegant code, and can also be interpreted very efficiently.
Presented by way of being an interesting link, and the educational nature of reading the best arguments in favor of something. I haven't done anything in concatenative programming in about 20 years, since I left math class and didn't need my HP 48G anymore.
So, for instance, let's elicit an error using Ghostscript, a freely available and efficient PostScript interpreter:
$ gs
GPL Ghostscript 9.27 (2019-04-04)
...
At the "GS>" prompt, I now define "f" via: /f { /hello g } def
Note that "f" refers to "g", which is not yet defined.Therefore, when I then invoke "f" via:
GS>f
I get an error: Error: /undefined in g
And importantly, the stack is retained, so I can inspect it at this point, interactively, using for example "pstack": GS<1>pstack
/hello
This shows that /hello is still on the stack. From there, we can resume in various ways, for example by clearing the stack (with "clear"), by redefining and reinvoking "f" etc.But I think maybe you meant in the sense of "in the real world", and I can't think of any examples. Prefixing some postscript to a document to manipulate that file is something it can be suited for, rather than using an external language to do so.
[0]: https://groups.google.com/d/msg/rec.arts.int-fiction/HNtntxC...
PostScript is a real programming language and can be used for many things (especially graphics). I also wrote a JSON parser in PostScript (see message <1567977875.bystand@zzo38computer.org> on comp.lang.postscript), and then someone else post their JSON parser in PostScript too.
I think PostScript isn't such a good protocol or document format, but it is good as a programming language. It is what I might use if I want to make a diagram (but unfortunately Ghostscript cannot produce SVG output; it can output PDF though, as well as many raster formats).
Someone was unsure how useful would be the JSON parser I wrote in PostScript, but if you want to print some diagram based on data in JSON format, then it can be helpful.
(I could implement Z-machine in Forth too if I wanted to do, but I have not done so yet because I have other things to do; I don't know if I might do so in future or not. I could implement Z-machine in any programming language with byte arrays, including assembly language (I started but haven't finished one in 6502).)
is a fractal fern. This is page description, but not in the normal way that it's used. Compare the output in a PS or PDF viewer with the source code which is under 1.5K.
https://www.cs.bham.ac.uk/research/projects/poplog/primer/#s...
Functions that return several results, implicit parameters, open stack, etc. It's a lot of fun.
1. Push the literal 2 onto the stack
2. Push the literal 3 onto the stack
3. Execute the Plus Operation
Therefore, there is no need to use a compiler, or even Dijkstra's shunting-yard algorithm[1], to reorder the statements for execution. This makes it extremely easy to write a compiler or interpreter for a stack-oriented language with postfix syntax: you never have to do any parsing at all, you just execute (or emit byte code) for each token as it comes, never needing to look forwards or backwards even a single token.
I would say that RPN is part of a paradigm - and if you pardon my bias I would say the Forth paradigm, really. The stack is part of a strategy of complexity reduction that start at the compiler/interpreter level.
Some virtual machine instruction sets (such as Glulx and Z-machine code) still require instruction operands but allow some or all of them to be optionally specified as stack operands. This allows you to have both stack and a register-like programming.
The reason I'm confused is that I see Forth in a lot of areas that look like they're typically for "C and lower", but looking at the syntax, Forth looks like a high-level language.
(Def ExecN func n infinite-series)
(ExecN + 10 integer)
... can it be done in forth.
The above dialect uses { } to delimit anonymous inline word definitions. RetroForth has a similar feature, and Factor uses the same syntax for "quotations", which have slightly different semantics but roughly the same meaning.
Actually the tutorial that host a forth on js (like clojurescript just self implement).
Which path to go?
Do not want to learn lisp ended up in scheme.
[0] https://www.gnu.org/software/gforth/
[1] https://github.com/nornagon/jonesforth/blob/master/jonesfort...
It's better than in the past with an ISO standard (IMHO) but know that if you change language providers there will be differences for things like external library linking (if available), GUI interaces etc.
There are demo versions of commericial systems at:
https://www.mpeforth.com/resource-links/downloads/
https://www.forth.com/download/
And of course a major pass-time in the Forth community is writing your own Forth. There is even a few Forths written in Python. (for instructional purposes only I assume)
Forth also has anonymous words (:NONAME), so you can dynamically define a computation and pass it around on the stack, and later execute it. I don't think there's any way to clean them up, though (no GC).
It's higher-level than C. Forth allows you to layer on dialects with custom domain-specific syntax and do other kinds of fancy metaprogramming. You can use Forth to interactively extend itself while you're working. Many Forths include a "bootstrapping" script, written entirely in forth, which defines such niceties as control structures and the syntax for comments.
Forth is more expressive than C, but just a bit more expensive. It being more expressive means it is in a higher level on my book, but it's outside of the usual hierarchy, so I would say it's in a higher level, but not on the same ladder.
The best way to achieve maximum flexibility and efficiency is to have the freedom to hop layers. To specify the high-level logic with a suitably abstract description, and then be able to reach into the lowest layers so that you can do what's necessary without needing to contort the logic to conform to the middle layers. If you do this once, it's a hack; if you hack repeatedly, you have a hot mess of entangled spaghetti; but if you design with this hackability in mind, you can evolve a system with abstractions at just the right level, that can be hacked as needed, without it turning into spaghetti. Requires discipline though.
A double edged sword too
I recall that the first thing that jumped out at me was that Chuck's code didn't have all those layers that my code had. There was the abstracted code on top and the hardware drivers on the bottom and very little in between. There was not a clear distinction in style at various levels as in my code where there were always someone else's code layered under mine that I could not or dared not change. Chuck's code looked abstracted and high level right from the bottom, the top used almost as many primitives as the bottom code. [1]
The confusion seems to come from the idea that a piece of code has to be either "abstract" all the way or "close to the metal" all the way. Why should it be? If you need to flip a bit in a peripheral between a call to some filesystem function and a call to memory page management function, just do it directly, don't invent a pseudo-high-level function just for that. Bare metal ain't dirty.
No, but it's not as solid as it sounds. What happens when version 2 of the hardware appears, and moves the bit to a different register?
You adapt your code for that platform. I don't know why developers today have such a love affair with unnecessary abstraction. Abstract when you need to; never before.
The asker isolated the question well, so I had no idea what Forth or stack machines are. Still it's a nice exercise to to implement common algorithms with a restricted set of moves.
The language is called UnoScript, inspired by the UNO card game. UNO has a natural stack built-in (thinking of the draw and discard piles) so there's a really natural connection. Link here if you're curious: https://github.com/berlinquin/UnoScript
https://esolangs.org/wiki/Pancake_Stack
And remember to Eat all of the pancakes!
An interpreter can be written rather quickly (compared to any productive program in the respective language) and it is interesting how much you can actually achieve with such primitive tools.
Why "had"? The x87 instructions are alive and well in modern intel processors. You can also generate code for them (for example, if you use "long double" in C) with all major compilers.
On topic: always good to read up on less common programming principles just to, erm, avoid lock-in