Скала, 3123 2844 2626 2,540 байт
В дополнение к ограничениям, изложенным в этом вопросе, этот переводчик был написан так, чтобы как можно больше склоняться к принципам FP. В частности:
- Только неизменные структуры
- Все функции чистые
Это было выполнено, за исключением четырех строк кода, которые управляют основным циклом интерпретатора. Неизменяемые структуры было очень трудно использовать здесь, потому что состояние регистров управляет потоком управления цикла (в частности, двумя операторами GOTO). Я все еще думаю о том, как преобразовать его, чтобы использовать чистые и неизменные структуры, но это не имеет отношения к проблеме гольфа в коде.
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}
Я опубликую версию без Golf на Github и предоставлю ссылку, когда я это сделаю. Пока я выложу оригинальную версию здесь:
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()
}
~
и~
в ваших командах "Roll Registers"? У вас есть пример программы, которую люди могут использовать для тестирования?