第2回コンパイラを作ろう スキャナ構築編

10月 4th, 2008 admin Posted in CSNAGOYA, コンパイラ, 勉強会 |

9月21日にCSNagoyaで第2回コンパイラを作ろうを開催しました。
ブログでの報告が遅れたのは宿題であるスキャナの作成が遅れたからです・・・

第1部 コンパイラを作ろう

「コンパイラ入門」という本の6章「スキャナの構築」を読みながら実際にスキャナのコードを書きました。
スキャナとはコンパイラの構成要素の一つで、コードを読み込んで、それをプログラムの最小構成であるトークンに分解するものです。echo 'Hello';というコードがあった場合、["echo","Hello",";"]という感じにコードを分解します。

コード

僕はRubyで書きました。

RUBY:
  1. class Token
  2.   attr_accessor :def, :str, :type
  3.  
  4.   def initialize(fp)
  5.     @def = ""
  6.     @str = ""
  7.     @type = ""
  8.  
  9.     @fp = fp
  10.   end
  11.  
  12.   def get_token
  13.     @def = "EOF"
  14.     @str = ""
  15.     @type = "EOF"
  16.     c = get_character
  17.     while(is_white_space(c))
  18.       c = @fp.read(1)
  19.     end
  20.  
  21.     if(c == ";") then @def = "SEMICOLON"; @str = c;end
  22.     if(c == ",") then @def = "COMMA";     @str = c;end
  23.     if(c == "(") then @def = "OPEN";      @str = c;end
  24.     if(c == ")") then @def = "CLOSE";     @str = c;end
  25.     if(c == ".") then @def = "PERIOD";    @str = c;end
  26.     if(c == "+") then @def = "PLUS";      @str = c;end
  27.     if(c == "-") then @def = "MINUS";     @str = c;end
  28.     if(c == "*") then @def = "MULT";      @str = c;end
  29.     if(c == "/") then @def = "DIV";       @str = c;end
  30.     if(c == "=") then @def = "EQ";        @str = c;end
  31.  
  32.     if(c == ":")
  33.       @str = @str + c
  34.       c = get_character
  35.       if(c == "=")
  36.         @def = "ASSIGN"
  37.         @str = @str + c
  38.       else
  39.         @def = "COLON"
  40.         unget_character(c)
  41.       end
  42.     elsif(c == ">")
  43.       @str = @str + c
  44.       c = get_character
  45.       if(c == "=")
  46.         @def = "GE"
  47.         @str = @str + c
  48.       else
  49.         @def = "GT"
  50.       end
  51.     elsif(c == "<")
  52.       @str = @str + c
  53.       c = get_character
  54.       if(c == "=")
  55.         @def = "LE"
  56.         @str = @str + c
  57.       elsif(c == ">")
  58.         @def = "NE"
  59.         @str = @str + c
  60.       else
  61.         @def = "LT"
  62.       end
  63.     elsif(c == '"')
  64.       c = get_character
  65.       until(c == '"')
  66.         @str = @str + c
  67.         c = get_character
  68.       end
  69.       @def = "STR"
  70.     elsif(is_digit(c))
  71.       while(is_digit(c))
  72.         @str = @str + c
  73.         c = get_character
  74.       end
  75.       unget_character(c)
  76.       @def = "NUMBER"
  77.  
  78.     elsif(is_alpha(c))
  79.       while(is_alpha(c) || is_digit(c))
  80.        @str = @str + c
  81.        c = get_character
  82.       end
  83.       unget_character(c)
  84.      
  85.       @def = "IDENT"
  86.       @def = "MODULE"     if @str == "MODULE"
  87.       @def = "BEGIN"      if @str == "BEGIN"
  88.       @def = "END"        if @str == "END"
  89.       @def = "VAR"        if @str == "VAR"
  90.       @def = "INTEGER"    if @str == "INTEGER"
  91.       @def = "STRING"     if @str == "STRING"
  92.       @def = "IF"         if @str == "IF"
  93.       @def = "THEN"       if @str == "THEN"
  94.       @def = "ELSE"       if @str == "ELSE"
  95.       @def = "WHILE"      if @str == "WHILE"
  96.       @def = "DO"         if @str == "DO"
  97.     elsif(is_EOF(c))
  98.       @def = "EOF"
  99.     end
  100.   end
  101.  
  102.   def get_character
  103.     c = @fp.read(1)
  104.     return c
  105.   end
  106.  
  107.   def unget_character(c)
  108.     return @fp.ungetc(c[0]) unless c.nil?
  109.   end
  110.  
  111.  
  112.   def is_EOF(i)
  113.     return true if i.nil?
  114.   end
  115.  
  116.   def is_white_space(i)
  117.     return true if i =~ /\s/
  118.   end
  119.  
  120.   def is_digit(i)
  121.     return true if i =~ /[0-9]/
  122.   end
  123.  
  124.   def is_alpha(i)
  125.     return true if i =~ /[a-zA-Z]/
  126.   end
  127. end
  128.  
  129.  
  130.  
  131.  
  132.  
  133. token = Token.new(open(ARGV[0],"r"))
  134. token.get_token
  135. until token.def == "EOF"
  136.  puts "DEF[" + token.def + "] \t\t STR[" + token.str + "]"
  137.  token.get_token
  138. end

これにたとえばこんなコードを食わせる

RUBY:
  1. MODULE HelloWorld;
  2. BEGIN
  3.   VAR = 1 + 100 * 2
  4.   if (VAR>= 100)
  5.     WriteStr("Hello World!")
  6.   END
  7. END HelloWorld.

と、それぞれがトークンに分解されて出力されます。

RUBY:
  1. DEF[MODULE]              STR[MODULE]
  2. DEF[IDENT]               STR[HelloWorld]
  3. DEF[SEMICOLON]           STR[;]
  4. DEF[BEGIN]               STR[BEGIN]
  5. DEF[VAR]                 STR[VAR]
  6. DEF[EQ]                  STR[=]
  7. DEF[NUMBER]              STR[1]
  8. DEF[PLUS]                STR[+]
  9. DEF[NUMBER]              STR[100]
  10. DEF[MULT]                STR[*]
  11. DEF[NUMBER]              STR[2]
  12. DEF[IDENT]               STR[if]
  13. DEF[OPEN]                STR[(]
  14. DEF[VAR]                 STR[VAR]
  15. DEF[GE]                  STR[>=]
  16. DEF[NUMBER]              STR[100]
  17. DEF[CLOSE]               STR[)]
  18. DEF[IDENT]               STR[WriteStr]
  19. DEF[OPEN]                STR[(]
  20. DEF[STR]                 STR[Hello World!]
  21. DEF[CLOSE]               STR[)]
  22. DEF[END]                 STR[END]
  23. DEF[END]                 STR[END]
  24. DEF[IDENT]               STR[HelloWorld]
  25. DEF[PERIOD]              STR[.]

第2部 サーバ/インフラ構築入門 -冗長化の基本-

id:dominion525氏による講義。前回のWebサーバの冗長化の話の続きでルータやロードバランサの冗長化の話でした。

まとめ

各自が好きな言語で実装しているので人のコードがあまり参考にならないのが辛いなと思いました。まぁその分他の人のコードを見るのが楽しみです。
次回の勉強会は明日!みんな宿題はやってくるでしょうか

Leave a Reply