erl_parse:parse_form 我做错了什么?

What am I doing wrong with erl_parse:parse_form?

我写了一个Hello-World模块,编译成功。然后我尝试通过使用 erl_scan 和 erl_parse.

来学习幕后的东西
-module(useless).                                                    
-export([hello/0]).                                               

hello() -> io:format("hello world\n").

然后我输入 erl shell

{ok, S} = file:read_file("useless.erl").

{ok, T, _} = erl_scan:string(binary_to_list(S)).

显然效果很好。但是当我尝试 erl_parse:parse_form(T).

给出{error,{2,erl_parse,["syntax error before: ","'-'"]}}

我做错了什么?

编辑: 模块 compile 很有帮助。

this很酷。

函数 erl_parse:parse_form/1 仅适用于一种形式。所以你必须先将 erl_scan:string/1 的结果拆分成单独的形式。

你可以使用 erl_scan:tokens 来实现这个(这段代码很糟糕,但我不确定我是否以正确的方式使用这个函数):

-module(useless).                                                    
-export([eval/1]).                                               

eval(File) -> 
    {ok, B} = file:read_file(File),
    Forms = scan(erl_scan:tokens([],binary_to_list(B),1),[]),
    F = fun(X) -> {ok,Y} = erl_parse:parse_form(X), Y end,
    [F(X) || X <- Forms].

scan({done,{ok,T,N},S},Res) ->
    scan(erl_scan:tokens([],S,N),[T|Res]);
scan(_,Res) ->
    lists:reverse(Res).

Robert 建议使用 erl_scan:tokens/3 的可重入特性。 这个函数的文档并不明确,我花了一些时间才明白初始字符串需要被 eof 关闭。 (如果不是,令牌函数将运行无限循环)。

这是我最终想出的代码,希望对其他人有所帮助。

eval(File)->
    {ok, Data} = file:read_file(File),
    String=erlang:binary_to_list(Data),
    scan(String).

scan(String) when is_list(String)->
    scan(String++eof,[]). %% appended eof

scan({done, Result, LeftOverChars},Acc)->
    scan_done(Result,LeftOverChars,Acc);
scan({more, Continuation},Acc)->
    scan(erl_scan:tokens(Continuation,[],1),Acc);
scan(String,Acc) when is_list(String)->
    scan(erl_scan:tokens([],String,1),Acc).

scan_done({error,ErrorMsg,_Location},_LeftOverChars,_Acc)->
    ErrorMsg;
scan_done({eof,Location},LeftOverChars,Acc)->
    Acc;
scan_done({ok,Tokens,Location},LeftOverChars,Acc)->
    case erl_parse:parse_form(Tokens) of
    {ok,R}->scan(LeftOverChars,Acc++[R]);
    {error,R}->scan(LeftOverChars,R)
    end.