0

所以我正在尝试使用yecc。

Terminals string string_delimeter.

Nonterminals value string_content.

Rootsymbol value.

value -> string : extract_value('$1').

value -> string_delimeter string_content string_delimeter : '$2'.
string_content -> value string_content : ['$1' | '$2'].
string_content -> value : '$1'.

Erlang code.

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

对于输入:

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

我明白了

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

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

value -> string_delimeter string_content string_delimeter : '$2'.

value -> string_delimeter string_content : '$2'.

为了

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

它返回

{:ok, 'test'}

我真的不明白这种行为,问题出在哪里?

4

3 回答 3

0

对于输入:

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

我认为你很困惑(或者可能是我!)。 yecc需要一个令牌列表,其中一个令牌是一个 2 或 3 个元素的元组。来自yecc 文档

用户应该实现一个扫描器来分割输入文本,并将其转换为一个或多个令牌列表。每个标记都应该是一个元组,包含有关语法类别、文本中的位置(例如行号)以及在文本中找到的实际终端符号的信息:{Category, LineNumber, Symbol}.

如果终端符号是类别的唯一成员,并且符号名称与类别名称相同,则标记格式可能是 {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解析器。

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

  1. 这是我尝试过的:

[你的代码在这里]

  1. 这是输出:

[您运行的所有命令和此处的输出]

  1. 这是我期望/想要的输出,或者 Wtf??!! 正在进行。

[此处的预期/期望输出]

于 2019-07-21T18:30:09.470 回答
0

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

于 2019-07-21T22:37:41.307 回答
0

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

Terminals string string_delimeter whitespace.


Nonterminals value string_content.


Rootsymbol value.

value -> string : extract_value('$1').

value -> string_delimeter string_content : '$2'.
string_content -> string_content string_delimeter : '$1'.
string_content -> value whitespace string_content : ['$1' | '$3'].
string_content -> value : ['$1'].

Erlang code.

extract_value({_, Value}) -> Value.
于 2019-07-22T11:33:35.160 回答