Parsing Erlang中的递归下降解析器

Parsing Erlang中的递归下降解析器,parsing,recursion,erlang,Parsing,Recursion,Erlang,我正试图在Erlang中构造一个RDP。到目前为止,我已经读取并处理了一个令牌文件,我将以eg[2,6,3,7,3,2,4,6,3,2,4,4,99](应该可以工作的示例输入)的形式传递给函数,我需要确保通过将默认规则[bexp0]转换为一些匹配的终端列表,可以派生出每个字符(或一组) get_terminal_list() -> [1,2,3,4,5,6,7,8,9,10,11,12,99]. get_prod_list() -> [bexp0,bexp,bexp1,bt

我正试图在Erlang中构造一个RDP。到目前为止,我已经读取并处理了一个令牌文件,我将以eg[2,6,3,7,3,2,4,6,3,2,4,4,99](应该可以工作的示例输入)的形式传递给函数,我需要确保通过将默认规则[bexp0]转换为一些匹配的终端列表,可以派生出每个字符(或一组)

get_terminal_list() ->
    [1,2,3,4,5,6,7,8,9,10,11,12,99].

get_prod_list() ->
[bexp0,bexp,bexp1,bterm].

get_sym_list(Prod) ->
    case Prod of
        bexp0 -> [[bexp,99]];
        bexp  -> [[bterm,bexp1]];
        bexp1 -> [[5,bexp,bexp1],[6,bexp,bexp1]];
        bterm -> [[3,bexp,4],[2],[8],[9],[2,10,1],[2,12,1],[2,11,1],[7,bterm]]
    end.
get_sym_list显示正在使用的语法-其中每个int代表一个终端字符,每个子列表是一个集合,即bterm->[[7,bterm]]意味着bterm可以变成终端“7”,后跟非终端“bterm”

现在我正在努力实现这一点:

Check if first set of rule has some terminal
 if so, check which side, reduce list of tokens from same side until first occurrence of this token,  
     parse this new list (w/o token) with rest of the set of this rule (also without the matched terminal). 
       return {success|failure, list_of_tokens, list_of_rules}  
   if success -> check with new list_of_tokens, default_rule
   if failure, check with old list_of_tokens, and new list_of_rules.
如果规则列表为空,我假设将达到最终状态-因此我们已用尽所有可能的生产,因此无效,或

令牌列表为空,因此我们已将每个令牌/令牌集匹配到某个规则

这可能会满足您的要求:

-module(parse).
-export([parse1/0, parse1/1, parse2/0, parse2/1]).

parse1() ->
    parse([bexp], [2,6,3,7,3,2,4,6,3,2,4,4,99], fun get_sym_list1/1).

parse1(Input) ->
    parse([bexp], Input, fun get_sym_list1/1).


parse2() ->
    parse([bexp0], [2,6,3,7,3,2,4,6,3,2,4,4,99], fun get_sym_list2/1).

parse2(Input) ->
    parse([bexp0], Input, fun get_sym_list2/1).


parse([], [], _) ->
    true;
parse([], _, _) ->
    false;
parse([X | TX], [X | TY], Fun) ->
    io:format("+ Current:~w\tTokens:~w Input:~w~n", [X, TX, TY]),
    parse(TX, TY, Fun);
parse([X | TX], Input, Fun) ->
    io:format("  Current:~w\tTokens:~w Input:~w~n", [X, TX, Input]),
    case lists:member(X, get_terminal_list()) of
        true -> false;
        false -> lists:any(fun(T) -> parse(T ++ TX, Input, Fun) end, Fun(X))
    end.

get_terminal_list() ->
    [1,2,3,4,5,6,7,8,9,10,11,12,99].

get_sym_list1(Prod) ->
    case Prod of
        bexp    -> [[bexp1],[bterm],[bterm,bexp2]];
        bexp1   -> [[99]];
        bexp2   -> [[5,bterm,bexp2],[6,bterm,bexp2]];
        bterm   -> [[bfactor],[7,bterm]];
        bfactor -> [[3,bexp,4],[bconst],[2,10,1],[2,12,1],[2,11,1],[2]];
        bconst  -> [[8],[9]]
    end.

get_sym_list2(Prod) ->
    case Prod of
        bexp0 -> [[bterm,bexp1]];
        bexp  -> [[bterm,bexp1]];
        bexp1 -> [[5,u1],[6,bexp,bexp1],[99]];
        bterm -> [[u1,4],[2],[8],[9],[2,10,1],[2,12,1],[2,11,1],[7,bterm]];
        u1    -> [[3,bexp]]
    end.
但是,看起来语法或输入列表不正确,因为就我所见,旧语法和新语法都不会解析输入。它似乎工作正常,因为它将解析如下输入:

41> parse:parse2([2,6,8,5,3,bterm,5,3,9,99,99]).
  Current:bexp0 Tokens:[] Input:[2,6,8,5,3,bterm,5,3,9,99,99]
  Current:bterm Tokens:[bexp1] Input:[2,6,8,5,3,bterm,5,3,9,99,99]
  Current:u1    Tokens:[4,bexp1] Input:[2,6,8,5,3,bterm,5,3,9,99,99]
  Current:3     Tokens:[bexp,4,bexp1] Input:[2,6,8,5,3,bterm,5,3,9,99,99]
+ Current:2     Tokens:[bexp1] Input:[6,8,5,3,bterm,5,3,9,99,99]
  Current:bexp1 Tokens:[] Input:[6,8,5,3,bterm,5,3,9,99,99]
  Current:5     Tokens:[u1] Input:[6,8,5,3,bterm,5,3,9,99,99]
+ Current:6     Tokens:[bexp,bexp1] Input:[8,5,3,bterm,5,3,9,99,99]
  Current:bexp  Tokens:[bexp1] Input:[8,5,3,bterm,5,3,9,99,99]
  Current:bterm Tokens:[bexp1,bexp1] Input:[8,5,3,bterm,5,3,9,99,99]
  Current:u1    Tokens:[4,bexp1,bexp1] Input:[8,5,3,bterm,5,3,9,99,99]
  Current:3     Tokens:[bexp,4,bexp1,bexp1] Input:[8,5,3,bterm,5,3,9,99,99]
  Current:2     Tokens:[bexp1,bexp1] Input:[8,5,3,bterm,5,3,9,99,99]
+ Current:8     Tokens:[bexp1,bexp1] Input:[5,3,bterm,5,3,9,99,99]
  Current:bexp1 Tokens:[bexp1] Input:[5,3,bterm,5,3,9,99,99]
+ Current:5     Tokens:[u1,bexp1] Input:[3,bterm,5,3,9,99,99]
  Current:u1    Tokens:[bexp1] Input:[3,bterm,5,3,9,99,99]
+ Current:3     Tokens:[bexp,bexp1] Input:[bterm,5,3,9,99,99]
  Current:bexp  Tokens:[bexp1] Input:[bterm,5,3,9,99,99]
+ Current:bterm Tokens:[bexp1,bexp1] Input:[5,3,9,99,99]
  Current:bexp1 Tokens:[bexp1] Input:[5,3,9,99,99]
+ Current:5     Tokens:[u1,bexp1] Input:[3,9,99,99]
  Current:u1    Tokens:[bexp1] Input:[3,9,99,99]
+ Current:3     Tokens:[bexp,bexp1] Input:[9,99,99]
  Current:bexp  Tokens:[bexp1] Input:[9,99,99]
  Current:bterm Tokens:[bexp1,bexp1] Input:[9,99,99]
  Current:u1    Tokens:[4,bexp1,bexp1] Input:[9,99,99]
  Current:3     Tokens:[bexp,4,bexp1,bexp1] Input:[9,99,99]
  Current:2     Tokens:[bexp1,bexp1] Input:[9,99,99]
  Current:8     Tokens:[bexp1,bexp1] Input:[9,99,99]
+ Current:9     Tokens:[bexp1,bexp1] Input:[99,99]
  Current:bexp1 Tokens:[bexp1] Input:[99,99]
  Current:5     Tokens:[u1,bexp1] Input:[99,99]
  Current:6     Tokens:[bexp,bexp1,bexp1] Input:[99,99]
+ Current:99    Tokens:[bexp1] Input:[99]
  Current:bexp1 Tokens:[] Input:[99]
  Current:5     Tokens:[u1] Input:[99]
  Current:6     Tokens:[bexp,bexp1] Input:[99]
+ Current:99    Tokens:[] Input:[]
true

顺便说一句,
true
表示输入已被解析,而
false
表示未被解析。

这可能会满足您的要求:

-module(parse).
-export([parse1/0, parse1/1, parse2/0, parse2/1]).

parse1() ->
    parse([bexp], [2,6,3,7,3,2,4,6,3,2,4,4,99], fun get_sym_list1/1).

parse1(Input) ->
    parse([bexp], Input, fun get_sym_list1/1).


parse2() ->
    parse([bexp0], [2,6,3,7,3,2,4,6,3,2,4,4,99], fun get_sym_list2/1).

parse2(Input) ->
    parse([bexp0], Input, fun get_sym_list2/1).


parse([], [], _) ->
    true;
parse([], _, _) ->
    false;
parse([X | TX], [X | TY], Fun) ->
    io:format("+ Current:~w\tTokens:~w Input:~w~n", [X, TX, TY]),
    parse(TX, TY, Fun);
parse([X | TX], Input, Fun) ->
    io:format("  Current:~w\tTokens:~w Input:~w~n", [X, TX, Input]),
    case lists:member(X, get_terminal_list()) of
        true -> false;
        false -> lists:any(fun(T) -> parse(T ++ TX, Input, Fun) end, Fun(X))
    end.

get_terminal_list() ->
    [1,2,3,4,5,6,7,8,9,10,11,12,99].

get_sym_list1(Prod) ->
    case Prod of
        bexp    -> [[bexp1],[bterm],[bterm,bexp2]];
        bexp1   -> [[99]];
        bexp2   -> [[5,bterm,bexp2],[6,bterm,bexp2]];
        bterm   -> [[bfactor],[7,bterm]];
        bfactor -> [[3,bexp,4],[bconst],[2,10,1],[2,12,1],[2,11,1],[2]];
        bconst  -> [[8],[9]]
    end.

get_sym_list2(Prod) ->
    case Prod of
        bexp0 -> [[bterm,bexp1]];
        bexp  -> [[bterm,bexp1]];
        bexp1 -> [[5,u1],[6,bexp,bexp1],[99]];
        bterm -> [[u1,4],[2],[8],[9],[2,10,1],[2,12,1],[2,11,1],[7,bterm]];
        u1    -> [[3,bexp]]
    end.
但是,看起来语法或输入列表不正确,因为就我所见,旧语法和新语法都不会解析输入。它似乎工作正常,因为它将解析如下输入:

41> parse:parse2([2,6,8,5,3,bterm,5,3,9,99,99]).
  Current:bexp0 Tokens:[] Input:[2,6,8,5,3,bterm,5,3,9,99,99]
  Current:bterm Tokens:[bexp1] Input:[2,6,8,5,3,bterm,5,3,9,99,99]
  Current:u1    Tokens:[4,bexp1] Input:[2,6,8,5,3,bterm,5,3,9,99,99]
  Current:3     Tokens:[bexp,4,bexp1] Input:[2,6,8,5,3,bterm,5,3,9,99,99]
+ Current:2     Tokens:[bexp1] Input:[6,8,5,3,bterm,5,3,9,99,99]
  Current:bexp1 Tokens:[] Input:[6,8,5,3,bterm,5,3,9,99,99]
  Current:5     Tokens:[u1] Input:[6,8,5,3,bterm,5,3,9,99,99]
+ Current:6     Tokens:[bexp,bexp1] Input:[8,5,3,bterm,5,3,9,99,99]
  Current:bexp  Tokens:[bexp1] Input:[8,5,3,bterm,5,3,9,99,99]
  Current:bterm Tokens:[bexp1,bexp1] Input:[8,5,3,bterm,5,3,9,99,99]
  Current:u1    Tokens:[4,bexp1,bexp1] Input:[8,5,3,bterm,5,3,9,99,99]
  Current:3     Tokens:[bexp,4,bexp1,bexp1] Input:[8,5,3,bterm,5,3,9,99,99]
  Current:2     Tokens:[bexp1,bexp1] Input:[8,5,3,bterm,5,3,9,99,99]
+ Current:8     Tokens:[bexp1,bexp1] Input:[5,3,bterm,5,3,9,99,99]
  Current:bexp1 Tokens:[bexp1] Input:[5,3,bterm,5,3,9,99,99]
+ Current:5     Tokens:[u1,bexp1] Input:[3,bterm,5,3,9,99,99]
  Current:u1    Tokens:[bexp1] Input:[3,bterm,5,3,9,99,99]
+ Current:3     Tokens:[bexp,bexp1] Input:[bterm,5,3,9,99,99]
  Current:bexp  Tokens:[bexp1] Input:[bterm,5,3,9,99,99]
+ Current:bterm Tokens:[bexp1,bexp1] Input:[5,3,9,99,99]
  Current:bexp1 Tokens:[bexp1] Input:[5,3,9,99,99]
+ Current:5     Tokens:[u1,bexp1] Input:[3,9,99,99]
  Current:u1    Tokens:[bexp1] Input:[3,9,99,99]
+ Current:3     Tokens:[bexp,bexp1] Input:[9,99,99]
  Current:bexp  Tokens:[bexp1] Input:[9,99,99]
  Current:bterm Tokens:[bexp1,bexp1] Input:[9,99,99]
  Current:u1    Tokens:[4,bexp1,bexp1] Input:[9,99,99]
  Current:3     Tokens:[bexp,4,bexp1,bexp1] Input:[9,99,99]
  Current:2     Tokens:[bexp1,bexp1] Input:[9,99,99]
  Current:8     Tokens:[bexp1,bexp1] Input:[9,99,99]
+ Current:9     Tokens:[bexp1,bexp1] Input:[99,99]
  Current:bexp1 Tokens:[bexp1] Input:[99,99]
  Current:5     Tokens:[u1,bexp1] Input:[99,99]
  Current:6     Tokens:[bexp,bexp1,bexp1] Input:[99,99]
+ Current:99    Tokens:[bexp1] Input:[99]
  Current:bexp1 Tokens:[] Input:[99]
  Current:5     Tokens:[u1] Input:[99]
  Current:6     Tokens:[bexp,bexp1] Input:[99]
+ Current:99    Tokens:[] Input:[]
true


顺便说一句,
true
表示输入已被解析,而
false
表示未被解析。

Upvote,因为它在erlang中。您可以添加一个您试图解析的输入的示例吗?到底是什么不起作用?“您是否遇到错误,或者算法似乎没有产生您所期望的结果(在这种情况下,请说明您所期望的结果),或者其他什么?”Amiramix向问题添加了示例输入。目前我认为它进入了一个循环,或者在它到达一个列表的产品时出现了一个错误。谢谢,但是看起来你的函数需要两个列表作为初始参数,而不是一个:list和NT。您提供了一个列表作为示例输入。@Amiramix是的,第二个列表是我最初调用函数时直接发送给函数的单个原子的列表,[bexp]Upvote,因为它在erlang中。您能添加一个您试图解析的输入示例吗?到底是什么不起作用?“您是否遇到错误,或者算法似乎没有产生您所期望的结果(在这种情况下,请说明您所期望的结果),或者其他什么?”Amiramix向问题添加了示例输入。目前我认为它进入了一个循环,或者在它到达一个列表的产品时出现了一个错误。谢谢,但是看起来你的函数需要两个列表作为初始参数,而不是一个:list和NT。您提供了一个列表作为示例输入。@Amiramix是的,第二个列表是一个单个原子的列表,当我最初调用它时,我直接将其发送给函数,[bexp]这是一个漂亮的人,大约7行的解析器。我正在重新修改语法,也许我能一次把它弄好,但示例输入是正确的。是的,Erlang中的代码非常简洁,这正是我喜欢的。我很高兴它终于成功了。顺便说一句,它可能与您手头的项目无关,但一般来说,Erlang支持使用yecc和leex的适当解析器和标记化器,因此您可能会在某个时候对此进行研究。从长生不老药的角度来看,这里有一个很好的描述如何使用它,但仍然很值得一读:可能是发生了什么导致了错误的是6必须由一个B项前置,所以如果案例失败,我们可能必须一起检查这对吗?我也更新了规则,但除了确保99必须位于输入流的末尾之外,没有什么特别的更改。我建议您从根符号开始,然后用生产符号替换令牌,并确保每次停止时输入都正确解析。如果语法是从上到下解析的,那么从下到上调试解析的语法是相当困难的。这是一个漂亮的人,一个大约7行的解析器。我正在重新修改语法,也许我能一次把它弄好,但示例输入是正确的。是的,Erlang中的代码非常简洁,这正是我喜欢的。我很高兴它终于成功了。顺便说一句,它可能与您手头的项目无关,但一般来说,Erlang支持使用yecc和leex的适当解析器和标记化器,因此您可能会在某个时候对此进行研究。从长生不老药的角度来看,这里有一个很好的描述如何使用它,但仍然很值得一读:可能是发生了什么导致了错误的是6必须由一个B项前置,所以如果案例失败,我们可能必须一起检查这对吗?我也更新了规则,但除了确保99必须位于输入流的末尾之外,没有什么特别的更改。我建议您从根符号开始,然后用生产符号替换令牌,并确保每次停止时输入都正确解析。如果语法是从上到下解析的,那么从下到上调试解析的语法是相当困难的。