Show HN: A toy interpreter for a minimalistic imperative language in 1.3k LoC
github.com
github.com
https://github.com/bbu/simple-interpreter/blob/master/src/ru...
And of course I want to test this myself with a few interesting programs.
In terms of computing power, I think this language is just shy of being Turing complete. It's probably in the same class as regular expressions.
I'm working on a similar project, with a minimal compiler for an integer-only language, and I expect it to have the same limitation at first. I think the easiest way to remedy that is to implement dynamic arrays or some form of recursion, although I'm not sure if the latter is sufficient.
The parts that I wanted to make robust and recoverable from all kinds of errors were the lexer and the parser.
The arrays themselves are dynamically realloc'ed and checked for out of bounds access. I've also added some runtime warnings for access to undefined variables and negative or out of bounds array access.
Also, there is an equivalence between variables and arrays: `var[0]` is the same as `var`.
All in 1466 lines :-)
If it is possible to code an infinite loop, that tends to be enough to bring a language up to the level of being Turing equivalent.
To put it more strongly, it is really hard to define a nontrivial language that has infinite loops that is not Turing equivalent.
And in fact I can see how to simulate a cpu in this language, so there you go.
Anyway, I see the author has implemented arrays now, and more specifically dynamically-sized arrays, so I will concede that it is Turing complete. That wasn't really the intent of my post, as there are other ways to devise a language, but cool none the less.
For a view of the classes of languages in computation, see this hierarchy: https://en.wikipedia.org/wiki/Chomsky_hierarchy#The_hierarch... Here, the set of languages that Turing machines recognize are labeled as recursively enumerable languages.
(I could emulate a bounded stack with a bunch of variables and conditionals choosing them, but that's pretty ugly, and brings home just how bounded the result would be)
> CPU in this case could be stateless or have a limited number of states
The bounded state is an issue, but it is for Pentiums as well. We have approximations of Turing equivalent machines in real life, and that's close enough.
Regarding these other things:
> pushdown automata are defined as finite-state machines combined with a stack
I didn't say it was impossible, I said it was difficult with a nontrivial language -- because I've seen people try, and accidentally make things Turing equivalent.
If you know what you're doing, like you for instance, then sure, you just leave out problematic features and make sure you don't leave the level of the Chomsky hierarchy you were aiming for.
But no, people always want handy things like assignment and arithmetic expressions and loops and function calls and so on. :)
A classic example is pure standard SQL (up to a few years ago), which had no loop construct, and the language was famously sub-Turing.
But if the embedding language puts some SQL in a loop, it's trivial to emulate a CPU with simple SQL, which won't surprise someone classically trained like yourself, but does tend to surprise random programmers in the wild.
(I hear a more recent SQL standard added loops, which I have mixed feelings about.)