Skip to content

Commit

Permalink
feat: Support START and MHELP instructions (#171)
Browse files Browse the repository at this point in the history
  • Loading branch information
slavek-kucera authored Aug 30, 2021
1 parent f272f7d commit f9f2fb2
Show file tree
Hide file tree
Showing 19 changed files with 358 additions and 19 deletions.
1 change: 1 addition & 0 deletions clients/vscode-hlasmplugin/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#### Added
- Document outline support
- CNOP instruction implementation (limited)
- START, MHELP instructions

#### Fixed
- Preserve mixed-case labels on macro calls
Expand Down
11 changes: 6 additions & 5 deletions parser_library/src/context/hlasm_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,8 @@ void hlasm_context::add_system_vars_to_scope()
auto val_ndx = std::make_shared<set_symbol<C_t>>(SYSNDX, true, false);

std::string value = std::to_string(SYSNDX_);
int tmp_size = (int)value.size();
for (int i = 0; i < 4 - tmp_size; ++i)
value.insert(value.begin(), '0');
if (auto value_len = value.size(); value_len < 4)
value.insert(0, 4 - value_len, '0');

val_ndx->set_value(std::move(value));
curr_scope()->variables.insert({ SYSNDX, val_ndx });
Expand Down Expand Up @@ -256,7 +255,6 @@ hlasm_context::hlasm_context(std::string file_name, asm_option asm_options, std:
, opencode_file_name_(file_name)
, asm_options_(std::move(asm_options))
, instruction_map_(init_instruction_map())
, SYSNDX_(0)
, ord_ctx(*ids_, *this)
{
scope_stack_.emplace_back();
Expand Down Expand Up @@ -727,16 +725,19 @@ bool hlasm_context::is_in_macro() const { return scope_stack_.back().is_in_macro

macro_invo_ptr hlasm_context::enter_macro(id_index name, macro_data_ptr label_param_data, std::vector<macro_arg> params)
{
assert(SYSNDX_ <= SYSNDX_limit);

macro_def_ptr macro_def = get_macro_definition(name);
assert(macro_def);

auto invo((macro_def->call(std::move(label_param_data), std::move(params), ids().add("SYSLIST"))));
auto invo = macro_def->call(std::move(label_param_data), std::move(params), ids().add("SYSLIST"));
scope_stack_.emplace_back(invo, macro_def);
add_system_vars_to_scope();

visited_files_.insert(macro_def->definition_location.file);

++SYSNDX_;

return invo;
}

Expand Down
19 changes: 17 additions & 2 deletions parser_library/src/context/hlasm_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
#ifndef CONTEXT_HLASM_CONTEXT_H
#define CONTEXT_HLASM_CONTEXT_H

#include <compiler_options.h>
#include <deque>
#include <memory>
#include <set>
#include <vector>

#include "code_scope.h"
#include "compiler_options.h"
#include "operation_code.h"
#include "ordinary_assembly/ordinary_assembly_context.h"
#include "processing_context.h"
Expand Down Expand Up @@ -69,13 +69,17 @@ class hlasm_context

// Compiler options
asm_option asm_options_;
static constexpr alignment sectalgn = doubleword;

// map of all instruction in HLASM
const instruction_storage instruction_map_;
instruction_storage init_instruction_map();

// value of system variable SYSNDX
size_t SYSNDX_;
unsigned long SYSNDX_ = 1;
static constexpr unsigned long SYSNDX_limit_max = 9999999UL;
unsigned long SYSNDX_limit = SYSNDX_limit_max;

void add_system_vars_to_scope();
void add_global_system_vars();

Expand Down Expand Up @@ -252,6 +256,17 @@ class hlasm_context

return val;
}

unsigned long next_sysndx() const { return SYSNDX_; }
void sysndx_limit(unsigned long limit)
{
assert(limit <= SYSNDX_limit_max);
SYSNDX_limit = limit;
}
unsigned long sysndx_limit() const { return SYSNDX_limit; }
static constexpr unsigned long sysndx_limit_max() { return SYSNDX_limit_max; }

alignment section_alignment() const { return sectalgn; }
};

} // namespace hlasm_plugin::parser_library::context
Expand Down
2 changes: 1 addition & 1 deletion parser_library/src/context/id_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,10 @@ id_storage::well_known_strings::well_known_strings(std::unordered_set<std::strin
, MACRO(&*ptr.emplace("MACRO").first)
, MEND(&*ptr.emplace("MEND").first)
, MEXIT(&*ptr.emplace("MEXIT").first)
, MHELP(&*ptr.emplace("MHELP").first)
, ASPACE(&*ptr.emplace("ASPACE").first)
, AIF(&*ptr.emplace("AIF").first)
, AGO(&*ptr.emplace("AGO").first)
, ACTR(&*ptr.emplace("ACTR").first)
, AREAD(&*ptr.emplace("AREAD").first)
, empty(&*ptr.emplace("").first)
{}
2 changes: 1 addition & 1 deletion parser_library/src/context/id_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ class id_storage
const std::string* MACRO;
const std::string* MEND;
const std::string* MEXIT;
const std::string* MHELP;
const std::string* ASPACE;
const std::string* AIF;
const std::string* AGO;
const std::string* ACTR;
const std::string* AREAD;
const std::string* empty;
well_known_strings(std::unordered_set<std::string>& ptr);

} const well_known;
Expand Down
1 change: 1 addition & 0 deletions parser_library/src/context/instruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ const std::vector<ca_instruction> instruction::ca_instructions = {
{ "MACRO", true },
{ "MEND", true },
{ "MEXIT", true },
{ "MHELP", false },
{ "AEJECT", true },
{ "AREAD", false },
{ "ASPACE", false },
Expand Down
19 changes: 19 additions & 0 deletions parser_library/src/diagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1142,6 +1142,14 @@ diagnostic_op diagnostic_op::warning_A249_sequence_symbol_expected(const range&
return diagnostic_op(diagnostic_severity::warning, "A249", "Sequence symbol expected", range);
}

diagnostic_op diagnostic_op::error_A250_absolute_with_known_symbols(const range& range)
{
return diagnostic_op(diagnostic_severity::error,
"A250",
"Operand must be an absolute expression of previously defined symbols",
range);
}

diagnostic_op diagnostic_op::warning_A300_op_apostrophes_missing(const std::string& instr_name, const range& range)
{
return diagnostic_op(diagnostic_severity::warning,
Expand Down Expand Up @@ -1828,6 +1836,17 @@ diagnostic_op diagnostic_op::error_E071(const range& range)
return diagnostic_op(diagnostic_severity::error, "E071", "Macro prototype expected.", range);
}

diagnostic_op diagnostic_op::error_E072(const range& range)
{
return diagnostic_op(diagnostic_severity::error, "E072", "SYSNDX limit reached, macro call supressed.", range);
}

diagnostic_op diagnostic_op::error_E073(const range& range)
{
return diagnostic_op(
diagnostic_severity::error, "E073", "Illegal START instruction - CSECT already exists.", range);
}

diagnostic_op diagnostic_op::warning_W010(const std::string& message, const range& range)
{
return diagnostic_op(diagnostic_severity::warning, "W010", message + " not expected", range);
Expand Down
6 changes: 6 additions & 0 deletions parser_library/src/diagnostic.h
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,8 @@ struct diagnostic_op

static diagnostic_op warning_A249_sequence_symbol_expected(const range& range);

static diagnostic_op error_A250_absolute_with_known_symbols(const range& range);

// other

static diagnostic_op warning_A300_op_apostrophes_missing(const std::string& instr_name, const range& range);
Expand Down Expand Up @@ -574,6 +576,10 @@ struct diagnostic_op

static diagnostic_op error_E071(const range& range);

static diagnostic_op error_E072(const range& range);

static diagnostic_op error_E073(const range& range);

static diagnostic_op warning_W010(const std::string& message, const range& range);

static diagnostic_op warning_W011(const range& range);
Expand Down
13 changes: 7 additions & 6 deletions parser_library/src/parsing/parser_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,26 +143,27 @@ void parser_impl::resolve_expression(std::vector<expressions::ca_expr_ptr>& expr
void parser_impl::resolve_expression(expressions::ca_expr_ptr& expr) const
{
auto [_, opcode] = *proc_status;
if (opcode.value == hlasm_ctx->ids().well_known.SETA || opcode.value == hlasm_ctx->ids().well_known.ACTR
|| opcode.value == hlasm_ctx->ids().well_known.ASPACE || opcode.value == hlasm_ctx->ids().well_known.AGO)
const auto& wk = hlasm_ctx->ids().well_known;
if (opcode.value == wk.SETA || opcode.value == wk.ACTR || opcode.value == wk.ASPACE || opcode.value == wk.AGO
|| opcode.value == wk.MHELP)
resolve_expression(expr, context::SET_t_enum::A_TYPE);
else if (opcode.value == hlasm_ctx->ids().well_known.SETB)
else if (opcode.value == wk.SETB)
{
if (!expr->is_compatible(ca_expression_compatibility::setb))
expr->add_diagnostic(diagnostic_op::error_CE016_logical_expression_parenthesis(expr->expr_range));

resolve_expression(expr, context::SET_t_enum::B_TYPE);
}
else if (opcode.value == hlasm_ctx->ids().well_known.AIF)
else if (opcode.value == wk.AIF)
{
if (!expr->is_compatible(ca_expression_compatibility::aif))
expr->add_diagnostic(diagnostic_op::error_CE016_logical_expression_parenthesis(expr->expr_range));

resolve_expression(expr, context::SET_t_enum::B_TYPE);
}
else if (opcode.value == hlasm_ctx->ids().well_known.SETC)
else if (opcode.value == wk.SETC)
resolve_expression(expr, context::SET_t_enum::C_TYPE);
else if (opcode.value == hlasm_ctx->ids().well_known.AREAD)
else if (opcode.value == wk.AREAD)
{
// aread operand is just enumeration
}
Expand Down
52 changes: 52 additions & 0 deletions parser_library/src/processing/instruction_sets/asm_processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,7 @@ asm_processor::process_table_t asm_processor::create_table(context::hlasm_contex
table.emplace(h_ctx.ids().add("CCW0"), [this](rebuilt_statement stmt) { process_CCW(std::move(stmt)); });
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)); });

return table;
}
Expand Down Expand Up @@ -765,4 +766,55 @@ void asm_processor::process_CNOP(rebuilt_statement stmt)
hlasm_ctx.ord_ctx.reserve_storage_area(0, context::alignment { (size_t)*byte_value, (size_t)*boundary_value });
}


void asm_processor::process_START(rebuilt_statement stmt)
{
auto sect_name = find_label_symbol(stmt);

if (std::any_of(hlasm_ctx.ord_ctx.sections().begin(), hlasm_ctx.ord_ctx.sections().end(), [](const auto& s) {
return s->kind == context::section_kind::EXECUTABLE || s->kind == context::section_kind::READONLY;
}))
{
add_diagnostic(diagnostic_op::error_E073(stmt.stmt_range_ref()));
return;
}

if (hlasm_ctx.ord_ctx.symbol_defined(sect_name))
{
add_diagnostic(diagnostic_op::error_E031("symbol", stmt.label_ref().field_range));
return;
}

auto sym_loc = hlasm_ctx.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));

