Hatena::ブログ(Diary)

氷雨係長の窓際日記

2016-05-27 Fri プログラミング言語「めうめう」

プログラミング言語「めうめう」

プログラミング言語ほむほむ」のほむをめうに置換すればプログラミング言語「めうめう」ができるのではないか?という発想で

http://yuroyoro.hatenablog.com/entry/20110601/1306908421

https://gist.github.com/yuroyoro/1001863

こちらの記事の「ほむ」を「めう」に置換しただけのソースコードを貼ったので誰か実行してください。

内容は全く理解してないけど、val wToken = "めう".r 辺りがめうをgrassのwに読みかえてるんだろうな。

たぶん"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)
  }
}

トラックバック - http://d.hatena.ne.jp/hisam_k/20160527

2014-09-03 Wed 職務経歴書

再就職の都合で職務経歴書更新を重ねてるんだけど、仕事の切り替わり時期を調べる為にブログtwitterを読み返してて、何だか本当に色々あった人生なんだなーと再確認したり。偉人になって自伝にまとめたい。

トラックバック - http://d.hatena.ne.jp/hisam_k/20140903

2014-07-19 Sat 戦闘国家改PC版メモ

起動の仕方

d3drm.dllダウンロードしてC:\Windows\SysWOW64に入れる

装甲歩兵の出し方

Ctrl+Alt+Shiftを押しながら生産

トラックバック - http://d.hatena.ne.jp/hisam_k/20140719

2014-05-12 Mon デんパちゃん

デんパちゃん

部屋の掃除で発掘した同人誌っちゅーか絵本?なんだけどいいんだわこれが

コミケ運命的に出会った同人誌はその場で買わないと、一般流通の本と違って再版しない中古で買えないどころか、サークル消滅してたり

トチュウGETだぜ!とか、フリキュラマシーンとか、今はどうなってるんじゃろか

トラックバック - http://d.hatena.ne.jp/hisam_k/20140512

2014-04-29 Tue 台湾

台湾に行ってきた。

メイド喫茶とか天燈とか行脚とか、気が向いたら書きます

トラックバック - http://d.hatena.ne.jp/hisam_k/20140429

2013-09-23 Mon twitterガジェット

twitterガジェットが表示されなくなっていたので、更新しました。

プレビューだと表示されないってのがトラップだった。

トラックバック - http://d.hatena.ne.jp/hisam_k/20130923

2013-02-11 Mon ダイアリーとかあったな

1年以上も放置してたみたいだ。twitterガジェットが無ければ生存を疑われるレベル。すまん。

はてなダイアリーがあるのにはてなブログを作ったらしい。

初期流入を考えたらアリだと思う。

ブログという単語メジャーじゃなかった時代に付けた名前だから仕方ないけど、早々にサービス名をはてなブログにしておけばこんな事にはならなかったんだろうけど。

シンプル簡単はてブロと、カスタマイズもりもりはてダで、住み分けしつつ共存できれば良いのではないでしょか。

トラックバック - http://d.hatena.ne.jp/hisam_k/20130211

2011-10-28 Fri コミケ落選

コミケ落ちました。

窓際デスクの新作ではありませんが、まじっくあわ〜さんのゲームの一部シナリオ担当しているので、そっちは出るかも。

トラックバック - http://d.hatena.ne.jp/hisam_k/20111028

2011-08-12 Fri 明日のお品書き

hisam_k2011-08-12

明日コミケますよ。

2日目ホ46b窓際デスク

ゲームの新作はありませんが、グッズの新作があります

囲碁将棋で使うタイマー、対局時計です。

萌えるチェスクロです。チェスクロさんが描いてあります

有名なアニメ声優さんの声でカウントダウンしてくれます

あと堕武者さんのCD委託とか。

まぁ、そんなかんじで。

トラックバック - http://d.hatena.ne.jp/hisam_k/20110812

2011-07-02 Sat 月姫・東方・ひぐらし、の次。

三大同人ゲームってあったじゃん?

一般的には以下の3作品。

月姫TYPE-MOON

東方Project上海アリス幻樂団

ひぐらしのなく頃に07th Expansion

でも、明らかに東方だけ息が長いよね。ひぐらしも長かったけど、流石にもう終わコンだよね。

で、何かそれに関係しそうな「どうすれば次のムーブメントに」ってな質問が出てたから、回答してみた。

個人的にはOmegaの視界とか来るんじゃないかと思ってたんだけどなぁ。聖地巡礼する人とかも出てたくらいだし。

二次創作の対象としてのムーブメントという視点で回答します。

全盛期のひぐらし現在東方について共通点を挙げるならば、定期的に公式のコンテンツが追加され続けている(いた)ことは見逃せないと思います。加えて、それらが明確な時間の経過を伴う続編ではない点も大きいのではないでしょうか。

例えば、大作RPGキャラクターのその後が書かれる続編が出た場合、前作をプレイしていない人は二の足を踏むでしょう。かと言って、タイトル世界観だけを引き継ぐ続編を出せば、キャラクター重視の二次創作を伴うコミュニティでの成長はリセットされるでしょう。

ひぐらしであれば、各キャラクターの位置付けが理解出来れば、全ての平行世界災害を把握していなくても(本来のミステリとしての楽しさではありませんが)二次創作世界を楽しむ事が出来ます。また、扱い易く濃いキャラが揃っており、新たな平行世界の構築・オリジナルストーリーの開発環境としては十分です。○○し編、を追加しやすいのは大きなメリットです。それは同人だけでなく、公式の漫画ラジオドラマでも同じです。

東方であれば、基本的にはシリーズのどのタイトルからであれゲームを楽しむ事が可能です。異変の時系列はあっても、霊夢の年齢が上がり続けている訳ではないです。また、STGゲーム性以外にも魅力的な世界観物語性、絵や音楽のアレンジへの寛容性など、開発環境としては前例がない程に整っています。そして、現在でも定期的にライブラリ拡張リソースの追加が行われています。

以上から

ゲーム・ノベルとして普通に面白い

・定期的に公式の続編が発表される。

・同一のキャラクターが登場する続編だが、明確な時間経過は伴わない。

・一部だけでも楽しめる。メディアミックスを含むシリーズ全てをプレイする必要はない。

・でもハマったら全シリーズを知りたくなる深い世界観と広い人間関係

物語、絵、音楽、について二次創作を許可、推奨している。

動画3Dモデル等も二次創作、アレンジ用に配布すれば良いかも知れない。

ひぐらし東方に公式の「地図」と空白部分があれば盛り上がらないかな?続編を追加した時に整合性とか大変になりそうだけど。

せらでynaな後輩せらでynaな後輩 2011/07/03 13:07 地味にomegaファンな後輩が通りますよっと。
omegaは完全に音楽から入ってしまったクチです。
本編は難解すぎる部分が多いから、よほどのコアなユーザーしか寄り付かなかったのでは。
多分私はまだ4割くらいしか理解できていないと思われます。
月姫やってみたいんですけど、さすがにもう手に取るのは厳しいですよね・・

氷雨係長氷雨係長 2011/07/04 09:28 そいやOmega完結したら買うとか言ってた気がする。難解だけど、格好いいからOKで。音楽、onokenさんBMSからポップンまで上り詰めたね。絵の人、閂夜明さんも元々有名なゲーム会社でグラフィックやってた人。
月姫、リメイクの話もあった気がするんだけど、どうなったんだろう?

トラックバック - http://d.hatena.ne.jp/hisam_k/20110702