diff --git a/erlang/apps/as/priv/test2.s b/erlang/apps/as/priv/test2.s
new file mode 100644
index 0000000..ada805b
--- /dev/null
+++ b/erlang/apps/as/priv/test2.s
@@ -0,0 +1,28 @@
+/*
+ * test2.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 .
+ */
+
+ .file "test2.s"
+ .text
+ .globl foo
+ .type foo,@function
+foo: jumpa .Lfie
+.Lfum: popj 017,
+.Lfie: jumpa .Lfum
+ .size foo,.-foo
diff --git a/erlang/apps/as/src/assemble.erl b/erlang/apps/as/src/assemble.erl
index 6f6c0c7..d6e7c53 100644
--- a/erlang/apps/as/src/assemble.erl
+++ b/erlang/apps/as/src/assemble.erl
@@ -73,38 +73,61 @@ image_size(Image) -> image_size(Image, 0).
image_size([H | T], Acc) -> image_size(T, image_size(H, Acc));
image_size([], Acc) -> Acc;
-image_size(TByte, Acc) when is_integer(TByte), 0 =< TByte, TByte =< 511 -> Acc + 1.
+image_size(TByte, Acc) when is_integer(TByte), 0 =< TByte, TByte =< 511 ->
+ Acc + 1.
%% Assemble .text --------------------------------------------------------------
text(Section = #section{data = {stmts, Stmts}}, Tunit) ->
- Image = text_image(Stmts),
- {ok, tunit:put_section(Tunit, Section#section{data = {image, Image}})}.
+ case text_image(Stmts, Tunit) of
+ {ok, Image} ->
+ {ok, tunit:put_section(Tunit, Section#section{data = {image, Image}})};
+ {error, _Reason} = Error -> Error
+ end.
-text_image(Stmts) -> text_image(Stmts, []).
+text_image(Stmts, Tunit) -> text_image(Stmts, Tunit, []).
-text_image([], Acc) -> Acc; % the input Stmts were in reverse order
-text_image([Stmt | Stmts], Acc) ->
- text_image(Stmts, [insn_image(Stmt) | Acc]).
+text_image([], _Tunit, Acc) -> {ok, Acc}; % the input Stmts were in reverse order
+text_image([Stmt | Stmts], Tunit, Acc) ->
+ case insn_image(Stmt, Tunit) of
+ {ok, Image} -> text_image(Stmts, Tunit, [Image | Acc]);
+ {error, _Reason} = Error -> Error
+ end.
-insn_image(Insn) ->
+insn_image(Insn, Tunit) ->
#s_insn{ high13 = High13
, at = At
- , address = Address
+ , address = AddressExpr
, index = Index
} = Insn,
- Word = (((High13 band ((1 bsl 13) - 1)) bsl (36 - 13)) bor
- ((case At of true -> 1; false -> 0 end) bsl (36 - 14)) bor
- ((Index band ((1 bsl 4) - 1)) bsl (36 - 18)) bor
- (Address band ((1 bsl 18) - 1))),
- %% big-endian conversion
- [(Word bsr 27) band 511,
- (Word bsr 18) band 511,
- (Word bsr 9) band 511,
- Word band 511].
+ case insn_address(AddressExpr, Tunit) of
+ {ok, Address} ->
+ Word = (((High13 band ((1 bsl 13) - 1)) bsl (36 - 13)) bor
+ ((case At of true -> 1; false -> 0 end) bsl (36 - 14)) bor
+ ((Index band ((1 bsl 4) - 1)) bsl (36 - 18)) bor
+ (Address band ((1 bsl 18) - 1))),
+ %% big-endian conversion
+ {ok, [(Word bsr 27) band 511,
+ (Word bsr 18) band 511,
+ (Word bsr 9) band 511,
+ Word band 511]};
+ {error, _Reason} = Error -> Error
+ end.
+
+insn_address(AddressExpr, Tunit) ->
+ case AddressExpr of
+ #e_integer{value = Value} -> {ok, Value};
+ #e_symbol{name = Name} ->
+ case tunit:get_symbol(Tunit, Name) of
+ #symbol{st_value = Value} when Value =/= false -> {ok, Value};
+ _ -> {error, {?MODULE, {undefined_symbol, Name}}}
+ end
+ end.
%% Error reporting -------------------------------------------------------------
-spec format_error(term()) -> io_lib:chars().
format_error({cannot_assemble, Name}) ->
- io_lib:format("don't know how to assemble section ~s", [Name]).
+ io_lib:format("don't know how to assemble section ~s", [Name]);
+format_error({undefined_symbol, Name}) ->
+ io_lib:format("reference to undefined symbol ~s", [Name]).
diff --git a/erlang/apps/as/src/parse.erl b/erlang/apps/as/src/parse.erl
index 8d98608..1969291 100644
--- a/erlang/apps/as/src/parse.erl
+++ b/erlang/apps/as/src/parse.erl
@@ -56,7 +56,7 @@ stmt(ScanState) ->
%%
%%
::= "@"? ? ?
%%
-%% ::=
+%% ::= |
%%
%% ::= "(" ")"
%%
@@ -66,6 +66,7 @@ stmt(ScanState) ->
%% popj 017,
%% pushj 017,bar
%% movei 1,@fum(2)
+%% jump bar
%%
%% TODO: should be and permit parentheses and
%% various operators.
@@ -92,6 +93,7 @@ stmt_after_symbol(ScanState, Name) ->
{ok, ?T_COLON} -> {ok, #s_label{name = 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);
ScanRes -> badtok(ScanState, "junk after symbol", ScanRes)
end.
@@ -102,27 +104,43 @@ insn_uint(ScanState, Name, UInt) ->
{ok, ?T_COMMA} -> % the Uint is the Accumulator, parse EA next
insn_ea(ScanState, Name, _AccOrDev = UInt);
{ok, ?T_LPAREN} -> % the Uint is the Displacement, parse Index next
- insn_ea_index(ScanState, Name, _AccOrDev = false, _At = false, _Displacement = UInt);
+ Displacement = #e_integer{value = UInt},
+ insn_ea_index(ScanState, Name, _AccOrDev = false, _At = false, Displacement);
{ok, ?T_NEWLINE} -> % the Uint is the Displacement
- make_insn(ScanState, Name, _AccOrDev = false, _At = false, _Displacement = UInt, _Index = false);
+ Displacement = #e_integer{value = UInt},
+ make_insn(ScanState, Name, _AccOrDev = false, _At = false, Displacement, _Index = false);
ScanRes -> badtok(ScanState, "junk after ", ScanRes)
end.
+%% Seen " ". The is (the start of) the .
+%% TODO: permit to be the (named register or device).
+insn_symbol(ScanState, Name, Symbol2) ->
+ Displacement = #e_symbol{name = Symbol2},
+ insn_ea_disp(ScanState, Name, _AccOrDev = false, _At = false, Displacement).
+
%% "," . [ ["@"] ["(" ")"] ]
insn_ea(ScanState, Name, AccOrDev) ->
case scan:token(ScanState) of
{ok, ?T_NEWLINE} ->
make_insn(ScanState, Name, AccOrDev, _At = false, _Displacement = false, _Index = false);
{ok, ?T_AT} -> insn_ea_at(ScanState, Name, AccOrDev);
- {ok, {?T_UINTEGER, Displacement}} ->
+ {ok, {?T_UINTEGER, UInt}} ->
+ Displacement = #e_integer{value = UInt},
+ insn_ea_disp(ScanState, Name, AccOrDev, _At = false, Displacement);
+ {ok, {?T_SYMBOL, Symbol}} ->
+ Displacement = #e_symbol{name = Symbol},
insn_ea_disp(ScanState, Name, AccOrDev, _At = false, Displacement);
ScanRes -> badtok(ScanState, "junk after comma", ScanRes)
end.
-%% [ ","] "@" . . ["(" ")"]
+%% [ ","] "@" . ["(" ")"]
insn_ea_at(ScanState, Name, AccOrDev) ->
case scan:token(ScanState) of
- {ok, {?T_UINTEGER, Displacement}} ->
+ {ok, {?T_UINTEGER, UInt}} ->
+ Displacement = #e_integer{value = UInt},
+ insn_ea_disp(ScanState, Name, AccOrDev, _At = true, Displacement);
+ {ok, {?T_SYMBOL, Symbol}} ->
+ Displacement = #e_symbol{name = Symbol},
insn_ea_disp(ScanState, Name, AccOrDev, _At = true, Displacement);
ScanRes -> badtok(ScanState, "junk after @", ScanRes)
end.
@@ -167,7 +185,10 @@ make_insn(ScanState, Name, AccOrDev, At, Displacement, Index) ->
{error, _Reason} = Error -> Error;
ok -> {ok, #s_insn{ high13 = FinalHigh13
, at = At
- , address = if Displacement =:= false -> 0; true -> Displacement end
+ , address = case Displacement of
+ false -> #e_integer{value = 0};
+ _ -> Displacement
+ end
, index = if Index =:= false -> 0; true -> Index end
}}
end
diff --git a/erlang/apps/as/src/tunit.hrl b/erlang/apps/as/src/tunit.hrl
index 2adca2e..1090745 100644
--- a/erlang/apps/as/src/tunit.hrl
+++ b/erlang/apps/as/src/tunit.hrl
@@ -21,6 +21,15 @@
-ifndef(TUNIT_HRL).
-define(TUNIT_HRL, 1).
+%% An expression occurring in a statement. (TODO: extend)
+
+-record(e_integer, {value :: integer()}).
+-record(e_symbol, {name :: string()}).
+
+-type expr() :: #e_integer{}
+ | #e_symbol{}
+ .
+
%% A directive, label, or instruction is parsed to a statement, which is
%% either interpreted immediately or appended to the representation of the
%% current section.