mirror of
https://github.com/mikpe/pdp10-tools.git
synced 2026-02-13 03:24:11 +00:00
as: support local labels
This commit is contained in:
28
erlang/apps/as/priv/test3.s
Normal file
28
erlang/apps/as/priv/test3.s
Normal 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
|
||||
@@ -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() ->
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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}}
|
||||
|
||||
@@ -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 -> ",";
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)}.
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user