diff --git a/erlang/apps/as/src/assemble.erl b/erlang/apps/as/src/assemble.erl index c167898..8750dd3 100644 --- a/erlang/apps/as/src/assemble.erl +++ b/erlang/apps/as/src/assemble.erl @@ -1,7 +1,7 @@ %%% -*- erlang-indent-level: 2 -*- %%% %%% sections assembler for pdp10-elf as -%%% Copyright (C) 2013-2020 Mikael Pettersson +%%% Copyright (C) 2013-2023 Mikael Pettersson %%% %%% This file is part of pdp10-tools. %%% @@ -183,16 +183,48 @@ exprs_values([Expr | Exprs], Tunit, SectionName, Dot, Size, Context, AccValues, {ok, {Value, Relocs}} = expr_value(Expr, Tunit, SectionName, Dot, Context), exprs_values(Exprs, Tunit, SectionName, Dot + Size, Size, Context, [Value | AccValues], Relocs ++ AccRelocs). -expr_value(Expr, Tunit, SectionName, Dot, Context) -> - #expr{symbol = Name, offset = Offset, modifier = Modifier} = Expr, - case Name of - false -> make_abs(Context, Modifier, Offset); - "." -> make_rel(Context, Modifier, Dot, SectionName, Dot + Offset); - _ -> - case tunit:get_symbol(Tunit, Name) of - #symbol{section = abs, st_value = Value} when Value =/= false -> - make_abs(Context, Modifier, Value + Offset); - _ -> make_rel(Context, Modifier, Dot, Name, Offset) +expr_value(Expr, Tunit, DotSection, Dot, Context) -> + #expr{modifier = Modifier} = Expr, + case expr_value(Expr, Tunit, DotSection, Dot) of + {Symbol, Offset} -> make_rel(Context, Modifier, Dot, Symbol, Offset); + Value -> make_abs(Context, Modifier, Value) + end. + +%% An expression can evaluate to: +%% - Value when is_integer(Value) +%% - {Symbol, Addend} when is_string(Symbol), is_integer(Addend) +expr_value(Expr, Tunit, DotSection, Dot) -> + #expr{operand1 = Opnd1, operator = Op, operand2 = Opnd2} = Expr, + case {Op, operand_value(Opnd1, Tunit, DotSection, Dot), operand_value(Opnd2, Tunit, DotSection, Dot)} of + {'+', false, Value2} -> Value2; + {'+', {Sect1, Off1}, Value2} when is_integer(Value2) -> {Sect1, Off1 + Value2}; + {'+', Value1, {Sect2, Off2}} when is_integer(Value1) -> {Sect2, Off2 + Value1}; + {'+', Value1, Value2} when is_integer(Value1), is_integer(Value2) -> Value1 + Value2; + {'-', false, Value2} when is_integer(Value2) -> -Value2; + {'-', {Sect, Off1}, {Sect, Off2}} -> Off1 - Off2; + {'-', {Sect1, Off1}, Value2} when is_integer(Value2) -> {Sect1, Off1 - Value2}; + {'-', Value1, Value2} when is_integer(Value1), is_integer(Value2) -> Value1 - Value2 + end. + +%% An operand can evaluate to: +%% - false +%% if the operand is absent +%% - Value when is_integer(Value) +%% if the operand is an integer or an absolute symbol +%% - {Section, Offset} when is_string(Section), is_integer(Offset) +%% if the operand is a label defined in the current translation unit +%% - {Symbol, 0} when is_string(Symbol) +%% if the operand is an undefined symbol +operand_value(Operand, Tunit, DotSection, Dot) -> + case Operand of + false -> false; + Value when is_integer(Value) -> Value; + "." -> {DotSection, Dot}; + Symbol when is_list(Symbol) -> + case tunit:get_symbol(Tunit, Symbol) of + #symbol{section = abs, st_value = Value} when Value =/= false -> Value; + #symbol{section = Section, st_value = Value} when Value =/= false -> {Section, Value}; + _ -> {Symbol, 0} end end. diff --git a/erlang/apps/as/src/input.erl b/erlang/apps/as/src/input.erl index 378cdc1..5318954 100644 --- a/erlang/apps/as/src/input.erl +++ b/erlang/apps/as/src/input.erl @@ -1,7 +1,7 @@ %%% -*- erlang-indent-level: 2 -*- %%% %%% input processing phase for pdp10-elf as -%%% Copyright (C) 2013-2020 Mikael Pettersson +%%% Copyright (C) 2013-2023 Mikael Pettersson %%% %%% This file is part of pdp10-tools. %%% @@ -634,18 +634,19 @@ insn_fixup(Tunit, Insn) -> Insn#s_insn{address = expr_fixup(Tunit, Address)}. expr_fixup(Tunit, Expr) -> - case Expr of - #expr{symbol = {Number, Direction}} -> - LabelSerial = local_label_serial(Tunit, Number), - ReferenceSerial = - case Direction of - $b -> LabelSerial; - $f -> LabelSerial + 1 - end, - Name = local_label_name(Number, ReferenceSerial), - Expr#expr{symbol = Name}; - _ -> Expr - end. + #expr{operand1 = Operand1, operand2 = Operand2} = Expr, + Expr#expr{operand1 = operand_fixup(Tunit, Operand1), + operand2 = operand_fixup(Tunit, Operand2)}. + +operand_fixup(Tunit, {Number, Direction}) -> + LabelSerial = local_label_serial(Tunit, Number), + ReferenceSerial = + case Direction of + $b -> LabelSerial; + $f -> LabelSerial + 1 + end, + local_label_name(Number, ReferenceSerial); +operand_fixup(_Tunit, Operand) -> Operand. %% Initialization -------------------------------------------------------------- diff --git a/erlang/apps/as/src/parse.erl b/erlang/apps/as/src/parse.erl index e2b6ddf..8ecfac1 100644 --- a/erlang/apps/as/src/parse.erl +++ b/erlang/apps/as/src/parse.erl @@ -1,7 +1,7 @@ %%% -*- erlang-indent-level: 2 -*- %%% %%% parser for pdp10-elf as -%%% Copyright (C) 2013-2020 Mikael Pettersson +%%% Copyright (C) 2013-2023 Mikael Pettersson %%% %%% This file is part of pdp10-tools. %%% @@ -605,8 +605,10 @@ section_name(ScanState) -> %% %% ::= "(" ")" %% | "-"? -%% | ( | ) (("+" | "-") )? +%% | (("+" | "-") )? +%% | "-" %% +%% := | %% ::= "w" | "b" | "h" %% %% Note: describes how the value should be represented, which also @@ -709,6 +711,10 @@ do_expr_offset(ScanState, Symbol, IsMinus, Modifier) -> case scan:token(ScanState) of {ok, {_Location, {?T_UINTEGER, UInt}}} -> {ok, mk_symbol_expr(Symbol, if IsMinus -> -UInt; true -> UInt end, Modifier)}; + {ok, {_Location, {?T_LOCAL_LABEL, Number, Direction}}} when IsMinus -> + {ok, mk_diff_expr(Symbol, _Symbol2 = {Number, Direction}, Modifier)}; + {ok, {_Location, {?T_SYMBOL, Symbol2}}} when IsMinus -> + {ok, mk_diff_expr(Symbol, Symbol2, Modifier)}; ScanRes -> badtok("expected after ", ScanRes) end. @@ -720,9 +726,10 @@ symbol_modifier(Symbol) -> _ -> error end. -mk_integer_expr(Value, Modifier) -> #expr{symbol = false, offset = Value, modifier = Modifier}. -mk_symbol_expr(Symbol, Modifier) -> #expr{symbol = Symbol, offset = 0, modifier = Modifier}. -mk_symbol_expr(Symbol, Offset, Modifier) -> #expr{symbol = Symbol, offset = Offset, modifier = Modifier}. +mk_integer_expr(Value, Modifier) -> #expr{operand1 = false, operator = '+', operand2 = Value, modifier = Modifier}. +mk_symbol_expr(Symbol, Modifier) -> #expr{operand1 = false, operator = '+', operand2 = Symbol, modifier = Modifier}. +mk_symbol_expr(Symbol, Offset, Modifier) -> #expr{operand1 = Symbol, operator = '+', operand2 = Offset, modifier = Modifier}. +mk_diff_expr(Symbol1, Symbol2, Modifier) -> #expr{operand1 = Symbol1, operator = '-', operand2 = Symbol2, modifier = Modifier}. %% String Lists ---------------------------------------------------------------- diff --git a/erlang/apps/as/src/tunit.hrl b/erlang/apps/as/src/tunit.hrl index a22881f..47632a0 100644 --- a/erlang/apps/as/src/tunit.hrl +++ b/erlang/apps/as/src/tunit.hrl @@ -1,7 +1,7 @@ %%% -*- erlang-indent-level: 2 -*- %%% %%% translation unit declarations for pdp10-elf as. -%%% Copyright (C) 2013-2020 Mikael Pettersson +%%% Copyright (C) 2013-2023 Mikael Pettersson %%% %%% This file is part of pdp10-tools. %%% @@ -23,9 +23,13 @@ %% An expression occurring in a statement. (TODO: extend) +-type operand() :: string() % label or symbol, may be "." + | {non_neg_integer(), $b | $f} % local label, eliminated before assembly + | integer(). -record(expr, - { symbol :: false | string() | {non_neg_integer(), $b | $f} - , offset :: integer() + { operand1 :: operand() | false + , operator :: '+' | '-' + , operand2 :: operand() , modifier :: false | w | b | h }). -type expr() :: #expr{}.