如何用Ragel解决这种歧义?

时间:2012-09-17 10:52:32

标签: ruby state-machine ragel

我正在尝试解析以下格式:(identifier/)?identifier(/keyword)?,第一个标识符以及关键字optional。关键字不能用作标识符。例如,如果up是关键字,则:

  • simple匹配第二个标识符
  • first/second匹配first作为第一个标识符,second作为第二个标识符,
  • second/up匹配second作为第二个标识符,up作为关键字。

在Ruby中使用Ragel,我定义了以下FSM:

%%{
  machine simple;

  keyword = "up";
  separator = '/';
  ident_char = any - separator;
  identifier = ident_char+ - keyword;

  action start_string { $start_string = p }

  action first_string { puts "First: #{get_string(data, p)}" }
  action second_string { puts "Second: #{get_string(data, p)}" }

  action keyword_string { puts "Keyword: #{get_string(data, p)}" }

  main := ( identifier >start_string %first_string separator )? 
         :> identifier >start_string %second_string 
          ( separator keyword >start_string %keyword_string )?
  ;

}%%

%% write data;

def get_string(data, p)
  data[$start_string...p].pack("c*")
end

def parse(data)
  data = data.unpack("c*")
  eof = pe = data.length

  %% write init;
  %% write exec;
end


parse("first/second")
puts("---")
parse("second/up")

这给出了以下输出:

$ ragel -R simple.rl ; ruby simple.rb
Second: first
---
Second: second
Keyword: up

这是不正确的,因为第一部分应该是First: first Second: second,但由于我已经给出了:>优先级而预期。

我尝试了不同的优先级组合,但未能获得预期的结果。有没有办法用Ragel解决这个问题(也就是说这可以不用前瞻来解决)?

1 个答案:

答案 0 :(得分:0)

尝试将此作为主机:

two_idents = identifier >start_first %first_string . separator . (identifier >start_second %second_string);                             

main := (two_idents | identifier >start_first %first_string) . ( separator . keyword )?;

问题是“第一个标识符”与“第二个标识符”共享一个前缀,因此尝试进行保护级联快捷方式是第一台机器。联盟实际上描述了你想要做的比赛。