From 761a62817d7622c7fcb1836d26ed6dfae67ce16b Mon Sep 17 00:00:00 2001 From: Mikael Pettersson Date: Sun, 8 Dec 2019 17:01:35 +0100 Subject: [PATCH] as: support subsections and section stack directives --- erlang/apps/as/priv/test4.s | 37 +++++ erlang/apps/as/src/input.erl | 303 ++++++++++++++++++++++++++++------- erlang/apps/as/src/parse.erl | 59 ++++++- erlang/apps/as/src/token.erl | 8 + erlang/apps/as/src/token.hrl | 20 ++- erlang/apps/as/src/tunit.hrl | 20 ++- 6 files changed, 383 insertions(+), 64 deletions(-) create mode 100644 erlang/apps/as/priv/test4.s diff --git a/erlang/apps/as/priv/test4.s b/erlang/apps/as/priv/test4.s new file mode 100644 index 0000000..94f88eb --- /dev/null +++ b/erlang/apps/as/priv/test4.s @@ -0,0 +1,37 @@ +/* + * test4.s + * Copyright (C) 2019 Mikael Pettersson + * + * This file is part of pdp10-tools. + * + * pdp10-tools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * pdp10-tools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with pdp10-tools. If not, see . + */ + +/* This exercises the section-switching directives and should assemble + to a sequence of moves with monotonically insreasing immediates. */ + + .text 0 # cur 0, prev -, stack [] + .globl foo + .type foo,@function +foo: + movei 0, 0 + .pushsection .text, 1 # cur 1, prev 0, stack [{0,-}] + movei 0, 2 + .text 2 # cur 2, prev 1, stack [{0,-}] + movei 0, 4 + .previous # cur 1, prev 2, stack [{0,-}] + movei 0, 3 + .popsection # cur 0, prev -, stack [] + movei 0, 1 + .size foo,.-foo diff --git a/erlang/apps/as/src/input.erl b/erlang/apps/as/src/input.erl index ce0b1f4..2d2639a 100644 --- a/erlang/apps/as/src/input.erl +++ b/erlang/apps/as/src/input.erl @@ -28,31 +28,199 @@ -include_lib("lib/include/pdp10_elf36.hrl"). -spec files([string()]) -> {ok, #tunit{}} | {error, {module(), term()}}. -files(Files) -> - NewFiles = - case Files of - [] -> ["--"]; - _ -> Files +files(Files0) -> + Files = + case Files0 of + [] -> ["--"]; % alias for stdin + _ -> Files0 end, - files(NewFiles, tunit_init()). + pass1(Files). -files([], Tunit) -> {ok, Tunit}; -files([File | Files], Tunit) -> - case file(File, Tunit) of - {ok, NewTunit} -> files(Files, NewTunit); +%% Pass 1 ---------------------------------------------------------------------- +%% +%% - scan, parse, annotate stmts with locations +%% - maintain current and previous section and subsection, and stack thereof +%% - interpret sectioning stmts, accumulate annotated stmts in subsections + +-type section() :: string(). +-type subsection() :: non_neg_integer(). + +-type sectionandsub() :: {section(), subsection()}. + +-record(ctx, + { sections_map :: #{section() => #{subsection() => [stmt()]}} + , stack :: [{Current :: sectionandsub(), Previous :: sectionandsub()}] + , current :: sectionandsub() + , previous :: sectionandsub() | [] + , stmts :: [{scan_state:location(), stmt()}] + }). + +pass1(Files) -> + pass1_files(Files, ctx_init()). + +pass1_files([], Ctx) -> pass2(ctx_fini(Ctx)); +pass1_files([File | Files], Ctx) -> + case pass1_file(File, Ctx) of + {ok, NewCtx} -> pass1_files(Files, NewCtx); {error, _Reason} = Error -> Error end. -file(File, Tunit) -> +pass1_file(File, Ctx) -> case scan_state_open(File) of {ok, ScanState} -> - try process(ScanState, Tunit) + try pass1_process(ScanState, Ctx) after scan_state:fclose(ScanState) end; {error, _Reason} = Error -> Error end. -%% Open next input file, support "--" and "-" as aliases for stdin. +pass1_process(ScanState, Ctx) -> + case parse:stmt(ScanState) of + eof -> {ok, Ctx}; + {ok, Stmt} -> + case pass1_stmt(scan_state_location(ScanState), Ctx, Stmt) of + {ok, NewCtx} -> pass1_process(ScanState, NewCtx); + {error, _Reason} = Error -> Error + end; + {error, _Reason} = Error -> Error + end. + +pass1_stmt(Location, Ctx, Stmt) -> + case Stmt of + #s_dot_popsection{} -> dot_popsection(Location, Ctx, Stmt); + #s_dot_previous{} -> dot_previous(Location, Ctx, Stmt); + #s_dot_pushsection{} -> dot_pushsection(Location, Ctx, Stmt); + #s_dot_subsection{} -> dot_subsection(Location, Ctx, Stmt); + #s_dot_text{} -> dot_text(Location, Ctx, Stmt); + _ -> {ok, ctx_append(Ctx, Location, Stmt)} + end. + +dot_popsection(Location, Ctx0, #s_dot_popsection{}) -> + case ctx_try_popsection(Ctx0) of + {ok, _Ctx} = Result -> Result; + false -> fmterr(Location, ".popsection with empty section stack", []) + end. + +dot_previous(Location, Ctx0, #s_dot_previous{}) -> + case ctx_try_previous(Ctx0) of + {ok, _Ctx} = Result -> Result; + false -> fmterr(Location, ".previous with empty section stack", []) + end. + +dot_pushsection(_Location, Ctx, #s_dot_pushsection{name = Section, nr = Subsection}) -> + {ok, ctx_pushsection(Ctx, Section, Subsection)}. + +dot_subsection(_Location, Ctx, #s_dot_subsection{nr = Subsection}) -> + {ok, ctx_subsection(Ctx, Subsection)}. + +dot_text(_Location, Ctx, #s_dot_text{nr = Subsection}) -> + {ok, ctx_text(Ctx, Subsection)}. + +%% Context utilities + +ctx_init() -> + InitialSection = ".text", + InitialSubsection = 0, + #ctx{ sections_map = #{InitialSection => #{}} + , stack = [] + , current = {InitialSection, InitialSubsection} + , previous = [] + , stmts = [] + }. + +ctx_fini(Ctx) -> + (ctx_flush(Ctx))#ctx.sections_map. + +ctx_flush(Ctx) -> + #ctx{ sections_map = SectionsMap0 + , current = {Section, Subsection} + , stmts = Stmts + } = Ctx, + SubsectionsMap0 = maps:get(Section, SectionsMap0, #{}), + SubsectionsMap = maps:put(Subsection, Stmts, SubsectionsMap0), + SectionsMap = maps:put(Section, SubsectionsMap, SectionsMap0), + Ctx#ctx{sections_map = SectionsMap}. + +ctx_try_popsection(Ctx0) -> % implements .popsection + Ctx = ctx_flush(Ctx0), + #ctx{ sections_map = SectionsMap + , stack = Stack + } = Ctx, + case Stack of + [] -> false; + [{Current = {Section, Subsection}, Previous} | RestStack] -> + SubsectionsMap = maps:get(Section, SectionsMap), % must exist + Stmts = maps:get(Subsection, SubsectionsMap), % must exist + {ok, Ctx#ctx{ stack = RestStack + , current = Current + , previous = Previous + , stmts = Stmts + }} + end. + +ctx_try_previous(Ctx0) -> % implements .previous + Ctx = ctx_flush(Ctx0), + #ctx{ sections_map = SectionsMap + , current = Current + , previous = Previous + } = Ctx, + case Previous of + [] -> false; + {Section, Subsection} -> + SubsectionsMap = maps:get(Section, SectionsMap), % must exist + Stmts = maps:get(Subsection, SubsectionsMap), % must exist + {ok, Ctx#ctx{ current = Previous + , previous = Current + , stmts = Stmts + }} + end. + +ctx_pushsection(Ctx0, Section, Subsection) -> % implements .pushsection + Ctx = ctx_flush(Ctx0), + #ctx{ sections_map = SectionsMap + , stack = Stack + , current = Current + , previous = Previous + } = Ctx, + SubsectionsMap = maps:get(Section, SectionsMap, #{}), + Stmts = maps:get(Subsection, SubsectionsMap, []), + Ctx#ctx{ stack = [{Current, Previous} | Stack] + , current = {Section, Subsection} + , previous = Current + , stmts = Stmts + }. + +ctx_subsection(Ctx0, Subsection) -> % implements .subsection + Ctx = ctx_flush(Ctx0), + #ctx{ sections_map = SectionsMap + , current = Current = {Section, _CurSubsection} + } = Ctx, + SubsectionsMap = maps:get(Section, SectionsMap), % must exist + Stmts = maps:get(Subsection, SubsectionsMap, []), + Ctx#ctx{ current = {Section, Subsection} + , previous = Current + , stmts = Stmts + }. + +ctx_text(Ctx0, Subsection) -> % implements .text + Ctx = ctx_flush(Ctx0), + #ctx{ sections_map = SectionsMap + , current = Current + } = Ctx, + Section = ".text", + SubsectionsMap = maps:get(Section, SectionsMap, #{}), + Stmts = maps:get(Subsection, SubsectionsMap, []), + Ctx#ctx{ current = {Section, Subsection} + , previous = Current + , stmts = Stmts + }. + +ctx_append(Ctx, Location, Stmt) -> + #ctx{stmts = Stmts} = Ctx, + Ctx#ctx{stmts = [{Location, Stmt} | Stmts]}. + +%% Scan state utilities + scan_state_open(File) -> case File of "--" -> scan_state:stdin(); @@ -60,31 +228,62 @@ scan_state_open(File) -> _ -> scan_state:fopen(File) end. -process(ScanState, Tunit) -> - case parse:stmt(ScanState) of - eof -> {ok, Tunit}; - {ok, Stmt} -> - case interpret(ScanState, Tunit, Stmt) of - {ok, NewTunit} -> process(ScanState, NewTunit); - {error, _Reason} = Error -> Error - end; +scan_state_location(ScanState) -> + {ok, Location = {_FileName, _LineNr}} = scan_state:location(ScanState), + Location. + +%% Pass 2 ---------------------------------------------------------------------- +%% +%% - process subsections in order +%% - interpret stmts + +pass2(SectionsMap) -> + pass2_sections(maps:to_list(SectionsMap), tunit_init()). + +pass2_sections([], Tunit) -> {ok, Tunit}; +pass2_sections([{SectionName, SubsectionsMap} | Sections], Tunit0) -> + %% TODO: handle creation of new sections here + #section{} = tunit:get_section(Tunit0, SectionName), + Tunit = Tunit0#tunit{cursect = SectionName}, + case pass2_subsections(SectionName, SubsectionsMap, Tunit) of + {ok, NewTunit} -> pass2_sections(Sections, NewTunit); {error, _Reason} = Error -> Error end. -interpret(ScanState, Tunit, Stmt) -> - case Stmt of - #s_dot_file{} -> dot_file(ScanState, Tunit, Stmt); - #s_dot_globl{} -> dot_globl(ScanState, Tunit, Stmt); - #s_dot_ident{} -> dot_ident(ScanState, Tunit, Stmt); - #s_dot_size{} -> dot_size(ScanState, Tunit, Stmt); - #s_dot_text{} -> dot_text(ScanState, Tunit, Stmt); - #s_dot_type{} -> dot_type(ScanState, Tunit, Stmt); - #s_label{} -> label(ScanState, Tunit, Stmt); - #s_local_label{} -> local_label(ScanState, Tunit, Stmt); - #s_insn{} -> insn(ScanState, Tunit, Stmt) +pass2_subsections(_SectionName = ".text", SubsectionsMap, Tunit) -> + pass2_subsections(lists:sort(maps:to_list(SubsectionsMap)), Tunit). + +pass2_subsections([], Tunit) -> {ok, Tunit}; +pass2_subsections([{_Nr, StmtsRev} | Subsections], Tunit) -> + case pass2_stmts(lists:reverse(StmtsRev), Tunit) of + {ok, NewTunit} -> + %% GAS documentation states that each sub-section is padded to make its + %% size a multiple of 4 bytes, but also that other implementations may + %% do differently. We do not insert any implicit padding. + pass2_subsections(Subsections, NewTunit); + {error, _Reason} = Error -> Error end. -dot_file(_ScanState, Tunit, #s_dot_file{string = String}) -> +pass2_stmts([], Tunit) -> {ok, Tunit}; +pass2_stmts([{Location, Stmt} | Stmts], Tunit) -> + case pass2_stmt(Location, Tunit, Stmt) of + {ok, NewTunit} -> pass2_stmts(Stmts, NewTunit); + {error, _Reason} = Error -> Error + end. + +pass2_stmt(Location, Tunit, Stmt) -> + case Stmt of + #s_dot_file{} -> dot_file(Location, Tunit, Stmt); + #s_dot_globl{} -> dot_globl(Location, Tunit, Stmt); + #s_dot_ident{} -> dot_ident(Location, Tunit, Stmt); + #s_dot_size{} -> dot_size(Location, Tunit, Stmt); + #s_dot_type{} -> dot_type(Location, Tunit, Stmt); + #s_label{} -> label(Location, Tunit, Stmt); + #s_local_label{} -> local_label(Location, Tunit, Stmt); + #s_insn{} -> insn(Location, Tunit, Stmt) + end. + +dot_file(_Location, Tunit, #s_dot_file{string = String}) -> Symbol = #symbol{ name = String , section = false , st_value = 0 @@ -95,7 +294,7 @@ dot_file(_ScanState, Tunit, #s_dot_file{string = String}) -> }, {ok, tunit:put_symbol(Tunit, Symbol)}. -dot_globl(ScanState, Tunit, #s_dot_globl{name = Name}) -> +dot_globl(Location, Tunit, #s_dot_globl{name = Name}) -> case tunit:get_symbol(Tunit, Name) of false -> Symbol = @@ -115,11 +314,11 @@ dot_globl(ScanState, Tunit, #s_dot_globl{name = Name}) -> Symbol = OldSymbol#symbol{st_info = ?ELF_ST_INFO(?STB_GLOBAL, ?ELF_ST_TYPE(StInfo))}, {ok, tunit:put_symbol(Tunit, Symbol)}; Bind -> - fmterr(ScanState, "symbol ~s has previous incompatible binding type ~p", [Name, Bind]) + fmterr(Location, "symbol ~s has previous incompatible binding type ~p", [Name, Bind]) end end. -dot_ident(_ScanState, Tunit, #s_dot_ident{} = Stmt) -> +dot_ident(_Location, Tunit, #s_dot_ident{} = Stmt) -> #section{data = {stmts, Stmts}} = OldSection = case tunit:get_section(Tunit, ".comment") of false -> section_dot_comment(); @@ -128,29 +327,24 @@ dot_ident(_ScanState, Tunit, #s_dot_ident{} = Stmt) -> NewSection = OldSection#section{data = {stmts, [Stmt | Stmts]}}, {ok, tunit:put_section(Tunit, NewSection)}. -dot_size(ScanState, Tunit, #s_dot_size{name = Name}) -> +dot_size(Location, Tunit, #s_dot_size{name = Name}) -> #tunit{cursect = Cursect} = Tunit, #section{dot = Dot} = tunit:get_section(Tunit, Cursect), case tunit:get_symbol(Tunit, Name) of #symbol{st_size = StSize} when StSize =/= false -> - fmterr(ScanState, "size of symbol ~s already defined", [Name]); + fmterr(Location, "size of symbol ~s already defined", [Name]); #symbol{section = Section} when Section =/= Cursect -> - fmterr(ScanState, "symbol ~s not defined in same section as dot", [Name]); + fmterr(Location, "symbol ~s not defined in same section as dot", [Name]); #symbol{st_value = StValue} = OldSymbol when StValue =< Dot -> % note: false > integer() Symbol = OldSymbol#symbol{st_size = Dot - StValue}, {ok, tunit:put_symbol(Tunit, Symbol)}; #symbol{st_value = StValue} when StValue =/= false, StValue > Dot -> - fmterr(ScanState, "cannot make symbol ~s negative size", [Name]); + fmterr(Location, "cannot make symbol ~s negative size", [Name]); _ -> - fmterr(ScanState, "symbol ~s not defined", [Name]) + fmterr(Location, "symbol ~s not defined", [Name]) end. -dot_text(_ScanState, Tunit, #s_dot_text{}) -> - %% just check that .text has been pre-created - #section{} = tunit:get_section(Tunit, ".text"), - {ok, Tunit#tunit{cursect = ".text"}}. - -dot_type(ScanState, Tunit, #s_dot_type{name = Name}) -> +dot_type(Location, Tunit, #s_dot_type{name = Name}) -> case tunit:get_symbol(Tunit, Name) of false -> Symbol = @@ -170,14 +364,14 @@ dot_type(ScanState, Tunit, #s_dot_type{name = Name}) -> Symbol = OldSymbol#symbol{st_info = ?ELF_ST_INFO(?ELF_ST_BIND(StInfo), ?STT_FUNC)}, {ok, tunit:put_symbol(Tunit, Symbol)}; Type -> - fmterr(ScanState, "symbol ~s has previous incompatible type ~p", [Name, Type]) + fmterr(Location, "symbol ~s has previous incompatible type ~p", [Name, Type]) end end. -label(ScanState, Tunit, #s_label{name = Name}) -> +label(Location, Tunit, #s_label{name = Name}) -> case tunit:get_symbol(Tunit, Name) of #symbol{section = false, st_value = false} = Symbol -> define_label(Tunit, Symbol); - #symbol{} -> fmterr(ScanState, "label ~s already defined", [Name]); + #symbol{} -> fmterr(Location, "label ~s already defined", [Name]); false -> define_new_label(Tunit, Name) end. @@ -189,7 +383,7 @@ define_label(Tunit, Symbol) -> #section{dot = Dot} = tunit:get_section(Tunit, Cursect), {ok, tunit:put_symbol(Tunit, Symbol#symbol{section = Cursect, st_value = Dot})}. -local_label(_ScanState, Tunit, #s_local_label{number = Number}) -> +local_label(_Location, Tunit, #s_local_label{number = Number}) -> Serial = local_label_serial(Tunit, Number) + 1, Name = local_label_name(Number, Serial), define_new_label(tunit:put_local_label(Tunit, Number, Serial), Name). @@ -203,7 +397,7 @@ local_label_serial(Tunit, Number) -> local_label_name(Number, Serial) -> lists:flatten(io_lib:format(".L~.10b\^B~.10b", [Number, Serial])). -insn(ScanState, Tunit, #s_insn{} = Stmt) -> +insn(Location, Tunit, #s_insn{} = Stmt) -> #tunit{cursect = Cursect} = Tunit, #section{data = {stmts, Stmts}, dot = Dot} = Section = tunit:get_section(Tunit, Cursect), case Dot rem 4 of % FIXME: target-specific @@ -214,7 +408,7 @@ insn(ScanState, Tunit, #s_insn{} = Stmt) -> , dot = Dot + 4 % FIXME: target-specific }, {ok, tunit:put_section(Tunit, NewSection)}; - _ -> fmterr(ScanState, "misaligned address for instruction", []) + _ -> fmterr(Location, "misaligned address for instruction", []) end. insn_fixup(Tunit, Insn) -> @@ -270,8 +464,7 @@ section_dot_text() -> % ".text" %% Error reporting ------------------------------------------------------------- -fmterr(ScanState, Fmt, Args) -> - {ok, {FileName, LineNr}} = scan_state:location(ScanState), +fmterr({FileName, LineNr}, Fmt, Args) -> {error, {?MODULE, {FileName, LineNr, Fmt, Args}}}. -spec format_error(term()) -> io_lib:chars(). diff --git a/erlang/apps/as/src/parse.erl b/erlang/apps/as/src/parse.erl index 474a663..cbce472 100644 --- a/erlang/apps/as/src/parse.erl +++ b/erlang/apps/as/src/parse.erl @@ -35,7 +35,11 @@ stmt(ScanState) -> {ok, ?T_DOT_FILE} -> dot_file(ScanState); {ok, ?T_DOT_GLOBL} -> dot_globl(ScanState); {ok, ?T_DOT_IDENT} -> dot_ident(ScanState); + {ok, ?T_DOT_POPSECTION} -> dot_popsection(ScanState); + {ok, ?T_DOT_PREVIOUS} -> dot_previous(ScanState); + {ok, ?T_DOT_PUSHSECTION} -> dot_pushsection(ScanState); {ok, ?T_DOT_SIZE} -> dot_size(ScanState); + {ok, ?T_DOT_SUBSECTION} -> dot_subsection(ScanState); {ok, ?T_DOT_TEXT} -> dot_text(ScanState); {ok, ?T_DOT_TYPE} -> dot_type(ScanState); {ok, {?T_SYMBOL, Name}} -> stmt_after_symbol(ScanState, Name); @@ -288,6 +292,44 @@ dot_globl(ScanState) -> ScanRes -> badtok(ScanState, "junk after .globl", ScanRes) end. +dot_popsection(ScanState) -> + case scan:token(ScanState) of + {ok, ?T_NEWLINE} -> {ok, #s_dot_popsection{}}; + ScanRes -> badtok(ScanState, "junk after .popsection", ScanRes) + end. + +dot_previous(ScanState) -> + case scan:token(ScanState) of + {ok, ?T_NEWLINE} -> {ok, #s_dot_previous{}}; + ScanRes -> badtok(ScanState, "junk after .previous", ScanRes) + end. + +%% For now only accepts ".pushsection [, ]". TODO: extend +dot_pushsection(ScanState) -> + case scan:token(ScanState) of + {ok, {?T_STRING, Name}} -> dot_pushsection(ScanState, Name); + {ok, {?T_SYMBOL, Name}} -> dot_pushsection(ScanState, Name); + %% TODO: do we need a general mapping from reserved to plain symbols? + {ok, ?T_DOT_TEXT} -> dot_pushsection(ScanState, _Name = ".text"); + ScanRes -> badtok(ScanState, "junk after .pushsection", ScanRes) + end. + +%% Seen ".pushsection ", expects "[, ]". +dot_pushsection(ScanState, Name) -> + case scan:token(ScanState) of + {ok, ?T_NEWLINE} -> {ok, #s_dot_pushsection{name = Name, nr = 0}}; + {ok, ?T_COMMA} -> + case scan:token(ScanState) of + {ok, {?T_UINTEGER, Nr}} -> + case scan:token(ScanState) of + {ok, ?T_NEWLINE} -> {ok, #s_dot_pushsection{name = Name, nr = Nr}}; + ScanRes -> badtok(ScanState, "junk after .pushsection , ", ScanRes) + end; + ScanRes -> badtok(ScanState, "junk after .pushsection ,", ScanRes) + end; + ScanRes -> badtok(ScanState, "junk after .pushsection ", ScanRes) + end. + %% For now only accepts ".size ,.-". TODO: extend dot_size(ScanState) -> case scan:token(ScanState) of @@ -315,9 +357,24 @@ dot_size(ScanState) -> ScanRes -> badtok(ScanState, "junk after .size", ScanRes) end. +dot_subsection(ScanState) -> + case scan:token(ScanState) of + {ok, {?T_UINTEGER, Nr}} -> + case scan:token(ScanState) of + {ok, ?T_NEWLINE} -> {ok, #s_dot_subsection{nr = Nr}}; + ScanRes -> badtok(ScanState, "junk after .subsection ", ScanRes) + end; + ScanRes -> badtok(ScanState, "junk after .subsection", ScanRes) + end. + dot_text(ScanState) -> case scan:token(ScanState) of - {ok, ?T_NEWLINE} -> {ok, #s_dot_text{}}; + {ok, ?T_NEWLINE} -> {ok, #s_dot_text{nr = 0}}; + {ok, {?T_UINTEGER, Nr}} -> + case scan:token(ScanState) of + {ok, ?T_NEWLINE} -> {ok, #s_dot_text{nr = Nr}}; + ScanRes -> badtok(ScanState, "junk after .text ", ScanRes) + end; ScanRes -> badtok(ScanState, "junk after .text", ScanRes) end. diff --git a/erlang/apps/as/src/token.erl b/erlang/apps/as/src/token.erl index 9817798..3bbd274 100644 --- a/erlang/apps/as/src/token.erl +++ b/erlang/apps/as/src/token.erl @@ -32,7 +32,11 @@ from_symbol(Name) -> ".file" -> ?T_DOT_FILE; ".globl" -> ?T_DOT_GLOBL; ".ident" -> ?T_DOT_IDENT; + ".popsection" -> ?T_DOT_POPSECTION; + ".previous" -> ?T_DOT_PREVIOUS; + ".pushsection" -> ?T_DOT_PUSHSECTION; ".size" -> ?T_DOT_SIZE; + ".subsection" -> ?T_DOT_SUBSECTION; ".text" -> ?T_DOT_TEXT; ".type" -> ?T_DOT_TYPE; _ -> {?T_SYMBOL, Name} @@ -44,7 +48,11 @@ format(Token) -> ?T_DOT_FILE -> ".file"; ?T_DOT_GLOBL -> ".globl"; ?T_DOT_IDENT -> ".ident"; + ?T_DOT_POPSECTION -> ".popsection"; + ?T_DOT_PREVIOUS -> ".previous"; + ?T_DOT_PUSHSECTION -> ".pushsection"; ?T_DOT_SIZE -> ".size"; + ?T_DOT_SUBSECTION -> ".subsection"; ?T_DOT_TEXT -> ".text"; ?T_DOT_TYPE -> ".type"; {?T_SYMBOL, Name} -> io_lib:format("symbol:~s", [Name]); diff --git a/erlang/apps/as/src/token.hrl b/erlang/apps/as/src/token.hrl index 00e9955..479e315 100644 --- a/erlang/apps/as/src/token.hrl +++ b/erlang/apps/as/src/token.hrl @@ -26,12 +26,16 @@ %% with attributes (ordinary symbols, literals, errors). %% reserved symbols including directives --define(T_DOT_FILE, 'T_DOT_FILE'). % .file --define(T_DOT_GLOBL, 'T_DOT_GLOBL'). % .globl --define(T_DOT_IDENT, 'T_DOT_IDENT'). % .ident --define(T_DOT_SIZE, 'T_DOT_SIZE'). % .size --define(T_DOT_TEXT, 'T_DOT_TEXT'). % .text --define(T_DOT_TYPE, 'T_DOT_TYPE'). % .type +-define(T_DOT_FILE, 'T_DOT_FILE'). % .file +-define(T_DOT_GLOBL, 'T_DOT_GLOBL'). % .globl +-define(T_DOT_IDENT, 'T_DOT_IDENT'). % .ident +-define(T_DOT_POPSECTION, 'T_DOT_POPSECTION'). % .popsection +-define(T_DOT_PREVIOUS, 'T_DOT_PREVIOUS'). % .previous +-define(T_DOT_PUSHSECTION, 'T_DOT_PUSHSECTION'). % .pushsection +-define(T_DOT_SIZE, 'T_DOT_SIZE'). % .size +-define(T_DOT_SUBSECTION, 'T_DOT_SUBSECTION'). % .subsection +-define(T_DOT_TEXT, 'T_DOT_TEXT'). % .text +-define(T_DOT_TYPE, 'T_DOT_TYPE'). % .type %% ordinary (non-reserved, non-special non-synthetic) symbols -define(T_SYMBOL, 'T_SYMBOL'). % pushj, foo, .Lbar @@ -57,7 +61,11 @@ -type token() :: ?T_DOT_FILE | ?T_DOT_GLOBL | ?T_DOT_IDENT + | ?T_DOT_POPSECTION + | ?T_DOT_PREVIOUS + | ?T_DOT_PUSHSECTION | ?T_DOT_SIZE + | ?T_DOT_SUBSECTION | ?T_DOT_TEXT | ?T_DOT_TYPE | {?T_SYMBOL, string()} diff --git a/erlang/apps/as/src/tunit.hrl b/erlang/apps/as/src/tunit.hrl index e82e4db..0c67d3d 100644 --- a/erlang/apps/as/src/tunit.hrl +++ b/erlang/apps/as/src/tunit.hrl @@ -45,11 +45,23 @@ %% .ident "..." -record(s_dot_ident, {string :: string()}). +%% .popsection +-record(s_dot_popsection, {}). + +%% .previous +-record(s_dot_previous, {}). + +%% .pushsection name [, nr] (TODO: extend) +-record(s_dot_pushsection, {name :: string(), nr :: non_neg_integer()}). + %% .size foo,.-foo (TODO: extend) -record(s_dot_size, {name :: string()}). -%% .text --record(s_dot_text, {}). +%% .subsection nr +-record(s_dot_subsection, {nr :: non_neg_integer()}). + +%% .text [nr] +-record(s_dot_text, {nr :: non_neg_integer()}). %% .type foo,@function (TODO: extend) -record(s_dot_type, {name :: string()}). @@ -69,7 +81,11 @@ -type stmt() :: #s_dot_file{} | #s_dot_globl{} | #s_dot_ident{} + | #s_dot_popsection{} + | #s_dot_previous{} + | #s_dot_pushsection{} | #s_dot_size{} + | #s_dot_subsection{} | #s_dot_text{} | #s_dot_type{} | #s_label{}