我写了一个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很酷。
答案 0 :(得分:3)
函数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).
答案 1 :(得分:0)
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.