4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

超シンプルな構文解析をやってみた。

Last updated at Posted at 2015-05-09

天国の木に実っている技術の実の端っこの方を
舌の先端で触ってみては苦い、渋いとかいって
かじるのを躊躇っている虫がいたとすればいればそれが僕です。
どうもkondogです。
もう29にもなろうというのに自分がどこに進めばいいのかよくわかりません。
やばい。ああ、そういえば最近暖かくなってきましたね。

ちょっと前に見たやつ。
Googleで1400万円以上稼ぐエンジニアになるためにマスターすべき11のスキル
1400万欲しい!けど全部面倒くさそう。。。
あー、コンパイラ?構文解析?だっけ?やってみっか。。。

ということでGWにやってみました。
目標はシンプルに1 + 1 = 2 を構文解析するということで決定。
構文解析の基本のkを理解するにはこれで十分(つーか限界)。
多分[[[1:数値], [1:数値], [+,+]], [2:数値], [=,=]]みたいな
感じの結果になればいいはず。。

適当に調べて、
どうやらyaccとかいうのを一般的には使うらしい。
あと構文解析の前に字句解析とかいうのもあるらしい。
yaccをrubyで使えるようにした(という言い方であってるか知らんが)
Raccなるものを発見。これを使えばいいのよね。。。
Racc の使い方

なんだこれは黒魔術か...?全然分からん。。。
実際に使っているページコピペ元を発見。嗚呼、ありがとうございます。
platform-echo: Raccを使って言語処理系作ってた

よし、なるほど。俺のしょっぱい梅色の脳細胞でも5%理解できた。
見よう見まねで実装。

ちなみに下記で実装してます。
Ruby 1.9.3
Racc 1.4.12

sample_parser.y
class SampleParser
    prechigh
        left    '+'
        left    '='
    preclow
    token int
rule
  EXP : int
        { p @stack; @stack << val[0].to_i }
      | EXP '+' EXP
        { p @stack; @stack << [@stack.pop, @stack.pop, :add] }
      | EXP '=' EXP
        { p @stack; @stack << [@stack.pop, @stack.pop, :equal] }

---- inner
def parse(tokens)
    @q      = tokens + [[false, '$']]
    @stack  = []
    do_parse
    return @stack
end

def next_token
    @q.shift
end

ははぁ、なんか式の評価がどうとか、
大学でやった覚えがあるな。。。あれそういう授業だったんだ。。
prechigh/lowとかいうのは評価順序、
inner以下とかtokenとかなんじゃこりゃと思ってたけど、
Raccにこいつを噛ませて実行するとどういう感じになるかちょっと分かる。
以下こいつを使うコード。

parse.rb
require './sample_parser.tab.rb'

def lexical_analyze(str)
  tokens = str.split(/\s+/)
  res    = []
  tokens.each do |token|
    case token
    when '+'      
      res << ['+', '+']
    when '='
      res << ['=', '=']
    when /\d+/ 
      res << [:int, token]
    end
  end
  return res
end

def parse(tokens)
  parser = SampleParser.new
  return parser.parse(tokens)
end

p tokens = lexical_analyze('1 + 1 = 2')
p parse(tokens)
#$ ruby parse.rb 
# 1 + 1 = 2
# [[:int, "1"], ["+", "+"], [:int, "1"], ["=", "="], [:int, "2"]]
# []
# [1]
# [1, 1]
# [[1, 1, :add]]
# [[1, 1, :add], 2]
# [[2, [1, 1, :add], :equal]]

1 + 1 = 2を字句解析して構文解析木に突っ込むだけ。
とりあえずそれっぽくなった時点で疲れたので終了。。
てさぐりかんがヤバイ。結果は合っているのか???

これを利用して=の左辺と右辺が一致するかどうかとか調べたりするのは
できそうだし面白そうではある。
その辺は多分意味解析とやらになっていくと思われる。

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?