M-Code

M-Code is a Turing-complete esoteric programming language designed by User:Madk.
M-Code takes a lot of inspiration from 6502 assembly, brainfuck, and then it tosses a handful of features of its own. Every character in a source file represents a single value, and numerical values can be specified inside [] brackets. There are three variations: 8 bit M-Code, 16 bit M-Code, and 32 bit M-Code. The higher bit variations were introduced to allow a larger tape size than a mere 256 bytes. All values in each bit mode are that number of bits. 32 bit values are signed.
==Key Features==
* Source code is stored in an accessible memory bank, making self-modification important to many functions.
* 3 value register
* File access
* Relatively robust arithmetic and logic operands
==Instruction Set==
===Commands===
These are the single-character commands recognized by the interpreter. All commands and symbols use 1 value, arguments must immediately follow commands. Program execution starts at memory address 0.
 Register handling for the A, B, C registers. > puts a value into the register and < takes it out.
 > < 
 } { 
 ) ( 
 arguments: [memory address]
 
 Store a literal value in the A, B, C registers
 4 5 6
 arguments: [number]
 
 Handle the string in memory by printing it, getting it from input, or swapping it with the secondary (inactive) memory string
 ; \ ~
 
 Clear the string in memory
 s
 
 Read characters from the memory string and put them in the A, B, C registers
 ^ ` '
 arguments: [position in memory string]
 
 Treat the memory string as a number and put it in the A, B, C register.
 U V W
 
 Write characters to the end of the memory string from the A, B, C registers
 : . ,
 
 Output the numerical value onto the end of the memory string
 1 2 3
 
 Store the length in characters of the string in memory to register A, B, C
 7 8 9
 
 Copy a byte, swap two bytes in memory from one place to another
 # S
 arguments: [origin memory address] [second memory address]
 
 Increment, decrement a byte in memory
 i d
 
 increment, decrement the value in the A, B, C registers
 o n
 u t
 f e
 
 Jump unconditionally
 j
 arguments: [jump to address]
 
 Jump if A > B
 ?
 arguments: [jump to address]
 
 Jump if A < B
 !
 arguments: [jump to address]
 
 Jump if A = B
 =
 arguments: [jump to address]
 
 Jump if A != B
 N
 arguments: [jump to address]
 
 Swap A and B registers
 x
 
 Swap B and C registers
 y
 
 Swap C and A registers
 z
 
 Set A, B, C register to 0
 a b c
 
 Perform a logical NOT operation on registers A, B, C
 A B C
 
 Copy the value in the A register into both B and C
 Y 
 
 Shift a value in memory left, right by one bit
 L R
 arguments: [memory address]
 
 Perform an operation on A and B and place the result in C
 Add:			+
 Subtract:		-
 Divide: 		/
 Multiply:		*
 Modulo:		%
 Raise to power:	v
 Bit shift left:	l
 Bit shift right:	r
 Mean:			m
 Logical OR:		O
 Logical AND:		&
 Logical XOR:		X 
 
 Creates a new external data file if one doesn't already exist. It opens it into memory if it does.
 F
 arguments: [file #] 
 
 Write a value from a program memory address into a file
 w
 arguments: [write from memory address][write to file address]
 
 Read a byte from a file and store it in program memory
 p
 arguments: [write to memory address][read from file address]
 
 Read a file's entire contents and store it all in program memory starting at a given location
 P
 arguments: [write to memory address]
 
 Print memory string to console without a newline (with the exception of the inclusion of an actual newline character)
 H
 
 Print a newline to the console
 I
 
 Delay program execution for some number of milliseconds
 D
 arguments: [milliseconds]
 
 Output a number, character to the end of the memory string from a memory address
 0 @
 arguments: [memory address]
 
 Kill program
 _
===Non-runtime parser instructions===
 
These are interpreter instructions. They aren't processed in memory at runtime, but aid in the writing of code and pre-runtime memory management.
 
 Comment
 // (...) // 
 
 Reference a label and store its position as a value in this memory address
 |(...)|
 
 Define a label mid-line
 |$(...)|
 
 Define a value numerically instead of an ASCII character. For example, [65] and "A" and also [35] and "#" would be interchangeable.
 [(...)] 
 
 Set string memory contents before runtime - first instance sets first string, second instance sets second string.
 $"(...)
 
 Set the current location in memory that the following data will start being written at. It must be numerical.
 $(...)
 
 Define a label based on this line's position in the source file. 
 It cannot start with a digit (0-9), "$", or a quote ("). It cannot contain "=". Labels are case-insensitive.
 $(...) 
 
 Simultaneously define a label and the contents of the immediate memory address. 
 The assignment should be formatted no differently than typical program data. Example: $pound = # OR $pound = [35]
 $(...)=(...)
 
 Count whitespace as valid characters in this line of code, with the exception of preceeding and following space. 
 (...) $
 
 Self-reference this address in memory - if [$$] were at the very beginning of a program, 
 it would be equivalent to [0]. At $42, [$$] would be [42].
 [$$]
 
 Put a $ character where the parser would normally see it as a non-runtime command 
 (at the very beginning or very end of a line, excluding whitespace)
 [$]
 
 Put a [ character where the parser would normally see it as a non-runtime command
 [[]
 
 Put a | character where the parser would normally see it as a non-runtime command
 [|]
==Examples==
===Hello, world!===
 
 // Print "Hello, world!" to the console. //
 
 4|data end|	// Store the location of the last character, "!", in register A. //
 j|main| // Jump to the main loop start // 
 
 
 $ main		// This is a label signifying the beginning of the main loop. //
 }|$pos||data|	// Push "H" into register B from the start of the "Hello, world!" string. $pos is a label definition. //
 .		// Add "H" from B to the end of the memory string. //
 i|pos|		// Increment the number in }|data| by one, so next loop it'll push "e", then "l", (...) //
 }|pos|		// Push that same number into B to get ready for a comparison. //
 ?|main| // Jump back to |main| to create a loop if the value in register A is > B to know if we've reached the end of "Hello, world!". //
 
 ;		// After the above loops has finished, ; prints the accumulated string to the console. //
 _		// Terminate program execution. //
 
 $data		// Label the location of the string data in memory //
 Hello,[32]world!// Whitespace is not recognized by the parser, [32] is the ASCII code for a space. //
 $data end	// This is a label to provide the ending point of the "Hello, world!" data. //
===Much less elegant Hello, world!===
 $"Hello, world! I'm a big fat cheater.
 ;_
===99 bottles of beer===
 // This program prints the lyrics to "99 bottles of beer". 
 It exceeds the program memory space offered by 8-bit
 M-Code and therefore is incompatible. //
 
 d[183]>[183]bu=G16[224]4[15]j[184]6[209]4[21]j[184]>[183]16[224] 
 4[30]j[184]4.:;s6[241]4)j[184]>[183]n1}[1]=76[224]4=j[184]6[273] 
 4=j[184]6[209]4Cj[184];sj[0]0[183]6[273]4Oj[184]6[209]4Uj[184]0[183] 
 6[273]4]j[184]4.:;s6[289]4hj[184]6[320]4nj[184]6[224]4tj[184]6[209] 
 4zj[184];s6[320]4[130]j[184]6[224]4[136]j[184]6[209]4[142]j[184] 
 6[320]4[148]j[184]6[224]4[154]j[184]4.:;s6[328]4[165]j[184]4c16[224] 
 4[174]j[184]6[209]4[180]j[184];s_d([201]<[202]#[201][192]>[0]b=[203] 
 i[201]:j[188][0][0]#[202][207]j[0]_[32]on[32]the[32]wall.[32][0][32]
 bottles[32]of[32]beer[0]Take[32]one[32]down,[32]pass[32]it[32]around
 .[32][0][32]bottle[32]of[32]beer[0]Take[32]it[32]down,[32]pass[32]it
 [32]around.[32][0]No[32]more[0]Go[32]to[32]the[32]store[32]and[32]bu
 y[32]some[32]more.[32]
===Fibonacci sequence===
 // Calculate the first several numbers of the Fibonacci sequence. //
 
 // A & B are added together each loop to calculate C, a member of the sequence. 
 A then becomes B and B becomes C and the next number is calculated next cycle. //
 
 5[1]			// The A and C registers start at 0. The B register needs to be set to 1. //
 
 $ loop start		// This label indicates the main loop initiation. //
 3;s			// Output the value in C to the console. //
 < |memoryA| { |memoryB|	// Store the values in the A and B registers into memory so we can do an
 			 end-of-loop check. //
 d |sequence|		// |sequence| is the label dictating how many numbers of the sequence to show.
 			 Here it is decremented by 1 each loop. //
 > |sequence| b		// Store |sequence| in the A register and 0 in B for comparison. //
 = |program end|		// If A=B (sequence=0) jump to the program's end. //
 > |memoryB| } |memoryA|	// Restore the previous states of A and B, but also swap them in the process. //
 y			// Swap the contents of the B and C registers. //
 +			// Add A and B and put the result in C. //
 j |loop start|		// Go back to the loop start label and do it all again. // 
 
 $ memoryA		// Used to temporarily store the A register during the loop. //
 [0]
 $ memoryB		// Used to store the B register. //
 [0]
 $ sequence		// Iterate the loop |sequence| number of times. The 15th member of the //
 [14]			// sequence exceeds 255, so only the first 14 are calculated. //
 
 $ program end		// The loop jumps here when it has completed |sequence| cycles. //
 _			// Program termination command //
===Collatz sequence===
 // Calculate a Collatz sequence from a starting amount. //
 // This program is _not_ intended to be run in the 8-bit version of M-Code. //
 
 $"Input a number to determine its Collatz sequence.
 $"Number of cycles:
 ;s;\Us;
 
 $loop
 <|var|1;s5[2]%5[0]z
 N|odd|
 $even
 >|var|5[2]/
 j|thru|
 $odd
 >|var|5[3]*f
 $thru
 i|cycles|z5[1]=|end|
 j|loop|
 
 $end
 1;~4[32]:>|cycles|1;
 _
 $var=0
 $cycles
 [0]
===Output ASCII table===
 // Prints ASCII table to the console //
 
 4[255]5[0]6[32].,,2;suN[6]_
===Quine===
In order to keep readable ASCII characters for memory address representations, the program memory storage starts at 35.
 // This program outputs its source to the console. 
 To maintain readable characters, the first symbol 
 is located at $35 within program memory. //
 
 $35
 >#y}$N/5#.j1:yi$>$5;!#;_
Formatted:
 $35
 
 >[35]
 }[36]
 N[45]
 5[35]
 .
 j[47]
 :
 i[36]
 >[36]
 5[59]
 ![35]
 
 ;_
===Cat===
 \;_
===Brainfuck Interpreter===
While this interpreter is designed with 8-bit M-Code in mind and has a maximum code size of 256 commands and a tape size of only 32, these values can be expanded into greater than 60,000 or over a million commands and tape by changing the wraparound code at the end and using the 16-bit or 32-bit M-Code interpreters, respectively. It shows through simulation that M-Code, if given infinite memory, is Turing-complete.
 // Interpret a brainfuck script. //
 
 $">+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.>>>++++++++[<++++>-]<.>>>++++++++++[<+++++++++>-]<---.<<<<.+++.------.--------.>>+.#
 
 $"Please wait, this may take a while :P
 ~;s~
 
 j |main loop|
 
 	$ >
 	 [62]
 	$ <
 	 [60]
 	$ +
 	 [43]
 	$ -
 	 [45]
 	$ .
 	 [46]
 	$ ,
 	 [44]
 	$ [
 	 [91]
 	$ ]
 	 [93]
 	$ #
 	 [35]
 
 $ tape
 [223]
 
 $ main loop 
 
 ^
 $ code
 [1] 
 
 $ check >
 } |>|
 N |check <|
 i |tape|
 j |end|
 
 $ check <
 } |<|
 N |check +|
 d |tape|
 j |end| 
 
 $ check +
 } |+|
 N |check -|
 # |tape||+arg|
 i
 $ +arg
 [ 0 ]
 j |end|
 
 $ check -
 } |-|
 N |check .|
 # |tape||-arg|
 d
 $ -arg
 [ 0 ]
 j |end|
 
 $ check .
 } |.|
 N |check ,|
 # |tape||.arg|
 ) 
 $ .arg
 [ 0 ]
 ~s,H~
 j |end|
 
 $ check ,
 } |,|
 N |check [|
 ~\'[1]~
 # |tape||,arg|
 (
 $ ,arg
 [ 0 ]
 j |end|
 
 $ check [
 } |[|
 N |check ]|
 # |tape||[mod|
 }
 $ [mod
 [ 0 ]
 4 [0]
 N |end|
 4 [1]
 < |nest|
 $ [start
 4 [0]
 } |nest|
 = |end|
 i |code|
 # |code||[char|
 ^
 $ [char
 [ 0 ]
 } |[|
 N |[2|
 i |nest|
 $ [2
 } |]|
 N |[start|
 d |nest|
 j |[start|
 
 $ check ]
 } |]|
 N |check #|
 4 [1]
 < |nest|
 $ ]start
 4 [0]
 } |nest|
 d |code|
 = |end|
 # |code||]char|
 ^
 $ ]char
 [ 0 ]
 } |[|
 N |]2|
 d |nest|
 $ ]2
 } |]|
 N |]start|
 i |nest|
 j |]start|
 
 $ check #
 } |#|
 N |end|
 I_ 
 
 $end
 i |code|
 > |code|
 5 [255]
 N |nc|
 # |const1||code|
 $ nc
 5 [221]
 N |main loop|
 # |const2||code|
 j |main loop|
 
 $ const1
 [222]
 $ const2
 [254]
 
 $nest
 [0]
==External resources==
* Download M-Code interpreter
Category:Languages
Category:Turing complete
Category:Cell-based
Category:Implemented
Category:Low-level
Category: 2010