rubyでantlr3を使う
インストール
% gem install antlr3
はじめの一歩
文法ファイル(.g)作成から実行まで
次のファイルを準備する。
- Hello.g
grammar Hello;
start_rule : 'hello' WS 'world' WS? EOF;
WS : (' ' | '\n')+;
% antlr4ruby Hello.g
もしくは
% ruby -S antlr4ruby Hello.g
実行すると次のファイルが生成される。
HelloLexer.rb
HelloParser.rb
Hello.tokens
HelloLexer.rb
HelloParser.rb
Hello.tokens
うまく生成できたら次に実行用のファイルを用意する。
- hello.rb
require 'rubygems'
require 'HelloLexer'
require 'HelloParser'
str = "hello world"
lexer = Hello::Lexer.new str
parser = Hello::Parser.new lexer
parser.start_rule
実行
% ruby hello.rb
実行しても何も起きません。何も起きないとパース成功となる。
生成されたファイルをみる
- HelloLexer.rb
module Hello
…
class Lexer < ANTLR3::Lexer
…
def initialize( input=nil, options = {} )
super( input, options )
end
…
def t__5!
type = T__5
channel = ANTLR3::DEFAULT_CHANNEL
match( "hello" )
@state.type = type
@state.channel = channel
ensure
end
def t__6!
type = T__6
channel = ANTLR3::DEFAULT_CHANNEL
match( "world" )
@state.type = type
@state.channel = channel
ensure
end
def ws!
…
ensure
end
def tokens!
alt_2 = 3
case look_2 = @input.peek( 1 )
when 0x68 then alt_2 = 1
when 0x77 then alt_2 = 2
when 0xa, 0x20 then alt_2 = 3
else
raise NoViableAlternative( "", 2, 0 )
end
case alt_2
when 1
t__5!
when 2
t__6!
when 3
ws!
end
…
end
end
ANTLR3::Lexerを継承している
token!が呼ばれると、トークンごとに@stateへ適切な値がセットされる。
自動生成されたt__5が"hello", t__6が"world"に対応する。
token!が呼ばれると、トークンごとに@stateへ適切な値がセットされる。
自動生成されたt__5が"hello", t__6が"world"に対応する。
- HelloParser.rb
…
module Hello
class Parser < ANTLR3::Parser
def initialize( input, options = {} )
super( input, options )
end
def start_rule
begin
match( T__5, TOKENS_FOLLOWING_T__5_IN_start_rule_12 ) # "hello"に相当
match( WS, TOKENS_FOLLOWING_WS_IN_start_rule_14 ) # WSに相当
match( T__6, TOKENS_FOLLOWING_T__6_IN_start_rule_16 ) # "world"に相当
…
rescue ANTLR3::Error::RecognitionError => re
report_error(re)
recover(re)
ensure
end
end
end
end
ANTLR3::Parserが継承されている。
.gファイルで記述したstart_ruleがdef定義され、エントリーポイントとなっている。
match()を呼ぶたびにトークンを比較。
比較してトークンがマッチしないと、rescueからreport_error(re)が呼ばれエラー処理に入る。
.gファイルで記述したstart_ruleがdef定義され、エントリーポイントとなっている。
match()を呼ぶたびにトークンを比較。
比較してトークンがマッチしないと、rescueからreport_error(re)が呼ばれエラー処理に入る。