Skip to content

Commit

Permalink
fix: Parsing of negative numbers in machine expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
slavek-kucera authored Apr 8, 2022
1 parent a223b48 commit fee9e33
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 86 deletions.
1 change: 1 addition & 0 deletions clients/vscode-hlasmplugin/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- Contents of subscript arrays are now visible during debugging without the need to expand them
- Improve detection of HLASM files
- Reaching ACTR limit now only generates warnings
- Parsing of negative numbers in machine expressions

## [1.1.0](https://github.com/eclipse/che-che4z-lsp-for-hlasm/compare/1.0.0...1.1.0) (2022-03-29)

Expand Down
140 changes: 81 additions & 59 deletions parser_library/src/parsing/grammar/ca_expr_rules.g4
Original file line number Diff line number Diff line change
Expand Up @@ -186,48 +186,59 @@ expr_comma_c returns [std::vector<ca_expr_ptr> ca_exprs]
$ca_exprs = std::move($tmp.ca_exprs);
};



created_set_body returns [concat_point_ptr point]
: ORDSYMBOL
{
collector.add_hl_symbol(token_info(provider.get_range( $ORDSYMBOL),hl_scopes::var_symbol));
$point = std::make_unique<char_str_conc>($ORDSYMBOL->getText(), provider.get_range($ORDSYMBOL));
}
| IDENTIFIER
{
collector.add_hl_symbol(token_info(provider.get_range( $IDENTIFIER),hl_scopes::var_symbol));
$point = std::make_unique<char_str_conc>($IDENTIFIER->getText(), provider.get_range($IDENTIFIER));
}
| NUM
{
collector.add_hl_symbol(token_info(provider.get_range( $NUM),hl_scopes::var_symbol));
$point = std::make_unique<char_str_conc>($NUM->getText(), provider.get_range($NUM));
}
| var_symbol {$point = std::make_unique<var_sym_conc>(std::move($var_symbol.vs));}
| dot {$point = std::make_unique<dot_conc>();};

created_set_body_c returns [concat_chain concat_list]
: (cl=created_set_body {$concat_list.push_back(std::move($cl.point));})+;
created_set_body returns [concat_chain concat_list]
:
(
ORDSYMBOL
{
collector.add_hl_symbol(token_info(provider.get_range( $ORDSYMBOL),hl_scopes::var_symbol));
$concat_list.push_back(std::make_unique<char_str_conc>($ORDSYMBOL->getText(), provider.get_range($ORDSYMBOL)));
}
|
IDENTIFIER
{
collector.add_hl_symbol(token_info(provider.get_range( $IDENTIFIER),hl_scopes::var_symbol));
$concat_list.push_back(std::make_unique<char_str_conc>($IDENTIFIER->getText(), provider.get_range($IDENTIFIER)));
}
|
NUM
{
collector.add_hl_symbol(token_info(provider.get_range( $NUM),hl_scopes::var_symbol));
$concat_list.push_back(std::make_unique<char_str_conc>($NUM->getText(), provider.get_range($NUM)));
}
|
var_symbol
{
$concat_list.push_back(std::make_unique<var_sym_conc>(std::move($var_symbol.vs)));
}
|
dot
{
$concat_list.push_back(std::make_unique<dot_conc>());
}
)+
;
finally
{concatenation_point::clear_concat_chain($concat_list);}

created_set_symbol returns [vs_ptr vs]
: AMPERSAND lpar (clc=created_set_body_c)? rpar subscript
{
collector.add_hl_symbol(token_info(provider.get_range( $AMPERSAND),hl_scopes::var_symbol));
$vs = std::make_unique<created_variable_symbol>($clc.ctx ? std::move($clc.concat_list) : concat_chain{},std::move($subscript.value),provider.get_range($AMPERSAND,$subscript.ctx->getStop()));
};

