啊好吧。elixir
即使您问题上的标签说您正在使用erlang
. 我可以得到一个更简单的解析器版本来工作:
string_parser.yrl:
Nonterminals the_string content.
Terminals '\'' string.
Rootsymbol the_string.
the_string -> '\'' content '\'' : '$2'.
%I guess the atom :string has to be the first element of the tuple
%returned by '$2' in previous line:
content -> string : extract_value('$1')
Erlang code.
extract_value({_, _, Value}) -> Value.
在 iex 中:
iex(1)> :yecc.file('string_parser.yrl')
{:ok, 'string_parser.erl'}
iex(2)> c("string_parser.erl")
[:string_parser]
iex(3)> :string_parser.parse([{:"'", 1}, {:string, 1, "hello"}, {:"'", 1}])
{:ok, "hello"}
但是,我无法让递归定义起作用。
好的,我越来越近了:
string_parser.yrl:
Nonterminals string interior_strings interior_string.
Terminals left_delim right_delim result.
Rootsymbol string.
string -> left_delim interior_strings right_delim : '$2'.
string -> left_delim right_delim : "".
interior_strings -> interior_string : ['$1'].
interior_strings -> interior_string interior_strings : ['$1' | '$2'].
interior_string -> result : extract_value('$1').
interior_string -> string : '$1'.
Erlang code.
extract_value({_, _, Value}) -> Value.
在 iex 中:
iex(49)> :yecc.file('string_parser.yrl')
{:ok, 'string_parser.erl'}
iex(50)> c("string_parser.erl")
[:string_parser]
iex(51)> :string_parser.parse([{:left_delim, 1}, {:result, 1, "hello"}, {:left_delim, 1}, {:result, 1, "goodbye"}, {:right_delim, 1}, {:right_delim, 1}])
{:ok, ["hello", ["goodbye"]]}
iex(53)>
在这一点上,我不知道为什么爆炸的括号在"goodbye"
.
成功!
string_parser.yrl:
Nonterminals string interior_strings interior_string.
Terminals left_delim right_delim result.
Rootsymbol string.
string -> left_delim interior_strings right_delim : '$2'.
string -> left_delim right_delim : "".
interior_strings -> left_delim interior_string right_delim: ['$2'].
interior_strings -> interior_string interior_strings : ['$1' | '$2'].
interior_string -> result : extract_value('$1').
interior_string -> string : '$1'.
Erlang code.
extract_value({_, _, Value}) -> Value.
在 iex 中:
iex(53)> :yecc.file('string_parser.yrl')
{:ok, 'string_parser.erl'}
iex(54)> c("string_parser.erl")
[:string_parser]
iex(55)> :string_parser.parse([{:left_delim, 1}, {:result, 1, "hello"}, {:left_delim, 1}, {:result, 1, "goodbye"}, {:right_delim, 1}, {:right_delim, 1}])
{:ok, ["hello", "goodbye"]}
我仍然无法开始工作的一件事是,如果我明确指定'\''
分隔符:
Nonterminals string interior_strings interior_string.
Terminals '\'' result.
Rootsymbol string.
Endsymbol '$end'.
string -> '\'' interior_strings '\'' : '$2'.
string -> '\'' '\'' : "".
interior_strings -> '\'' interior_string '\'': ['$2'].
interior_strings -> interior_string interior_strings : ['$1' | '$2'].
interior_string -> result : extract_value('$1').
interior_string -> string : '$1'.
Erlang code.
extract_value({_, _, Value}) -> Value.
在 iex 中:
iex(3)> :string_parser.parse([{:"'", 1}, {:result, 1, "hello"},
{:"'", 1}, {:result, 1, "goodbye"}, {:"'", 1}, {:"'", 1}, {:"$end", 1}])
{:error, {1, :string_parser, ['syntax error before: ', []]}}
处理如此可怕的错误消息太令人沮丧了。空列表前有语法错误[]
???令牌列表中的空列表在哪里?
我认为添加最后一个元组:{:"$end", 1}
可能会起作用——但没有运气。同样的错误。
如果我使用文字括号作为分隔符,我可以让 string_parser 工作:
string_parser.yrl:
Nonterminals string interior_strings interior_string.
Terminals '[' ']' content.
Rootsymbol string.
string -> '[' interior_strings ']' : '$2'.
string -> '[' ']' : "".
interior_strings -> '[' interior_string ']' : ['$2'].
interior_strings -> interior_string interior_strings : ['$1' | '$2'].
interior_string -> content : extract_content('$1').
interior_string -> string : '$1'.
Erlang code.
extract_content({_, _, Content}) -> Content.
在 iex 中:
iex(11)> :yecc.file('string_parser.yrl')
{:ok, 'string_parser.erl'}
iex(12)> c("string_parser.erl")
[:string_parser]
iex(13)> :string_parser.parse([{:"[", 1}, {:content, 1, "hello"}, {:"[", 1}, {:content, 1, "goodbye"}, {:"]", 1}, {:"]", 1}])
{:ok, ["hello", "goodbye"]}
iex(14)>
我尝试在 erlang 中编写 string_parser,但我得到了同样的错误。.yrl 文件不是 erlang 语法,因此无论解析 .yrl 文件似乎都无法解析单引号原子:'\''
。