Skip to content

Commit

Permalink
feat: AREAD support (#125)
Browse files Browse the repository at this point in the history
  • Loading branch information
slavek-kucera authored May 14, 2021
1 parent daa662e commit 052c844
Show file tree
Hide file tree
Showing 26 changed files with 745 additions and 115 deletions.
2 changes: 2 additions & 0 deletions parser_library/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
# Broadcom, Inc. - initial API and implementation

target_sources(parser_library PRIVATE
aread_time.cpp
aread_time.h
analyzer.cpp
analyzer.h
analyzing_context.h
Expand Down
44 changes: 44 additions & 0 deletions parser_library/src/aread_time.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* 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 "aread_time.h"

namespace {
std::string zero_left_pad(std::string s, size_t len)
{
if (s.size() >= len)
return s;

s.insert(s.begin(), len - s.size(), '0');
return s;
}
} // namespace


std::string hlasm_plugin::parser_library::time_to_clockb(std::chrono::nanoseconds d)
{
using namespace std::chrono;
return zero_left_pad(std::to_string(duration_cast<milliseconds>(d).count() / 10), 8);
}

std::string hlasm_plugin::parser_library::time_to_clockd(std::chrono::nanoseconds d)
{
using namespace std::chrono;
std::string result;
result.append(zero_left_pad(std::to_string(duration_cast<hours>(d).count()), 2));
result.append(zero_left_pad(std::to_string(duration_cast<minutes>(d).count() % 60), 2));
result.append(zero_left_pad(std::to_string(duration_cast<seconds>(d).count() % 60), 2));
result.append(zero_left_pad(std::to_string(duration_cast<milliseconds>(d).count() % 1000 / 10), 2));
return result;
}
26 changes: 26 additions & 0 deletions parser_library/src/aread_time.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* 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_AREAD_TIME_H
#define HLASMPLUGIN_PARSERLIBRARY_AREAD_TIME_H

#include <chrono>
#include <string>

namespace hlasm_plugin::parser_library {
std::string time_to_clockb(std::chrono::nanoseconds d);
std::string time_to_clockd(std::chrono::nanoseconds d);
} // namespace hlasm_plugin::parser_library

#endif // HLASMPLUGIN_PARSERLIBRARY_AREAD_TIME_H
5 changes: 5 additions & 0 deletions parser_library/src/checking/asm_instr_check.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1263,6 +1263,11 @@ bool ainsert::check(const std::vector<const asm_operand*>& to_check,
diagnostic_op::error_A301_op_apostrophes_missing(name_of_instruction, to_check[0]->operand_range));
return false;
}
if (first->operand_identifier.size() == 2) // empty string
{
add_diagnostic(diagnostic_op::error_A021_cannot_be_empty(name_of_instruction, to_check[0]->operand_range));
return false;
}
// check second operand
if (second == nullptr || (second->operand_identifier != "BACK" && second->operand_identifier != "FRONT"))
{
Expand Down
12 changes: 12 additions & 0 deletions parser_library/src/diagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1773,6 +1773,18 @@ diagnostic_op diagnostic_op::error_E068(const range& range)
diagnostic_severity::error, "E068", "Operand value falls outside of current section/LOCTR", range);
}

diagnostic_op diagnostic_op::error_E069(const range& range)
{
return diagnostic_op(
diagnostic_severity::error, "E069", "AREAD instruction can only be called from within a macro", range);
}

diagnostic_op diagnostic_op::error_E070(const range& range)
{
return diagnostic_op(
diagnostic_severity::error, "E070", "Invalid AREAD operand. Use AREAD [NOSTMT|NOPRINT|CLOCKB|CLOCKD].", range);
}