var_symbol returns [vs_ptr vs]
: AMPERSAND vs_id tmp=subscript
{
auto id = $vs_id.name;
auto r = provider.get_range( $AMPERSAND,$tmp.ctx->getStop());
$vs = std::make_unique<basic_variable_symbol>(id, std::move($tmp.value), r);
collector.add_hl_symbol(token_info(provider.get_range( $AMPERSAND, $vs_id.ctx->getStop()),hl_scopes::var_symbol));
}
| created_set_symbol {$vs = std::move($created_set_symbol.vs);};
:
AMPERSAND
(
vs_id tmp=subscript
{
auto id = $vs_id.name;
auto r = provider.get_range( $AMPERSAND,$tmp.ctx->getStop());
$vs = std::make_unique<basic_variable_symbol>(id, std::move($tmp.value), r);
collector.add_hl_symbol(token_info(provider.get_range( $AMPERSAND, $vs_id.ctx->getStop()),hl_scopes::var_symbol));
}
|
lpar (clc=created_set_body)? rpar subscript
{
collector.add_hl_symbol(token_info(provider.get_range( $AMPERSAND),hl_scopes::var_symbol));
$vs = std::make_unique<created_variable_symbol>($clc.ctx ? std::move($clc.concat_list) : concat_chain{},std::move($subscript.value),provider.get_range($AMPERSAND,$subscript.ctx->getStop()));
}
);

data_attribute returns [context::data_attr_kind attribute, std::variant<context::id_index, semantics::vs_ptr, semantics::literal_si> value, range value_range]
: ORDSYMBOL (attr|apostrophe_as_attr) data_attribute_value
Expand All @@ -254,19 +265,29 @@ data_attribute_value returns [std::variant<context::id_index, semantics::vs_ptr,
$value = $id.name;
};

vs_id_ch_c
: (NUM|ORDSYMBOL)+;

vs_id returns [id_index name = id_storage::empty_id]
: ORDSYMBOL vs_id_ch_c
: ORDSYMBOL
{
std::string tmp($ORDSYMBOL->getText());
tmp.append($vs_id_ch_c.ctx->getText());
$name = parse_identifier(std::move(tmp),provider.get_range($ORDSYMBOL,$vs_id_ch_c.ctx->getStop()));
std::string text = $ORDSYMBOL->getText();
auto first = $ORDSYMBOL;
auto last = first;
}
| ORDSYMBOL {$name = parse_identifier($ORDSYMBOL->getText(),provider.get_range($ORDSYMBOL));};


(
NUM
{
text += $NUM->getText();
last = $NUM;
}
|
ORDSYMBOL
{
text += $ORDSYMBOL->getText();
last = $ORDSYMBOL;
}
)*
{
$name = parse_identifier(text, provider.get_range(first, last));
};

var_def returns [vs_ptr vs]
: var_def_name var_def_substr
Expand All @@ -282,8 +303,12 @@ var_def returns [vs_ptr vs]
};

var_def_name returns [id_index name, concat_chain created_name]
: AMPERSAND? vs_id {$name = $vs_id.name; }
| AMPERSAND? lpar clc=created_set_body_c rpar {$created_name = std::move($clc.concat_list);};
: AMPERSAND?
(
vs_id {$name = $vs_id.name;}
|
lpar clc=created_set_body rpar {$created_name = std::move($clc.concat_list);}
);

var_def_substr returns [std::vector<ca_expr_ptr> value]
: lpar num rpar
Expand All @@ -303,19 +328,16 @@ ca_dupl_factor returns [ca_expr_ptr value]
|;

substring returns [expressions::ca_string::substring_t value]
: lpar e1=expr comma e2=expr rpar
: lpar e1=expr comma (e2=expr|ASTERISK) rpar
{
$value.start = std::move($e1.ca_expr);
$value.count = std::move($e2.ca_expr);
$value.substring_range = provider.get_range($lpar.ctx->getStart(), $rpar.ctx->getStop());
resolve_expression($value.start, context::SET_t_enum::A_TYPE);
resolve_expression($value.count, context::SET_t_enum::A_TYPE);
}
| lpar expr comma ASTERISK rpar
{
$value.start = std::move($expr.ca_expr);
$value.substring_range = provider.get_range($lpar.ctx->getStart(), $rpar.ctx->getStop());
resolve_expression($value.start, context::SET_t_enum::A_TYPE);
if ($e2.ctx)
{
$value.count = std::move($e2.ca_expr);
resolve_expression($value.count, context::SET_t_enum::A_TYPE);
}
}
|;

