10

有効なErlang式を含む文字列をその抽象構文ツリー表現に変換したいのですが、これまでのところ成功していません。

以下は私がやりたいことの例です。コンパイル後、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は私にとって選択肢ではないことに注意してください。)


編集

以下のようにListASTを指定すると、巨大なdict-digraph-error-monsterが生成され、「lint_moduleの内部エラー」と表示されます。

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

EDIT2

このソリューションは、簡単な用語で機能します。

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

3 に答える 3

5

EDITの例では:

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

ListASTは実際にはAST:のリストです(名前が示すように、parse_exprsは複数の式を解析します(それぞれがピリオドで終了します)。文字列には単一の式が含まれているため、1つの要素のリストが得られます。それを一致させることです:

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

したがって、erl_syntax(すべてのerl_parseツリーを受け入れる)とは何の関係もありません。ListASTの周りに余分なリストラッパーがあり、コンパイラーが吐き出しただけです。

于 2009-12-30T15:07:41.357 に答える
3

私の頭のてっぺんのいくつかのコメント。

私は実際にはerl_syntaxライブラリを使用していませんが、作成しようとしているものを読んだり「見たり」するのが難しくなっていると思います。関数をインポートするか、独自のAPIを定義して、短くて読みやすくします。しかし、私は一般的に短い関数名と変数名を好む傾向があります。

erl_syntaxによって作成されたASTとerl_parseによって作成され、コンパイラーで使用される「標準」のものは異なり、混合することはできません。したがって、それらの1つを選択し、それに固執する必要があります。

2番目のEDITの例は、用語に対しては機能しますが、より一般的な場合には機能しません。

{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_exprsはASTを返すためです。それらをerl_syntax:abstractに入れると、面白いことができます。

何をしようとしているのかによっては、抽象フォームを直接操作するよりも、実際にファイルを書き出してerlangファイルを作成してコンパイルする方が実際には簡単な場合があります。これは私の根深い感情に反しますが、erlangASTを生成することは簡単ではありません。どのような種類のコードを作成する予定ですか?

<shameless_plug>

リストが怖くない場合は、LFE(lispフレーバーerlang)を使用してコードを生成してみてください。すべてのlispと同様に、特別な抽象形式はありません。すべて同像性であり、操作がはるかに簡単です。

</shameless_plug>

于 2009-12-31T01:40:12.927 に答える
2

ゾルタン

これが私たちが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> 
于 2009-12-29T11:54:57.743 に答える