在 Elixir/Erlang 中附加项目以使用 Yecc 解析器进行映射
Append item to map with Yecc parser in Elixir/Erlang
我正在尝试在 Elixir 中使用 Leex/Yecc 解析特定的日志文件。几个小时后,我得到了最简单的方案。但是我想进入下一步,但我不知道该怎么做。
首先,这里有一个日志格式的例子:
[!] plugin error detected
| check the version of the plugin
我的简单尝试只是第一行,但是有多个条目,例如:
[!] plugin error detected
[!] plugin error 2 detected
[!] plugin error 3 detected
这很有效,给了我一张包含文本和日志行类型的漂亮地图(警告):
iex(20)> LogParser.parse("[!] a big warning\n[!] another warning")
[%{text: "a big warning", type: :warning},
%{text: "another warning", type: :warning}]
太完美了。但如上所示,日志行可以在下一行继续,用竖线字符 |
表示。我的词法分析器有管道字符,解析器可以理解它,但我想要的是将下一行附加到我的地图的 text
值。现在它只是作为一个字符串附加在地图中。所以而不是:
[%{text: "a big warning ", type: :warning}, " continues on next line"]
我需要:
[%{text: "a big warning continues on next line", type: :warning}]
我看了网上的例子,但大多数都有非常明确的 'end' 标记,例如结束标记或结束括号,但我仍然不太清楚如何添加属性,因此最终的 AST 是正确的。
为了完整起见,这是我的词法分析器:
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 : [''|['']].
lines -> line : ''.
line -> pipe line_content : ''.
line -> type_regular line_content : #{type => regular, text => ''}.
line -> type_warning line_content : #{type => warning, text => ''}.
line_content -> chars : ''.
line_content -> pipe chars : ''.
chars -> char chars : unicode:characters_to_binary([get_value('')] ++ '').
chars -> char : unicode:characters_to_binary([get_value('')]).
Erlang code.
get_value({_, _, Value}) -> Value.
如果你能走到这一步,谢谢你!如果有人能帮忙,那就更感谢了!
我建议添加一个 line_content
规则来处理由竖线分隔的多行并删除规则 line -> pipe line_content : ''.
.
您在 lines
子句中的 ''
周围也有一个不必要的 []
并且单行子句应该 return 一个与 [=28] 一致的列表=] 前一个子句的值,这样你就不会得到不正确的列表。
有了这四个变化,
-lines -> line lines : [''|['']].
+lines -> line lines : [''|''].
-lines -> line : ''.
+lines -> line : [''].
-line -> pipe line_content : ''.
line -> type_regular line_content : #{type => regular, text => ''}.
line -> type_warning line_content : #{type => warning, text => ''}.
line_content -> chars : ''.
-line_content -> pipe chars : ''.
+line_content -> line_content pipe chars : <<''/binary, ''/binary>>.
我可以很好地解析多行文本:
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}]
我正在尝试在 Elixir 中使用 Leex/Yecc 解析特定的日志文件。几个小时后,我得到了最简单的方案。但是我想进入下一步,但我不知道该怎么做。
首先,这里有一个日志格式的例子:
[!] plugin error detected
| check the version of the plugin
我的简单尝试只是第一行,但是有多个条目,例如:
[!] plugin error detected
[!] plugin error 2 detected
[!] plugin error 3 detected
这很有效,给了我一张包含文本和日志行类型的漂亮地图(警告):
iex(20)> LogParser.parse("[!] a big warning\n[!] another warning")
[%{text: "a big warning", type: :warning},
%{text: "another warning", type: :warning}]
太完美了。但如上所示,日志行可以在下一行继续,用竖线字符 |
表示。我的词法分析器有管道字符,解析器可以理解它,但我想要的是将下一行附加到我的地图的 text
值。现在它只是作为一个字符串附加在地图中。所以而不是:
[%{text: "a big warning ", type: :warning}, " continues on next line"]
我需要:
[%{text: "a big warning continues on next line", type: :warning}]
我看了网上的例子,但大多数都有非常明确的 'end' 标记,例如结束标记或结束括号,但我仍然不太清楚如何添加属性,因此最终的 AST 是正确的。
为了完整起见,这是我的词法分析器:
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 : [''|['']].
lines -> line : ''.
line -> pipe line_content : ''.
line -> type_regular line_content : #{type => regular, text => ''}.
line -> type_warning line_content : #{type => warning, text => ''}.
line_content -> chars : ''.
line_content -> pipe chars : ''.
chars -> char chars : unicode:characters_to_binary([get_value('')] ++ '').
chars -> char : unicode:characters_to_binary([get_value('')]).
Erlang code.
get_value({_, _, Value}) -> Value.
如果你能走到这一步,谢谢你!如果有人能帮忙,那就更感谢了!
我建议添加一个 line_content
规则来处理由竖线分隔的多行并删除规则 line -> pipe line_content : ''.
.
您在 lines
子句中的 ''
周围也有一个不必要的 []
并且单行子句应该 return 一个与 [=28] 一致的列表=] 前一个子句的值,这样你就不会得到不正确的列表。
有了这四个变化,
-lines -> line lines : [''|['']].
+lines -> line lines : [''|''].
-lines -> line : ''.
+lines -> line : [''].
-line -> pipe line_content : ''.
line -> type_regular line_content : #{type => regular, text => ''}.
line -> type_warning line_content : #{type => warning, text => ''}.
line_content -> chars : ''.
-line_content -> pipe chars : ''.
+line_content -> line_content pipe chars : <<''/binary, ''/binary>>.
我可以很好地解析多行文本:
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}]