OISC:2bis

From Esolang
Jump to navigation Jump to search

Obfuscated Indirect Subleq with Coprocessor: 2 word instruction, version 2. (That's what 'bis' means, from the Latin.)

Summary

This is the new and improved version, now with an actual parser. And a stack. And you don't have to use a separate file for the negative memory assignments.

The raw numbers are extremely obfuscated, but the parser makes it easy to use. This may be against the spirit of esolangs. Positive, negative, and zero valued instructions change the effects, and decimals make arguments indirect. All instructions are in positive memory (use the absolute value). Negative memory can only be accessed indirectly.

   Two word instruction:  A B

   A B    Effect
   + +    B = B - A
   - +    if [A] <= 0, jump to B
   + -    if [A] <=0, call B
   - -    if [A] <= 0, relative jump by [B]
   + 0    Push [A] onto the stack
   - 0    Pop the stack into A
   0 +    Execute instruction [B] on the stack
   0 -    if [B] <= 0, return
   0 0    halt

   Assembler formats:

   #            comment
   %            data (optional in negative memory)
   name:        naming a memory word
   name         using a named word
   *name        indirect reference name (if N is 23, *N is 23.0)
   @            this word
   ?            next word
   % --NEGATIVE: --NEGATIVE--     mandatory memory separator
   !            0
   ;            end of instruction
   ,            separator
   " or '       string delimiters
   ZERO         automatically created word containing 0
   &            negative and pointer (parser internal use)

   /sub can be called with 1 or 2 words
       X Y      [Y] = [Y] - [X]
       X        [X] = 0
   /call, /jump and /relj can be called with 1 or 2 words.  Branching to a negative address will halt.
       X Y      if [X] <= 0, branch to Y (relative jump by [Y])
       X        unconditional branch to X (relative jump by [X])
   /push, /pop and /exec are called with 1 word
       X        push [X] / pop to X / execute instruction [X]
   /ret can be called with 0 or 1 word.  If the return stack is empty, the program will halt.
       X        if [X] <= 0, return
       -        unconditional return (ZERO inserted)
   /halt        takes no arguments


   Stack instructions:

        Positive                      Negative
   1    input char ( -- a)            output char (a -- )
   2    input digit  ( -- a)          output number (a -- )
   3    DUP (a -- aa)                 DROP (a -- )
   4    OVER (ab -- aba)              SWAP (ab -- ba)
   5    roll left N (abcd1 -- bcda)   roll right N (abcd2 -- cdab)
   6    reverse stack (abcd -- dcba)  clear stack (abcd -- )
   7    depth of stack ( -- a)        pick N (abcd3 -- abcdb) 
   8    bitwise true ( -- -1)         bitwise false ( -- 0)
   9    bitwise AND (ab -- a&b)       bitwise NOT (a -- ~a)
   10   bitwise OR (ab -- a|b)        bitwise XOR (ab -- a^b)
   11   shift left N bits (aN -- a)   shift right N bits (aN -- a)
   12   times (ab -- a*b)             divide (ab -- a/b)
   13   int division (ab -- a//b)     remainder (ab -- a%b)
   14   exponent e (a -- exp(a))      natural log (a -- log(a))
   15   convert to integer (a -- a)   convert to float (a -- a)
   16   alloc N words (sign matters)  free N words (sign matters)
   17   plus (ab -- a+b)              minus (ab -- a-b)
   18   sin (a -- sin(a))             asin (a -- asin(a))
   19   cos (a -- cos(a))             acos (a -- acos(a))
   20   tan (a -- tan(a))             atan (a -- atan(a))
   21   sinh (a -- sinh(a))           asinh (a -- asinh(a))
   22   cosh (a -- cos(a))            acosh (a -- acosh(a))
   23   tanh (a -- cos(a))            atanh (a -- atanh(a))

Sample program

Less obfuscated

               /jump ZERO Main                 # jump is conditional
                                               # ZERO would have been inserted if there was no reference

% Text1: "Hello, starshine!" 0
% Text1*: Text1
% Text2*: Text2
% m1: -1
% p1: 1
% write_char: -1


Main:           /push Text1*
                /call Print_string
                /relj three                     # relative jump is conditional, ZERO inserted
% three: +3                                      # relative jump is from the current instruction pointer
                /push Text2*                    # target of relative jump
                /call Neg_print_string
                /halt 

Print_string:   /pop String*
Print_loop:     /push *String*
                /exec write_char
                /sub m1 String*                 # subtract -1 to advance
                /ret *String*                   # Return is conditional, ZERO inserted
                /jump Print_loop
% String*: 0

Neg_print_string:   /pop Neg_string*
Neg_print_loop:     /push *Neg_string*
                    /exec write_char
                    /sub p1 Neg_string*         # negative memory, so subtract 1 to advance
                    /ret *Neg_string*
                    /jump Neg_print_loop
% Neg_string*: 0 -99                            # '-99' just to make finding ZERO inserted into the compiled code easier
                                                # 'ZERO: 0' will be inserted here automatically if ZERO: is undefined

% --NEGATIVE--: --NEGATIVE--

Text2: 32 32 'The earth says, "Hello!"' 10 0

More obfuscated

-65 25 ; 72 101 ; 108 108 ; 111 44 ; 32 115 ;
116 97 ; 114 115 ; 104 105 ; 110 101 ; 33 0 ;
2 -1 ; -1 1 ; -1 20 ; 0 65 ; -38 -65 ;
-31 3 ; 21 0 ; 65 -51 ; 0 0 ; -50 0 ;
50.0 0 ; 0 24 ; 22 50 ; 0 -50.0 ; -65 40 ;
0 -63 ; 0 63.0 ; 0 0 ; 24 23 ; 63 0 ;
-63.0 -65 ; 53 0 ; -99 0 ;
% --NEGATIVE--: --NEGATIVE--
32 32 ; 84 104 ; 101 32 ; 101 97 ; 114 116 ;
104 32 ; 115 97 ; 121 115 ; 44 32 ; 34 72 ;
101 108 ; 108 111 ; 33 34 ; 10 0 ;


Philosophy

What's the point of all this? What is an instruction?

Subleq is, to me, the premier one instruction set computer (OISC). Three memory addresses, A B C, where B=B-A, if B<=0, jump to C. That's it. Simple, elegant, usable. An operating system (Dawn, sadly no longer available) was once written using it. Since there is only one instruction, it is assumed. But to be useful, any language has to perform I/O. So Subleq uses memory mappings for input, output, and halt. Each of these attaches to a different part of the instruction (A, B, or C). It works well. Where is the instruction?

Subleq+ uses negative numbers to indicate indirect addressing. It is a touch more complicated, but works well and enhances the power of the language. Where is the instruction?

OISC: uses the trichotomy of numbers (positive, negative and zero), along with floating points and integers, to accomplish several different things using the same two (or three) words, which are memory addresses. There is even a parser which uses recognizable commands. But these commands are seen nowhere in the actual executable code. It's nothing but memory addresses expressed as numbers in different ways. Where is the instruction?

Complexity arises from relationships. Power arises from complexity.


Computational class

OISC:2bis is Turing-complete. It is, as the name implies, an extension of Subleq.

See also

  • OISC One instruction set computing
  • Subleq Subleq
  • Subleq+ Subleq with indirection through negative addressing.
  • OISC:2 Where the madness began.
  • OISC:3 Easier to use but somewhat wasteful of memory. Has literals instead of relative jumps.

External resources