diff --git a/language_server/test/telemetry_test.cpp b/language_server/test/telemetry_test.cpp index 76b2e4c5c..32569b82b 100644 --- a/language_server/test/telemetry_test.cpp +++ b/language_server/test/telemetry_test.cpp @@ -112,7 +112,7 @@ TEST(telemetry, telemetry_broker) //"textDocument/hover",R"#({"textDocument":{"uri":"file:///c%3A/test/stability.hlasm"},"position":{"line":0,"character":7}})#"_json), - std::thread lsp_thread([&broker, &lsp_server]() { + std::thread lsp_thread([&lsp_server]() { lsp_server.message_received( R"({"jsonrpc":"2.0","id":48,"method":"textDocument/hover","params":{"textDocument":{"uri":"file:///test_file"},"position":{"line":0,"character":2} }})"_json); }); diff --git a/parser_library/src/context/CMakeLists.txt b/parser_library/src/context/CMakeLists.txt index dab2b4ad8..890d5c9cc 100644 --- a/parser_library/src/context/CMakeLists.txt +++ b/parser_library/src/context/CMakeLists.txt @@ -24,6 +24,8 @@ target_sources(parser_library PRIVATE instruction.cpp instruction.h instruction_type.h + literal_pool.cpp + literal_pool.h macro.cpp macro.h macro_param_data.cpp diff --git a/parser_library/src/context/hlasm_context.cpp b/parser_library/src/context/hlasm_context.cpp index 967019652..75a27d0c3 100644 --- a/parser_library/src/context/hlasm_context.cpp +++ b/parser_library/src/context/hlasm_context.cpp @@ -273,6 +273,8 @@ hlasm_context::hlasm_context(std::string file_name, asm_option asm_options, std: add_global_system_vars(); } +hlasm_context::~hlasm_context() = default; + void hlasm_context::set_source_position(position pos) { source_stack_.back().current_instruction.pos = pos; } void hlasm_context::set_source_indices(size_t begin_index, size_t end_index, size_t end_line) @@ -647,7 +649,7 @@ C_t hlasm_context::get_type_attr(var_sym_ptr var_symbol, const std::vector init_ids = std::make_shared()); + ~hlasm_context(); // gets name of file where is open-code located const std::string& opencode_file_name() const; diff --git a/parser_library/src/context/id_storage.h b/parser_library/src/context/id_storage.h index 13a369c8d..17d534bf4 100644 --- a/parser_library/src/context/id_storage.h +++ b/parser_library/src/context/id_storage.h @@ -67,8 +67,8 @@ class id_storage const std::string* AGO; const std::string* ACTR; const std::string* AREAD; - const std::string* END; const std::string* ALIAS; + const std::string* END; well_known_strings(std::unordered_set& ptr); } const well_known; diff --git a/parser_library/src/context/instruction.cpp b/parser_library/src/context/instruction.cpp index e39c9e5a0..00dcf1594 100644 --- a/parser_library/src/context/instruction.cpp +++ b/parser_library/src/context/instruction.cpp @@ -15,6 +15,7 @@ #include "instruction.h" #include +#include using namespace hlasm_plugin::parser_library::context; using namespace hlasm_plugin::parser_library::checking; @@ -179,7 +180,6 @@ const std::map instruction::assembler_instru { "XATTR", assembler_instruction(1, -1, false, "attribute+") }, }; - bool hlasm_plugin::parser_library::context::machine_instruction::check_nth_operand( size_t place, const checking::machine_operand* operand) { @@ -2670,3 +2670,55 @@ const std::map instruction::machine_instructio const std::map instruction::mnemonic_codes = instruction::get_mnemonic_codes(machine_instructions); + +// Generates a bitmask for an arbitrary machine instruction indicating which operands +// are of the RI type (and therefore are modified by transform_reloc_imm_operands) +unsigned char machine_instruction::generate_reladdr_bitmask( + const std::vector& operands) +{ + unsigned char result = 0; + + assert(operands.size() <= std::numeric_limits::digits); + + decltype(result) top_bit = 1 << (std::numeric_limits::digits - 1); + + for (const auto& op : operands) + { + if (op.identifier.type == checking::machine_operand_type::RELOC_IMM) + result |= top_bit; + top_bit >>= 1; + } + + return result; +} + +// Generates a bitmask for an arbitrary mnemonit indicating which operands +// are of the RI type (and therefore are modified by transform_reloc_imm_operands) +unsigned char mnemonic_code::generate_reladdr_bitmask( + const machine_instruction* instruction, const std::vector>& replaced) +{ + unsigned char result = 0; + + decltype(result) top_bit = 1 << (std::numeric_limits::digits - 1); + + const std::pair* replaced_b = replaced.data(); + const std::pair* const replaced_e = replaced.data() + replaced.size(); + + size_t position = 0; + for (const auto& op : instruction->operands) + { + if (replaced_b != replaced_e && position == replaced_b->first) + { + ++replaced_b; + ++position; + continue; + } + + if (op.identifier.type == checking::machine_operand_type::RELOC_IMM) + result |= top_bit; + top_bit >>= 1; + + ++position; + } + return result; +} diff --git a/parser_library/src/context/instruction.h b/parser_library/src/context/instruction.h index 4a906fc00..d35fbb882 100644 --- a/parser_library/src/context/instruction.h +++ b/parser_library/src/context/instruction.h @@ -178,10 +178,28 @@ const checking::machine_operand_format rel_addr_imm_24_S = const checking::machine_operand_format rel_addr_imm_32_S = checking::machine_operand_format(reladdr_imm_32s, empty, empty); +class reladdr_transform_mask +{ + unsigned char m_mask; + +public: + reladdr_transform_mask(unsigned char m) + : m_mask(m) + {} + unsigned char mask() const { return m_mask; } + + friend bool operator==(const reladdr_transform_mask& l, const reladdr_transform_mask& r) + { + return l.m_mask == r.m_mask; + } + friend bool operator!=(const reladdr_transform_mask& l, const reladdr_transform_mask& r) { return !(l == r); } +}; // machine instruction representation for checking class machine_instruction { + static unsigned char generate_reladdr_bitmask(const std::vector& operands); + public: std::string instr_name; mach_format format; @@ -190,18 +208,20 @@ class machine_instruction int no_optional; size_t page_no; + reladdr_transform_mask reladdr_mask; + machine_instruction(const std::string& name, mach_format format, std::vector operands, int no_optional, - size_t page_no) : instr_name(name) , format(format) , operands(operands) , size_for_alloc(get_length_by_format(format)) , no_optional(no_optional) - , page_no(page_no) {}; + , page_no(page_no) + , reladdr_mask(generate_reladdr_bitmask(operands)) {}; machine_instruction(const std::string& name, mach_format format, std::vector operands, @@ -237,16 +257,22 @@ struct ca_instruction // representation of mnemonic codes for machine instructions struct mnemonic_code { + static unsigned char generate_reladdr_bitmask( + const machine_instruction* instruction, const std::vector>& replaced); + public: mnemonic_code(const machine_instruction* instr, std::vector> replaced) : instruction(instr) - , replaced(replaced) {}; + , replaced(replaced) + , reladdr_mask(generate_reladdr_bitmask(instr, replaced)) {}; const machine_instruction* instruction; // first goes place, then value std::vector> replaced; + reladdr_transform_mask reladdr_mask; + size_t operand_count() const { return instruction->operands.size() + instruction->no_optional - replaced.size(); } }; diff --git a/parser_library/src/context/literal_pool.cpp b/parser_library/src/context/literal_pool.cpp new file mode 100644 index 000000000..ff488620b --- /dev/null +++ b/parser_library/src/context/literal_pool.cpp @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2021 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ + +#include "literal_pool.h" + +#include +#include + +#include "context/ordinary_assembly/ordinary_assembly_context.h" +#include "context/ordinary_assembly/postponed_statement.h" +#include "diagnosable_ctx.h" +#include "ebcdic_encoding.h" +#include "hlasm_context.h" +#include "processing/statement.h" +#include "semantics/operand_impls.h" + +namespace hlasm_plugin::parser_library::context { + +id_index literal_pool::add_literal(const std::string& literal_text, + const std::shared_ptr& dd, + range r, + size_t unique_id, + std::optional
loctr, + bool align_on_halfword) +{ + unique_id = dd->references_loctr ? unique_id : 0; + if (auto lit = get_literal(m_current_literal_pool_generation, dd, unique_id)) + return lit; + + auto [it, inserted] = m_literals.try_emplace( + literal_id { m_current_literal_pool_generation, unique_id, dd }, literal_text, std::move(r), std::move(loctr)); + // even if we end up inserting a duplicate + // we need to try to insert const expressions::data_definition->iterator relation + // because a single literal may be referenced by independent data_definitions + m_literals_genmap.try_emplace(literal_id { m_current_literal_pool_generation, unique_id, dd }, it); + // but we should not try to put logical duplicates on the pending queue + if (inserted) + { + m_pending_literals.emplace_back(it); + it->second.stack = hlasm_ctx.processing_stack(); + } + it->second.align_on_halfword |= align_on_halfword; + + return &it->second.text; +} + +id_index literal_pool::get_literal( + size_t generation, const std::shared_ptr& dd, size_t unique_id) const +{ + unique_id = dd->references_loctr ? unique_id : 0; + auto it = m_literals_genmap.find(literal_id { generation, unique_id, dd }); + if (it == m_literals_genmap.end()) + return nullptr; + return &it->second->second.text; +} + + +class literal_pool::literal_postponed_statement : public context::postponed_statement, + public processing::resolved_statement +{ + const literal_pool::literal_details* details; + semantics::operands_si op; + processing::op_code op_code; + + static const semantics::remarks_si empty_remarks; + static const semantics::label_si empty_label; + static const semantics::instruction_si empty_instr; + static const processing::processing_format dc_format; + +public: + literal_postponed_statement(const std::shared_ptr& dd, + const literal_pool::literal_details& details, + id_storage& ids) + : details(&details) + , op(details.r, {}) + , op_code(ids.add("DC"), instruction_type::ASM) + { + op.value.push_back(std::make_unique(dd, details.r)); + } + const processing_stack_t& location_stack() const override { return details->stack; } + const processing::resolved_statement* resolved_stmt() const override { return this; } + const processing::op_code& opcode_ref() const override { return op_code; } + processing::processing_format format_ref() const override { return dc_format; } + const semantics::operands_si& operands_ref() const override { return op; } + const semantics::remarks_si& remarks_ref() const override { return empty_remarks; } + const range& stmt_range_ref() const override { return details->r; } + const semantics::label_si& label_ref() const override { return empty_label; } + const semantics::instruction_si& instruction_ref() const override { return empty_instr; } + std::pair diagnostics() const override { return {}; }; +}; +const semantics::remarks_si literal_pool::literal_postponed_statement::empty_remarks({}, {}); +const semantics::label_si literal_pool::literal_postponed_statement::empty_label(range {}); +const semantics::instruction_si literal_pool::literal_postponed_statement::empty_instr(range {}); +const processing::processing_format literal_pool::literal_postponed_statement::dc_format( + processing::processing_kind::ORDINARY, processing::processing_form::ASM, processing::operand_occurence::PRESENT); + +void literal_pool::generate_pool(dependency_solver& solver, const diagnosable_ctx& diags) +{ + ordinary_assembly_context& ord_ctx = hlasm_ctx.ord_ctx; + + if (m_pending_literals.empty()) + return; + + for (auto& [it, size, alignment] : m_pending_literals) + { + const auto& lit = it->first.lit; + if (!lit->access_data_def_type()) // unknown type + continue; + + size = (semantics::data_def_operand::get_operand_value(*lit, solver).get_length() + 7) / 8; + if (size == 0) + continue; + + auto top_alignment = size | 16; // 16B length alignment is the top + alignment = (~top_alignment & top_alignment - 1) + 1; + } + + std::stable_sort(m_pending_literals.begin(), m_pending_literals.end(), [](const auto& l, const auto& r) { + return l.alignment > r.alignment; + }); + + constexpr auto sectalign = doubleword; + ord_ctx.align(sectalign); + + for (const auto& [it, size, alignment] : m_pending_literals) + { + const auto& lit_key = it->first; + const auto& lit = lit_key.lit; + const auto& lit_val = it->second; + + if (!lit->access_data_def_type()) // unknown type + continue; + + // TODO: warn on align > sectalign + + bool cycle_ok = ord_ctx.create_symbol(&lit_val.text, + ord_ctx.align(lit_val.align_on_halfword ? halfword : no_align), + symbol_attributes(symbol_origin::DAT, + ebcdic_encoding::a2e[(unsigned char)lit->get_type_attribute()], + lit->get_length_attribute(solver)), + {}); + + if (size == 0) + { + diags.add_diagnostic(diagnostic_op::error_D031(it->second.r)); + continue; + } + + ord_ctx.reserve_storage_area(size, no_align); + + if (!cycle_ok) + diags.add_diagnostic(diagnostic_op::error_E033(it->second.r)); + else if (lit->get_dependencies(solver).contains_dependencies()) + { + auto adder = ord_ctx.symbol_dependencies.add_dependencies( + std::make_unique(lit, lit_val, hlasm_ctx.ids()), + { lit_val.loctr, lit_key.generation, lit_key.unique_id }); + adder.add_dependency(); + adder.finish(); + } + else + { + auto ddt = lit->access_data_def_type(); + if (!ddt) // unknown type + continue; + + auto ddo = semantics::data_def_operand::get_operand_value(*lit, solver); + ddt->check_DC(ddo, diagnostic_collector(&diags, lit_val.stack)); + } + } + + m_pending_literals.clear(); + ++m_current_literal_pool_generation; +} + +bool literal_pool::literal_id::is_similar(const literal_id& ld) const noexcept +{ + return generation == ld.generation && unique_id == ld.unique_id && utils::is_similar(lit, ld.lit); +} + +size_t literal_pool::literal_definition_hasher::operator()(const literal_id& ld) const noexcept +{ + return ld.lit->hash() ^ ld.generation ^ ld.unique_id; +} + +} // namespace hlasm_plugin::parser_library::context diff --git a/parser_library/src/context/literal_pool.h b/parser_library/src/context/literal_pool.h new file mode 100644 index 000000000..05916e8e2 --- /dev/null +++ b/parser_library/src/context/literal_pool.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2021 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ + +#ifndef HLASMPLUGIN_PARSERLIBRARY_LITERAL_POOL_H +#define HLASMPLUGIN_PARSERLIBRARY_LITERAL_POOL_H + +#include +#include + +#include "expressions/data_definition.h" +#include "id_storage.h" +#include "location.h" +#include "processing_context.h" +#include "utils/similar.h" + +namespace hlasm_plugin::parser_library::context { +class hlasm_context; + +class literal_pool +{ + struct literal_id + { + size_t generation; + size_t unique_id; + std::shared_ptr lit; + + bool is_similar(const literal_id&) const noexcept; + }; + struct literal_details + { + std::string text; + range r; + std::optional
loctr; + processing_stack_t stack; + bool align_on_halfword = false; + + literal_details(std::string text, range r, std::optional
loctr) + : text(std::move(text)) + , r(r) + , loctr(std::move(loctr)) + {} + + literal_details(std::string text, range r, std::optional
loctr, processing_stack_t stack) + : text(std::move(text)) + , r(r) + , loctr(std::move(loctr)) + , stack(std::move(stack)) + {} + }; + class literal_postponed_statement; + struct literal_definition_hasher + { + size_t operator()(const literal_id&) const noexcept; + }; + size_t m_current_literal_pool_generation = 0; + + struct literal_id_helper + { + size_t operator()(const literal_id& p) const noexcept + { + return std::hash()(p.generation) ^ std::hash()(p.unique_id) + ^ std::hash()(p.lit.get()); + } + bool operator()(const literal_id& l, const literal_id& r) const noexcept + { + return l.lit == r.lit && l.generation == r.generation && l.unique_id == r.unique_id; + } + }; + + std::unordered_map m_literals; + std::unordered_map + m_literals_genmap; + + struct pending_literal + { + decltype(m_literals)::const_iterator literal; + size_t size = 0; + size_t alignment = 0; + + explicit pending_literal(decltype(m_literals)::const_iterator l) noexcept + : literal(l) + {} + }; + + std::vector m_pending_literals; + + hlasm_context& hlasm_ctx; + +public: + explicit literal_pool(hlasm_context& hlasm_ctx) + : hlasm_ctx(hlasm_ctx) + {} + + id_index add_literal(const std::string& literal_text, + const std::shared_ptr& dd, + range r, + size_t unique_id, + std::optional
loctr, + bool align_on_halfword); + id_index get_literal( + size_t generation, const std::shared_ptr& dd, size_t unique_id) const; + + void generate_pool(dependency_solver& solver, const diagnosable_ctx& diags); + size_t current_generation() const { return m_current_literal_pool_generation; } + + // testing + size_t get_pending_count() const { return m_pending_literals.size(); } +}; + +} // namespace hlasm_plugin::parser_library::context + +#endif diff --git a/parser_library/src/context/ordinary_assembly/CMakeLists.txt b/parser_library/src/context/ordinary_assembly/CMakeLists.txt index 0d652d8df..d84726e6b 100644 --- a/parser_library/src/context/ordinary_assembly/CMakeLists.txt +++ b/parser_library/src/context/ordinary_assembly/CMakeLists.txt @@ -28,6 +28,8 @@ target_sources(parser_library PRIVATE loctr_dependency_resolver.h ordinary_assembly_context.cpp ordinary_assembly_context.h + ordinary_assembly_dependency_solver.cpp + ordinary_assembly_dependency_solver.h postponed_statement.cpp postponed_statement.h section.cpp diff --git a/parser_library/src/context/ordinary_assembly/dependable.h b/parser_library/src/context/ordinary_assembly/dependable.h index 07fdb5c3d..c152adae6 100644 --- a/parser_library/src/context/ordinary_assembly/dependable.h +++ b/parser_library/src/context/ordinary_assembly/dependable.h @@ -18,6 +18,10 @@ #include "dependency_collector.h" #include "symbol.h" +namespace hlasm_plugin::parser_library::expressions { +struct data_definition; +} // namespace hlasm_plugin::parser_library::expressions + namespace hlasm_plugin::parser_library::context { // interface for obtaining symbol from its name @@ -25,6 +29,11 @@ class dependency_solver { public: virtual const symbol* get_symbol(id_index name) const = 0; + virtual std::optional
get_loctr() const = 0; + virtual id_index get_literal_id(const std::string&, + const std::shared_ptr&, + const range& r, + bool align_on_halfword) = 0; protected: ~dependency_solver() = default; diff --git a/parser_library/src/context/ordinary_assembly/loctr_dependency_resolver.h b/parser_library/src/context/ordinary_assembly/loctr_dependency_resolver.h index a0f6848f9..d8784a899 100644 --- a/parser_library/src/context/ordinary_assembly/loctr_dependency_resolver.h +++ b/parser_library/src/context/ordinary_assembly/loctr_dependency_resolver.h @@ -15,14 +15,18 @@ #ifndef CONTEXT_LOCTR_DEPENDENCY_RESOLVER_H #define CONTEXT_LOCTR_DEPENDENCY_RESOLVER_H +#include + #include "address.h" namespace hlasm_plugin::parser_library::context { +struct dependency_evaluation_context; class loctr_dependency_resolver { public: - virtual void resolve_unknown_loctr_dependency(space_ptr sp, const context::address& addr, range err_range) = 0; + virtual void resolve_unknown_loctr_dependency( + space_ptr sp, const context::address& addr, range err_range, const dependency_evaluation_context& dep_ctx) = 0; protected: ~loctr_dependency_resolver() = default; diff --git a/parser_library/src/context/ordinary_assembly/ordinary_assembly_context.cpp b/parser_library/src/context/ordinary_assembly/ordinary_assembly_context.cpp index 7dc584616..86a01380e 100644 --- a/parser_library/src/context/ordinary_assembly/ordinary_assembly_context.cpp +++ b/parser_library/src/context/ordinary_assembly/ordinary_assembly_context.cpp @@ -20,25 +20,28 @@ #include "alignment.h" #include "context/hlasm_context.h" +#include "context/literal_pool.h" namespace hlasm_plugin::parser_library::context { void ordinary_assembly_context::create_private_section() { - sections_.emplace_back(std::make_unique
(id_storage::empty_id, section_kind::EXECUTABLE, ids)); - curr_section_ = sections_.back().get(); + curr_section_ = create_section(id_storage::empty_id, section_kind::EXECUTABLE); } const std::vector>& ordinary_assembly_context::sections() const { return sections_; } const std::unordered_map& ordinary_assembly_context::symbols() const { return symbols_; } -ordinary_assembly_context::ordinary_assembly_context(id_storage& storage, const hlasm_context& hlasm_ctx) +ordinary_assembly_context::ordinary_assembly_context(id_storage& storage, hlasm_context& hlasm_ctx) : curr_section_(nullptr) + , m_literals(std::make_unique(hlasm_ctx)) , ids(storage) , hlasm_ctx_(hlasm_ctx) , symbol_dependencies(*this) {} +ordinary_assembly_context::ordinary_assembly_context(ordinary_assembly_context&&) noexcept = default; +ordinary_assembly_context::~ordinary_assembly_context() = default; bool ordinary_assembly_context::create_symbol( id_index name, symbol_value value, symbol_attributes attributes, location symbol_location) @@ -69,13 +72,6 @@ const symbol* ordinary_assembly_context::get_symbol_reference(context::id_index return tmp == symbol_refs_.end() ? nullptr : &tmp->second; } -const symbol* ordinary_assembly_context::get_symbol(id_index name) const -{ - auto tmp = symbols_.find(name); - - return tmp == symbols_.end() ? nullptr : &tmp->second; -} - symbol* ordinary_assembly_context::get_symbol(id_index name) { auto tmp = symbols_.find(name); @@ -107,11 +103,10 @@ void ordinary_assembly_context::set_section(id_index name, section_kind kind, lo curr_section_ = &**tmp; else { - if (symbols_.find(name) != symbols_.end()) + if (name != id_storage::empty_id && symbols_.find(name) != symbols_.end()) throw std::invalid_argument("symbol already defined"); - sections_.emplace_back(std::make_unique
(name, kind, ids)); - curr_section_ = sections_.back().get(); + curr_section_ = create_section(name, kind); auto tmp_addr = curr_section_->current_location_counter().current_address(); symbols_.try_emplace(name, @@ -141,9 +136,7 @@ void ordinary_assembly_context::create_external_section( if (!symbols_ .try_emplace(name, name, - sections_.emplace_back(std::make_unique
(name, kind, ids)) - ->current_location_counter() - .current_address(), + create_section(name, kind)->current_location_counter().current_address(), attrs, std::move(symbol_location), processing_stack) @@ -188,16 +181,24 @@ void ordinary_assembly_context::set_location_counter_value(const address& addr, size_t boundary, int offset, const resolvable* undefined_address, - post_stmt_ptr dependency_source) + post_stmt_ptr dependency_source, + const dependency_evaluation_context& dep_ctx) +{ + (void)set_location_counter_value_space( + addr, boundary, offset, undefined_address, std::move(dependency_source), dep_ctx); +} + +void ordinary_assembly_context::set_location_counter_value(const address& addr, size_t boundary, int offset) { - (void)set_location_counter_value_space(addr, boundary, offset, undefined_address, std::move(dependency_source)); + set_location_counter_value(addr, boundary, offset, nullptr, nullptr, dependency_evaluation_context {}); } space_ptr ordinary_assembly_context::set_location_counter_value_space(const address& addr, size_t boundary, int offset, const resolvable* undefined_address, - post_stmt_ptr dependency_source) + post_stmt_ptr dependency_source, + const dependency_evaluation_context& dep_ctx) { if (!curr_section_) create_private_section(); @@ -210,20 +211,23 @@ space_ptr ordinary_assembly_context::set_location_counter_value_space(const addr if (!undefined_address) symbol_dependencies.add_dependency(sp, std::make_unique( - std::move(curr_addr), std::vector
{ addr }, boundary, offset)); + std::move(curr_addr), std::vector
{ addr }, boundary, offset), + dep_ctx); else symbol_dependencies.add_dependency(sp, std::make_unique(undefined_address), + dep_ctx, std::move(dependency_source)); return sp; } else { - return reserve_storage_area_space(offset, alignment { 0, boundary ? boundary : 1 }).second; + return reserve_storage_area_space(offset, alignment { 0, boundary ? boundary : 1 }, dep_ctx).second; } } -void ordinary_assembly_context::set_available_location_counter_value(size_t boundary, int offset) +void ordinary_assembly_context::set_available_location_counter_value( + size_t boundary, int offset, const dependency_evaluation_context& dep_ctx) { if (!curr_section_) create_private_section(); @@ -232,14 +236,18 @@ void ordinary_assembly_context::set_available_location_counter_value(size_t boun if (sp) symbol_dependencies.add_dependency( - sp, std::make_unique(std::move(addr), boundary, offset)); + sp, std::make_unique(std::move(addr), boundary, offset), dep_ctx); else { if (boundary) - (void)align(alignment { 0, boundary }); - (void)reserve_storage_area(offset, context::no_align); + (void)align(alignment { 0, boundary }, dep_ctx); + (void)reserve_storage_area(offset, context::no_align, dep_ctx); } } +void ordinary_assembly_context::set_available_location_counter_value(size_t boundary, int offset) +{ + set_available_location_counter_value(boundary, offset, dependency_evaluation_context {}); +} bool ordinary_assembly_context::symbol_defined(id_index name) { return symbols_.find(name) != symbols_.end(); } @@ -263,12 +271,23 @@ bool ordinary_assembly_context::counter_defined(id_index name) return false; } +address ordinary_assembly_context::reserve_storage_area( + size_t length, alignment align, const dependency_evaluation_context& dep_ctx) +{ + return reserve_storage_area_space(length, align, dep_ctx).first; +} + address ordinary_assembly_context::reserve_storage_area(size_t length, alignment align) { - return reserve_storage_area_space(length, align).first; + return reserve_storage_area(length, align, dependency_evaluation_context {}); } -address ordinary_assembly_context::align(alignment align) { return reserve_storage_area(0, align); } +address ordinary_assembly_context::align(alignment align, const dependency_evaluation_context& dep_ctx) +{ + return reserve_storage_area(0, align, dep_ctx); +} + +address ordinary_assembly_context::align(alignment a) { return align(a, dependency_evaluation_context {}); } space_ptr ordinary_assembly_context::register_ordinary_space(alignment align) { @@ -300,7 +319,8 @@ void ordinary_assembly_context::finish_module_layout(loctr_dependency_resolver* const std::unordered_map& ordinary_assembly_context::get_all_symbols() { return symbols_; } -std::pair ordinary_assembly_context::reserve_storage_area_space(size_t length, alignment align) +std::pair ordinary_assembly_context::reserve_storage_area_space( + size_t length, alignment align, const dependency_evaluation_context& dep_ctx) { if (!curr_section_) create_private_section(); @@ -311,10 +331,27 @@ std::pair ordinary_assembly_context::reserve_storage_area_sp auto [ret_addr, sp] = curr_section_->current_location_counter().reserve_storage_area(length, align); assert(sp); - symbol_dependencies.add_dependency(sp, std::make_unique(addr)); + symbol_dependencies.add_dependency(sp, std::make_unique(addr), dep_ctx); return std::make_pair(ret_addr, sp); } return std::make_pair(curr_section_->current_location_counter().reserve_storage_area(length, align).first, nullptr); } +section* ordinary_assembly_context::create_section(id_index name, section_kind kind) +{ + section* ret = sections_.emplace_back(std::make_unique
(name, kind, ids)).get(); + if (first_control_section_ == nullptr + && (kind == section_kind::COMMON || kind == section_kind::EXECUTABLE || kind == section_kind::READONLY)) + first_control_section_ = ret; + return ret; +} + + +size_t ordinary_assembly_context::current_literal_pool_generation() const { return m_literals->current_generation(); } + +void ordinary_assembly_context::generate_pool(dependency_solver& solver, const diagnosable_ctx& diags) const +{ + m_literals->generate_pool(solver, diags); +} + } // namespace hlasm_plugin::parser_library::context diff --git a/parser_library/src/context/ordinary_assembly/ordinary_assembly_context.h b/parser_library/src/context/ordinary_assembly/ordinary_assembly_context.h index 2a56b8a29..8b229bff7 100644 --- a/parser_library/src/context/ordinary_assembly/ordinary_assembly_context.h +++ b/parser_library/src/context/ordinary_assembly/ordinary_assembly_context.h @@ -19,20 +19,28 @@ #include "alignment.h" #include "dependable.h" +#include "diagnostic_consumer.h" #include "location_counter.h" #include "loctr_dependency_resolver.h" #include "section.h" #include "symbol.h" #include "symbol_dependency_tables.h" +namespace hlasm_plugin::parser_library { +class diagnosable_ctx; +} // namespace hlasm_plugin::parser_library -namespace hlasm_plugin::parser_library::context { +namespace hlasm_plugin::parser_library::expressions { +struct data_definition; +} // namespace hlasm_plugin::parser_library::expressions +namespace hlasm_plugin::parser_library::context { class hlasm_context; +class literal_pool; // class holding complete information about the 'ordinary assembly' (assembler and machine instructions) // it contains 'sections' ordinary 'symbols' and all dependencies between them -class ordinary_assembly_context : public dependency_solver +class ordinary_assembly_context { // list of visited sections std::vector> sections_; @@ -42,11 +50,17 @@ class ordinary_assembly_context : public dependency_solver std::unordered_map symbol_refs_; section* curr_section_; + section* first_control_section_ = nullptr; + + // literals + std::unique_ptr m_literals; + size_t m_statement_unique_id = 1; -public: // access id storage id_storage& ids; - const hlasm_context& hlasm_ctx_; + hlasm_context& hlasm_ctx_; + +public: // access sections const std::vector>& sections() const; @@ -56,7 +70,9 @@ class ordinary_assembly_context : public dependency_solver // access symbol dependency table symbol_dependency_tables symbol_dependencies; - ordinary_assembly_context(id_storage& storage, const hlasm_context& hlasm_ctx); + ordinary_assembly_context(id_storage& storage, hlasm_context& hlasm_ctx); + ordinary_assembly_context(ordinary_assembly_context&&) noexcept; + ~ordinary_assembly_context(); // creates symbol // returns false if loctr cycle has occured @@ -66,8 +82,6 @@ class ordinary_assembly_context : public dependency_solver void add_symbol_reference(symbol sym); const symbol* get_symbol_reference(context::id_index name) const; - // gets symbol by name - const symbol* get_symbol(id_index name) const override; symbol* get_symbol(id_index name); // gets section by name @@ -91,14 +105,19 @@ class ordinary_assembly_context : public dependency_solver size_t boundary, int offset, const resolvable* undefined_address, - post_stmt_ptr dependency_source); + post_stmt_ptr dependency_source, + const dependency_evaluation_context& dep_ctx); + void set_location_counter_value(const address& addr, size_t boundary, int offset); space_ptr set_location_counter_value_space(const address& addr, size_t boundary, int offset, const resolvable* undefined_address, - post_stmt_ptr dependency_source); + post_stmt_ptr dependency_source, + const dependency_evaluation_context& dep_ctx); // sets next available value for the current location counter + void set_available_location_counter_value( + size_t boundary, int offset, const dependency_evaluation_context& dep_ctx); void set_available_location_counter_value(size_t boundary, int offset); // check whether symbol is already defined @@ -109,10 +128,12 @@ class ordinary_assembly_context : public dependency_solver bool counter_defined(id_index name); // reserves storage area of specified length and alignment + address reserve_storage_area(size_t length, alignment align, const dependency_evaluation_context& dep_ctx); address reserve_storage_area(size_t length, alignment align); // aligns storage - address align(alignment align); + address align(alignment align, const dependency_evaluation_context& dep_ctx); + address align(alignment a); // adds space to the current location counter space_ptr register_ordinary_space(alignment align); @@ -122,9 +143,26 @@ class ordinary_assembly_context : public dependency_solver const std::unordered_map& get_all_symbols(); + size_t current_literal_pool_generation() const; + size_t next_unique_id() { return m_statement_unique_id++; } + + const literal_pool& literals() const { return *m_literals; } + void generate_pool(dependency_solver& solver, const diagnosable_ctx& diags) const; + location_counter* implicit_ltorg_target() + { + if (!first_control_section_) + create_private_section(); + + return &first_control_section_->current_location_counter(); + } + private: void create_private_section(); - std::pair reserve_storage_area_space(size_t length, alignment align); + std::pair reserve_storage_area_space( + size_t length, alignment align, const dependency_evaluation_context& dep_ctx); + section* create_section(id_index name, section_kind kind); + + friend class ordinary_assembly_dependency_solver; }; } // namespace hlasm_plugin::parser_library::context diff --git a/parser_library/src/context/ordinary_assembly/ordinary_assembly_dependency_solver.cpp b/parser_library/src/context/ordinary_assembly/ordinary_assembly_dependency_solver.cpp new file mode 100644 index 000000000..1091d1a35 --- /dev/null +++ b/parser_library/src/context/ordinary_assembly/ordinary_assembly_dependency_solver.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ + +#include "ordinary_assembly_dependency_solver.h" + +#include "context/literal_pool.h" + +namespace hlasm_plugin::parser_library::context { + +const symbol* ordinary_assembly_dependency_solver::get_symbol(id_index name) const +{ + auto tmp = ord_context.symbols_.find(name); + + return tmp == ord_context.symbols_.end() ? nullptr : &tmp->second; +} + +std::optional
ordinary_assembly_dependency_solver::get_loctr() const { return loctr_addr; } + +id_index ordinary_assembly_dependency_solver::get_literal_id(const std::string& text, + const std::shared_ptr& lit, + const range& r, + bool align_on_halfword) +{ + if (allow_adding_literals) + return ord_context.m_literals->add_literal(text, lit, r, unique_id, get_loctr(), align_on_halfword); + else + return ord_context.m_literals->get_literal(literal_pool_generation, lit, unique_id); +} + + +dependency_evaluation_context ordinary_assembly_dependency_solver::derive_current_dependency_evaluation_context() const +{ + return dependency_evaluation_context { + loctr_addr, + literal_pool_generation, + unique_id, + }; +} + +} // namespace hlasm_plugin::parser_library::context \ No newline at end of file diff --git a/parser_library/src/context/ordinary_assembly/ordinary_assembly_dependency_solver.h b/parser_library/src/context/ordinary_assembly/ordinary_assembly_dependency_solver.h new file mode 100644 index 000000000..4e0d0333d --- /dev/null +++ b/parser_library/src/context/ordinary_assembly/ordinary_assembly_dependency_solver.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2021 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ + +#ifndef CONTEXT_ORDINARY_ASSEMBLY_DEPENDENCY_SOLVER_H +#define CONTEXT_ORDINARY_ASSEMBLY_DEPENDENCY_SOLVER_H + +#include "ordinary_assembly_context.h" + +namespace hlasm_plugin::parser_library::context { + +class ordinary_assembly_dependency_solver final : public dependency_solver +{ + ordinary_assembly_context& ord_context; + std::optional loctr_addr; + size_t literal_pool_generation = (size_t)-1; + size_t unique_id = 0; + bool allow_adding_literals = false; + +public: + explicit ordinary_assembly_dependency_solver(ordinary_assembly_context& ord_context) + : ord_context(ord_context) + , literal_pool_generation(ord_context.current_literal_pool_generation()) + , unique_id(ord_context.next_unique_id()) + , allow_adding_literals(true) + {} + struct no_new_literals + {}; + ordinary_assembly_dependency_solver(ordinary_assembly_context& ord_context, no_new_literals) + : ord_context(ord_context) + {} + + ordinary_assembly_dependency_solver(ordinary_assembly_context& ord_context, context::address loctr_addr) + : ord_context(ord_context) + , loctr_addr(std::move(loctr_addr)) + , literal_pool_generation(ord_context.current_literal_pool_generation()) + , unique_id(ord_context.next_unique_id()) + , allow_adding_literals(true) + {} + + ordinary_assembly_dependency_solver( + ordinary_assembly_context& ord_context, const dependency_evaluation_context& dep_ctx) + : ord_context(ord_context) + , loctr_addr(dep_ctx.loctr_address) + , literal_pool_generation(dep_ctx.literal_pool_generation) + , unique_id(dep_ctx.unique_id) + {} + + const symbol* get_symbol(id_index name) const override; + std::optional
get_loctr() const override; + id_index get_literal_id(const std::string& text, + const std::shared_ptr& lit, + const range& r, + bool align_on_halfword) override; + + dependency_evaluation_context derive_current_dependency_evaluation_context() const; +}; + +} // namespace hlasm_plugin::parser_library::context + +#endif \ No newline at end of file diff --git a/parser_library/src/context/ordinary_assembly/postponed_statement.cpp b/parser_library/src/context/ordinary_assembly/postponed_statement.cpp index a320b4a6b..8730bb3be 100644 --- a/parser_library/src/context/ordinary_assembly/postponed_statement.cpp +++ b/parser_library/src/context/ordinary_assembly/postponed_statement.cpp @@ -15,12 +15,3 @@ #include "postponed_statement.h" #include "processing/instruction_sets/postponed_statement_impl.h" - -namespace hlasm_plugin::parser_library::context { - -const processing::postponed_statement_impl* postponed_statement::impl() const -{ - return static_cast(this); -} - -} // namespace hlasm_plugin::parser_library::context diff --git a/parser_library/src/context/ordinary_assembly/postponed_statement.h b/parser_library/src/context/ordinary_assembly/postponed_statement.h index 6557bb842..cad33af0b 100644 --- a/parser_library/src/context/ordinary_assembly/postponed_statement.h +++ b/parser_library/src/context/ordinary_assembly/postponed_statement.h @@ -15,6 +15,8 @@ #ifndef CONTEXT_POSTPONED_STATEMENT_H #define CONTEXT_POSTPONED_STATEMENT_H +#include + #include "context/processing_context.h" namespace hlasm_plugin::parser_library::processing { @@ -29,7 +31,7 @@ struct postponed_statement { virtual const processing_stack_t& location_stack() const = 0; - const processing::postponed_statement_impl* impl() const; + virtual const processing::resolved_statement* resolved_stmt() const = 0; virtual ~postponed_statement() = default; }; diff --git a/parser_library/src/context/ordinary_assembly/symbol_dependency_tables.cpp b/parser_library/src/context/ordinary_assembly/symbol_dependency_tables.cpp index 2de05fc0b..759292ef0 100644 --- a/parser_library/src/context/ordinary_assembly/symbol_dependency_tables.cpp +++ b/parser_library/src/context/ordinary_assembly/symbol_dependency_tables.cpp @@ -21,6 +21,7 @@ #include #include "ordinary_assembly_context.h" +#include "ordinary_assembly_dependency_solver.h" #include "processing/instruction_sets/low_language_processor.h" #include "processing/instruction_sets/postponed_statement_impl.h" @@ -40,14 +41,11 @@ bool symbol_dependency_tables::check_cycle(dependant target, std::vectorsecond; - else + auto it = dependencies_.find(top_dep); + if (it == dependencies_.end()) continue; - for (auto&& dep : extract_dependencies(dep_src)) + for (auto&& dep : extract_dependencies(it->second.first, it->second.second)) { if (dep == target) { @@ -57,7 +55,6 @@ bool symbol_dependency_tables::check_cycle(dependant target, std::vector& dependency_source_stmts_; + const dependency_evaluation_context& dep_ctx; void operator()(const attr_ref& ref) const { @@ -96,18 +94,22 @@ struct resolve_dependant_visitor if (sp->kind == space_kind::LOCTR_UNKNOWN) resolver->resolve_unknown_loctr_dependency(sp, val.get_reloc(), - dependency_source_stmts_.find(sp)->second.stmt_ref->get()->impl()->stmt_range_ref()); + dependency_source_stmts_.find(sp)->second.stmt_ref->first->resolved_stmt()->stmt_range_ref(), + dep_ctx); else space::resolve(sp, length); } }; -void symbol_dependency_tables::resolve_dependant( - dependant target, const resolvable* dep_src, loctr_dependency_resolver* resolver) +void symbol_dependency_tables::resolve_dependant(dependant target, + const resolvable* dep_src, + loctr_dependency_resolver* resolver, + const dependency_evaluation_context& dep_ctx) { - symbol_value val = dep_src->resolve(sym_ctx_); + context::ordinary_assembly_dependency_solver dep_solver(sym_ctx_, dep_ctx); + symbol_value val = dep_src->resolve(dep_solver); - std::visit(resolve_dependant_visitor { val, resolver, sym_ctx_, dependency_source_stmts_ }, target); + std::visit(resolve_dependant_visitor { val, resolver, sym_ctx_, dependency_source_stmts_, dep_ctx }, target); } struct resolve_dependant_default_visitor @@ -145,17 +147,19 @@ void symbol_dependency_tables::resolve(loctr_dependency_resolver* resolver) while (defined) { defined = false; - for (auto& [target, dep_src] : dependencies_) + for (const auto& [target, dep_src_and_context] : dependencies_) { // resolve only symbol dependencies when resolver is not present if (resolver == nullptr && std::holds_alternative(target)) continue; - if (extract_dependencies(dep_src).empty()) // target no longer dependent on anything + const auto& [dep_src, context] = dep_src_and_context; + + if (extract_dependencies(dep_src, context).empty()) // target no longer dependent on anything { to_delete.push_back(target); - resolve_dependant(target, dep_src, resolver); // resolve target + resolve_dependant(target, dep_src, resolver, context); // resolve target defined = true; // another defined target => iterate again @@ -173,10 +177,12 @@ void symbol_dependency_tables::resolve(loctr_dependency_resolver* resolver) } } -std::vector symbol_dependency_tables::extract_dependencies(const resolvable* dependency_source) +std::vector symbol_dependency_tables::extract_dependencies( + const resolvable* dependency_source, const dependency_evaluation_context& dep_ctx) { std::vector ret; - auto deps = dependency_source->get_dependencies(sym_ctx_); + context::ordinary_assembly_dependency_solver dep_solver(sym_ctx_, dep_ctx); + auto deps = dependency_source->get_dependencies(dep_solver); ret.insert(ret.end(), std::make_move_iterator(deps.undefined_symbols.begin()), @@ -207,13 +213,13 @@ std::vector symbol_dependency_tables::extract_dependencies(const reso } std::vector symbol_dependency_tables::extract_dependencies( - const std::vector& dependency_sources) + const std::vector& dependency_sources, const dependency_evaluation_context& dep_ctx) { std::vector ret; for (auto dep : dependency_sources) { - auto tmp = extract_dependencies(dep); + auto tmp = extract_dependencies(dep, dep_ctx); ret.insert(ret.end(), std::make_move_iterator(tmp.begin()), std::make_move_iterator(tmp.end())); } return ret; @@ -243,8 +249,10 @@ symbol_dependency_tables::symbol_dependency_tables(ordinary_assembly_context& sy : sym_ctx_(sym_ctx) {} -bool symbol_dependency_tables::add_dependency( - dependant target, const resolvable* dependency_source, bool check_for_cycle) +bool symbol_dependency_tables::add_dependency(dependant target, + const resolvable* dependency_source, + bool check_for_cycle, + const dependency_evaluation_context& dep_ctx) { if (dependencies_.find(target) != dependencies_.end()) throw std::invalid_argument("symbol dependency already present"); @@ -252,7 +260,7 @@ bool symbol_dependency_tables::add_dependency( if (check_for_cycle) { - auto dependencies = extract_dependencies(dependency_source); + auto dependencies = extract_dependencies(dependency_source, dep_ctx); bool no_cycle = check_cycle(target, dependencies); if (!no_cycle) @@ -262,49 +270,58 @@ bool symbol_dependency_tables::add_dependency( } } - dependencies_.emplace(target, dependency_source); + dependencies_.try_emplace(target, dependency_source, dep_ctx); return true; } -bool symbol_dependency_tables::add_dependency( - id_index target, const resolvable* dependency_source, post_stmt_ptr dependency_source_stmt) +bool symbol_dependency_tables::add_dependency(id_index target, + const resolvable* dependency_source, + post_stmt_ptr dependency_source_stmt, + const dependency_evaluation_context& dep_ctx) { - dependency_adder adder(*this, std::move(dependency_source_stmt)); + dependency_adder adder(*this, std::move(dependency_source_stmt), dep_ctx); bool added = adder.add_dependency(target, dependency_source); adder.finish(); return added; } -bool symbol_dependency_tables::add_dependency( - id_index target, data_attr_kind attr, const resolvable* dependency_source, post_stmt_ptr dependency_source_stmt) +bool symbol_dependency_tables::add_dependency(id_index target, + data_attr_kind attr, + const resolvable* dependency_source, + post_stmt_ptr dependency_source_stmt, + const dependency_evaluation_context& dep_ctx) { - dependency_adder adder(*this, std::move(dependency_source_stmt)); + dependency_adder adder(*this, std::move(dependency_source_stmt), dep_ctx); bool added = adder.add_dependency(target, attr, dependency_source); adder.finish(); return added; } -void symbol_dependency_tables::add_dependency( - space_ptr space, const resolvable* dependency_source, post_stmt_ptr dependency_source_stmt) +void symbol_dependency_tables::add_dependency(space_ptr space, + const resolvable* dependency_source, + post_stmt_ptr dependency_source_stmt, + const dependency_evaluation_context& dep_ctx) { - dependency_adder adder(*this, std::move(dependency_source_stmt)); + dependency_adder adder(*this, std::move(dependency_source_stmt), dep_ctx); adder.add_dependency(space, dependency_source); adder.finish(); } -void symbol_dependency_tables::add_dependency( - space_ptr target, addr_res_ptr dependency_source, post_stmt_ptr dependency_source_stmt) +void symbol_dependency_tables::add_dependency(space_ptr target, + addr_res_ptr dependency_source, + const dependency_evaluation_context& dep_ctx, + post_stmt_ptr dependency_source_stmt) { auto [it, inserted] = dependency_source_addrs_.emplace(target, std::move(dependency_source)); - add_dependency(dependant(target), &*it->second, false); + add_dependency(dependant(target), &*it->second, false, dep_ctx); if (dependency_source_stmt) { - auto [sit, sinserted] = postponed_stmts_.emplace(std::move(dependency_source_stmt)); + auto [sit, sinserted] = postponed_stmts_.try_emplace(std::move(dependency_source_stmt), dep_ctx); if (!sinserted) throw std::runtime_error("statement already registered"); @@ -319,7 +336,7 @@ bool symbol_dependency_tables::check_cycle(space_ptr target) if (dep_src == dependencies_.end()) return true; - bool no_cycle = check_cycle(target, extract_dependencies(dep_src->second)); + bool no_cycle = check_cycle(target, extract_dependencies(dep_src->second.first, dep_src->second.second)); if (!no_cycle) resolve(nullptr); @@ -327,16 +344,17 @@ bool symbol_dependency_tables::check_cycle(space_ptr target) return no_cycle; } -void symbol_dependency_tables::add_dependency(post_stmt_ptr target) +void symbol_dependency_tables::add_dependency(post_stmt_ptr target, const dependency_evaluation_context& dep_ctx) { - dependency_adder adder(*this, std::move(target)); + dependency_adder adder(*this, std::move(target), dep_ctx); adder.add_dependency(); adder.finish(); } -dependency_adder symbol_dependency_tables::add_dependencies(post_stmt_ptr dependency_source_stmt) +dependency_adder symbol_dependency_tables::add_dependencies( + post_stmt_ptr dependency_source_stmt, const dependency_evaluation_context& dep_ctx) { - return dependency_adder(*this, std::move(dependency_source_stmt)); + return dependency_adder(*this, std::move(dependency_source_stmt), dep_ctx); } void symbol_dependency_tables::add_defined(loctr_dependency_resolver* resolver) { resolve(resolver); } @@ -352,24 +370,23 @@ bool symbol_dependency_tables::check_loctr_cycle() std::unordered_map visited; // create graph - for (auto& [target, dep_src] : dependencies_) + for (const auto& [target, dep_src_loctr] : dependencies_) { - if (std::holds_alternative(target)) - { - auto new_deps = extract_dependencies(dep_src); - if (!new_deps.empty() && std::holds_alternative(new_deps.front())) - continue; - else - { - std::vector space_deps; - for (auto& entry : new_deps) - if (std::holds_alternative(entry)) - space_deps.push_back(std::move(entry)); + if (!std::holds_alternative(target)) + continue; - if (!space_deps.empty()) - dep_g.emplace(target, std::move(space_deps)); - } - } + const auto& [dep_src, loctr] = dep_src_loctr; + auto new_deps = extract_dependencies(dep_src, loctr); + if (!new_deps.empty() && std::holds_alternative(new_deps.front())) + continue; + + std::vector space_deps; + for (auto& entry : new_deps) + if (std::holds_alternative(entry)) + space_deps.push_back(std::move(entry)); + + if (!space_deps.empty()) + dep_g.emplace(target, std::move(space_deps)); } // find cycle @@ -440,15 +457,15 @@ bool symbol_dependency_tables::check_loctr_cycle() return cycled.empty(); } -std::vector symbol_dependency_tables::collect_postponed() +std::vector> symbol_dependency_tables::collect_postponed() { - std::vector res; + std::vector> res; res.reserve(postponed_stmts_.size()); for (auto it = postponed_stmts_.begin(); it != postponed_stmts_.end();) { auto node = postponed_stmts_.extract(it++); - res.push_back(std::move(node.value())); + res.emplace_back(std::move(node.key()), std::move(node.mapped())); } postponed_stmts_.clear(); @@ -469,15 +486,17 @@ statement_ref::statement_ref(ref_t stmt_ref, size_t ref_count) , ref_count(ref_count) {} -dependency_adder::dependency_adder(symbol_dependency_tables& owner, post_stmt_ptr dependency_source_stmt) +dependency_adder::dependency_adder( + symbol_dependency_tables& owner, post_stmt_ptr dependency_source_stmt, const dependency_evaluation_context& dep_ctx) : owner_(owner) , ref_count_(0) + , dep_ctx(dep_ctx) , source_stmt(std::move(dependency_source_stmt)) {} bool dependency_adder::add_dependency(id_index target, const resolvable* dependency_source) { - bool added = owner_.add_dependency(dependant(target), dependency_source, true); + bool added = owner_.add_dependency(dependant(target), dependency_source, true, dep_ctx); if (added) { @@ -490,7 +509,7 @@ bool dependency_adder::add_dependency(id_index target, const resolvable* depende bool dependency_adder::add_dependency(id_index target, data_attr_kind attr, const resolvable* dependency_source) { - bool added = owner_.add_dependency(dependant(attr_ref { attr, target }), dependency_source, true); + bool added = owner_.add_dependency(dependant(attr_ref { attr, target }), dependency_source, true, dep_ctx); if (added) { @@ -503,7 +522,7 @@ bool dependency_adder::add_dependency(id_index target, data_attr_kind attr, cons void dependency_adder::add_dependency(space_ptr target, const resolvable* dependency_source) { - owner_.add_dependency(dependant(target), dependency_source, false); + owner_.add_dependency(dependant(target), dependency_source, false, dep_ctx); ++ref_count_; dependants.push_back(target); } @@ -515,7 +534,7 @@ void dependency_adder::finish() if (ref_count_ == 0) return; - auto [it, inserted] = owner_.postponed_stmts_.emplace(std::move(source_stmt)); + auto [it, inserted] = owner_.postponed_stmts_.try_emplace(std::move(source_stmt), dep_ctx); if (!inserted) throw std::runtime_error("statement already registered"); diff --git a/parser_library/src/context/ordinary_assembly/symbol_dependency_tables.h b/parser_library/src/context/ordinary_assembly/symbol_dependency_tables.h index 66e1f7a87..500c72336 100644 --- a/parser_library/src/context/ordinary_assembly/symbol_dependency_tables.h +++ b/parser_library/src/context/ordinary_assembly/symbol_dependency_tables.h @@ -15,6 +15,7 @@ #ifndef SEMANTICS_SYMBOL_DEPENDENCY_TABLES_H #define SEMANTICS_SYMBOL_DEPENDENCY_TABLES_H +#include #include #include #include @@ -31,13 +32,20 @@ namespace hlasm_plugin::parser_library::context { class ordinary_assembly_context; +struct dependency_evaluation_context +{ + std::optional
loctr_address; + size_t literal_pool_generation = 0; + size_t unique_id = 0; +}; + // helper structure to count dependencies of a statement struct statement_ref { - using ref_t = std::unordered_set::const_iterator; + using ref_t = std::unordered_map::const_iterator; statement_ref(ref_t stmt_ref, size_t ref_count = (size_t)1); - std::unordered_set::const_iterator stmt_ref; + ref_t stmt_ref; size_t ref_count; }; @@ -46,56 +54,73 @@ class dependency_adder; class symbol_dependency_tables { // actual dependecies of symbol or space - std::unordered_map dependencies_; + std::unordered_map> dependencies_; // statements where dependencies are from std::unordered_map dependency_source_stmts_; // addresses where dependencies are from std::unordered_map dependency_source_addrs_; // list of statements containing dependencies that can not be checked yet - std::unordered_set postponed_stmts_; + std::unordered_map postponed_stmts_; ordinary_assembly_context& sym_ctx_; bool check_cycle(dependant target, std::vector dependencies); - void resolve_dependant(dependant target, const resolvable* dep_src, loctr_dependency_resolver* resolver); + void resolve_dependant(dependant target, + const resolvable* dep_src, + loctr_dependency_resolver* resolver, + const dependency_evaluation_context& dep_ctx); void resolve_dependant_default(dependant target); void resolve(loctr_dependency_resolver* resolver); - std::vector extract_dependencies(const resolvable* dependency_source); - std::vector extract_dependencies(const std::vector& dependency_sources); + std::vector extract_dependencies( + const resolvable* dependency_source, const dependency_evaluation_context& dep_ctx); + std::vector extract_dependencies( + const std::vector& dependency_sources, const dependency_evaluation_context& dep_ctx); void try_erase_source_statement(dependant index); - bool add_dependency(dependant target, const resolvable* dependency_source, bool check_cycle); + bool add_dependency(dependant target, + const resolvable* dependency_source, + bool check_cycle, + const dependency_evaluation_context& dep_ctx); public: symbol_dependency_tables(ordinary_assembly_context& sym_ctx); // add symbol dependency on statement // returns false if cyclic dependency occured - [[nodiscard]] bool add_dependency( - id_index target, const resolvable* dependency_source, post_stmt_ptr dependency_source_stmt); + [[nodiscard]] bool add_dependency(id_index target, + const resolvable* dependency_source, + post_stmt_ptr dependency_source_stmt, + const dependency_evaluation_context& dep_ctx); // add symbol attribute dependency on statement // returns false if cyclic dependency occured [[nodiscard]] bool add_dependency(id_index target, data_attr_kind attr, const resolvable* dependency_source, - post_stmt_ptr dependency_source_stmt); + post_stmt_ptr dependency_source_stmt, + const dependency_evaluation_context& dep_ctx); // add space dependency - void add_dependency(space_ptr target, const resolvable* dependency_source, post_stmt_ptr dependency_source_stmt); - void add_dependency( - space_ptr target, addr_res_ptr dependency_source, post_stmt_ptr dependency_source_stmt = nullptr); + void add_dependency(space_ptr target, + const resolvable* dependency_source, + post_stmt_ptr dependency_source_stmt, + const dependency_evaluation_context& dep_ctx); + void add_dependency(space_ptr target, + addr_res_ptr dependency_source, + const dependency_evaluation_context& dep_ctx, + post_stmt_ptr dependency_source_stmt = nullptr); bool check_cycle(space_ptr target); // add statement dependency on its operands - void add_dependency(post_stmt_ptr target); + void add_dependency(post_stmt_ptr target, const dependency_evaluation_context& dep_ctx); // method for creating more than one dependency assigned to one statement - dependency_adder add_dependencies(post_stmt_ptr dependency_source_stmt); + dependency_adder add_dependencies( + post_stmt_ptr dependency_source_stmt, const dependency_evaluation_context& dep_ctx); // registers that some symbol has been defined // if resolver is present, location counter dependencies are checked as well (not just symbol deps) @@ -105,7 +130,7 @@ class symbol_dependency_tables bool check_loctr_cycle(); // collect all postponed statements either if they still contain dependent objects - std::vector collect_postponed(); + std::vector> collect_postponed(); // assign default values to all unresoved dependants void resolve_all_as_default(); @@ -120,11 +145,14 @@ class dependency_adder size_t ref_count_; std::vector dependants; + dependency_evaluation_context dep_ctx; public: post_stmt_ptr source_stmt; - dependency_adder(symbol_dependency_tables& owner, post_stmt_ptr dependency_source_stmt); + dependency_adder(symbol_dependency_tables& owner, + post_stmt_ptr dependency_source_stmt, + const dependency_evaluation_context& dep_ctx); // add symbol dependency on statement [[nodiscard]] bool add_dependency(id_index target, const resolvable* dependency_source); diff --git a/parser_library/src/diagnostic.cpp b/parser_library/src/diagnostic.cpp index ead2533d0..8e9b5c0d9 100644 --- a/parser_library/src/diagnostic.cpp +++ b/parser_library/src/diagnostic.cpp @@ -1529,6 +1529,11 @@ diagnostic_op diagnostic_op::error_D030(const range& range, const std::string& t return diagnostic_op(diagnostic_severity::error, "D030", "Only single symbol expected with type " + type, range); } +diagnostic_op diagnostic_op::error_D031(const range& range) +{ + return diagnostic_op(diagnostic_severity::error, "D031", "Duplication factor in literals must be positive", range); +} + diagnostic_op diagnostic_op::error_M135(const std::string& instr_name, long long from, long long to, const range& range) { diff --git a/parser_library/src/diagnostic.h b/parser_library/src/diagnostic.h index 96933e82d..043a0f687 100644 --- a/parser_library/src/diagnostic.h +++ b/parser_library/src/diagnostic.h @@ -445,6 +445,7 @@ struct diagnostic_op static diagnostic_op error_D028(const range& range); static diagnostic_op error_D029(const range& range); static diagnostic_op error_D030(const range& range, const std::string& type); + static diagnostic_op error_D031(const range& range); static diagnostic_op warn_D031(const range& range, const std::string& modifier); static diagnostic_op error_M102(const std::string& instr_name, const range& range); diff --git a/parser_library/src/diagnostic_adder.h b/parser_library/src/diagnostic_adder.h index 92519ada7..c6cb98027 100644 --- a/parser_library/src/diagnostic_adder.h +++ b/parser_library/src/diagnostic_adder.h @@ -39,6 +39,9 @@ class diagnostic_adder : op_diagnoser_(&diagnoser) , diag_range_(diag_range) {}; + explicit diagnostic_adder(range diag_range) + : diag_range_(diag_range) {}; + diagnostic_adder() = default; template>> diff --git a/parser_library/src/ebcdic_encoding.cpp b/parser_library/src/ebcdic_encoding.cpp index 0eec00afe..644fc26fd 100644 --- a/parser_library/src/ebcdic_encoding.cpp +++ b/parser_library/src/ebcdic_encoding.cpp @@ -65,6 +65,12 @@ unsigned char hlasm_plugin::parser_library::ebcdic_encoding::to_ebcdic(unsigned std::string hlasm_plugin::parser_library::ebcdic_encoding::to_ascii(unsigned char c) { + if (c == 0x0D || c == 0x25) // CR LF + return std::string { + static_cast(0b11100000 | ebcdic_encoding::unicode_private >> 4), + static_cast(0x80 | ebcdic_encoding::unicode_private & 0xf | c >> 6), + static_cast(0x80 | c & 0x3f), + }; auto val = e2a[c]; if (0x80 > val) return std::string({ static_cast(val) }); diff --git a/parser_library/src/ebcdic_encoding.h b/parser_library/src/ebcdic_encoding.h index 34b7caa46..ddfe391ca 100644 --- a/parser_library/src/ebcdic_encoding.h +++ b/parser_library/src/ebcdic_encoding.h @@ -77,6 +77,8 @@ class ebcdic_encoding static std::string to_ascii(unsigned char c); // Converts EBCDIC string to UTF-8 string. static std::string to_ascii(const std::string& s); + + static constexpr unsigned char unicode_private = 0xe0; }; inline unsigned char operator""_ebcdic(char c) { return ebcdic_encoding::a2e[static_cast(c)]; } diff --git a/parser_library/src/expressions/CMakeLists.txt b/parser_library/src/expressions/CMakeLists.txt index 947c4e801..30fe13bdb 100644 --- a/parser_library/src/expressions/CMakeLists.txt +++ b/parser_library/src/expressions/CMakeLists.txt @@ -19,6 +19,7 @@ target_sources(parser_library PRIVATE mach_expr_visitor.h mach_expression.cpp mach_expression.h + mach_operator.cpp mach_operator.h nominal_value.cpp nominal_value.h diff --git a/parser_library/src/expressions/conditional_assembly/terms/ca_constant.cpp b/parser_library/src/expressions/conditional_assembly/terms/ca_constant.cpp index 272f36bdc..4a6db20a4 100644 --- a/parser_library/src/expressions/conditional_assembly/terms/ca_constant.cpp +++ b/parser_library/src/expressions/conditional_assembly/terms/ca_constant.cpp @@ -43,36 +43,82 @@ void ca_constant::apply(ca_expr_visitor& visitor) const { visitor.visit(*this); context::SET_t ca_constant::evaluate(const evaluation_context&) const { return value; } +namespace { +context::A_t CA_selfdef(std::string_view value, diagnostic_adder& add_diagnostic) +{ + if (value.size() > 4) + { + add_diagnostic(diagnostic_op::error_CE007); + return 0; + } + + unsigned long long result = 0; + for (unsigned char c : value) + result = (result << 8) | c; + + return (context::A_t)result; +} +} // namespace + context::A_t ca_constant::self_defining_term( std::string_view type, std::string_view value, diagnostic_adder& add_diagnostic) { - if (value.empty() || type.size() != 1) + if (value.empty()) { - add_diagnostic(diagnostic_op::error_CE015); - return context::object_traits::default_v(); + /* noting to do */ } - - switch (std::toupper((unsigned char)type.front())) + else if (type.size() == 1) + { + switch (type.front()) + { + case 'b': + case 'B': + return ca_function::B2A(value, add_diagnostic).access_a(); + case 'c': + case 'C': + return ca_function::C2A(value, add_diagnostic).access_a(); + case 'd': + case 'D': + return ca_function::D2A(value, add_diagnostic).access_a(); + case 'x': + case 'X': + return ca_function::X2A(value, add_diagnostic).access_a(); + default: + break; + } + } + else if (type.size() == 2) { - case 'B': - return ca_function::B2A(value, add_diagnostic).access_a(); - case 'C': - return ca_function::C2A(value, add_diagnostic).access_a(); - case 'D': - return ca_function::D2A(value, add_diagnostic).access_a(); - case 'X': - return ca_function::X2A(value, add_diagnostic).access_a(); - default: - add_diagnostic(diagnostic_op::error_CE015); - return context::object_traits::default_v(); + switch (type.front()) + { + case 'c': + case 'C': + switch (type.back()) + { + case 'a': + case 'A': + return CA_selfdef(value, add_diagnostic); + + default: + break; + } + break; + + default: + break; + } } + add_diagnostic(diagnostic_op::error_CE015); + return context::object_traits::default_v(); } context::A_t ca_constant::self_defining_term(const std::string& value, diagnostic_adder& add_diagnostic) { - if (value.size() >= 3 && value[1] == '\'' && value.back() == '\'') - return self_defining_term( - std::string_view(value.c_str(), 1), std::string_view(value.c_str() + 2, value.size() - 3), add_diagnostic); + auto q = value.find('\''); + if (value.size() >= 3 && value.back() == '\'' && q != value.size() - 1) + return self_defining_term(std::string_view(value.c_str(), q), + std::string_view(value.c_str() + q + 1, value.size() - q - 2), + add_diagnostic); else return self_defining_term("D", value, add_diagnostic); } diff --git a/parser_library/src/expressions/conditional_assembly/terms/ca_symbol_attribute.cpp b/parser_library/src/expressions/conditional_assembly/terms/ca_symbol_attribute.cpp index 40b026a6b..6fe348410 100644 --- a/parser_library/src/expressions/conditional_assembly/terms/ca_symbol_attribute.cpp +++ b/parser_library/src/expressions/conditional_assembly/terms/ca_symbol_attribute.cpp @@ -16,6 +16,8 @@ #include "ca_var_sym.h" #include "context/ordinary_assembly/dependable.h" +#include "context/ordinary_assembly/ordinary_assembly_dependency_solver.h" +#include "ebcdic_encoding.h" #include "expressions/conditional_assembly/ca_expr_visitor.h" #include "expressions/evaluation_context.h" #include "lexing/lexer.h" @@ -58,6 +60,14 @@ ca_symbol_attribute::ca_symbol_attribute( , symbol_range(symbol_rng) {} +ca_symbol_attribute::ca_symbol_attribute( + ca_literal_def lit, context::data_attr_kind attribute, range expr_range, range symbol_rng) + : ca_expression(get_attribute_type(attribute), std::move(expr_range)) + , attribute(attribute) + , symbol(std::move(lit)) + , symbol_range(symbol_rng) +{} + undef_sym_set ca_symbol_attribute::get_undefined_attributed_symbols(const evaluation_context& eval_ctx) const { if (std::holds_alternative(symbol)) @@ -82,7 +92,7 @@ undef_sym_set ca_symbol_attribute::get_undefined_attributed_symbols(const evalua if (substituted_name.type != context::SET_t_enum::C_TYPE) return {}; - auto [valid, ord_name] = mngr.try_get_symbol_name(substituted_name.access_c()); + auto [valid, ord_name] = mngr.try_get_symbol_name(try_extract_leading_symbol(substituted_name.access_c())); if (!valid) return {}; @@ -94,6 +104,11 @@ undef_sym_set ca_symbol_attribute::get_undefined_attributed_symbols(const evalua } return undef_syms; } + else if (std::holds_alternative(symbol)) + { + // everything needs to be defined + return undef_sym_set(); + } else { assert(false); @@ -113,10 +128,15 @@ void ca_symbol_attribute::collect_diags() const { if (std::holds_alternative(symbol)) { - auto&& sym = std::get(symbol); - for (auto&& expr : sym->subscript) + const auto& sym = std::get(symbol); + for (const auto& expr : sym->subscript) collect_diags_from_child(*expr); } + else if (std::holds_alternative(symbol)) + { + const auto& lit = std::get(symbol); + collect_diags_from_child(*lit.dd); + } } bool ca_symbol_attribute::is_character_expression(character_expression_purpose) const @@ -138,38 +158,35 @@ context::SET_t ca_symbol_attribute::evaluate(const evaluation_context& eval_ctx) return evaluate_varsym(std::get(symbol), eval_ctx); } + if (std::holds_alternative(symbol)) + { + return evaluate_literal(std::get(symbol), eval_ctx); + } + return context::SET_t(expr_kind); } - -void ca_symbol_attribute::try_extract_leading_symbol(std::string& expr) +std::string ca_symbol_attribute::try_extract_leading_symbol(std::string_view expr) { - std::string delims = "+-*/()"; - // remove parentheses - size_t start = 0; - for (; start < expr.size() && expr[start] == '(' && expr[expr.size() - 1 - start] == ')'; ++start) {}; - expr.resize(expr.size() - start); - - // remove leading using prefixes - for (size_t i = start; i < expr.size(); ++i) + while (!expr.empty() && expr.front() == '(' && expr.back() == ')') { - if (expr[i] == '.' && i != expr.size() - 1) - start = i + 1; - else if (!lexing::lexer::ord_char(expr[i])) - break; + expr.remove_prefix(1); + expr.remove_suffix(1); } - expr.erase(0, start); - // look for symbol in the rest - if (expr.front() >= '0' && expr.front() <= '9') - return; - for (size_t i = 0; i < expr.size(); ++i) + // remove leading using prefixes + for (auto p = expr.find_first_of('.'); p != std::string_view::npos && !std::isdigit((unsigned char)expr.front()) + && std::all_of(expr.begin(), expr.begin() + p, lexing::lexer::ord_char); + p = expr.find_first_of('.')) + expr.remove_prefix(p + 1); + + // try to isolate one ordinary symbol + if (!expr.empty() && !std::isdigit((unsigned char)expr.front()) && lexing::lexer::ord_char(expr.front())) { - if (delims.find(expr[i]) != std::string::npos) - expr.resize(i); - else if (!lexing::lexer::ord_char(expr[i])) - return; + if (auto d = expr.find_first_of("+-*/()"); d != std::string_view::npos) + expr = expr.substr(0, d); } + return std::string(expr); } context::SET_t ca_symbol_attribute::get_ordsym_attr_value( @@ -235,6 +252,41 @@ context::SET_t ca_symbol_attribute::evaluate_ordsym(context::id_index name, cons } } +context::SET_t ca_symbol_attribute::evaluate_literal( + const ca_literal_def& lit, const evaluation_context& eval_ctx) const +{ + context::ordinary_assembly_dependency_solver solver( + eval_ctx.hlasm_ctx.ord_ctx, eval_ctx.hlasm_ctx.ord_ctx.align(context::no_align)); + (void)solver.get_literal_id(lit.text, lit.dd, expr_range, false); + + if (attribute == context::data_attr_kind::D) + return false; + else if (attribute == context::data_attr_kind::O) + { + eval_ctx.add_diagnostic(diagnostic_op::error_E066(expr_range)); + return {}; + } + else if (attribute == context::data_attr_kind::T) + { + return "U"; + } + else + { + context::symbol_attributes attrs(context::symbol_origin::DAT, + ebcdic_encoding::a2e[(unsigned char)lit.dd->get_type_attribute()], + lit.dd->get_length_attribute(solver), + lit.dd->get_scale_attribute(solver), + lit.dd->get_integer_attribute(solver)); + if ((attribute == context::data_attr_kind::S || attribute == context::data_attr_kind::I) + && !attrs.can_have_SI_attr()) + { + add_diagnostic(diagnostic_op::warning_W011(symbol_range)); + return 0; + } + return attrs.get_attribute_value(attribute); + } +} + std::vector transform(const std::vector& v) { std::vector ret; @@ -302,8 +354,7 @@ context::SET_t ca_symbol_attribute::evaluate_substituted(context::id_index var_n return context::symbol_attributes::default_ca_value(attribute); } - try_extract_leading_symbol(substituted_name.access_c()); - auto [valid, ord_name] = mngr.try_get_symbol_name(substituted_name.access_c()); + auto [valid, ord_name] = mngr.try_get_symbol_name(try_extract_leading_symbol(substituted_name.access_c())); if (!valid) { diff --git a/parser_library/src/expressions/conditional_assembly/terms/ca_symbol_attribute.h b/parser_library/src/expressions/conditional_assembly/terms/ca_symbol_attribute.h index 8773d3286..721cf5bf8 100644 --- a/parser_library/src/expressions/conditional_assembly/terms/ca_symbol_attribute.h +++ b/parser_library/src/expressions/conditional_assembly/terms/ca_symbol_attribute.h @@ -18,15 +18,23 @@ #include #include "../ca_expression.h" +#include "expressions/data_definition.h" #include "semantics/variable_symbol.h" namespace hlasm_plugin::parser_library::expressions { +struct ca_literal_def +{ + std::string text; + std::shared_ptr dd; +}; + // represents CA expression attributed ordinary symbol class ca_symbol_attribute : public ca_expression { - // variant of ordinary symbol, variable symbol(, literal TODO) - using ca_attr_variant_t = std::variant; + // variant of ordinary symbol, variable symbol, literal + + using ca_attr_variant_t = std::variant; public: const context::data_attr_kind attribute; @@ -37,6 +45,7 @@ class ca_symbol_attribute : public ca_expression context::id_index symbol, context::data_attr_kind attribute, range expr_range, range symbol_range); ca_symbol_attribute( semantics::vs_ptr symbol, context::data_attr_kind attribute, range expr_range, range symbol_range); + ca_symbol_attribute(ca_literal_def lit, context::data_attr_kind attribute, range expr_range, range symbol_range); undef_sym_set get_undefined_attributed_symbols(const evaluation_context& eval_ctx) const override; @@ -52,7 +61,7 @@ class ca_symbol_attribute : public ca_expression // if expr contains a symbol as a first term, the rest of the string is thrown away // used for L'I'S'T' reference of variable symbol - static void try_extract_leading_symbol(std::string& expr); + static std::string try_extract_leading_symbol(std::string_view expr); private: context::SET_t get_ordsym_attr_value(context::id_index name, const evaluation_context& eval_ctx) const; @@ -64,6 +73,7 @@ class ca_symbol_attribute : public ca_expression std::vector expr_subscript, range var_range, const evaluation_context& eval_ctx) const; + context::SET_t evaluate_literal(const ca_literal_def& lit, const evaluation_context& eval_ctx) const; }; } // namespace hlasm_plugin::parser_library::expressions diff --git a/parser_library/src/expressions/data_definition.cpp b/parser_library/src/expressions/data_definition.cpp index b15c2c9dc..dc2592bdf 100644 --- a/parser_library/src/expressions/data_definition.cpp +++ b/parser_library/src/expressions/data_definition.cpp @@ -22,7 +22,9 @@ #include "checking/data_definition/data_def_fields.h" #include "checking/data_definition/data_def_type_base.h" #include "mach_expr_term.h" +#include "mach_expr_visitor.h" #include "semantics/collector.h" +#include "utils/similar.h" using namespace hlasm_plugin::parser_library::expressions; using namespace hlasm_plugin::parser_library; @@ -144,7 +146,7 @@ char hlasm_plugin::parser_library::expressions::data_definition::get_type_attrib return 'U'; } -int32_t data_definition::get_scale_attribute(expressions::mach_evaluate_info info) const +int32_t data_definition::get_scale_attribute(context::dependency_solver& info) const { auto def_type = access_data_def_type(); if (def_type) @@ -153,7 +155,7 @@ int32_t data_definition::get_scale_attribute(expressions::mach_evaluate_info inf return 0; } -uint32_t data_definition::get_length_attribute(expressions::mach_evaluate_info info) const +uint32_t data_definition::get_length_attribute(context::dependency_solver& info) const { auto def_type = access_data_def_type(); if (def_type) @@ -162,7 +164,7 @@ uint32_t data_definition::get_length_attribute(expressions::mach_evaluate_info i return 0; } -int32_t data_definition::get_integer_attribute(expressions::mach_evaluate_info info) const +int32_t data_definition::get_integer_attribute(context::dependency_solver& info) const { auto def_type = access_data_def_type(); if (def_type) @@ -227,37 +229,39 @@ std::vector data_definition::get_single_symbol_names() const return symbols; } -void data_definition::assign_location_counter(context::address loctr_value) +void data_definition::collect_diags() const { if (dupl_factor) - dupl_factor->fill_location_counter(loctr_value); + collect_diags_from_child(*dupl_factor); if (program_type) - program_type->fill_location_counter(loctr_value); + collect_diags_from_child(*program_type); if (length) - length->fill_location_counter(loctr_value); + collect_diags_from_child(*length); if (scale) - scale->fill_location_counter(loctr_value); + collect_diags_from_child(*scale); if (exponent) - exponent->fill_location_counter(loctr_value); + collect_diags_from_child(*exponent); + if (nominal_value && nominal_value->access_exprs()) { - for (auto& entry : nominal_value->access_exprs()->exprs) + for (const auto& val : nominal_value->access_exprs()->exprs) { - if (std::holds_alternative(entry)) - std::get(entry)->fill_location_counter(loctr_value); + if (std::holds_alternative(val)) + collect_diags_from_child(*std::get(val)); else { - std::get(entry).base->fill_location_counter(loctr_value); - std::get(entry).displacement->fill_location_counter(loctr_value); + const auto& addr = std::get(val); + if (addr.base) + collect_diags_from_child(*addr.base); + if (addr.displacement) + collect_diags_from_child(*addr.displacement); } } } } -void data_definition::collect_diags() const {} - checking::data_def_field set_data_def_field( - const expressions::mach_expression* e, expressions::mach_evaluate_info info) + const expressions::mach_expression* e, context::dependency_solver& info) { using namespace checking; data_def_field field; @@ -274,12 +278,12 @@ checking::data_def_field set_data_def_field( return field; } -checking::dupl_factor_modifier_t data_definition::evaluate_dupl_factor(expressions::mach_evaluate_info info) const +checking::dupl_factor_modifier_t data_definition::evaluate_dupl_factor(context::dependency_solver& info) const { - return set_data_def_field(dupl_factor.get(), info); + return dupl_factor ? set_data_def_field(dupl_factor.get(), info) : checking::data_def_field(1); } -checking::data_def_length_t data_definition::evaluate_length(expressions::mach_evaluate_info info) const +checking::data_def_length_t data_definition::evaluate_length(context::dependency_solver& info) const { checking::data_def_length_t len(set_data_def_field(length.get(), info)); len.len_type = length_type == expressions::data_definition::length_type::BIT ? checking::data_def_length_t::BIT @@ -287,88 +291,150 @@ checking::data_def_length_t data_definition::evaluate_length(expressions::mach_e return len; } -checking::scale_modifier_t data_definition::evaluate_scale(expressions::mach_evaluate_info info) const +checking::scale_modifier_t data_definition::evaluate_scale(context::dependency_solver& info) const { auto common = set_data_def_field(scale.get(), info); return checking::scale_modifier_t(common.present, (int16_t)common.value, common.rng); } -checking::exponent_modifier_t data_definition::evaluate_exponent(expressions::mach_evaluate_info info) const +checking::exponent_modifier_t data_definition::evaluate_exponent(context::dependency_solver& info) const { return set_data_def_field(exponent.get(), info); } -checking::nominal_value_t data_definition::evaluate_nominal_value(expressions::mach_evaluate_info info) const +inline checking::nominal_value_expressions extract_nominal_value_expressions( + const expr_or_address_list& exprs, context::dependency_solver& info) { - checking::nominal_value_t nom; - if (nominal_value) + checking::nominal_value_expressions values; + for (const auto& e_or_a : exprs) { - nom.present = true; - if (nominal_value->access_string()) + if (std::holds_alternative(e_or_a)) { - nom.value = nominal_value->access_string()->value; - nom.rng = nominal_value->access_string()->value_range; - } - else if (nominal_value->access_exprs()) - { - checking::nominal_value_expressions values; - for (auto& e_or_a : nominal_value->access_exprs()->exprs) + const expressions::mach_expr_ptr& e = std::get(e_or_a); + auto deps = e->get_dependencies(info); + bool ignored = deps.has_error || deps.contains_dependencies(); // ignore values with dependencies + auto ev = e->evaluate(info); + auto kind = ev.value_kind(); + if (kind == context::symbol_value_kind::ABS) + { + values.push_back(checking::data_def_expr { + ev.get_abs(), + checking::expr_type::ABS, + e->get_range(), + ignored, + }); + } + else if (kind == context::symbol_value_kind::RELOC) { - if (std::holds_alternative(e_or_a)) - { - expressions::mach_expr_ptr& e = std::get(e_or_a); - bool ignored = e->get_dependencies(info).has_error - || e->get_dependencies(info).contains_dependencies(); // ignore values with dependencies - auto ev = e->evaluate(info); - auto kind = ev.value_kind(); - if (kind == context::symbol_value_kind::ABS) - values.push_back(checking::data_def_expr { - ev.get_abs(), checking::expr_type::ABS, e->get_range(), ignored }); - - else if (kind == context::symbol_value_kind::RELOC) - { - checking::expr_type ex_type; - const auto& reloc = ev.get_reloc(); - if (reloc.is_complex()) - ex_type = checking::expr_type::COMPLEX; - else - ex_type = checking::expr_type::RELOC; - // TO DO value of the relocatable expression - // maybe push back data_def_addr? - values.push_back(checking::data_def_expr { 0, ex_type, e->get_range(), ignored }); - } - else if (kind == context::symbol_value_kind::UNDEF) - { - values.push_back(checking::data_def_expr { 0, checking::expr_type::ABS, e->get_range(), true }); - } - else - { - assert(false); - continue; - } - } - else // there is an address D(B) - { - auto& a = std::get(e_or_a); - checking::data_def_address ch_adr; - - ch_adr.base = set_data_def_field(a.base.get(), info); - ch_adr.displacement = set_data_def_field(a.displacement.get(), info); - if (!ch_adr.base.present || !ch_adr.displacement.present) - ch_adr.ignored = true; // ignore values with dependencies - values.push_back(ch_adr); - } + // TO DO value of the relocatable expression + // maybe push back data_def_addr? + values.push_back(checking::data_def_expr { + 0, + ev.get_reloc().is_complex() ? checking::expr_type::COMPLEX : checking::expr_type::RELOC, + e->get_range(), + ignored, + }); + } + else if (kind == context::symbol_value_kind::UNDEF) + { + values.push_back(checking::data_def_expr { 0, checking::expr_type::ABS, e->get_range(), true }); + } + else + { + assert(false); + continue; } - nom.value = std::move(values); } - else - assert(false); + else // there is an address D(B) + { + const auto& a = std::get(e_or_a); + checking::data_def_address ch_adr; + + ch_adr.base = set_data_def_field(a.base.get(), info); + ch_adr.displacement = set_data_def_field(a.displacement.get(), info); + ch_adr.ignored = !ch_adr.base.present || !ch_adr.displacement.present; // ignore value with dependencies + values.push_back(ch_adr); + } + } + return values; +} + +checking::nominal_value_t data_definition::evaluate_nominal_value(context::dependency_solver& info) const +{ + if (!nominal_value) + return {}; + + checking::nominal_value_t nom; + nom.present = true; + if (nominal_value->access_string()) + { + nom.value = nominal_value->access_string()->value; + nom.rng = nominal_value->access_string()->value_range; + } + else if (nominal_value->access_exprs()) + { + nom.value = extract_nominal_value_expressions(nominal_value->access_exprs()->exprs, info); } else - nom.present = false; + assert(false); + return nom; } +void data_definition::apply(mach_expr_visitor& visitor) const +{ + if (dupl_factor) + dupl_factor->apply(visitor); + if (program_type) + program_type->apply(visitor); + if (length) + length->apply(visitor); + if (scale) + scale->apply(visitor); + if (exponent) + exponent->apply(visitor); + + if (nominal_value && nominal_value->access_exprs()) + { + for (const auto& val : nominal_value->access_exprs()->exprs) + { + if (std::holds_alternative(val)) + std::get(val)->apply(visitor); + else + { + const auto& addr = std::get(val); + if (addr.base) + addr.base->apply(visitor); + if (addr.displacement) + addr.displacement->apply(visitor); + } + } + } +} + +size_t hlasm_plugin::parser_library::expressions::data_definition::hash() const +{ + auto ret = (size_t)0x65b40f329f97f6c9; + ret = hash_combine(ret, type); + ret = hash_combine(ret, extension); + if (length) + ret = hash_combine(ret, length->hash()); + + ret = hash_combine(ret, (size_t)length_type); + if (dupl_factor) + ret = hash_combine(ret, dupl_factor->hash()); + if (program_type) + ret = hash_combine(ret, program_type->hash()); + if (scale) + ret = hash_combine(ret, scale->hash()); + if (exponent) + ret = hash_combine(ret, exponent->hash()); + if (nominal_value) + ret = hash_combine(ret, nominal_value->hash()); + + return ret; +} + data_definition::parser::parser( semantics::collector& coll, std::string format, mach_expr_list exprs, nominal_value_ptr nominal, position begin) : collector_(coll) @@ -455,30 +521,23 @@ void data_definition::parser::update_position_by_one() { ++pos_.column; } void data_definition::parser::parse_duplication_factor() { - if (isdigit(format_[0]) || format_[0] == '-') // duplication factor is present + if (isdigit(static_cast(format_[0])) || format_[0] == '-') // duplication factor is present { position old_pos = pos_; auto dupl_factor_num = parse_number(); if (dupl_factor_num) result_.dupl_factor = std::make_unique(*dupl_factor_num, range(old_pos, pos_)); - else - result_.dupl_factor = std::make_unique(1, range(old_pos, pos_)); } else if (format_[0] == *data_definition::expr_placeholder) { // duplication factor as expression result_.dupl_factor = move_next_expression(); } - else - { - result_.dupl_factor = std::make_unique(1, range(pos_, pos_)); - } } -bool is_type_extension(char ch) +bool is_type_extension(char type, char ch) { - static std::set type_extensions({ 'A', 'E', 'U', 'H', 'B', 'D', 'Q', 'Y' }); - return type_extensions.find(ch) != type_extensions.end(); + return checking::data_def_type::types_and_extensions.count(std::make_pair(type, ch)) > 0; } bool is_modifier_or_prog(char ch) { return ch == 'P' || ch == 'L' || ch == 'S' || ch == 'E'; } @@ -601,6 +660,21 @@ void data_definition::parser::parse_modifier() assign_expr_to_modifier(modifier, std::move(expr)); } +namespace { +struct loctr_reference_visitor final : public mach_expr_visitor +{ + bool found_loctr_reference = false; + + void visit(const mach_expr_constant&) override {} + void visit(const mach_expr_data_attr&) override {} + void visit(const mach_expr_symbol&) override {} + void visit(const mach_expr_location_counter&) override { found_loctr_reference = true; } + void visit(const mach_expr_self_def&) override {} + void visit(const mach_expr_default&) override {} + void visit(const mach_expr_literal& expr) override { expr.get_data_definition().apply(*this); } +}; +} // namespace + data_definition data_definition::parser::parse() { parse_duplication_factor(); @@ -614,7 +688,7 @@ data_definition data_definition::parser::parse() if (p_ >= format_.size()) return std::move(result_); - if (is_type_extension(format_[p_])) + if (is_type_extension(result_.type, format_[p_])) { result_.extension = format_[p_]; result_.extension_range = { pos_, { pos_.line, pos_.column + 1 } }; @@ -651,5 +725,24 @@ data_definition data_definition::parser::parse() } } + loctr_reference_visitor v; + result_.apply(v); + result_.references_loctr = v.found_loctr_reference; + return std::move(result_); } + +bool hlasm_plugin::parser_library::expressions::is_similar(const data_definition& l, const data_definition& r) noexcept +{ + return hlasm_plugin::utils::is_similar(l, + r, + &data_definition::type, + &data_definition::extension, + &data_definition::length, + &data_definition::length_type, + &data_definition::dupl_factor, + &data_definition::program_type, + &data_definition::scale, + &data_definition::exponent, + &data_definition::nominal_value); +} diff --git a/parser_library/src/expressions/data_definition.h b/parser_library/src/expressions/data_definition.h index d3bcec385..79127ea53 100644 --- a/parser_library/src/expressions/data_definition.h +++ b/parser_library/src/expressions/data_definition.h @@ -33,12 +33,13 @@ class collector; namespace hlasm_plugin::parser_library::expressions { +class mach_expr_visitor; // Represents data definition operand as it was written into source code. // Uses machine expressions to represent all modifiers and nominal value. struct data_definition final : public diagnosable_op_impl, public context::dependable { - enum class length_type + enum class length_type : unsigned char { BYTE, BIT @@ -57,6 +58,7 @@ struct data_definition final : public diagnosable_op_impl, public context::depen nominal_value_ptr nominal_value = nullptr; length_type length_type = length_type::BYTE; + bool references_loctr = false; inline static const char* expr_placeholder = "&"; inline static const char* nominal_placeholder = " "; @@ -82,9 +84,9 @@ struct data_definition final : public diagnosable_op_impl, public context::depen char get_type_attribute() const; // Expects, that scale does not have unresolved dependencies - int32_t get_scale_attribute(expressions::mach_evaluate_info info) const; - uint32_t get_length_attribute(expressions::mach_evaluate_info info) const; - int32_t get_integer_attribute(expressions::mach_evaluate_info info) const; + int32_t get_scale_attribute(context::dependency_solver& info) const; + uint32_t get_length_attribute(context::dependency_solver& info) const; + int32_t get_integer_attribute(context::dependency_solver& info) const; // Returns true, if this data definition has one of the types, that take expressions consisting of only one symbol // (like V or R) @@ -95,21 +97,24 @@ struct data_definition final : public diagnosable_op_impl, public context::depen // Expects that check_single_symbol_ok returned true. std::vector get_single_symbol_names() const; - // Assigns location counter to all expressions used to represent this data_definition. - void assign_location_counter(context::address loctr_value); - void collect_diags() const override; // When any of the evaluated expressions have dependencies, resulting modifier will have data_def_field::present set // to false - checking::dupl_factor_modifier_t evaluate_dupl_factor(expressions::mach_evaluate_info info) const; - checking::data_def_length_t evaluate_length(expressions::mach_evaluate_info info) const; - checking::scale_modifier_t evaluate_scale(expressions::mach_evaluate_info info) const; - checking::exponent_modifier_t evaluate_exponent(expressions::mach_evaluate_info info) const; + checking::dupl_factor_modifier_t evaluate_dupl_factor(context::dependency_solver& info) const; + checking::data_def_length_t evaluate_length(context::dependency_solver& info) const; + checking::scale_modifier_t evaluate_scale(context::dependency_solver& info) const; + checking::exponent_modifier_t evaluate_exponent(context::dependency_solver& info) const; // When any of the evaluated expressions have dependencies, resulting modifier will have // data_def_expr::ignored or data_def_address::ignored set to false - checking::nominal_value_t evaluate_nominal_value(expressions::mach_evaluate_info info) const; + checking::nominal_value_t evaluate_nominal_value(context::dependency_solver& info) const; + + void apply(mach_expr_visitor& visitor) const; + + friend bool is_similar(const data_definition& l, const data_definition& r) noexcept; + + size_t hash() const; private: class parser; diff --git a/parser_library/src/expressions/mach_expr_term.cpp b/parser_library/src/expressions/mach_expr_term.cpp index 1a07d2a36..ef3f054c9 100644 --- a/parser_library/src/expressions/mach_expr_term.cpp +++ b/parser_library/src/expressions/mach_expr_term.cpp @@ -18,11 +18,24 @@ #include "checking/checker_helper.h" #include "conditional_assembly/terms/ca_constant.h" +#include "ebcdic_encoding.h" #include "mach_expr_visitor.h" +#include "utils/similar.h" namespace hlasm_plugin::parser_library::expressions { - //*********** mach_expr_constant ************ + +bool mach_expr_constant::do_is_similar(const mach_expression& expr) const +{ + const auto& e = static_cast(expr); + if (value_.value_kind() != e.value_.value_kind()) + return false; + if (value_.value_kind() == context::symbol_value_kind::ABS) + return value_.get_abs() == e.value_.get_abs(); + + return true; +} + mach_expr_constant::mach_expr_constant(std::string value_text, range rng) : mach_expression(rng) { @@ -45,15 +58,19 @@ context::dependency_collector mach_expr_constant::get_dependencies(context::depe return context::dependency_collector(); } -mach_expr_constant::value_t mach_expr_constant::evaluate(mach_evaluate_info) const { return value_; } - -void mach_expr_constant::fill_location_counter(context::address) {} +mach_expr_constant::value_t mach_expr_constant::evaluate(context::dependency_solver&) const { return value_; } const mach_expression* mach_expr_constant::leftmost_term() const { return this; } void mach_expr_constant::apply(mach_expr_visitor& visitor) const { visitor.visit(*this); } - +size_t mach_expr_constant::hash() const +{ + auto result = (size_t)0x38402610af574281; + if (value_.value_kind() == context::symbol_value_kind::ABS) + result = hash_combine(result, value_.get_abs()); + return result; +} //*********** mach_expr_symbol ************ mach_expr_symbol::mach_expr_symbol(context::id_index value, range rng) @@ -74,7 +91,7 @@ context::dependency_collector mach_expr_symbol::get_dependencies(context::depend return context::dependency_collector(); } -mach_expr_constant::value_t mach_expr_symbol::evaluate(mach_evaluate_info info) const +mach_expr_constant::value_t mach_expr_symbol::evaluate(context::dependency_solver& info) const { auto symbol = info.get_symbol(value); @@ -83,10 +100,29 @@ mach_expr_constant::value_t mach_expr_symbol::evaluate(mach_evaluate_info info) return symbol->value(); } -void mach_expr_symbol::fill_location_counter(context::address) {} + const mach_expression* mach_expr_symbol::leftmost_term() const { return this; } void mach_expr_symbol::apply(mach_expr_visitor& visitor) const { visitor.visit(*this); } +size_t mach_expr_symbol::hash() const +{ + auto result = (size_t)0xdf510e8c145dd28d; + + if (value) + result = hash_combine(result, (uintptr_t)value); + return result; +} +bool mach_expr_symbol::do_is_similar(const mach_expression& expr) const +{ + const auto& e = static_cast(expr); + return value == e.value; +} //*********** mach_expr_self_def ************ +bool mach_expr_self_def::do_is_similar(const mach_expression& expr) const +{ + const auto& e = static_cast(expr); + return value_.get_abs() == e.value_.get_abs(); +} + mach_expr_self_def::mach_expr_self_def(std::string option, std::string value, range rng) : mach_expression(rng) { @@ -99,40 +135,46 @@ context::dependency_collector mach_expr_self_def::get_dependencies(context::depe return context::dependency_collector(); } -mach_expr_self_def::value_t mach_expr_self_def::evaluate(mach_evaluate_info) const { return value_; } - -void mach_expr_self_def::fill_location_counter(context::address) {} +mach_expr_self_def::value_t mach_expr_self_def::evaluate(context::dependency_solver&) const { return value_; } const mach_expression* mach_expr_self_def::leftmost_term() const { return this; } void mach_expr_self_def::apply(mach_expr_visitor& visitor) const { visitor.visit(*this); } +size_t mach_expr_self_def::hash() const { return hash_combine((size_t)0x038d7ea26932b75b, value_.get_abs()); } + +bool mach_expr_location_counter::do_is_similar(const mach_expression&) const { return true; } + mach_expr_location_counter::mach_expr_location_counter(range rng) : mach_expression(rng) {} -context::dependency_collector mach_expr_location_counter::get_dependencies(context::dependency_solver&) const +context::dependency_collector mach_expr_location_counter::get_dependencies(context::dependency_solver& mi) const { + auto location_counter = mi.get_loctr(); if (!location_counter.has_value()) return context::dependency_collector(true); else return context::dependency_collector(*location_counter); } -mach_expression::value_t mach_expr_location_counter::evaluate(mach_evaluate_info) const +mach_expression::value_t mach_expr_location_counter::evaluate(context::dependency_solver& mi) const { + auto location_counter = mi.get_loctr(); if (!location_counter.has_value()) return context::address({ nullptr }, 0, {}); else return *location_counter; } -void mach_expr_location_counter::fill_location_counter(context::address addr) { location_counter = std::move(addr); } - const mach_expression* mach_expr_location_counter::leftmost_term() const { return this; } void mach_expr_location_counter::apply(mach_expr_visitor& visitor) const { visitor.visit(*this); } +size_t mach_expr_location_counter::hash() const { return (size_t)0x0009459ca772d69b; } + +bool mach_expr_default::do_is_similar(const mach_expression&) const { return true; } + mach_expr_default::mach_expr_default(range rng) : mach_expression(rng) {} @@ -142,9 +184,7 @@ context::dependency_collector mach_expr_default::get_dependencies(context::depen return context::dependency_collector(); } -mach_expression::value_t mach_expr_default::evaluate(mach_evaluate_info) const { return value_t(); } - -void mach_expr_default::fill_location_counter(context::address) {} +mach_expression::value_t mach_expr_default::evaluate(context::dependency_solver&) const { return value_t(); } const mach_expression* mach_expr_default::leftmost_term() const { return this; } @@ -152,6 +192,14 @@ void mach_expr_default::apply(mach_expr_visitor& visitor) const { visitor.visit( void mach_expr_default::collect_diags() const {} +size_t mach_expr_default::hash() const { return (size_t)0xd11a22d1aa4016e0; } + +bool mach_expr_data_attr::do_is_similar(const mach_expression& expr) const +{ + const auto& e = static_cast(expr); + return value == e.value && attribute == e.attribute && utils::is_similar(lit, e.lit); +} + mach_expr_data_attr::mach_expr_data_attr( context::id_index value, context::data_attr_kind attribute, range rng, range symbol_rng) : mach_expression(rng) @@ -160,44 +208,158 @@ mach_expr_data_attr::mach_expr_data_attr( , symbol_range(symbol_rng) {} +mach_expr_data_attr::mach_expr_data_attr( + std::unique_ptr value, context::data_attr_kind attribute, range whole_rng, range symbol_rng) + : mach_expression(whole_rng) + , value(nullptr) + , attribute(attribute) + , symbol_range(symbol_rng) + , lit(std::move(value)) +{} + context::dependency_collector mach_expr_data_attr::get_dependencies(context::dependency_solver& solver) const { - auto symbol = solver.get_symbol(value); + if (value) + { + auto symbol = solver.get_symbol(value); - if (symbol == nullptr || !symbol->attributes().is_defined(attribute)) + if (symbol == nullptr || !symbol->attributes().is_defined(attribute)) + return context::dependency_collector({ attribute, value }); + else + return context::dependency_collector(); + } + else if (lit) { - return context::dependency_collector({ attribute, value }); + return lit->get_data_definition().get_dependencies(solver); } - else - return context::dependency_collector(); + + return context::dependency_collector(true); } -mach_expression::value_t mach_expr_data_attr::evaluate(mach_evaluate_info info) const +mach_expression::value_t mach_expr_data_attr::evaluate(context::dependency_solver& solver) const { - auto symbol = info.get_symbol(value); - - if (symbol == nullptr) + if (value) { - return context::symbol_attributes::default_value(attribute); + auto symbol = solver.get_symbol(value); + + if (symbol == nullptr) + { + return context::symbol_attributes::default_value(attribute); + } + else if ((attribute == context::data_attr_kind::S || attribute == context::data_attr_kind::I) + && !symbol->attributes().can_have_SI_attr()) + { + add_diagnostic(diagnostic_op::warning_W011(get_range())); + return 0; + } + else if (symbol->attributes().is_defined(attribute)) + { + return symbol->attributes().get_attribute_value(attribute); + } + else + return context::symbol_attributes::default_value(attribute); } - else if ((attribute == context::data_attr_kind::S || attribute == context::data_attr_kind::I) - && !symbol->attributes().can_have_SI_attr()) + else if (lit) { - add_diagnostic(diagnostic_op::warning_W011(get_range())); - return 0; + (void)lit->evaluate(solver); + + auto& dd = lit->get_data_definition(); + context::symbol_attributes attrs(context::symbol_origin::DAT, + ebcdic_encoding::a2e[(unsigned char)dd.get_type_attribute()], + dd.get_length_attribute(solver), + dd.get_scale_attribute(solver), + dd.get_integer_attribute(solver)); + if ((attribute == context::data_attr_kind::S || attribute == context::data_attr_kind::I) + && !attrs.can_have_SI_attr()) + { + add_diagnostic(diagnostic_op::warning_W011(get_range())); + return 0; + } + return attrs.get_attribute_value(attribute); } - else if (symbol->attributes().is_defined(attribute)) + return context::symbol_attributes::default_value(attribute); +} + +const mach_expression* mach_expr_data_attr::leftmost_term() const { return this; } + +void mach_expr_data_attr::apply(mach_expr_visitor& visitor) const { visitor.visit(*this); } + +void mach_expr_data_attr::collect_diags() const +{ + if (lit) + collect_diags_from_child(*lit); +} + +size_t mach_expr_data_attr::hash() const +{ + auto result = (size_t)0xa2957a462d908bd2; + if (value) + result = hash_combine(result, (uintptr_t)value); + result = hash_combine(result, (size_t)attribute); + if (lit) + result = hash_combine(result, lit->hash()); + + return result; +} + +bool mach_expr_literal::do_is_similar(const mach_expression& expr) const +{ + const auto& e = static_cast(expr); + return utils::is_similar(m_literal_data->dd, e.m_literal_data->dd); +} + +mach_expr_literal::mach_expr_literal(range rng, data_definition dd, std::string dd_text) + : mach_expression(rng) + , m_literal_data(std::make_shared(std::move(dd))) + , m_dd_text(std::move(dd_text)) +{} + +context::dependency_collector mach_expr_literal::get_dependencies(context::dependency_solver& solver) const +{ + auto length_deps = m_literal_data->dd.get_length_dependencies(solver); + // literal size has to be evaluable at the definition point (ASMA151E) + if (length_deps.has_error || length_deps.contains_dependencies()) + return context::dependency_collector(true); + else { - return symbol->attributes().get_attribute_value(attribute); + auto symbol_id = get_literal_id(solver); + auto symbol = solver.get_symbol(symbol_id); + + if (symbol == nullptr || symbol->kind() == context::symbol_value_kind::UNDEF) + return symbol_id; + else if (symbol->kind() == context::symbol_value_kind::RELOC) + return symbol->value().get_reloc(); + else + return context::dependency_collector(); } - else - return context::symbol_attributes::default_value(attribute); } -void mach_expr_data_attr::fill_location_counter(context::address) {} +mach_expression::value_t mach_expr_literal::evaluate(context::dependency_solver& solver) const +{ + auto symbol = solver.get_symbol(get_literal_id(solver)); -const mach_expression* mach_expr_data_attr::leftmost_term() const { return this; } + if (symbol == nullptr || symbol->kind() == context::symbol_value_kind::UNDEF) + return context::symbol_value(); -void mach_expr_data_attr::apply(mach_expr_visitor& visitor) const { visitor.visit(*this); } + return symbol->value(); +} + +const mach_expression* mach_expr_literal::leftmost_term() const { return this; } + +void mach_expr_literal::apply(mach_expr_visitor& visitor) const { visitor.visit(*this); } + +void mach_expr_literal::collect_diags() const { collect_diags_from_child(m_literal_data->dd); } + +size_t mach_expr_literal::hash() const { return m_literal_data->dd.hash(); } + +const data_definition& mach_expr_literal::get_data_definition() const { return m_literal_data->dd; } + +context::id_index mach_expr_literal::get_literal_id(context::dependency_solver& solver) const +{ + return solver.get_literal_id(m_dd_text, + std::shared_ptr(m_literal_data, &m_literal_data->dd), + get_range(), + m_literal_data->referenced_by_reladdr); +} } // namespace hlasm_plugin::parser_library::expressions diff --git a/parser_library/src/expressions/mach_expr_term.h b/parser_library/src/expressions/mach_expr_term.h index 056238755..9e23ceb5d 100644 --- a/parser_library/src/expressions/mach_expr_term.h +++ b/parser_library/src/expressions/mach_expr_term.h @@ -16,58 +16,110 @@ #define HLASMPLUGIN_PARSERLIBRARY_EXPRESSIONS_MACH_EXPR_TERM_H #include "context/id_storage.h" +#include "expressions/data_definition.h" #include "mach_expression.h" namespace hlasm_plugin::parser_library::expressions { // Represents a number written in a machine expression. -class mach_expr_constant : public mach_expression +class mach_expr_constant final : public mach_expression { value_t value_; + bool do_is_similar(const mach_expression& expr) const override; + public: mach_expr_constant(std::string value_text, range rng); mach_expr_constant(int value, range rng); context::dependency_collector get_dependencies(context::dependency_solver& solver) const override; - value_t evaluate(mach_evaluate_info info) const override; - - void fill_location_counter(context::address addr) override; + value_t evaluate(context::dependency_solver& info) const override; const mach_expression* leftmost_term() const override; void apply(mach_expr_visitor& visitor) const override; void collect_diags() const override {} + + size_t hash() const override; +}; + +// Represents a literal expression (e.g. =C'text') +class mach_expr_literal final : public mach_expression +{ + bool do_is_similar(const mach_expression& expr) const override; + + struct literal_data + { + const data_definition dd; + bool referenced_by_reladdr = false; + + explicit literal_data(data_definition dd) + : dd(std::move(dd)) + {} + }; + + std::shared_ptr m_literal_data; + std::string m_dd_text; + +public: + mach_expr_literal(range rng, data_definition dd, std::string text); + + context::dependency_collector get_dependencies(context::dependency_solver& solver) const override; + + value_t evaluate(context::dependency_solver& info) const override; + + const mach_expression* leftmost_term() const override; + + void apply(mach_expr_visitor& visitor) const override; + + void collect_diags() const override; + + size_t hash() const override; + + const data_definition& get_data_definition() const; + + const std::string& get_data_definition_text() const { return m_dd_text; } + + context::id_index get_literal_id(context::dependency_solver& solver) const; + + void referenced_by_reladdr() const { m_literal_data->referenced_by_reladdr = true; } }; // Represents an attribute of a symbol written in machine expressions (e.g. L'SYMBOL) -class mach_expr_data_attr : public mach_expression +class mach_expr_data_attr final : public mach_expression { + bool do_is_similar(const mach_expression& expr) const override; + public: mach_expr_data_attr(context::id_index value, context::data_attr_kind attribute, range whole_rng, range symbol_rng); + mach_expr_data_attr( + std::unique_ptr value, context::data_attr_kind attribute, range whole_rng, range symbol_rng); context::id_index value; context::data_attr_kind attribute; range symbol_range; + std::unique_ptr lit; context::dependency_collector get_dependencies(context::dependency_solver& solver) const override; - value_t evaluate(mach_evaluate_info info) const override; - - void fill_location_counter(context::address addr) override; + value_t evaluate(context::dependency_solver& info) const override; const mach_expression* leftmost_term() const override; void apply(mach_expr_visitor& visitor) const override; - void collect_diags() const override {} + void collect_diags() const override; + + size_t hash() const override; }; // Represents an ordinary symbol in machine expressions. -class mach_expr_symbol : public mach_expression +class mach_expr_symbol final : public mach_expression { + bool do_is_similar(const mach_expression& expr) const override; + public: mach_expr_symbol(context::id_index value, range rng); @@ -76,41 +128,43 @@ class mach_expr_symbol : public mach_expression context::dependency_collector get_dependencies(context::dependency_solver& solver) const override; - value_t evaluate(mach_evaluate_info info) const override; - - void fill_location_counter(context::address addr) override; + value_t evaluate(context::dependency_solver& info) const override; const mach_expression* leftmost_term() const override; void apply(mach_expr_visitor& visitor) const override; void collect_diags() const override {} + + size_t hash() const override; }; // Represents a location counter written in a machine expression (the character *) -class mach_expr_location_counter : public mach_expression +class mach_expr_location_counter final : public mach_expression { -public: - std::optional location_counter; + bool do_is_similar(const mach_expression& expr) const override; +public: mach_expr_location_counter(range rng); context::dependency_collector get_dependencies(context::dependency_solver& solver) const override; - value_t evaluate(mach_evaluate_info info) const override; - - void fill_location_counter(context::address addr) override; + value_t evaluate(context::dependency_solver& info) const override; const mach_expression* leftmost_term() const override; void apply(mach_expr_visitor& visitor) const override; void collect_diags() const override {} + + size_t hash() const override; }; // Represents a self defining term (e.g. X'4A') -class mach_expr_self_def : public mach_expression +class mach_expr_self_def final : public mach_expression { + bool do_is_similar(const mach_expression& expr) const override; + value_t value_; public: @@ -118,35 +172,37 @@ class mach_expr_self_def : public mach_expression context::dependency_collector get_dependencies(context::dependency_solver& solver) const override; - value_t evaluate(mach_evaluate_info info) const override; - - void fill_location_counter(context::address addr) override; + value_t evaluate(context::dependency_solver& info) const override; const mach_expression* leftmost_term() const override; void apply(mach_expr_visitor& visitor) const override; void collect_diags() const override {} + + size_t hash() const override; }; // Represents an "empty" term that is used when parsing of a machine expression fails //(the user writes invalid expression) -class mach_expr_default : public mach_expression +class mach_expr_default final : public mach_expression { + bool do_is_similar(const mach_expression& expr) const override; + public: mach_expr_default(range rng); context::dependency_collector get_dependencies(context::dependency_solver& solver) const override; - value_t evaluate(mach_evaluate_info info) const override; - - void fill_location_counter(context::address addr) override; + value_t evaluate(context::dependency_solver& info) const override; const mach_expression* leftmost_term() const override; void apply(mach_expr_visitor& visitor) const override; void collect_diags() const override; + + size_t hash() const override; }; } // namespace hlasm_plugin::parser_library::expressions diff --git a/parser_library/src/expressions/mach_expr_visitor.h b/parser_library/src/expressions/mach_expr_visitor.h index f5f3e82b4..6ad41f419 100644 --- a/parser_library/src/expressions/mach_expr_visitor.h +++ b/parser_library/src/expressions/mach_expr_visitor.h @@ -30,6 +30,7 @@ class mach_expr_visitor virtual void visit(const mach_expr_location_counter& expr) = 0; virtual void visit(const mach_expr_self_def& expr) = 0; virtual void visit(const mach_expr_default& expr) = 0; + virtual void visit(const mach_expr_literal& expr) = 0; protected: ~mach_expr_visitor() = default; diff --git a/parser_library/src/expressions/mach_expression.cpp b/parser_library/src/expressions/mach_expression.cpp index 7184f2901..f28d73ca1 100644 --- a/parser_library/src/expressions/mach_expression.cpp +++ b/parser_library/src/expressions/mach_expression.cpp @@ -14,6 +14,8 @@ #include "mach_expression.h" +#include + #include "mach_expr_term.h" using namespace hlasm_plugin::parser_library; @@ -29,6 +31,11 @@ mach_expr_ptr hlasm_plugin::parser_library::expressions::mach_expression::assign return expr ? std::move(expr) : std::make_unique(expr_range); } +bool mach_expression::is_similar(const mach_expression& expr) const +{ + return typeid(*this) == typeid(expr) && do_is_similar(expr); +} + range mach_expression::get_range() const { return expr_range_; } context::symbol_value hlasm_plugin::parser_library::expressions::mach_expression::resolve( diff --git a/parser_library/src/expressions/mach_expression.h b/parser_library/src/expressions/mach_expression.h index 47099504d..1ac08b5f3 100644 --- a/parser_library/src/expressions/mach_expression.h +++ b/parser_library/src/expressions/mach_expression.h @@ -24,8 +24,6 @@ namespace hlasm_plugin::parser_library::expressions { -using mach_evaluate_info = context::dependency_solver&; - class mach_expr_visitor; class mach_expression; using mach_expr_ptr = std::unique_ptr; @@ -35,29 +33,32 @@ using mach_expr_list = std::vector; // This interface represents one node (operator or term) in // a machine expression, the root operator represents the // whole machine expression. -// It can be evaluated using mach_evaluate_info that provides +// It can be evaluated using context::dependency_solver& that provides // information about values of ordinary symbols. class mach_expression : public diagnosable_op_impl, public context::resolvable { + virtual bool do_is_similar(const mach_expression& expr) const = 0; + public: using value_t = context::symbol_value; context::symbol_value resolve(context::dependency_solver& solver) const override; - virtual value_t evaluate(mach_evaluate_info info) const = 0; - - // Sets location counter in the whole machine expression to specified address. - virtual void fill_location_counter(context::address addr) = 0; + virtual value_t evaluate(context::dependency_solver& info) const = 0; virtual const mach_expression* leftmost_term() const = 0; virtual void apply(mach_expr_visitor& visitor) const = 0; + virtual size_t hash() const = 0; + range get_range() const; virtual ~mach_expression() {} static mach_expr_ptr assign_expr(mach_expr_ptr expr, range expr_range); + bool is_similar(const mach_expression& expr) const; + protected: mach_expression(range rng); @@ -65,7 +66,10 @@ class mach_expression : public diagnosable_op_impl, public context::resolvable range expr_range_; }; - +inline size_t hash_combine(std::size_t old, std::size_t next) +{ + return old ^ (next + 0x9e3779b9 + (old << 6) + (old >> 2)); +} } // namespace hlasm_plugin::parser_library::expressions diff --git a/parser_library/src/expressions/mach_operator.cpp b/parser_library/src/expressions/mach_operator.cpp new file mode 100644 index 000000000..25b7189b6 --- /dev/null +++ b/parser_library/src/expressions/mach_operator.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2021 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ + +#include "mach_operator.h" + +#include "utils/similar.h" + +namespace hlasm_plugin::parser_library::expressions { + +template +bool mach_expr_binary::do_is_similar(const mach_expression& expr) const +{ + return utils::is_similar(*this, + static_cast&>(expr), + &mach_expr_binary::left_, + &mach_expr_binary::right_); +} + +template bool mach_expr_binary::do_is_similar(const mach_expression& expr) const; +template bool mach_expr_binary::do_is_similar(const mach_expression& expr) const; +template bool mach_expr_binary::do_is_similar(const mach_expression& expr) const; +template bool mach_expr_binary::do_is_similar(const mach_expression& expr) const; +template bool mach_expr_binary
::do_is_similar(const mach_expression& expr) const; + +template<> +size_t mach_expr_binary::hash() const +{ + return hash_combine((size_t)0xb97f4e373e923282, hash_combine(left_->hash(), right_->hash())); +} +template<> +size_t mach_expr_binary::hash() const +{ + return hash_combine((size_t)0x41e9ae4811f88d69, hash_combine(left_->hash(), right_->hash())); +} +template<> +size_t mach_expr_binary::hash() const +{ + return hash_combine((size_t)0xa5aac0163f6f9304, hash_combine(left_->hash(), right_->hash())); +} +template<> +size_t mach_expr_binary::hash() const +{ + return hash_combine((size_t)0xc1cffe0cc1aa0820, hash_combine(left_->hash(), right_->hash())); +} +template<> +size_t mach_expr_binary
::hash() const +{ + return hash_combine((size_t)0xdc34b8e67fb7ed92, hash_combine(left_->hash(), right_->hash())); +} + +template +bool mach_expr_unary::do_is_similar(const mach_expression& expr) const +{ + return utils::is_similar(child_, static_cast&>(expr).child_); +} + +template bool mach_expr_unary::do_is_similar(const mach_expression& expr) const; +template bool mach_expr_unary::do_is_similar(const mach_expression& expr) const; +template bool mach_expr_unary::do_is_similar(const mach_expression& expr) const; + +template<> +size_t mach_expr_unary::hash() const +{ + return hash_combine((size_t)0xf65c5e195b070c15, child_->hash()); +} +template<> +size_t mach_expr_unary::hash() const +{ + return hash_combine((size_t)0x837fe8200ff456f6, child_->hash()); +} +template<> +size_t mach_expr_unary::hash() const +{ + return hash_combine((size_t)0xe45af0e42cda6037, child_->hash()); +} + +} // namespace hlasm_plugin::parser_library::expressions diff --git a/parser_library/src/expressions/mach_operator.h b/parser_library/src/expressions/mach_operator.h index ed0edadec..865de43ff 100644 --- a/parser_library/src/expressions/mach_operator.h +++ b/parser_library/src/expressions/mach_operator.h @@ -28,6 +28,8 @@ namespace hlasm_plugin::parser_library::expressions { template class mach_expr_binary final : public mach_expression { + bool do_is_similar(const mach_expression& expr) const override; + mach_expr_ptr left_; mach_expr_ptr right_; @@ -40,15 +42,9 @@ class mach_expr_binary final : public mach_expression // text = left_->move_text() + T::sign_char() + right_->move_text(); } - context::dependency_collector get_dependencies(mach_evaluate_info info) const override; - - value_t evaluate(mach_evaluate_info info) const override; + context::dependency_collector get_dependencies(context::dependency_solver& info) const override; - void fill_location_counter(context::address addr) override - { - left_->fill_location_counter(addr); - right_->fill_location_counter(std::move(addr)); - } + value_t evaluate(context::dependency_solver& info) const override; void apply(mach_expr_visitor& visitor) const override { @@ -63,6 +59,8 @@ class mach_expr_binary final : public mach_expression collect_diags_from_child(*left_); collect_diags_from_child(*right_); } + + size_t hash() const override; }; // Represents a unart operator in machine expression. Holds its @@ -71,6 +69,8 @@ class mach_expr_binary final : public mach_expression template class mach_expr_unary final : public mach_expression { + bool do_is_similar(const mach_expression& expr) const override; + mach_expr_ptr child_; public: @@ -81,17 +81,17 @@ class mach_expr_unary final : public mach_expression // text = T::sign_char_begin() + child_->move_text() + T::sign_char_end(); } - context::dependency_collector get_dependencies(mach_evaluate_info info) const override; + context::dependency_collector get_dependencies(context::dependency_solver& info) const override; - value_t evaluate(mach_evaluate_info info) const override; - - void fill_location_counter(context::address addr) override { child_->fill_location_counter(std::move(addr)); } + value_t evaluate(context::dependency_solver& info) const override; void apply(mach_expr_visitor& visitor) const override { child_->apply(visitor); } const mach_expression* leftmost_term() const override { return child_->leftmost_term(); } void collect_diags() const override { collect_diags_from_child(*child_); } + + size_t hash() const override; }; struct add @@ -134,19 +134,19 @@ struct par template<> -inline mach_expression::value_t mach_expr_binary::evaluate(mach_evaluate_info info) const +inline mach_expression::value_t mach_expr_binary::evaluate(context::dependency_solver& info) const { return left_->evaluate(info) + right_->evaluate(info); } template<> -inline mach_expression::value_t mach_expr_binary::evaluate(mach_evaluate_info info) const +inline mach_expression::value_t mach_expr_binary::evaluate(context::dependency_solver& info) const { return left_->evaluate(info) - right_->evaluate(info); } template<> -inline mach_expression::value_t mach_expr_binary::evaluate(mach_evaluate_info info) const +inline mach_expression::value_t mach_expr_binary::evaluate(context::dependency_solver& info) const { auto location = left_->evaluate(info); auto target = right_->evaluate(info); @@ -167,7 +167,7 @@ inline mach_expression::value_t mach_expr_binary::evaluate(mach_evalua } template<> -inline mach_expression::value_t mach_expr_binary::evaluate(mach_evaluate_info info) const +inline mach_expression::value_t mach_expr_binary::evaluate(context::dependency_solver& info) const { auto left_res = left_->evaluate(info); auto right_res = right_->evaluate(info); @@ -183,7 +183,7 @@ inline mach_expression::value_t mach_expr_binary::evaluate(mach_evaluate_in } template<> -inline mach_expression::value_t mach_expr_binary
::evaluate(mach_evaluate_info info) const +inline mach_expression::value_t mach_expr_binary
::evaluate(context::dependency_solver& info) const { auto left_res = left_->evaluate(info); auto right_res = right_->evaluate(info); @@ -198,67 +198,68 @@ inline mach_expression::value_t mach_expr_binary
::evaluate(mach_evaluate_in } template<> -inline mach_expression::value_t mach_expr_unary::evaluate(mach_evaluate_info info) const +inline mach_expression::value_t mach_expr_unary::evaluate(context::dependency_solver& info) const { return child_->evaluate(info); } template<> -inline mach_expression::value_t mach_expr_unary::evaluate(mach_evaluate_info info) const +inline mach_expression::value_t mach_expr_unary::evaluate(context::dependency_solver& info) const { return -child_->evaluate(info); } template<> -inline mach_expression::value_t mach_expr_unary::evaluate(mach_evaluate_info info) const +inline mach_expression::value_t mach_expr_unary::evaluate(context::dependency_solver& info) const { return child_->evaluate(info); } template<> -inline context::dependency_collector mach_expr_binary::get_dependencies(mach_evaluate_info info) const +inline context::dependency_collector mach_expr_binary::get_dependencies(context::dependency_solver& info) const { return left_->get_dependencies(info) + right_->get_dependencies(info); } template<> -inline context::dependency_collector mach_expr_binary::get_dependencies(mach_evaluate_info info) const +inline context::dependency_collector mach_expr_binary::get_dependencies(context::dependency_solver& info) const { return left_->get_dependencies(info) - right_->get_dependencies(info); } template<> -inline context::dependency_collector mach_expr_binary::get_dependencies(mach_evaluate_info info) const +inline context::dependency_collector mach_expr_binary::get_dependencies( + context::dependency_solver& info) const { return left_->get_dependencies(info) - right_->get_dependencies(info); } template<> -inline context::dependency_collector mach_expr_binary::get_dependencies(mach_evaluate_info info) const +inline context::dependency_collector mach_expr_binary::get_dependencies(context::dependency_solver& info) const { return left_->get_dependencies(info) * right_->get_dependencies(info); } template<> -inline context::dependency_collector mach_expr_binary
::get_dependencies(mach_evaluate_info info) const +inline context::dependency_collector mach_expr_binary
::get_dependencies(context::dependency_solver& info) const { return left_->get_dependencies(info) / right_->get_dependencies(info); } template<> -inline context::dependency_collector mach_expr_unary::get_dependencies(mach_evaluate_info info) const +inline context::dependency_collector mach_expr_unary::get_dependencies(context::dependency_solver& info) const { return child_->get_dependencies(info); } template<> -inline context::dependency_collector mach_expr_unary::get_dependencies(mach_evaluate_info info) const +inline context::dependency_collector mach_expr_unary::get_dependencies(context::dependency_solver& info) const { return context::dependency_collector() - child_->get_dependencies(info); } template<> -inline context::dependency_collector mach_expr_unary::get_dependencies(mach_evaluate_info info) const +inline context::dependency_collector mach_expr_unary::get_dependencies(context::dependency_solver& info) const { return child_->get_dependencies(info); } diff --git a/parser_library/src/expressions/nominal_value.cpp b/parser_library/src/expressions/nominal_value.cpp index ab8cd1322..d025971eb 100644 --- a/parser_library/src/expressions/nominal_value.cpp +++ b/parser_library/src/expressions/nominal_value.cpp @@ -16,6 +16,8 @@ #include +#include "utils/similar.h" + using namespace hlasm_plugin::parser_library::expressions; using namespace hlasm_plugin::parser_library::context; @@ -23,6 +25,16 @@ nominal_value_string* nominal_value_t::access_string() { return dynamic_cast(this); } +const nominal_value_string* nominal_value_t::access_string() const +{ + return dynamic_cast(this); +} + +const nominal_value_exprs* nominal_value_t::access_exprs() const +{ + return dynamic_cast(this); +} + //*********** nominal_value_string *************** dependency_collector nominal_value_string::get_dependencies(dependency_solver&) const { return dependency_collector(); } @@ -31,6 +43,11 @@ nominal_value_string::nominal_value_string(std::string value, hlasm_plugin::pars , value_range(rng) {} +size_t hlasm_plugin::parser_library::expressions::nominal_value_string::hash() const +{ + return hash_combine((size_t)0xfc655abdb5880969, std::hash {}(value)); +} + //*********** nominal_value_exprs *************** dependency_collector nominal_value_exprs::get_dependencies(dependency_solver& solver) const { @@ -52,6 +69,24 @@ nominal_value_exprs::nominal_value_exprs(expr_or_address_list exprs) : exprs(std::move(exprs)) {} +size_t nominal_value_exprs::hash() const +{ + auto result = (size_t)0x0c260c0f86f63b4e; + for (const auto& e : exprs) + { + result = hash_combine(result, + std::visit( + [](const auto& v) { + if constexpr (std::is_same_v) + return v->hash(); + else + return v.hash(); + }, + e)); + } + return result; +} + //*********** nominal_value_list *************** @@ -74,3 +109,51 @@ address_nominal::address_nominal(mach_expr_ptr displacement, mach_expr_ptr base) : displacement(std::move(displacement)) , base(std::move(base)) {} + +size_t address_nominal::hash() const +{ + auto result = (size_t)0x2aa82a8e5d77ef6c; + + if (displacement) + result = hash_combine(result, displacement->hash()); + if (base) + result = hash_combine(result, base->hash()); + + return result; +} + +namespace hlasm_plugin::parser_library::expressions { + +bool is_similar(const nominal_value_t& l, const nominal_value_t& r) +{ + return utils::is_similar(l.access_string(), r.access_string()) + && utils::is_similar(l.access_exprs(), r.access_exprs()); +} + +bool is_similar(const address_nominal& l, const address_nominal& r) +{ + return utils::is_similar(l, r, &address_nominal::displacement, &address_nominal::base); +} + +bool is_similar(const nominal_value_exprs& left, const nominal_value_exprs& right) +{ + if (left.exprs.size() != right.exprs.size()) + return false; + + for (size_t i = 0; i < left.exprs.size(); ++i) + { + if (!std::visit( + [](const auto& l, const auto& r) { + if constexpr (std::is_same_v) + return utils::is_similar(l, r); + else + return false; + }, + left.exprs[i], + right.exprs[i])) + return false; + } + return true; +} + +} // namespace hlasm_plugin::parser_library::expressions diff --git a/parser_library/src/expressions/nominal_value.h b/parser_library/src/expressions/nominal_value.h index 142e21370..94e8afa0a 100644 --- a/parser_library/src/expressions/nominal_value.h +++ b/parser_library/src/expressions/nominal_value.h @@ -29,7 +29,14 @@ struct nominal_value_t : public context::dependable nominal_value_string* access_string(); nominal_value_exprs* access_exprs(); + const nominal_value_string* access_string() const; + const nominal_value_exprs* access_exprs() const; + virtual ~nominal_value_t() = default; + + virtual size_t hash() const = 0; + + friend bool is_similar(const nominal_value_t& l, const nominal_value_t& r); }; using nominal_value_ptr = std::unique_ptr; @@ -41,16 +48,24 @@ struct nominal_value_string final : public nominal_value_t nominal_value_string(std::string value, range rng); std::string value; range value_range; + + friend bool is_similar(const nominal_value_string& l, const nominal_value_string& r) { return l.value == r.value; } + + size_t hash() const override; }; // Represents address in the form D(B) -struct address_nominal : public context::dependable +struct address_nominal final : public context::dependable { context::dependency_collector get_dependencies(context::dependency_solver& solver) const override; address_nominal(); address_nominal(mach_expr_ptr displacement, mach_expr_ptr base); mach_expr_ptr displacement; mach_expr_ptr base; + + friend bool is_similar(const address_nominal& l, const address_nominal& r); + + size_t hash() const; }; using expr_or_address = std::variant; @@ -62,6 +77,10 @@ struct nominal_value_exprs final : public nominal_value_t nominal_value_exprs(expr_or_address_list exprs); expr_or_address_list exprs; + + friend bool is_similar(const nominal_value_exprs& l, const nominal_value_exprs& r); + + size_t hash() const override; }; diff --git a/parser_library/src/parsing/grammar/ca_expr_rules.g4 b/parser_library/src/parsing/grammar/ca_expr_rules.g4 index da54b4592..ff4f52748 100644 --- a/parser_library/src/parsing/grammar/ca_expr_rules.g4 +++ b/parser_library/src/parsing/grammar/ca_expr_rules.g4 @@ -84,10 +84,11 @@ term returns [ca_expr_ptr ca_expr] | data_attribute { auto r = provider.get_range($data_attribute.ctx); - if (std::holds_alternative($data_attribute.value)) - $ca_expr = std::make_unique(std::get($data_attribute.value), $data_attribute.attribute, r, $data_attribute.value_range); - else if (std::holds_alternative($data_attribute.value)) - $ca_expr = std::make_unique(std::move(std::get($data_attribute.value)), $data_attribute.attribute, r, $data_attribute.value_range); + auto val_range = $data_attribute.value_range; + auto attr = $data_attribute.attribute; + $ca_expr = std::visit([&r, &val_range, &attr](auto& v){ + return std::make_unique(std::move(v), attr, r, val_range); + }, $data_attribute.value); } | {is_self_def()}? self_def_term { @@ -228,7 +229,7 @@ var_symbol returns [vs_ptr vs] } | created_set_symbol {$vs = std::move($created_set_symbol.vs);}; -data_attribute returns [context::data_attr_kind attribute, std::variant value, range value_range] +data_attribute returns [context::data_attr_kind attribute, std::variant value, range value_range] : ORDSYMBOL (attr|apostrophe_as_attr) data_attribute_value { collector.add_hl_symbol(token_info(provider.get_range($ORDSYMBOL), hl_scopes::data_attr_type)); @@ -237,8 +238,12 @@ data_attribute returns [context::data_attr_kind attribute, std::variant value] +data_attribute_value returns [std::variant value] : literal + { + if ($literal.value.has_value()) + $value = expressions::ca_literal_def {$literal.text, std::make_shared(std::move($literal.value.value()))}; + } | var_symbol DOT? { $value = std::move($var_symbol.vs); diff --git a/parser_library/src/parsing/grammar/hlasmparser.g4 b/parser_library/src/parsing/grammar/hlasmparser.g4 index ceeb32b72..233cf7635 100644 --- a/parser_library/src/parsing/grammar/hlasmparser.g4 +++ b/parser_library/src/parsing/grammar/hlasmparser.g4 @@ -77,12 +77,6 @@ options { superClass = parser_impl; } -@members -{ - #define last_text() _input->LT(-1)->getText() - #define text(token) token->getText() -} - /* program : ictl? prcs* program_block EOF; diff --git a/parser_library/src/parsing/grammar/machine_expr_rules.g4 b/parser_library/src/parsing/grammar/machine_expr_rules.g4 index 4645da6c9..6a86399d7 100644 --- a/parser_library/src/parsing/grammar/machine_expr_rules.g4 +++ b/parser_library/src/parsing/grammar/machine_expr_rules.g4 @@ -70,12 +70,19 @@ mach_term returns [mach_expr_ptr m_e] } | {is_data_attr()}? mach_data_attribute { - auto rng = provider.get_range( $mach_data_attribute.ctx); - auto attr = get_attribute(std::move($mach_data_attribute.attribute)); - if(attr == data_attr_kind::UNKNOWN || $mach_data_attribute.data == nullptr) + auto rng = provider.get_range($mach_data_attribute.ctx); + auto attr = $mach_data_attribute.attribute; + if(attr == data_attr_kind::UNKNOWN) $m_e = std::make_unique(rng); else - $m_e = std::make_unique($mach_data_attribute.data, attr, rng, $mach_data_attribute.symbol_rng); + $m_e = std::visit([rng, attr, symbol_rng = $mach_data_attribute.symbol_rng](auto& arg) -> mach_expr_ptr { + if constexpr (std::is_same_v,std::monostate>) { + return std::make_unique(rng); + } + else { + return std::make_unique(std::move(arg), attr, rng, symbol_rng); + } + }, $mach_data_attribute.data); } | id { @@ -93,29 +100,50 @@ mach_term returns [mach_expr_ptr m_e] } | literal { - $m_e = std::make_unique(0, provider.get_range($literal.ctx)); + auto rng = provider.get_range($literal.ctx); + if (auto& lv = $literal.value; lv.has_value()) + $m_e = std::make_unique(rng, std::move(lv.value()), $literal.text); + else + $m_e = std::make_unique(rng); }; -literal - : equals data_def; +literal returns [std::optional value] + : equals + { + bool lit_allowed = allow_literals(); + auto lit_restore = disable_literals(); + } + data_def + { + if (lit_allowed) + $value = std::move($data_def.value); + else + add_diagnostic(diagnostic_severity::error, "S0013", "Invalid literal usage", provider.get_range($equals.ctx)); + }; -mach_data_attribute returns [std::string attribute, id_index data = nullptr, range symbol_rng] - : ORDSYMBOL (attr|apostrophe_as_attr) mach_data_attribute_value +mach_data_attribute returns [data_attr_kind attribute, std::variant> data, range symbol_rng] + : ORDSYMBOL (attr|apostrophe_as_attr) {auto lit_restore = enable_literals();} mach_data_attribute_value { collector.add_hl_symbol(token_info(provider.get_range($ORDSYMBOL), hl_scopes::data_attr_type)); - $attribute = $ORDSYMBOL->getText(); - $data = $mach_data_attribute_value.data; - $symbol_rng = provider.get_range( $mach_data_attribute_value.ctx); + $attribute = get_attribute($ORDSYMBOL->getText()); + $data = std::move($mach_data_attribute_value.data); + $symbol_rng = provider.get_range($mach_data_attribute_value.ctx); }; -mach_data_attribute_value returns [id_index data = nullptr] +mach_data_attribute_value returns [std::variant> data] : literal + { + auto rng = provider.get_range($literal.ctx); + if (auto& lv = $literal.value; lv.has_value()) + $data = std::make_unique(rng, std::move(lv.value()), $literal.text); + } | mach_location_counter | id { - collector.add_hl_symbol(token_info(provider.get_range( $id.ctx), hl_scopes::ordinary_symbol)); - $data = $id.name; + collector.add_hl_symbol(token_info(provider.get_range($id.ctx), hl_scopes::ordinary_symbol)); + if (auto name = $id.name) + $data = name; }; string_ch returns [std::string value] diff --git a/parser_library/src/parsing/grammar/operand_field_rules.g4 b/parser_library/src/parsing/grammar/operand_field_rules.g4 index 31c8811b0..054c1cffa 100644 --- a/parser_library/src/parsing/grammar/operand_field_rules.g4 +++ b/parser_library/src/parsing/grammar/operand_field_rules.g4 @@ -97,7 +97,7 @@ op_rem_body_dat | {collector.set_operand_remark_field(provider.get_range(_localctx));} EOF; op_list_dat returns [std::vector operands] - : operand_dat (comma operand_dat)* + : {auto lit_restore = disable_literals();} operand_dat (comma operand_dat)* { auto& result = $operands; auto operands = $ctx->operand_dat(); diff --git a/parser_library/src/parsing/parser_impl.cpp b/parser_library/src/parsing/parser_impl.cpp index f297d2e40..f9ed42dfe 100644 --- a/parser_library/src/parsing/parser_impl.cpp +++ b/parser_library/src/parsing/parser_impl.cpp @@ -16,6 +16,7 @@ #include +#include "context/literal_pool.h" #include "error_strategy.h" #include "expressions/conditional_assembly/ca_expr_visitor.h" #include "expressions/conditional_assembly/terms/ca_constant.h" @@ -98,10 +99,8 @@ bool parser_impl::is_var_def() self_def_t parser_impl::parse_self_def_term(const std::string& option, const std::string& value, range term_range) { - diagnostic_adder add_diagnostic(*diagnoser_, term_range); - auto val = expressions::ca_constant::self_defining_term(option, value, add_diagnostic); - - return val; + auto add_diagnostic = diagnoser_ ? diagnostic_adder(*diagnoser_, term_range) : diagnostic_adder(term_range); + return expressions::ca_constant::self_defining_term(option, value, add_diagnostic); } context::data_attr_kind parser_impl::get_attribute(std::string attr_data) @@ -206,6 +205,13 @@ antlr4::misc::IntervalSet parser_impl::getExpectedTokens() return antlr4::Parser::getExpectedTokens(); } +void parser_impl::add_diagnostic( + diagnostic_severity severity, std::string code, std::string message, range diag_range) const +{ + if (diagnoser_) + diagnoser_->add_diagnostic(diagnostic_op(severity, std::move(code), std::move(message), diag_range)); +} + parser_holder::~parser_holder() = default; } // namespace hlasm_plugin::parser_library::parsing diff --git a/parser_library/src/parsing/parser_impl.h b/parser_library/src/parsing/parser_impl.h index 4e57960cf..9ee91da81 100644 --- a/parser_library/src/parsing/parser_impl.h +++ b/parser_library/src/parsing/parser_impl.h @@ -19,6 +19,7 @@ #include "context/hlasm_context.h" #include "diagnosable.h" +#include "expressions/data_definition.h" #include "lexing/lexer.h" #include "processing/opencode_provider.h" #include "processing/statement_fields_parser.h" @@ -62,6 +63,44 @@ class parser_impl : public antlr4::Parser semantics::collector& get_collector() { return collector; } protected: + class literal_controller + { + enum class request_t + { + none, + off, + on, + } request = request_t::none; + parser_impl& impl; + + public: + explicit literal_controller(parser_impl& impl) + : impl(impl) + {} + literal_controller(parser_impl& impl, bool restore) + : request(restore ? request_t::on : request_t::off) + , impl(impl) + {} + literal_controller(literal_controller&& oth) noexcept + : request(std::exchange(oth.request, request_t::none)) + , impl(oth.impl) + {} + ~literal_controller() + { + switch (request) + { + case request_t::off: + impl.literals_allowed = false; + break; + case request_t::on: + impl.literals_allowed = true; + break; + default: + break; + } + } + }; + void enable_continuation(); void disable_continuation(); bool is_self_def(); @@ -72,6 +111,24 @@ class parser_impl : public antlr4::Parser void enable_ca_string() { ca_string_enabled = true; } void disable_ca_string() { ca_string_enabled = false; } + bool allow_literals() const { return literals_allowed; } + literal_controller enable_literals() + { + if (literals_allowed) + return literal_controller(*this); + + literals_allowed = true; + return literal_controller(*this, false); + } + literal_controller disable_literals() + { + if (!literals_allowed) + return literal_controller(*this); + + literals_allowed = false; + return literal_controller(*this, true); + } + self_def_t parse_self_def_term(const std::string& option, const std::string& value, range term_range); context::data_attr_kind get_attribute(std::string attr_data); context::id_index parse_identifier(std::string value, range id_range); @@ -91,12 +148,15 @@ class parser_impl : public antlr4::Parser bool DAT(); bool ALIAS(); + void add_diagnostic(diagnostic_severity severity, std::string code, std::string message, range diag_range) const; + private: antlr4::misc::IntervalSet getExpectedTokens() override; diagnostic_op_consumer* diagnoser_ = nullptr; parser_error_listener err_listener_; bool ca_string_enabled = true; + bool literals_allowed = true; }; // structure containing parser components diff --git a/parser_library/src/processing/CMakeLists.txt b/parser_library/src/processing/CMakeLists.txt index e73b15d0a..8b4fdc4ab 100644 --- a/parser_library/src/processing/CMakeLists.txt +++ b/parser_library/src/processing/CMakeLists.txt @@ -17,6 +17,7 @@ target_sources(parser_library PRIVATE db2_preprocessor.cpp error_statement.cpp error_statement.h + op_code.cpp op_code.h opencode_provider.cpp opencode_provider.h diff --git a/parser_library/src/processing/instruction_sets/asm_processor.cpp b/parser_library/src/processing/instruction_sets/asm_processor.cpp index 6d86251a0..b910ee386 100644 --- a/parser_library/src/processing/instruction_sets/asm_processor.cpp +++ b/parser_library/src/processing/instruction_sets/asm_processor.cpp @@ -15,6 +15,8 @@ #include "asm_processor.h" #include "checking/instr_operand.h" +#include "context/literal_pool.h" +#include "context/ordinary_assembly/ordinary_assembly_dependency_solver.h" #include "data_def_postponed_statement.h" #include "ebcdic_encoding.h" #include "expressions/mach_expr_term.h" @@ -28,17 +30,34 @@ void asm_processor::process_sect(const context::section_kind kind, rebuilt_state { auto sect_name = find_label_symbol(stmt); - if (hlasm_ctx.ord_ctx.symbol_defined(sect_name) && !hlasm_ctx.ord_ctx.section_defined(sect_name, kind)) + using context::section_kind; + const auto do_other_private_sections_exist = [this](context::id_index sect_name, section_kind kind) { + for (auto k : { section_kind::COMMON, section_kind::EXECUTABLE, section_kind::READONLY }) + { + if (k == kind) + continue; + if (hlasm_ctx.ord_ctx.section_defined(sect_name, k)) + return true; + } + return false; + }; + + const auto& processing_stack = hlasm_ctx.processing_stack(); + if (hlasm_ctx.ord_ctx.symbol_defined(sect_name) + && (sect_name != context::id_storage::empty_id && !hlasm_ctx.ord_ctx.section_defined(sect_name, kind) + || sect_name == context::id_storage::empty_id && kind != section_kind::DUMMY + && do_other_private_sections_exist(sect_name, kind))) { add_diagnostic(diagnostic_op::error_E031("symbol", stmt.label_ref().field_range)); } else { - auto sym_loc = hlasm_ctx.processing_stack().back().proc_location; + auto sym_loc = processing_stack.back().proc_location; sym_loc.pos.column = 0; hlasm_ctx.ord_ctx.set_section(sect_name, kind, std::move(sym_loc)); } - check(stmt, hlasm_ctx, checker_, *this); + context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx); + check(stmt, processing_stack, dep_solver, checker_, *this); } void asm_processor::process_LOCTR(rebuilt_statement stmt) @@ -48,6 +67,7 @@ void asm_processor::process_LOCTR(rebuilt_statement stmt) if (loctr_name == context::id_storage::empty_id) add_diagnostic(diagnostic_op::error_E053(stmt.label_ref().field_range)); + const auto& processing_stack = hlasm_ctx.processing_stack(); if (hlasm_ctx.ord_ctx.symbol_defined(loctr_name) && !hlasm_ctx.ord_ctx.counter_defined(loctr_name)) { add_diagnostic(diagnostic_op::error_E031("symbol", stmt.label_ref().field_range)); @@ -58,12 +78,14 @@ void asm_processor::process_LOCTR(rebuilt_statement stmt) sym_loc.pos.column = 0; hlasm_ctx.ord_ctx.set_location_counter(loctr_name, std::move(sym_loc)); } - check(stmt, hlasm_ctx, checker_, *this); + context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx); + check(stmt, processing_stack, dep_solver, checker_, *this); } void asm_processor::process_EQU(rebuilt_statement stmt) { - fill_expression_loc_counters(stmt, context::no_align); + auto loctr = hlasm_ctx.ord_ctx.align(context::no_align); + context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx, loctr); auto symbol_name = find_label_symbol(stmt); @@ -86,9 +108,9 @@ void asm_processor::process_EQU(rebuilt_statement stmt) auto asm_op = stmt.operands_ref().value[2]->access_asm(); auto expr_op = asm_op->access_expr(); - if (expr_op && !expr_op->has_dependencies(hlasm_ctx.ord_ctx)) + if (expr_op && !expr_op->has_dependencies(dep_solver)) { - auto t_value = expr_op->expression->resolve(hlasm_ctx.ord_ctx); + auto t_value = expr_op->expression->resolve(dep_solver); if (t_value.value_kind() == context::symbol_value_kind::ABS && t_value.get_abs() >= 0 && t_value.get_abs() <= 255) t_attr = (context::symbol_attributes::type_attr)t_value.get_abs(); @@ -106,9 +128,9 @@ void asm_processor::process_EQU(rebuilt_statement stmt) auto asm_op = stmt.operands_ref().value[1]->access_asm(); auto expr_op = asm_op->access_expr(); - if (expr_op && !expr_op->has_dependencies(hlasm_ctx.ord_ctx)) + if (expr_op && !expr_op->has_dependencies(dep_solver)) { - auto length_value = expr_op->expression->resolve(hlasm_ctx.ord_ctx); + auto length_value = expr_op->expression->resolve(dep_solver); if (length_value.value_kind() == context::symbol_value_kind::ABS && length_value.get_abs() >= 0 && length_value.get_abs() <= 65535) length_attr = (context::symbol_attributes::len_attr)length_value.get_abs(); @@ -127,7 +149,7 @@ void asm_processor::process_EQU(rebuilt_statement stmt) if (expr_op) { - auto holder(expr_op->expression->get_dependencies(hlasm_ctx.ord_ctx)); + auto holder(expr_op->expression->get_dependencies(dep_solver)); if (length_attr == context::symbol_attributes::undef_length) { @@ -149,8 +171,7 @@ void asm_processor::process_EQU(rebuilt_statement stmt) if (!holder.contains_dependencies()) { - create_symbol( - stmt.stmt_range_ref(), symbol_name, expr_op->expression->resolve(hlasm_ctx.ord_ctx), attrs); + create_symbol(stmt.stmt_range_ref(), symbol_name, expr_op->expression->resolve(dep_solver), attrs); } else { @@ -164,7 +185,8 @@ void asm_processor::process_EQU(rebuilt_statement stmt) add_dependency(stmt_range, symbol_name, &*expr_op->expression, - std::make_unique(std::move(stmt), hlasm_ctx.processing_stack())); + std::make_unique(std::move(stmt), hlasm_ctx.processing_stack()), + dep_solver.derive_current_dependency_evaluation_context()); } } else @@ -177,12 +199,19 @@ void asm_processor::process_EQU(rebuilt_statement stmt) template void asm_processor::process_data_instruction(rebuilt_statement stmt) { - // enforce alignment of the first operand - context::alignment al = context::no_align; - if (!stmt.operands_ref().value.empty() && stmt.operands_ref().value[0]->type != semantics::operand_type::EMPTY) - al = stmt.operands_ref().value[0]->access_data_def()->value->get_alignment(); + if (const auto& ops = stmt.operands_ref().value; ops.empty() + || std::any_of( + ops.begin(), ops.end(), [](const auto& op) { return op->type == semantics::operand_type::EMPTY; })) + { + context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx); + check(stmt, hlasm_ctx.processing_stack(), dep_solver, checker_, *this); + return; + } - context::address adr = hlasm_ctx.ord_ctx.align(al); + // enforce alignment of the first operand + context::alignment al = stmt.operands_ref().value.front()->access_data_def()->value->get_alignment(); + context::address loctr = hlasm_ctx.ord_ctx.align(al); + context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx, loctr); // dependency sources is list of all expressions in data def operand, that have some unresolved dependencies. bool has_dependencies = false; @@ -191,15 +220,11 @@ void asm_processor::process_data_instruction(rebuilt_statement stmt) bool has_length_dependencies = false; for (const auto& op : stmt.operands_ref().value) { - if (op->type == semantics::operand_type::EMPTY) - continue; auto data_op = op->access_data_def(); - data_op->value->assign_location_counter(adr); - - has_dependencies |= data_op->value->type != 'V' && data_op->has_dependencies(hlasm_ctx.ord_ctx); + has_dependencies |= data_op->has_dependencies(dep_solver); - has_length_dependencies |= data_op->get_length_dependencies(hlasm_ctx.ord_ctx).contains_dependencies(); + has_length_dependencies |= data_op->get_length_dependencies(dep_solver).contains_dependencies(); // some types require operands that consist only of one symbol data_op->value->check_single_symbol_ok(diagnostic_collector(this)); @@ -208,8 +233,7 @@ void asm_processor::process_data_instruction(rebuilt_statement stmt) // process label auto label = find_label_symbol(stmt); - if (label != context::id_storage::empty_id && stmt.operands_ref().value.size() - && stmt.operands_ref().value.front()->type != semantics::operand_type::EMPTY) + if (label != context::id_storage::empty_id) { if (!hlasm_ctx.ord_ctx.symbol_defined(label)) { @@ -221,22 +245,21 @@ void asm_processor::process_data_instruction(rebuilt_statement stmt) context::symbol_attributes::len_attr len = context::symbol_attributes::undef_length; context::symbol_attributes::scale_attr scale = context::symbol_attributes::undef_scale; - auto tmp = data_op->get_operand_value(hlasm_ctx.ord_ctx); + auto tmp = data_op->get_operand_value(dep_solver); auto& value = dynamic_cast(*tmp); if (!data_op->value->length - || !data_op->value->length->get_dependencies(hlasm_ctx.ord_ctx).contains_dependencies()) + || !data_op->value->length->get_dependencies(dep_solver).contains_dependencies()) { len = value.get_length_attribute(); } - if (data_op->value->scale - && !data_op->value->scale->get_dependencies(hlasm_ctx.ord_ctx).contains_dependencies()) + if (data_op->value->scale && !data_op->value->scale->get_dependencies(dep_solver).contains_dependencies()) { scale = value.get_scale_attribute(); } create_symbol(stmt.stmt_range_ref(), label, - std::move(adr), + loctr, context::symbol_attributes( context::symbol_origin::DAT, type, len, scale, value.get_integer_attribute())); } @@ -251,7 +274,8 @@ void asm_processor::process_data_instruction(rebuilt_statement stmt) if (has_dependencies) { auto adder = hlasm_ctx.ord_ctx.symbol_dependencies.add_dependencies( - std::make_unique>(std::move(stmt), hlasm_ctx.processing_stack())); + std::make_unique>(std::move(stmt), hlasm_ctx.processing_stack()), + dep_solver.derive_current_dependency_evaluation_context()); if (has_length_dependencies) { auto sp = hlasm_ctx.ord_ctx.register_ordinary_space(al); @@ -261,41 +285,36 @@ void asm_processor::process_data_instruction(rebuilt_statement stmt) else hlasm_ctx.ord_ctx.reserve_storage_area( data_def_postponed_statement::get_operands_length( - adder.source_stmt->impl()->operands_ref().value, hlasm_ctx.ord_ctx), + adder.source_stmt->resolved_stmt()->operands_ref().value, dep_solver), context::no_align); bool cycle_ok = true; if (label != context::id_storage::empty_id) { - if (adder.source_stmt->impl()->operands_ref().value.empty()) - return; - - auto data_op = adder.source_stmt->impl()->operands_ref().value.front()->access_data_def(); + auto data_op = adder.source_stmt->resolved_stmt()->operands_ref().value.front()->access_data_def(); - if (data_op->value->length - && data_op->value->length->get_dependencies(hlasm_ctx.ord_ctx).contains_dependencies()) + if (data_op->value->length && data_op->value->length->get_dependencies(dep_solver).contains_dependencies()) cycle_ok = adder.add_dependency(label, context::data_attr_kind::L, data_op->value->length.get()); - if (data_op->value->scale - && data_op->value->scale->get_dependencies(hlasm_ctx.ord_ctx).contains_dependencies()) + if (data_op->value->scale && data_op->value->scale->get_dependencies(dep_solver).contains_dependencies()) cycle_ok &= adder.add_dependency(label, context::data_attr_kind::S, data_op->value->scale.get()); } adder.add_dependency(); if (!cycle_ok) - add_diagnostic( - diagnostic_op::error_E033(adder.source_stmt->impl()->operands_ref().value.front()->operand_range)); + add_diagnostic(diagnostic_op::error_E033( + adder.source_stmt->resolved_stmt()->operands_ref().value.front()->operand_range)); adder.finish(); } else { hlasm_ctx.ord_ctx.reserve_storage_area( - data_def_postponed_statement::get_operands_length(stmt.operands_ref().value, hlasm_ctx.ord_ctx), + data_def_postponed_statement::get_operands_length(stmt.operands_ref().value, dep_solver), context::no_align); - check(stmt, hlasm_ctx, checker_, *this); + check(stmt, hlasm_ctx.processing_stack(), dep_solver, checker_, *this); } } @@ -319,7 +338,8 @@ void asm_processor::process_COPY(rebuilt_statement stmt) } else { - check(stmt, hlasm_ctx, checker_, *this); + context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx); + check(stmt, hlasm_ctx.processing_stack(), dep_solver, checker_, *this); } } @@ -336,7 +356,8 @@ void asm_processor::process_external(rebuilt_statement stmt, external_type t) else find_sequence_symbol(stmt); } - if (!check(stmt, hlasm_ctx, checker_, *this)) + context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx); + if (!check(stmt, hlasm_ctx.processing_stack(), dep_solver, checker_, *this)) return; const auto add_external = [s_kind = t == external_type::strong ? context::section_kind::EXTERNAL @@ -374,20 +395,22 @@ void asm_processor::process_external(rebuilt_statement stmt, external_type t) } } -std::optional asm_processor::try_get_abs_value(const semantics::operand* op) const +std::optional asm_processor::try_get_abs_value( + const semantics::operand* op, context::dependency_solver& dep_solver) const { auto expr_op = dynamic_cast(op); if (!expr_op) return std::nullopt; - return try_get_abs_value(expr_op); + return try_get_abs_value(expr_op, dep_solver); } -std::optional asm_processor::try_get_abs_value(const semantics::simple_expr_operand* op) const +std::optional asm_processor::try_get_abs_value( + const semantics::simple_expr_operand* op, context::dependency_solver& dep_solver) const { - if (op->has_dependencies(hlasm_ctx.ord_ctx)) + if (op->has_dependencies(dep_solver)) return std::nullopt; - auto val = op->expression->evaluate(hlasm_ctx.ord_ctx); + auto val = op->expression->evaluate(dep_solver); if (val.value_kind() != context::symbol_value_kind::ABS) return std::nullopt; @@ -396,21 +419,19 @@ std::optional asm_processor::try_get_abs_value(const semantics::si void asm_processor::process_ORG(rebuilt_statement stmt) { - fill_expression_loc_counters(stmt, context::no_align); find_sequence_symbol(stmt); auto label = find_label_symbol(stmt); + auto loctr = hlasm_ctx.ord_ctx.align(context::no_align); if (label != context::id_storage::empty_id) { if (hlasm_ctx.ord_ctx.symbol_defined(label)) add_diagnostic(diagnostic_op::error_E031("symbol", stmt.label_ref().field_range)); else - create_symbol(stmt.stmt_range_ref(), - label, - hlasm_ctx.ord_ctx.align(context::no_align), - context::symbol_attributes::make_org_attrs()); + create_symbol(stmt.stmt_range_ref(), label, loctr, context::symbol_attributes::make_org_attrs()); } + context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx, loctr); const semantics::expr_assembler_operand* reloc_expr = nullptr; bool undefined_absolute_part = false; @@ -436,7 +457,7 @@ void asm_processor::process_ORG(rebuilt_statement stmt) if (i == 0) { - auto deps = expr->expression->get_dependencies(hlasm_ctx.ord_ctx); + auto deps = expr->expression->get_dependencies(dep_solver); undefined_absolute_part = deps.undefined_attr_refs.size() || deps.undefined_symbols.size() || deps.unresolved_spaces.size(); if (!deps.unresolved_address) @@ -449,7 +470,7 @@ void asm_processor::process_ORG(rebuilt_statement stmt) if (i == 1) { - auto val = try_get_abs_value(expr); + auto val = try_get_abs_value(expr, dep_solver); if (!val || *val < 2 || *val > 4096 || ((*val & (*val - 1)) != 0)) // check range and test for power of 2 { add_diagnostic(diagnostic_op::error_A116_ORG_boundary_operand(stmt.stmt_range_ref())); @@ -459,7 +480,7 @@ void asm_processor::process_ORG(rebuilt_statement stmt) } if (i == 2) { - auto val = try_get_abs_value(expr); + auto val = try_get_abs_value(expr, dep_solver); if (!val) { add_diagnostic(diagnostic_op::error_A115_ORG_op_format(stmt.stmt_range_ref())); @@ -472,21 +493,21 @@ void asm_processor::process_ORG(rebuilt_statement stmt) if (reloc_expr) { auto reloc_val = !undefined_absolute_part - ? reloc_expr->expression->evaluate(hlasm_ctx.ord_ctx).get_reloc() - : *reloc_expr->expression->get_dependencies(hlasm_ctx.ord_ctx).unresolved_address; + ? reloc_expr->expression->evaluate(dep_solver).get_reloc() + : *reloc_expr->expression->get_dependencies(dep_solver).unresolved_address; - if (!check_address_for_ORG( - stmt.stmt_range_ref(), reloc_val, hlasm_ctx.ord_ctx.align(context::no_align), boundary, offset)) + if (!check_address_for_ORG(stmt.stmt_range_ref(), reloc_val, loctr, boundary, offset)) return; if (undefined_absolute_part) - hlasm_ctx.ord_ctx.set_location_counter_value(std::move(reloc_val), + hlasm_ctx.ord_ctx.set_location_counter_value(reloc_val, boundary, offset, reloc_expr->expression.get(), - std::make_unique(std::move(stmt), hlasm_ctx.processing_stack())); + std::make_unique(std::move(stmt), hlasm_ctx.processing_stack()), + dep_solver.derive_current_dependency_evaluation_context()); else - hlasm_ctx.ord_ctx.set_location_counter_value(std::move(reloc_val), boundary, offset, nullptr, nullptr); + hlasm_ctx.ord_ctx.set_location_counter_value(reloc_val, boundary, offset); } else hlasm_ctx.ord_ctx.set_available_location_counter_value(boundary, offset); @@ -495,7 +516,8 @@ void asm_processor::process_ORG(rebuilt_statement stmt) void asm_processor::process_OPSYN(rebuilt_statement stmt) { const auto& operands = stmt.operands_ref().value; - if (!check(stmt, hlasm_ctx, checker_, *this)) + context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx); + if (!check(stmt, hlasm_ctx.processing_stack(), dep_solver, checker_, *this)) return; auto label = find_label_symbol(stmt); @@ -555,7 +577,8 @@ void asm_processor::process(std::shared_ptrsecond.has_ord_symbols : true; if (op->type != semantics::operand_type::EMPTY && can_have_ord_syms - && op->access_asm()->has_dependencies(hlasm_ctx.ord_ctx)) - return; + && op->access_asm()->has_dependencies(dep_solver)) + skip_check = true; } - check(rebuilt_stmt, hlasm_ctx, checker_, *this); + if (skip_check) + return; + check(rebuilt_stmt, hlasm_ctx.processing_stack(), dep_solver, checker_, *this); } } @@ -644,6 +669,7 @@ asm_processor::process_table_t asm_processor::create_table(context::hlasm_contex table.emplace(h_ctx.ids().add("START"), [this](rebuilt_statement stmt) { process_START(std::move(stmt)); }); table.emplace(h_ctx.ids().add("ALIAS"), [this](rebuilt_statement stmt) { process_ALIAS(std::move(stmt)); }); table.emplace(h_ctx.ids().add("END"), [this](rebuilt_statement stmt) { process_END(std::move(stmt)); }); + table.emplace(h_ctx.ids().add("LTORG"), [this](rebuilt_statement stmt) { process_LTORG(std::move(stmt)); }); return table; } @@ -673,6 +699,7 @@ class AINSERT_operand_visitor final : public expressions::mach_expr_visitor void visit(const expressions::mach_expr_location_counter&) override {} void visit(const expressions::mach_expr_self_def&) override {} void visit(const expressions::mach_expr_default&) override {} + void visit(const expressions::mach_expr_literal&) override {} context::id_index value = nullptr; }; @@ -682,7 +709,8 @@ void asm_processor::process_AINSERT(rebuilt_statement stmt) { const auto& ops = stmt.operands_ref(); - if (!check(stmt, hlasm_ctx, checker_, *this)) + context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx); + if (!check(stmt, hlasm_ctx.processing_stack(), dep_solver, checker_, *this)) return; const auto& record = dynamic_cast(*ops.value[0]).value; @@ -702,43 +730,38 @@ void asm_processor::process_CCW(rebuilt_statement stmt) constexpr context::alignment ccw_align = context::doubleword; constexpr size_t ccw_length = 8U; - fill_expression_loc_counters(stmt, ccw_align); + auto loctr = hlasm_ctx.ord_ctx.align(ccw_align); + context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx, loctr); find_sequence_symbol(stmt); - - if (auto label = find_label_symbol(stmt); label != context::id_storage::empty_id) { if (hlasm_ctx.ord_ctx.symbol_defined(label)) add_diagnostic(diagnostic_op::error_E031("symbol", stmt.label_ref().field_range)); else - create_symbol(stmt.stmt_range_ref(), - label, - hlasm_ctx.ord_ctx.align(ccw_align), - context::symbol_attributes::make_ccw_attrs()); + create_symbol(stmt.stmt_range_ref(), label, loctr, context::symbol_attributes::make_ccw_attrs()); } hlasm_ctx.ord_ctx.reserve_storage_area(ccw_length, ccw_align); - - bool has_dependencies = - std::any_of(stmt.operands_ref().value.begin(), stmt.operands_ref().value.end(), [this](const auto& op) { + bool has_dependencies = std::any_of( + stmt.operands_ref().value.begin(), stmt.operands_ref().value.end(), [this, &dep_solver](const auto& op) { auto evaluable = dynamic_cast(op.get()); - return evaluable && evaluable->has_dependencies(hlasm_ctx.ord_ctx); + return evaluable && evaluable->has_dependencies(dep_solver); }); if (has_dependencies) hlasm_ctx.ord_ctx.symbol_dependencies.add_dependency( - std::make_unique(std::move(stmt), hlasm_ctx.processing_stack())); + std::make_unique(std::move(stmt), hlasm_ctx.processing_stack()), + dep_solver.derive_current_dependency_evaluation_context()); else - check(stmt, hlasm_ctx, checker_, *this); + check(stmt, hlasm_ctx.processing_stack(), dep_solver, checker_, *this); } void asm_processor::process_CNOP(rebuilt_statement stmt) { - constexpr context::alignment CNOP_symbol_align = context::halfword; - - fill_expression_loc_counters(stmt, CNOP_symbol_align); + auto loctr = hlasm_ctx.ord_ctx.align(context::halfword); + context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx, loctr); find_sequence_symbol(stmt); if (auto label = find_label_symbol(stmt); label != context::id_storage::empty_id) @@ -746,20 +769,16 @@ void asm_processor::process_CNOP(rebuilt_statement stmt) if (hlasm_ctx.ord_ctx.symbol_defined(label)) add_diagnostic(diagnostic_op::error_E031("symbol", stmt.label_ref().field_range)); else - create_symbol(stmt.stmt_range_ref(), - label, - hlasm_ctx.ord_ctx.align(CNOP_symbol_align), - context::symbol_attributes::make_cnop_attrs()); + create_symbol(stmt.stmt_range_ref(), label, loctr, context::symbol_attributes::make_cnop_attrs()); } - check(stmt, hlasm_ctx, checker_, *this); + check(stmt, hlasm_ctx.processing_stack(), dep_solver, checker_, *this); if (stmt.operands_ref().value.size() != 2) return; - - std::optional byte_value = try_get_abs_value(stmt.operands_ref().value[0].get()); - std::optional boundary_value = try_get_abs_value(stmt.operands_ref().value[1].get()); + std::optional byte_value = try_get_abs_value(stmt.operands_ref().value[0].get(), dep_solver); + std::optional boundary_value = try_get_abs_value(stmt.operands_ref().value[1].get(), dep_solver); // For now, the implementation ignores the instruction, if the operands have dependencies. Most uses of this // instruction should by covered anyway. It will still generate the label correctly. if (!byte_value.has_value() || !boundary_value.has_value()) @@ -787,18 +806,20 @@ void asm_processor::process_START(rebuilt_statement stmt) return; } - auto sym_loc = hlasm_ctx.processing_stack().back().proc_location; + const auto& processing_stack = hlasm_ctx.processing_stack(); + auto sym_loc = processing_stack.back().proc_location; sym_loc.pos.column = 0; hlasm_ctx.ord_ctx.set_section(sect_name, context::section_kind::EXECUTABLE, std::move(sym_loc)); + context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx); const auto& ops = stmt.operands_ref().value; if (ops.size() != 1) { - check(stmt, hlasm_ctx, checker_, *this); + check(stmt, processing_stack, dep_solver, checker_, *this); return; } - auto initial_offset = try_get_abs_value(ops.front().get()); + auto initial_offset = try_get_abs_value(ops.front().get(), dep_solver); if (!initial_offset.has_value()) { add_diagnostic(diagnostic_op::error_A250_absolute_with_known_symbols(ops.front()->operand_range)); @@ -821,7 +842,9 @@ void asm_processor::process_START(rebuilt_statement stmt) void asm_processor::process_END(rebuilt_statement stmt) { const auto& label = stmt.label_ref(); - check(stmt, hlasm_ctx, checker_, *this); + context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx); + + check(stmt, hlasm_ctx.processing_stack(), dep_solver, checker_, *this); if (!(label.type == semantics::label_si_type::EMPTY || label.type == semantics::label_si_type::SEQ)) { @@ -832,8 +855,8 @@ void asm_processor::process_END(rebuilt_statement stmt) if (stmt.operands_ref().value[0]->access_asm() != nullptr && stmt.operands_ref().value[0]->access_asm()->kind == semantics::asm_kind::EXPR) { - auto symbol = stmt.operands_ref().value[0]->access_asm()->access_expr()->expression.get()->evaluate( - hlasm_ctx.ord_ctx); + auto symbol = + stmt.operands_ref().value[0]->access_asm()->access_expr()->expression.get()->evaluate(dep_solver); if (symbol.value_kind() == context::symbol_value_kind::ABS) { @@ -842,11 +865,13 @@ void asm_processor::process_END(rebuilt_statement stmt) } } } + hlasm_ctx.end_reached(); } void asm_processor::process_ALIAS(rebuilt_statement stmt) { - if (!check(stmt, hlasm_ctx, checker_, *this)) + context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx); + if (!check(stmt, hlasm_ctx.processing_stack(), dep_solver, checker_, *this)) return; auto symbol_name = find_label_symbol(stmt); if (symbol_name->empty()) @@ -857,5 +882,29 @@ void asm_processor::process_ALIAS(rebuilt_statement stmt) // TODO: check that the symbol_name is an external symbol } +void asm_processor::process_LTORG(rebuilt_statement stmt) +{ + constexpr size_t sectalgn = 8; + auto loctr = hlasm_ctx.ord_ctx.align(context::alignment { 0, sectalgn }); + + context::ordinary_assembly_dependency_solver dep_solver( + hlasm_ctx.ord_ctx, context::ordinary_assembly_dependency_solver::no_new_literals {}); + find_sequence_symbol(stmt); + + check(stmt, hlasm_ctx.processing_stack(), dep_solver, checker_, *this); + + if (auto label = find_label_symbol(stmt); label != context::id_storage::empty_id) + { + if (hlasm_ctx.ord_ctx.symbol_defined(label)) + add_diagnostic(diagnostic_op::error_E031("symbol", stmt.label_ref().field_range)); + else + create_symbol(stmt.stmt_range_ref(), + label, + loctr, + context::symbol_attributes(context::symbol_origin::EQU, ebcdic_encoding::to_ebcdic('U'), 1)); + } + + hlasm_ctx.ord_ctx.generate_pool(dep_solver, *this); +} } // namespace hlasm_plugin::parser_library::processing diff --git a/parser_library/src/processing/instruction_sets/asm_processor.h b/parser_library/src/processing/instruction_sets/asm_processor.h index adcf284f4..0d96ff8e1 100644 --- a/parser_library/src/processing/instruction_sets/asm_processor.h +++ b/parser_library/src/processing/instruction_sets/asm_processor.h @@ -65,14 +65,16 @@ class asm_processor : public low_language_processor void process_CNOP(rebuilt_statement stmt); void process_START(rebuilt_statement stmt); void process_ALIAS(rebuilt_statement stmt); - void process_END(rebuilt_statement stmt); + void process_LTORG(rebuilt_statement stmt); template void process_data_instruction(rebuilt_statement stmt); - std::optional try_get_abs_value(const semantics::operand* op) const; - std::optional try_get_abs_value(const semantics::simple_expr_operand* op) const; + std::optional try_get_abs_value( + const semantics::operand* op, context::dependency_solver& dep_solver) const; + std::optional try_get_abs_value( + const semantics::simple_expr_operand* op, context::dependency_solver& dep_solver) const; enum class external_type { diff --git a/parser_library/src/processing/instruction_sets/data_def_postponed_statement.h b/parser_library/src/processing/instruction_sets/data_def_postponed_statement.h index 7bebc4567..8111d167f 100644 --- a/parser_library/src/processing/instruction_sets/data_def_postponed_statement.h +++ b/parser_library/src/processing/instruction_sets/data_def_postponed_statement.h @@ -18,6 +18,7 @@ #include #include "checking/data_definition/data_definition_operand.h" +#include "context/ordinary_assembly/symbol_dependency_tables.h" #include "postponed_statement_impl.h" namespace hlasm_plugin::parser_library::processing { @@ -43,20 +44,65 @@ struct data_def_postponed_statement : public postponed_statement_impl, public co return conjunction; } - static int32_t get_operands_length(const semantics::operand_list& operands, context::dependency_solver& solver) + static int32_t get_operands_length(const semantics::operand_list& operands, context::dependency_solver& _solver) { - std::vector checking_ops; - std::vector get_len_ops; + struct data_def_dependency_solver final : public context::dependency_solver + { + explicit data_def_dependency_solver(context::dependency_solver& base) + : base(base) + {} + context::dependency_solver& base; + uint64_t operands_bit_length = 0; + + const context::symbol* get_symbol(context::id_index name) const override { return base.get_symbol(name); } + std::optional get_loctr() const override + { + if (auto loctr = base.get_loctr(); loctr.has_value()) + return loctr.value() + (int)(operands_bit_length / 8); + + return std::nullopt; + } + context::id_index get_literal_id(const std::string& text, + const std::shared_ptr& dd, + const range& r, + bool align_on_halfword) override + { + return base.get_literal_id(text, dd, r, align_on_halfword); + } + } solver(_solver); + + constexpr const auto round_up_bytes = [](uint64_t& v, uint64_t bytes) { v = checking::round_up(v, bytes * 8); }; + for (const auto& op : operands) { if (op->type == semantics::operand_type::EMPTY) continue; - auto o = op->access_data_def()->get_operand_value(solver); - checking::data_definition_operand* dd_op = dynamic_cast(o.get()); - checking_ops.push_back(std::move(o)); - get_len_ops.push_back(dd_op); + + if (auto dd = op->access_data_def()->value.get(); + dd->length_type != expressions::data_definition::length_type::BIT) + { + // align to whole byte + round_up_bytes(solver.operands_bit_length, 1); + + // enforce data def alignment + round_up_bytes(solver.operands_bit_length, dd->get_alignment().boundary); + } + const auto o = op->access_data_def()->get_operand_value(solver); + const auto* dd_op = dynamic_cast(o.get()); + + + if (!dd_op->check(diagnostic_collector())) + return 0; + + solver.operands_bit_length += dd_op->get_length(); } - uint64_t len = checking::data_definition_operand::get_operands_length(get_len_ops); + + // align to whole byte + round_up_bytes(solver.operands_bit_length, 1); + + // returns the length in bytes + uint64_t len = solver.operands_bit_length / 8; + if (len > INT32_MAX) return 0; else diff --git a/parser_library/src/processing/instruction_sets/low_language_processor.cpp b/parser_library/src/processing/instruction_sets/low_language_processor.cpp index 64ef0abcc..db51a8c30 100644 --- a/parser_library/src/processing/instruction_sets/low_language_processor.cpp +++ b/parser_library/src/processing/instruction_sets/low_language_processor.cpp @@ -31,54 +31,6 @@ low_language_processor::low_language_processor(analyzing_context ctx, , parser(parser) {} -namespace { -class fill_loctr_visitor final : public semantics::operand_visitor -{ -public: - explicit fill_loctr_visitor(context::address address_to_fill) - : addr(std::move(address_to_fill)) - {} - -private: - context::address addr; - // Inherited via operand_visitor - void visit(const semantics::empty_operand&) override {} - void visit(const semantics::model_operand&) override {} - void visit(const semantics::expr_machine_operand& op) override { op.expression->fill_location_counter(addr); } - void visit(const semantics::address_machine_operand& op) override - { - if (op.displacement) - op.displacement->fill_location_counter(addr); - if (op.first_par) - op.first_par->fill_location_counter(addr); - if (op.second_par) - op.second_par->fill_location_counter(addr); - } - void visit(const semantics::expr_assembler_operand& op) override { op.expression->fill_location_counter(addr); } - void visit(const semantics::using_instr_assembler_operand&) override - { - // TODO when USING implementation is done - } - void visit(const semantics::complex_assembler_operand&) override {} - void visit(const semantics::string_assembler_operand&) override {} - void visit(const semantics::data_def_operand& op) override { op.value->assign_location_counter(addr); } - void visit(const semantics::var_ca_operand&) override {} - void visit(const semantics::expr_ca_operand&) override {} - void visit(const semantics::seq_ca_operand&) override {} - void visit(const semantics::branch_ca_operand&) override {} - void visit(const semantics::macro_operand_chain&) override {} - void visit(const semantics::macro_operand_string&) override {} -}; -} // namespace - -void low_language_processor::fill_expression_loc_counters(rebuilt_statement& stmt, context::alignment instr_alignment) -{ - auto addr = hlasm_ctx.ord_ctx.align(instr_alignment); - fill_loctr_visitor fill_visitor(addr); - for (auto& op : stmt.operands_ref().value) - op->apply(fill_visitor); -} - rebuilt_statement low_language_processor::preprocess(std::shared_ptr statement) { auto stmt = std::static_pointer_cast(statement); @@ -209,16 +161,21 @@ bool low_language_processor::check_address_for_ORG(range err_range, return true; } -void low_language_processor::resolve_unknown_loctr_dependency( - context::space_ptr sp, const context::address& addr, range err_range) +void low_language_processor::resolve_unknown_loctr_dependency(context::space_ptr sp, + const context::address& addr, + range err_range, + const context::dependency_evaluation_context& dep_ctx) { auto tmp_loctr = hlasm_ctx.ord_ctx.current_section()->current_location_counter(); hlasm_ctx.ord_ctx.set_location_counter(sp->owner.name, location()); hlasm_ctx.ord_ctx.current_section()->current_location_counter().switch_to_unresolved_value(sp); - if (!check_address_for_ORG( - err_range, addr, hlasm_ctx.ord_ctx.align(context::no_align), sp->previous_boundary, sp->previous_offset)) + if (!check_address_for_ORG(err_range, + addr, + hlasm_ctx.ord_ctx.align(context::no_align, dep_ctx), + sp->previous_boundary, + sp->previous_offset)) { (void)hlasm_ctx.ord_ctx.current_section()->current_location_counter().restore_from_unresolved_value(sp); hlasm_ctx.ord_ctx.set_location_counter(tmp_loctr.name, location()); @@ -226,7 +183,7 @@ void low_language_processor::resolve_unknown_loctr_dependency( } auto new_sp = hlasm_ctx.ord_ctx.set_location_counter_value_space( - addr, sp->previous_boundary, sp->previous_offset, nullptr, nullptr); + addr, sp->previous_boundary, sp->previous_offset, nullptr, nullptr, dep_ctx); auto ret = hlasm_ctx.ord_ctx.current_section()->current_location_counter().restore_from_unresolved_value(sp); hlasm_ctx.ord_ctx.set_location_counter(tmp_loctr.name, location()); @@ -247,7 +204,7 @@ void low_language_processor::resolve_unknown_loctr_dependency( low_language_processor::transform_result low_language_processor::transform_mnemonic( - const resolved_statement& stmt, context::hlasm_context& hlasm_ctx, diagnostic_collector add_diagnostic) + const resolved_statement& stmt, context::dependency_solver& dep_solver, diagnostic_collector add_diagnostic) { // operands obtained from the user const auto& operands = stmt.operands_ref().value; @@ -298,7 +255,7 @@ low_language_processor::transform_result low_language_processor::transform_mnemo } else // if operand is not empty { - auto uniq = get_check_op(operand.get(), hlasm_ctx, add_diagnostic, stmt, j, &mnemonic); + auto uniq = get_check_op(operand.get(), dep_solver, add_diagnostic, stmt, j, &mnemonic); if (!uniq) return std::nullopt; // contains dependencies @@ -311,7 +268,7 @@ low_language_processor::transform_result low_language_processor::transform_mnemo } low_language_processor::transform_result low_language_processor::transform_default( - const resolved_statement& stmt, context::hlasm_context& hlasm_ctx, diagnostic_collector add_diagnostic) + const resolved_statement& stmt, context::dependency_solver& dep_solver, diagnostic_collector add_diagnostic) { std::vector operand_vector; for (auto& op : stmt.operands_ref().value) @@ -324,7 +281,7 @@ low_language_processor::transform_result low_language_processor::transform_defau continue; } - auto uniq = get_check_op(op.get(), hlasm_ctx, add_diagnostic, stmt, operand_vector.size()); + auto uniq = get_check_op(op.get(), dep_solver, add_diagnostic, stmt, operand_vector.size()); if (!uniq) return std::nullopt; // contains dependencies @@ -336,7 +293,7 @@ low_language_processor::transform_result low_language_processor::transform_defau } checking::check_op_ptr low_language_processor::get_check_op(const semantics::operand* op, - context::hlasm_context& hlasm_ctx, + context::dependency_solver& dep_solver, diagnostic_collector add_diagnostic, const resolved_statement& stmt, size_t op_position, @@ -348,7 +305,7 @@ checking::check_op_ptr low_language_processor::get_check_op(const semantics::ope bool can_have_ord_syms = tmp != context::instruction::assembler_instructions.end() ? tmp->second.has_ord_symbols : true; - if (can_have_ord_syms && ev_op.has_dependencies(hlasm_ctx.ord_ctx)) + if (can_have_ord_syms && ev_op.has_dependencies(dep_solver)) { add_diagnostic(diagnostic_op::error_E010("ordinary symbol", ev_op.operand_range)); return nullptr; @@ -363,18 +320,18 @@ checking::check_op_ptr low_language_processor::get_check_op(const semantics::ope if (instr->operands.size() > op_position) { auto type = instr->operands[op_position].identifier.type; - uniq = mach_op->get_operand_value(hlasm_ctx.ord_ctx, type); + uniq = mach_op->get_operand_value(dep_solver, type); } else - uniq = ev_op.get_operand_value(hlasm_ctx.ord_ctx); + uniq = ev_op.get_operand_value(dep_solver); } else if (auto expr_op = dynamic_cast(&ev_op)) { - uniq = expr_op->get_operand_value(hlasm_ctx.ord_ctx, can_have_ord_syms); + uniq = expr_op->get_operand_value(dep_solver, can_have_ord_syms); } else { - uniq = ev_op.get_operand_value(hlasm_ctx.ord_ctx); + uniq = ev_op.get_operand_value(dep_solver); } ev_op.collect_diags(); @@ -386,13 +343,12 @@ checking::check_op_ptr low_language_processor::get_check_op(const semantics::ope } bool low_language_processor::check(const resolved_statement& stmt, - context::hlasm_context& hlasm_ctx, - checking::instruction_checker& checker, + const context::processing_stack_t& processing_stack, + context::dependency_solver& dep_solver, + const checking::instruction_checker& checker, const diagnosable_ctx& diagnoser) { - auto postponed_stmt = dynamic_cast(&stmt); - diagnostic_collector collector( - &diagnoser, postponed_stmt ? postponed_stmt->location_stack() : hlasm_ctx.processing_stack()); + diagnostic_collector collector(&diagnoser, processing_stack); std::vector operand_ptr_vector; transform_result operand_vector; @@ -402,13 +358,13 @@ bool low_language_processor::check(const resolved_statement& stmt, if (mnem_tmp != context::instruction::mnemonic_codes.end()) { - operand_vector = transform_mnemonic(stmt, hlasm_ctx, collector); + operand_vector = transform_mnemonic(stmt, dep_solver, collector); // save the actual mnemonic name instruction_name = &mnem_tmp->first; } else { - operand_vector = transform_default(stmt, hlasm_ctx, collector); + operand_vector = transform_default(stmt, dep_solver, collector); instruction_name = stmt.opcode_ref().value; } diff --git a/parser_library/src/processing/instruction_sets/low_language_processor.h b/parser_library/src/processing/instruction_sets/low_language_processor.h index 259fead63..4f13118db 100644 --- a/parser_library/src/processing/instruction_sets/low_language_processor.h +++ b/parser_library/src/processing/instruction_sets/low_language_processor.h @@ -27,12 +27,15 @@ class low_language_processor : public instruction_processor, public context::loc { public: static bool check(const resolved_statement& stmt, - context::hlasm_context& hlasm_ctx, - checking::instruction_checker& checker, + const context::processing_stack_t& processing_stack, + context::dependency_solver& dep_solver, + const checking::instruction_checker& checker, const diagnosable_ctx& diagnoser); - void resolve_unknown_loctr_dependency( - context::space_ptr sp, const context::address& addr, range err_range) override; + void resolve_unknown_loctr_dependency(context::space_ptr sp, + const context::address& addr, + range err_range, + const context::dependency_evaluation_context& dep_ctx) override; protected: statement_fields_parser& parser; @@ -44,11 +47,10 @@ class low_language_processor : public instruction_processor, public context::loc rebuilt_statement preprocess(std::shared_ptr stmt); - void fill_expression_loc_counters(rebuilt_statement& stmt, context::alignment instr_alignment); - // adds dependency and also check for cyclic dependency and adds diagnostics if so template - void add_dependency(range err_range, Args&&... args) + auto add_dependency(range err_range, Args&&... args) + -> std::void_t(args)...))> { bool cycle_ok = hlasm_ctx.ord_ctx.symbol_dependencies.add_dependency(std::forward(args)...); if (!cycle_ok) @@ -79,13 +81,13 @@ class low_language_processor : public instruction_processor, public context::loc using transform_result = std::optional>; // transform semantic operands to checking operands - machine mnemonics instructions static transform_result transform_mnemonic( - const resolved_statement& stmt, context::hlasm_context& hlasm_ctx, diagnostic_collector collector); + const resolved_statement& stmt, context::dependency_solver& dep_solver, diagnostic_collector collector); // transform semantic operands to checking operands - default machine instructions static transform_result transform_default( - const resolved_statement& stmt, context::hlasm_context& hlasm_ctx, diagnostic_collector collector); + const resolved_statement& stmt, context::dependency_solver& dep_solver, diagnostic_collector collector); static checking::check_op_ptr get_check_op(const semantics::operand* op, - context::hlasm_context& hlasm_ctx, + context::dependency_solver& dep_solver, diagnostic_collector collector, const resolved_statement& stmt, size_t op_position, diff --git a/parser_library/src/processing/instruction_sets/mach_processor.cpp b/parser_library/src/processing/instruction_sets/mach_processor.cpp index a6d492586..12cc6348b 100644 --- a/parser_library/src/processing/instruction_sets/mach_processor.cpp +++ b/parser_library/src/processing/instruction_sets/mach_processor.cpp @@ -17,6 +17,7 @@ #include #include "context/instruction_type.h" +#include "context/ordinary_assembly/ordinary_assembly_dependency_solver.h" #include "postponed_statement_impl.h" #include "semantics/operand_impls.h" @@ -31,9 +32,8 @@ mach_processor::mach_processor(analyzing_context ctx, void mach_processor::process(std::shared_ptr stmt) { - constexpr context::alignment mach_instr_alignment = context::halfword; auto rebuilt_stmt = preprocess(stmt); - fill_expression_loc_counters(rebuilt_stmt, mach_instr_alignment); + auto loctr = hlasm_ctx.ord_ctx.align(context::halfword); const auto& mach_instr = [](const std::string& name) { if (auto mnemonic = context::instruction::mnemonic_codes.find(name); @@ -53,35 +53,29 @@ void mach_processor::process(std::shared_ptr(op.get()); - if (evaluable) - { - if (evaluable->has_dependencies(hlasm_ctx.ord_ctx)) - { - has_dependencies = true; - break; - } - } + if (evaluable && evaluable->has_dependencies(dep_solver)) + has_dependencies = true; } if (has_dependencies) hlasm_ctx.ord_ctx.symbol_dependencies.add_dependency( - std::make_unique(std::move(rebuilt_stmt), hlasm_ctx.processing_stack())); + std::make_unique(std::move(rebuilt_stmt), hlasm_ctx.processing_stack()), + dep_solver.derive_current_dependency_evaluation_context()); else - check(rebuilt_stmt, hlasm_ctx, checker, *this); + check(rebuilt_stmt, hlasm_ctx.processing_stack(), dep_solver, checker, *this); (void)hlasm_ctx.ord_ctx.reserve_storage_area(mach_instr.size_for_alloc / 8, context::halfword); } diff --git a/parser_library/src/processing/instruction_sets/postponed_statement_impl.h b/parser_library/src/processing/instruction_sets/postponed_statement_impl.h index 4b23b8b8d..c03c4fa18 100644 --- a/parser_library/src/processing/instruction_sets/postponed_statement_impl.h +++ b/parser_library/src/processing/instruction_sets/postponed_statement_impl.h @@ -33,6 +33,8 @@ struct postponed_statement_impl : public context::postponed_statement, public re rebuilt_statement stmt; context::processing_stack_t stmt_location_stack; + const processing::resolved_statement* resolved_stmt() const override { return this; } + const semantics::label_si& label_ref() const override { return stmt.label_ref(); } const semantics::instruction_si& instruction_ref() const override { return stmt.instruction_ref(); } const semantics::operands_si& operands_ref() const override { return stmt.operands_ref(); } @@ -42,7 +44,6 @@ struct postponed_statement_impl : public context::postponed_statement, public re processing_format format_ref() const override { return stmt.format_ref(); } const context::processing_stack_t& location_stack() const override { return stmt_location_stack; } - std::pair diagnostics() const override { return stmt.diagnostics(); } }; diff --git a/parser_library/src/processing/op_code.cpp b/parser_library/src/processing/op_code.cpp new file mode 100644 index 000000000..62ea0e341 --- /dev/null +++ b/parser_library/src/processing/op_code.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ + +#include "op_code.h" + +#include "context/instruction.h" + +namespace hlasm_plugin::parser_library::processing { + +inline unsigned char get_reladdr_bitmask(context::id_index id) +{ + if (!id || id->empty()) + return 0; + + if (auto p_instr = context::instruction::machine_instructions.find(*id); + p_instr != context::instruction::machine_instructions.end()) + return p_instr->second.reladdr_mask.mask(); + + if (auto p_mnemo = context::instruction::mnemonic_codes.find(*id); + p_mnemo != context::instruction::mnemonic_codes.end()) + return p_mnemo->second.reladdr_mask.mask(); + + return 0; +} + +processing_status_cache_key::processing_status_cache_key(const processing_status& s) + : form(s.first.form) + , occurence(s.first.occurence) + , is_alias(s.second.type == context::instruction_type::ASM && s.second.value && *s.second.value == "ALIAS") + , rel_addr(get_reladdr_bitmask(s.second.value)) +{} +} // namespace hlasm_plugin::parser_library::processing diff --git a/parser_library/src/processing/op_code.h b/parser_library/src/processing/op_code.h index 3b06dca10..6a30d9764 100644 --- a/parser_library/src/processing/op_code.h +++ b/parser_library/src/processing/op_code.h @@ -46,19 +46,16 @@ class processing_status_cache_key processing_form form; operand_occurence occurence; bool is_alias; + unsigned char rel_addr; public: friend bool operator==(processing_status_cache_key l, processing_status_cache_key r) { - return l.form == r.form && l.occurence == r.occurence && l.is_alias == r.is_alias; + return l.form == r.form && l.occurence == r.occurence && l.is_alias == r.is_alias && l.rel_addr == r.rel_addr; } friend bool operator!=(processing_status_cache_key l, processing_status_cache_key r) { return !(l == r); } - explicit processing_status_cache_key(const processing_status& s) - : form(s.first.form) - , occurence(s.first.occurence) - , is_alias(s.second.type == context::instruction_type::ASM && s.second.value && *s.second.value == "ALIAS") - {} + explicit processing_status_cache_key(const processing_status& s); }; } // namespace hlasm_plugin::parser_library::processing diff --git a/parser_library/src/processing/statement_analyzers/occurence_collector.cpp b/parser_library/src/processing/statement_analyzers/occurence_collector.cpp index a4d97e1b2..8b711b1fa 100644 --- a/parser_library/src/processing/statement_analyzers/occurence_collector.cpp +++ b/parser_library/src/processing/statement_analyzers/occurence_collector.cpp @@ -63,34 +63,7 @@ void occurence_collector::visit(const semantics::complex_assembler_operand&) {} void occurence_collector::visit(const semantics::string_assembler_operand&) {} -void occurence_collector::visit(const semantics::data_def_operand& op) -{ - if (op.value->dupl_factor) - op.value->dupl_factor->apply(*this); - if (op.value->program_type) - op.value->program_type->apply(*this); - if (op.value->length) - op.value->length->apply(*this); - if (op.value->scale) - op.value->scale->apply(*this); - if (op.value->exponent) - op.value->exponent->apply(*this); - - if (op.value->nominal_value && op.value->nominal_value->access_exprs()) - { - for (const auto& val : op.value->nominal_value->access_exprs()->exprs) - { - if (std::holds_alternative(val)) - std::get(val)->apply(*this); - else - { - const auto& addr = std::get(val); - addr.base->apply(*this); - addr.displacement->apply(*this); - } - } - } -} +void occurence_collector::visit(const semantics::data_def_operand& op) { op.value->apply(*this); } void occurence_collector::visit(const semantics::var_ca_operand& op) { get_occurence(*op.variable_symbol); } @@ -163,6 +136,13 @@ void occurence_collector::get_occurence(const semantics::concat_chain& chain) } } } +void occurence_collector::get_occurence(const expressions::ca_literal_def& lit) +{ + if (collector_kind == lsp::occurence_kind::ORD) + { + lit.dd->apply(*this); + } +} void occurence_collector::visit(const expressions::mach_expr_constant&) {} @@ -182,6 +162,8 @@ void occurence_collector::visit(const expressions::mach_expr_self_def&) {} void occurence_collector::visit(const expressions::mach_expr_default&) {} +void occurence_collector::visit(const expressions::mach_expr_literal& lit) { lit.get_data_definition().apply(*this); } + void occurence_collector::visit(const expressions::ca_constant&) {} void occurence_collector::visit(const expressions::ca_expr_list& expr) @@ -210,8 +192,10 @@ void occurence_collector::visit(const expressions::ca_symbol_attribute& expr) { if (std::holds_alternative(expr.symbol)) get_occurence(std::get(expr.symbol), expr.symbol_range); - else + else if (std::holds_alternative(expr.symbol)) get_occurence(*std::get(expr.symbol)); + else if (std::holds_alternative(expr.symbol)) + get_occurence(std::get(expr.symbol)); } void occurence_collector::visit(const expressions::ca_var_sym& expr) { get_occurence(*expr.symbol); } diff --git a/parser_library/src/processing/statement_analyzers/occurence_collector.h b/parser_library/src/processing/statement_analyzers/occurence_collector.h index 98a598804..03f1e9c12 100644 --- a/parser_library/src/processing/statement_analyzers/occurence_collector.h +++ b/parser_library/src/processing/statement_analyzers/occurence_collector.h @@ -55,6 +55,7 @@ class occurence_collector : public semantics::operand_visitor, void get_occurence(const semantics::seq_sym& seq); void get_occurence(context::id_index ord, const range& ord_range); void get_occurence(const semantics::concat_chain& chain); + void get_occurence(const expressions::ca_literal_def& var); private: void visit(const expressions::mach_expr_constant& expr) override; @@ -63,6 +64,7 @@ class occurence_collector : public semantics::operand_visitor, void visit(const expressions::mach_expr_location_counter& expr) override; void visit(const expressions::mach_expr_self_def& expr) override; void visit(const expressions::mach_expr_default& expr) override; + void visit(const expressions::mach_expr_literal& expr) override; void visit(const expressions::ca_constant& expr) override; void visit(const expressions::ca_expr_list& expr) override; diff --git a/parser_library/src/processing/statement_processors/lookahead_processor.cpp b/parser_library/src/processing/statement_processors/lookahead_processor.cpp index 966c82cfc..4549bdbb3 100644 --- a/parser_library/src/processing/statement_processors/lookahead_processor.cpp +++ b/parser_library/src/processing/statement_processors/lookahead_processor.cpp @@ -14,6 +14,7 @@ #include "lookahead_processor.h" +#include "context/ordinary_assembly/ordinary_assembly_dependency_solver.h" #include "ebcdic_encoding.h" #include "expressions/mach_expr_term.h" #include "ordinary_processor.h" @@ -151,6 +152,7 @@ lookahead_processor::process_table_t lookahead_processor::create_table(context:: void lookahead_processor::assign_EQU_attributes(context::id_index symbol_name, const resolved_statement& statement) { + context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx); // type attribute operand context::symbol_attributes::type_attr t_attr = context::symbol_attributes::undef_type; if (statement.operands_ref().value.size() >= 3 @@ -159,9 +161,9 @@ void lookahead_processor::assign_EQU_attributes(context::id_index symbol_name, c auto asm_op = statement.operands_ref().value[2]->access_asm(); auto expr_op = asm_op->access_expr(); - if (expr_op && !expr_op->has_error(hlasm_ctx.ord_ctx) && !expr_op->has_dependencies(hlasm_ctx.ord_ctx)) + if (expr_op && !expr_op->has_error(dep_solver) && !expr_op->has_dependencies(dep_solver)) { - auto t_value = expr_op->expression->resolve(hlasm_ctx.ord_ctx); + auto t_value = expr_op->expression->resolve(dep_solver); if (t_value.value_kind() == context::symbol_value_kind::ABS && t_value.get_abs() >= 0 && t_value.get_abs() <= 255) t_attr = (context::symbol_attributes::type_attr)t_value.get_abs(); @@ -176,9 +178,9 @@ void lookahead_processor::assign_EQU_attributes(context::id_index symbol_name, c auto asm_op = statement.operands_ref().value[1]->access_asm(); auto expr_op = asm_op->access_expr(); - if (expr_op && !expr_op->has_error(hlasm_ctx.ord_ctx) && !expr_op->has_dependencies(hlasm_ctx.ord_ctx)) + if (expr_op && !expr_op->has_error(dep_solver) && !expr_op->has_dependencies(dep_solver)) { - auto length_value = expr_op->expression->resolve(hlasm_ctx.ord_ctx); + auto length_value = expr_op->expression->resolve(dep_solver); if (length_value.value_kind() == context::symbol_value_kind::ABS && length_value.get_abs() >= 0 && length_value.get_abs() <= 65535) length_attr = (context::symbol_attributes::len_attr)length_value.get_abs(); @@ -234,14 +236,15 @@ void lookahead_processor::assign_data_def_attributes(context::id_index symbol_na context::symbol_attributes::len_attr len = context::symbol_attributes::undef_length; context::symbol_attributes::scale_attr scale = context::symbol_attributes::undef_scale; - auto tmp = data_op->get_operand_value(hlasm_ctx.ord_ctx); + context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx); + auto tmp = data_op->get_operand_value(dep_solver); auto& value = dynamic_cast(*tmp); - if (!data_op->value->length || !data_op->value->length->get_dependencies(hlasm_ctx.ord_ctx).contains_dependencies()) + if (!data_op->value->length || !data_op->value->length->get_dependencies(dep_solver).contains_dependencies()) { len = value.get_length_attribute(); } - if (data_op->value->scale && !data_op->value->scale->get_dependencies(hlasm_ctx.ord_ctx).contains_dependencies()) + if (data_op->value->scale && !data_op->value->scale->get_dependencies(dep_solver).contains_dependencies()) { scale = value.get_scale_attribute(); } diff --git a/parser_library/src/processing/statement_processors/ordinary_processor.cpp b/parser_library/src/processing/statement_processors/ordinary_processor.cpp index c4137d87a..2283f7cb3 100644 --- a/parser_library/src/processing/statement_processors/ordinary_processor.cpp +++ b/parser_library/src/processing/statement_processors/ordinary_processor.cpp @@ -17,6 +17,8 @@ #include #include "checking/instruction_checker.h" +#include "context/literal_pool.h" +#include "context/ordinary_assembly/ordinary_assembly_dependency_solver.h" #include "ebcdic_encoding.h" #include "processing/instruction_sets/postponed_statement_impl.h" @@ -123,6 +125,17 @@ void ordinary_processor::process_statement(context::shared_stmt_ptr s) void ordinary_processor::end_processing() { + if (hlasm_ctx.ord_ctx.literals().get_pending_count()) + { + auto ltorg = hlasm_ctx.ord_ctx.implicit_ltorg_target(); + hlasm_ctx.ord_ctx.set_location_counter(ltorg->name, {}); + hlasm_ctx.ord_ctx.set_available_location_counter_value(0, 0); + + context::ordinary_assembly_dependency_solver dep_solver( + hlasm_ctx.ord_ctx, context::ordinary_assembly_dependency_solver::no_new_literals {}); + hlasm_ctx.ord_ctx.generate_pool(dep_solver, *this); + } + hlasm_ctx.ord_ctx.symbol_dependencies.add_defined(&asm_proc_); hlasm_ctx.ord_ctx.finish_module_layout(&asm_proc_); @@ -222,24 +235,34 @@ void ordinary_processor::collect_diags() const collect_diags_from_child(eval_ctx); } -void ordinary_processor::check_postponed_statements(std::vector stmts) +void ordinary_processor::check_postponed_statements( + const std::vector>& stmts) { - checking::assembler_checker asm_checker; - checking::machine_checker mach_checker; + static const checking::assembler_checker asm_checker; + static const checking::machine_checker mach_checker; - for (auto& stmt : stmts) + for (const auto& [stmt, dep_ctx] : stmts) { if (!stmt) continue; + context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx, dep_ctx); - assert(stmt->impl()->opcode_ref().type == context::instruction_type::ASM - || stmt->impl()->opcode_ref().type == context::instruction_type::MACH); + const auto* rs = stmt->resolved_stmt(); + switch (rs->opcode_ref().type) + { + case hlasm_plugin::parser_library::context::instruction_type::MACH: + low_language_processor::check(*rs, stmt->location_stack(), dep_solver, mach_checker, *this); + break; - if (stmt->impl()->opcode_ref().type == context::instruction_type::ASM) - low_language_processor::check(*stmt->impl(), hlasm_ctx, asm_checker, *this); - else - low_language_processor::check(*stmt->impl(), hlasm_ctx, mach_checker, *this); + case hlasm_plugin::parser_library::context::instruction_type::ASM: + low_language_processor::check(*rs, stmt->location_stack(), dep_solver, asm_checker, *this); + break; + + default: + assert(false); + break; + } } } diff --git a/parser_library/src/processing/statement_processors/ordinary_processor.h b/parser_library/src/processing/statement_processors/ordinary_processor.h index 8d8ece12d..7ad6a7aca 100644 --- a/parser_library/src/processing/statement_processors/ordinary_processor.h +++ b/parser_library/src/processing/statement_processors/ordinary_processor.h @@ -63,7 +63,8 @@ class ordinary_processor : public statement_processor void collect_diags() const override; private: - void check_postponed_statements(std::vector stmts); + void check_postponed_statements( + const std::vector>& stmts); bool check_fatals(range line_range); context::id_index resolve_instruction(const semantics::concat_chain& chain, range instruction_range) const; diff --git a/parser_library/src/semantics/operand_impls.cpp b/parser_library/src/semantics/operand_impls.cpp index 85ce4905a..a49729a6e 100644 --- a/parser_library/src/semantics/operand_impls.cpp +++ b/parser_library/src/semantics/operand_impls.cpp @@ -14,9 +14,12 @@ #include "operand_impls.h" +#include + #include "context/instruction.h" #include "expressions/conditional_assembly/terms/ca_var_sym.h" #include "expressions/mach_expr_term.h" +#include "expressions/mach_expr_visitor.h" #include "expressions/mach_operator.h" #include "operand_visitor.h" @@ -84,7 +87,7 @@ address_machine_operand* machine_operand::access_address() } std::unique_ptr make_check_operand( - expressions::mach_evaluate_info info, const expressions::mach_expression& expr) + context::dependency_solver& info, const expressions::mach_expression& expr) { auto res = expr.evaluate(info); if (res.value_kind() == context::symbol_value_kind::ABS) @@ -99,7 +102,7 @@ std::unique_ptr make_check_operand( } std::unique_ptr make_rel_imm_operand( - expressions::mach_evaluate_info info, const expressions::mach_expression& expr) + context::dependency_solver& info, const expressions::mach_expression& expr) { auto res = expr.evaluate(info); if (res.value_kind() == context::symbol_value_kind::ABS) @@ -120,13 +123,13 @@ expr_machine_operand::expr_machine_operand(expressions::mach_expr_ptr expression , simple_expr_operand(std::move(expression)) {} -std::unique_ptr expr_machine_operand::get_operand_value(expressions::mach_evaluate_info info) const +std::unique_ptr expr_machine_operand::get_operand_value(context::dependency_solver& info) const { return make_check_operand(info, *expression); } std::unique_ptr expr_machine_operand::get_operand_value( - expressions::mach_evaluate_info info, checking::machine_operand_type type_hint) const + context::dependency_solver& info, checking::machine_operand_type type_hint) const { if (type_hint == checking::machine_operand_type::RELOC_IMM) { @@ -136,13 +139,13 @@ std::unique_ptr expr_machine_operand::get_operand_value( } // suppress MSVC warning 'inherits via dominance' -bool expr_machine_operand::has_dependencies(expressions::mach_evaluate_info info) const +bool expr_machine_operand::has_dependencies(context::dependency_solver& info) const { return simple_expr_operand::has_dependencies(info); } // suppress MSVC warning 'inherits via dominance' -bool expr_machine_operand::has_error(expressions::mach_evaluate_info info) const +bool expr_machine_operand::has_error(context::dependency_solver& info) const { return simple_expr_operand::has_error(info); } @@ -166,7 +169,7 @@ address_machine_operand::address_machine_operand(expressions::mach_expr_ptr disp , state(std::move(state)) {} -bool address_machine_operand::has_dependencies(expressions::mach_evaluate_info info) const +bool address_machine_operand::has_dependencies(context::dependency_solver& info) const { if (first_par) { @@ -183,7 +186,7 @@ bool address_machine_operand::has_dependencies(expressions::mach_evaluate_info i || second_par->get_dependencies(info).contains_dependencies(); // D(,B) } -bool address_machine_operand::has_error(expressions::mach_evaluate_info info) const +bool address_machine_operand::has_error(context::dependency_solver& info) const { if (first_par) { @@ -198,8 +201,7 @@ bool address_machine_operand::has_error(expressions::mach_evaluate_info info) co return displacement->get_dependencies(info).has_error || second_par->get_dependencies(info).has_error; // D(,B) } -std::unique_ptr address_machine_operand::get_operand_value( - expressions::mach_evaluate_info info) const +std::unique_ptr address_machine_operand::get_operand_value(context::dependency_solver& info) const { context::symbol_value displ, first, second; context::symbol_value::abs_value_t displ_v, first_v, second_v; @@ -230,7 +232,7 @@ std::unique_ptr address_machine_operand::get_operand_value( } std::unique_ptr address_machine_operand::get_operand_value( - expressions::mach_evaluate_info info, checking::machine_operand_type) const + context::dependency_solver& info, checking::machine_operand_type) const { return get_operand_value(info); } @@ -280,19 +282,19 @@ expr_assembler_operand::expr_assembler_operand( , value_(std::move(string_value)) {} -std::unique_ptr expr_assembler_operand::get_operand_value(expressions::mach_evaluate_info info) const +std::unique_ptr expr_assembler_operand::get_operand_value(context::dependency_solver& info) const { return get_operand_value_inner(info, true); } std::unique_ptr expr_assembler_operand::get_operand_value( - expressions::mach_evaluate_info info, bool can_have_ordsym) const + context::dependency_solver& info, bool can_have_ordsym) const { return get_operand_value_inner(info, can_have_ordsym); } std::unique_ptr expr_assembler_operand::get_operand_value_inner( - expressions::mach_evaluate_info info, bool can_have_ordsym) const + context::dependency_solver& info, bool can_have_ordsym) const { if (!can_have_ordsym && dynamic_cast(expression.get())) return std::make_unique(value_); @@ -313,13 +315,13 @@ std::unique_ptr expr_assembler_operand::get_operand_value_inn } // suppress MSVC warning 'inherits via dominance' -bool expr_assembler_operand::has_dependencies(expressions::mach_evaluate_info info) const +bool expr_assembler_operand::has_dependencies(context::dependency_solver& info) const { return simple_expr_operand::has_dependencies(info); } // suppress MSVC warning 'inherits via dominance' -bool expr_assembler_operand::has_error(expressions::mach_evaluate_info info) const +bool expr_assembler_operand::has_error(context::dependency_solver& info) const { return simple_expr_operand::has_error(info); } @@ -338,18 +340,18 @@ using_instr_assembler_operand::using_instr_assembler_operand( , end(std::move(end)) {} -bool using_instr_assembler_operand::has_dependencies(expressions::mach_evaluate_info info) const +bool using_instr_assembler_operand::has_dependencies(context::dependency_solver& info) const { return base->get_dependencies(info).contains_dependencies() || end->get_dependencies(info).contains_dependencies(); } -bool using_instr_assembler_operand::has_error(expressions::mach_evaluate_info info) const +bool using_instr_assembler_operand::has_error(context::dependency_solver& info) const { return base->get_dependencies(info).has_error || end->get_dependencies(info).has_error; } std::unique_ptr using_instr_assembler_operand::get_operand_value( - expressions::mach_evaluate_info info) const + context::dependency_solver& info) const { (void)info; std::vector> pair; @@ -374,11 +376,11 @@ complex_assembler_operand::complex_assembler_operand( , value(std::move(identifier), std::move(values), std::move(operand_range)) {} -bool complex_assembler_operand::has_dependencies(expressions::mach_evaluate_info) const { return false; } +bool complex_assembler_operand::has_dependencies(context::dependency_solver&) const { return false; } -bool complex_assembler_operand::has_error(expressions::mach_evaluate_info) const { return false; } +bool complex_assembler_operand::has_error(context::dependency_solver&) const { return false; } -std::unique_ptr complex_assembler_operand::get_operand_value(expressions::mach_evaluate_info) const +std::unique_ptr complex_assembler_operand::get_operand_value(context::dependency_solver&) const { return value.create_operand(); } @@ -441,12 +443,12 @@ simple_expr_operand::simple_expr_operand(expressions::mach_expr_ptr expression) {} -[[nodiscard]] bool simple_expr_operand::has_dependencies(expressions::mach_evaluate_info info) const +[[nodiscard]] bool simple_expr_operand::has_dependencies(context::dependency_solver& info) const { return expression->get_dependencies(info).contains_dependencies(); } -[[nodiscard]] bool simple_expr_operand::has_error(expressions::mach_evaluate_info info) const +[[nodiscard]] bool simple_expr_operand::has_error(context::dependency_solver& info) const { return expression->get_dependencies(info).has_error; } @@ -519,23 +521,28 @@ data_def_operand::data_def_operand(expressions::data_definition val, range opera , value(std::make_shared(std::move(val))) {} +data_def_operand::data_def_operand(std::shared_ptr dd_ptr, range operand_range) + : evaluable_operand(operand_type::DAT, std::move(operand_range)) + , value(std::move(dd_ptr)) +{} + -context::dependency_collector data_def_operand::get_length_dependencies(expressions::mach_evaluate_info info) const +context::dependency_collector data_def_operand::get_length_dependencies(context::dependency_solver& info) const { return value->get_length_dependencies(info); } -context::dependency_collector data_def_operand::get_dependencies(expressions::mach_evaluate_info info) const +context::dependency_collector data_def_operand::get_dependencies(context::dependency_solver& info) const { return value->get_dependencies(info); } -bool data_def_operand::has_dependencies(expressions::mach_evaluate_info info) const +bool data_def_operand::has_dependencies(context::dependency_solver& info) const { return value->get_dependencies(info).contains_dependencies(); } -bool data_def_operand::has_error(expressions::mach_evaluate_info info) const +bool data_def_operand::has_error(context::dependency_solver& info) const { return value->get_dependencies(info).has_error; } @@ -553,21 +560,28 @@ std::vector resolvable_list(const args&... expr) return list; } -std::unique_ptr data_def_operand::get_operand_value(expressions::mach_evaluate_info info) const +std::unique_ptr data_def_operand::get_operand_value(context::dependency_solver& info) const { - auto op = std::make_unique(); + return std::make_unique(get_operand_value(*value, info)); +} + +checking::data_definition_operand data_def_operand::get_operand_value( + const expressions::data_definition& dd, context::dependency_solver& info) +{ + checking::data_definition_operand op; - op->dupl_factor = value->evaluate_dupl_factor(info); - op->type.value = value->type; - op->type.rng = value->type_range; - op->extension.present = value->extension != '\0'; - op->extension.value = value->extension; - op->extension.rng = value->extension_range; - op->length = value->evaluate_length(info); - op->scale = value->evaluate_scale(info); - op->exponent = value->evaluate_exponent(info); + op.dupl_factor = dd.evaluate_dupl_factor(info); + op.type.value = dd.type; + op.type.rng = dd.type_range; + op.extension.present = dd.extension != '\0'; + op.extension.value = dd.extension; + op.extension.rng = dd.extension_range; + op.length = dd.evaluate_length(info); + op.scale = dd.evaluate_scale(info); + op.exponent = dd.evaluate_exponent(info); + + op.nominal_value = dd.evaluate_nominal_value(info); - op->nominal_value = value->evaluate_nominal_value(info); return op; } @@ -581,11 +595,11 @@ string_assembler_operand::string_assembler_operand(std::string value, range oper , value(std::move(value)) {} -bool string_assembler_operand::has_dependencies(expressions::mach_evaluate_info) const { return false; } +bool string_assembler_operand::has_dependencies(context::dependency_solver&) const { return false; } -bool string_assembler_operand::has_error(expressions::mach_evaluate_info) const { return false; } +bool string_assembler_operand::has_error(context::dependency_solver&) const { return false; } -std::unique_ptr string_assembler_operand::get_operand_value(expressions::mach_evaluate_info) const +std::unique_ptr string_assembler_operand::get_operand_value(context::dependency_solver&) const { return std::make_unique("'" + value + "'"); } @@ -650,49 +664,47 @@ join_operands_result join_operands(const operand_list& operands) return result; } +struct request_halfword_alignment final : public expressions::mach_expr_visitor +{ + // Inherited via mach_expr_visitor + void visit(const expressions::mach_expr_constant&) override {} + void visit(const expressions::mach_expr_data_attr&) override {} + void visit(const expressions::mach_expr_symbol&) override {} + void visit(const expressions::mach_expr_location_counter&) override {} + void visit(const expressions::mach_expr_self_def&) override {} + void visit(const expressions::mach_expr_default&) override {} + void visit(const expressions::mach_expr_literal& expr) override { expr.referenced_by_reladdr(); } +}; + void transform_reloc_imm_operands(semantics::operand_list& op_list, context::id_index instruction) { if (instruction->empty()) return; - const context::machine_instruction* instr; - const std::pair* replaced_b = nullptr; - const std::pair* replaced_e = nullptr; + unsigned char mask = 0; + decltype(mask) top_bit = 1 << (std::numeric_limits::digits - 1); if (auto mnem_tmp = context::instruction::mnemonic_codes.find(*instruction); mnem_tmp != context::instruction::mnemonic_codes.end()) - { - const auto& mnemonic = mnem_tmp->second; - instr = mnemonic.instruction; - replaced_b = mnemonic.replaced.data(); - replaced_e = replaced_b + mnemonic.replaced.size(); - } + mask = mnem_tmp->second.reladdr_mask.mask(); else - { - instr = &context::instruction::machine_instructions.at(*instruction); - } + mask = context::instruction::machine_instructions.at(*instruction).reladdr_mask.mask(); - size_t position = 0; for (const auto& operand : op_list) { - while (replaced_b != replaced_e) - { - const auto index = replaced_b->first; - if (position < index) - break; - if (position++ == index) - ++replaced_b; - } - - if (position >= instr->operands.size()) - break; + bool eligible = mask & top_bit; + top_bit >>= 1; - if (instr->operands[position++].identifier.type != checking::machine_operand_type::RELOC_IMM) + if (!eligible) continue; if (auto* mach_op = operand->access_mach(); mach_op != nullptr && mach_op->kind == mach_kind::EXPR) { auto& mach_expr = mach_op->access_expr()->expression; + + request_halfword_alignment visitor; + mach_expr->apply(visitor); + auto range = mach_expr->get_range(); mach_expr = std::make_unique>( std::make_unique(range), std::move(mach_expr), range); diff --git a/parser_library/src/semantics/operand_impls.h b/parser_library/src/semantics/operand_impls.h index a6ef72a76..a2ffc41cd 100644 --- a/parser_library/src/semantics/operand_impls.h +++ b/parser_library/src/semantics/operand_impls.h @@ -55,11 +55,11 @@ struct evaluable_operand : operand, diagnosable_op_impl { evaluable_operand(const operand_type type, const range operand_range); - virtual bool has_dependencies(expressions::mach_evaluate_info info) const = 0; + virtual bool has_dependencies(context::dependency_solver& info) const = 0; - virtual bool has_error(expressions::mach_evaluate_info info) const = 0; + virtual bool has_error(context::dependency_solver& info) const = 0; - virtual std::unique_ptr get_operand_value(expressions::mach_evaluate_info info) const = 0; + virtual std::unique_ptr get_operand_value(context::dependency_solver& info) const = 0; }; @@ -69,9 +69,9 @@ struct simple_expr_operand : virtual evaluable_operand { simple_expr_operand(expressions::mach_expr_ptr expression); - bool has_dependencies(expressions::mach_evaluate_info info) const override; + bool has_dependencies(context::dependency_solver& info) const override; - bool has_error(expressions::mach_evaluate_info info) const override; + bool has_error(context::dependency_solver& info) const override; expressions::mach_expr_ptr expression; }; @@ -95,7 +95,7 @@ struct machine_operand : virtual evaluable_operand using evaluable_operand::get_operand_value; virtual std::unique_ptr get_operand_value( - expressions::mach_evaluate_info info, checking::machine_operand_type type_hint) const = 0; + context::dependency_solver& info, checking::machine_operand_type type_hint) const = 0; const mach_kind kind; }; @@ -107,12 +107,12 @@ struct expr_machine_operand final : machine_operand, simple_expr_operand { expr_machine_operand(expressions::mach_expr_ptr expression, const range operand_range); - std::unique_ptr get_operand_value(expressions::mach_evaluate_info info) const override; + std::unique_ptr get_operand_value(context::dependency_solver& info) const override; std::unique_ptr get_operand_value( - expressions::mach_evaluate_info info, checking::machine_operand_type type_hint) const override; + context::dependency_solver& info, checking::machine_operand_type type_hint) const override; - bool has_dependencies(expressions::mach_evaluate_info info) const override; - bool has_error(expressions::mach_evaluate_info info) const override; + bool has_dependencies(context::dependency_solver& info) const override; + bool has_error(context::dependency_solver& info) const override; void collect_diags() const override; @@ -134,13 +134,13 @@ struct address_machine_operand final : machine_operand expressions::mach_expr_ptr second_par; checking::operand_state state; - bool has_dependencies(expressions::mach_evaluate_info info) const override; + bool has_dependencies(context::dependency_solver& info) const override; - bool has_error(expressions::mach_evaluate_info info) const override; + bool has_error(context::dependency_solver& info) const override; - std::unique_ptr get_operand_value(expressions::mach_evaluate_info info) const override; + std::unique_ptr get_operand_value(context::dependency_solver& info) const override; std::unique_ptr get_operand_value( - expressions::mach_evaluate_info info, checking::machine_operand_type type_hint) const override; + context::dependency_solver& info, checking::machine_operand_type type_hint) const override; void collect_diags() const override; @@ -183,13 +183,12 @@ struct expr_assembler_operand final : assembler_operand, simple_expr_operand public: expr_assembler_operand(expressions::mach_expr_ptr expression, std::string string_value, const range operand_range); - std::unique_ptr get_operand_value(expressions::mach_evaluate_info info) const override; + std::unique_ptr get_operand_value(context::dependency_solver& info) const override; - std::unique_ptr get_operand_value( - expressions::mach_evaluate_info info, bool can_have_ordsym) const; + std::unique_ptr get_operand_value(context::dependency_solver& info, bool can_have_ordsym) const; - bool has_dependencies(expressions::mach_evaluate_info info) const override; - bool has_error(expressions::mach_evaluate_info info) const override; + bool has_dependencies(context::dependency_solver& info) const override; + bool has_error(context::dependency_solver& info) const override; void collect_diags() const override; @@ -197,7 +196,7 @@ struct expr_assembler_operand final : assembler_operand, simple_expr_operand private: std::unique_ptr get_operand_value_inner( - expressions::mach_evaluate_info info, bool can_have_ordsym) const; + context::dependency_solver& info, bool can_have_ordsym) const; }; @@ -208,11 +207,11 @@ struct using_instr_assembler_operand final : assembler_operand using_instr_assembler_operand( expressions::mach_expr_ptr base, expressions::mach_expr_ptr end, const range operand_range); - bool has_dependencies(expressions::mach_evaluate_info info) const override; + bool has_dependencies(context::dependency_solver& info) const override; - bool has_error(expressions::mach_evaluate_info info) const override; + bool has_error(context::dependency_solver& info) const override; - std::unique_ptr get_operand_value(expressions::mach_evaluate_info info) const override; + std::unique_ptr get_operand_value(context::dependency_solver& info) const override; expressions::mach_expr_ptr base; expressions::mach_expr_ptr end; @@ -289,11 +288,11 @@ struct complex_assembler_operand final : assembler_operand complex_assembler_operand( std::string identifier, std::vector> values, const range operand_range); - bool has_dependencies(expressions::mach_evaluate_info info) const override; + bool has_dependencies(context::dependency_solver& info) const override; - bool has_error(expressions::mach_evaluate_info info) const override; + bool has_error(context::dependency_solver& info) const override; - std::unique_ptr get_operand_value(expressions::mach_evaluate_info info) const override; + std::unique_ptr get_operand_value(context::dependency_solver& info) const override; composite_value_t value; @@ -309,11 +308,11 @@ struct string_assembler_operand : assembler_operand { string_assembler_operand(std::string value, const range operand_range); - bool has_dependencies(expressions::mach_evaluate_info info) const override; + bool has_dependencies(context::dependency_solver& info) const override; - bool has_error(expressions::mach_evaluate_info info) const override; + bool has_error(context::dependency_solver& info) const override; - std::unique_ptr get_operand_value(expressions::mach_evaluate_info info) const override; + std::unique_ptr get_operand_value(context::dependency_solver& info) const override; std::string value; @@ -326,18 +325,21 @@ struct string_assembler_operand : assembler_operand struct data_def_operand final : evaluable_operand { data_def_operand(expressions::data_definition data_def, const range operand_range); + data_def_operand(std::shared_ptr dd_ptr, const range operand_range); - std::shared_ptr value; + std::shared_ptr value; - context::dependency_collector get_length_dependencies(expressions::mach_evaluate_info info) const; + context::dependency_collector get_length_dependencies(context::dependency_solver& info) const; - context::dependency_collector get_dependencies(expressions::mach_evaluate_info info) const; + context::dependency_collector get_dependencies(context::dependency_solver& info) const; - bool has_dependencies(expressions::mach_evaluate_info info) const override; + bool has_dependencies(context::dependency_solver& info) const override; - bool has_error(expressions::mach_evaluate_info info) const override; + bool has_error(context::dependency_solver& info) const override; - std::unique_ptr get_operand_value(expressions::mach_evaluate_info info) const override; + std::unique_ptr get_operand_value(context::dependency_solver& info) const override; + static checking::data_definition_operand get_operand_value( + const expressions::data_definition& dd, context::dependency_solver& info); void collect_diags() const override; diff --git a/parser_library/src/workspaces/processor_file_impl.cpp b/parser_library/src/workspaces/processor_file_impl.cpp index 6fe695f3f..2ebb0d02d 100644 --- a/parser_library/src/workspaces/processor_file_impl.cpp +++ b/parser_library/src/workspaces/processor_file_impl.cpp @@ -157,7 +157,7 @@ class empty_feature_provider final : public lsp::feature_provider { return {}; } - lsp::document_symbol_list_s document_symbol(const std::string&, long long limit) const override { return {}; } + lsp::document_symbol_list_s document_symbol(const std::string&, long long) const override { return {}; } }; } // namespace diff --git a/parser_library/test/checking/data_definition/data_definition_check_test.cpp b/parser_library/test/checking/data_definition/data_definition_check_test.cpp index c6efae48c..bb9bc8878 100644 --- a/parser_library/test/checking/data_definition/data_definition_check_test.cpp +++ b/parser_library/test/checking/data_definition/data_definition_check_test.cpp @@ -66,7 +66,7 @@ TEST(data_def_checker, unknown_extension_analyzer) a.collect_diags(); ASSERT_EQ(a.diags().size(), 1U); - EXPECT_EQ(a.diags()[0].code, "D013"); + EXPECT_EQ(a.diags()[0].code, "D006"); } TEST(data_def_checker, unexpected_expr) diff --git a/parser_library/test/checking/data_definition/data_definition_length_test.cpp b/parser_library/test/checking/data_definition/data_definition_length_test.cpp index 6dcf28112..4cc55bb4b 100644 --- a/parser_library/test/checking/data_definition/data_definition_length_test.cpp +++ b/parser_library/test/checking/data_definition/data_definition_length_test.cpp @@ -12,6 +12,7 @@ * Broadcom, Inc. - initial API and implementation */ +#include "context/ordinary_assembly/ordinary_assembly_dependency_solver.h" #include "data_definition_common.h" #include "expressions/data_definition.h" #include "processing/instruction_sets/data_def_postponed_statement.h" @@ -35,8 +36,9 @@ TEST(data_def_operands_length, all_bit_len) list.push_back(data_def_op_from_string("BL.6'101'")); context::hlasm_context ctx; + context::ordinary_assembly_dependency_solver dep_solver(ctx.ord_ctx); - EXPECT_EQ(processing::data_def_postponed_statement::get_operands_length(list, ctx.ord_ctx), 2); + EXPECT_EQ(processing::data_def_postponed_statement::get_operands_length(list, dep_solver), 2); } TEST(data_def_operands_length, byte_in_middle_len) @@ -46,8 +48,9 @@ TEST(data_def_operands_length, byte_in_middle_len) list.push_back(data_def_op_from_string("A(1)")); list.push_back(data_def_op_from_string("BL.6'101'")); context::hlasm_context ctx; + context::ordinary_assembly_dependency_solver dep_solver(ctx.ord_ctx); - EXPECT_EQ(processing::data_def_postponed_statement::get_operands_length(list, ctx.ord_ctx), 9); + EXPECT_EQ(processing::data_def_postponed_statement::get_operands_length(list, dep_solver), 9); } TEST(data_def_operands_length, explicit_byte) @@ -57,9 +60,9 @@ TEST(data_def_operands_length, explicit_byte) list.push_back(data_def_op_from_string("AL4(1)")); list.push_back(data_def_op_from_string("C'101'")); context::hlasm_context ctx; + context::ordinary_assembly_dependency_solver dep_solver(ctx.ord_ctx); - EXPECT_EQ( - processing::data_def_postponed_statement::get_operands_length(list, ctx.ord_ctx), 12); + EXPECT_EQ(processing::data_def_postponed_statement::get_operands_length(list, dep_solver), 12); } diff --git a/parser_library/test/checking/data_definition/data_definition_test.cpp b/parser_library/test/checking/data_definition/data_definition_test.cpp index 457bfd3e0..68cfc3900 100644 --- a/parser_library/test/checking/data_definition/data_definition_test.cpp +++ b/parser_library/test/checking/data_definition/data_definition_test.cpp @@ -14,6 +14,7 @@ #include "gtest/gtest.h" #include "../../common_testing.h" +#include "context/ordinary_assembly/ordinary_assembly_dependency_solver.h" void expect_no_errors(const std::string& text) { @@ -64,6 +65,7 @@ TEST(data_definition_grammar, modifiers) DC (1*8)FDP(123)L3S(2*4)E12'2.25' DC (1*8)FDP(123)L1S30E(-12*2)'2.25' DC (1*8)FDP(123)L1S30E40'2.25' + DC EE(1)'1' DC 10FDL(2*3)S(2*4)E(-12*2)'2.25' DC 10FDL2S(2*4)E(-12*2)'2.25' @@ -117,6 +119,7 @@ TEST(data_definition_grammar, modifiers_lower_case) dc (1*8)fdp(123)l3s(2*4)e12'2.25' dc (1*8)fdp(123)l1s30e(-12*2)'2.25' dc (1*8)fdp(123)l1s30e40'2.25' + dc ee(1)'1' dc 10fdl(2*3)s(2*4)e(-12*2)'2.25' dc 10fdl2s(2*4)e(-12*2)'2.25' @@ -188,7 +191,9 @@ TEST(data_definition, duplication_factor) auto parsed = std::move(res->value); EXPECT_EQ(parsed.diags().size(), (size_t)0); - auto dup_f = parsed.dupl_factor->evaluate(a.hlasm_ctx().ord_ctx).get_abs(); + context::ordinary_assembly_dependency_solver dep_solver(a.hlasm_ctx().ord_ctx); + + auto dup_f = parsed.dupl_factor->evaluate(dep_solver).get_abs(); EXPECT_EQ(dup_f, 13); } @@ -201,7 +206,9 @@ TEST(data_definition, duplication_factor_expr) auto parsed = std::move(res->value); EXPECT_EQ(parsed.diags().size(), (size_t)0); - auto dup_f = parsed.dupl_factor->evaluate(a.hlasm_ctx().ord_ctx).get_abs(); + context::ordinary_assembly_dependency_solver dep_solver(a.hlasm_ctx().ord_ctx); + + auto dup_f = parsed.dupl_factor->evaluate(dep_solver).get_abs(); EXPECT_EQ(dup_f, 26); } @@ -214,8 +221,9 @@ TEST(data_definition, duplication_factor_out_of_range) auto parsed = std::move(res->value); EXPECT_GT(parsed.diags().size(), (size_t)0); - auto dup_f = parsed.dupl_factor->evaluate(a.hlasm_ctx().ord_ctx).get_abs(); - EXPECT_EQ(dup_f, 1); + context::ordinary_assembly_dependency_solver dep_solver(a.hlasm_ctx().ord_ctx); + + EXPECT_FALSE(parsed.dupl_factor); } TEST(data_definition, duplication_factor_invalid_number) @@ -227,8 +235,9 @@ TEST(data_definition, duplication_factor_invalid_number) auto parsed = std::move(res->value); EXPECT_GT(parsed.diags().size(), (size_t)0); - auto dup_f = parsed.dupl_factor->evaluate(a.hlasm_ctx().ord_ctx).get_abs(); - EXPECT_EQ(dup_f, 1); + context::ordinary_assembly_dependency_solver dep_solver(a.hlasm_ctx().ord_ctx); + + EXPECT_FALSE(parsed.dupl_factor); } TEST(data_definition, all_fields) @@ -240,14 +249,16 @@ TEST(data_definition, all_fields) auto parsed = std::move(res->value); EXPECT_EQ(parsed.diags().size(), (size_t)0); - auto dup_f = parsed.dupl_factor->evaluate(a.hlasm_ctx().ord_ctx).get_abs(); + context::ordinary_assembly_dependency_solver dep_solver(a.hlasm_ctx().ord_ctx); + + auto dup_f = parsed.dupl_factor->evaluate(dep_solver).get_abs(); EXPECT_EQ(dup_f, 8); - EXPECT_EQ(parsed.program_type->evaluate(a.hlasm_ctx().ord_ctx).get_abs(), 123); - EXPECT_EQ(parsed.length->evaluate(a.hlasm_ctx().ord_ctx).get_abs(), 2); + EXPECT_EQ(parsed.program_type->evaluate(dep_solver).get_abs(), 123); + EXPECT_EQ(parsed.length->evaluate(dep_solver).get_abs(), 2); EXPECT_EQ(parsed.length_type, expressions::data_definition::length_type::BYTE); - EXPECT_EQ(parsed.scale->evaluate(a.hlasm_ctx().ord_ctx).get_abs(), 8); - EXPECT_EQ(parsed.exponent->evaluate(a.hlasm_ctx().ord_ctx).get_abs(), -24); + EXPECT_EQ(parsed.scale->evaluate(dep_solver).get_abs(), 8); + EXPECT_EQ(parsed.exponent->evaluate(dep_solver).get_abs(), -24); ASSERT_NE(parsed.nominal_value->access_string(), nullptr); EXPECT_EQ(parsed.nominal_value->access_string()->value, "2.25"); } @@ -261,9 +272,11 @@ TEST(data_definition, no_nominal) auto parsed = std::move(res->value); EXPECT_EQ(parsed.diags().size(), (size_t)0); - EXPECT_EQ(parsed.dupl_factor->evaluate(a.hlasm_ctx().ord_ctx).get_abs(), 0); + context::ordinary_assembly_dependency_solver dep_solver(a.hlasm_ctx().ord_ctx); + + EXPECT_EQ(parsed.dupl_factor->evaluate(dep_solver).get_abs(), 0); EXPECT_EQ(parsed.program_type, nullptr); - EXPECT_EQ(parsed.length->evaluate(a.hlasm_ctx().ord_ctx).get_abs(), 2); + EXPECT_EQ(parsed.length->evaluate(dep_solver).get_abs(), 2); EXPECT_EQ(parsed.length_type, expressions::data_definition::length_type::BYTE); EXPECT_EQ(parsed.scale, nullptr); EXPECT_EQ(parsed.exponent, nullptr); @@ -279,9 +292,11 @@ TEST(data_definition, no_nominal_expr) auto parsed = std::move(res->value); EXPECT_EQ(parsed.diags().size(), (size_t)0); - EXPECT_EQ(parsed.dupl_factor->evaluate(a.hlasm_ctx().ord_ctx).get_abs(), 0); + context::ordinary_assembly_dependency_solver dep_solver(a.hlasm_ctx().ord_ctx); + + EXPECT_EQ(parsed.dupl_factor->evaluate(dep_solver).get_abs(), 0); EXPECT_EQ(parsed.program_type, nullptr); - EXPECT_EQ(parsed.length->evaluate(a.hlasm_ctx().ord_ctx).get_abs(), 4); + EXPECT_EQ(parsed.length->evaluate(dep_solver).get_abs(), 4); EXPECT_EQ(parsed.length_type, expressions::data_definition::length_type::BYTE); EXPECT_EQ(parsed.scale, nullptr); EXPECT_EQ(parsed.exponent, nullptr); @@ -297,13 +312,15 @@ TEST(data_definition, bit_length) auto parsed = std::move(res->value); EXPECT_EQ(parsed.diags().size(), (size_t)0); - EXPECT_EQ(parsed.dupl_factor->evaluate(a.hlasm_ctx().ord_ctx).get_abs(), 8); + context::ordinary_assembly_dependency_solver dep_solver(a.hlasm_ctx().ord_ctx); + + EXPECT_EQ(parsed.dupl_factor->evaluate(dep_solver).get_abs(), 8); - EXPECT_EQ(parsed.program_type->evaluate(a.hlasm_ctx().ord_ctx).get_abs(), 123); - EXPECT_EQ(parsed.length->evaluate(a.hlasm_ctx().ord_ctx).get_abs(), 2); + EXPECT_EQ(parsed.program_type->evaluate(dep_solver).get_abs(), 123); + EXPECT_EQ(parsed.length->evaluate(dep_solver).get_abs(), 2); EXPECT_EQ(parsed.length_type, expressions::data_definition::length_type::BIT); - EXPECT_EQ(parsed.scale->evaluate(a.hlasm_ctx().ord_ctx).get_abs(), -8); - EXPECT_EQ(parsed.exponent->evaluate(a.hlasm_ctx().ord_ctx).get_abs(), -24); + EXPECT_EQ(parsed.scale->evaluate(dep_solver).get_abs(), -8); + EXPECT_EQ(parsed.exponent->evaluate(dep_solver).get_abs(), -24); ASSERT_NE(parsed.nominal_value->access_string(), nullptr); EXPECT_EQ(parsed.nominal_value->access_string()->value, "2.25"); } @@ -317,13 +334,15 @@ TEST(data_definition, unexpected_dot) auto parsed = std::move(res->value); EXPECT_GT(parsed.diags().size(), (size_t)0); - EXPECT_EQ(parsed.dupl_factor->evaluate(a.hlasm_ctx().ord_ctx).get_abs(), 8); + context::ordinary_assembly_dependency_solver dep_solver(a.hlasm_ctx().ord_ctx); + + EXPECT_EQ(parsed.dupl_factor->evaluate(dep_solver).get_abs(), 8); EXPECT_EQ(parsed.program_type, nullptr); - EXPECT_EQ(parsed.length->evaluate(a.hlasm_ctx().ord_ctx).get_abs(), 2); + EXPECT_EQ(parsed.length->evaluate(dep_solver).get_abs(), 2); EXPECT_EQ(parsed.length_type, expressions::data_definition::length_type::BIT); - EXPECT_EQ(parsed.scale->evaluate(a.hlasm_ctx().ord_ctx).get_abs(), -8); - EXPECT_EQ(parsed.exponent->evaluate(a.hlasm_ctx().ord_ctx).get_abs(), -24); + EXPECT_EQ(parsed.scale->evaluate(dep_solver).get_abs(), -8); + EXPECT_EQ(parsed.exponent->evaluate(dep_solver).get_abs(), -24); ASSERT_NE(parsed.nominal_value->access_string(), nullptr); EXPECT_EQ(parsed.nominal_value->access_string()->value, "2.25"); } @@ -451,3 +470,58 @@ TEST(data_definition, externals_part_support) expect_errors(" EXTRN PART()"); expect_errors(" WXTRN PART()"); } + +TEST(data_definition, moving_loctr) +{ + std::string input = R"( +X DC (*-X+1)XL(*-X+1)'0',(*-X+1)F'0' +LX EQU *-X +TEST DS 0FD + DS A +B DS A +Y DC FL.(2*(*-TEST))'0',FL.(2*(*-TEST))'-1',FL.12'0' +LY EQU *-Y +Z DC 3FL(*-Z+1)'0',3FL(*-Z+1)'0' +LZ EQU *-Z +)"; + analyzer a(input); + a.analyze(); + a.collect_diags(); + EXPECT_EQ(a.diags().size(), (size_t)0); + + auto LX = a.hlasm_ctx().ord_ctx.get_symbol(a.hlasm_ctx().ids().add("LX")); + auto LY = a.hlasm_ctx().ord_ctx.get_symbol(a.hlasm_ctx().ids().add("LY")); + auto LZ = a.hlasm_ctx().ord_ctx.get_symbol(a.hlasm_ctx().ids().add("LZ")); + + ASSERT_TRUE(LX && LX->value().value_kind() == context::symbol_value_kind::ABS); + ASSERT_TRUE(LY && LY->value().value_kind() == context::symbol_value_kind::ABS); + ASSERT_TRUE(LZ && LZ->value().value_kind() == context::symbol_value_kind::ABS); + + EXPECT_EQ(LX->value().get_abs(), 24); + EXPECT_EQ(LY->value().get_abs(), 6); + EXPECT_EQ(LZ->value().get_abs(), 15); +} + +TEST(data_definition, no_loctr_ref) +{ + std::string input = "(2*2)ADL(2*2)(2*2)"; + analyzer a(input); + auto res = a.parser().data_def(); + + auto parsed = std::move(res->value); + EXPECT_EQ(parsed.diags().size(), (size_t)0); + EXPECT_FALSE(parsed.references_loctr); +} + +TEST(data_definition, loctr_ref) +{ + for (std::string input : { "(*-*)ADL(2*2)(2*2)", "(2*2)ADL(*-*)(2*2)", "(2*2)ADL(2*2)(*-*)" }) + { + analyzer a(input); + auto res = a.parser().data_def(); + + auto parsed = std::move(res->value); + EXPECT_EQ(parsed.diags().size(), (size_t)0); + EXPECT_TRUE(parsed.references_loctr); + } +} diff --git a/parser_library/test/common_testing.h b/parser_library/test/common_testing.h index 02137aa10..05338af15 100644 --- a/parser_library/test/common_testing.h +++ b/parser_library/test/common_testing.h @@ -135,4 +135,22 @@ inline bool matches_message_codes(const std::vector& d, std::initi return std::is_permutation(codes.begin(), codes.end(), m.begin(), m.end()); } +inline const section* get_section(hlasm_context& ctx, std::string name) +{ + auto sect = ctx.ids().find(std::move(name)); + if (!sect) + return nullptr; + + return ctx.ord_ctx.get_section(sect); +} + +inline const symbol* get_symbol(hlasm_context& ctx, std::string name) +{ + auto sect = ctx.ids().find(std::move(name)); + if (!sect) + return nullptr; + + return ctx.ord_ctx.get_symbol(sect); +} + #endif diff --git a/parser_library/test/context/CMakeLists.txt b/parser_library/test/context/CMakeLists.txt index 56b28291d..baf3c6669 100644 --- a/parser_library/test/context/CMakeLists.txt +++ b/parser_library/test/context/CMakeLists.txt @@ -15,6 +15,7 @@ target_sources(library_test PRIVATE context_test.cpp data_attribute_test.cpp dependency_collector_test.cpp + literals_test.cpp macro_test.cpp ord_sym_test.cpp ) diff --git a/parser_library/test/context/dependency_collector_test.cpp b/parser_library/test/context/dependency_collector_test.cpp index eee9820cd..5f7c114c6 100644 --- a/parser_library/test/context/dependency_collector_test.cpp +++ b/parser_library/test/context/dependency_collector_test.cpp @@ -15,6 +15,7 @@ #include "gtest/gtest.h" #include "../common_testing.h" +#include "context/ordinary_assembly/ordinary_assembly_dependency_solver.h" // test for // dependency_collector class @@ -50,7 +51,9 @@ TEST(dependency_collector, uresolved_addresses) std::make_unique(name2, range()), range()); - auto deps = expr.get_dependencies(ctx.ord_ctx); + context::ordinary_assembly_dependency_solver dep_solver(ctx.ord_ctx); + + auto deps = expr.get_dependencies(dep_solver); ASSERT_EQ(deps.unresolved_spaces.size(), (size_t)1); EXPECT_TRUE(deps.unresolved_spaces.find(sp) != deps.unresolved_spaces.end()); diff --git a/parser_library/test/context/literals_test.cpp b/parser_library/test/context/literals_test.cpp new file mode 100644 index 000000000..ec6f0e940 --- /dev/null +++ b/parser_library/test/context/literals_test.cpp @@ -0,0 +1,476 @@ +/* + * Copyright (c) 2021 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ + +#include "gtest/gtest.h" + +#include "../common_testing.h" +#include "context/literal_pool.h" + +// test for +// handling of literals + +TEST(literals, duplicate_when_loctr_references) +{ + std::string input = R"( + MACRO + MAC + LARL 0,=A(*) + MEND + MAC + MAC +)"; + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(a.diags().empty()); + + auto* sect = get_section(a.hlasm_ctx(), ""); + ASSERT_TRUE(sect); + EXPECT_EQ(sect->location_counters().back()->current_address().offset(), 24); +} + +TEST(literals, unique_when_no_loctr_references) +{ + std::string input = R"( + MACRO + MAC + LARL 0,=A(0) + MEND + MAC + MAC +)"; + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(a.diags().empty()); + + auto* sect = get_section(a.hlasm_ctx(), ""); + ASSERT_TRUE(sect); + EXPECT_EQ(sect->location_counters().back()->current_address().offset(), 20); +} + +TEST(literals, no_nested_literals) +{ + std::string input = R"( + LARL 0,=A(=A(0)) + DC A(=A(0)) +)"; + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(matches_message_codes(a.diags(), { "S0013", "S0013" })); +} + +TEST(literals, attribute_references_to_literals) +{ + std::string input = R"( + DC A(L'=A(0)) +A EQU L'=A(0) + LARL 0,=A(L'=A(0)) +)"; + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(a.diags().empty()); + + const auto* symbol = get_symbol(a.hlasm_ctx(), "A"); + ASSERT_TRUE(symbol); + auto symbol_value = symbol->value(); + ASSERT_EQ(symbol_value.value_kind(), context::symbol_value_kind::ABS); + EXPECT_EQ(symbol_value.get_abs(), 4); + + auto* sect = get_section(a.hlasm_ctx(), ""); + ASSERT_TRUE(sect); + EXPECT_EQ(sect->location_counters().back()->current_address().offset(), 24); +} + +TEST(literals, attribute_references_to_literals_in_ca) +{ + std::string input = R"( +&L SETA L'=FS1'0' +&D SETA D'=FS1'0' +&S SETA S'=FS1'0' +&I SETA I'=FS1'0' +&T SETC T'=FS1'0' +)"; + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(a.diags().empty()); + + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "L"), 4); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "D"), 0); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "S"), 1); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "I"), 30); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "T"), "U"); + + auto* sect = get_section(a.hlasm_ctx(), ""); + ASSERT_TRUE(sect); + EXPECT_EQ(sect->location_counters().back()->current_address().offset(), 4); +} + +TEST(literals, attribute_references_to_literals_in_ca_future) +{ + // IBM HLASM currently fails to parse the expression with parenthesis (ASMA128S), + // but the support claims it may be accepted in the future (TS007628335) + std::string input = R"( +A DC A(0) +B DC A(0) +&L SETA L'=FL(B-A)S1'0' +&D SETA D'=FL(B-A)S1'0' +&S SETA S'=FL(B-A)S1'0' +&I SETA I'=FL(B-A)S1'0' +&T SETC T'=FL(B-A)S1'0' +)"; + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(a.diags().empty()); + + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "L"), 4); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "D"), 0); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "S"), 1); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "I"), 30); + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "T"), "U"); + + auto* sect = get_section(a.hlasm_ctx(), ""); + ASSERT_TRUE(sect); + EXPECT_EQ(sect->location_counters().back()->current_address().offset(), 12); +} + +TEST(literals, ltorg) +{ + std::string input = R"( + LARL 0,=A(0) +A LTORG +B EQU *-A +)"; + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(a.diags().empty()); + + const auto* symbol = get_symbol(a.hlasm_ctx(), "B"); + ASSERT_TRUE(symbol); + auto symbol_value = symbol->value(); + ASSERT_EQ(symbol_value.value_kind(), context::symbol_value_kind::ABS); + EXPECT_EQ(symbol_value.get_abs(), 4); +} + +TEST(literals, ltorg_repeating_literals) +{ + std::string input = R"( + LARL 0,=A(0) + LARL 0,=A(0) + LTORG + LARL 0,=A(0) + LARL 0,=A(0) + LTORG + LARL 0,=A(0) + LARL 0,=A(0) + LTORG + LARL 0,=A(0) + LARL 0,=A(0) + LTORG +)"; + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(a.diags().empty()); + + auto* sect = get_section(a.hlasm_ctx(), ""); + ASSERT_TRUE(sect); + EXPECT_EQ(sect->location_counters().back()->current_address().offset(), 68); +} + +TEST(literals, similar) +{ + struct test + { + std::string l; + std::string r; + size_t size; + + std::string operator()() const { return "L:" + l + '\n' + "R:" + r + '\n' + "S:" + std::to_string(size); } + }; + for (const auto& t : { + test { "=A(0)", "=a(0)", 4 }, + test { "=A(0)", "=AL4(0)", 8 }, + test { "=A(a)", "=a(A)", 4 }, + test { "=A(A)", "=A(B)", 8 }, + test { "=A(A,B)", "=a(B,A)", 16 }, + test { "=A(A,b)", "=a(a,B)", 8 }, + test { "=F'1 2'", "=F'1 2'", 8 }, + test { "=A(0)", "=1A(0)", 8 }, + test { "=F'0'", "=A(0)", 8 }, + test { "=FD'0'", "=F'0'", 12 }, + test { "=(B-A)A(0)", "=(1)A(0)", 8 }, + test { "=A(*)", "=A(*)", 8 }, + test { "=Al4(0)", "=aL4(0)", 4 }, + }) + { + std::string input = "A EQU 1\nB EQU 2\nT1 EQU L'" + t.l + '\n' + "T2 EQU L'" + t.r; + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(a.diags().empty()); + + auto* sect = get_section(a.hlasm_ctx(), ""); + ASSERT_TRUE(sect); + EXPECT_EQ(sect->location_counters().back()->current_address().offset(), t.size) << t(); + } +} + +TEST(literals, in_machine_instructions) +{ + std::string input = R"( + MVC =A(0),=A(0) +)"; + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(a.diags().empty()); + + auto* sect = get_section(a.hlasm_ctx(), ""); + ASSERT_TRUE(sect); + EXPECT_EQ(sect->location_counters().back()->current_address().offset(), 12); +} + +TEST(literals, strange_literals) +{ + std::string input = R"( +&ENDL SETC X2C('0D25') + MVC 0,=C'&ENDL' +)"; + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(a.diags().empty()); +} + +TEST(literals, missing_label_in_literal) +{ + std::string input = R"( + LARL 0,=A(LABEL) +)"; + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(matches_message_codes(a.diags(), { "E010" })); +} + +TEST(literals, processing_stack_in_messages) +{ + std::string input = R"( + MACRO + MAC + LARL 0,=A(B) + MEND + MAC +)"; + analyzer a(input); + a.analyze(); + a.collect_diags(); + + auto& d = a.diags(); + ASSERT_TRUE(matches_message_codes(d, { "E010" })); + EXPECT_EQ(d.front().related.size(), 1); +} + +TEST(literals, halfward_alignment) +{ + std::string input = R"( + LARL 0,=C'0' + LARL 0,=C'1' +)"; + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(a.diags().empty()); +} + +TEST(literals, halfward_alignment_expression) +{ + std::string input = R"( + LARL 0,=C'0' + LARL 0,2+=C'1'-2 +)"; + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(a.diags().empty()); +} + +TEST(literals, halfward_alignment_delayed) +{ + std::string input = R"( + LARL 0,=C'0' + LA 0,=C'1' + LARL 0,=C'1' +)"; + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(a.diags().empty()); + + auto* sect = get_section(a.hlasm_ctx(), ""); + ASSERT_TRUE(sect); + EXPECT_EQ(sect->location_counters().back()->current_address().offset(), 19); +} + +TEST(literals, target_csect) +{ + std::string input = R"( +A CSECT +L2 LOCTR +L1 LOCTR + LARL 0,=C'0' +L2 LOCTR +B CSECT +)"; + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(a.diags().empty()); + + auto* sect_a = get_section(a.hlasm_ctx(), "A"); + ASSERT_TRUE(sect_a); + EXPECT_EQ(sect_a->location_counters().back()->current_address().offset(), 8); + + auto* sect_b = get_section(a.hlasm_ctx(), "B"); + ASSERT_TRUE(sect_b); + EXPECT_EQ(sect_b->location_counters().back()->current_address().offset(), 0); +} + +TEST(literals, unreachable_literal) +{ + std::string input = R"( +A CSECT +B CSECT + LARL 0,=C'0' +)"; + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(matches_message_codes(a.diags(), { "M113" })); +} + +TEST(literals, no_csect_available) +{ + std::string input = R"( + DSECT + LARL 0,=A(0) +)"; + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(matches_message_codes(a.diags(), { "M113" })); +} + +TEST(literals, ltorg_in_dsect) +{ + std::string input = R"( + DSECT + LARL 0,=A(0) + LTORG +)"; + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(a.diags().empty()); +} + +TEST(literals, bad_attribute) +{ + std::string input = R"( + LHI 0,S'=A(0) +)"; + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(matches_message_codes(a.diags(), { "W011" })); +} + +TEST(literals, bad_nominal_value) +{ + std::string input = R"( + LARL 0,=AL4'123' +)"; + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(matches_message_codes(a.diags(), { "D017" })); +} + +TEST(literals, bad_nominal_value_dependency) +{ + std::string input = R"( + LARL 0,=FL4(X) + LTORG +X DS 0H +)"; + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(matches_message_codes(a.diags(), { "D018" })); +} + +TEST(literals, bad_nominal_value_both) +{ + std::string input = R"( + LARL 0,=AL4'123' + LARL 0,=FL4(X) + LTORG +X DS 0H +)"; + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(matches_message_codes(a.diags(), { "D017", "D018" })); +} + +TEST(literals, zero_length) +{ + std::string input = R"( + LARL 0,=0A(0) +)"; + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(matches_message_codes(a.diags(), { "D031" })); +} diff --git a/parser_library/test/context/ord_sym_test.cpp b/parser_library/test/context/ord_sym_test.cpp index fbfecb149..8e5cdb3ae 100644 --- a/parser_library/test/context/ord_sym_test.cpp +++ b/parser_library/test/context/ord_sym_test.cpp @@ -422,3 +422,65 @@ C EQU B-A EXPECT_EQ(a.diags().size(), (size_t)0); } + +TEST(ordinary_symbols, postponed_statement_in_macro) +{ + std::string input = R"( + MACRO + MAC + DS XL(*-AAA+(YD-XD)) + MEND +AAA DS C + MAC + MAC + MAC +TEST_AAA EQU *-AAA + +XD DSECT + DS F +YD DS 0C +)"; + + analyzer a(input); + a.analyze(); + + a.collect_diags(); + EXPECT_TRUE(a.diags().empty()); + + auto test_aaa = a.hlasm_ctx().ord_ctx.get_symbol(a.hlasm_ctx().ids().add("TEST_AAA")); + ASSERT_TRUE(test_aaa && test_aaa->kind() == context::symbol_value_kind::ABS); + EXPECT_EQ(test_aaa->value().get_abs(), 36); +} + +TEST(ordinary_symbols, private_sections_valid) +{ + for (std::string sect_type : { "CSECT", "RSECT", "COM" }) + { + std::string input = R"( + DSECT + )" + sect_type; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + EXPECT_EQ(a.diags().size(), (size_t)0) << sect_type; + } +} + +TEST(ordinary_symbols, private_sections_invalid) +{ + std::initializer_list types = { "CSECT", "RSECT", "COM" }; + + for (const auto& t1 : types) + { + for (const auto& t2 : types) + { + std::string input = " " + t1 + "\n " + t2; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + EXPECT_EQ(a.diags().size(), t1 != t2) << t1 << t2; + } + } +} diff --git a/parser_library/test/expressions/arithmetic_expression_test.cpp b/parser_library/test/expressions/arithmetic_expression_test.cpp index 5db7bc655..00e0b31fc 100644 --- a/parser_library/test/expressions/arithmetic_expression_test.cpp +++ b/parser_library/test/expressions/arithmetic_expression_test.cpp @@ -70,12 +70,13 @@ TEST(arithmetic_expressions, invalid_self_defining_term) R"( &C1 SETC 'D' &A1 SETA C'&C1' +&A2 SETA CA'A' )"; analyzer a(input); a.analyze(); a.collect_diags(); - ASSERT_EQ(a.diags().size(), (size_t)1); + ASSERT_EQ(a.diags().size(), (size_t)3); } TEST(arithmetic_expressions, substitution_to_character_expression) diff --git a/parser_library/test/expressions/ca_constant_test.cpp b/parser_library/test/expressions/ca_constant_test.cpp index cbffbedaa..5d1532528 100644 --- a/parser_library/test/expressions/ca_constant_test.cpp +++ b/parser_library/test/expressions/ca_constant_test.cpp @@ -77,4 +77,10 @@ TEST(ca_constant, self_def_term_valid_input) ASSERT_FALSE(add_diags.diagnostics_present); EXPECT_EQ(res, 15); } + { + diagnostic_adder add_diags; + auto res = ca_constant::self_defining_term("CA'A'", add_diags); + ASSERT_FALSE(add_diags.diagnostics_present); + EXPECT_EQ(res, 0x41); + } } diff --git a/parser_library/test/processing/lookahead_test.cpp b/parser_library/test/processing/lookahead_test.cpp index f825518fa..092ca9090 100644 --- a/parser_library/test/processing/lookahead_test.cpp +++ b/parser_library/test/processing/lookahead_test.cpp @@ -873,3 +873,20 @@ LABEL LLILF 0,C'&S' EXPECT_TRUE(a.diags().empty()); EXPECT_EQ(get_var_value(a.hlasm_ctx(), "RESULT"), "6 I"); } + +TEST(attribute_lookahead, expression) +{ + std::string input = R"( +&X SETC 'A(3)' +&T SETC T'&X +A DS C +)"; + + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(a.diags().empty()); + + EXPECT_EQ(get_var_value(a.hlasm_ctx(), "T"), "C"); +} diff --git a/parser_library/test/processing/mach_instr_test.cpp b/parser_library/test/processing/mach_instr_test.cpp index ebf6f7348..6337a0abb 100644 --- a/parser_library/test/processing/mach_instr_test.cpp +++ b/parser_library/test/processing/mach_instr_test.cpp @@ -232,3 +232,25 @@ SYM DS CL1 a.collect_diags(); ASSERT_EQ(a.diags().size(), 0U); } + +TEST(mach_instr_processing, rel_addr_bitmask) +{ + for (const auto& [instr, expected] : std::initializer_list> { + { "LARL", 0x40 }, + { "LA", 0x00 }, + { "CLIJ", 0x10 }, + { "BPRP", 0x60 }, + }) + { + EXPECT_EQ(context::instruction::machine_instructions.at(instr).reladdr_mask.mask(), expected) << instr; + } + + for (const auto& [instr, expected] : std::initializer_list> { + { "CLIJE", 0x20 }, + { "BNE", 0x00 }, + { "JNE", 0x80 }, + }) + { + EXPECT_EQ(context::instruction::mnemonic_codes.at(instr).reladdr_mask.mask(), expected) << instr; + } +} diff --git a/parser_library/test/processing/occurence_collector_test.cpp b/parser_library/test/processing/occurence_collector_test.cpp index 583a14dd3..2fbe84529 100644 --- a/parser_library/test/processing/occurence_collector_test.cpp +++ b/parser_library/test/processing/occurence_collector_test.cpp @@ -222,3 +222,24 @@ TEST(occurence_collector, ord_dc_operand_nominal_value) sort_occurence_vector(oa.st); EXPECT_EQ(oa.st, expected); } + +TEST(occurence_collector, ord_literal) +{ + std::string input = R"( + LARL 0,=A(X,X) +X DC A(X) +&A SETA L'=A(X) +)"; + operand_occurence_analyzer_mock oa(input, lsp::occurence_kind::ORD); + + // operands only + std::vector expected = { + { lsp::occurence_kind::ORD, oa.get_id("X"), { { 1, 14 }, { 1, 15 } } }, + { lsp::occurence_kind::ORD, oa.get_id("X"), { { 1, 16 }, { 1, 17 } } }, + { lsp::occurence_kind::ORD, oa.get_id("X"), { { 2, 11 }, { 2, 12 } } }, + { lsp::occurence_kind::ORD, oa.get_id("X"), { { 3, 14 }, { 3, 15 } } }, + }; + + sort_occurence_vector(oa.st); + EXPECT_EQ(oa.st, expected); +} diff --git a/parser_library/test/processing/opsyn_test.cpp b/parser_library/test/processing/opsyn_test.cpp index 9f3660ecd..1ff4371cf 100644 --- a/parser_library/test/processing/opsyn_test.cpp +++ b/parser_library/test/processing/opsyn_test.cpp @@ -317,3 +317,24 @@ B DS C EXPECT_TRUE(a.diags().empty()); EXPECT_EQ(get_var_value(a.hlasm_ctx(), "CNT"), 1); } + +TEST(OPSYN, reladdr_caching) +{ + std::string input(R"( + MACRO + MAC + INSTR 0,A + MEND + +INSTR OPSYN LA + MAC +INSTR OPSYN LARL + MAC +A DS 0H +)"); + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(a.diags().empty()); +} diff --git a/parser_library/test/semantics/operand_test.cpp b/parser_library/test/semantics/operand_test.cpp index 6887cba39..044f272b6 100644 --- a/parser_library/test/semantics/operand_test.cpp +++ b/parser_library/test/semantics/operand_test.cpp @@ -136,7 +136,7 @@ TEST(operand, access_operand) EXPECT_TRUE(access_asm_op(asm_kind::STRING, &sao)); // datadef operand - data_def_operand ddo({}, range()); + data_def_operand ddo(expressions::data_definition {}, range()); EXPECT_TRUE(access_op(operand_type::DAT, &ddo)); // ca operand diff --git a/utils/include/utils/similar.h b/utils/include/utils/similar.h index 747994428..fb15f4337 100644 --- a/utils/include/utils/similar.h +++ b/utils/include/utils/similar.h @@ -15,6 +15,7 @@ #ifndef HLASMPLUGIN_UTILS_SIMILAR_H #define HLASMPLUGIN_UTILS_SIMILAR_H +#include #include #include @@ -41,6 +42,12 @@ class is_similar_t static std::false_type use_equal(...); public: + template + bool operator()(const T& l, const T& r, Members T::*... member) const + { + return (operator()(l.*member, r.*member) && ...); + } + template bool operator()(const T& l, const T& r) const { @@ -49,6 +56,8 @@ class is_similar_t constexpr bool equal = decltype(use_equal(l))::value; static_assert(standalone || member || equal, "is_similar or equal to operator not available"); + if (&l == &r) + return true; if constexpr (standalone) return is_similar(l, r); else if constexpr (member) @@ -56,6 +65,24 @@ class is_similar_t else if constexpr (equal) return l == r; // if things are the same then they are also similar } + + template + bool operator()(const std::shared_ptr& l, const std::shared_ptr& r) const + { + return l == r || (l && r && operator()(*l, *r)); + } + + template + bool operator()(const std::unique_ptr& l, const std::unique_ptr& r) const + { + return l == r || (l && r && operator()(*l, *r)); + } + + template + bool operator()(T* const& l, T* const& r) const + { + return l == r || (l && r && operator()(*l, *r)); + } }; } // namespace detail