From dd1a6a9c3d36762dcb979c15c53f4fe8dc70f734 Mon Sep 17 00:00:00 2001 From: Erik Stenman Date: Thu, 28 Feb 2019 07:55:51 +0100 Subject: [PATCH] Generate tokens in scanner from definitions. --- .gitignore | 1 + Makefile | 6 +- src/aeb_fate_asm_scan.template | 99 ++++++++++++++++ src/aeb_fate_asm_scan.xrl | 207 --------------------------------- src/aeb_fate_generate_ops.erl | 45 +++++-- 5 files changed, 139 insertions(+), 219 deletions(-) create mode 100644 src/aeb_fate_asm_scan.template delete mode 100644 src/aeb_fate_asm_scan.xrl diff --git a/.gitignore b/.gitignore index 385e93a..cccd365 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ rel/example_project .rebar aeb_asm_scan.erl aeb_fate_asm_scan.erl +aeb_fate_asm_scan.xrl _build/ aefateasm include/aeb_fate_opcodes.hrl diff --git a/Makefile b/Makefile index 6153766..071e04c 100644 --- a/Makefile +++ b/Makefile @@ -4,10 +4,10 @@ REBAR ?= rebar3 all: local -local: src/aeb_fate_opcodes.erl src/aeb_fate_code.erl include/aeb_fate_opcodes.hrl +local: src/aeb_fate_opcodes.erl src/aeb_fate_code.erl include/aeb_fate_opcodes.hrl src/aeb_fate_asm_scan.xrl @$(REBAR) as local release -console: src/aeb_fate_opcodes.erl src/aeb_fate_code.erl include/aeb_fate_opcodes.hrl +console: local @$(REBAR) as local shell clean: @@ -34,7 +34,7 @@ test: local ebin/aeb_fate_generate_ops.beam: src/aeb_fate_generate_ops.erl ebin erlc -o $(dir $@) $< -src/aeb_fate_opcodes.erl src/aeb_fate_code.erl include/aeb_fate_opcodes.hrl: ebin/aeb_fate_generate_ops.beam +src/aeb_fate_opcodes.erl src/aeb_fate_code.erl include/aeb_fate_opcodes.hrl src/aeb_fate_asm_scan.xrl: ebin/aeb_fate_generate_ops.beam erl -pa ebin/ -noshell -s aeb_fate_generate_ops gen_and_halt src/ include/ ebin: diff --git a/src/aeb_fate_asm_scan.template b/src/aeb_fate_asm_scan.template new file mode 100644 index 0000000..f894aa5 --- /dev/null +++ b/src/aeb_fate_asm_scan.template @@ -0,0 +1,99 @@ +%%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*- +%%%------------------------------------------------------------------- +%%% @copyright (C) 2019, aeternity Anstalt +%%% @doc +%%% Handling FATE code. +%%% @end +###REPLACEWITHNOTE### +%%%------------------------------------------------------------------- + +Definitions. +DIGIT = [0-9] +HEXDIGIT = [0-9a-fA-F] +LOWER = [a-z_] +UPPER = [A-Z] +INT = {DIGIT}+ +HEX = 0x{HEXDIGIT}+ +HASH = #{HEXDIGIT}+ +WS = [\000-\s] +ID = {LOWER}[a-zA-Z0-9_]* + + +Rules. +arg{INT} : {token, {arg, TokenLine, parse_arg(TokenChars)}}. +var{INT} : {token, {var, TokenLine, parse_var(TokenChars)}}. +a : {token, {stack, TokenLine, 0}}. +a{INT} : {token, {stack, TokenLine, parse_acc(TokenChars)}}. + +true : {token, {boolean, TokenLine, true}}. +false : {token, {boolean, TokenLine, false}}. + +###REPLACEWITHOPTOKENS### + +FUNCTION : {token, {function, TokenLine, 'FUNCTION' }}. + +{ID} : + {token, {id, TokenLine, TokenChars}}. +{HEX} : + {token, {int, TokenLine, parse_hex(TokenChars)}}. +{INT} : + {token, {int, TokenLine, parse_int(TokenChars)}}. +{HASH} : + {token, {hash, TokenLine, parse_hash(TokenChars)}}. + + +%% Symbols +\-\> : {token, {'to', TokenLine}}. +\: : {token, {'to', TokenLine}}. +, : {token, {',', TokenLine}}. +\( : {token, {'(', TokenLine}}. +\) : {token, {')', TokenLine}}. +\[ : {token, {'[', TokenLine}}. +\] : {token, {']', TokenLine}}. +\{ : {token, {'{', TokenLine}}. +\} : {token, {'}', TokenLine}}. + +;;.* : + {token, {comment, TokenLine, drop_prefix($;, TokenChars)}}. + +\. : skip_token. + + +%% Whitespace ignore +{WS} : skip_token. + +%% Comments (TODO: nested comments) + + +. : {error, "Unexpected token: " ++ TokenChars}. + +Erlang code. + +-export([scan/1]). + +-dialyzer({nowarn_function, yyrev/2}). + +-ignore_xref([format_error/1, string/2, token/2, token/3, tokens/2, tokens/3]). + +-include_lib("aebytecode/include/aeb_fate_opcodes.hrl"). + + +parse_hex("0x" ++ Chars) -> list_to_integer(Chars, 16). + +parse_int(Chars) -> list_to_integer(Chars). + +parse_arg("arg" ++ N) -> list_to_integer(N). +parse_var("var" ++ N) -> list_to_integer(N). +parse_acc("a" ++ N) -> list_to_integer(N). + + +parse_hash("#" ++ Chars) -> + N = list_to_integer(Chars, 16), + <>. + +scan(S) -> + string(S). + +drop_prefix(C, [C|Rest]) -> + drop_prefix(C, Rest); +drop_prefix(_, Tail) -> Tail. diff --git a/src/aeb_fate_asm_scan.xrl b/src/aeb_fate_asm_scan.xrl deleted file mode 100644 index 6d10f56..0000000 --- a/src/aeb_fate_asm_scan.xrl +++ /dev/null @@ -1,207 +0,0 @@ -%%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*- -%%%------------------------------------------------------------------- -%%% @copyright (C) 2019, aeternity Anstalt -%%% @doc -%%% Handling FATE code. -%%% @end -%%% Created : 9 Jan 2019 -%%%------------------------------------------------------------------- - -Definitions. -DIGIT = [0-9] -HEXDIGIT = [0-9a-fA-F] -LOWER = [a-z_] -UPPER = [A-Z] -INT = {DIGIT}+ -HEX = 0x{HEXDIGIT}+ -HASH = #{HEXDIGIT}+ -WS = [\000-\s] -ID = {LOWER}[a-zA-Z0-9_]* - - -Rules. -arg{INT} : {token, {arg, TokenLine, parse_arg(TokenChars)}}. -var{INT} : {token, {var, TokenLine, parse_var(TokenChars)}}. -a : {token, {stack, TokenLine, 0}}. -a{INT} : {token, {stack, TokenLine, parse_acc(TokenChars)}}. - -true : {token, {boolean, TokenLine, true}}. -false : {token, {boolean, TokenLine, false}}. - -RETURN : {token, {mnemonic, TokenLine, 'RETURN'}}. -RETURNR : {token, {mnemonic, TokenLine, 'RETURNR'}}. -CALL : {token, {mnemonic, TokenLine, 'CALL'}}. -NOP : {token, {mnemonic, TokenLine, 'NOP'}}. - -CALL_R : {token, {mnemonic, TokenLine, 'CALL_R'}}. -CALL_T : {token, {mnemonic, TokenLine, 'CALL_T'}}. -CALL_TR : {token, {mnemonic, TokenLine, 'CALL_TR'}}. -JUMP : {token, {mnemonic, TokenLine, 'JUMP'}}. -JUMPIF : {token, {mnemonic, TokenLine, 'JUMPIF'}}. -SWITCH_V2 : {token, {mnemonic, TokenLine, 'SWITCH_V2'}}. -SWITCH_V3 : {token, {mnemonic, TokenLine, 'SWITCH_V3'}}. -SWITCH_VN : {token, {mnemonic, TokenLine, 'SWITCH_VN'}}. - -PUSH : {token, {mnemonic, TokenLine, 'PUSH'}}. -DUP : {token, {mnemonic, TokenLine, 'DUP'}}. -DUPA : {token, {mnemonic, TokenLine, 'DUPA'}}. -POP : {token, {mnemonic, TokenLine, 'POP'}}. - -STORE : {token, {mnemonic, TokenLine, 'STORE'}}. - -ADD : {token, {mnemonic, TokenLine, 'ADD'}}. -MUL : {token, {mnemonic, TokenLine, 'MUL'}}. -SUB : {token, {mnemonic, TokenLine, 'SUB'}}. -DIV : {token, {mnemonic, TokenLine, 'DIV'}}. -MOD : {token, {mnemonic, TokenLine, 'MOD'}}. -POW : {token, {mnemonic, TokenLine, 'POW'}}. - -INC : {token, {mnemonic, TokenLine, 'INC'}}. -DEC : {token, {mnemonic, TokenLine, 'DEC'}}. -INCA : {token, {mnemonic, TokenLine, 'INCA'}}. -DECA : {token, {mnemonic, TokenLine, 'DECA'}}. - -LT : {token, {mnemonic, TokenLine, 'LT'}}. -GT : {token, {mnemonic, TokenLine, 'GT'}}. -EQ : {token, {mnemonic, TokenLine, 'EQ'}}. -ELT : {token, {mnemonic, TokenLine, 'ELT'}}. -EGT : {token, {mnemonic, TokenLine, 'EGT'}}. -NEQ : {token, {mnemonic, TokenLine, 'NEQ'}}. - -AND : {token, {mnemonic, TokenLine, 'AND'}}. -OR : {token, {mnemonic, TokenLine, 'OR'}}. -NOT : {token, {mnemonic, TokenLine, 'NOT'}}. - -TUPLE : {token, {mnemonic, TokenLine, 'TUPLE'}}. -ELEMENT : {token, {mnemonic, TokenLine, 'ELEMENT'}}. - -MAP_EMPTY : {token, {mnemonic, TokenLine, 'MAP_EMPTY'}}. -MAP_LOOKUP : {token, {mnemonic, TokenLine, 'MAP_LOOKUP'}}. -MAP_LOOKUPD : {token, {mnemonic, TokenLine, 'MAP_LOOKUPD'}}. -MAP_UPDATE : {token, {mnemonic, TokenLine, 'MAP_UPDATE'}}. -MAP_MEMBER : {token, {mnemonic, TokenLine, 'MAP_MEMBER'}}. -MAP_DELETE : {token, {mnemonic, TokenLine, 'MAP_DELETE'}}. -MAP_FROM_LIST : {token, {mnemonic, TokenLine, 'MAP_FROM_LIST'}}. - -NIL : {token, {mnemonic, TokenLine, 'NIL'}}. -IS_NIL : {token, {mnemonic, TokenLine, 'IS_NIL'}}. -CONS : {token, {mnemonic, TokenLine, 'CONS'}}. -HD : {token, {mnemonic, TokenLine, 'HD'}}. -TL : {token, {mnemonic, TokenLine, 'TL'}}. -LENGTH : {token, {mnemonic, TokenLine, 'LENGTH'}}. - -STR_EQ : {token, {mnemonic, TokenLine, 'STR_EQ'}}. -STR_JOIN : {token, {mnemonic, TokenLine, 'STR_JOIN'}}. -INT_TO_STR : {token, {mnemonic, TokenLine, 'INT_TO_STR'}}. -ADDR_TO_STR : {token, {mnemonic, TokenLine, 'ADDR_TO_STR'}}. -STR_REVERSE : {token, {mnemonic, TokenLine, 'STR_REVERSE'}}. - -INT_TO_ADDR : {token, {mnemonic, TokenLine, 'INT_TO_ADDR'}}. - -VARIANT : {token, {mnemonic, TokenLine, 'VARIANT'}}. -VARIANT_TEST : {token, {mnemonic, TokenLine, 'VARIANT_TEST'}}. -VARIANT_ELEMENT : {token, {mnemonic, TokenLine, 'VARIANT_ELEMENT'}}. - -BITS_NONE : {token, {mnemonic, TokenLine, 'BITS_NONE'}}. -BITS_NONEA : {token, {mnemonic, TokenLine, 'BITS_NONEA'}}. -BITS_ALL : {token, {mnemonic, TokenLine, 'BITS_ALL'}}. -BITS_ALLA : {token, {mnemonic, TokenLine, 'BITS_ALLA'}}. -BITS_ALL_N : {token, {mnemonic, TokenLine, 'BITS_ALL_N'}}. -BITS_SET : {token, {mnemonic, TokenLine, 'BITS_SET'}}. -BITS_CLEAR : {token, {mnemonic, TokenLine, 'BITS_CLEAR'}}. -BITS_TEST : {token, {mnemonic, TokenLine, 'BITS_TEST'}}. -BITS_SUM : {token, {mnemonic, TokenLine, 'BITS_SUM'}}. -BITS_OR : {token, {mnemonic, TokenLine, 'BITS_OR'}}. -BITS_AND : {token, {mnemonic, TokenLine, 'BITS_AND'}}. -BITS_DIFF : {token, {mnemonic, TokenLine, 'BITS_DIFF'}}. - - -ADDRESS : {token, {mnemonic, TokenLine, 'ADDRESS'}}. -BALANCE : {token, {mnemonic, TokenLine, 'BALANCE'}}. -ORIGIN : {token, {mnemonic, TokenLine, 'ORIGIN'}}. -CALLER : {token, {mnemonic, TokenLine, 'CALLER'}}. -GASPRICE : {token, {mnemonic, TokenLine, 'GASPRICE'}}. -BLOCKHASH : {token, {mnemonic, TokenLine, 'BLOCKHASH'}}. -BENEFICIARY : {token, {mnemonic, TokenLine, 'BENEFICIARY'}}. -TIMESTAMP : {token, {mnemonic, TokenLine, 'TIMESTAMP'}}. -NUMBER : {token, {mnemonic, TokenLine, 'NUMBER'}}. -DIFFICULTY : {token, {mnemonic, TokenLine, 'DIFFICULTY'}}. -GASLIMIT : {token, {mnemonic, TokenLine, 'GASLIMIT'}}. -GAS : {token, {mnemonic, TokenLine, 'GAS'}}. -LOG0 : {token, {mnemonic, TokenLine, 'LOG0'}}. -LOG1 : {token, {mnemonic, TokenLine, 'LOG1'}}. -LOG2 : {token, {mnemonic, TokenLine, 'LOG2'}}. -LOG3 : {token, {mnemonic, TokenLine, 'LOG3'}}. -LOG4 : {token, {mnemonic, TokenLine, 'LOG4'}}. -ABORT : {token, {mnemonic, TokenLine, 'ABORT'}}. -EXIT : {token, {mnemonic, TokenLine, 'EXIT'}}. -DEACTIVATE : {token, {mnemonic, TokenLine, 'DEACTIVATE'}}. -COMMENT : {token, {mnemonic, TokenLine, 'COMMENT'}}. - -FUNCTION : {token, {function, TokenLine, 'FUNCTION' }}. - -{ID} : - {token, {id, TokenLine, TokenChars}}. -{HEX} : - {token, {int, TokenLine, parse_hex(TokenChars)}}. -{INT} : - {token, {int, TokenLine, parse_int(TokenChars)}}. -{HASH} : - {token, {hash, TokenLine, parse_hash(TokenChars)}}. - - -%% Symbols -\-\> : {token, {'to', TokenLine}}. -\: : {token, {'to', TokenLine}}. -, : {token, {',', TokenLine}}. -\( : {token, {'(', TokenLine}}. -\) : {token, {')', TokenLine}}. -\[ : {token, {'[', TokenLine}}. -\] : {token, {']', TokenLine}}. -\{ : {token, {'{', TokenLine}}. -\} : {token, {'}', TokenLine}}. - -;;.* : - {token, {comment, TokenLine, drop_prefix($;, TokenChars)}}. - -\. : skip_token. - - -%% Whitespace ignore -{WS} : skip_token. - -%% Comments (TODO: nested comments) - - -. : {error, "Unexpected token: " ++ TokenChars}. - -Erlang code. - --export([scan/1]). - --dialyzer({nowarn_function, yyrev/2}). - --ignore_xref([format_error/1, string/2, token/2, token/3, tokens/2, tokens/3]). - --include_lib("aebytecode/include/aeb_fate_opcodes.hrl"). - - -parse_hex("0x" ++ Chars) -> list_to_integer(Chars, 16). - -parse_int(Chars) -> list_to_integer(Chars). - -parse_arg("arg" ++ N) -> list_to_integer(N). -parse_var("var" ++ N) -> list_to_integer(N). -parse_acc("a" ++ N) -> list_to_integer(N). - - -parse_hash("#" ++ Chars) -> - N = list_to_integer(Chars, 16), - <>. - -scan(S) -> - string(S). - -drop_prefix(C, [C|Rest]) -> - drop_prefix(C, Rest); -drop_prefix(_, Tail) -> Tail. diff --git a/src/aeb_fate_generate_ops.erl b/src/aeb_fate_generate_ops.erl index 3bb8a26..925caf9 100644 --- a/src/aeb_fate_generate_ops.erl +++ b/src/aeb_fate_generate_ops.erl @@ -17,19 +17,20 @@ generate(Src, Include) -> HrlFile = Include ++ "aeb_fate_opcodes.hrl", generate_header_file(HrlFile, Ops), generate_opcodes_ops(aeb_fate_opcodes, HrlFile, Src, Ops), - generate_code_ops(aeb_fate_code, Src, Ops). + generate_code_ops(aeb_fate_code, Src, Ops), + generate_scanner("aeb_fate_asm_scan.template", "aeb_fate_asm_scan.xrl", Src, Ops). %% TODO: Some real gas numbers... ops_defs() -> %% Opname, Opcode, args, end_bb, gas, format, Constructor, Documentation - [ { 'RETURN', 16#00, 0, true, 2, atomic, return, "Return from function call pop stack to arg0."} - , { 'RETURNR', 16#01, 1, true, 2, [a], returnr, "Return from function call copy Arg0 to arg0."} - , { 'CALL', 16#02, 1, true, 4, [is], call, "Call given function with args on stack."} - , { 'CALL_R', 16#03, 2, true, 8, [a,is], call_r, "Remote call to given contract and function."} - , { 'CALL_T', 16#04, 1, true, 4, [is], call_t, "Tail call to given function."} - , { 'CALL_TR', 16#05, 2, true, 8, [a,is], call_tr, "Remote tail call to given contract and function."} - , { 'JUMP', 16#06, 1, true, 3, [ii], jump, "Jump to a basic block."} - , { 'JUMPIF', 16#07, 2, true, 4, [a,ii], jumpif, "Conditional jump to a basic block."} + [ { 'RETURN', 16#00, 0, true, 2, atomic, return, "Return from function call pop stack to arg0. The type of the retun value has to match the return type of the function."} + , { 'RETURNR', 16#01, 1, true, 2, [a], returnr, "Return from function call copy Arg0 to arg0. The type of the retun value has to match the return type of the function."} + , { 'CALL', 16#02, 1, true, 4, [is], call, "Call given function with args on stack. The types of the arguments has to match the argument typs of the function."} + , { 'CALL_R', 16#03, 2, true, 8, [a,is], call_r, "Remote call to given contract and function. The types of the arguments has to match the argument typs of the function."} + , { 'CALL_T', 16#04, 1, true, 4, [is], call_t, "Tail call to given function. The types of the arguments has to match the argument typs of the function. And the return type of the called function has to match the type of the current function."} + , { 'CALL_TR', 16#05, 2, true, 8, [a,is], call_tr, "Remote tail call to given contract and function. The types of the arguments has to match the argument typs of the function. And the return type of the called function has to match the type of the current function."} + , { 'JUMP', 16#06, 1, true, 3, [ii], jump, "Jump to a basic block. The basic block has to exist in the current function."} + , { 'JUMPIF', 16#07, 2, true, 4, [a,ii], jumpif, "Conditional jump to a basic block. If Arg0 then jump to Arg1."} , { 'SWITCH_V2', 16#08, 3, true, 4, [a,ii,ii], switch, "Conditional jump to a basic block on variant tag."} , { 'SWITCH_V3', 16#09, 4, true, 4, [a,ii,ii,ii], switch, "Conditional jump to a basic block on variant tag."} , { 'SWITCH_VN', 16#0a, 2, true, 4, [a,li], switch, "Conditional jump to a basic block on variant tag."} @@ -372,3 +373,29 @@ expand_type(ii) -> "fate_arg_immediate(aeb_fate_data:fate_integer())"; expand_type(li) -> "[fate_arg_immediate(aeb_fate_data:fate_integer())]"; expand_type(t) -> "aeb_fate_data:fate_type_type()". +generate_scanner(TemplateFile, Outfile, Path, Ops) -> + {ok, Template} = file:read_file(filename:join(Path,TemplateFile)), + Tokens = lists:flatten([gen_token(Op) || Op <- Ops]), + NewFile = insert_tokens_in_template(Template, Tokens), + file:write_file(filename:join(Path, Outfile), NewFile). + +gen_token(#{opname := OpName}) -> + Name = atom_to_list(OpName), + io_lib:format("~-28s: {token, {mnemonic, TokenLine, ~w}}.\n", + [Name, OpName]). + +insert_tokens_in_template(<<"###REPLACEWITHOPTOKENS###", Rest/binary >>, Tokens) -> + [Tokens, Rest]; +insert_tokens_in_template(<<"###REPLACEWITHNOTE###", Rest/binary >>, Tokens) -> + [ + "%%%\n" + "%%% === === N O T E : This file is generated do not edit. === ===\n" + "%%%\n" + "%%% Source is in aeb_fate_generate_ops.erl\n" + "%%% and aeb_fate_asm_scan.template" + | insert_tokens_in_template(Rest, Tokens)]; +insert_tokens_in_template(<>, Tokens) -> + [B|insert_tokens_in_template(Rest, Tokens)]. + + +