Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Elixir/Erlang中的Yecc解析器将项附加到映射_Erlang_Elixir_Leex_Yecc - Fatal编程技术网

使用Elixir/Erlang中的Yecc解析器将项附加到映射

使用Elixir/Erlang中的Yecc解析器将项附加到映射,erlang,elixir,leex,yecc,Erlang,Elixir,Leex,Yecc,我正在尝试用Elixir中的Leex/Yecc解析特定的日志文件。几个小时后,我得到了最简单的工作场景。然而,我想进入下一步,但我不知道如何做到这一点 首先,以下是日志格式的示例: [!] plugin error detected | check the version of the plugin 我的简单尝试只是第一行,但有多个条目,例如: [!] plugin error detected [!] plugin error 2 detected [!] plugin error 3

我正在尝试用Elixir中的Leex/Yecc解析特定的日志文件。几个小时后,我得到了最简单的工作场景。然而,我想进入下一步,但我不知道如何做到这一点

首先,以下是日志格式的示例:

[!] plugin error detected
 |  check the version of the plugin
我的简单尝试只是第一行,但有多个条目,例如:

[!] plugin error detected
[!] plugin error 2 detected
[!] plugin error 3 detected
这很有效,给了我一个很好的地图,其中包含文本和日志行类型(警告):

那太完美了。但如上图所示,日志行可以在下一行继续,用管道字符
|
表示。我的lexer具有管道字符,解析器可以理解它,但我想要的是在映射的
文本
值后面追加下一行。现在它只是作为一个字符串附加在地图上。因此,不是:

[%{text: "a big warning ", type: :warning}, " continues on next line"]
我需要:

[%{text: "a big warning continues on next line", type: :warning}]
我在网上查看了一些示例,但大多数示例都有非常清晰的“结束”标记,如结束标记或结束括号,然后我仍然不清楚如何添加属性,以便最终的AST是正确的

为了完整起见,以下是我的lexer:

Definitions.

Char          = [a-zA-Z0-9\.\s\,\[\]]
Word          = [^\t\s\.#"=]+
Space         = [\s\t]
New_Line      = [\n]
%New_Line      = \n|\r\n|\r
Type_Regular  = \[\s\]\s
Type_Warning  = \[!\]\s
Pipe          = \|

Rules.

{Type_Regular}  : {token, {type_regular,  TokenLine}}.
{Type_Warning}  : {token, {type_warning,  TokenLine}}.
{Char}          : {token, {char, TokenLine, TokenChars}}.
{Space}         : skip_token.
{Pipe}          : {token, {pipe, TokenLine}}.
{New_Line}      : skip_token.

Erlang code.
还有我的解析器:

Nonterminals lines line line_content chars.
Terminals type_regular type_warning char pipe.
Rootsymbol lines.

lines -> line lines : ['$1'|['$2']].
lines -> line : '$1'.

line -> pipe line_content : '$2'.
line -> type_regular line_content : #{type => regular, text => '$2'}.
line -> type_warning line_content : #{type => warning, text => '$2'}.

line_content -> chars : '$1'.
line_content -> pipe chars : '$1'.

chars -> char chars : unicode:characters_to_binary([get_value('$1')] ++ '$2').
chars -> char : unicode:characters_to_binary([get_value('$1')]).

Erlang code.

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

如果你已经走了这么远,谢谢你了!如果有人能帮忙,那就更谢谢你了

我建议添加一个
line\u content
规则来处理由管道分隔的多行,并删除规则
line->pipe-line\u content:“$2”。

子句中,在
'$2'
周围还有一个不必要的
[]
,单行子句应该返回一个列表,以与上一个子句的返回值一致,这样就不会得到不正确的列表

有了这四个变化,

-lines -> line lines : ['$1'|['$2']].
+lines -> line lines : ['$1'|'$2'].
-lines -> line : '$1'.
+lines -> line : ['$1'].

-line -> pipe line_content : '$2'.
 line -> type_regular line_content : #{type => regular, text => '$2'}.
 line -> type_warning line_content : #{type => warning, text => '$2'}.

 line_content -> chars : '$1'.
-line_content -> pipe chars : '$1'.
+line_content -> line_content pipe chars : <<'$1'/binary, '$3'/binary>>.
输出:

[%{text: "Look at the error", type: :warning}]
[%{text: "plugin error detected  check the version of the plugin",
   type: :warning}]
[%{text: "a  warning ", type: :warning}, %{text: "a  regular ", type: :regular},
 %{text: "another  regular ", type: :regular},
 %{text: "and another  warning", type: :warning}]

我现在无法测试这一点,但我认为您应该删除
line->pipe line\u内容:'$2'。
并使
line\u内容
处理多行。在PEG-like表示法中,这将是
line\u content=chars(pipe chars)*
,即chars后面跟着0或更多
(pipe chars)
@Dogbert aha好的,谢谢,我尝试搜索解析多行,但没有得到一个好的示例。我会进一步搜索你的建议,已经非常感谢了!我现在没有时间详细讨论这个问题,但几个月前我在旧金山的Erlang/Elixir Conf上用leex/yecc(在Erlang中)做了一个小项目的闪电演讲。这里有幻灯片的链接,结尾有一个参考资料部分,其中有一些我觉得很有用的链接,例如:@JeroenBourgois如果你能在某处上传问题代码的可编译包(Github/Dropbox?),我会尝试做我建议的修改,并让你知道它是否有效。@Dogbert我把这个项目放到github上:谢谢你!关于额外的
[]
,您现在可以在输出中看到最后一项前面有一个
|
(在
iex
输出中),因此列表有问题。使用
Enum
循环时,我遇到了一个错误。这就是我返回并添加括号的原因,因为这应该是使用
[1,2]
[1 |[2]]
构建地图的Erlang代码?我将用您的编辑再次测试。另外,我使用了
\n
而不是实际的新行,但这不重要,对吗?再一次,非常感谢你!啊对。您还应该从
行的第二个子句返回一个列表。我已经编辑了我的答案,成功了!令人惊叹的。我会花一些时间试图理解到底发生了什么,但我想我明白了。下一步:将每一行的内容进一步解析为嵌套节点,因为行本身可以解析为一种映射(日志中有日期:今天、重要性:紧急等条目:)再次感谢!也许我稍后会发布一个新问题。作为一个小的额外问题:你会建议同时测试lexer和解析器,还是解析器就足够了?对两者都进行测试感觉不是那么枯燥,因为lib感兴趣的是某个输入与某个输出匹配,中间值没有那么相关?我会为两者编写测试。lexer测试应该只有几行,但是如果您修改lexer的方式使得它只创建一个解析错误,那么它可能会非常有用。对lexer进行测试将帮助您更快地发现这些错误。
Belino.parse("[!] Look at the error")
Belino.parse("[!] plugin error detected
 | check the version of the plugin")
Belino.parse("[!] a
 | warning
 [ ] a
 | regular
 [ ] another
 | regular
 [!] and another
 | warning")
[%{text: "Look at the error", type: :warning}]
[%{text: "plugin error detected  check the version of the plugin",
   type: :warning}]
[%{text: "a  warning ", type: :warning}, %{text: "a  regular ", type: :regular},
 %{text: "another  regular ", type: :regular},
 %{text: "and another  warning", type: :warning}]