diff --git a/erlang/apps/as/priv/test6.s b/erlang/apps/as/priv/test6.s
new file mode 100644
index 0000000..4c09155
--- /dev/null
+++ b/erlang/apps/as/priv/test6.s
@@ -0,0 +1,23 @@
+/*
+ * test6.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 .
+ */
+
+ .text
+ .ascii "bar"
+ .asciz "foo", "fie", "fum"
diff --git a/erlang/apps/as/src/assemble.erl b/erlang/apps/as/src/assemble.erl
index 17807e9..815b322 100644
--- a/erlang/apps/as/src/assemble.erl
+++ b/erlang/apps/as/src/assemble.erl
@@ -100,12 +100,21 @@ stmts_image([Stmt | Stmts], Tunit, Acc) ->
stmt_image(Stmt, Tunit) ->
case Stmt of
+ #s_dot_ascii{} -> dot_ascii_image(Stmt, Tunit);
#s_dot_byte{} -> dot_byte_image(Stmt, Tunit);
#s_dot_long{} -> dot_long_image(Stmt, Tunit);
#s_dot_short{} -> dot_short_image(Stmt, Tunit);
#s_insn{} -> insn_image(Stmt, Tunit)
end.
+dot_ascii_image(#s_dot_ascii{z = Z, strings = Strings}, _Tunit) ->
+ Image =
+ case Z of
+ true -> [String ++ [0] || String <- Strings];
+ false -> Strings
+ end,
+ {ok, Image}.
+
dot_byte_image(#s_dot_byte{exprs = Exprs}, Tunit) ->
integer_data_directive(Exprs, Tunit, fun(Value) -> Value band ?PDP10_UINT9_MAX end).
diff --git a/erlang/apps/as/src/input.erl b/erlang/apps/as/src/input.erl
index d2389cc..5c1c8c3 100644
--- a/erlang/apps/as/src/input.erl
+++ b/erlang/apps/as/src/input.erl
@@ -313,6 +313,7 @@ pass2_stmts([{Location, Stmt} | Stmts], Tunit) ->
pass2_stmt(Location, Tunit, Stmt) ->
case Stmt of
+ #s_dot_ascii{} -> dot_ascii(Location, Tunit, Stmt);
#s_dot_byte{} -> dot_byte(Location, Tunit, Stmt);
#s_dot_file{} -> dot_file(Location, Tunit, Stmt);
#s_dot_globl{} -> dot_globl(Location, Tunit, Stmt);
@@ -326,6 +327,21 @@ pass2_stmt(Location, Tunit, Stmt) ->
#s_insn{} -> insn(Location, Tunit, Stmt)
end.
+dot_ascii(_Location, Tunit, #s_dot_ascii{z = Z, strings = Strings} = Stmt) ->
+ #tunit{cursect = Cursect} = Tunit,
+ #section{data = {stmts, Stmts}, dot = Dot} = Section = tunit:get_section(Tunit, Cursect),
+ Size0 = lists:sum(lists:map(fun erlang:length/1, Strings)),
+ Size =
+ case Z of
+ true -> Size0 + length(Strings);
+ false -> Size0
+ end,
+ NewSection =
+ Section#section{ data = {stmts, [Stmt | Stmts]}
+ , dot = Dot + Size
+ },
+ {ok, tunit:put_section(Tunit, NewSection)}.
+
dot_byte(Location, Tunit, #s_dot_byte{} = Stmt0) ->
integer_data_directive(Location, Tunit, Stmt0, 1, ".byte",
fun(Stmt) -> Stmt#s_dot_byte.exprs end,
diff --git a/erlang/apps/as/src/parse.erl b/erlang/apps/as/src/parse.erl
index d0cd659..4fc217e 100644
--- a/erlang/apps/as/src/parse.erl
+++ b/erlang/apps/as/src/parse.erl
@@ -34,6 +34,8 @@
-> {ok, {location(), stmt()}} | eof | {error, {module(), term()}}.
stmt(ScanState) ->
case scan:token(ScanState) of
+ {ok, {Location, ?T_DOT_ASCII}} -> dot_ascii(ScanState, Location);
+ {ok, {Location, ?T_DOT_ASCIZ}} -> dot_asciz(ScanState, Location);
{ok, {Location, ?T_DOT_BYTE}} -> dot_byte(ScanState, Location);
{ok, {Location, ?T_DOT_DATA}} -> dot_data(ScanState, Location);
{ok, {Location, ?T_DOT_FILE}} -> dot_file(ScanState, Location);
@@ -274,6 +276,23 @@ badinsn(Location, Fmt, Mnemonic) ->
%% Directives ------------------------------------------------------------------
+dot_ascii(ScanState, Location) ->
+ dot_ascii(ScanState, Location, ".ascii", _Z = false).
+
+dot_asciz(ScanState, Location) ->
+ dot_ascii(ScanState, Location, ".asciz", _Z = true).
+
+dot_ascii(ScanState, Location, Lexeme, Z) ->
+ case string_list(ScanState) of
+ {ok, {Strings, Follow}} ->
+ case Follow of
+ {_Location, ?T_NEWLINE} ->
+ {ok, {Location, #s_dot_ascii{z = Z, strings = Strings}}};
+ _ -> badtok("junk after " ++ Lexeme ++ " ", {ok, Follow})
+ end;
+ {error, _Reason} = Error -> Error
+ end.
+
dot_byte(ScanState, Location) ->
integer_data_directive(ScanState, Location, ".byte",
fun(Exprs) -> #s_dot_byte{exprs = Exprs} end).
@@ -500,6 +519,29 @@ expr_opt(ScanState) ->
Error
end.
+%% String Lists ----------------------------------------------------------------
+
+%% ::= ( ("," )*)?
+string_list(ScanState) ->
+ case scan:token(ScanState) of
+ {ok, {_Location, {?T_STRING, String}}} -> string_list(ScanState, [String]);
+ {ok, Follow} -> {ok, {[], Follow}};
+ {error, _Reason} = Error -> Error
+ end.
+
+string_list(ScanState, Strings) ->
+ case scan:token(ScanState) of
+ {ok, {_Location1, ?T_COMMA}} ->
+ case scan:token(ScanState) of
+ {ok, {_Location2, {?T_STRING, String}}} ->
+ string_list(ScanState, [String | Strings]);
+ {ok, First} -> badtok("expected string literal", {ok, First});
+ {error, _Reason} = Error -> Error
+ end;
+ {ok, Follow} -> {ok, {lists:reverse(Strings), Follow}};
+ {error, _Reason} = Error -> Error
+ end.
+
%% Error reporting -------------------------------------------------------------
badtok(_ErrMsg, {error, _Reason} = Error) -> Error;
diff --git a/erlang/apps/as/src/token.erl b/erlang/apps/as/src/token.erl
index 3ecc880..8506cd5 100644
--- a/erlang/apps/as/src/token.erl
+++ b/erlang/apps/as/src/token.erl
@@ -29,6 +29,8 @@
-spec from_symbol(string()) -> token().
from_symbol(Name) ->
case Name of
+ ".ascii" -> ?T_DOT_ASCII;
+ ".asciz" -> ?T_DOT_ASCIZ;
".byte" -> ?T_DOT_BYTE;
".data" -> ?T_DOT_DATA;
".file" -> ?T_DOT_FILE;
@@ -51,6 +53,8 @@ from_symbol(Name) ->
-spec format(token()) -> io_lib:chars().
format(Token) ->
case Token of
+ ?T_DOT_ASCII -> ".ascii";
+ ?T_DOT_ASCIZ -> ".asciz";
?T_DOT_BYTE -> ".byte";
?T_DOT_DATA -> ".data";
?T_DOT_FILE -> ".file";
diff --git a/erlang/apps/as/src/token.hrl b/erlang/apps/as/src/token.hrl
index 23553e9..1a3da82 100644
--- a/erlang/apps/as/src/token.hrl
+++ b/erlang/apps/as/src/token.hrl
@@ -26,6 +26,8 @@
%% with attributes (ordinary symbols, literals, errors).
%% reserved symbols including directives
+-define(T_DOT_ASCII, 'T_DOT_ASCII'). % .ascii
+-define(T_DOT_ASCIZ, 'T_DOT_ASCIZ'). % .asciz
-define(T_DOT_BYTE, 'T_DOT_BYTE'). % .byte
-define(T_DOT_DATA, 'T_DOT_DATA'). % .data
-define(T_DOT_FILE, 'T_DOT_FILE'). % .file
@@ -64,7 +66,9 @@
-define(T_NEWLINE, 'T_NEWLINE'). %
-define(T_EOF, 'T_EOF'). %
--type token() :: ?T_DOT_BYTE
+-type token() :: ?T_DOT_ASCII
+ | ?T_DOT_ASCIZ
+ | ?T_DOT_BYTE
| ?T_DOT_DATA
| ?T_DOT_FILE
| ?T_DOT_GLOBL
diff --git a/erlang/apps/as/src/tunit.hrl b/erlang/apps/as/src/tunit.hrl
index 19b5cb7..64fc667 100644
--- a/erlang/apps/as/src/tunit.hrl
+++ b/erlang/apps/as/src/tunit.hrl
@@ -36,6 +36,9 @@
%% either interpreted immediately or appended to the representation of the
%% current section.
+%% .asci{i,z} [string (, string)*]
+-record(s_dot_ascii, {z :: boolean(), strings :: [string()]}).
+
%% .byte [expr (, expr)*]
-record(s_dot_byte, {exprs :: [expr()]}).
@@ -90,7 +93,8 @@
, index :: 0..((1 bsl 4) - 1)
}).
--type stmt() :: #s_dot_data{}
+-type stmt() :: #s_dot_ascii{}
+ | #s_dot_data{}
| #s_dot_file{}
| #s_dot_globl{}
| #s_dot_ident{}