読者です 読者をやめる 読者になる 読者になる

( ꒪⌓꒪) ゆるよろ日記

( ゚∀゚)o彡°オパーイ!オパーイ! ( ;゚皿゚)ノシΣ フィンギィィーーッ!!!

プログラミング言語「ほむほむ」

scala ネタ

なんか、極めると「ほむほむ」だけで会話できるみたいですね?


俺はまだそこまでの域には至ってないんですが、「ほむほむ」だけでプログラミングできたらステキですよね?

そこで、ちょっと草植えときますね型言語 Grassを元にして以前作ったプログラミング言語「天使ちゃんマジ天使」とか 「ブブゼラ」をベースに、 またまたネタ言語を作りました。


Grassの文法と異なる点は以下のとおり。

  • wがほむ
  • スペース・タブにはさまれた"ほむ"がW
  • vは改行


wを出力するプログラム:

ほむ ほむほむ ほむほむほむほむ


xを出力するプログラム:

ほむ ほむほむほむ ほむほむほむほむ ほむほむほむ ほむ


"Hello, world!"を出力するプログラム

ほむ
ほむ ほむ ほむほむほむほむ ほむ ほむほむほむほむほむほむ ほむほむほむほむほむ ほむ ほむほむほむほむほむ ほむほむほむほむ
ほむほむほむほむ ほむほむほむ ほむほむ ほむ ほむほむ ほむほむほむほむほむほむ ほむほむほむほむ ほむ ほむほむ
ほむ ほむほむ ほむ ほむ ほむほむ
ほむほむ ほむほむ ほむ
ほむ ほむほむほむ ほむほむ ほむほむほむほむほむ ほむほむほむ ほむ ほむほむ ほむほむほむほむほむほむ ほむ ほむほむほむほむほむほむほむ ほむ ほむほむほむほむ ほむ ほむほむほむほむほむ ほむ ほむほむほむほむほむほむ ほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむほむほむほむほむほむほむほむ ほむ ほむ ほむ ほむ ほむほむほむ ほむほむ ほむほむほむほむ ほむほむほむほむほむほむほむ ほむほむほむほむほむ ほむほむほむほむほむほむほむ ほむほむほむほむほむほむ ほむほむほむほむほむほむほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむ ほむほむほむほむほむほむ ほむほむ ほむほむほむほむほむほむ ほむほむほむ ほむほむほむほむほむほむ ほむほむほむほむほむほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむ ほむほむほむほむほむほむほむほむほむほむ ほむほむ ほむほむほむほむ ほむほむほむ ほむほむほむほむ ほむほむほむほむ ほむ ほむほむほむほむほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむほむほむほむほむほむほむほむほむほむほむ ほむ ほむ ほむほむほむ ほむほむ ほむ ほむほむほむ ほむ ほむほむほむほむ ほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむ ほむほむほむほむほむほむほむほむほむほむほむ ほむほむ ほむほむほむほむほむほむほむほむほむほむほむ ほむほむほむ ほむほむほむほむほむほむほむ ほむほむほむほむ ほむ ほむほむほむほむほむ ほむほむほむほむほむほむほむほむ ほむほむほむほむほむほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむほむほむほむほむほむほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむほむほむほむほむほむほむほむほむ ほむほむほむほむほむほむほむほむ ほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむほむほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむほむほむほむ ほむほむほむほむほむほむほむほむ ほむほむほむほむほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむほむほむほむほむほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむ


ソースコードです。

import java.io.File
import scala.io.Source
import scala.util.matching.Regex
import scala.util.parsing.combinator._
import scala.util.parsing.input.{Position, NoPosition}

sealed abstract class Insn extends ( CED => CED ){
  val pos:Position
}
case class App( m:Int, n:Int, pos:Position ) extends Insn{
  override def apply( ced:CED ) = ced.e( m - 1 )( ced.e( n - 1 ), ced )
  override def toString = "App(%s,%s)".format(m, n)
}

