Scala, 3.123 2.844 2.626 2.540 bytes
Además de las limitaciones esbozadas en la pregunta, este intérprete fue escrito para inclinarse lo más posible hacia los principios de FP. Específicamente:
- Solo estructuras inmutables
- Todas las funciones son puras
Esto se logró, con la excepción de las cuatro líneas de código que impulsan el bucle principal del intérprete. Las estructuras inmutables eran muy difíciles de utilizar aquí porque el estado de los registros impulsa el flujo de control del bucle (específicamente las dos declaraciones GOTO). Todavía estoy pensando en cómo convertirlo para usar estructuras puras e inmutables, pero eso es irrelevante para el desafío del código de golf.
import java.util.Scanner
import scala.util._
object Z extends App{type K=Long
type G=List[K]
type I=String
type E=Boolean
val(f,t,ф,д,б)=(false,true,(z:G)=>z(0),(z:G)=>z.tail,(q:K,w:K,e:K)=>q::w::e::Nil)
trait O{def h(z:I)=BigInt(z,16).longValue()}
trait S extends O
trait B extends S with P{def apply(r:G):E}
trait R extends O{def a(r:G):G}
trait T extends O{def a(r:G,s:G):(G,G)}
trait P{def p:I}
case class L(p:I)extends S with P
case class U(p:I)extends B{def apply(r:G):E=r(2)==0}
case class J(p:I)extends B{def apply(r:G):E=r(2)!=0}
case class M(p:I)extends R with P{def a(r:G):G=h(p)::д(r)}
class Y extends R{def a(r:G):G=б(r(0),r(0)%r(1),r(0)/r(1))}
case class Q(p:I)extends T with P{def r(q:G,i:Int):G={val s=д(q):+ф(q)
if(i>0)r(s,i-1)else s}
def a(e:G,t:G)=e->r(t,Try(p.toInt).getOrElse(1))}
case class N(p:I)extends T with P{def r(q:G,i:Int):G={
val s=q.last::q.iterator.sliding(2).map(_(0)).toList
if(i>0)r(s,i-1)else s}
def a(e:G,t:G)=e->r(t,Try(p.toInt).getOrElse(1))}
case class A(n:Array[O], l:Map[I,Int]){def e={var (r,t,x)=(List(0L,0,0),List[K](),0)
while(x<n.length){x=n(x)match{case i:B=>if(i(r))l(i.p)else x+1
case i:R=>r=i.a(r);x+1
case i:T=>val(y,u)=i.a(r,t);r=y;t=u;x+1
case _=>x+1}}}}
object A{def apply(i:Seq[O]):A={A(n=i.toArray,l=Map(i.zipWithIndex.flatMap{case(e:L,i)=>Some(e.p->i)
case _=>None}.toList:_*))}}
object X{def v(y:(Char, Option[Z.I]))=y._2.getOrElse("");val F=Map('x->new R{def a(t:G)=б(t(1),t(0),t(2))},'|'->new R{def a(r:G)=h(new Scanner(System.in).next("[0-9a-fA-F]+"))::д(r)},'!'->new R{def a(r:G)=(System.in.read match{case i if i== -1=>0;case i=>i})::д(r)},'%'->new R{def a(r:G)={print(Integer.toHexString(r(2).toInt));r}},'$'->new R{def a(r:G)={print(r(2).toChar);r}},'~'->new R{def a(r:G)=д(r):+ф(r)},'='->new R{def a(r:G)=б(r(2),r(0),r(1))},'?'->new T{def a(r:G,s:G)=r->List()},'>'->new T{def a(r:G,s:G)=r->(r(2)::s)},'{'->new T{def a(r:G, s:G)=(ф(s)::д(r))->д(s)},'+'->new R{def a(r:G)=б(r(0),r(1),r(0)+r(1))},'-'->new R{def a(r:G)=б(r(0),r(1),r(0)-r(1))},'*'->new R{def a(r:G)=б(r(0),r(1),r(0)*r(1))},'/'->new Y);def apply(i:I)={(i+" ").foldLeft((List[(Char,Option[I])](),None:Option[Char],"",f))((a,n)=>{n match{case i if i==':'=>if(a._4)(a._1:+(a._2.get->Some(a._3)),None,"",f)else(a._1,a._2,"",t)
case i if a._4=>(a._1,a._2,a._3+i,t)
case i if a._2.isEmpty=>(a._1,Some(i),"",f)
case i=>(a._1:+(a._2.get->None),Some(i),"",f)}})._1.map(x=>x._1 match{
case'<'=>M(v(x))
case'}'=>L(v(x))
case'^'=>J(v(x))
case'#'=>U(v(x))
case'@'=>Q(v(x))
case'&'=>N(v(x))
case c=>F(c)})}}
A(X(args(0))).e}
Publicaré la versión no protegida en Github y proporcionaré un enlace cuando lo haga. Por ahora, publicaré la versión original aquí:
import java.util.Scanner
import scala.util.Try
trait Operation {
def hexToLong(hex:String):Long = BigInt(hex, 16).longValue()
}
trait Parameter {
def param:String
}
trait RegisterOperation extends Operation { def apply(registers:List[Long]):List[Long] }
trait StackOperation extends Operation { def apply(registers:List[Long], stack:List[Long]):(List[Long], List[Long]) }
trait SpecialOperation extends Operation
trait SpecialRegisterOperation extends SpecialOperation with Parameter { def apply(registers:List[Long]):Boolean }
class Move(val param:String) extends RegisterOperation with Parameter { override def apply(registers:List[Long]): List[Long] = hexToLong(param) :: registers.tail }
class Swap extends RegisterOperation { override def apply(registers:List[Long]): List[Long] = registers(1) :: registers(0) :: registers(2) :: Nil }
class InputNumber extends RegisterOperation { override def apply(registers:List[Long]): List[Long] = hexToLong(new Scanner(System.in).next("[0-9a-fA-F]+")) :: registers.tail }
class InputAscii extends RegisterOperation {
override def apply(registers:List[Long]): List[Long] = (System.in.read() match {
case i if i == -1 => 0
case i => i}) :: registers.tail }
class PrintNumber extends RegisterOperation { override def apply(registers:List[Long]): List[Long] = { print(Integer.toHexString(registers(2).toInt)); registers } }
class PrintAscii extends RegisterOperation { override def apply(registers:List[Long]): List[Long] = { print(registers(2).toChar); registers } }
class RegisterRollLeft extends RegisterOperation { override def apply(registers:List[Long]): List[Long] = registers.tail :+ registers.head }
class RegisterRollRight extends RegisterOperation { override def apply(registers:List[Long]): List[Long] = registers(2) :: registers(0) :: registers(1) :: Nil }
class Add extends RegisterOperation { override def apply(registers:List[Long]): List[Long] = registers(0) :: registers(1) :: (registers(0) + registers(1)) :: Nil }
class Subtract extends RegisterOperation { override def apply(registers:List[Long]): List[Long] = registers(0) :: registers(1) :: (registers(0) - registers(1)) :: Nil }
class Multiply extends RegisterOperation { override def apply(registers:List[Long]): List[Long] = registers(0) :: registers(1) :: (registers(0) * registers(1)) :: Nil }
class Divide extends RegisterOperation { override def apply(registers:List[Long]): List[Long] = registers(0) :: (registers(0) % registers(1)) :: (registers(0) / registers(1)) :: Nil }
class Clear extends StackOperation { override def apply(registers:List[Long], stack:List[Long]) = registers -> List() }
class Enqueue extends StackOperation { override def apply(registers:List[Long], stack:List[Long]) = registers -> (registers(2) :: stack) }
class Dequeue extends StackOperation { override def apply(registers:List[Long], stack:List[Long]) = (stack.head :: registers.tail) -> stack.tail }
class QueueRollLeft(val param:String) extends StackOperation with Parameter {
def roll(stack:List[Long], i:Int):List[Long] = {
val s = stack.tail :+ stack.head
if (i > 0) roll(s, i-1) else s
}
override def apply(registers:List[Long], stack:List[Long]) = registers -> roll(stack, Try(param.toInt).toOption.getOrElse(1))
}
class QueueRollRight(val param:String) extends StackOperation with Parameter {
def roll(stack:List[Long], i:Int):List[Long] = {
val s = stack.last :: stack.iterator.sliding(2).map(_.head).toList
if (i > 0) roll(s, i-1) else s
}
override def apply(registers:List[Long], stack:List[Long]) = registers -> roll(stack, Try(param.toInt).toOption.getOrElse(1))
}
class SetLabel(val param:String) extends SpecialOperation with Parameter
class JumpLabelIfZero(val param:String) extends SpecialRegisterOperation { override def apply(registers: List[Long]): Boolean = registers(2) == 0 }
class JumpLabelIfNotZero(val param:String) extends SpecialRegisterOperation { override def apply(registers: List[Long]): Boolean = registers(2) != 0 }
class Script(val instructions:Array[Operation],
val labels:Map[String, Int]) {
def execute() = {
var registers = List[Long](0, 0, 0)
var stack = List[Long]()
var idx = 0;
while(idx < instructions.length) {
idx = instructions(idx) match {
case i: SpecialRegisterOperation => if(i(registers)) labels(i.param) else idx + 1
case i: RegisterOperation => { registers = i(registers); idx + 1 }
case i: StackOperation => { val (zregisters, zstack) = i(registers, stack); registers = zregisters; stack = zstack; idx + 1 }
case _ => idx + 1
}
}
}
}
object Script {
def apply(instructions: Seq[Operation]):Script = {
new Script(instructions = instructions.toArray, labels = Map(instructions.zipWithIndex.flatMap {
case (e:SetLabel, i) => Some(e.param -> i)
case _ => None
}.toList:_*))
}
}
object Parser {
def apply(input:String): Seq[Operation] = {
case class Accumulator(val list: List[(Char, Option[String])] = List(), val char:Option[Char] = None, val str:String = "", val parsingVar:Boolean = false)
(input + " ").foldLeft(Accumulator())((acc, next) => {
next match {
case i if i == ':' => if(acc.parsingVar) Accumulator(acc.list :+ (acc.char.get -> Some(acc.str)), None, "", false) else Accumulator(acc.list, acc.char, "", true)
case i if acc.parsingVar => Accumulator(acc.list, acc.char, acc.str + i, true)
case i if !acc.char.isDefined => Accumulator(acc.list, Some(i), "", false)
case i => Accumulator(acc.list :+ (acc.char.get -> None), Some(i), "", false)
}
}).list.map(x => x._1 match {
case '<' => new Move(x._2.getOrElse(""))
case 'x' => new Swap
case '}' => new SetLabel(x._2.getOrElse(""))
case '|' => new InputNumber
case '!' => new InputAscii
case '%' => new PrintNumber
case '$' => new PrintAscii
case '~' => new RegisterRollLeft
case '=' => new RegisterRollRight
case '^' => new JumpLabelIfNotZero(x._2.getOrElse(""))
case '#' => new JumpLabelIfZero(x._2.getOrElse(""))
case '?' => new Clear
case '>' => new Enqueue
case '{' => new Dequeue
case '@' => new QueueRollLeft(x._2.getOrElse(""))
case '&' => new QueueRollRight(x._2.getOrElse(""))
case '+' => new Add
case '-' => new Subtract
case '*' => new Multiply
case '/' => new Divide
})
}
}
object Go extends App {
Script(Parser(args(0))).execute()
}
~
y~
en sus comandos "roll registers"? ¿Tiene un programa de ejemplo que la gente pueda usar para probar?