First iteration of assembler.
This commit is contained in:
parent
5878ef3e9b
commit
c4adf27a6e
@ -9,3 +9,11 @@
|
|||||||
{plt_apps, all_deps},
|
{plt_apps, all_deps},
|
||||||
{base_plt_apps, [erts, kernel, stdlib]}
|
{base_plt_apps, [erts, kernel, stdlib]}
|
||||||
]}.
|
]}.
|
||||||
|
|
||||||
|
{relx, [{release, {aessembler, "0.0.1"},
|
||||||
|
[aebytecode]},
|
||||||
|
|
||||||
|
{dev_mode, true},
|
||||||
|
{include_erts, false},
|
||||||
|
|
||||||
|
{extended_start_script, true}]}.
|
@ -60,7 +60,7 @@ format(Asm) -> format(Asm, 0).
|
|||||||
format([{comment, Comment} | Rest], Address) ->
|
format([{comment, Comment} | Rest], Address) ->
|
||||||
";; " ++ Comment ++ "\n" ++ format(Rest, Address);
|
";; " ++ Comment ++ "\n" ++ format(Rest, Address);
|
||||||
format([Mnemonic | Rest], Address) ->
|
format([Mnemonic | Rest], Address) ->
|
||||||
_Op = aefa_opcodes:m_to_op(Mnemonic),
|
_Op = aefa_opcode:m_to_op(Mnemonic),
|
||||||
" " ++ atom_to_list(Mnemonic) ++ "\n"
|
" " ++ atom_to_list(Mnemonic) ++ "\n"
|
||||||
++ format(Rest, Address + 1);
|
++ format(Rest, Address + 1);
|
||||||
format([],_) -> [].
|
format([],_) -> [].
|
||||||
@ -79,7 +79,9 @@ file(Filename, Options) ->
|
|||||||
ok
|
ok
|
||||||
end,
|
end,
|
||||||
|
|
||||||
ByteList = to_bytecode(Tokens, 0, #{}, [], Options),
|
Env = to_bytecode(Tokens, none, #{}, [], Options),
|
||||||
|
|
||||||
|
ByteList = serialize(Env),
|
||||||
|
|
||||||
case proplists:lookup(pp_hex_string, Options) of
|
case proplists:lookup(pp_hex_string, Options) of
|
||||||
{pp_hex_string, true} ->
|
{pp_hex_string, true} ->
|
||||||
@ -88,19 +90,27 @@ file(Filename, Options) ->
|
|||||||
ok
|
ok
|
||||||
end,
|
end,
|
||||||
|
|
||||||
|
{Env, list_to_binary(ByteList)}.
|
||||||
|
|
||||||
list_to_binary(ByteList).
|
serialize(Env) ->
|
||||||
|
%% TODO: add serialization of immediates
|
||||||
|
%% TODO: add serialization of function definitions
|
||||||
|
Code = [C || {_Name, {_Sig, C}} <- maps:to_list(Env)],
|
||||||
|
Code.
|
||||||
|
|
||||||
to_hexstring(ByteList) ->
|
to_hexstring(ByteList) ->
|
||||||
"0x" ++ lists:flatten(
|
"0x" ++ lists:flatten(
|
||||||
[io_lib:format("~2.16.0b", [X])
|
[io_lib:format("~2.16.0b", [X])
|
||||||
|| X <- ByteList]).
|
|| X <- ByteList]).
|
||||||
|
|
||||||
|
to_bytecode([{function,_line, 'FUNCTION'}|Rest], Address, Env, Code, Opts) ->
|
||||||
|
Env2 = insert_fun(Address, Code, Env),
|
||||||
|
{Fun, Rest2} = to_fun_def(Rest),
|
||||||
|
to_bytecode(Rest2, Fun, Env2, [], Opts);
|
||||||
to_bytecode([{mnemonic,_line, Op}|Rest], Address, Env, Code, Opts) ->
|
to_bytecode([{mnemonic,_line, Op}|Rest], Address, Env, Code, Opts) ->
|
||||||
OpCode = aefa_opcodes:m_to_op(Op),
|
OpCode = aefa_opcode:m_to_op(Op),
|
||||||
OpSize = aefa_opcodes:op_size(OpCode),
|
%% TODO: arguments
|
||||||
to_bytecode(Rest, Address + OpSize, Env, [OpCode|Code], Opts);
|
to_bytecode(Rest, Address, Env, [OpCode|Code], Opts);
|
||||||
to_bytecode([{int,_line, Int}|Rest], Address, Env, Code, Opts) ->
|
to_bytecode([{int,_line, Int}|Rest], Address, Env, Code, Opts) ->
|
||||||
to_bytecode(Rest, Address, Env, [Int|Code], Opts);
|
to_bytecode(Rest, Address, Env, [Int|Code], Opts);
|
||||||
to_bytecode([{hash,_line, Hash}|Rest], Address, Env, Code, Opts) ->
|
to_bytecode([{hash,_line, Hash}|Rest], Address, Env, Code, Opts) ->
|
||||||
@ -109,23 +119,63 @@ to_bytecode([{id,_line, ID}|Rest], Address, Env, Code, Opts) ->
|
|||||||
to_bytecode(Rest, Address, Env, [{ref, ID}|Code], Opts);
|
to_bytecode(Rest, Address, Env, [{ref, ID}|Code], Opts);
|
||||||
to_bytecode([{label,_line, Label}|Rest], Address, Env, Code, Opts) ->
|
to_bytecode([{label,_line, Label}|Rest], Address, Env, Code, Opts) ->
|
||||||
to_bytecode(Rest, Address, Env#{Label => Address}, Code, Opts);
|
to_bytecode(Rest, Address, Env#{Label => Address}, Code, Opts);
|
||||||
to_bytecode([], _Address, Env, Code, Opts) ->
|
to_bytecode([], Address, Env, Code, Opts) ->
|
||||||
|
Env2 = insert_fun(Address, Code, Env),
|
||||||
case proplists:lookup(pp_opcodes, Opts) of
|
case proplists:lookup(pp_opcodes, Opts) of
|
||||||
{pp_opcodes, true} ->
|
{pp_opcodes, true} ->
|
||||||
io:format("opcodes ~p~n", [lists:reverse(Code)]);
|
Ops = [C || {_Name, {_Sig, C}} <- maps:to_list(Env2)],
|
||||||
|
io:format("opcodes ~p~n", [Ops]);
|
||||||
none ->
|
none ->
|
||||||
ok
|
ok
|
||||||
end,
|
end,
|
||||||
|
Env2.
|
||||||
|
|
||||||
|
|
||||||
|
to_fun_def([{id, _, Name}, {'(', _} | Rest]) ->
|
||||||
|
{ArgsType, [{'->', _} | Rest2]} = to_arg_types(Rest),
|
||||||
|
{RetType, Rest3} = to_type(Rest2),
|
||||||
|
{{Name, ArgsType, RetType}, Rest3}.
|
||||||
|
|
||||||
|
to_arg_types([{')', _} | Rest]) -> {[], Rest};
|
||||||
|
to_arg_types(Tokens) ->
|
||||||
|
case to_type(Tokens) of
|
||||||
|
{Type, [{',', _} | Rest]} ->
|
||||||
|
{MoreTypes, Rest2} = to_arg_types(Rest),
|
||||||
|
{[Type|MoreTypes], Rest2};
|
||||||
|
{Type, [{')', _} | Rest]} ->
|
||||||
|
{[Type], Rest}
|
||||||
|
end.
|
||||||
|
|
||||||
|
to_type([{id, _, "integer"} | Rest]) -> {integer, Rest};
|
||||||
|
to_type([{id, _, "boolean"} | Rest]) -> {boolean, Rest};
|
||||||
|
to_type([{id, _, "string"} | Rest]) -> {string, Rest};
|
||||||
|
to_type([{id, _, "address"} | Rest]) -> {address, Rest};
|
||||||
|
to_type([{id, _, "bits"} | Rest]) -> {bits, Rest};
|
||||||
|
to_type([{'{', _}, {id, _, "list"}, {',', _} | Rest]) ->
|
||||||
|
%% TODO: Error handling
|
||||||
|
{ListType, [{'}', _}| Rest2]} = to_type(Rest),
|
||||||
|
{{list, ListType}, Rest2};
|
||||||
|
to_type([{'{', _}, {id, _, "tuple"}, {',', _}, {'[', _} | Rest]) ->
|
||||||
|
%% TODO: Error handling
|
||||||
|
{ElementTypes, [{'}', _}| Rest2]} = to_list_of_types(Rest),
|
||||||
|
{{tuple, ElementTypes}, Rest2};
|
||||||
|
to_type([{'{', _}, {id, _, "map"}, {',', _} | Rest]) ->
|
||||||
|
%% TODO: Error handling
|
||||||
|
{KeyType, [{',', _}| Rest2]} = to_type(Rest),
|
||||||
|
{ValueType, [{'}', _}| Rest3]} = to_type(Rest2),
|
||||||
|
{{map, KeyType, ValueType}, Rest3}.
|
||||||
|
|
||||||
|
to_list_of_types([{']', _} | Rest]) -> {[], Rest};
|
||||||
|
to_list_of_types(Tokens) ->
|
||||||
|
case to_type(Tokens) of
|
||||||
|
{Type, [{',', _} | Rest]} ->
|
||||||
|
{MoreTypes, Rest2} = to_list_of_types(Rest),
|
||||||
|
{[Type|MoreTypes], Rest2};
|
||||||
|
{Type, [{']', _} | Rest]} ->
|
||||||
|
{[Type], Rest}
|
||||||
|
end.
|
||||||
|
|
||||||
PatchedCode = resolve_refs(Code, Env, []),
|
|
||||||
case proplists:lookup(pp_patched_code, Opts) of
|
|
||||||
{pp_patched_code, true} ->
|
|
||||||
io:format("Patched Code: ~p~n", [PatchedCode]);
|
|
||||||
none ->
|
|
||||||
ok
|
|
||||||
end,
|
|
||||||
|
|
||||||
expand_args(PatchedCode).
|
|
||||||
|
|
||||||
%% Also reverses the code (back to unreversed state).
|
%% Also reverses the code (back to unreversed state).
|
||||||
resolve_refs([{ref, ID} | Rest], Env, Code) ->
|
resolve_refs([{ref, ID} | Rest], Env, Code) ->
|
||||||
@ -138,3 +188,7 @@ resolve_refs([],_Env, Code) -> Code.
|
|||||||
expand_args([OP | Rest]) ->
|
expand_args([OP | Rest]) ->
|
||||||
[OP | expand_args(Rest)];
|
[OP | expand_args(Rest)];
|
||||||
expand_args([]) -> [].
|
expand_args([]) -> [].
|
||||||
|
|
||||||
|
insert_fun(none, [], Env) -> Env;
|
||||||
|
insert_fun({Name, Type, RetType}, Code, Env) ->
|
||||||
|
Env#{Name => {{Type, RetType}, lists:reverse(Code)}}.
|
||||||
|
@ -18,13 +18,15 @@ HASH = #{HEXDIGIT}+
|
|||||||
WS = [\000-\s]
|
WS = [\000-\s]
|
||||||
ID = {LOWER}[a-zA-Z0-9_]*
|
ID = {LOWER}[a-zA-Z0-9_]*
|
||||||
|
|
||||||
Rules.
|
|
||||||
{ID} : {token, {id, TokenLine, TokenChars }}.
|
|
||||||
|
|
||||||
NOP : {token, {mnemonic, TokenLine, 'NOP'}}.
|
Rules.
|
||||||
|
%%{ID} : {token, {id, TokenLine, TokenChars }}.
|
||||||
|
|
||||||
RETURN : {token, {mnemonic, TokenLine, 'RETURN'}}.
|
RETURN : {token, {mnemonic, TokenLine, 'RETURN'}}.
|
||||||
CALL : {token, {mnemonic, TokenLine, 'CALL'}}.
|
CALL : {token, {mnemonic, TokenLine, 'CALL'}}.
|
||||||
|
FUNCTION : {token, {function, TokenLine, 'FUNCTION' }}.
|
||||||
|
NOP : {token, {mnemonic, TokenLine, 'NOP'}}.
|
||||||
|
|
||||||
CALL_R : {token, {mnemonic, TokenLine, 'CALL_R'}}.
|
CALL_R : {token, {mnemonic, TokenLine, 'CALL_R'}}.
|
||||||
CALL_T : {token, {mnemonic, TokenLine, 'CALL_T'}}.
|
CALL_T : {token, {mnemonic, TokenLine, 'CALL_T'}}.
|
||||||
CALL_TR : {token, {mnemonic, TokenLine, 'CALL_TR'}}.
|
CALL_TR : {token, {mnemonic, TokenLine, 'CALL_TR'}}.
|
||||||
@ -127,14 +129,15 @@ COMMENT : {token, {mnemonic, TokenLine, 'COMMENT'}}.
|
|||||||
|
|
||||||
|
|
||||||
%% Symbols
|
%% Symbols
|
||||||
|
\-\> : {token, {'->', TokenLine}}.
|
||||||
, : {token, {',', TokenLine}}.
|
, : {token, {',', TokenLine}}.
|
||||||
\. : {token, {'.', TokenLine}}.
|
\. : {token, {'.', TokenLine}}.
|
||||||
\( : {token, {'(', TokenLine}}.
|
\( : {token, {'(', TokenLine}}.
|
||||||
\) : {token, {')', TokenLine}}.
|
\) : {token, {')', TokenLine}}.
|
||||||
\[ : {token, {'[', TokenLine}}.
|
\[ : {token, {'[', TokenLine}}.
|
||||||
\] : {token, {']', TokenLine}}.
|
\] : {token, {']', TokenLine}}.
|
||||||
{ : {token, {'{', TokenLine}}.
|
\{ : {token, {'{', TokenLine}}.
|
||||||
} : {token, {'}', TokenLine}}.
|
\} : {token, {'}', TokenLine}}.
|
||||||
|
|
||||||
|
|
||||||
%% Whitespace ignore
|
%% Whitespace ignore
|
||||||
@ -153,7 +156,7 @@ Erlang code.
|
|||||||
|
|
||||||
-ignore_xref([format_error/1, string/2, token/2, token/3, tokens/2, tokens/3]).
|
-ignore_xref([format_error/1, string/2, token/2, token/3, tokens/2, tokens/3]).
|
||||||
|
|
||||||
-include_lib("aebytecode/include/aeb_opcodes.hrl").
|
-include_lib("aebytecode/include/aefa_opcodes.hrl").
|
||||||
|
|
||||||
|
|
||||||
parse_hex("0x" ++ Chars) -> list_to_integer(Chars, 16).
|
parse_hex("0x" ++ Chars) -> list_to_integer(Chars, 16).
|
||||||
|
@ -27,6 +27,8 @@ mnemonic({comment,_}) -> 'COMMENT' .
|
|||||||
|
|
||||||
m_to_op('NOP') -> ?NOP ;
|
m_to_op('NOP') -> ?NOP ;
|
||||||
m_to_op('COMMENT') -> ?COMMENT("") ;
|
m_to_op('COMMENT') -> ?COMMENT("") ;
|
||||||
m_to_op(Data) when 0=<Data, Data=<255
|
m_to_op('RETURN') -> ?RETURN ;
|
||||||
-> Data .
|
m_to_op('PUSH') -> ?PUSH ;
|
||||||
|
m_to_op('JUMP') -> ?JUMP ;
|
||||||
|
m_to_op(Data) when 0=<Data, Data=<255 -> Data.
|
||||||
|
|
||||||
|
8
test/asm_code/identity.fate
Normal file
8
test/asm_code/identity.fate
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
;; CONTRACT: Identity
|
||||||
|
FUNCTION id(integer) -> integer
|
||||||
|
RETURN
|
||||||
|
|
||||||
|
;; Test the code from the shell
|
||||||
|
;; _build/default/rel/aessembler/bin/aessembler console
|
||||||
|
|
||||||
|
;; aeb_aefa:file("../../../../test/asm_code/identity.fate", []).
|
23
test/asm_code/test.fate
Normal file
23
test/asm_code/test.fate
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
;; CONTRACT: Test
|
||||||
|
FUNCTION id(integer) -> integer
|
||||||
|
RETURN
|
||||||
|
|
||||||
|
FUNCTION jumps() -> integer
|
||||||
|
PUSH 0
|
||||||
|
JUMP 3
|
||||||
|
NOP
|
||||||
|
JUMP 2
|
||||||
|
NOP
|
||||||
|
RETURN
|
||||||
|
NOP
|
||||||
|
JUMP 1
|
||||||
|
|
||||||
|
FUNCTION inc(integer) -> integer
|
||||||
|
INC arg0
|
||||||
|
INC
|
||||||
|
RETURN
|
||||||
|
|
||||||
|
;; Test the code from the shell
|
||||||
|
;; _build/default/rel/aessembler/bin/aessembler console
|
||||||
|
|
||||||
|
;; aeb_aefa:file("../../../../test/asm_code/test.fate", []).
|
Loading…
x
Reference in New Issue
Block a user