User:Ian/LARSA Interpreter

From Esolang
Jump to navigation Jump to search

My LARSA interpreter in Perl

our %DATA, $datstr="", $cmdstr, $state="", @i;
our $ivalence, $ovalence, $var;
@{$DATA{'0'}}=@{$DATA{'1'}}=(0,1);

sub do_step {
	$_=shift;
	if (/^[01]$/) { $datstr.=$_;
	} elsif (length($datstr)<($_[0]||1)&&defined($_[5])) {
		$cmdstr=$_[5].$cmdstr; $state=$_[6]//$state;
	} else {
		$state=substr($_[4], ((1<<$_[3])-1-oct '0b' . substr $datstr, -$_[3], $_[3]), 1) if defined $_[4];
		$cmdstr=(substr $_[2], ((1<<$_[0])-1-oct '0b' . substr $datstr, -$_[0], $_[0], '')*$_[1], $_[1]).$cmdstr;
	}
}

sub process {
	my $_;
	while (length $cmdstr) {
		$_=substr $cmdstr, 0, 1, '';
		$_.=$state if defined $DATA{$_.$state};
		do_step $_, @{$DATA{$_}};
		print $state,'@',$datstr,'$',$cmdstr,"\n"; #stack trace
	}
}

while (<>) {
	while (/\\$/) {chomp; chop; $_.=<>}
	next if /^\$[01]=[^=]/; #Comment
	if (/^\$(..?)=(\d+)?(?:(?:@([^|]?))?\|(.*?))?(?:,(\d+)?(?:,(.*?)(?:(?:,(\d+))?,(.*))?)?)?$/) { #Assignment
		@i=@{$DATA{$1}}=($2//0,$5//int(length($6)/(1<<$2))//0,$6,$7//$2//0,$8,$4,$3);
		print $1,' (',$i[0],'--',$i[1],')=',$i[2],"\t@(",$i[3],')',
			defined($i[4])?'!':'','=',$i[4],defined($i[5])?"\t|".
			(defined($i[6])?'@!='.$i[6]:'').'|':'',$i[5],"\n";
	} elsif (/^#(.(.)?)?(?:,(\d+))?=(.*)$/) { #Table Composition
		my $var = $1;
		chomp $4; $cmdbak=$4; my $istate=$2;
		my @output=(),@ostate=(),$output="";
		my $datbak=$datstr, my $statebak=$state;
		my @vtrace=(), $ovalence=0;
		for (split //, $cmdbak) {
			$vtrace[++$#vtrace]=$DATA{$_}->[1]-$DATA{$_}->[0]+$vtrace[-1]//-1;
			$ovalence=$vtrace[-1]>0?$vtrace[-1]:$DATA{$_}->[1]>$ovalence?$DATA{$_}->[1]:$ovalence;
		}
		{local $,=", ";print @vtrace,"\n"};
		$ivalence = -(sort {$a <=> $b} @vtrace)[0]+1;
		$ivalence = 0 if $ivalence<0;
		$ivalence = $3 if defined $3;
		print 'Examining function: valence (',$ivalence,',',$ovalence,")...\n";
		for my $i (reverse 0..(1<<$ivalence)-1) {
			print 'Processing given ',$i," on the stack...\n";
			$datstr=substr sprintf('%0'.$ivalence.'b', $i), 0, $ivalence;
			($_, $state, $cmdstr)=($i, $istate, $cmdbak);
			process;
			print $var,"(",$i,"):(",$ivalence,",",length $datstr,")@",$state,"=",$datstr,"\n";
			push @output, $datstr;
			push @ostate, $state;
		}
		($datstr, $state)=($datbak, $statebak);
		$ovalence=(sort {$b <=> $a} map {length $_} @output)[0];
		$output=join '', map {sprintf '%'.$ovalence.'s',$_} @output;
		$istate=join '', map {$_ eq ''?"\x7F":$_} @ostate;
		$istate =~ s/\x7F*$//;
		undef $istate unless length $istate;
		print "*",$var,"=",$ivalence,",",$ovalence,",",$output,$istate?(",".$istate):'',"\n";
		@{$DATA{$var}}=($ivalence,$ovalence,$output,$ivalence,$istate);
	} else {chomp; $cmdstr=$_; process} #Evaluation
}

About the Interpreter

In addition to accepting LARSA assignments and evaluations, it also has a "composition" or "currying" feature (#[var][state]=[...]) that takes a group of commands and optionally assigns them to a new command. For example, if the stack was pqrs, #a=&|> would do p>(q|(r&s)) to the number (note the RPN ordering). It accepts an input bit count, so, if there was a "+" command that incremented the stack as a single binary number, #p,8=+++++ will generate a command p for all values from 0 to 255 that adds 5 to the input. It also does constant folding, so #o=1| would generate a table that takes one value and replaces it with 1 (unary tautology). If you don't want to assign it to a new command, use #=[...] to just test it and output a table. If a state is given, that will determine the initial state for the commands. The composition assignment, like a regular assignment, does not interfere with the current stack or state.