Expand Down
6 changes: 3 additions & 3 deletions parser_library/src/parsing/grammar/machine_expr_rules.g4
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,10 @@ mach_term returns [mach_expr_ptr m_e]
collector.add_hl_symbol(token_info(provider.get_range( $id.ctx),hl_scopes::ordinary_symbol));
$m_e = std::make_unique<mach_expr_symbol>($id.name, $id.using_qualifier, provider.get_range( $id.ctx));
}
| num
| signed_num
{
collector.add_hl_symbol(token_info(provider.get_range( $num.ctx),hl_scopes::number));
$m_e = std::make_unique<mach_expr_constant>($num.value, provider.get_range( $num.ctx));
collector.add_hl_symbol(token_info(provider.get_range( $signed_num.ctx),hl_scopes::number));
$m_e = std::make_unique<mach_expr_constant>($signed_num.value, provider.get_range( $signed_num.ctx));
}
| literal
{
Expand Down
72 changes: 48 additions & 24 deletions parser_library/test/processing/mach_instr_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,8 @@ TEST(mach_instr_processing, reloc_imm_expected)
analyzer a(input);
a.analyze();
a.collect_diags();
ASSERT_EQ(a.parser().getNumberOfSyntaxErrors(), (size_t)0);
ASSERT_EQ(a.diags().size(), (size_t)1);
ASSERT_EQ(a.diags().at(0).code, "M113");
EXPECT_EQ(a.parser().getNumberOfSyntaxErrors(), (size_t)0);
EXPECT_TRUE(matches_message_codes(a.diags(), { "M113" }));
}

TEST(mach_instr_processing, invalid_reloc_operand)
Expand All @@ -44,8 +43,7 @@ LENGTH DS CL(SIZE)
a.analyze();
a.collect_diags();

ASSERT_EQ(a.diags().size(), (size_t)1);
ASSERT_EQ(a.diags().at(0).code, "M113");
EXPECT_TRUE(matches_message_codes(a.diags(), { "M113" }));
}

TEST(mach_instr_processing, valid_reloc_operand)
Expand All @@ -61,7 +59,7 @@ LENGTH DS CL(SIZE)
a.analyze();
a.collect_diags();

ASSERT_EQ(a.diags().size(), (size_t)0);
EXPECT_TRUE(a.diags().empty());
}

TEST(mach_instr_processing, reloc_operand_halfword_o_error)
Expand All @@ -77,8 +75,7 @@ LEN120 DS CL1
a.analyze();
a.collect_diags();

ASSERT_EQ(a.diags().size(), (size_t)1);
ASSERT_EQ(a.diags().at(0).code, "ME003");
EXPECT_TRUE(matches_message_codes(a.diags(), { "ME003" }));
}
TEST(mach_instr_processing, vec_reg_expected)
{
Expand All @@ -89,9 +86,8 @@ TEST(mach_instr_processing, vec_reg_expected)
analyzer a(input);
a.analyze();
a.collect_diags();
ASSERT_EQ(a.parser().getNumberOfSyntaxErrors(), (size_t)0);
ASSERT_EQ(a.diags().size(), (size_t)1);
ASSERT_EQ(a.diags().at(0).code, "M114");
EXPECT_EQ(a.parser().getNumberOfSyntaxErrors(), (size_t)0);
EXPECT_TRUE(matches_message_codes(a.diags(), { "M114" }));
}
TEST(mach_instr_processing, reloc_symbol_expected)
{
Expand All @@ -116,8 +112,8 @@ TEST(mach_instr_processing, setc_variable_mnemonic_reloc_operand)
analyzer a(input);
a.analyze();
a.collect_diags();
ASSERT_EQ(a.parser().getNumberOfSyntaxErrors(), (size_t)0);
ASSERT_EQ(a.diags().size(), (size_t)0);
EXPECT_EQ(a.parser().getNumberOfSyntaxErrors(), (size_t)0);
EXPECT_TRUE(a.diags().empty());
}
TEST(mach_instr_processing, setc_variable_reloc_operand)
{
Expand All @@ -132,8 +128,8 @@ TEST CSECT
analyzer a(input);
a.analyze();
a.collect_diags();
ASSERT_EQ(a.parser().getNumberOfSyntaxErrors(), (size_t)0);
ASSERT_EQ(a.diags().size(), (size_t)0);
EXPECT_EQ(a.parser().getNumberOfSyntaxErrors(), (size_t)0);
EXPECT_TRUE(a.diags().empty());
}
TEST(mach_instr_processing, setc_variable_reloc_symbol_expected_warn)
{
Expand Down Expand Up @@ -164,8 +160,8 @@ LABEL BRAS 0,*+12
analyzer a(input);
a.analyze();
a.collect_diags();
ASSERT_EQ(a.parser().getNumberOfSyntaxErrors(), (size_t)0);
ASSERT_EQ(a.diags().size(), (size_t)0);
EXPECT_EQ(a.parser().getNumberOfSyntaxErrors(), (size_t)0);
EXPECT_TRUE(a.diags().empty());
}
TEST(mach_instr_processing, reloc_parsed_in_macro_with_immValue)
{
Expand Down Expand Up @@ -199,8 +195,7 @@ LEN120 DS CL1
analyzer a(input);
a.analyze();
a.collect_diags();
ASSERT_EQ(a.diags().size(), (size_t)1);
ASSERT_EQ(a.diags().at(0).code, "ME003");
EXPECT_TRUE(matches_message_codes(a.diags(), { "ME003" }));
}

