reMorse

You'll wish you didn't ask.

Turn back, if you value your sanity! This language in insane! INSANE, I TELL YOU!!!!!
reMorse programming language specification
(you may distribute this file freely, but please do not modify it)
(also, do not distribute the other reMorse files without this one)

note: this is only the specification.  to get the interpreter,
go to my Programs page which is at 
http://www.geocities.com/r_kusnery/progs.html

and now, there's reMorse2!
and reMorse2.-
and reMorse4ever

History
invented by Ryan Kusnery on February 14, 1998.  the fact that it was
Valentine's day is insignificant.  however, the fact that I had
recently stayed awake (at my computer, of course) for more than
24 hours may have had something to do with it.

Purpose of reMorse
reMorse (pronounced with the accent on the 're') was designed to be
as unrecognizable as possible, so I figured that Morse code would be
a good starting point.  originally, there were to be only 2 instructions
in it, but then I realized that it wouldn't look quite like Morse code
because Morse code has to have pauses (represented by whitespace)
between characters to indicate where one ends and another begins.

Description
reMorse. the Turing complete language with 4 instructions,
but you can get by with only 2 if you are writing a program that
doesn't use any input or need any loops.  (if you try it, I recommend
you use dot and dasher.)
reMorse, the language that is so hard to use that (unless aliens or
some sort of paranormal phenomenon is at work), there are currently
(almost certainly) no working, finished reMorse programs in existence.]

The Four Instructions (dot, dotty, dash, and dasher):
[.] = do operation (e.g. push, increase, output chr, etc.)
[. ] = do opposite operation (e.g. ptr back, pop, etc.)
[-] = next operation (i.e. increment operation selector)
[- ] = previous operation (i.e. decrement operation selector)
(of course you don't use brackets when you write a program,
but they are included here for clarity.  it's okay to use
more than one space; a space only has effect only when it is
the next recognized character after a dot or a dash.)

The (circular) List of Operations and their Opposites
operations|opposites|comments
----------+---------+--------
push      |pop      |into/outof datum
output chr|input chr|always ASCII (use stack)
bit sort  |tros tib |bit sort (stacktop) normal/reverse
select bit|filt bit |stacktop=stacktop AND YES/NOT funky
rot left  |rot right|rotate funky (bitwise)
increase  |decrease |(datum) by value in funky reg
ptr forth |ptr back |by value in funky reg
jmp forth |jmp back |by top value on stack

(the operation selector starts out on the push/pop pair, of course)

