Amelia

Amelia: 
 Allele Mediated Expressive List Interpretation Algorithms
Amelia's Monstrously Enervating List Interpretative Acts
Amelia's Manipilatively Esoteric Listy Instigative Activity
Amelia's Messy Esoteric Language Is Anguishing
Anti-Modular Enlightened Loopy Architecture
==Overview==
Amelia is the progeny of Iris. (Its namesake is the progeny of Iris's namesake as of March 22, 2013.) Its design philosophy mirrors Iris: no syntax errors, no premature exiting, and a simple structure. Programs are designed to be produced by random mutation and non-random selection.
Amelia, however, has important differences. There are only two function calls: move pointer & calculate expression. These calls are clearly separated (using a semi-colon in the current version).
With a clear separation between functions, it's much easier to try create programs via mutation and selection.
What it loses: Iris allowed for any element in the program to be modified by register values. Amelia only allows expression elements and where to put results to be modified by register values. Iris allows a snippet of code to be used several times as several different things (function call, value, etc.). Amelia's components are single function.
The program structure carries the genetic metaphore into its operation. A function is a "gene"; each component of which is a tripplet of values called a codon. Each value is called a base. The first codon defines the function call, the remaining codons are an expression which result is used as a truth test or gets assigned to a register. Each "level" (gene, codon, base) can also be modified when creating new programs. These modifications can vary depending on the level.
==Syntax==
The specifications of this language call for one or more sets of numbers. These sets are called genes. The numbers are comma delimited. The sets are semi-colon delimited. The program in its entirety is called a chromosome. 
The instructions (genes) are executed through an instruction pointer that advances by one gene after each execution.
There are two types of genes. The first type (MOD) modifies the value in a given register. The second type (MOV) moves the intruction pointer to a new location.
A gene is read in tripplets (codons). A gene may have a few numbers left over after dividing up the codons. Those extras are discarded.
After the first tripplet in a gene is used to call MOV or MOD, the remaining tripplets are an expression. In the case of MOD, the result of the expression is assigned to a register. In the case of MOV, the expression is a truth value. If true, then the instruction pointer is moved to a new location on the chromosome. If there are fewer than three tripplets in the expression, the first tripplet is the expression result. If there isn't enough to have even one tripplet, then the expression result is 0.
Expressions are prefix (polish) notation.
If there are fewer than three codons in an expression, the first codon is parsed and returned as a value.
The chromosome loops perpetually, so the interpreter should terminate in a reasonable number of gene executions.
To exit a program, one may either execute an expression that divides by 0 or move the execution pointer to the current gene.
Comments are preceeded by a colon. 
===Syntax tables===
 Gene structure
 	Schematic	Example 	Description
Function Call	Codon 	24, 	Calls MOD. This is an assignment statement.
Function Call	Codon 	45, 	The register that gets the new value.
Function Call	Codon 	12, 	Just states that the 45 is a register and not a reference to another register.
Expression 	Codon 	6, 	 
Expression 	Codon 	7, 	 
Expression 	Codon 	8, 	 
Expression 	… 	…	 
Expression 	Codon 	0, 	 
Expression 	Codon 	3, 	 
Expression 	Codon 	4,; 	 
 Function call MOD
Value position 	Value meaning 	Note
n1 (number at position 1 of codon)	Function call. If n1 % 2 == 0 then call MOD 	Even numbers always call MOD. Odd numbers call MOV.
n2 (number at position 2 of codon)	Register to change according to attached expression	The implementation uses a single array for registers
n3 (number at position 3 of codon)	if n3%2 == 0 then register[n2] = expression result
if n3%2 == 1 then register[register[n2]] = expression result	There isn't much to say here.
 Function call MOV
Value position	Value meaning 	Notes
n1 	Function call. If n1 % 2 == 1 then call MOV	Even numbers always call MOD. Odd numbers call MOV.
n2 	Move the pointer to Gene n2 	Self explanatory.
n3 	How many function calls (genes) before going to the gene following the current one.
If this value is 0 then there is no returning to the following gene.	when n3 > 0, the current location is saved, the pointer goes to new location (gene n2), and n3 calls are made before returning. When n3 == 0 we start over at the new location (gene n2)
Think of this as a GOTO or GOSUB statement if n3 == 0 or 1 respectively
 expression contents (per codon)
Value position	Value meaning 	Notes
n1 	if #values -1 <= #operators then n3 is a value
if #values > 1/2 of total #operators and #values for the expression then n3 is an operator
if n1%2 == 0 then n3 is a value
if n1%2 == 1 then n3 is an operator	Since the values and operators are (potentially) randomly built, there has to be a way to guarantee a legitimate expression to evaluate.
This decision set (and other bits) guarantees that proper expression.
n2 	if n2%3 == 0 then n3 is a value or operator
if n2%3 == 1 then register[n3] is a value or operator
if n2%3 == 2 then register[register[n3]] is a value or operator	 
n3 	operator or value	When an operator for a MOD expression: 
n3 % 6 ==
0 then + 
1 then - 
2 then * 
3 then / 
4 then ** 
5 then %
When an operator for a MOV expression:
n3 % 9 ==
0 then == 
1 then > 
2 then < 
3 then >= 
4 then <= 
5 then != 
6 then and 
7 then or 
8 then not 
9 then xor
==Examples==
Fibonacci:
The output of the following code is 
26 24 23 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711
The fourth number is the start of the sequence. The first number 26 refers to the register about to be written to. (Register 26 endes up never being written to.) The second and third numbers 24 and 23 refer to the registers which hold the previous two numbers in the sequence.
 0,0,0,		:assigns a value to register 0,
 	0,5,0,; :the value is 5
 
 0,3,0,		: register 3
 	0,0,0,; : gets a 0
 
 0,4,0,		: register 4
 	0,1,0,; : gets a 1
 
 0,1,0,		: register 1 gets
 	0,1,0,	: 1
 	0,0,1,	: register[0]
 	0,1,0,; : - 
 		: - register[0] 1 (prefix notation)
 
 0,2,0,		: register 2 gets
 	0,1,0,	: 1
 	0,1,1,	: register[1]
 	0,1,0,; : -
 		: - register[1] 1 (prefix notation)
 
 
 0,0,1,		: location referenced by register [0]
 	0,1,2,	: value in register[2] is a reference to
 	0,2,2, : another register (this changes during run)
 	0,0,0,;	: + 
 		: this produces each value in the
 		: Fibonacci sequence
 
 0,0,0,		: add 1 to register[0]
 	0,0,1,
 	0,1,0,
 	0,0,0,;
 
 1,7,0,			: go to gene 7 
 	0,25,1,;	: if register[25] has a value
 			: (other than 0)
 			: this is gene 7 (infinite loop)
 			: this is one way to end the program
 
 1,3,0,			:go to gene 3
 	1,1,0,;		:if (1)
 			:this is how we iterate
 ##################
 
 : this following is alternate way to terminate a program
 0,0,0,			: (gene 9) assign a divide by zero
 	0,0,0,
 	0,0,0,
 	0,3,0,;		: / 0 0 (illegal devide by 0 - 
 			:ends program and outputs)
==Implementation==
 #!/usr/bin/perl 
 #use warnings;
 use strict;
 use Data::Dumper;
 
 { #closure for death count
 
 	my $still_alive = 1000;
 
 	sub deathcount{
 		my $opt = shift;
 		return $still_alive if $opt;
 		$still_alive--;
 		finish ("counted down\n") unless ($still_alive);
 	}
 
 }
 
 { #closure for genome
 	my $file = "sequence.ama";
 	my $string = get_file($file);
 	
 	my @C = get_chromasome($string);
 	sub Access_C{
 		my $access_type = shift; #gene, codon, base, size
 		my $ptr = shift; #which gene
 		return map { [@$_] }@{$C[$ptr]} if $access_type eq "gene"; #gene
 		return $#C if $access_type eq "size";
 	}
 
 
 }
 { #closure for register
 	my @R = qw//;
 	sub Access_R{
 		my $access_type = shift;
 		my $register_location = shift;
 		$register_location = abs $register_location;
 		my $value = shift;
 
 		$R[$register_location] = $value if $access_type eq "write";
 		return $R[$register_location] if $access_type eq "read";
 	}
 	sub output{
 		for (@R){
 			print "$_ ";
 		}
 	}
 }
 
 wrapper(0);
 
 sub wrapper{
 	my $ptr = shift; #genome pointer
 	my $i = 1 + deathcount("return");#iterator for top level call() 
 
 	while (1) {
 		$ptr = call ($ptr, $i); 
 			
 		#ptr is changed to call()'s return value if we 
 		#ever get to this point
 	}
 }
 
 sub get_file{
 	my $infile = shift;
 	my $string;
 	open (my $fh, "<", $infile) or die "nopen $infile, $!";
 	while (<$fh>){
 		chomp;
 		s/:.*//;	#comments
 		s/(\d)\s/$1,/g; #space to comma
 		s/(\d);/$1,;/g; # forgottn comma before ;
 		s/\s//g;	#get rid of space
 		s/,,+/,/g;	#get rid of duplicate commas
 		$string .= $_
 	}
 	return $string;
 }
 
 sub finish{
 	my $message = shift;
 	print "$message \nthe end. let's print output:\n";
 	output ();
 	die
 
 }
 
 sub get_chromasome{
 	my $Genome = shift;#string
 	my @C = 
 	 map {
 	 [
 	 
 	 map{
 	 [
 	 /(-?\d+\.?\d*),/g	# the parens excise the commas
 	 
 	 ]
 	 }
 	 /-?\d+\.?\d*,-?\d+\.?\d*,-?\d+\.?\d*,/g
 	 ]
 	 
 	} split /;/, $Genome;
 	
 	for (@C){
 		if ($#$_ > 1) {
 			unless ($#$_ % 2){	
 				splice @$_, -1, 1
 			}
 	
 		}
 	
 	
 	}
 	@C # @C[gene[codon[base,base,base]]]
 }
 
 
 sub call{
 	my $ptr = shift;
 	my $i = shift;
 	my $alt_ptr = -1;
 	for (1 .. $i){
 
 		deathcount(); #count down to process death
 		my @g = Access_C("gene",$ptr);
 		my $call = shift $g[0]; #1st base of 1st codon
 		my $modcall = $call % 2;
 		($call % 2)?($alt_ptr = MOV(\@g,$ptr)):(MOD(\@g));
 		(return $alt_ptr) if ($alt_ptr >= 0);
 		($ptr == Access_C("size")) ? $ptr = 0 : $ptr++;#circular chromasome
 	}
 	
 	return $alt_ptr;
 	#if alt_ptr >= 0
 	#alt_ptr is used to reset ptr permanently.
 	#the recursive calls to call() are unwound in favor of alt_ptr
 }
 
 sub MOD{
 	my $g = shift; #gene
 	my ($loc,$reftype) = @{(shift @$g)};
 	my @ops = qw/+ - * \/ ** %/;
 	$loc = abs($loc);
 	$loc = Access_R("read",$loc) if ($reftype%2);
 	$loc = 0 unless $loc;
 	Access_R("write",$loc,expression_processor($g,\@ops));
 }
 
 sub MOV{
 	my $g = shift;
 	my $ptr = shift; #needed to check for infi-loop
 	my @ops = qw/== > < >= <= != and or not xor/;
 	my ($loc,$i) = @{(shift @$g)};
 	$loc = abs $loc;
 	$loc = 0 if $loc > Access_C("size");
 	$i = abs $i;
 	
 	if (expression_processor($g, \@ops)){
 		(finish ("pointer collision")) if ($loc == $ptr);
 		return $loc unless $i;
 		return call($loc,$i);
 	}
 	return -1
 
 }
 
 sub filter_v_or_o{
 	my ($v,$o,$total_bits,$orig) = @_;
 
 	(return 0) if ($v-1 <= $o);
 	(return 1) if ($v >= ($total_bits / 2));
 	return ($orig % 2)
 
 
 }
 
 sub expression_processor{ #build a polish notation expression from triplets.
 	
 	my $g = shift; #gene
 	my $ops = shift; #operators
 	my ($v,$o) = 0; #init counting vars
 	my $total_bits = $#$g;
 	my @expression;
 	return 0 unless @$g;
 	while (@$g){
 		my ($v_or_o, $data, $ref_type) = @{(shift @$g)};
 		$v_or_o = filter_v_or_o($v,$o,$total_bits,$v_or_o);
 		$ref_type = ($ref_type % 3);
 		($data = Access_R("read",$data)) if ($ref_type == 1);
 		($data = Access_R("read",Access_R("read",$data))) if ($ref_type == 2);
 		$data = 0 unless $data;
 		($data = $ops->[$data % ($#$ops +1)]) if ($v_or_o);
 		($v_or_o)?($o++):($v++);
 		unshift @expression, $data;
 	}
 	return solve(\@expression)
 }
 
 sub solve{
 	my $exp = shift;
 	my $a = shift @$exp;
 	($a=~/\d/)?
 	 (return $a) :
 	 ($a = eval(solve($exp) . " $a " . solve($exp)));
 
 	(finish("termination with n/0\n")) if ($@=~ /Illegal/);
 	return $a;
 }
Category:Languages
Category:Implemented