{:error, {:undefined, :standard_syntax_parser, ['syntax error before: ', []]}}

{:error, {:undefined, :standard_syntax_parser, ['syntax error before: ', []]}}

所以我正在尝试使用 yecc。

Terminals string string_delimeter.

Nonterminals value string_content.

Rootsymbol value.

value -> string : extract_value('').

value -> string_delimeter string_content string_delimeter : ''.
string_content -> value string_content : ['' | ''].
string_content -> value : ''.

Erlang code.

extract_value({_, Value}) -> Value.

对于输入:

[string_delimeter: '\'', string: 'test', string_delimeter: '\'']

我明白了

{:error, {:undefined, :standard_syntax_parser, ['syntax error before: ', []]}}

如果我删除 string_content 周围的任何(左或右)string_delimeter:

value -> string_delimeter string_content string_delimeter : ''.

value -> string_delimeter string_content : ''.

[string_delimeter: '\'', string: 'test']

它returns

{:ok, 'test'}

我不太理解这种行为,问题出在哪里?

For the input:

[string_delimeter: '\'', string: 'test', string_delimeter: '\'']

我觉得你很困惑(或者也许是我!)。 yecc 需要一个标记列表,其中标记是一个 2 或 3 元素元组。来自 yecc docs:

The user should implement a scanner that segments the input text, and turns it into one or more lists of tokens. Each token should be a tuple containing information about syntactic category, position in the text (e.g. line number), and the actual terminal symbol found in the text: {Category, LineNumber, Symbol}.

If a terminal symbol is the only member of a category, and the symbol name is identical to the category name, the token format may be {Symbol, LineNumber}...

这是 yecc 期望的示例:

[
     {'[',1},
     {atom,1,foo},
     {',',1},
     {'[',1},
     {int,1,1},
     {']',1},
     {',',1},
     {'[',1},
     {atom,1,bar},
     {',',1},
     {'[',1},
     {int,1,2},
     {',',1},
     {int,1,3}, 
     {']',1},
     {']',1},
     {']',1}
]

您可以使用 leex 实现这样的扫描器,然后将输出提供给 yecc 解析器。

忠告:你永远不应该 post 一个描述你如何 运行 你的代码的问题——这只是在浪费大量时间。而是复制并粘贴您 运行 的确切命令以及这些命令产生的输出。您只需要说:

  1. This is what I tried:

[Your code here]

  1. Here is the output:

[all commands you ran and the output here]

  1. This is the output I expect/want, or Wtf??!! is going on.

[expected/desired output here]

啊,好的。您正在使用 elixir,即使您问题上的标签说您正在使用 erlang。我可以获得一个更简单的解析器版本:

string_parser.yrl:

Nonterminals the_string content.
Terminals '\'' string.
Rootsymbol the_string.

the_string -> '\'' content '\'' : ''.

%I guess the atom :string has to be the first element of the tuple
%returned by '' in previous line:
content -> string : extract_value('')

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 : ''.
string -> left_delim right_delim : "".

interior_strings -> interior_string : [''].
interior_strings -> interior_string interior_strings : ['' | ''].

interior_string -> result : extract_value('').
interior_string -> string : ''.

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 : ''.
string -> left_delim right_delim : "".

interior_strings -> left_delim interior_string right_delim: [''].
interior_strings -> interior_string interior_strings : ['' | ''].

interior_string -> result : extract_value('').
interior_string -> string : ''.

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 '\'' : ''.
string -> '\'' '\'' : "".

interior_strings -> '\'' interior_string '\'': [''].
interior_strings -> interior_string interior_strings : ['' | ''].

interior_string -> result : extract_value('').
interior_string -> string : ''.

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 ']' : ''.
string -> '[' ']' : "".

interior_strings -> '[' interior_string ']' : [''].
interior_strings -> interior_string interior_strings : ['' | ''].

interior_string -> content : extract_content('').
interior_string -> string : ''.

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 文件似乎都无法解析单引号原子:'\''.

我没有弄清楚为什么这是 yecc 中的问题: token_1 token_2 token_1 我真的希望我知道,但我有办法解决这个问题:

Terminals string string_delimeter whitespace.


Nonterminals value string_content.


Rootsymbol value.

value -> string : extract_value('').

value -> string_delimeter string_content : ''.
string_content -> string_content string_delimeter : ''.
string_content -> value whitespace string_content : ['' | ''].
string_content -> value : [''].

Erlang code.

extract_value({_, Value}) -> Value.