remember, whenever a value on the top of the stack is used (by jmp
or output chr) it gets used up, like in Befunge or FALSE.  though,
of course, (I can't remember what I was going to say here!)

Initialization and Errors
the funky register is initialized to 1 at the start.  data is
always 8-bit unsigned bytes; the data array has 256 bytes.  at
the start of a program run, each datum is initialized
to a value corresponding to its position in the array.  when
the data ptr goes pasts one end it comes back
at the other end; thus, the array is circular.  the stack
is theoretically infinite, but in practice it is merely as
large as is practical.  it should be at least 32768 bytes
in size.  stack overflow should cause the program to terminate
with the message "ABEND".  stack underflow should cause program
termination and a core dump.  all 256 bytes of data are dumped
as hex in 16 neat rows of 16 numbers.

for example, if a pop was the first operation done by a
program, the output would look like this:
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
(by the way, I typed this all by hand)

Jumping
all jumps are relative to the next instruction, not the one causing
the jump.  therefore, jumping by 0 has no effect, jumping forth by 1
skips the next instruction, and jumping back by 1 is always an infinite
loop.  when a jump attempts to jump past the beginning or end of
the program, the program will terminate normally.


Compatibility Issues
implementations on non-ASCII or non-Unix machines must be kluged to use
ASCII codes and Unix I/O conventions (10 = newline; 4 = end-of-file). if
an attempt is made to read a character when none is available, execution
of the program will be suspended until the user types a character.

Real reMorse Programming
_real_ reMorse programmers write their programs so that at at least
one point in the program, the operation selector could contain any of
two or more values.  thus, the operation performed at that point in the
program is not always the same, and it is practically impossible to
rewrite the program in another language.  this strengthens the argument
that reMorse is a powerful language, able to do things other languages
just can't.  real reMorse programmers also strive to make their reMorse
code look exactly like valid Morse code (at least one space per four
dots and/or dashes).

Using Good reMorse Programming Style
all you have to remember is to never, ever put a space at the end of a
line, because some mailreaders (and even some editors) remove spaces
from the ends of lines.  it's almost as bad to put a space at the
beginning of a line.  also, all unrecognized characters (including
newline characters) are ignored.  (I could have made newlines to do the
same thing as spaces, but that would have been the Wrong Thing, because
that would make it impossible to have extremely long sequences of
instructions.) spaces that come before the first dot or dash are also
ignored; there is no such thing as a compiler error in reMorse.

Sample Program (Hello, World!)
- - - ..- ...-.---.;newline
- - - .-. - ..-.- ...-. ---.;!
- - - ...- . . -.---.;d
----. . . -.---.;l
----. . -...---.;r
----. -...---.;o
----...-.- ..-. ---.;W
<i didn't feel like doing this part>
-..............;output all characters

turning this into 'real' reMorse code is left as an exercise to the
reader.  reMorse programs should, of course, be written in a single
sitting.  otherwise, you will need to write comments and things
indicating the expected position of the stack and data pointers as well
as the funky value, and that is considered bad form.  in fact, the
comments in the above program are included only because that program
is an example program.  furthermore, it is considered bad form to make
lines of reMorse code vary widely in length.  again, the above program
is done that way only because it is an example.

(note: this example doesn't work.  there is a bug in the second line,
and I think there are more bugs in the following lines.  if I hadn't
labeled it Hello, World I don't think I would even remember what it's
supposed to do.)

Debugging
in order to debug reMorse code, you have to run the reMorse interpreter
in a C debugger.  you have to Watch all the variables in remorse.h and
check to make sure that the operation counter (op) always contains the
value that it is supposed to.

Reimplementing reMorse
feel free to reimplement reMorse, but NOT from scratch.  if you write a
reMorse interpreter or compiler directly from the specs, you will almost
certainly get wrong an extremely important detail (such as the fact that
a space does not have to immediately follow the dot or dash that it is
modifying; it merely has to be the next _recognized_ character).
therefore, you should use the interpret(), compile(), and optimize()
functions with a minimum of modification, and be sure to give me credit.

Optimization
the optimize() function doesn't do anything except turn all the
instructions into single characters.  replacing sequences of the same
instruction with a number indicating how many would not work, because
it would cause the jump operation to malfunction.

Note:
the interpreter still does not work.  reMorse is such a simple language
that I thought an interpreter for it could not possibly fail.  I was
wrong.  the last time I tried to run it, it dumped core.  if you want
the sources anyway, you should email me.
(I now have gotten an interpreter for this language to work, but I
wrote it in Turbo Pascal.)
************************************************************************
reMorse2 (or should I say, "rereMorse"?)

reMorse2 is like reMorse except for a couple of minor changes:
I realized that to force reMorse programmers to use spaces
actually makes it harder to use reMorse for it true purpose:
to write programs that look like Morse code.

The Four New Instructions (doubledot, dottydash, doubledash, and balderdash):
[..] = do operation (e.g. push, increase, output chr, etc.)
[.-] = do opposite operation (e.g. ptr back, pop, etc.)
[--] = next operation (i.e. increment operation selector)
[-.] = previous operation (i.e. decrement operation selector)

in reMorse2, absolutely any characters besides dots and dashes are
completely ignored, so you can put spaces absolutely anywhere you want.
when a program is read in, it is converted to an array of bits.
(a zero represents a dash and a 1 represents a dot.)
in C (or maybe it was only in C++? (or maybe only Borland C++?)),
there is thing called bitfields,
however I will be writing the reMorse2 interpreter only in Turbo Pascal,
my native language, so I will be using an array[0..$7FE] of set of byte.
I have also rewritten the reMorse interpreter in Turbo Pascal.

(but oh no, now you could use absolutely no spaces at all, if you want!
unless of course, I make the interpreter simply refuse to operate
unless you use at least one space for every five meaningful characters.
I could also make it test for uniformity and randomness of distribution
(of spaces).  I think I'll do that.)

also, the jump operation now operates differently.  after getting a
value off the top of the stack, it jumps forward or backward by that
many _bits_, not by that many instructions.
************************************************************************
ooooooooops...  actually reMorse is not quite Turing complete.
I seem to have made the same mistake that Wouter van Oortmerssen,
(the inventor of FALSE) made.  you see, in order for a language to be
Turing complete, it must include a theoretically infinite randomly
accessible data store.  without this, a language cannot sort an
arbitrarily large list of numbers, nor can it be used to implement a
compiler (or interpreter) of itself.  both FALSE and reMorse have a
strictly limited random access data store and a theoretically
infinite restricted-access data store, but no theoretically infinite
randomly accessible data store.
(FALSE can be considered Turing complete if you use the compiler,
which has no type checking, stack checking, or range checking,
and therefore you can store data in a function or do various
other things that you can't do in the interpreter.
however the compiler is available only for the Amiga,
and most people use either a Microsoft Windows (95) box,
a Macintosh, or a Unix or Linux box.)
FALSE has an instruction that copies a value from anywhere in the
stack up to the top.  it could be made Turing complete with the
addition of one more instruction: an instruction that overwrites
a value anywhere in the stack with the one on top.  reMorse also
could be made Turing complete with the addition of just one more
instruction (an operation, actually (by the terminology that I
defined for reMorse)): an operation that bumps the stack pointer as
though pushing something but without making a change to the stack
memory!
because operations in reMorse come in pairs, I will create two
new ones: "fake push" and "fake pop".  these will change the stack
pointer without changing anything else.  the new dialect with this
revision shall be called "reMorse2.-" and it shall be the exactly
the same as reMorse2 except for this change.

The New List of Operations and their Opposites for reMorse2.-
operations|opposites|comments
----------+---------+--------
push      |pop      |into/outof datum
output chr|input chr|always ASCII (use stack)
fake push |fake pop |change only the stack pointer
bit sort  |tros tib |bit sort (stacktop) normal/reverse
select bit|filt bit |stacktop=stacktop AND YES/NOT funky
rot left  |rot right|rotate funky (bitwise)
increase  |decrease |(datum) by value in funky reg
ptr forth |ptr back |by value in funky reg
jmp forth |jmp back |by top value on stack

(note: reMorse2.- is pronounced "reMorse two dot dash" or
"reMorse two point blank" or "line pointing to esroMer".
and the interpreter for it shall be given the filename
REMORSE3.EXE (REMORSE3.PAS for the source file))

************************************************************************

reMorse (and its descendants (except for reMorse4ever)) is one of the
few languages that has no conditional jumps.  if you want conditional
execution, you have to take advantage of the fact that your jump
destination is dynamically assigned.  upon realizing this, I realized
that I had never heard of a language specifically designed to have no
conditional jumps.  so I got the idea for Bullfrog, which has no
conditional jumps, but is still pretty easy to use.
************************************************************************
reMorse4ever (Friday, April 9, 1999)

this language is based partly on the reMorse language, partly on the
Doublef*** language, and partly on the Blank language.
the first line of a reMorse4ever program is a list of operations that
the reMorse4ever program will be able to execute.  this first line can
contain any or all of the operations.  it can even contain repetitions.
in reMorse4ever there are only two instructions instead of the usual
four: the dash instruction which you use to move the operation counter
through the (circular) list of operations, and the dot instruction which
you use to execute the currently selected operations.  reMorse4ever has
2 arrays for data which are initialized to 0 at the beginning of the
program run.  each data pointer begins at the first element of the array.
the operations in reMorse4ever are:

+ increment datum at pointer1
- decrement datum at pointer1
> increment pointer1
< decrement pointer1
, input character at pointer1
. output character at pointer1
[ if the datum at pointer1 is nonzero, push the location of the current
  instruction onto the stack, and jump over the next 64 instructions.
] pop an address off the stack, and if the datum at pointer1 is zero,
  add one to the address.  jump to the resulting address.
/ increment datum at pointer2
\ decrement datum at pointer2
^ increment pointer2
v decrement pointer2
; input character at pointer2
" output character at pointer2
{ if the datum at pointer2 is nonzero, push the location of the current
  instruction onto the stack, and jump over the next 64 instructions.
} pop an address off the stack, and if the datum at pointer2 is zero,
  add one to the address.  jump to the resulting address.
* skip the next 8 instructions
_ no-op

revision: by following any of the characters [{* with a number,
you can override the default distance to jump forward.  only positive
base ten integers are allowed, however, if you type a number larger
than 2147483647 it will end up as a negative number.

remember that in reMorse4ever you decide what operations are on the list,
and in what order.  once you've made up your mind, you pretty much
can't change it (and have your program still work), so choose carefully.

go back to my homepage

go to my Programs page

go to my Weird Languages page