case class Abs( m:Int, body:List[App] ,pos:Position ) extends Insn{
  override def apply( ced:CED ) =
    if( m == 1) CED( ced.c, Fn( body, ced.e ) :: ced.e, ced.d )
    else        CED( ced.c, Fn( Abs( m - 1, body, pos ) :: Nil, ced.e ) :: ced.e, ced.d )

  override def toString = "Abs(%s)".format(m)
}

case class CED( c:List[Insn], e:List[Value], d:List[CE] )
case class CE( c:List[Insn], e:List[Value] )

class GrassRuntime( val insn:List[Insn], val source:String){

  val e0 = Out :: Succ :: CharFn('w') :: In :: Nil
  val d0 = CE(Nil, Nil) :: CE( App(1, 1, NoPosition) :: Nil, Nil) :: Nil

  def run:Unit = {
    var c = eval( CED( insn, e0, d0 ) )
    while( c != None ){
      val Some(m) = c
      c = eval( m )
    }
  }

  def eval( ced:CED ) = ced.c match {
    case Nil => ced.d match {
      case Nil => None
      case x::xs  => Some( CED( x.c, ced.e.head:: x.e , xs ))
    }
    case code :: remains => Some( code( CED( remains, ced.e, ced.d )) )
  }
}

abstract class Value extends ( (Value, CED) => CED )

case class Fn(code : List[Insn], env : List[Value]) extends Value {
  override def apply( v:Value, ced:CED ) = CED( code , v :: env, CE( ced.c, ced.e ) :: ced.d )
  override def toString = "Fn"
}

case class CharFn(char : Char) extends Value {
  val ChurchTrue  = Fn( Abs( 1, App( 3, 2, NoPosition ) :: Nil, NoPosition ) :: Nil, Fn( Nil, Nil ) :: Nil )
  val ChurchFalse = Fn( Abs( 1, Nil,  NoPosition) :: Nil,  Nil)

  override def apply( v:Value, ced:CED ) = v match {
    case CharFn( c ) => CED( ced.c, ced.e ::: ( if( char == c ) ChurchTrue else ChurchFalse ) :: Nil, ced.d )
    case _ => throw new Exception("eval error value is not CharFn")
  }
  override def toString = "CharFn(%s, %s)".format( char , char.toInt)
}

object Succ extends Value {
  override def apply( v:Value, ced:CED ) = v match {
    case CharFn( c ) =>
      val char = ( (c + 1) % 256 ).toChar
      CED( ced.c, CharFn( char ) :: ced.e, ced.d )
    case _ => throw new Exception("eval error value is not CharFn")
  }
  override def toString = "Succ"
}

object Out extends Value {
  override def apply( v:Value, ced:CED ) = v match {
    case CharFn( c ) =>
      print(c)
      CED( ced.c, v :: ced.e, ced.d )
    case _ => throw new Exception("eval error value is not CharFn")
  }
  override def toString = "Out"
}
object In extends Value {
  override def apply( v:Value, ced:CED ) ={
    val c = readChar
    CED( ced.c, CharFn( c ) :: ced.e, ced.d )
  }
  override def toString = "In"
}

object Home2LangParser extends RegexParsers{
  import scala.util.parsing.input.CharSequenceReader._
  override def skipWhitespace = false

  val wToken = "ほむ".r
  val sep = """[ \t]""".r
  val fToken = rep1( sep ) ~> rep1(wToken) <~ rep1( sep ) ^^ { x => "W" * x.length }
  val vToken = """\n""".r

  def p(s:String):Parser[String] = s

  def wrap[A](p: Parser[A]) = Parser{r => Success(r.pos,  r)} ~ p

  def w :Parser[String] = rep( comment ) ~> wToken <~ rep( comment )
  def f :Parser[String] = rep( comment ) ~> fToken <~ rep( comment )
  def v :Parser[String] = rep( comment ) ~> vToken <~ rep( comment )
  val any :Parser[String] = elem("", _ != EofCh) ^^ { _.toString }

  def token   :Parser[String] = wToken ||| fToken ||| vToken
  def comment :Parser[String] = not( token ) <~ any ^^ ( (Unit) => "" )

