What is imeight
imeight is an imaginary eight-bit machine imagined by Csaba Skrabák. As an open source project, its emulator is also implemented and available online. The project has two goals:
- with its video functions it can be used as a game maker for 80s style online games,
- by having a programming tutorial, it serves as a gamified learning platform for beginners in programming.
The imeight language
The imeight machine comes with a language called imeight language, which is a kind of rip-off of Commodore 64's BASIC V2, with modifications that make it more suitable for the above purposes, and more suited to run in current browsers. However, it tries to keep the abstraction level of programming as close as possible to BASIC V2:
- Floating-point arithmetic with math-like infix notation.
- Built-in string manipulation functions.
- Named global variables (only global ones, no option for local scope.)
- Subprograms without any special support for return values or parameters, but with return stack.
- A single form of loop: FOR.
- Conditional statements (without support for ELSE branch, restricted to be written on one line.)
- Interactive I/O, line or character based. (Video functions add mouse and touch I/O via built-in arrays, not affecting language syntax.)
- DATA lines to store values in the program text.
- Line remarks (block comments not supported.)
- Abbreviations for some frequently used keywords.
- Multi-dimensional arrays.
- User functions (pure, single-line.)
- Expression/statement distinction.
- Not structured - program flow constructs are built up of flow instructions, which aren't validated by the parser; so ill-formed programs may produce run-time errors.
- Named labels (as a more convenient counterpart of line numbers.)
- PUSH and PULL stack instructions (so imeight language can replace a separate assembly language or machine code, which are not implemented in the emulator.)
As opposed to C/C++/Java where execution of a statement is done by evaluating an expression with side-effects then dropping its return value, imeight language distinguishes syntactic contexts where expressions are expected and evaluation happens from those where statements are expected and execution happens.
REM * BUBBLE SORT * DIM ARRAY(10) INPUT ARRAY(0) FOR I=1 TO 9 READ ARRAY(I) NEXT FOR K=8 TO 0 STEP -1 FOR I=0 TO K IF ARRAY(I)>ARRAY(I + 1) THEN NEXT I:GOTO OUT SWAP = ARRAY(I) ARRAY(I) = ARRAY(I + 1) ARRAY(I + 1) = SWAP NEXT I @OUT PRINT ARRAY(I) NEXT K PRINT ARRAY(0) END DATA 1, 2, 3, 5, 9, 8, 7, 4, 6
In a sense. In order to run, the program text is first parsed into a structure, which can be viewed as the analogy of C64's tokenized code and linked list of lines as those are stored in its BASIC RAM. But while the textual representation of the imeight program code uses infix notation for expressions, its structured representation is already translated into postfix Polish. So there is a more complex parsing before running, which may be thought of as compilation.
The tokenization (parsing) is almost completely reversible both in C64 and imeight. Although the existing emulator is not capable of actually do a reverse tokenization. Instead, it keeps the original text representation of the program, and the emulated LIST command really just displays the original list. Examples of incomplete reversibility include ignored white spaces in imeight, (and abbreviations in C64.)
Both the parser and the runner in the imeight emulator are designed with focus on positive use cases. It enables running correct programs; but does not take effort to prevent writing programs that exploit undocumented features or flaws of the parser and the runner. This is a principle that machines and languages designed in the 1980s used to follow, which enables for programming hacks with well predictable outcome. Although in order to predict the outcome, one needs deep understanding of both the language and machine. This is a signature part of the feel when programming eight bit machines, deliberately kept in imeight, too.
For instance, the language of variable names includes the instruction keywords. The parser does not check for instruction keyword appearing where a variable name should. Parser will put it in postfix order as if it would be a variable. Then, runner will execute the instruction with whatever there is on the argument stack instead of dereferencing a variable. Example:
- GOTO is an instruction keyword, but also is a legal variable name
- `SPRX(6) = REM - A/GOTO:@A` is accepted
- it translates into postfix as 6, SPRX(, REM, A, GOTO, /, -, LET, A, @
- execution: push 6, push SPRX(, pop and ignore SPRX( as if it was REM's argument, push the name A, jump to label A as GOTO pops it