diagnostic_op diagnostic_op::error_E044(const range& range)
{
return diagnostic_op(diagnostic_severity::error, "E044", "Illegal name field in macro prototype, discarded", range);
Expand Down
4 changes: 4 additions & 0 deletions parser_library/src/diagnostic.h
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,10 @@ struct diagnostic_op

static diagnostic_op error_E068(const range& range);

static diagnostic_op error_E069(const range& range);

static diagnostic_op error_E070(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
57 changes: 46 additions & 11 deletions parser_library/src/lexing/lexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,9 @@ void lexer::start_token() { token_start_state_ = *input_state_; }

void lexer::switch_input_streams()
{
if (ainsert_stream_->LA(1) != ainsert_stream_->EOF)
return;

if (!ainsert_buffer_.empty())
{
UTF32String f = ainsert_buffer_.front();
Expand Down Expand Up @@ -786,42 +789,74 @@ std::string lexer::aread()

switch_input_streams();

start_token();
if (eof())
return "";

if (file_input_state_.char_position_in_line)
rewind_input(stream_position { file_input_state_.line,
file_input_state_.char_position
- file_input_state_.char_position_in_line }); // make sure we read the WHOLE line
if (from_buffer() && buffer_input_state_.char_position_in_line)
{
buffer_input_state_.char_position -= buffer_input_state_.char_position_in_line;
buffer_input_state_.char_position_in_line = 0;
buffer_input_state_.char_position_in_line_utf16 = 0;
buffer_input_state_.input->rewind_input(buffer_input_state_.char_position);
input_state_->c = buffer_input_state_.input->LA(1);
}

while (!eof() && input_state_->c != '\n' && input_state_->c != static_cast<char_t>(-1) && str.length() < 80)
start_token();
while (!eof() && input_state_->c != '\r' && input_state_->c != '\n' && input_state_->c != static_cast<char_t>(-1))
{
str.append(converter.to_bytes(input_state_->c));
consume();
}
create_token(AREAD, HIDDEN_CHANNEL);
lex_end(false);
consume_new_line();

if (input_state_ == &file_input_state_)
set_last_line_pos(input_state_->char_position, token_start_state_.line);

if (eof())
create_token(Token::EOF);

if (str.empty())
str = " ";

return str;
}

std::unique_ptr<input_source>& lexer::get_ainsert_stream() { return ainsert_stream_; }

void lexer::ainsert_back(const std::string& back) { ainsert(back, true); }
void lexer::ainsert_back(const std::string& back) { ainsert(back, false); }

void lexer::ainsert_front(const std::string& back) { ainsert(back, false); }
void lexer::ainsert_front(const std::string& back) { ainsert(back, true); }

void lexer::ainsert(const std::string& inp, bool front)
{
auto len = length_utf16(inp);
auto s = converter.from_bytes(inp);
UTF32String str(s.begin(), s.end());
if (len > 0)
if (str.size())
{
for (; len < 80; ++len)
str.push_back(' ');
if (str.size() < 80)
str.resize(80, ' ');
str.push_back('\n');
if (front)
ainsert_buffer_.push_front(str);
else
ainsert_buffer_.push_back(str);

if (file_input_state_.char_position_in_line)
rewind_input(stream_position { file_input_state_.line,
file_input_state_.char_position
- file_input_state_.char_position_in_line }); // make sure we read the WHOLE line

while (token_queue_.size())
token_queue_.pop();
eof_generated_ = false;
}
else
{
throw std::runtime_error("invalid insertion - empty string");
throw std::logic_error("invalid insertion - empty string");
}
}

Expand Down
2 changes: 1 addition & 1 deletion parser_library/src/lexing/lexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class input_source;

using token_ptr = std::unique_ptr<antlr4::Token>;
using char_t = char32_t;
class lexer : public antlr4::TokenSource
class lexer final : public antlr4::TokenSource
{
public:
struct stream_position
Expand Down
46 changes: 40 additions & 6 deletions parser_library/src/parsing/parser_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,29 +47,56 @@ void parser_impl::initialize(analyzing_context a_ctx,
finished_flag = false;
lib_provider_ = lib_provider;
state_listener_ = state_listener;
}

bool parser_impl::is_last_line() const
{
return dynamic_cast<lexing::lexer&>(*_input->getTokenSource()).is_last_line();
input_lexer = &dynamic_cast<lexing::lexer&>(*_input->getTokenSource());
}

bool parser_impl::is_last_line() const { return input_lexer->is_last_line(); }

void parser_impl::rewind_input(context::source_position pos)
{
finished_flag = false;
_matchedEOF = false;
input.rewind_input(lexing::lexer::stream_position { pos.file_line, pos.file_offset });
}

std::string parser_impl::aread()
{
std::string line = input_lexer->aread();

if (input_lexer->eof_generated())
finished_flag = true;
input_tokens_invalidated = true;

if (!line.empty())
line.resize(80, ' ');
return line;
}

void parser_impl::ainsert(const std::string& record, processing::ainsert_destination dest)
{
switch (dest)
{
case ainsert_destination::back:
input_lexer->ainsert_back(record);
break;
case ainsert_destination::front:
input_lexer->ainsert_front(record);
break;
}
// TODO: this needs to be really reworked...
input_tokens_invalidated = true;
}

context::source_position parser_impl::statement_start() const
{
auto pos = dynamic_cast<lexing::lexer&>(*_input->getTokenSource()).last_lln_begin_position();
auto pos = input_lexer->last_lln_begin_position();
return { pos.line, pos.offset };
}

context::source_position parser_impl::statement_end() const
{
auto pos = dynamic_cast<lexing::lexer&>(*_input->getTokenSource()).last_lln_end_position();
auto pos = input_lexer->last_lln_end_position();
return { pos.line, pos.offset };
}

Expand Down Expand Up @@ -337,6 +364,13 @@ bool parser_impl::process_statement()

context::shared_stmt_ptr parser_impl::get_next(const statement_processor& proc)
{
if (input_tokens_invalidated)
{
input_tokens_invalidated = false;

input.reset();
reset();
}
processor = &proc;

if (proc.kind == processing::processing_kind::LOOKAHEAD)
Expand Down
6 changes: 6 additions & 0 deletions parser_library/src/parsing/parser_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ class parser_impl : public antlr4::Parser,

bool is_last_line() const;
void rewind_input(context::source_position pos) override;
std::string aread() override;
void ainsert(const std::string& record, processing::ainsert_destination front) override;

context::source_position statement_start() const;
context::source_position statement_end() const;

Expand Down Expand Up @@ -116,6 +119,7 @@ class parser_impl : public antlr4::Parser,
std::unique_ptr<parser_holder> rest_parser_;
workspaces::parse_lib_provider* lib_provider_ = nullptr;
processing::processing_state_listener* state_listener_ = nullptr;
lexing::lexer* input_lexer = nullptr;

void initialize(context::hlasm_context* hlasm_ctx,
semantics::range_provider range_prov,
Expand All @@ -135,6 +139,8 @@ class parser_impl : public antlr4::Parser,
void parse_lookahead_operands(const std::string& text, range text_range);

antlr4::misc::IntervalSet getExpectedTokens() override;

bool input_tokens_invalidated = false;
};

// structure containing parser components
Expand Down
Loading

0 comments on commit 052c844

Please sign in to comment.