const auto& ops = stmt.operands_ref().value;
if (ops.size() != 1)
{
check(stmt, hlasm_ctx, checker_, *this);
return;
}

auto initial_offset = try_get_abs_value(ops.front().get());
if (!initial_offset.has_value())
{
add_diagnostic(diagnostic_op::error_A250_absolute_with_known_symbols(ops.front()->operand_range));
return;
}

size_t start_section_alignment = hlasm_ctx.section_alignment().boundary;
size_t start_section_alignment_mask = start_section_alignment - 1;

auto offset = initial_offset.value();
if (offset & start_section_alignment_mask)
{
// TODO: generate informational message?
offset += start_section_alignment_mask;
offset &= ~start_section_alignment_mask;
}

hlasm_ctx.ord_ctx.set_available_location_counter_value(start_section_alignment, offset);
}

} // namespace hlasm_plugin::parser_library::processing
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class asm_processor : public low_language_processor
void process_AINSERT(rebuilt_statement stmt);
void process_CCW(rebuilt_statement stmt);
void process_CNOP(rebuilt_statement stmt);
void process_START(rebuilt_statement stmt);

template<checking::data_instr_type instr_type>
void process_data_instruction(rebuilt_statement stmt);
Expand Down
42 changes: 42 additions & 0 deletions parser_library/src/processing/instruction_sets/ca_processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ ca_processor::process_table_t ca_processor::create_table(context::hlasm_context&
table.emplace(h_ctx.ids().add("AREAD"), std::bind(&ca_processor::process_AREAD, this, std::placeholders::_1));
table.emplace(h_ctx.ids().add("ASPACE"), std::bind(&ca_processor::process_ASPACE, this, std::placeholders::_1));
table.emplace(h_ctx.ids().add("AEJECT"), std::bind(&ca_processor::process_AEJECT, this, std::placeholders::_1));
table.emplace(h_ctx.ids().add("MHELP"), [this](const semantics::complete_statement& stmt) { process_MHELP(stmt); });

return table;
}
Expand Down Expand Up @@ -638,3 +639,44 @@ template void ca_processor::process_GBL_LCL<context::C_t, false>(const semantics
template void ca_processor::process_GBL_LCL<context::A_t, true>(const semantics::complete_statement& stmt);
template void ca_processor::process_GBL_LCL<context::B_t, true>(const semantics::complete_statement& stmt);
template void ca_processor::process_GBL_LCL<context::C_t, true>(const semantics::complete_statement& stmt);

void ca_processor::process_MHELP(const semantics::complete_statement& stmt)
{
register_seq_sym(stmt);

const auto& ops = stmt.operands_ref().value;
if (ops.size() > 1)
{
add_diagnostic(diagnostic_op::error_E020("operand", stmt.instruction_ref().field_range));
return;
}
if (ops.size() < 1)
{
add_diagnostic(diagnostic_op::error_E021("operand", stmt.instruction_ref().field_range));
return;
}

const auto* ca_op = ops[0]->access_ca();
assert(ca_op);
if (!ca_op)
return;

uint32_t value = 0;
if (ca_op->kind == semantics::ca_kind::EXPR)
{
value = ca_op->access_expr()->expression->evaluate<context::A_t>(eval_ctx);
}
else if (ca_op->kind == semantics::ca_kind::VAR)
{
auto val = ca_op->access_var()->variable_symbol->evaluate(eval_ctx);
if (val.type == context::SET_t_enum::A_TYPE)
value = val.access_a();
}
else
{
add_diagnostic(diagnostic_op::error_E010("operand", ca_op->operand_range));
}
value &= ~0xffUL; // ignore the option part
if (value & 0xff00UL) // rest is considered only when byte 3 is non-zero
hlasm_ctx.sysndx_limit(std::min((unsigned long)value, context::hlasm_context::sysndx_limit_max()));
}
2 changes: 2 additions & 0 deletions parser_library/src/processing/instruction_sets/ca_processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ class ca_processor : public instruction_processor
void process_AREAD(const semantics::complete_statement& stmt);

void process_empty(const semantics::complete_statement&);

void process_MHELP(const semantics::complete_statement& stmt);
};

} // namespace hlasm_plugin::parser_library::processing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,15 @@ macro_processor::macro_processor(

void macro_processor::process(std::shared_ptr<const processing::resolved_statement> stmt)
{
auto args = get_args(*stmt);
const auto next_sysndx = hlasm_ctx.next_sysndx();
const auto sysndx_limit = hlasm_ctx.sysndx_limit();
if (next_sysndx > sysndx_limit)
{
add_diagnostic(diagnostic_op::error_E072(stmt->stmt_range_ref()));
return;
}

auto args = get_args(*stmt);
hlasm_ctx.enter_macro(stmt->opcode_ref().value, std::move(args.name_param), std::move(args.symbolic_params));
}

Expand Down
2 changes: 1 addition & 1 deletion parser_library/test/debugging/debugger_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ TEST(debugger, test)
}),
},
{ "&SYSECT", "" },
{ "&SYSNDX", "0000" },
{ "&SYSNDX", "0001" },
{ "&SYSSTYP", "" },
{ "&SYSLOC", "" },
{ "&SYSNEST", 1 },
Expand Down
Loading

0 comments on commit f9f2fb2

Please sign in to comment.