第2回コンパイラを作ろう スキャナ構築編
10月 4th, 2008 admin Posted in CSNAGOYA, コンパイラ, 勉強会 |
9月21日にCSNagoyaで第2回コンパイラを作ろうを開催しました。
ブログでの報告が遅れたのは宿題であるスキャナの作成が遅れたからです・・・
第1部 コンパイラを作ろう
「コンパイラ入門」という本の6章「スキャナの構築」を読みながら実際にスキャナのコードを書きました。
スキャナとはコンパイラの構成要素の一つで、コードを読み込んで、それをプログラムの最小構成であるトークンに分解するものです。echo 'Hello';というコードがあった場合、["echo","Hello",";"]という感じにコードを分解します。
コード
僕はRubyで書きました。
RUBY:
-
class Token
-
attr_accessor :def, :str, :type
-
-
def initialize(fp)
-
@def = ""
-
@str = ""
-
@type = ""
-
-
@fp = fp
-
end
-
-
def get_token
-
@def = "EOF"
-
@str = ""
-
@type = "EOF"
-
c = get_character
-
while(is_white_space(c))
-
c = @fp.read(1)
-
end
-
-
if(c == ";") then @def = "SEMICOLON"; @str = c;end
-
if(c == ",") then @def = "COMMA"; @str = c;end
-
if(c == "(") then @def = "OPEN"; @str = c;end
-
if(c == ")") then @def = "CLOSE"; @str = c;end
-
if(c == ".") then @def = "PERIOD"; @str = c;end
-
if(c == "+") then @def = "PLUS"; @str = c;end
-
if(c == "-") then @def = "MINUS"; @str = c;end
-
if(c == "*") then @def = "MULT"; @str = c;end
-
if(c == "/") then @def = "DIV"; @str = c;end
-
if(c == "=") then @def = "EQ"; @str = c;end
-
-
if(c == ":")
-
@str = @str + c
-
c = get_character
-
if(c == "=")
-
@def = "ASSIGN"
-
@str = @str + c
-
else
-
@def = "COLON"
-
unget_character(c)
-
end
-
elsif(c == ">")
-
@str = @str + c
-
c = get_character
-
if(c == "=")
-
@def = "GE"
-
@str = @str + c
-
else
-
@def = "GT"
-
end
-
elsif(c == "<")
-
@str = @str + c
-
c = get_character
-
if(c == "=")
-
@def = "LE"
-
@str = @str + c
-
elsif(c == ">")
-
@def = "NE"
-
@str = @str + c
-
else
-
@def = "LT"
-
end
-
elsif(c == '"')
-
c = get_character
-
until(c == '"')
-
@str = @str + c
-
c = get_character
-
end
-
@def = "STR"
-
elsif(is_digit(c))
-
while(is_digit(c))
-
@str = @str + c
-
c = get_character
-
end
-
unget_character(c)
-
@def = "NUMBER"
-
-
elsif(is_alpha(c))
-
while(is_alpha(c) || is_digit(c))
-
@str = @str + c
-
c = get_character
-
end
-
unget_character(c)
-
-
@def = "IDENT"
-
@def = "MODULE" if @str == "MODULE"
-
@def = "BEGIN" if @str == "BEGIN"
-
@def = "END" if @str == "END"
-
@def = "VAR" if @str == "VAR"
-
@def = "INTEGER" if @str == "INTEGER"
-
@def = "STRING" if @str == "STRING"
-
@def = "IF" if @str == "IF"
-
@def = "THEN" if @str == "THEN"
-
@def = "ELSE" if @str == "ELSE"
-
@def = "WHILE" if @str == "WHILE"
-
@def = "DO" if @str == "DO"
-
elsif(is_EOF(c))
-
@def = "EOF"
-
end
-
end
-
-
def get_character
-
c = @fp.read(1)
-
return c
-
end
-
-
def unget_character(c)
-
return @fp.ungetc(c[0]) unless c.nil?
-
end
-
-
-
def is_EOF(i)
-
return true if i.nil?
-
end
-
-
def is_white_space(i)
-
return true if i =~ /\s/
-
end
-
-
def is_digit(i)
-
return true if i =~ /[0-9]/
-
end
-
-
def is_alpha(i)
-
return true if i =~ /[a-zA-Z]/
-
end
-
end
-
-
-
-
-
-
token = Token.new(open(ARGV[0],"r"))
-
token.get_token
-
until token.def == "EOF"
-
puts "DEF[" + token.def + "] \t\t STR[" + token.str + "]"
-
token.get_token
-
end
これにたとえばこんなコードを食わせる
RUBY:
-
MODULE HelloWorld;
-
BEGIN
-
VAR = 1 + 100 * 2
-
if (VAR>= 100)
-
WriteStr("Hello World!")
-
END
-
END HelloWorld.
と、それぞれがトークンに分解されて出力されます。
RUBY:
-
DEF[MODULE] STR[MODULE]
-
DEF[IDENT] STR[HelloWorld]
-
DEF[SEMICOLON] STR[;]
-
DEF[BEGIN] STR[BEGIN]
-
DEF[VAR] STR[VAR]
-
DEF[EQ] STR[=]
-
DEF[NUMBER] STR[1]
-
DEF[PLUS] STR[+]
-
DEF[NUMBER] STR[100]
-
DEF[MULT] STR[*]
-
DEF[NUMBER] STR[2]
-
DEF[IDENT] STR[if]
-
DEF[OPEN] STR[(]
-
DEF[VAR] STR[VAR]
-
DEF[GE] STR[>=]
-
DEF[NUMBER] STR[100]
-
DEF[CLOSE] STR[)]
-
DEF[IDENT] STR[WriteStr]
-
DEF[OPEN] STR[(]
-
DEF[STR] STR[Hello World!]
-
DEF[CLOSE] STR[)]
-
DEF[END] STR[END]
-
DEF[END] STR[END]
-
DEF[IDENT] STR[HelloWorld]
-
DEF[PERIOD] STR[.]
第2部 サーバ/インフラ構築入門 -冗長化の基本-
id:dominion525氏による講義。前回のWebサーバの冗長化の話の続きでルータやロードバランサの冗長化の話でした。
まとめ
各自が好きな言語で実装しているので人のコードがあまり参考にならないのが辛いなと思いました。まぁその分他の人のコードを見るのが楽しみです。
次回の勉強会は明日!みんな宿題はやってくるでしょうか
Leave a Reply