代码之家  ›  专栏  ›  技术社区  ›  Zed

字符串到抽象语法树

  •  10
  • Zed  · 技术社区  · 15 年前

    下面是我想做的一个例子。编译后,alling z:z(). 生成模块 zed ,通过打电话 zed:zed(). lists:reverse 在给定的列表上。

    -module(z).
    -export([z/0]).
    
    z() ->
      ModuleAST = erl_syntax:attribute(erl_syntax:atom(module),
                                       [erl_syntax:atom("zed")]),
    
      ExportAST = erl_syntax:attribute(erl_syntax:atom(export),
                                       [erl_syntax:list(
                                        [erl_syntax:arity_qualifier(
                                         erl_syntax:atom("zed"),
                                         erl_syntax:integer(0))])]),
    
      %ListAST = ?(String),  % This is where I would put my AST
      ListAST = erl_syntax:list([erl_syntax:integer(1), erl_syntax:integer(2)]),
    
      FunctionAST = erl_syntax:function(erl_syntax:atom("zed"),
                                        [erl_syntax:clause(
                                         [], none,
                                         [erl_syntax:application(
                                            erl_syntax:atom(lists),
                                            erl_syntax:atom(reverse),
                                            [ListAST]
                        )])]),
    
      Forms = [erl_syntax:revert(AST) || AST <- [ModuleAST, ExportAST, FunctionAST]],
    
      case compile:forms(Forms) of
        {ok,ModuleName,Binary}           -> code:load_binary(ModuleName, "z", Binary);
        {ok,ModuleName,Binary,_Warnings} -> code:load_binary(ModuleName, "z", Binary)
      end.
    

    String 可以是 "[1,2,3]." "begin A=4, B=2+3, [A,B] end."

    (请注意,这只是我想做的一个例子,因此 一串 这不是我的选择。)


    :

    String = "[1,2,3].",
    {ok, Ts, _} = erl_scan:string(String),
    {ok, ListAST} = erl_parse:parse_exprs(Ts),
    

    编辑2 :

    {ok, Ts, _} = erl_scan:string(String),
    {ok, Term} = erl_parse:parse_term(Ts),
    ListAST = erl_syntax:abstract(Term),
    
    3 回复  |  直到 5 年前
        1
  •  5
  •   RichardC    15 年前

    String = "[1,2,3].",
    {ok, Ts, _} = erl_scan:string(String),
    {ok, ListAST} = erl_parse:parse_exprs(Ts),
    

    ListAST实际上是一个AST:s的列表(因为parse_exprs,顾名思义,解析多个表达式(每个表达式以句点结尾)。由于字符串包含一个表达式,因此得到了一个元素列表。您所需要做的就是匹配:

    {ok, [ListAST]} = erl_parse:parse_exprs(Ts),
    

        2
  •  3
  •   rvirding    15 年前

    我脑子里的一些评论。

    我没有真正使用erl_语法库,但我确实认为它们使阅读和“查看”您试图构建的内容变得困难。我可能会导入函数或定义自己的API,以使其更短、更清晰。但我通常倾向于选择较短的函数名和变量名。

    由erl_语法创建的AST和由erl_parse创建并在编译器中使用的“标准”AST是不同的 混合。所以你必须从中选择一个并坚持下去。

    第二次编辑中的示例适用于术语,但不适用于更一般的情况:

    {ok, Ts, _} = erl_scan:string(String),
    {ok, Term} = erl_parse:parse_term(Ts),
    ListAST = erl_syntax:abstract(Term),
    

    这是因为erl_parse:parse_term/1返回由令牌表示的实际术语,而其他erl_parse函数parse_form和parse_expr返回AST。把它们放到erl_语法中:抽象会做一些有趣的事情。

    <shameless_plug>

    </shameless_plug>

        3
  •  2
  •   Gordon Guthrie    15 年前

    佐尔坦

    以下是我们获取AST的方式:

    11> String = "fun() -> io:format(\"blah~n\") end.".
    "fun() -> io:format(\"blah~n\") end."
    12> {ok, Tokens, _} = erl_scan:string(String).     
    {ok,[{'fun',1},
         {'(',1},
         {')',1},
         {'->',1},
         {atom,1,io},
         {':',1},
         {atom,1,format},
         {'(',1},
         {string,1,"blah~n"},
         {')',1},
         {'end',1},
         {dot,1}],
        1}
    13> {ok, AbsForm} = erl_parse:parse_exprs(Tokens). 
    {ok,[{'fun',1,
                {clauses,[{clause,1,[],[],
                                  [{call,1,
                                         {remote,1,{atom,1,io},{atom,1,format}},
                                         [{string,1,"blah~n"}]}]}]}}]}
    14>