Sendai Hackathon#0

今日は、片平さんのオフィスにお邪魔させてもらい、勉強会をしてきました。
で、名前を勝手にSendai hackathon#0 とすることにしました。ということで、
Sedai Hackathon#0終了です。
14時〜21時の7時間、しりをたたき、たたきたたかれつつおのおの作りたいものを作りました。
途中で一度、ドイツビールのお祭りやってるのでのみに行って、ワインも飲んだりしました。
非常に楽しかったです。
わがまま、言いまくって、申し訳ない気もしますが、ま、いいや。(w


自分は簡単なプログラミング言語の作り方を書きたいので、片平さんに説明しつつ、難しいところはどこなのかを
聞いて、自分の経験とあわせつつ、難しく感じる部分は取っ払っおうという結論になりました。
まず、字句解析は配列を作ってしまうのがやっぱりわかりいい。細々読み込みは難しいし、先読み機構も最初はわかりずらい。
だんだん分かってくればいいんだろうけど。という話で、自分も昔はそう思ってたのでそう直すことにしました。
あと、優先順位をつける構文解析まで一気に理解するのも、理解するのも難しいだろうということで、
優先順位無しでまず説明することにしました。
ということで、今日作ったプログラムはこれです。
ならべて、phpバージョンもこれから作ります。
説明はまた、あとで書きます。(w


いろいろ話を聞いてもらって、自分が作ろうとしているのは教育用言語で、
限りなく簡単だけど十分な表現能力を持っている言語を作ろうとしていることがわかりました。
それで、書籍になるレベルまでレベルUPさせていくのが目標と。


ライブラリを作るのが大変なんじゃ?
とか、何人かに聞かれたのだけどそうじゃないんだよなぁっと。
そりゃライブラリ作りは大変だけど、その前に誰でも簡単に言語処理系を作れるようにすることがもっと難しいんです。
というのがあるので、それが実現されることがまず、大きな目標なのです。
誰でも作れるくらい簡単だから、美しい言語なのだといいたいのです。
それって結局教育用言語ってことになるのかなと。
でも、そのくらい簡単なので、自分でもさくさく作れるようになるはずで、
本当に、さくさく作れるようになってしまえば、あとはライブラリを書くだけです。

class Lexer

  def initialize src
    @src = src
  end

  def lex
    case @src
      when /^[\r\n\t ]*([0-9]+)(.*$)/
      when /^[\r\n\t ]*([+*\-\/()])(.*$)/
      when /^[\r\n\t ]*(.*)(.*$)/
        return nil
    end
    @src = $2
    $1
  end

  def tokens
    ts = []
    while (token = lex) != nil
      ts.push(token)
    end
    ts
  end

end

class Parser
  def parse(src)
    @lexer = Lexer.new(src)
    tokens = @lexer.tokens
#   p tokens
    t = tokens.shift.to_i
    while tokens.first == "+" || tokens.first == "-" || tokens.first == "*" || tokens.first == "/"
      op = tokens.shift
      t = [op, t, tokens.shift.to_i]
    end
    t
  end
end

class Calc
  def initialize
    @parser = Parser.new
  end
  def eval src
    tree = @parser.parse(src)
#    p tree
    exp tree
  end
  
  def exp tree
    if tree.instance_of?(Array)
      case tree[0]
      when "+"
        exp(tree[1]) + exp(tree[2])
      when "-"
        exp(tree[1]) - exp(tree[2])
      when "*"
        exp(tree[1]) * exp(tree[2])
      when "/"
        exp(tree[1]) / exp(tree[2])
      end
    else
      tree
    end
  end
end

calc = Calc.new
p calc.eval("1+2*3")

このプログラムは優先順位がないので、((1+2)*3)を計算します。結果として9が返ります。
ざっくりした説明だけ書いておきますと、Lexerというのが文字列をトークンの列に分解します。
Parserがトークン列を木構造にします。
そして、Calcが木構造を計算して結果を返します。
というようなつくりになっております。