TEST(mach_instr_processing, mach_instr_aligned_assign_to_loctr)
Expand All @@ -214,8 +209,7 @@ SYM DS CL15
analyzer a(input);
a.analyze();
a.collect_diags();
ASSERT_EQ(a.diags().size(), 1U);
ASSERT_EQ(a.diags()[0].code, "M120");
EXPECT_TRUE(matches_message_codes(a.diags(), { "M120" }));
}

TEST(mach_instr_processing, mach_instr_aligned_assign_to_loctr_reloc_imm)
Expand All @@ -229,7 +223,7 @@ SYM DS CL1
analyzer a(input);
a.analyze();
a.collect_diags();
ASSERT_EQ(a.diags().size(), 0U);
EXPECT_TRUE(a.diags().empty());
}

TEST(mach_instr_processing, rel_addr_bitmask)
Expand Down Expand Up @@ -293,7 +287,7 @@ LABEL DS 0H
a.analyze();
a.collect_diags();

ASSERT_TRUE(a.diags().empty());
EXPECT_TRUE(a.diags().empty());
}

TEST(mach_instr_processing, relimm_qualified_bad)
Expand Down Expand Up @@ -321,5 +315,35 @@ TEST(mach_instr_processing, literals_with_index_register)
a.analyze();
a.collect_diags();

ASSERT_TRUE(a.diags().empty());
EXPECT_TRUE(a.diags().empty());
}

TEST(mach_instr_processing, mach_expr_limits)
{
std::string input(R"(
LARL 0,-2147483648+*+2147483647+1
LARL 0,*+-2147483648+2147483647+1
LARL 0,*+++++2
LARL 0,*-----2
LARL 0,*-+-+-2
)");

analyzer a(input);
a.analyze();
a.collect_diags();

EXPECT_TRUE(a.diags().empty());
}

TEST(mach_instr_processing, mach_expr_out_of_bounds)
{
std::string input(R"(
LARL 0,*-2147483648+2147483647+1
)");

analyzer a(input);
a.analyze();
a.collect_diags();

EXPECT_TRUE(matches_message_codes(a.diags(), { "CE007" }));
}
14 changes: 14 additions & 0 deletions parser_library/test/semantics/concatenation_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,17 @@ TEST(concatenation, no_dots_without_subscript)
EXPECT_TRUE(a.diags().empty());
EXPECT_EQ(get_var_value<C_t>(a.hlasm_ctx(), "A"), " ' ");
}

TEST(concatenation, identifier_after_variable_name)
{
std::string input = R"(
&A SETC 'X'
&B SETC '&A:'
)";
analyzer a(input);
a.analyze();
a.collect_diags();

EXPECT_TRUE(a.diags().empty());
EXPECT_EQ(get_var_value<C_t>(a.hlasm_ctx(), "B"), "X:");
}

0 comments on commit fee9e33

Please sign in to comment.