as: support local labels

This commit is contained in:
Mikael Pettersson
2019-09-07 17:40:39 +02:00
parent 162faefd81
commit d3e5383f36
8 changed files with 114 additions and 11 deletions

View File

@@ -0,0 +1,28 @@
/*
* test3.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 <http://www.gnu.org/licenses/>.
*/
.file "test3.s"
.text
.globl foo
.type foo,@function
foo: jumpa 1f
0: popj 017,
1: jumpa 0b
.size foo,.-foo

View File

@@ -80,6 +80,7 @@ interpret(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)
end.
@@ -175,29 +176,61 @@ dot_type(ScanState, Tunit, #s_dot_type{name = Name}) ->
label(ScanState, Tunit, #s_label{name = Name}) ->
case tunit:get_symbol(Tunit, Name) of
#symbol{section = false, st_value = false} = Symbol -> label2(Tunit, Symbol);
#symbol{section = false, st_value = false} = Symbol -> define_label(Tunit, Symbol);
#symbol{} -> fmterr(ScanState, "label ~s already defined", [Name]);
false -> label2(Tunit, #symbol{name = Name, st_size = false, st_info = 0})
false -> define_new_label(Tunit, Name)
end.
label2(Tunit, Symbol) ->
define_new_label(Tunit, Name) ->
define_label(Tunit, #symbol{name = Name, st_size = false, st_info = 0}).
define_label(Tunit, Symbol) ->
#tunit{cursect = Cursect} = Tunit,
#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}) ->
Serial = local_label_serial(Tunit, Number) + 1,
Name = local_label_name(Number, Serial),
define_new_label(tunit:put_local_label(Tunit, Number, Serial), Name).
local_label_serial(Tunit, Number) ->
case tunit:get_local_label(Tunit, Number) of
false -> 0;
Serial -> Serial
end.
local_label_name(Number, Serial) ->
lists:flatten(io_lib:format(".L~.10b\^B~.10b", [Number, Serial])).
insn(ScanState, 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
0 ->
NewStmt = insn_fixup(Tunit, Stmt),
NewSection =
Section#section{ data = {stmts, [Stmt | Stmts]}
Section#section{ data = {stmts, [NewStmt | Stmts]}
, dot = Dot + 4 % FIXME: target-specific
},
{ok, tunit:put_section(Tunit, NewSection)};
_ -> fmterr(ScanState, "misaligned address for instruction", [])
end.
insn_fixup(Tunit, Insn) ->
case Insn#s_insn.address of
#e_local_label{number = Number, direction = Direction} ->
LabelSerial = local_label_serial(Tunit, Number),
ReferenceSerial =
case Direction of
$b -> LabelSerial;
$f -> LabelSerial + 1
end,
Name = local_label_name(Number, ReferenceSerial),
Insn#s_insn{address = #e_symbol{name = Name}};
_ -> Insn
end.
%% Initialization --------------------------------------------------------------
tunit_init() ->

View File

@@ -39,6 +39,7 @@ stmt(ScanState) ->
{ok, ?T_DOT_TEXT} -> dot_text(ScanState);
{ok, ?T_DOT_TYPE} -> dot_type(ScanState);
{ok, {?T_SYMBOL, Name}} -> stmt_after_symbol(ScanState, Name);
{ok, {?T_UINTEGER, UInt}} -> stmt_after_uinteger(ScanState, UInt);
{ok, ?T_NEWLINE} -> stmt(ScanState);
{ok, ?T_EOF} -> eof;
ScanRes -> badtok(ScanState, "expected directive, label, or instruction", ScanRes)
@@ -48,7 +49,7 @@ stmt(ScanState) ->
%%
%% Recognize:
%%
%% <label> ::= <symbol> ":"
%% <label> ::= <symbol> ":" | <uinteger> ":"
%%
%% <insn> ::= <symbol> (<accumulator> ",")? <address> <newline>
%%
@@ -56,7 +57,7 @@ stmt(ScanState) ->
%%
%% <address> ::= "@"? <displacement>? <index>?
%%
%% <displacement> ::= <uinteger> | <symbol>
%% <displacement> ::= <uinteger> | <symbol> | <uinteger>[bf]
%%
%% <index> ::= "(" <accumulator> ")"
%%
@@ -94,6 +95,15 @@ stmt_after_symbol(ScanState, Name) ->
{ok, ?T_NEWLINE} -> make_insn(ScanState, Name, false, false, false, false);
{ok, {?T_UINTEGER, UInt}} -> insn_uint(ScanState, Name, UInt);
{ok, {?T_SYMBOL, Symbol}} -> insn_symbol(ScanState, Name, Symbol);
{ok, {?T_LOCAL_LABEL, Number, Direction}} ->
insn_local_label(ScanState, Name, Number, Direction);
ScanRes -> badtok(ScanState, "junk after symbol", ScanRes)
end.
%% <stmt> ::= <uinteger> . ":"
stmt_after_uinteger(ScanState, UInt) ->
case scan:token(ScanState) of
{ok, ?T_COLON} -> {ok, #s_local_label{number = UInt}};
ScanRes -> badtok(ScanState, "junk after symbol", ScanRes)
end.
@@ -118,6 +128,11 @@ insn_symbol(ScanState, Name, Symbol2) ->
Displacement = #e_symbol{name = Symbol2},
insn_ea_disp(ScanState, Name, _AccOrDev = false, _At = false, Displacement).
%% Seen "<symbol> <local label>". The <local label> is (the start of) the <displacement>.
insn_local_label(ScanState, Name, Number, Direction) ->
Displacement = #e_local_label{number = Number, direction = Direction},
insn_ea_disp(ScanState, Name, _AccOrDev = false, _At = false, Displacement).
%% <symbol> <accordev> "," . [ ["@"] <displacement> ["(" <index> ")"] ] <newline>
insn_ea(ScanState, Name, AccOrDev) ->
case scan:token(ScanState) of
@@ -130,6 +145,9 @@ insn_ea(ScanState, Name, AccOrDev) ->
{ok, {?T_SYMBOL, Symbol}} ->
Displacement = #e_symbol{name = Symbol},
insn_ea_disp(ScanState, Name, AccOrDev, _At = false, Displacement);
{ok, {?T_LOCAL_LABEL, Number, Direction}} ->
Displacement = #e_local_label{number = Number, direction = Direction},
insn_ea_disp(ScanState, Name, AccOrDev, _At = false, Displacement);
ScanRes -> badtok(ScanState, "junk after comma", ScanRes)
end.
@@ -142,6 +160,9 @@ insn_ea_at(ScanState, Name, AccOrDev) ->
{ok, {?T_SYMBOL, Symbol}} ->
Displacement = #e_symbol{name = Symbol},
insn_ea_disp(ScanState, Name, AccOrDev, _At = true, Displacement);
{ok, {?T_LOCAL_LABEL, Number, Direction}} ->
Displacement = #e_local_label{number = Number, direction = Direction},
insn_ea_disp(ScanState, Name, AccOrDev, _At = true, Displacement);
ScanRes -> badtok(ScanState, "junk after @", ScanRes)
end.

View File

@@ -206,8 +206,9 @@ do_number(ScanState, Base, Val) ->
case chval(Ch) of
ChVal when ChVal < Base ->
do_number(ScanState, Base, Val * Base + ChVal);
_ChVal when Base =< 10 andalso (Ch =:= $b orelse Ch =:= $f) ->
{ok, {?T_LOCAL_LABEL, Val, Ch}};
_ChVal ->
%% TODO: check for <decimal>[bf] which is a local label reference
case scan_state:ungetc(Ch, ScanState) of
{error, _Reason} = Error -> Error;
ok -> {ok, {?T_UINTEGER, Val}}

View File

@@ -48,8 +48,10 @@ format(Token) ->
?T_DOT_TEXT -> ".text";
?T_DOT_TYPE -> ".type";
{?T_SYMBOL, Name} -> io_lib:format("symbol:~s", [Name]);
{?T_UINTEGER, Int} -> io_lib:format("uinteger:~p", [Int]);
{?T_LOCAL_LABEL, Number, Direction} ->
io_lib:format("label: ~.10b~c", [Number, Direction]);
{?T_STRING, Str} -> io_lib:format("string:~p", [Str]); % FIXME: quoting
{?T_UINTEGER, Int} -> io_lib:format("uinteger:~p", [Int]);
?T_AT -> "@";
?T_COLON -> ":";
?T_COMMA -> ",";

View File

@@ -37,8 +37,9 @@
-define(T_SYMBOL, 'T_SYMBOL'). % pushj, foo, .Lbar
%% literals
-define(T_UINTEGER, 'T_UINTEGER'). % 017
-define(T_LOCAL_LABEL, 'T_LOCAL_LABEL'). % 1f, 0b
-define(T_STRING, 'T_STRING'). % "foo"
-define(T_UINTEGER, 'T_UINTEGER'). % 017
%% special symbols including operators and separators
-define(T_AT, 'T_AT'). % @
@@ -60,8 +61,9 @@
| ?T_DOT_TEXT
| ?T_DOT_TYPE
| {?T_SYMBOL, string()}
| {?T_UINTEGER, non_neg_integer()}
| {?T_LOCAL_LABEL, non_neg_integer(), $b | $f}
| {?T_STRING, string()}
| {?T_UINTEGER, non_neg_integer()}
| ?T_AT
| ?T_COLON
| ?T_COMMA

View File

@@ -25,6 +25,8 @@
, put_section/2
, get_symbol/2
, put_symbol/2
, get_local_label/2
, put_local_label/3
]).
-include("tunit.hrl").
@@ -36,6 +38,7 @@ new() ->
#tunit{ sections = #{}
, cursect = false
, symbols = #{}
, local_labels = #{}
}.
-spec get_section(#tunit{}, string()) -> #section{} | false.
@@ -53,3 +56,11 @@ get_symbol(#tunit{symbols = Symbols}, Name) ->
-spec put_symbol(#tunit{}, #symbol{}) -> #tunit{}.
put_symbol(Tunit = #tunit{symbols = Symbols}, Symbol) ->
Tunit#tunit{symbols = maps:put(Symbol#symbol.name, Symbol, Symbols)}.
-spec get_local_label(#tunit{}, non_neg_integer()) -> pos_integer() | false.
get_local_label(#tunit{local_labels = LocalLabels}, Number) ->
maps:get(Number, LocalLabels, false).
-spec put_local_label(#tunit{}, non_neg_integer(), pos_integer()) -> #tunit{}.
put_local_label(Tunit = #tunit{local_labels = LocalLabels}, Number, Serial) ->
Tunit#tunit{local_labels = maps:put(Number, Serial, LocalLabels)}.

View File

@@ -24,9 +24,11 @@
%% An expression occurring in a statement. (TODO: extend)
-record(e_integer, {value :: integer()}).
-record(e_local_label, {number :: non_neg_integer(), direction :: $b | $f}).
-record(e_symbol, {name :: string()}).
-type expr() :: #e_integer{}
| #e_local_label{}
| #e_symbol{}
.
@@ -52,8 +54,9 @@
%% .type foo,@function (TODO: extend)
-record(s_dot_type, {name :: string()}).
%% foo:
%% foo: 1:
-record(s_label, {name :: string()}).
-record(s_local_label, {number :: non_neg_integer()}).
%% opcode accumulator,@address(index)
-record(s_insn,
@@ -70,6 +73,7 @@
| #s_dot_text{}
| #s_dot_type{}
| #s_label{}
| #s_local_label{}
| #s_insn{}
.
@@ -120,6 +124,7 @@
{ sections :: #{string() => #section{}}
, cursect :: string()
, symbols :: #{string() => #symbol{}}
, local_labels :: #{non_neg_integer() => pos_integer()}
}).
-endif. % TUNIT_HRL