  def app :Parser[App] = wrap(  f  ~ rep1( w ) ) ^^
    { case ~( p, x ~ y ) => App( x.size, y.size, p ) }

  def abs :Parser[Abs] = wrap( rep1( w ) ~ rep( app ) ~ rep(v) ) ^^
    { case ~( p, ws ~ body ~ vs ) => Abs( ws.size, body, p ) }

  def prog :Parser[List[Insn]] = rep( abs ) ~ rep( app ) ~ rep( v ) ^^
    { case a ~ p ~ v => a ::: p  }

  def parse( s:String ):Option[GrassRuntime] = parseAll( prog , s ) match {
    case Success( insn, _ )  =>  Some( new GrassRuntime( insn, s ) )
    case Failure( msg, _ ) => { println( msg ); None }
    case Error( msg, _ )   => { println( msg ); None }
  }
  def run( s:String ) = parse( s ) foreach{ _.run }

  def test( s:String ) = parse( s ) foreach{ r => dump( r.insn, 0 ) }

  def dump( x:List[Insn] , n:Int ):Unit = {
    val sp = (for( i <- 0 to n ) yield{ "  " } ).mkString
    x.foreach{ o => o match {
      case Abs( i,b,_ ) => {
        println( sp + "Abs( " + i + ")")
        dump( b , n + 1 )
      }
      case App( i,j,_) => println( sp + "App( " + i + ", " + j + " )")
    }}
  }
}

class GrassParser(
  wTokens:List[String],
  fTokens:List[String],
  vTokens:List[String]
)extends RegexParsers{
  import scala.util.parsing.input.CharSequenceReader._
  override def skipWhitespace = false

  def p(s:String):Parser[String] = s
  def make( tk:List[String] ) = ( p( tk.head ) /: tk.tail ){ _ ||| p( _ ) }

  def wrap[A](p: Parser[A]) = Parser{r => Success(r.pos,  r)} ~ p

  def w :Parser[String] = rep( comment ) ~> ( make( wTokens ) ) <~ rep( comment )
  def f :Parser[String] = rep( comment ) ~> ( make( fTokens ) ) <~ rep( comment )
  def v :Parser[String] = rep( comment ) ~> ( make( vTokens ) ) <~ rep( comment )
  val any :Parser[String] = elem("", _ != EofCh) ^^ { _.toString }

  def token   :Parser[String] = make( wTokens ) ||| make( fTokens ) ||| make( vTokens )
  def comment :Parser[String] = not( token ) <~ any ^^ ( (Unit) => "" )

  def app :Parser[App] = wrap( rep1( f ) ~ rep1( w ) ) ^^
    { case ~( p, x ~ y ) => App( x.size, y.size, p ) }

  def abs :Parser[Abs] = wrap( rep1( w ) ~ rep( app ) ~ rep(v) ) ^^
    { case ~( p, ws ~ body ~ vs ) => Abs( ws.size, body, p ) }

  def prog :Parser[List[Insn]] = rep( abs ) ~ rep( app ) ~ rep( v ) ^^
    { case a ~ p ~ v => a ::: p  }

  def parse( s:String ):Option[GrassRuntime] = parseAll( prog , s ) match {
    case Success( insn, _ )  =>  Some( new GrassRuntime( insn, s ) )
    case Failure( msg, _ ) => { println( msg ); None }
    case Error( msg, _ )   => { println( msg ); None }
  }
  def run( s:String ) = parse( s ) foreach{ _.run }

  def test( s:String ) = parse( s ) foreach{ r => dump( r.insn, 0 ) }

  def dump( x:List[Insn] , n:Int ):Unit = {
    val sp = (for( i <- 0 to n ) yield{ "  " } ).mkString
    x.foreach{ o => o match {
      case Abs( i,b,_ ) => {
        println( sp + "Abs( " + i + ")")
        dump( b , n + 1 )
      }
      case App( i,j,_) => println( sp + "App( " + i + ", " + j + " )")
    }}
  }
}

