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.

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
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; }
 * 1) !/usr/bin/perl
 * 2) use warnings;