用 Ruby 寫一個送禮自用兩相宜的 Compiler
View Slide
襟儘䓛⛳@elct9620WEB DEVELOPERGAME DEVELOPER
#I_feel_border⼤大家都在寫 Compier 作業
C4 不夠⽤用就⽤用 C5 啊!https://github.com/elct9620/5compilerDemo First Talk
LexerTokenizerParserSource CodeAST
簡單說就是照規則把字串串切開來來Lexer
Lexer.new("count = 1 if reset")# ['count', '=', '1', 'if', 'reset']Lexer
class Lexer < ArrayKEYWORDS =%w[if else end puts].freezeKEYWORD_RULE =/(?#{KEYWORDS.join('|')})/endLexer
RULE = Regexp.union(LINEFEED_RULE,SYMBOL_RULE,KEYWORD_RULE,STRING_RULE,NUMBER_RULE,WORD_RULE)Lexer
script.scan(RULE).flatten.compact# ['count', '=', '1', 'if', 'reset']Lexer
把 Lexer 切好的⽂文字片段做簡單的分類Tokenizer
Tokeinzer.new(['if', 'reset'])# [# # @value="if"># # @value="reset"># ]Tokenizer
MATCH_RULES.each do |type, rule|if word.match?(rule)return Token.new(type, word)endendToken.new(:literal, word)Tokenizer
class Token# ...def symbol?type == :symbolend# ...endTokenizer
依照 Token 的狀狀況轉換成⽤用樹狀狀的⽅方式表⽰示程式運作Parser
IFTRUE FALSEBLOCK BLOCK
class Parserdef parsetokens = @tokenizer.to_enum@context =Node::Context.new(tokens)@ast = context.astendendParser
loop dobreak if t.peek.else? || #...#…if t.peek.fn?next @ast << Node::Function.new(t)end#...endParser
ContextParserFunctionEnterContext StateExit StateNext token is ‘else’EnterFunction StateExit StateNext token is ‘end’
基於 Parser ⽣生成的 Abstract Syntax Tree 執⾏行行程式Virtual Machine
將 AST 轉換為機器碼或者 VM 可以直接讀取的規格Bytecode
借⽤用 Ruby VM 直接執⾏行行 `Kernel.send(‘puts’, ‘Hello World’)`5Compiler’s VM
在 Router 中可以⽤用來來判斷⽬目前請求的網址對應的 ControllerRails’s AST
在 ActiveRecord (Arel) 可以⽤用來來組成 SQL 語法Rails’s AST
⽤用來來動態執⾏行行 ActiveRecord 相關的動作 Ex. JSON Query, Update …Tamashii::TLang’s AST
很可惜困難的是 VM 怎麼動起來來喔⋯⋯聽起來來好像很簡單,對吧?