From 480e602c30fc6cf0cddcd017ee4abe66d75fc043 Mon Sep 17 00:00:00 2001 From: slavek-kucera <53339291+slavek-kucera@users.noreply.github.com> Date: Fri, 17 Sep 2021 13:58:16 +0200 Subject: [PATCH] fix: Remove ALIAS operand parsing limitation (#178) (fixes #157) --- clients/vscode-hlasmplugin/CHANGELOG.md | 1 + .../src/checking/asm_instr_check.cpp | 8 +- parser_library/src/diagnostic.cpp | 5 ++ parser_library/src/diagnostic.h | 2 + .../grammar/assembler_operand_rules.g4 | 11 ++- parser_library/src/parsing/parser_impl.cpp | 6 ++ parser_library/src/parsing/parser_impl.h | 1 + .../instruction_sets/asm_processor.cpp | 15 ++++ .../instruction_sets/asm_processor.h | 1 + .../test/checking/asm_instr_check_test.cpp | 4 - .../test/processing/asm_instr_test.cpp | 81 ++++++++++++++++++- 11 files changed, 122 insertions(+), 13 deletions(-) diff --git a/clients/vscode-hlasmplugin/CHANGELOG.md b/clients/vscode-hlasmplugin/CHANGELOG.md index a97cdcc2b..dbbef3d7c 100644 --- a/clients/vscode-hlasmplugin/CHANGELOG.md +++ b/clients/vscode-hlasmplugin/CHANGELOG.md @@ -19,6 +19,7 @@ - Files with extension should not be set to hlasm in libs folder - Lookahead mode does not work correctly when triggered from AINSERTed code - Incorrect relative immediate operand validation +- Remove ALIAS operand parsing limitation ## [0.14.0](https://github.com/eclipse/che-che4z-lsp-for-hlasm/compare/0.13.0...0.14.0) (2021-08-18) diff --git a/parser_library/src/checking/asm_instr_check.cpp b/parser_library/src/checking/asm_instr_check.cpp index 7178ed5e2..55b7d6559 100644 --- a/parser_library/src/checking/asm_instr_check.cpp +++ b/parser_library/src/checking/asm_instr_check.cpp @@ -1236,7 +1236,7 @@ bool alias::check(const std::vector& to_check, { // TO DO - no support for four characters in EBCDIC (¢, ¬, ±, ¦) - we throw an error although it should // not be - std::regex regex(R"([\.<¢\(\+\|&!\$\*\);¬\-\/¦,%_>\?`,:#@\=\"~±\[\]\{\}\^\\a-zA-Z0-9]*)"); + static const std::regex regex(R"([\.<¢\(\+\|&!\$\*\);¬\-\/¦,%_>\?`,:#@\=\"~±\[\]\{\}\^\\a-zA-Z0-9]*)"); std::string substr = first->operand_identifier.substr(2, first->operand_identifier.size() - 3); if (!std::regex_match(substr, regex)) { @@ -1247,7 +1247,7 @@ bool alias::check(const std::vector& to_check, } else if (first->operand_identifier[0] == 'X') { - if (first->operand_identifier.size() % 2 == 1) + if ((first->operand_identifier.size() - 3) % 2 == 1) { add_diagnostic(diagnostic_op::error_A154_ALIAS_X_format_no_of_chars(first->operand_range)); return false; @@ -1282,10 +1282,6 @@ bool alias::check(const std::vector& to_check, } return true; } - else - { - return false; - } } add_diagnostic(diagnostic_op::error_A151_ALIAS_op_format(first->operand_range)); return false; diff --git a/parser_library/src/diagnostic.cpp b/parser_library/src/diagnostic.cpp index 2990ea9da..c5f8d39c7 100644 --- a/parser_library/src/diagnostic.cpp +++ b/parser_library/src/diagnostic.cpp @@ -682,6 +682,11 @@ diagnostic_op diagnostic_op::error_A162_PROCESS_uknown_option(const std::string& diagnostic_severity::error, "A162", "Error at *PROCESS instruction: unknown assembler option " + option, range); } +diagnostic_op diagnostic_op::error_A163_ALIAS_mandatory_label(const range& range) +{ + return diagnostic_op(diagnostic_severity::error, "A163", "Label not provided on ALIAS instruction", range); +} + diagnostic_op diagnostic_op::error_A200_SCOPE_param(const std::string& instr_name, const range& range) { return diagnostic_op(diagnostic_severity::error, diff --git a/parser_library/src/diagnostic.h b/parser_library/src/diagnostic.h index e6384ab44..1d28dcf9d 100644 --- a/parser_library/src/diagnostic.h +++ b/parser_library/src/diagnostic.h @@ -279,6 +279,8 @@ struct diagnostic_op static diagnostic_op error_A162_PROCESS_uknown_option(const std::string& option, const range& range); + static diagnostic_op error_A163_ALIAS_mandatory_label(const range& range); + // operand parameters static diagnostic_op error_A200_SCOPE_param(const std::string& instr_name, const range& range); diff --git a/parser_library/src/parsing/grammar/assembler_operand_rules.g4 b/parser_library/src/parsing/grammar/assembler_operand_rules.g4 index 9a4d2cdc6..00acf7328 100644 --- a/parser_library/src/parsing/grammar/assembler_operand_rules.g4 +++ b/parser_library/src/parsing/grammar/assembler_operand_rules.g4 @@ -16,7 +16,14 @@ parser grammar assembler_operand_rules; asm_op returns [operand_ptr op] - : id lpar asm_op_comma_c rpar + : + { ALIAS() }? ORDSYMBOL string + { + auto range = provider.get_range($ORDSYMBOL,$string.ctx->getStop()); + collector.add_hl_symbol(token_info(provider.get_range($ORDSYMBOL),hl_scopes::self_def_type)); + $op = std::make_unique(std::make_unique(range),$ctx->getText(),range); + } + | id lpar asm_op_comma_c rpar { $op = std::make_unique( *$id.name,std::move($asm_op_comma_c.asm_ops), @@ -47,7 +54,7 @@ asm_op returns [operand_ptr op] provider.get_range($lpar.ctx->getStart(),$rpar.ctx->getStop()) ); } - | mach_expr + | { !ALIAS() }? mach_expr { std::string upper_case = $mach_expr.ctx->getText(); context::to_upper(upper_case); diff --git a/parser_library/src/parsing/parser_impl.cpp b/parser_library/src/parsing/parser_impl.cpp index e0719f8ad..d81f675fc 100644 --- a/parser_library/src/parsing/parser_impl.cpp +++ b/parser_library/src/parsing/parser_impl.cpp @@ -235,6 +235,12 @@ bool parser_impl::UNKNOWN() return format.form == processing::processing_form::UNKNOWN; } +bool parser_impl::ALIAS() +{ + auto& [format, opcode] = *proc_status; + return opcode.type == instruction_type::ASM && *opcode.value == "ALIAS"; +} + antlr4::misc::IntervalSet parser_impl::getExpectedTokens() { if (proc_status->first.kind == processing::processing_kind::LOOKAHEAD) diff --git a/parser_library/src/parsing/parser_impl.h b/parser_library/src/parsing/parser_impl.h index 1efc78efd..ffa22787a 100644 --- a/parser_library/src/parsing/parser_impl.h +++ b/parser_library/src/parsing/parser_impl.h @@ -93,6 +93,7 @@ class parser_impl : public antlr4::Parser bool CA(); bool MAC(); bool UNKNOWN(); + bool ALIAS(); private: antlr4::misc::IntervalSet getExpectedTokens() override; diff --git a/parser_library/src/processing/instruction_sets/asm_processor.cpp b/parser_library/src/processing/instruction_sets/asm_processor.cpp index 54bcf16c8..6708a852d 100644 --- a/parser_library/src/processing/instruction_sets/asm_processor.cpp +++ b/parser_library/src/processing/instruction_sets/asm_processor.cpp @@ -642,6 +642,7 @@ asm_processor::process_table_t asm_processor::create_table(context::hlasm_contex table.emplace(h_ctx.ids().add("CCW1"), [this](rebuilt_statement stmt) { process_CCW(std::move(stmt)); }); table.emplace(h_ctx.ids().add("CNOP"), [this](rebuilt_statement stmt) { process_CNOP(std::move(stmt)); }); 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)); }); return table; } @@ -817,4 +818,18 @@ void asm_processor::process_START(rebuilt_statement stmt) hlasm_ctx.ord_ctx.set_available_location_counter_value(start_section_alignment, offset); } +void asm_processor::process_ALIAS(rebuilt_statement stmt) +{ + if (!check(stmt, hlasm_ctx, checker_, *this)) + return; + auto symbol_name = find_label_symbol(stmt); + if (symbol_name->empty()) + { + add_diagnostic(diagnostic_op::error_A163_ALIAS_mandatory_label(stmt.stmt_range_ref())); + return; + } + + // TODO: check that the symbol_name is an external symbol +} + } // 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 47dc38f7f..505820f7c 100644 --- a/parser_library/src/processing/instruction_sets/asm_processor.h +++ b/parser_library/src/processing/instruction_sets/asm_processor.h @@ -64,6 +64,7 @@ class asm_processor : public low_language_processor void process_CCW(rebuilt_statement stmt); void process_CNOP(rebuilt_statement stmt); void process_START(rebuilt_statement stmt); + void process_ALIAS(rebuilt_statement stmt); template void process_data_instruction(rebuilt_statement stmt); diff --git a/parser_library/test/checking/asm_instr_check_test.cpp b/parser_library/test/checking/asm_instr_check_test.cpp index d327a37eb..aff505125 100644 --- a/parser_library/test/checking/asm_instr_check_test.cpp +++ b/parser_library/test/checking/asm_instr_check_test.cpp @@ -876,14 +876,10 @@ TEST_F(instruction_test, ainsert) TEST_F(instruction_test, alias) { - // TO DO - not working due to self-defining terms issues - - /* EXPECT_FALSE(checker.check("ALIAS", test_alias_false, range(), collector)); EXPECT_TRUE(checker.check("ALIAS", test_alias_true_one, range(), collector)); EXPECT_TRUE(checker.check("ALIAS", test_alias_true_two, range(), collector)); EXPECT_FALSE(checker.check("ALIAS", test_acontrol_true, range(), collector)); - */ } TEST_F(instruction_test, amode) diff --git a/parser_library/test/processing/asm_instr_test.cpp b/parser_library/test/processing/asm_instr_test.cpp index 9a5167e0e..cee90044b 100644 --- a/parser_library/test/processing/asm_instr_test.cpp +++ b/parser_library/test/processing/asm_instr_test.cpp @@ -14,6 +14,7 @@ #include "gtest/gtest.h" +#include "../common_testing.h" #include "analyzer.h" #include "ebcdic_encoding.h" @@ -132,4 +133,82 @@ CNOPSYM CNOP ADDR,16 auto symbol = ctx.ord_ctx.get_symbol(ctx.ids().add("CNOPSYM")); ASSERT_NE(symbol, nullptr); EXPECT_EQ(symbol->value().get_reloc().offset(), 4); -} \ No newline at end of file +} + +TEST(asm_instr_processing, ALIAS_mandatory_label) +{ + std::string input = R"( + ALIAS C'SOMESTRING' + ALIAS X'434343434343' +)"; + + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(matches_message_codes(a.diags(), { "A163", "A163" })); +} + +TEST(asm_instr_processing, ALIAS_external_missing) +{ + /* TODO: label must be an external symbol + std::string input = R"( +A ALIAS C'SOMESTRING' +)"; + + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(matches_message_codes(a.diags(), { "????" })); + */ +} + +TEST(asm_instr_processing, ALIAS_external_present) +{ + std::string input = R"( +A DSECT +B START +C CSECT +D DXD F + DC Q(A) + ENTRY E +E DS 0H + DC V(F) +G RSECT +H COM + EXTRN I + WXTRN J +A ALIAS C'STRING' +B ALIAS C'STRING' +C ALIAS C'STRING' +D ALIAS C'STRING' +E ALIAS C'STRING' +F ALIAS C'STRING' +G ALIAS C'STRING' +H ALIAS C'STRING' +I ALIAS C'STRING' +J ALIAS C'STRING' +)"; + + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(a.diags().empty()); +} + +TEST(asm_instr_processing, ALIAS_with_opsyn) +{ + std::string input = R"( +X OPSYN ALIAS +L X C'SOMESTRING' + EXTRN L +)"; + + analyzer a(input); + a.analyze(); + a.collect_diags(); + + EXPECT_TRUE(a.diags().empty()); +}