object Main{
  def main(args:Array[String]) = {

    println()
    println( "プログラミング言語 ほむほむ" )

    println("-" * 80)
    println( "print w" )
    val printW = "ほむ ほむほむ ほむほむほむほむ"

    println( "source code:")
    println( "  %s" format printW)
    println()
    println( "AST:")
    Home2LangParser.test( printW )
    println()
    println( "Result:")
    Home2LangParser.run( printW )
    println()

    println("-" * 80)
    println( "print x" )
    val printX ="ほむ ほむほむほむ ほむほむほむほむ ほむほむほむ ほむ"

    println( "source code:")
    println( "  %s" format printX)
    println()
    println( "AST:")
    Home2LangParser.test( printX )
    println()
    println( "Result:")
    Home2LangParser.run( printX )
    println()

    println("-" * 80)
    println( "Hello World" )
    val hw = Source.fromFile(new File( "./home2lang.grass" )).mkString

    println( "source code:")
    println( "  %s" format hw)
    // println()
    // println( "AST:")
    // Home2LangParser.test( printX )
    println()
    println( "Result:")
    Home2LangParser.run( hw)
    println()
    println("-" * 80)
  }
}

https://gist.github.com/1001863


実行結果

$ scala Main 

プログラミング言語 ほむほむ
--------------------------------------------------------------------------------
print w
source code:
  ほむ ほむほむ ほむほむほむほむ

AST:
  Abs( 1)
    App( 2, 4 )

Result:
w
--------------------------------------------------------------------------------
print x
source code:
  ほむ ほむほむほむ ほむほむほむほむ ほむほむほむ ほむ

AST:
  Abs( 1)
    App( 3, 4 )
    App( 3, 1 )

Result:
x
--------------------------------------------------------------------------------
Hello World
source code:
  ほむ
ほむ ほむ ほむほむほむほむ ほむ ほむほむほむほむほむほむ ほむほむほむほむほむ ほむ ほむほむほむほむほむ ほむほむほむほむ
ほむほむほむほむ ほむほむほむ ほむほむ ほむ ほむほむ ほむほむほむほむほむほむ ほむほむほむほむ ほむ ほむほむ
ほむ ほむほむ ほむ ほむ ほむほむ
ほむほむ ほむほむ ほむ
ほむ ほむほむほむ ほむほむ ほむほむほむほむほむ ほむほむほむ ほむ ほむほむ ほむほむほむほむほむほむ ほむ ほむほむほむほむほむほむほむ ほむ ほむほむほむほむ ほむ ほむほむほむほむほむ ほむ ほむほむほむほむほむほむ ほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむほむほむほむほむほむほむほむ ほむ ほむ ほむ ほむ ほむほむほむ ほむほむ ほむほむほむほむ ほむほむほむほむほむほむほむ ほむほむほむほむほむ ほむほむほむほむほむほむほむ ほむほむほむほむほむほむ ほむほむほむほむほむほむほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむ ほむほむほむほむほむほむ ほむほむ ほむほむほむほむほむほむ ほむほむほむ ほむほむほむほむほむほむ ほむほむほむほむほむほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむ ほむほむほむほむほむほむほむほむほむほむ ほむほむ ほむほむほむほむ ほむほむほむ ほむほむほむほむ ほむほむほむほむ ほむ ほむほむほむほむほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむほむほむほむほむほむほむほむほむほむほむ ほむ ほむ ほむほむほむ ほむほむ ほむ ほむほむほむ ほむ ほむほむほむほむ ほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむ ほむほむほむほむほむほむほむほむほむほむほむ ほむほむ ほむほむほむほむほむほむほむほむほむほむほむ ほむほむほむ ほむほむほむほむほむほむほむ ほむほむほむほむ ほむ ほむほむほむほむほむ ほむほむほむほむほむほむほむほむ ほむほむほむほむほむほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむほむほむほむほむほむほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむほむほむほむほむほむほむほむほむ ほむほむほむほむほむほむほむほむ ほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむほむほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむほむほむほむ ほむほむほむほむほむほむほむほむ ほむほむほむほむほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむ ほむほむほむほむほむほむ ほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむほむ


Result:
Hello, world!
--------------------------------------------------------------------------------


ほむほむ