i was wondering if anyone could help me drawing the syntactic tree of a very very simple instruction in erlang : a simple assignment like A = 2 + 3. using , of course the erlang official grammar available at http://svn.ulf.wiger.net/indent/trunk/erl_parse.yrl
Thanks for everything
You can simply use Erlang own tools:
1> {ok, Toks, _} = erl_scan:string("A=2+3.").
{ok,[{var,1,'A'},
{'=',1},
{integer,1,2},
{'+',1},
{integer,1,3},
{dot,1}],
1}
2> {ok, [AST]} = erl_parse:parse_exprs(Toks).
{ok,[{match,1,
{var,1,'A'},
{op,1,'+',{integer,1,2},{integer,1,3}}}]}
3> AST.
{match,1,{var,1,'A'},{op,1,'+',{integer,1,2},{integer,1,3}}}
Related
I have a list like this one ['a','b','c','d'] and what I need is to add a affix to each item in that list like : ['a#erlang','b#erlang','c#erlang','d#erlang']
I tried using 1lists:foreach1 and then concat two strings to one and then lists:append to the main list, but that didn't work for me.
Example of what I tried:
LISTa = [],
lists:foreach(fun (Item) ->
LISTa = lists:append([Item,<<"#erlang">>])
end,['a','b','c','d'])
Thanks in advance.
1> L = ['a','b','c','d'].
[a,b,c,d]
2> [ list_to_atom(atom_to_list(X) ++ "#erlang") ||X <- L].
[a#erlang,b#erlang,c#erlang,d#erlang]
Please try this code, you can use list_to_atom and atom_to_list.
This will do the trick (using list comprehensions):
1> L = ["a","b","c","d"].
["a","b","c","d"]
2> R = [X ++ "#erlang" || X <- L].
["a#erlang","b#erlang","c#erlang","d#erlang"]
3>
Notice that I changed the atoms for strings; It's discouraged to "create atoms on the fly/dynamically" in Erlang, so I have that framed in my mind. If you still need so, change the implementation a little bit and you are good to go.
NOTE: I'm assuming the concatenation between atoms and binaries is, somehow, something you did not do on purpose.
With language like JS it's really easy to write something like:
var a = 5;
console.log(a + ' times\n');
how can I write the same code with erlang?
If your question is about stringification of any Erlang term, there is ~p in io:format/2,3 function.
A = 5, io:format("~p times~n", [A]).
If you are interested in debugging output, there is also erlang:display/1 function. It works like io:format("~p~n", [X]), true..
I am trying to extend the Erlang Mixer Library (https://github.com/opscode/mixer) to pass the "-spec()." lines for the functions that it is adding to a module. However I am unclear on how erlc places specs into the core erlang code.
I started with a really simple (test) module:
-module(mix1).
-export([square/1]).
-spec(square(number()) -> number()).
square(X) -> X * X.
And compiled it with "erlc +debug_info -S mix1.erl" and got this (module_info functions removed):
{module, mix1}. %% version = 0
{exports, [{module_info,0},{module_info,1},{square,1}]}.
{attributes, []}.
{labels, 7}.
{function, square, 1, 2}.
{label,1}.
{line,[{location,"mix1.erl",7}]}.
{func_info,{atom,mix1},{atom,square},1}.
{label,2}.
{line,[{location,"mix1.erl",8}]}.
{gc_bif,'*',{f,0},1,[{x,0},{x,0}],{x,0}}.
return.
I am trying to figure out how the "-spec()" are translated and I don't see them there, any ideas? What am I missing. The eventual goal here is to use this for a parse transform.
I believe your output is not exactly AST, but some normalized form of AST.
{ok, Forms} = epp:parse_file("mix1.erl",[],[]).
{ok,[{attribute,1,file,{"mix1.erl",1}},
{attribute,1,module,mix1},
{attribute,2,export,[{square,1}]},
{attribute,3,spec,
{{square,1},
[{type,3,'fun',
[{type,3,product,[{type,3,number,[]}]},
{type,3,number,[]}]}]}},
{function,4,square,1,
[{clause,4,
[{var,4,'X'}],
[],
[{op,4,'*',{var,4,'X'},{var,4,'X'}}]}]},
{eof,6}]}
I work in erlang
Now, I have a big problem
I want to have a log from a table mnesia and this log should be write in excel file
So the goal is write data from table mnesia to the excel file
I think and this is related to some code find in this forum that the best way is to write .txt file then transfer data from .txt file to excel file
I find this code in this forum in this link.
exporttxt()->
F = fun(T) -> mnesia:foldl(fun(X,Acc) -> [X|Acc] end, [],T) end,
{atomic,L} = mnesia:transaction(F(user)),
file:write_file("test.txt",[io_lib:format("~p\t~p\t~p~n",[F1,F2,F3]) ||
#user{id = F1,adress = F2,birthday = F3} <- L]).
But this code produces an error
As commented, the problem is clearly explained in the link itself. If you want the code then here it is. But please understand before directly jumping into the code.
exporttxt()->
F = fun() -> mnesia:foldl(fun(X,Acc) -> [X|Acc] end, [],user) end,
{atomic,L} = mnesia:transaction(F),
file:write_file("test.txt",[io_lib:format("~p\t~p\t~p~n",[F1,F2,F3]) ||
#user{id = F1,adress = F2,birthday = F3} <- L]).
in the subject you mention, I said that I didn't test the code, and of course there was a syntax error.
Here is a code that run.
1> ok = mnesia:create_schema([node()]).
ok
2> rd(my_user,{firstname,lastname,age}).
my_user
3> ok =application:start(mnesia).
ok
4> {atomic,ok} = mnesia:create_table(my_user,[{attributes,record_info(fields,my_user)},{disc_copies,[node()]},{type,bag}]).
{atomic,ok}
5> Add_user = fun(Fn,Ln,Ag) ->
5> F = fun() -> mnesia:write(my_user,#my_user{firstname=Fn,lastname=Ln,age=Ag},write) end,
5> mnesia:activity(transaction,F)
5> end.
#Fun<erl_eval.18.82930912>
6> ok = Add_user("Georges","Boy",25).
ok
7> ok = Add_user("Joe","Armstrong",52).
ok
8> ok = Add_user("Pascal","Me",55).
ok
9> F = fun(T) -> mnesia:foldl(fun(X,Acc) -> [X|Acc] end, [],T) end.
#Fun<erl_eval.6.82930912>
10> {atomic,L} = mnesia:transaction(F,[my_user]).
{atomic,[#my_user{firstname = "Pascal",lastname = "Me",
age = 55},
#my_user{firstname = "Joe",lastname = "Armstrong",age = 52},
#my_user{firstname = "Georges",lastname = "Boy",age = 25}]}
11> ok = file:write_file("test.txt",[io_lib:format("~p\t~p\t~p~n",[F1,F2,F3]) || #my_user{firstname = F1, lastname = F2, age = F3} <- L]).
ok
12>
you will have in your working directory a file named test.txt containing
"Pascal" "Me" 55
"Joe" "Armstrong" 52
"Georges" "Boy" 25
and if you open it with excel you will get
But this is not a code sequence you should use directly.
line 1 should take place in a code use for the deployment of your application.
line 2 is a record definition, necessary for the shell to understand the next lines. It should be replaced by a -record(...) in a module or an included file.
lines 3 and 4 should take place in the init function of one of the higher level supervisor (with some test to check already started application, existing table...)
line 5 should be in the interface definition of a server
line 6,7,8 should be generated by a user interface in some client
and last line 9,10,11 in another interface (for admin?).
Message to Lost_with_coding and his fellows,
If I may give you my opinion, you are burning steps. You should focus on mastering the Erlang syntax, the concept of pattern matching and variable bounding... after you should look at more advance construction such as list and binary comprehensions. Take time to look at error messages and use them to solve simple problems. The official Erlang documentation is great for this purpose. I always have it open in my browser and sometimes I also use this link http://erldocs.com/R15B/ when I look for function I don't know.
Next will come higher order functions, error handling, processes, concurrency, OTP... plus the usage of the efficient but not sexy Erlang tools (tv, appmon, debugger...).
I recommend it very often, but use the fantastic Fred Hebert's web site http://learnyousomeerlang.com/ and follow it step by step, rewriting the code, not copy/paste; it really worths the effort.
I would like to convert a string containing a valid Erlang expression to its abstract syntax tree representation, without any success so far.
Below is an example of what I would like to do. After compiling, alling z:z(). generates module zed, which by calling zed:zed(). returns the result of applying lists:reverse on the given list.
-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 could be "[1,2,3].", or "begin A=4, B=2+3, [A,B] end.", or anything alike.
(Note that this is just an example of what I would like to do, so evaluating String is not an option for me.)
EDIT:
Specifying ListAST as below generates a huge dict-digraph-error-monster, and says "internal error in lint_module".
String = "[1,2,3].",
{ok, Ts, _} = erl_scan:string(String),
{ok, ListAST} = erl_parse:parse_exprs(Ts),
EDIT2:
This solution works for simple terms:
{ok, Ts, _} = erl_scan:string(String),
{ok, Term} = erl_parse:parse_term(Ts),
ListAST = erl_syntax:abstract(Term),
In your EDIT example:
String = "[1,2,3].",
{ok, Ts, _} = erl_scan:string(String),
{ok, ListAST} = erl_parse:parse_exprs(Ts),
the ListAST is actually a list of AST:s (because parse_exprs, as the name indicates, parses multiple expressions (each terminated by a period). Since your string contained a single expression, you got a list of one element. All you need to do is match that out:
{ok, [ListAST]} = erl_parse:parse_exprs(Ts),
so it has nothing to do with erl_syntax (which accepts all erl_parse trees); it's just that you had an extra list wrapper around the ListAST, which caused the compiler to puke.
Some comments of the top of my head.
I have not really used the erl_syntax libraries but I do think they make it difficult to read and "see" what you are trying to build. I would probably import the functions or define my own API to make it shorter and more legible. But then I generally tend to prefer shorter function and variable names.
The AST created by erl_syntax and the "standard" one created by erl_parse and used in the compiler are different and cannot be mixed. So you have to choose one of them and stick with it.
The example in your second EDIT will work for terms but not in the more general case:
{ok, Ts, _} = erl_scan:string(String),
{ok, Term} = erl_parse:parse_term(Ts),
ListAST = erl_syntax:abstract(Term),
This because erl_parse:parse_term/1 returns the actual term represented by the tokens while the other erl_parse functions parse_form and parse_exprs return the ASTs. Putting them into erl_syntax:abstract will do funny things.
Depending on what you are trying to do it might actually be easier to actually write out and erlang file and compile it rather than working directly with the abstract forms. This goes against my ingrained feelings but generating the erlang ASTs is not trivial. What type of code do you intend to produce?
<shameless_plug>
If you are not scared of lists you might try using LFE (lisp flavoured erlang) to generate code as with all lisps there is no special abstract form, it's all homoiconic and much easier to work with.
</shameless_plug>
Zoltan
This is how we get the 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>