From 99c45ee0a45d4b54b4c043e79afb92b73edee935 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20=C5=A0melko?= Date: Mon, 24 Aug 2020 11:23:49 +0200 Subject: [PATCH] fix: Conditional assembly expressions (#65) Co-authored-by: Zeibura Kathau --- benchmark/benchmark.cpp | 1 + docs/Analyzer-pages/Expressions.md | 77 +- docs/Home.md | 2 +- docs/img/all_arch.svg | 4456 +---------------- docs/img/analyzer_arch.svg | 210 +- docs/img/diagnosable_hierarchy.svg | 317 +- docs/img/hlasm_architecture.svg | 572 +-- docs/img/hover_sequence.svg | 1380 +---- docs/img/lang_detection.svg | 451 +- docs/img/lang_server.svg | 564 +-- docs/img/lexer_arch.svg | 351 +- docs/img/lsp_addition.svg | 364 +- docs/img/mach_expr_example.svg | 367 +- docs/img/macro_tracer_arch.svg | 519 +- docs/img/operand_arch.svg | 644 +-- docs/img/ord_ctx_arch.svg | 282 +- docs/img/org_diagram.svg | 179 +- docs/img/parser_lexer_arch.svg | 153 +- docs/img/process_next.svg | 450 +- docs/img/processing_manager_arch.svg | 775 +-- docs/img/variable_arch.svg | 293 +- docs/img/ws_mngr_arch.svg | 433 +- parser_library/CMakeLists.txt | 6 +- .../src/checking/diagnostic_collector.cpp | 15 +- .../src/checking/diagnostic_collector.h | 10 +- parser_library/src/context/common_types.cpp | 23 +- parser_library/src/context/common_types.h | 10 +- parser_library/src/context/hlasm_context.cpp | 63 +- parser_library/src/context/hlasm_context.h | 5 +- parser_library/src/context/lsp_context.cpp | 2 + parser_library/src/context/lsp_context.h | 3 + .../context/ordinary_assembly/dependable.h | 2 +- .../ordinary_assembly_context.cpp | 7 + .../ordinary_assembly_context.h | 3 +- .../ordinary_assembly/symbol_attributes.cpp | 18 +- .../ordinary_assembly/symbol_attributes.h | 7 +- .../src/context/variables/macro_param.h | 6 +- .../src/context/variables/set_symbol.h | 12 +- .../src/context/variables/system_variable.cpp | 2 +- .../src/context/variables/system_variable.h | 6 +- .../src/context/variables/variable.h | 4 +- parser_library/src/diagnosable_ctx.h | 10 +- parser_library/src/diagnosable_impl.h | 2 +- parser_library/src/diagnostic.cpp | 82 + parser_library/src/diagnostic.h | 36 +- parser_library/src/diagnostic_adder.cpp | 50 + parser_library/src/diagnostic_adder.h | 49 + .../src/expressions/arithmetic_expression.cpp | 448 -- .../src/expressions/arithmetic_expression.h | 82 - .../src/expressions/character_expression.cpp | 727 --- .../src/expressions/character_expression.h | 183 - .../conditional_assembly/ca_expr_policy.cpp | 405 ++ .../conditional_assembly/ca_expr_policy.h | 259 + .../conditional_assembly/ca_expression.cpp | 41 + .../conditional_assembly/ca_expression.h | 81 + .../ca_operator_binary.cpp | 310 ++ .../conditional_assembly/ca_operator_binary.h | 129 + .../ca_operator_unary.cpp | 130 + .../conditional_assembly/ca_operator_unary.h | 85 + .../terms/ca_constant.cpp | 90 + .../conditional_assembly/terms/ca_constant.h | 56 + .../terms/ca_expr_list.cpp | 253 + .../conditional_assembly/terms/ca_expr_list.h | 68 + .../terms/ca_function.cpp | 693 +++ .../conditional_assembly/terms/ca_function.h | 98 + .../conditional_assembly/terms/ca_string.cpp | 137 + .../conditional_assembly/terms/ca_string.h | 59 + .../conditional_assembly/terms/ca_symbol.cpp | 57 + .../conditional_assembly/terms/ca_symbol.h | 44 + .../terms/ca_symbol_attribute.cpp | 258 + .../terms/ca_symbol_attribute.h | 63 + .../conditional_assembly/terms/ca_var_sym.cpp | 102 + .../conditional_assembly/terms/ca_var_sym.h | 53 + .../src/expressions/evaluation_context.h | 19 +- parser_library/src/expressions/expression.cpp | 203 - parser_library/src/expressions/expression.h | 171 - .../src/expressions/keyword_expression.cpp | 100 - .../src/expressions/keyword_expression.h | 104 - .../src/expressions/logic_expression.cpp | 224 - .../src/expressions/logic_expression.h | 92 - .../src/expressions/mach_expr_term.cpp | 13 +- .../src/expressions/numeric_wrapper.h | 75 - .../visitors/expression_analyzer.cpp | 216 - .../visitors/expression_analyzer.h | 56 - .../visitors/expression_evaluator.cpp | 589 --- .../visitors/expression_evaluator.h | 104 - .../src/parsing/grammar/ca_expr_rules.g4 | 258 +- .../src/parsing/grammar/ca_operand_rules.g4 | 25 +- .../src/parsing/grammar/hlasmparser.g4 | 28 +- .../src/parsing/grammar/label_field_rules.g4 | 86 +- .../src/parsing/grammar/machine_expr_rules.g4 | 61 +- .../parsing/grammar/macro_operand_rules.g4 | 30 +- .../parsing/grammar/model_operand_rules.g4 | 26 +- parser_library/src/parsing/parser_impl.cpp | 161 +- parser_library/src/parsing/parser_impl.h | 7 +- .../src/processing/context_manager.cpp | 209 +- .../src/processing/context_manager.h | 50 +- .../instruction_sets/ca_processor.cpp | 66 +- .../instruction_sets/ca_processor.h | 110 +- .../instruction_sets/instruction_processor.h | 2 +- .../low_language_processor.cpp | 18 +- .../instruction_sets/low_language_processor.h | 2 +- .../instruction_sets/macro_processor.cpp | 216 +- .../instruction_sets/macro_processor.h | 17 + .../statement_processors/empty_processor.cpp | 2 +- .../lookahead_processor.cpp | 2 +- .../macrodef_processor.cpp | 117 +- .../statement_processors/macrodef_processor.h | 10 + .../ordinary_processor.cpp | 5 +- .../macro_statement_provider.h | 1 + parser_library/src/semantics/collector.cpp | 5 +- .../src/semantics/concatenation.cpp | 194 +- parser_library/src/semantics/concatenation.h | 105 +- .../src/semantics/concatenation_term.cpp | 86 + .../src/semantics/concatenation_term.h | 75 + .../src/semantics/highlighting_info.h | 1 - .../src/semantics/lsp_info_processor.cpp | 2 +- parser_library/src/semantics/operand.cpp | 54 +- parser_library/src/semantics/operand.h | 18 +- .../src/semantics/variable_symbol.cpp | 96 + .../src/semantics/variable_symbol.h | 84 + .../src/workspaces/processor_file_impl.cpp | 2 +- .../src/workspaces/processor_file_impl.h | 2 - parser_library/test/common_testing.h | 1 - parser_library/test/context/context_test.cpp | 12 +- .../test/context/data_attribute_test.cpp | 38 +- .../arithmetic_expression_test.cpp | 234 + .../test/expressions/ca_constant_test.cpp | 76 + .../test/expressions/ca_expr_list_test.cpp | 180 + .../test/expressions/ca_function_test.cpp | 315 ++ .../test/expressions/ca_operator_test.cpp | 171 + .../test/expressions/ca_string_test.cpp | 115 + .../expressions/ca_symbol_attribute_test.cpp | 100 + .../test/expressions/ca_symbol_test.cpp | 48 + .../test/expressions/ca_var_sym_test.cpp | 61 + .../expressions/character_expression_test.cpp | 138 + parser_library/test/expressions/expr_mocks.h | 58 + .../expressions/logical_expression_test.cpp | 213 + parser_library/test/lexing/lexer_test.cpp | 11 +- parser_library/test/parsing/parser_test.cpp | 26 - .../test/processing/ca_instr_test.cpp | 32 +- parser_library/test/processing/dc_test.cpp | 2 +- .../test/processing/lookahead_test.cpp | 32 +- .../test/res/input/expression_test.in | 172 - .../test/res/output/expression_test.output | Bin 981 -> 0 bytes .../test/semantics/concatenation_test.cpp | 86 + 146 files changed, 7052 insertions(+), 17452 deletions(-) create mode 100644 parser_library/src/diagnostic_adder.cpp create mode 100644 parser_library/src/diagnostic_adder.h delete mode 100644 parser_library/src/expressions/arithmetic_expression.cpp delete mode 100644 parser_library/src/expressions/arithmetic_expression.h delete mode 100644 parser_library/src/expressions/character_expression.cpp delete mode 100644 parser_library/src/expressions/character_expression.h create mode 100644 parser_library/src/expressions/conditional_assembly/ca_expr_policy.cpp create mode 100644 parser_library/src/expressions/conditional_assembly/ca_expr_policy.h create mode 100644 parser_library/src/expressions/conditional_assembly/ca_expression.cpp create mode 100644 parser_library/src/expressions/conditional_assembly/ca_expression.h create mode 100644 parser_library/src/expressions/conditional_assembly/ca_operator_binary.cpp create mode 100644 parser_library/src/expressions/conditional_assembly/ca_operator_binary.h create mode 100644 parser_library/src/expressions/conditional_assembly/ca_operator_unary.cpp create mode 100644 parser_library/src/expressions/conditional_assembly/ca_operator_unary.h create mode 100644 parser_library/src/expressions/conditional_assembly/terms/ca_constant.cpp create mode 100644 parser_library/src/expressions/conditional_assembly/terms/ca_constant.h create mode 100644 parser_library/src/expressions/conditional_assembly/terms/ca_expr_list.cpp create mode 100644 parser_library/src/expressions/conditional_assembly/terms/ca_expr_list.h create mode 100644 parser_library/src/expressions/conditional_assembly/terms/ca_function.cpp create mode 100644 parser_library/src/expressions/conditional_assembly/terms/ca_function.h create mode 100644 parser_library/src/expressions/conditional_assembly/terms/ca_string.cpp create mode 100644 parser_library/src/expressions/conditional_assembly/terms/ca_string.h create mode 100644 parser_library/src/expressions/conditional_assembly/terms/ca_symbol.cpp create mode 100644 parser_library/src/expressions/conditional_assembly/terms/ca_symbol.h create mode 100644 parser_library/src/expressions/conditional_assembly/terms/ca_symbol_attribute.cpp create mode 100644 parser_library/src/expressions/conditional_assembly/terms/ca_symbol_attribute.h create mode 100644 parser_library/src/expressions/conditional_assembly/terms/ca_var_sym.cpp create mode 100644 parser_library/src/expressions/conditional_assembly/terms/ca_var_sym.h delete mode 100644 parser_library/src/expressions/expression.cpp delete mode 100644 parser_library/src/expressions/expression.h delete mode 100644 parser_library/src/expressions/keyword_expression.cpp delete mode 100644 parser_library/src/expressions/keyword_expression.h delete mode 100644 parser_library/src/expressions/logic_expression.cpp delete mode 100644 parser_library/src/expressions/logic_expression.h delete mode 100644 parser_library/src/expressions/numeric_wrapper.h delete mode 100644 parser_library/src/expressions/visitors/expression_analyzer.cpp delete mode 100644 parser_library/src/expressions/visitors/expression_analyzer.h delete mode 100644 parser_library/src/expressions/visitors/expression_evaluator.cpp delete mode 100644 parser_library/src/expressions/visitors/expression_evaluator.h create mode 100644 parser_library/src/semantics/concatenation_term.cpp create mode 100644 parser_library/src/semantics/concatenation_term.h create mode 100644 parser_library/src/semantics/variable_symbol.cpp create mode 100644 parser_library/src/semantics/variable_symbol.h create mode 100644 parser_library/test/expressions/arithmetic_expression_test.cpp create mode 100644 parser_library/test/expressions/ca_constant_test.cpp create mode 100644 parser_library/test/expressions/ca_expr_list_test.cpp create mode 100644 parser_library/test/expressions/ca_function_test.cpp create mode 100644 parser_library/test/expressions/ca_operator_test.cpp create mode 100644 parser_library/test/expressions/ca_string_test.cpp create mode 100644 parser_library/test/expressions/ca_symbol_attribute_test.cpp create mode 100644 parser_library/test/expressions/ca_symbol_test.cpp create mode 100644 parser_library/test/expressions/ca_var_sym_test.cpp create mode 100644 parser_library/test/expressions/character_expression_test.cpp create mode 100644 parser_library/test/expressions/expr_mocks.h create mode 100644 parser_library/test/expressions/logical_expression_test.cpp delete mode 100644 parser_library/test/res/input/expression_test.in delete mode 100644 parser_library/test/res/output/expression_test.output create mode 100644 parser_library/test/semantics/concatenation_test.cpp diff --git a/benchmark/benchmark.cpp b/benchmark/benchmark.cpp index a7d9069c9..a34fc3b87 100644 --- a/benchmark/benchmark.cpp +++ b/benchmark/benchmark.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include "json.hpp" diff --git a/docs/Analyzer-pages/Expressions.md b/docs/Analyzer-pages/Expressions.md index 2cca81cdd..ba90d2e92 100644 --- a/docs/Analyzer-pages/Expressions.md +++ b/docs/Analyzer-pages/Expressions.md @@ -4,61 +4,52 @@ HLASM differentiates two kinds of expressions: *Conditional Assembly* (CA) and * HLASM evaluates CA expressions during assembly generation. For further details, refer to the [[HLASM overview]]. -We employ the ANTLR 4 Parse-Tree Visitors during the expression evaluation. For further detail on ANTLR, refer to [[Third party libraries]] - The HLASM CA expression is conceptually similar to expressions in other languages: they support unary and binary operators, functions, variables and literals. In HLASM, each expression has a type. *Arithmetic*, *Logic*, *Character* expressions are supported. We implement the logic in the following classes: -`expression` -A pure virtual class that defines a shared interface, operators, and functions. The class also implements evaluation logic for terms and factors. - -`diagnostic_op` -The concept of *diagnostics* is fundamental. During the evaluation of an expression, an error can occur (syntactic or semantic). Hence, we try to improve the user experience by reporting diagnostics. Each instance of `expression` has a pointer to `diagnostic_op` associated to it. If the pointer is `null`, it is considered error-free. During the evaluation of a child expression, the parent checks for errors and propagates the error upwards. The checks and propagation are implemented by the `copy_return_on_error` macro, which must be called immediately before the creation of a new expression during evaluation. - -The `expression` class implements the evaluation as follows: A `std::deque` of `expression` pointers is passed. The evaluation iterates the list from left to right. Functions, binary, and unary operators consume the rest of the deque. +- `ca_expression` +A pure virtual class that defines a shared interface, operators, and functions. -Some expression symbols can be either HLASM keywords or variable identifiers (see the example below). Therefore, the resolution of symbols is complicated and cannot be done straight, but instead during the evaluation time. The order of the expression’s terms and the previous evaluation context is crucial for disambiguation. - - - name operation operands - - AND EQU 1 - NOT EQU 0 - AIF (NOT AND AND AND).LAB <- EVALUATES TO (!1 & 1) +- `ca_unary_operator` and `ca_binary_operator` +These virtual classes provide a point of inheritance for specialized classes that represent binary and unary operators that are found in HLASM. There are basic arithmetic operators (e.g. plus, minus) or function operators (e.g. `NOT`, `SLL`). -- `keyword_expression` -Helper class that represents HLASM keywords in expressions. It determines a keyword type from a string, containing its arity (unary, binary) and priority. +- Term classes `ca_function`, `ca_constant`, `ca_string`, `ca_symbol`, `ca_symbol_attribute`, `ca_var_sym` +These classes all inherit from the `ca_expression` class. Each of them represents a term that can be used in HLASM conditional assembly expressions. +The following examples show the usage of each class: -- `logic_expression` -Represents a boolean expression. + | Class | Examples of terms they represent | + |:------------------------|:----------------------------------| + | `ca_function` | `FIND('abc','d')`, `DCLEN('abcd')`| + | `ca_constant` | `42`, `C'A'` | + | `ca_string` | `'abc'`, `'**findme**'(3,*)` | + | `ca_symbol` | `R1` | + | `ca_symbol_attribute` | `L'DC_HALF`, `T'&VAR` | + | `ca_var_sym` | `&VAR`, `&VAR(1,2,3)` | -- `arithmetic_expression` -Represents an arithmetic expression. +- `ca_expr_list` +This is the class that holds a list of instantiated objects of the above stated classes. +In logical expressions, some symbols can be either expression operators or ordinary symbol identifiers (see the example below). Therefore, the resolution of symbols can be complicated and cannot be done straight during parsing. This class holds the list of the terms that contributed to the logical expressions and contains an algorithm that disambiguates the expression (from the example logical expression `(NOT AND AND AND)`, the object of this class would hold four `ca_symbol` objects, one `NOT` and three `AND`s. -- `arithmetic_logic_expr_wrapper` -HLASM language supports expressions with operands of mixed types. For more straightforward and readable use of arithmetic and logical expressions, this class wraps them under one class. + + AND EQU 1 + AIF (NOT AND AND AND).LAB <- EVALUATES TO (!1 & 1) -- `character_expression` -Represents a character expression. +- `ca_expr_policies` +Static classes that provide useful information about each built-in function (e.g. return type, number of parameters) and operators. The classes are divided into arithmetic, logical and character because some operators have different meanings in different types of expressions (like logical and arithmetic `AND`). - `ebcdic_encoding` -This class defines a custom EBCDIC literal and provides helper functions for conversion between EBCDIC and ASCII. EBCDIC is a character encoding used on IBM mainframes. It has a different layout to ASCII. +This class defines a custom EBCDIC literal and provides helper functions for conversion between EBCDIC and ASCII. EBCDIC is a character encoding used on IBM mainframes. It has a different layout to ASCII. EBCDIC layout. Taken from https://i.stack.imgur.com/h3u5A.png. -- `error_messages` -A static class with a list of all `diagnostic_op`s that can be generated from expressions. - -## CA expression evaluation - -In the previous section, we described the representation of the CA expressions themselves. In this section, we explain the coupling of CA expressions with grammar. - -The `expression_evaluator` encapsulates the coupling logic between the grammar and the expression logic. That is, the evaluator has a notion about grammar, which translates into C++ expression logic. +## Resolution and evaluation of CA expressions -The top-level expression first gathers a list of space-separated expressions. The evaluation must be done using a list from left to right (not using a tree) as any token may be a keyword (such as the operator `AND`) or variable identifier, depending on the position in an expression (using language keywords as identifiers is allowed in HLASM). `expression::evaluate` provides the disambiguation. +To evaluate a CA expression, the expression object has to be resolved once. Each class overrides the `resolve_expression` method which typically checks whether it has the correct number of fields and that the fields are of the correct type. The `ca_expr_list` class does the most of the resolving work. +It contains an algorithm that creates an expression tree from its list of expression terms. This tree is then used for further evaluation. -During its work, the evaluator substitutes variable and ordinary symbols for their values. To know which values to substitute, the evaluator is given *evaluation context*. This consists of objects that are required for correct evaluation: *HLASM context* for symbol values, *attribute provider* for values of symbol attributes that are not yet defined and *library provider* for evaluation of some types of symbol attributes. +When an expression was resolved once, it can be properly evaluated. +During the evaluation, variable and ordinary symbols are substituted for their values. To determine which values to substitute, the `evaluate` method is given *evaluation context*. This consists of objects that are required for correct evaluation: *HLASM context* for symbol values, *attribute provider* for values of symbol attributes that are not yet defined and *library provider* for evaluation of some types of symbol attributes. -Lookahead is triggered in conditional assembly expressions when evaluation visits a yet undefined ordinary symbol. As this might be a rather demanding operation, the expression evaluator uses *expression analyzer*. It looks for all the undefined symbol references in the expression and collects them in a common collection. Then, the lookahead is triggered to look for all references in the collection. Hence, it is triggered once per expression rather than any time an undefined symbol reference is found. +Lookahead is triggered in conditional assembly expressions when an evaluation visits a yet undefined ordinary symbol. As this might be a rather demanding operation, the `ca_expression` class contains the method `get_undefined_attributed_symbols`. It looks for all the undefined symbol references in the expression and collects them in a common collection. Then, the lookahead can be triggered to look for all references in the collection. Hence, it is triggered once per expression rather than any time an undefined symbol reference is found. # Machine expressions @@ -70,16 +61,16 @@ We use a standard infix tree representation of expressions. There is an interfac - `mach_expr_symbol` represents an ordinary symbol. -- `mach_expr_data_attr` represents an attribute of a symbol (e.g. `L’SYM` is length of symbol `SYM`) +- `mach_expr_data_attr` represents an attribute of a symbol (e.g. `L'SYM` is length of symbol `SYM`) - `mach_expr_location_counter` represents a location counter represented by an asterisk in expressions. -- `mach_expr_self_def` represents a self defining term (e.g. `X’1F’`) +- `mach_expr_self_def` represents a self defining term (e.g. `X'1F'`) The following example shows a representation for one specific expression. -Example representation of the machine expression (A-4)+L’B. +Example representation of the machine expression (A-4)+L'B. Machine expressions can also evaluate the expressions they represent. The evaluation is done in a recursive manner. It is fairly simple when there are no symbols used in the expression — each node in the tree computes the result with basic arithmetic operations. -However, the process can get tricky since expressions might contain e.g. `mach_expr_symbol`, whose value is dependant on symbols defined in other parts of source code. Moreover, the result of a machine expression can be an absolute value (a number) or relocatable value (an address). The process of symbol resolution is explained in the *symbol dependency tables* section of [[HLASM context tables]]. \ No newline at end of file +However, the process can get tricky since expressions might contain e.g. `mach_expr_symbol`, whose value is dependant on symbols defined in other parts of source code. Moreover, the result of a machine expression can be an absolute value (a number) or relocatable value (an address). The process of symbol resolution is explained in the *symbol dependency tables* section of [[HLASM context tables]]. diff --git a/docs/Home.md b/docs/Home.md index 64218cb91..3dd8f1ef7 100644 --- a/docs/Home.md +++ b/docs/Home.md @@ -26,4 +26,4 @@ Firstly, in [[HLASM overview]], we briefly explain the basics of HLASM needed t The page [[language server]] describes the responsibilities of the language server as the communication provider between the extension client and the parsing library. The [[workspace manager]] is the entry point to the parsing library used by the language server. The purpose of its sub-components is to handle file management, dependency resolution and parsing. -The core of the processing of a HLASM file is implemented inside the [[analyzer]]. The project also provides macro tracing through the standard debugging procedure and it is fully explained in [[macro tracer]].The last mentioned component is the [[extension|VSCode extension]], which communicates with the language server and provides IDE features to the user. In [[build instructions]], we provide a guide to build this project. +The core of the processing of a HLASM file is implemented inside the [[analyzer]]. The project also provides macro tracing through the standard debugging procedure and it is fully explained in [[macro tracer]]. The last mentioned component is the [[extension|VSCode extension]], which communicates with the language server and provides IDE features to the user. In [[build instructions]], we provide a guide to build this project. diff --git a/docs/img/all_arch.svg b/docs/img/all_arch.svg index 2d5270745..f6c9a2773 100644 --- a/docs/img/all_arch.svg +++ b/docs/img/all_arch.svg @@ -1,4455 +1,3 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +
 Language server
 Language server
 Workspace
 manager
Workspace...
Analyzer
Analyzer
Macro tracer 
Macro tracer 
Machine expressions
Machine expressions
use
use
CA Expressions
CA Expressions
Parser and lexer
Parser and lexer
uses
uses
uses
uses
Processing manager
Processing manager
reads/writes
reads/writes
uses
uses
Dispatcher
Dispatcher
uses
uses
Server
Server
runs
runs
uses
uses
Request manager
Request mana...
LSP communication
(standard IO)
LSP communicati...
DAP communication
(TCP loopback)
DAP communicati...
implements
implements
uses
uses
LSP server
LSP server
Request
Request
implements
implements
uses
uses
DAP server
DAP server
Feature
Feature
implements
implements
LSP feature
LSP feature
LSP feature
LSP feature
use
use
LSP features
LSP features
implements
implements
use
use
DAP features
DAP features
uses
uses
reads/writes
reads/writes
TCP handler
TCP handler
HLASM context
HLASM context
Macro storage
Macro storage
Copy storage
Copy storage
Source stack
Source stack
ID storage
ID storage
uses
uses
Global variable symbol storage
Global variable...
Scope stack
Scope stack
LSP context
LSP context
Processing stack
Processing stack
uses
uses
LSP data
collector
LSP data...
implements
implements
Ordinary assembly context
Ordinary assembly context
has
has
Symbol storage
Symbol stora...
has
has
Section storage
Section stor...
Symbol dependency tables
Symbol depen...
Symbol
Symbol
Value
Value
Attributes
Attributes
Variable symbol
Variable sym...
extends
extends
Macro parameter base
Macro parame...
implements
implements
Positional parameter
Positional p...
implements
implements
Keyword parameter
Keyword para...
implements
implements
System variable
System varia...
extends
extends
SET symbol base
SET symbol b...
SETC symbol
SETC symbol
SETB symbol
SETB symbol
implements
implements
SETA symbol
SETA symbol
Operand
Operand
implements
implements
Empty Operand
Empty Operand
implements
implements
uses
uses
Model Operand
Model Operand
uses
uses
Machine Operand
Machine Oper...
implements
implements
Expression Machine operand
Expression M...
implements
implements
Address Machine operand
Address Mach...
Assembler Operand
Assembler Op...
implements
implements
Expression Assembler operand
Expression A...
uses
uses
USING Assembler operand
USING Assemb...
Complex Assembler operand
Complex Asse...
String Assembler operand
String Assem...
implements
implements
uses
uses
Data Definition Assembler operand
Data Definitio...
extends
extends
uses
uses
Conditional Assembly Operand
Conditional...
implements
implements
Variable symbol CA operand
Variable sym...
Sequnece symbol CA operand
Sequnece sym...
Branch CA operand
Branch CA op...
implements
implements
Expression CA operand
Expression C...
implements
implements
Macro Operand
Macro Operand
Evaluable Operand
Evaluable Op...
uses
uses
implements
implements
Debugger
Debugger
Processor tracer
Processor tracer
Variable
Variable
implements
implements
uses
uses
Ordinary symbol variable
Ordinary symbol...
implements
implements
Set symbol variable
Set symbol vari...
implements
implements
uses
uses
Macro parameter  variable
Macro parameter...
implements
implements
Attribute variable
Attribute varia...
uses
uses
implements
implements
implements
implements
generates
generates
uses
uses
uses
uses
Parser
Parser
uses
uses
Token stream
Token stream
uses
uses
uses
uses
uses
uses
Lexer
Lexer
Input Source
Input Source
Instruction format validation
Instruction format validation
uses
uses
uses
uses
Processing Manager
Processing M...
Statement Processors
Statement Pr...
Statement Provider
Statement Pr...
implements
implements
Opencode statement Provider
Opencode sta...
implements
implements
Copy statement Provider
Copy stateme...
implements
implements
Macro statement Provider
Macro statem...
implements
implements
uses
uses
Lookahead Processor
Lookahead Pr...
implements
implements
Macro definition Processor
Macro defini...
implements
implements
notifies
notifies
Opencode Processor
Opencode Pro...
implements
implements
Copy definition Processor
Copy definit...
Instruction Processors
Instruction...
implements
implements
uses
uses
Conditional Assembly IP
Conditional...
uses
uses
Machine instruction checker
Machine inst...
implements
implements
uses
uses
Assembler
IP
Assembler...
Assembler instruction checker
Assembler in...
implements
implements
Macro IP
Macro IP
implements
implements
uses
uses
uses
uses
Machine IP
Machine IP
holds
holds
uses
uses
uses
uses
Workspace manager
Workspace manager
holds
holds
holds
holds
File manager
File manager
File
File
extends
extends
Processor file
Processor file
uses
uses
uses
uses
implements
implements
Workspace
Workspace
uses
uses
uses
uses
uses
uses
Analyzer
Analyzer
uses
uses
Library
Library
uses
uses
implements
implements
Local library
Local library
Parse library provider
Parse library p...
uses
uses
Processor group
Processor group
Token
Token
Statement fields parser
Statement fi...
uses
uses
creates
creates
Token factory
Token factory
Statement
Statement
uses
uses
Collector
Collector
uses
uses
Machine expression
Machine expression
uses
uses
uses
uses
evaluates
evaluates
Expression evaluator
Expression eva...
CA expression
CA expression
implements
implements
CAE symbol
CAE symbol
CAE symbol attribute
CAE symbol at...
CAE function
CAE function
CAE variable symbol
CAE variable...
ME constant
ME constant
implements
implements
ME data attribute
ME data attribu...
implements
implements
ME symbol
ME symbol
implements
implements
ME
 self defining term
ME...
ME operator
ME operator
uses
uses
uses
uses
Data definition
Data definition
Nominal value
Nominal value
Data definition types
Data definit...
Concatenation
Concatenation
Section
Section
Location counter storage
Location cou...
Dependency solver
Dependency s...
reads/writes
reads/writes
reads/writes
reads/writes
uses
uses
Visual Studio Code
Visual Studio Code
Extension
Extension
Diagnosable
Diagnosable
uses
uses
CAE constant
CAE constant
implements
implements
uses
uses
CAE expression list
CAE expressio...
CAE string
CAE string
CAE policy
CAE policy
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/img/analyzer_arch.svg b/docs/img/analyzer_arch.svg index af93cf1ff..2b0dbedc6 100644 --- a/docs/img/analyzer_arch.svg +++ b/docs/img/analyzer_arch.svg @@ -1,209 +1,3 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +
Analyzer
Analyzer
Processing
manager
Processing...
HLASM
context tables
HLASM...
LSP data
collector
LSP data...
Lexer - Parser
components
Lexer - Parser...
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/img/diagnosable_hierarchy.svg b/docs/img/diagnosable_hierarchy.svg index a94a976d0..a2a9e86b6 100644 --- a/docs/img/diagnosable_hierarchy.svg +++ b/docs/img/diagnosable_hierarchy.svg @@ -1,316 +1,3 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +
Workspace manager
Workspace manag...
Workspace
Workspace
Workspace
Workspace
Workspace
Workspace
File manager
File manager
Processor file
Processor file
...
...
Processor file
Processor file
Processor file
Processor file
...
...
Analyzer
Analyzer
Analyzer
Analyzer
Analyzer
Analyzer
...
...
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/img/hlasm_architecture.svg b/docs/img/hlasm_architecture.svg index 138857b41..f8f263516 100644 --- a/docs/img/hlasm_architecture.svg +++ b/docs/img/hlasm_architecture.svg @@ -1,571 +1,3 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +
Language server
Chapter 4
Language server...
Editor or IDE (e.g. VS Code)
Editor or IDE (e.g. V...
Parser library
Parser library
Workspace manager
Chapter 5
Workspace manager...
HLASM Plugin extension
Chapter 8
HLASM Plugin ext...
LSP extension
LSP extension
Macro tracer
Chapter 7
Macro tracer...
DAP
DAP
Components of HLASM Plugin
Components of HL...
Third party software
Third party softwa...
LSP
LSP
Analyzer
Chapter 6
Analyzer...
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/img/hover_sequence.svg b/docs/img/hover_sequence.svg index b65ff6fa1..1085f08eb 100644 --- a/docs/img/hover_sequence.svg +++ b/docs/img/hover_sequence.svg @@ -1,1379 +1,3 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +
Request manager
Request manager
cond_var.notify_one()
cond_var.notify_one()
LSP server
LSP server
Feature: Language features
Feature: Languag...
Workspace manager
Workspace manager
Dispatcher
Dispatcher
hover(file_name, position)
hover(file_name, position)
respond(message_id,args)
respond(message_id,args)
return
return
hover(message_id,
 json_args)
hover(message_id,...
add_request(server, json)
add_request(server, json)
read input
read input
Content-Length: 47

{"jsonrpc":"2.0",
"id":1,
"method":"textDocum
ent/hover",
"params:{...}}
Content-Length: 47...
return
return
message_received(json)
message_received(json)
return
return
{"jsonrpc":"2.0",
"id":1,
"method":"textDocum
ent/hover",
"params":{...}}
{"jsonrpc":"2.0",...
{"jsonrpc":"2.0",
"id":1,
"method":"textDocum
ent/hover",
"params":{...}}
{"jsonrpc":"2.0",...
message_id = 1,
args = {"textDocument":{"uri":"file://c:/file.asm"},
"position":{"line":24,"character":31}
message_id = 1,...
file_name = "C:\file.asm"
position = {24, 31}
file_name = "C:\file.a...
write_message(json)
write_message(json)
message_id = 1,
args = {"contents":
"hover message"}
message_id = 1,...
write output
write output
return
return
{"jsonrpc":"2.0",
"id":1,
"result":{"contents":
"hover message"}}
{"jsonrpc":"2.0",...
Content-Length: 63

{"jsonrpc":"2.0",
"id":1,
"result":{"contents":
"hover message"}}
Content-Length: 63...
return
return
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/img/lang_detection.svg b/docs/img/lang_detection.svg index ef4d8ad2b..2ca7685d8 100644 --- a/docs/img/lang_detection.svg +++ b/docs/img/lang_detection.svg @@ -1,450 +1,3 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +
Does the file contain 'MACRO' one the first line?
Does the file contain 'M...
NO
NO
Is it a program?
Is it a program?
NO
NO
Is it a library defined in processor group?
Is it a library defined...
NO
NO
Does it suffice any of the wildcards?
Does it suffice any of t...
NO
NO
Does it contain enough HLASM lines?
Does it contain enough H...
NO
NO
Not HLASM
Not HLASM
HLASM
HLASM
YES
YES
YES
YES
YES
YES
YES
YES
YES
YES
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/img/lang_server.svg b/docs/img/lang_server.svg index 4997ff960..769ebface 100644 --- a/docs/img/lang_server.svg +++ b/docs/img/lang_server.svg @@ -1,563 +1,3 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +
reads/writes
reads/writes
uses
uses
Dispatcher
Dispatcher
Parser library
Parser library
uses
uses
Server
Server
runs
runs
uses
uses
Request manager
Request mana...
LSP communication
(standard IO)
LSP communicati...
DAP communication
(TCP loopback)
DAP communicati...
implements
implements
uses
uses
LSP server
LSP server
Request
Request
implements
implements
uses
uses
DAP server
DAP server
Feature
Feature
implements
implements
LSP feature
LSP feature
LSP feature
LSP feature
use
use
LSP features
LSP features
implements
implements
use
use
DAP features
DAP features
uses
uses
TCP handler
TCP handler
wraps
wraps
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/img/lexer_arch.svg b/docs/img/lexer_arch.svg index 57e473909..95bb106f8 100644 --- a/docs/img/lexer_arch.svg +++ b/docs/img/lexer_arch.svg @@ -1,350 +1,3 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +
token
token
token
token
emits
emits
token_factory
token_factory
input_source
(AINSERT buffer)
input_source...
inputs
inputs
input_source
(main source)
input_source...
calls
calls
AINSERT
AINSERT
lexer
lexer
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/img/lsp_addition.svg b/docs/img/lsp_addition.svg index 8af957366..17a6a1e4a 100644 --- a/docs/img/lsp_addition.svg +++ b/docs/img/lsp_addition.svg @@ -1,363 +1,3 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +
Language Client
Language Client
LSP
LSP
Standard LSP features
Standard LSP features
hlasmSemanticHighlighting
hlasmSemanticHighlighting
hover
hover
references
refere...
...
...
continuation info
continuation info
semanticHighlighting
semanticHighlighting
Language Server
Language Server
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/img/mach_expr_example.svg b/docs/img/mach_expr_example.svg index b430ac88e..1ef928c15 100644 --- a/docs/img/mach_expr_example.svg +++ b/docs/img/mach_expr_example.svg @@ -1,366 +1,3 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +
mach_expr_binary<add>
(A-4)+L'B
mach_expr_binary<add>...
Expression: (A-4)+L'B

Representation:
Expression: (A-4)+L'B...
mach_expr_data_attr
L'B
mach_expr_data_attr...
mach_expr_binary<sub>
A-4
mach_expr_binary<sub>...
mach_expr_symbol
A
mach_expr_symbol...
mach_expr_constant
4
mach_expr_constant...
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/img/macro_tracer_arch.svg b/docs/img/macro_tracer_arch.svg index c1aefcdbb..d7a0a7c8a 100644 --- a/docs/img/macro_tracer_arch.svg +++ b/docs/img/macro_tracer_arch.svg @@ -1,518 +1,3 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +
implements
implements
uses
uses
uses
uses
uses
uses
Debugger
Debugger
Processor tracer
Processor tracer
notifies
notifies
Analyzer
Analyzer
Variable
Variable
implements
implements
uses
uses
Set symbol variable
Set symbol vari...
implements
implements
uses
uses
Ordinary symbol variable
Ordinary symbol...
implements
implements
uses
uses
Macro parameter  variable
Macro parameter...
implements
implements
Attribute variable
Attribute varia...
Context
Context
Debug event consumer
Debug event con...
implements
implements
Language server
Language server
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/img/operand_arch.svg b/docs/img/operand_arch.svg index 893c3b5c3..4187d24fb 100644 --- a/docs/img/operand_arch.svg +++ b/docs/img/operand_arch.svg @@ -1,643 +1,3 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +
Operand
Operand
Empty Operand
Empty Operand
Model Operand
Model Operand
Machine Operand
Machine Operand
Expression Machine operand
Expression Mac...
Address Machine operand
Address Machin...
Assembler Operand
Assembler Oper...
Expression Assembler operand
Expression Ass...
USING Assembler operand
USING Assemble...
Complex Assembler operand
Complex Assemb...
String Assembler operand
String Assembl...
Data Definition Assembler operand
Data Definitio...
Conditional Assembly Operand
Conditional As...
Variable symbol CA operand
Variable symbo...
Sequnece symbol CA operand
Sequnece symbo...
Branch CA operand
Branch CA oper...
Expression CA operand
Expression CA...
Macro Operand
Macro Operand
Evaluable Operand
Evaluable Oper...
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/img/ord_ctx_arch.svg b/docs/img/ord_ctx_arch.svg index 2d52ca304..31624abb4 100644 --- a/docs/img/ord_ctx_arch.svg +++ b/docs/img/ord_ctx_arch.svg @@ -1,281 +1,3 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +
Section
Section
Ordinary assembly context
Ordinary assembly context
has
has
Symbol storage
Symbol storage
has
has
Section storage
Section storage
Symbol dependency tables
Symbol dependency ta...
Location counter storage
Location counter sto...
Symbol
Symbol
Value
Value
Attributes
Attributes
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/img/org_diagram.svg b/docs/img/org_diagram.svg index 3a446f6f9..65959aa56 100644 --- a/docs/img/org_diagram.svg +++ b/docs/img/org_diagram.svg @@ -1,178 +1,3 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +
symbol
symbol
ORG
ORG
expression
expression
,
,
boundary
boundary
,offset
,offset
,offset
,offset
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/img/parser_lexer_arch.svg b/docs/img/parser_lexer_arch.svg index 283e20a10..038852e45 100644 --- a/docs/img/parser_lexer_arch.svg +++ b/docs/img/parser_lexer_arch.svg @@ -1,152 +1,3 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +
uses
uses
Parser
Parser
uses
uses
Token stream
Token stream
uses
uses
Lexer
Lexer
Input Source
Input Source
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/img/process_next.svg b/docs/img/process_next.svg index f0882a400..c816440e1 100644 --- a/docs/img/process_next.svg +++ b/docs/img/process_next.svg @@ -1,449 +1,3 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +
Statement Processor
Statement Proces...
Statement Provider
Statement Provid...
process_next
process_next
Processing Manager
Processing Manag...
read instruction
field
read instruction...
get_processing_status(
instruction field)
get_processing_status(...
return
return
process_statement(
statement)
process_statement(...
return
return
return
return
return
return
retrieve statement
using processing status
retrieve statement...
return
return
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/img/processing_manager_arch.svg b/docs/img/processing_manager_arch.svg index cea10e737..a31ab2d20 100644 --- a/docs/img/processing_manager_arch.svg +++ b/docs/img/processing_manager_arch.svg @@ -1,774 +1,3 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +
Instruction format validation
Instruction format validation
uses
uses
uses
uses
Processing Manager
Processing Man...
Statement Processors
Statement Proc...
Statement Provider
Statement Prov...
implements
implements
Opencode statement Provider
Opencode state...
implements
implements
Copy statement Provider
Copy statement...
implements
implements
Macro statement Provider
Macro statemen...
implements
implements
uses
uses
Opencode Processor
Opencode Proce...
implements
implements
Macro definition Processor
Macro definiti...
implements
implements
Lookahead Processor
Lookahead Proc...
implements
implements
Copy definition Processor
Copy definitio...
Instruction Processors
Instruction Pr...
implements
implements
uses
uses
Machine IP
Machine IP
Machine instruction checker
Machine instru...
implements
implements
uses
uses
Assembler
IP
Assembler...
Assembler instruction checker
Assembler inst...
implements
implements
Macro IP
Macro IP
implements
implements
Conditional Assembly IP
Conditional As...
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/img/variable_arch.svg b/docs/img/variable_arch.svg index aebda7519..daf7ceb5e 100644 --- a/docs/img/variable_arch.svg +++ b/docs/img/variable_arch.svg @@ -1,292 +1,3 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +
Variable symbol
Variable symbol
Macro parameter base
Macro paramete...
Positional parameter
Positional par...
Keyword parameter
Keyword parame...
System variable
System variable
SET symbol base
SET symbol base
SETC symbol
SETC symbol
SETB symbol
SETB symbol
SETA symbol
SETA symbol
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/img/ws_mngr_arch.svg b/docs/img/ws_mngr_arch.svg index a8478466d..7f9f7771f 100644 --- a/docs/img/ws_mngr_arch.svg +++ b/docs/img/ws_mngr_arch.svg @@ -1,432 +1,3 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +
holds
holds
uses
uses
Workspace manager
Workspace manager
holds
holds
holds
holds
File manager
File manager
File
File
extends
extends
Processor file
Processor file
implements
implements
uses
uses
uses
uses
Workspace
Workspace
uses
uses
Analyzer
Analyzer
uses
uses
Library
Library
implements
implements
uses
uses
Local library
Local library
Parse library provider
Parse library prov...
uses
uses
Processor group
Processor group
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/parser_library/CMakeLists.txt b/parser_library/CMakeLists.txt index b2ffd633a..7997c2c97 100644 --- a/parser_library/CMakeLists.txt +++ b/parser_library/CMakeLists.txt @@ -21,10 +21,6 @@ set(GENERATED_FOLDER ${CMAKE_BINARY_DIR}/generated_parser/) #generated grammar source files set(GENERATED_SRC ${GENERATED_FOLDER}/hlasmparser.cpp - ${GENERATED_FOLDER}/hlasmparserBaseListener.cpp - ${GENERATED_FOLDER}/hlasmparserBaseVisitor.cpp - ${GENERATED_FOLDER}/hlasmparserListener.cpp - ${GENERATED_FOLDER}/hlasmparserVisitor.cpp ) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") @@ -42,7 +38,7 @@ add_custom_command(OUTPUT ${GENERATED_SRC} COMMAND ${CMAKE_COMMAND} -E make_directory ${GENERATED_FOLDER} COMMAND - "${Java_JAVA_EXECUTABLE}" -jar ${ANTLR_JAR_LOCATION} -Werror -Dlanguage=Cpp -lib ${PROJECT_SOURCE_DIR}/src/parsing/grammar/ -visitor -o ${GENERATED_FOLDER}/ -package hlasm_plugin::parser_library::parsing hlasmparser.g4 + "${Java_JAVA_EXECUTABLE}" -jar ${ANTLR_JAR_LOCATION} -Werror -Dlanguage=Cpp -lib ${PROJECT_SOURCE_DIR}/src/parsing/grammar/ -o ${GENERATED_FOLDER}/ -package hlasm_plugin::parser_library::parsing hlasmparser.g4 WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/src/parsing/grammar/" DEPENDS antlr4jar ${GRAMMAR_SRC} ${PROJECT_SOURCE_DIR}/src/parsing/grammar/lex.tokens ) diff --git a/parser_library/src/checking/diagnostic_collector.cpp b/parser_library/src/checking/diagnostic_collector.cpp index 84c18dacf..60da17171 100644 --- a/parser_library/src/checking/diagnostic_collector.cpp +++ b/parser_library/src/checking/diagnostic_collector.cpp @@ -18,14 +18,13 @@ namespace hlasm_plugin::parser_library { -diagnostic_collector::diagnostic_collector(diagnosable_ctx* diagnoser, context::processing_stack_t location_stack) +diagnostic_collector::diagnostic_collector(const diagnosable_ctx* diagnoser, context::processing_stack_t location_stack) : diagnoser_(diagnoser) , location_stack_(std::move(location_stack)) {} -diagnostic_collector::diagnostic_collector(diagnosable_ctx* diagnoser) +diagnostic_collector::diagnostic_collector(const diagnosable_ctx* diagnoser) : diagnoser_(diagnoser) - , location_stack_(diagnoser->ctx_.processing_stack()) {} diagnostic_collector::diagnostic_collector() @@ -36,7 +35,15 @@ void diagnostic_collector::operator()(diagnostic_op diagnostic) const { if (!diagnoser_) return; - diagnoser_->add_diagnostic_inner(std::move(diagnostic), location_stack_); + diagnoser_->add_diagnostic_inner(std::move(diagnostic), get_location_stack()); +} + +context::processing_stack_t diagnostic_collector::get_location_stack() const +{ + if (location_stack_.empty()) + return diagnoser_->ctx_.processing_stack(); + else + return location_stack_; } } // namespace hlasm_plugin::parser_library \ No newline at end of file diff --git a/parser_library/src/checking/diagnostic_collector.h b/parser_library/src/checking/diagnostic_collector.h index ce1a3d08c..758b06ade 100644 --- a/parser_library/src/checking/diagnostic_collector.h +++ b/parser_library/src/checking/diagnostic_collector.h @@ -29,22 +29,26 @@ class diagnosable_ctx; // used to unify diagnostics collecting for checking objects class diagnostic_collector { - diagnosable_ctx* diagnoser_; + const diagnosable_ctx* diagnoser_; context::processing_stack_t location_stack_; + range diag_range_; public: // constructor with explicit location stack // used for outputing diagnostic of postponed statements - diagnostic_collector(diagnosable_ctx* diagnoser, context::processing_stack_t location_stack); + diagnostic_collector(const diagnosable_ctx* diagnoser, context::processing_stack_t location_stack); // constructor with implicit location stack (aquired from the diagnoser) // used for default statement checking - diagnostic_collector(diagnosable_ctx* diagnoser); + explicit diagnostic_collector(const diagnosable_ctx* diagnoser); // constructor for collector that silences diagnostics diagnostic_collector(); void operator()(diagnostic_op diagnostic) const; + +private: + context::processing_stack_t get_location_stack() const; }; } // namespace hlasm_plugin::parser_library diff --git a/parser_library/src/context/common_types.cpp b/parser_library/src/context/common_types.cpp index e18c39e6b..bd6a27b9a 100644 --- a/parser_library/src/context/common_types.cpp +++ b/parser_library/src/context/common_types.cpp @@ -29,18 +29,18 @@ std::string to_upper_copy(std::string s) { for (auto& c : s) c = static_cast(std::toupper(c)); - return std::move(s); + return s; } SET_t::SET_t(context::A_t value) : a_value(value) - , b_value(object_traits::default_v()) + , b_value(value) , c_value(object_traits::default_v()) , type(SET_t_enum::A_TYPE) {} SET_t::SET_t(context::B_t value) - : a_value(object_traits::default_v()) + : a_value(value) , b_value(value) , c_value(object_traits::default_v()) , type(SET_t_enum::B_TYPE) @@ -53,11 +53,18 @@ SET_t::SET_t(context::C_t value) , type(SET_t_enum::C_TYPE) {} -SET_t::SET_t() +SET_t::SET_t(const char* value) + : a_value(object_traits::default_v()) + , b_value(object_traits::default_v()) + , c_value(value) + , type(SET_t_enum::C_TYPE) +{} + +SET_t::SET_t(SET_t_enum type) : a_value(object_traits::default_v()) , b_value(object_traits::default_v()) , c_value(object_traits::default_v()) - , type(SET_t_enum::UNDEF_TYPE) + , type(type) {} A_t& SET_t::access_a() { return a_value; } @@ -66,4 +73,10 @@ B_t& SET_t::access_b() { return b_value; } C_t& SET_t::access_c() { return c_value; } +const A_t& SET_t::access_a() const { return a_value; } + +const B_t& SET_t::access_b() const { return b_value; } + +const C_t& SET_t::access_c() const { return c_value; } + } // namespace hlasm_plugin::parser_library::context diff --git a/parser_library/src/context/common_types.h b/parser_library/src/context/common_types.h index 2660ed3dc..a39245665 100644 --- a/parser_library/src/context/common_types.h +++ b/parser_library/src/context/common_types.h @@ -102,13 +102,19 @@ struct SET_t SET_t(A_t value); SET_t(B_t value); SET_t(C_t value); - SET_t(); + // for string literals (otherwise they prefer coversion to bool rather than to string) + SET_t(const char* value); + SET_t(SET_t_enum type = SET_t_enum::UNDEF_TYPE); - const SET_t_enum type; + SET_t_enum type; A_t& access_a(); B_t& access_b(); C_t& access_c(); + + const A_t& access_a() const; + const B_t& access_b() const; + const C_t& access_c() const; }; // just mock method for now, will be implemented later with respect to UTF/EBCDIC diff --git a/parser_library/src/context/hlasm_context.cpp b/parser_library/src/context/hlasm_context.cpp index 4a47cce64..a608a2901 100644 --- a/parser_library/src/context/hlasm_context.cpp +++ b/parser_library/src/context/hlasm_context.cpp @@ -15,20 +15,18 @@ #include "hlasm_context.h" #include +#include -#include "diagnosable_impl.h" #include "ebcdic_encoding.h" -#include "expressions/arithmetic_expression.h" +#include "expressions/conditional_assembly/terms/ca_constant.h" #include "instruction.h" -using namespace hlasm_plugin::parser_library; -using namespace hlasm_plugin::parser_library::context; +namespace hlasm_plugin::parser_library::context { code_scope* hlasm_context::curr_scope() { return &scope_stack_.back(); } const code_scope* hlasm_context::curr_scope() const { return &scope_stack_.back(); } - hlasm_context::instruction_storage hlasm_context::init_instruction_map() { hlasm_context::instruction_storage instr_map; @@ -337,7 +335,7 @@ std::vector hlasm_context::whole_copy_stack() const return ret; } -void hlasm_plugin::parser_library::context::hlasm_context::fill_metrics_files() +void hlasm_context::fill_metrics_files() { metrics.files = visited_files_.size(); // for each line without '\n' at the end of the files @@ -461,15 +459,16 @@ opcode_t hlasm_context::get_operation_code(id_index symbol) const return value; } -SET_t hlasm_context::get_data_attribute(data_attr_kind attribute, var_sym_ptr var_symbol, std::vector offset) +SET_t hlasm_context::get_attribute_value_ca( + data_attr_kind attribute, var_sym_ptr var_symbol, std::vector offset) { switch (attribute) { case data_attr_kind::K: - return var_symbol ? var_symbol->count(offset) : 0; + return var_symbol ? var_symbol->count(std::move(offset)) : 0; case data_attr_kind::N: - return var_symbol ? var_symbol->number(offset) : 0; - case hlasm_plugin::parser_library::context::data_attr_kind::T: + return var_symbol ? var_symbol->number(std::move(offset)) : 0; + case data_attr_kind::T: return get_type_attr(var_symbol, std::move(offset)); default: break; @@ -478,22 +477,36 @@ SET_t hlasm_context::get_data_attribute(data_attr_kind attribute, var_sym_ptr va return SET_t(); } -SET_t hlasm_context::get_data_attribute(data_attr_kind attribute, id_index symbol_name) +SET_t hlasm_context::get_attribute_value_ca(data_attr_kind attribute, id_index symbol_name) +{ + if (attribute == data_attr_kind::O) + return get_opcode_attr(symbol_name); + return get_attribute_value_ca(attribute, ord_ctx.get_symbol(symbol_name)); +} + +SET_t hlasm_context::get_attribute_value_ca(data_attr_kind attribute, const symbol* symbol) { switch (attribute) { - case hlasm_plugin::parser_library::context::data_attr_kind::D: - return ord_ctx.symbol_defined(symbol_name) ? 1 : 0; - case hlasm_plugin::parser_library::context::data_attr_kind::T: - return std::string({ ord_ctx.symbol_defined(symbol_name) ? (char)ebcdic_encoding::e2a - [ord_ctx.get_symbol(symbol_name)->attributes().get_attribute_value(attribute)] - : 'U' }); - case hlasm_plugin::parser_library::context::data_attr_kind::O: - return get_opcode_attr(symbol_name); + case data_attr_kind::D: + if (symbol) + return 1; + return 0; + case data_attr_kind::T: + if (symbol) + { + auto attr_val = symbol->attributes().get_attribute_value(attribute); + return std::string { (char)ebcdic_encoding::e2a[attr_val] }; + } + return "U"; + case data_attr_kind::O: + if (symbol) + return get_opcode_attr(symbol->name); + return "U"; default: - return ord_ctx.symbol_defined(symbol_name) - ? ord_ctx.get_symbol(symbol_name)->attributes().get_attribute_value(attribute) - : symbol_attributes::default_value(attribute); + if (symbol) + return symbol->attributes().get_attribute_value(attribute); + return symbol_attributes::default_value(attribute); } } @@ -528,8 +541,8 @@ C_t hlasm_context::get_type_attr(var_sym_ptr var_symbol, const std::vectordiag) + auto res = expressions::ca_constant::try_self_defining_term(value); + if (res) return "N"; id_index symbol_name = ids_.add(std::move(value)); @@ -678,3 +691,5 @@ void hlasm_context::apply_source_snapshot(source_snapshot snapshot) } const code_scope& hlasm_context::current_scope() const { return *curr_scope(); } + +} // namespace hlasm_plugin::parser_library::context diff --git a/parser_library/src/context/hlasm_context.h b/parser_library/src/context/hlasm_context.h index e39e2b814..79cca6807 100644 --- a/parser_library/src/context/hlasm_context.h +++ b/parser_library/src/context/hlasm_context.h @@ -153,9 +153,10 @@ class hlasm_context opcode_t get_operation_code(id_index symbol) const; // get data attribute value of variable symbol - SET_t get_data_attribute(data_attr_kind attribute, var_sym_ptr var_symbol, std::vector offset = {}); + SET_t get_attribute_value_ca(data_attr_kind attribute, var_sym_ptr var_symbol, std::vector offset); // get data attribute value of ordinary symbol - SET_t get_data_attribute(data_attr_kind attribute, id_index symbol); + SET_t get_attribute_value_ca(data_attr_kind attribute, id_index symbol); + SET_t get_attribute_value_ca(data_attr_kind attribute, const symbol* symbol); C_t get_type_attr(var_sym_ptr var_symbol, const std::vector& offset); C_t get_opcode_attr(id_index symbol); diff --git a/parser_library/src/context/lsp_context.cpp b/parser_library/src/context/lsp_context.cpp index 36856ce6f..491f5fc6e 100644 --- a/parser_library/src/context/lsp_context.cpp +++ b/parser_library/src/context/lsp_context.cpp @@ -14,6 +14,8 @@ #include "lsp_context.h" +#include + #include "ebcdic_encoding.h" using namespace hlasm_plugin::parser_library::context; diff --git a/parser_library/src/context/lsp_context.h b/parser_library/src/context/lsp_context.h index 299a3a951..a9811d878 100644 --- a/parser_library/src/context/lsp_context.h +++ b/parser_library/src/context/lsp_context.h @@ -15,8 +15,11 @@ #ifndef CONTEXT_LSP_CONTEXT_H #define CONTEXT_LSP_CONTEXT_H +#include #include +#include +#include "context/ordinary_assembly/symbol.h" #include "semantics/highlighting_info.h" namespace hlasm_plugin::parser_library::context { diff --git a/parser_library/src/context/ordinary_assembly/dependable.h b/parser_library/src/context/ordinary_assembly/dependable.h index aa7948aba..bcdc89e24 100644 --- a/parser_library/src/context/ordinary_assembly/dependable.h +++ b/parser_library/src/context/ordinary_assembly/dependable.h @@ -26,7 +26,7 @@ namespace context { class dependency_solver { public: - virtual symbol* get_symbol(id_index name) = 0; + virtual const symbol* get_symbol(id_index name) const = 0; }; // interface of an object that depends on another objects (addresses or symbols) 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 4574d13c5..5580bbd06 100644 --- a/parser_library/src/context/ordinary_assembly/ordinary_assembly_context.cpp +++ b/parser_library/src/context/ordinary_assembly/ordinary_assembly_context.cpp @@ -55,6 +55,13 @@ bool ordinary_assembly_context::create_symbol( return ok; } +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); 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 46af8e912..dd0488efc 100644 --- a/parser_library/src/context/ordinary_assembly/ordinary_assembly_context.h +++ b/parser_library/src/context/ordinary_assembly/ordinary_assembly_context.h @@ -58,7 +58,8 @@ class ordinary_assembly_context : public dependency_solver id_index name, symbol_value value, symbol_attributes attributes, location symbol_location); // gets symbol by name - virtual symbol* get_symbol(id_index name) override; + virtual const symbol* get_symbol(id_index name) const override; + symbol* get_symbol(id_index name); // access current section const section* current_section() const; diff --git a/parser_library/src/context/ordinary_assembly/symbol_attributes.cpp b/parser_library/src/context/ordinary_assembly/symbol_attributes.cpp index 9310886fd..8a51a4ae0 100644 --- a/parser_library/src/context/ordinary_assembly/symbol_attributes.cpp +++ b/parser_library/src/context/ordinary_assembly/symbol_attributes.cpp @@ -71,13 +71,13 @@ data_attr_kind symbol_attributes::transform_attr(char c) } } -bool symbol_attributes::needs_ordinary(data_attr_kind attribute) +bool symbol_attributes::requires_ordinary_symbol(data_attr_kind attribute) { return attribute == data_attr_kind::D || attribute == data_attr_kind::L || attribute == data_attr_kind::O || attribute == data_attr_kind::S || attribute == data_attr_kind::I; } -bool symbol_attributes::ordinary_allowed(data_attr_kind attribute) +bool symbol_attributes::is_ordinary_attribute(data_attr_kind attribute) { return attribute == data_attr_kind::L || attribute == data_attr_kind::I || attribute == data_attr_kind::S || attribute == data_attr_kind::T; @@ -96,6 +96,20 @@ symbol_attributes::value_t symbol_attributes::default_value(data_attr_kind attri } } +SET_t symbol_attributes::default_ca_value(data_attr_kind attribute) +{ + switch (attribute) + { + case data_attr_kind::T: + case data_attr_kind::O: + return std::string("U"); + case data_attr_kind::L: + return 1; + default: + return 0; + } +} + symbol_attributes::symbol_attributes(symbol_origin origin) : origin(origin) , type_(undef_type) diff --git a/parser_library/src/context/ordinary_assembly/symbol_attributes.h b/parser_library/src/context/ordinary_assembly/symbol_attributes.h index c40266e8b..32a75fb1d 100644 --- a/parser_library/src/context/ordinary_assembly/symbol_attributes.h +++ b/parser_library/src/context/ordinary_assembly/symbol_attributes.h @@ -17,6 +17,8 @@ #include +#include "context/common_types.h" + namespace hlasm_plugin { namespace parser_library { namespace context { @@ -68,9 +70,10 @@ struct symbol_attributes // helper function to transform char to enum static data_attr_kind transform_attr(char c); - static bool needs_ordinary(data_attr_kind attribute); - static bool ordinary_allowed(data_attr_kind attribute); + static bool requires_ordinary_symbol(data_attr_kind attribute); + static bool is_ordinary_attribute(data_attr_kind attribute); static value_t default_value(data_attr_kind attribute); + static SET_t default_ca_value(data_attr_kind attribute); symbol_attributes(symbol_origin origin, type_attr type, diff --git a/parser_library/src/context/variables/macro_param.h b/parser_library/src/context/variables/macro_param.h index 7ae33f45b..ade231048 100644 --- a/parser_library/src/context/variables/macro_param.h +++ b/parser_library/src/context/variables/macro_param.h @@ -48,11 +48,11 @@ class macro_param_base : public variable_symbol virtual const macro_param_data_component* get_data(const std::vector& offset) const; // N' attribute of the symbol - virtual A_t number(std::vector offset = {}) const override; + virtual A_t number(std::vector offset) const override; // K' attribute of the symbol - virtual A_t count(std::vector offset = {}) const override; + virtual A_t count(std::vector offset) const override; - virtual size_t size(std::vector offset = {}) const; + virtual size_t size(std::vector offset) const; protected: macro_param_base(macro_param_type param_type, id_index name, bool is_global); diff --git a/parser_library/src/context/variables/set_symbol.h b/parser_library/src/context/variables/set_symbol.h index b452263e6..d8a829e33 100644 --- a/parser_library/src/context/variables/set_symbol.h +++ b/parser_library/src/context/variables/set_symbol.h @@ -111,14 +111,13 @@ class set_symbol : public set_symbol_base } // N' attribute of the symbol - virtual A_t number(std::vector offset = {}) const override + virtual A_t number(std::vector) const override { - (void)offset; return (A_t)(is_scalar || data.empty() ? 0 : data.rbegin()->first + 1); } // K' attribute of the symbol - virtual A_t count(std::vector offset = {}) const override; + virtual A_t count(std::vector offset) const override; virtual size_t size() const override { return data.size(); }; @@ -132,7 +131,7 @@ class set_symbol : public set_symbol_base } private: - const T* get_data(std::vector offset = {}) const + const T* get_data(std::vector offset) const { if ((is_scalar && !offset.empty()) || (!is_scalar && offset.size() != 1)) return nullptr; @@ -153,12 +152,13 @@ inline A_t set_symbol::count(std::vector offset) const auto tmp = get_data(std::move(offset)); return tmp ? (A_t)std::to_string(*tmp).size() : (A_t)1; } + template<> -inline A_t set_symbol::count(std::vector offset) const +inline A_t set_symbol::count(std::vector) const { - (void)offset; return (A_t)1; } + template<> inline A_t set_symbol::count(std::vector offset) const { diff --git a/parser_library/src/context/variables/system_variable.cpp b/parser_library/src/context/variables/system_variable.cpp index 2eb5dadf8..4e5e51724 100644 --- a/parser_library/src/context/variables/system_variable.cpp +++ b/parser_library/src/context/variables/system_variable.cpp @@ -61,7 +61,7 @@ A_t system_variable::count(std::vector offset) const { tmp = tmp->get_ith(offset[i] - (i == 0 ? 0 : 1)); } - return tmp->get_value().size(); + return (A_t)tmp->get_value().size(); } size_t system_variable::size(std::vector offset) const diff --git a/parser_library/src/context/variables/system_variable.h b/parser_library/src/context/variables/system_variable.h index 4bb09bad6..4d94e9df0 100644 --- a/parser_library/src/context/variables/system_variable.h +++ b/parser_library/src/context/variables/system_variable.h @@ -43,11 +43,11 @@ class system_variable : public macro_param_base virtual const macro_param_data_component* get_data(const std::vector& offset) const override; // N' attribute of the symbol - virtual A_t number(std::vector offset = {}) const override; + virtual A_t number(std::vector offset) const override; // K' attribute of the symbol - virtual A_t count(std::vector offset = {}) const override; + virtual A_t count(std::vector offset) const override; - virtual size_t size(std::vector offset = {}) const override; + virtual size_t size(std::vector offset) const override; protected: virtual const macro_param_data_component* real_data() const override; diff --git a/parser_library/src/context/variables/variable.h b/parser_library/src/context/variables/variable.h index 7a84b81fb..9c0ccf49a 100644 --- a/parser_library/src/context/variables/variable.h +++ b/parser_library/src/context/variables/variable.h @@ -51,9 +51,9 @@ class variable_symbol const macro_param_base* access_macro_param_base() const; // N' attribute of the symbol - virtual A_t number(std::vector offset = {}) const = 0; + virtual A_t number(std::vector offset) const = 0; // K' attribute of the symbol - virtual A_t count(std::vector offset = {}) const = 0; + virtual A_t count(std::vector offset) const = 0; virtual ~variable_symbol() = default; diff --git a/parser_library/src/diagnosable_ctx.h b/parser_library/src/diagnosable_ctx.h index 7ae0e5e8f..e62afa508 100644 --- a/parser_library/src/diagnosable_ctx.h +++ b/parser_library/src/diagnosable_ctx.h @@ -28,9 +28,15 @@ class diagnosable_ctx : public diagnosable_impl context::hlasm_context& ctx_; public: - using diagnosable_impl::add_diagnostic; + virtual void add_diagnostic(diagnostic_s diagnostic) const override + { + add_diagnostic_inner( + diagnostic_op( + diagnostic.severity, std::move(diagnostic.code), std::move(diagnostic.message), diagnostic.diag_range), + ctx_.processing_stack()); + } - virtual void add_diagnostic(diagnostic_op diagnostic) const + void add_diagnostic(diagnostic_op diagnostic) const { add_diagnostic_inner(std::move(diagnostic), ctx_.processing_stack()); } diff --git a/parser_library/src/diagnosable_impl.h b/parser_library/src/diagnosable_impl.h index a44b43735..e261d4a6c 100644 --- a/parser_library/src/diagnosable_impl.h +++ b/parser_library/src/diagnosable_impl.h @@ -62,4 +62,4 @@ using diagnosable_op_impl = collectable_impl; } // namespace hlasm_plugin::parser_library -#endif \ No newline at end of file +#endif diff --git a/parser_library/src/diagnostic.cpp b/parser_library/src/diagnostic.cpp index c4317490f..e47960351 100644 --- a/parser_library/src/diagnostic.cpp +++ b/parser_library/src/diagnostic.cpp @@ -1837,6 +1837,88 @@ diagnostic_op diagnostic_op::error_ME002(const range& range) return diagnostic_op(diagnostic_severity::error, "ME002", "multiplication or division of address", range); } +diagnostic_op diagnostic_op::error_CE001(const range& range) +{ + return diagnostic_op(diagnostic_severity::error, "CE001", "Operator expected", range); +} + +diagnostic_op diagnostic_op::error_CE002(const std::string& message, const range& range) +{ + return diagnostic_op(diagnostic_severity::error, "CE002", "Undefined operator - " + message, range); +} + +diagnostic_op diagnostic_op::error_CE003(const range& range) +{ + return diagnostic_op(diagnostic_severity::error, "CE003", "Operand expected", range); +} + +diagnostic_op diagnostic_op::error_CE004(const range& range) +{ + return diagnostic_op( + diagnostic_severity::error, "CE004", "Invalid use of operator - different return type expected", range); +} + +diagnostic_op diagnostic_op::error_CE005(const range& range) +{ + return diagnostic_op(diagnostic_severity::error, "CE005", "Illegal duplication factor", range); +} + +diagnostic_op diagnostic_op::error_CE006(const range& range) +{ + return diagnostic_op(diagnostic_severity::error, "CE006", "Bad number of operands", range); +} + +diagnostic_op diagnostic_op::error_CE007(const range& range) +{ + return diagnostic_op(diagnostic_severity::error, "CE007", "Bad operand value", range); +} + +diagnostic_op diagnostic_op::error_CE008(const range& range) +{ + return diagnostic_op(diagnostic_severity::error, "CE008", "Bad substring expression", range); +} + +diagnostic_op diagnostic_op::error_CE009(const range& range) +{ + return diagnostic_op(diagnostic_severity::error, "CE009", "Substring start points past string end", range); +} + +diagnostic_op diagnostic_op::error_CE010(const range& range) +{ + return diagnostic_op(diagnostic_severity::error, "CE010", "Negative duplication factor", range); +} + +diagnostic_op diagnostic_op::error_CE011(const range& range) +{ + return diagnostic_op(diagnostic_severity::error, "CE011", "Maximum string size exceeded", range); +} + +diagnostic_op diagnostic_op::error_CE012(const range& range) +{ + return diagnostic_op(diagnostic_severity::error, "CE012", "Only absolute and defined symbols allowed", range); +} + +diagnostic_op diagnostic_op::error_CE013(const range& range) +{ + return diagnostic_op(diagnostic_severity::error, "CE013", "Arithmetic overflow", range); +} + +diagnostic_op diagnostic_op::error_CE014(const range& range) +{ + return diagnostic_op(diagnostic_severity::error, "CE014", "Arithmetic underflow", range); +} + +diagnostic_op diagnostic_op::error_CE015(const range& range) +{ + return diagnostic_op(diagnostic_severity::error, "CE015", "Invalid self-defining term", range); +} + +diagnostic_op diagnostic_op::error_CW001(const range& range) +{ + return diagnostic_op(diagnostic_severity::warning, "CW001", "Substring count points past string end", range); +} + + diagnostic_s diagnostic_s::error_W002(const std::string& ws_uri, const std::string& ws_name) { return diagnostic_s(ws_uri, diff --git a/parser_library/src/diagnostic.h b/parser_library/src/diagnostic.h index 8db6e75a4..9264feb43 100644 --- a/parser_library/src/diagnostic.h +++ b/parser_library/src/diagnostic.h @@ -111,11 +111,11 @@ struct diagnostic_op , code(std::move(code)) , message(std::move(message)) {}; - diagnostic_op(diagnostic_severity severity, std::string code, std::string message, range range_) + diagnostic_op(diagnostic_severity severity, std::string code, std::string message, range diag_range) : severity(severity) , code(std::move(code)) , message(std::move(message)) - , diag_range(std::move(range_)) {}; + , diag_range(std::move(diag_range)) {}; static diagnostic_op error_I999(const std::string& instr_name, const range& range); @@ -584,6 +584,38 @@ struct diagnostic_op static diagnostic_op error_ME001(const range& range); static diagnostic_op error_ME002(const range& range); + + static diagnostic_op error_CE001(const range& range); + + static diagnostic_op error_CE002(const std::string& message, const range& range); + + static diagnostic_op error_CE003(const range& range); + + static diagnostic_op error_CE004(const range& range); + + static diagnostic_op error_CE005(const range& range); + + static diagnostic_op error_CE006(const range& range); + + static diagnostic_op error_CE007(const range& range); + + static diagnostic_op error_CE008(const range& range); + + static diagnostic_op error_CE009(const range& range); + + static diagnostic_op error_CE010(const range& range); + + static diagnostic_op error_CE011(const range& range); + + static diagnostic_op error_CE012(const range& range); + + static diagnostic_op error_CE013(const range& range); + + static diagnostic_op error_CE014(const range& range); + + static diagnostic_op error_CE015(const range& range); + + static diagnostic_op error_CW001(const range& range); }; struct range_uri_s diff --git a/parser_library/src/diagnostic_adder.cpp b/parser_library/src/diagnostic_adder.cpp new file mode 100644 index 000000000..0738e7056 --- /dev/null +++ b/parser_library/src/diagnostic_adder.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019 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 "diagnostic_adder.h" + +#include "diagnosable_impl.h" + +namespace hlasm_plugin::parser_library { + +diagnostic_adder::diagnostic_adder(const collectable* diagnoser, range diag_range) + : s_diagnoser_(diagnoser) + , op_diagnoser_(nullptr) + , diag_range_(diag_range) + , diagnostics_present(false) +{} + +diagnostic_adder::diagnostic_adder(const collectable* diagnoser, range diag_range) + : s_diagnoser_(nullptr) + , op_diagnoser_(diagnoser) + , diag_range_(diag_range) + , diagnostics_present(false) +{} + +diagnostic_adder::diagnostic_adder() + : s_diagnoser_(nullptr) + , op_diagnoser_(nullptr) + , diagnostics_present(false) +{} + +void diagnostic_adder::operator()(const std::function& f) +{ + diagnostics_present = true; + if (s_diagnoser_) + s_diagnoser_->add_diagnostic(f(diag_range_)); + else if (op_diagnoser_) + op_diagnoser_->add_diagnostic(f(diag_range_)); +} + +} // namespace hlasm_plugin::parser_library diff --git a/parser_library/src/diagnostic_adder.h b/parser_library/src/diagnostic_adder.h new file mode 100644 index 000000000..b13e7bb37 --- /dev/null +++ b/parser_library/src/diagnostic_adder.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 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_DIAGNOSTIC_ADDER_H +#define HLASMPLUGIN_PARSERLIBRARY_DIAGNOSTIC_ADDER_H + +#include +#include + +#include "diagnosable.h" +#include "protocol.h" + +namespace hlasm_plugin::parser_library { + +// class that simplyfies adding of diagnostics +// holds both range and collectable object +// hence, there is no need to specify range in a diagnostic creation, just pass diagnostic function +class diagnostic_adder +{ + const collectable* s_diagnoser_; + const collectable* op_diagnoser_; + range diag_range_; + +public: + bool diagnostics_present; + + diagnostic_adder(const collectable* diagnoser, range diag_range); + + diagnostic_adder(const collectable* diagnoser, range diag_range); + + diagnostic_adder(); + + void operator()(const std::function& f); +}; + +} // namespace hlasm_plugin::parser_library + +#endif diff --git a/parser_library/src/expressions/arithmetic_expression.cpp b/parser_library/src/expressions/arithmetic_expression.cpp deleted file mode 100644 index fb08b7d03..000000000 --- a/parser_library/src/expressions/arithmetic_expression.cpp +++ /dev/null @@ -1,448 +0,0 @@ -/* - * Copyright (c) 2019 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 "arithmetic_expression.h" - -#include -#include -#include -#include - -#include "character_expression.h" -#include "ebcdic_encoding.h" -#include "error_messages.h" -#include "expression.h" -#include "numeric_wrapper.h" - -using namespace hlasm_plugin; -using namespace parser_library; -using namespace expressions; - -const int32_t numeric_part_mask = (1 << 31) ^ static_cast(-1); - -arithmetic_expression::arithmetic_expression(int32_t val) - : value_(val) -{} - -arithmetic_expression::arithmetic_expression(const arithmetic_expression& expr) - : value_(expr.value_) -{ - if (expr.diag) - diag = std::make_unique(*expr.diag); -} - -context::SET_t arithmetic_expression::get_set_value() const { return value_; } - -int32_t arithmetic_expression::get_value() const { return value_; } - -expr_ptr arithmetic_expression::from_string(const std::string_view& s, int base) -{ - if (s.empty()) - return make_arith(0); - - bool may_have_sign = base == 10; - constexpr auto max = static_cast(INT32_MAX); - constexpr auto min = static_cast(INT32_MIN); - constexpr auto umax = static_cast(UINT32_MAX); - - size_t sign_off = 0; - - if (*s.begin() == '+' && base == 10) - sign_off = 1; - - long long lval; - auto conversion_result = std::from_chars(s.data() + sign_off, s.data() + sign_off + s.size(), lval, base); - - if ((may_have_sign && lval > max && lval < min) || (!may_have_sign && lval > umax) - || conversion_result.ec == std::errc::result_out_of_range) - return default_expr_with_error(error_messages::ea01()); - - if (conversion_result.ec == std::errc::invalid_argument) - return default_expr_with_error(error_messages::ea02(std::string(s))); - - return make_arith(static_cast(lval)); -} - -std::string arithmetic_expression::get_str_val() const { return std::to_string(value_); } - -expr_ptr arithmetic_expression::from_string(const std::string& option, const std::string_view& value, bool dbcs) -{ - if (option.empty() || toupper(option[0]) == 'D') - return from_string(value, 10); - - if (toupper(option[0]) == 'B') - return from_string(value, 2); - - if (toupper(option[0]) == 'X') - return from_string(value, 16); - - if (toupper(option[0]) == 'C') - return c2arith(std::string(value)); - - if (toupper(option[0]) == 'G') - return g2arith(std::string(value), dbcs); - - return default_expr_with_error(error_messages::ea03()); -} - -expr_ptr arithmetic_expression::from_string(const std::string_view& value, bool dbcs) -{ - if (value.empty()) - return make_arith(0); - - if (isdigit(value.front())) - return from_string("", value, dbcs); - - if (value.size() >= 3 && value[1] == '\'' && value.back() == '\'') - return from_string({ value.front() }, value.substr(2, value.size() - 3), dbcs); - else - return default_expr_with_error(error_messages::ea03()); -} - -expr_ptr arithmetic_expression::c2arith(const std::string& value) -{ - /* - first escaping is enforced in grammar (for ampersands and apostrophes) - second escaping escapes only apostrophes - */ - int32_t val = 0; - size_t escaped = 0; - for (const char* i = value.c_str(); *i != 0; ++i) - { - if (*i == '\'' && *(i + 1) == '\'') - { - ++i; - ++escaped; - } - - val <<= 8; - val += ebcdic_encoding::to_ebcdic(ebcdic_encoding::to_pseudoascii(i)); - } - - if (value.length() - escaped > 4) - return default_expr_with_error(error_messages::ea04()); - - return make_arith(val); -} - -// states of FSM rewritting double-byte data -enum class G2C_STATES -{ - EMPTY, - CLOSED, - DOUBLE_BYTE_EMPTY, - DOUBLE_BYTE_ODD, - DOUBLE_BYTE_EVEN, - INVALID -}; - -// double byte interpret as number -expr_ptr arithmetic_expression::g2arith(const std::string& value, bool dbcs) -{ - if (!dbcs) - return default_expr_with_error(error_messages::ea05()); - - int32_t val = 0; - G2C_STATES state = G2C_STATES::EMPTY; - for (const char* i = value.c_str(); *i != 0; ++i) - { - if (*i == '<') - { - if (state == G2C_STATES::EMPTY || state == G2C_STATES::CLOSED) - { - state = G2C_STATES::DOUBLE_BYTE_EMPTY; - continue; - } - else - break; - } - else if (*i == '>') - { - if (state == G2C_STATES::DOUBLE_BYTE_EVEN) - { - state = G2C_STATES::CLOSED; - continue; - } - else - break; - } - else if (state != G2C_STATES::CLOSED) - { - if (state == G2C_STATES::DOUBLE_BYTE_EVEN) - state = G2C_STATES::DOUBLE_BYTE_ODD; - else if (state == G2C_STATES::DOUBLE_BYTE_ODD) - state = G2C_STATES::DOUBLE_BYTE_EVEN; - } - else - { - state = G2C_STATES::INVALID; - break; - } - - val <<= 8; - val += ebcdic_encoding::to_ebcdic(ebcdic_encoding::to_pseudoascii(i)); - } - - if (state != G2C_STATES::CLOSED) - return default_expr_with_error(error_messages::ea06()); - - return make_arith(val); -} - -expr_ptr arithmetic_expression::binary_operation(str_ref operation, expr_ref arg2) const -{ - std::string o = operation; - std::transform(o.begin(), o.end(), o.begin(), [](char c) { return static_cast(toupper(c)); }); - int32_t val = 0; - auto e = arg2->retype(); - if (e == nullptr) - { - auto ae = arg2->retype(); - if (ae == nullptr) - { - return default_expr_with_error(error_messages::ea07()); - } - val = ae->get_value(); - } - else - val = e->get_value(); - - if (o == "OR") - { - copy_return_on_error_binary(arg2.get(), arithmetic_expression); - return make_arith(value_ | val); - } - - if (o == "AND") - { - copy_return_on_error_binary(arg2.get(), arithmetic_expression); - return make_arith(value_ & val); - } - - if (o == "SLA") - { - copy_return_on_error_binary(arg2.get(), arithmetic_expression); - - uint32_t value = static_cast(value_); - - return make_arith( - (value & (1 << 31)) | ((value & (static_cast(numeric_part_mask))) << static_cast(val))); - } - - if (o == "SLL") - { - copy_return_on_error_binary(arg2.get(), arithmetic_expression); - uint32_t value = static_cast(value_); - return make_arith(static_cast(value << static_cast(val))); - } - - if (o == "SRA") - { - copy_return_on_error_binary(arg2.get(), arithmetic_expression); - uint64_t value = static_cast(static_cast(value_)); - if ((63 & val) > 31) - return make_arith(static_cast((value & (1 << 31)) >> 31)); - return make_arith(static_cast(value >> (static_cast(val) & (63)))); - } - - if (o == "SRL") - { - copy_return_on_error_binary(arg2.get(), arithmetic_expression); - return make_arith(static_cast( - static_cast(static_cast(value_)) >> static_cast(val & (63)))); - } - - if (o == "XOR") - { - copy_return_on_error_binary(arg2.get(), arithmetic_expression); - return make_arith(value_ ^ val); - } - - if (o == "EQ") - { - copy_return_on_error_binary(arg2.get(), logic_expression); - return make_logic(value_ == val); - } - - if (o == "LE") - { - copy_return_on_error_binary(arg2.get(), logic_expression); - return make_logic(value_ <= val); - } - - if (o == "LT") - { - copy_return_on_error_binary(arg2.get(), logic_expression); - return make_logic(value_ < val); - } - - if (o == "GE") - { - copy_return_on_error_binary(arg2.get(), logic_expression); - return make_logic(value_ >= val); - } - - if (o == "GT") - { - copy_return_on_error_binary(arg2.get(), logic_expression); - return make_logic(value_ > val); - } - - if (o == "NE") - { - copy_return_on_error_binary(arg2.get(), logic_expression); - return make_logic(value_ != val); - } - - return default_expr_with_error(error_messages::ea08()); -} - -expr_ptr arithmetic_expression::operator+(expression_ref e) const -{ - copy_return_on_error_binary(e, arithmetic_expression); - - auto w = al_wrap(e); - if (!w) - return default_expr_with_error(error_messages::ea09()); - auto value = w.value(); - - auto res = static_cast(value_) + static_cast(value); - if (res > INT32_MAX || res < INT32_MIN) - return default_expr_with_error(error_messages::ea10()); - - return make_arith(static_cast(res)); -} - -expr_ptr arithmetic_expression::operator-(expression_ref e) const -{ - copy_return_on_error_binary(e, arithmetic_expression); - - auto w = al_wrap(e); - if (!w) - return default_expr_with_error(error_messages::ea09()); - auto value = w.value(); - - auto res = static_cast(value_) - static_cast(value); - if (res > INT32_MAX || res < INT32_MIN) - return default_expr_with_error(error_messages::ea10()); - - return make_arith(static_cast(res)); -} - -expr_ptr arithmetic_expression::operator*(expression_ref e) const -{ - copy_return_on_error_binary(e, arithmetic_expression); - - auto w = al_wrap(e); - if (!w) - return default_expr_with_error(error_messages::ea09()); - auto value = w.value(); - - auto res = static_cast(value_) * static_cast(value); - if (res > INT32_MAX || res < INT32_MIN) - return default_expr_with_error(error_messages::ea10()); - - return make_arith(static_cast(res)); -} - -expr_ptr arithmetic_expression::operator/(expression_ref e) const -{ - copy_return_on_error_binary(e, arithmetic_expression); - - auto w = al_wrap(e); - if (!w) - return default_expr_with_error(error_messages::ea09()); - auto value = w.value(); - - if (value == 0) - return make_arith(0); - - return make_arith(value_ / value); -} - -expr_ptr arithmetic_expression::operator+() const -{ - copy_return_on_error(this, arithmetic_expression); - - return make_arith(value_); -} - -expr_ptr arithmetic_expression::operator-() const -{ - copy_return_on_error(this, arithmetic_expression); - - if (value_ == INT32_MIN) - return default_expr_with_error(error_messages::ea10()); - - return make_arith(-value_); -} - -int32_t arithmetic_expression::get_numeric_value() const { return value_; } - -expr_ptr arithmetic_expression::unary_operation(str_ref o) const -{ - std::string operation_name = o; - std::transform(operation_name.begin(), operation_name.end(), operation_name.begin(), [](char c) { - return static_cast(toupper(c)); - }); - if (operation_name == "NOT") - { - copy_return_on_error(this, arithmetic_expression); - return make_arith(value_ ^ static_cast(-1)); - } - - if (operation_name == "A2B") - { - copy_return_on_error(this, character_expression); - return make_char(std::bitset<32>(get_value()).to_string()); - } - - if (operation_name == "A2C") - { - copy_return_on_error(this, character_expression); - return make_char(character_expression::num_to_ebcdic(get_value())); - } - - if (operation_name == "A2D") - { - copy_return_on_error(this, character_expression); - auto val = std::to_string(get_value()); - if (val[0] == '-') - return make_char(std::move(val)); - else - return make_char("+" + val); - } - - if (operation_name == "A2X") - { - copy_return_on_error(this, character_expression); - return make_char(character_expression::num_to_hex(value_)); - } - - if (operation_name == "BYTE") - { - copy_return_on_error(this, character_expression); - if (value_ > 255 || value_ < 0) - return default_expr_with_error(error_messages::ea11()); - return make_char(ebcdic_encoding::to_ascii(static_cast(value_))); - } - - if (operation_name == "SIGNED") - { - copy_return_on_error(this, character_expression); - return make_char(std::to_string(get_value())); - } - - return default_expr_with_error(error_messages::ea08()); -} diff --git a/parser_library/src/expressions/arithmetic_expression.h b/parser_library/src/expressions/arithmetic_expression.h deleted file mode 100644 index 6ec4d1cee..000000000 --- a/parser_library/src/expressions/arithmetic_expression.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2019 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_PARSER_HLASMAEXPRESSION_H -#define HLASMPLUGIN_PARSER_HLASMAEXPRESSION_H -#include -#include - -#include "expression.h" - -namespace hlasm_plugin { -namespace parser_library { -namespace expressions { -class logic_expression; -class arithmetic_expression; -using arith_ptr = std::unique_ptr; -/** - * logic for arithmetic expression and operations on this type - * */ -class arithmetic_expression : public expression -{ -public: - virtual ~arithmetic_expression() = default; - arithmetic_expression() = default; - arithmetic_expression(int32_t); - arithmetic_expression(const arithmetic_expression& expr); - arithmetic_expression(arithmetic_expression&&) = default; - arithmetic_expression& operator=(arithmetic_expression&&) = default; - static expr_ptr from_string(const std::string& option, const std::string_view& value, bool dbcs); - static expr_ptr from_string(const std::string_view& value, bool dbcs); - - // EBCDIC string interpret as number (1 char = 1B) - static expr_ptr c2arith(const std::string& value); - // double byte interpret as number - static expr_ptr g2arith(const std::string& value, bool dbcs = false); - - /** - * all operations involving arguments check for errors - * in all arguments immediately before accessing their values - * - * if any argument contains an error, it is copied - * and an erroneous expression (meaning with en error) - * is returned - * - * see: copy_return_on_error and copy_return_on_error_binary - * */ - - virtual expr_ptr operator+(expression_ref) const override; - virtual expr_ptr operator-(expression_ref) const override; - virtual expr_ptr operator*(expression_ref) const override; - virtual expr_ptr operator/(expression_ref) const override; - virtual expr_ptr operator+() const override; - virtual expr_ptr operator-() const override; - - virtual int32_t get_numeric_value() const override; - - virtual expr_ptr unary_operation(str_ref operation_name) const override; - virtual expr_ptr binary_operation(str_ref o, expr_ref arg2) const override; - static expr_ptr from_string(const std::string_view&, int base); - context::SET_t get_set_value() const override; - int32_t get_value() const; - virtual std::string get_str_val() const override; - -private: - int32_t value_ = 0; -}; -} // namespace expressions -} // namespace parser_library -} // namespace hlasm_plugin - -#endif diff --git a/parser_library/src/expressions/character_expression.cpp b/parser_library/src/expressions/character_expression.cpp deleted file mode 100644 index dd0e00eb3..000000000 --- a/parser_library/src/expressions/character_expression.cpp +++ /dev/null @@ -1,727 +0,0 @@ -/* - * Copyright (c) 2019 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 "character_expression.h" - -#include -#include -#include - -#include "arithmetic_expression.h" -#include "ebcdic_encoding.h" -#include "error_messages.h" - -using namespace hlasm_plugin; -using namespace parser_library; -using namespace expressions; - -std::string character_expression::get_str_val() const { return value_; } - -char_ptr character_expression::append(const char_ptr& arg) const -{ - copy_return_on_error_binary(arg.get(), character_expression); - return make_char(value_ + arg->value_); -} - -char_ptr character_expression::append(const character_expression* arg) const -{ - copy_return_on_error_binary(arg, character_expression); - return make_char(value_ + arg->value_); -} - -context::SET_t character_expression::get_set_value() const { return value_; } - -character_expression::character_expression(const character_expression& expr) - : value_(expr.value_) -{ - if (expr.diag) - diag = std::make_unique(*expr.diag); -} - -character_expression::character_expression(std::string val) - : value_(std::move(val)) -{} - -void character_expression::append(std::string v) { value_.append(v); } - -int ebcdic_compare(const std::string& lhs, const std::string& rhs) -{ - int diff = (int)lhs.size() - (int)rhs.size(); - - if (diff != 0) - return diff; - - return ebcdic_encoding::to_ebcdic(lhs).compare(ebcdic_encoding::to_ebcdic(rhs)); -} - -expr_ptr character_expression::binary_operation(str_ref operation, expr_ref arg2) const -{ - std::string o = operation; - // case insensitive - std::transform(o.begin(), o.end(), o.begin(), [](char c) { return static_cast(toupper(c)); }); - auto a2 = arg2->retype(); - if (a2 == nullptr) - return default_expr_with_error(error_messages::ec03()); - auto& b = a2->value_; - - if (o == "EQ") - { - copy_return_on_error_binary(arg2.get(), logic_expression); - return make_logic(ebcdic_compare(value_, b) == 0); - } - - if (o == "NE") - { - copy_return_on_error_binary(arg2.get(), logic_expression); - return make_logic(ebcdic_compare(value_, b) != 0); - } - - if (o == "LE") - { - copy_return_on_error_binary(arg2.get(), logic_expression); - return make_logic(ebcdic_compare(value_, b) <= 0); - } - - if (o == "LT") - { - copy_return_on_error_binary(arg2.get(), logic_expression); - return make_logic(ebcdic_compare(value_, b) < 0); - } - - if (o == "GT") - { - copy_return_on_error_binary(arg2.get(), logic_expression); - return make_logic(ebcdic_compare(value_, b) > 0); - } - - if (o == "GE") - { - copy_return_on_error_binary(arg2.get(), logic_expression); - return make_logic(ebcdic_compare(value_, b) >= 0); - } - - copy_return_on_error_binary(arg2.get(), arithmetic_expression); - - if (o == "FIND") - // indices are 1-based - return make_arith(static_cast(value_.find_first_of(b)) + 1); - - if (o == "INDEX") - { - auto i = value_.find(b); - if (i == std::string::npos) - // 0 indicates not found - return make_arith(0); - else - // indices are 1-based - return make_arith(static_cast(i) + 1); - } - - return default_expr_with_error(error_messages::ec05()); -} - -bool character_expression::isalpha_hlasm(char c) -{ - return (isalpha(c) || c == '$' || c == '_' || c == '#' || c == '@'); -} - -expr_ptr character_expression::unary_operation(str_ref operation) const -{ - std::string o = operation; - // transformation to uppercase for case insensitivity - std::transform(o.begin(), o.end(), o.begin(), [](char c) { return static_cast(toupper(c)); }); - - // binary string to arithmetic expr - if (o == "B2A") - { - copy_return_on_error(this, arithmetic_expression); - if (value_.empty()) - return make_arith(0); - return arithmetic_expression::from_string(value_, 2); - } - - // interpret string as arith value - if (o == "C2A") - { - copy_return_on_error(this, arithmetic_expression); - if (value_.empty()) - return make_arith(0); - return arithmetic_expression::c2arith(value_); - } - - // parse int (base 10) - if (o == "D2A") - { - copy_return_on_error(this, arithmetic_expression); - if (value_.empty()) - return default_expr_with_error(error_messages::ec04()); - return arithmetic_expression::from_string(value_, 10); - } - - if (o == "DCLEN") - return dclen(); - - if (o == "ISBIN") - return isbin(); - - if (o == "ISDEC") - return isdec(); - - if (o == "ISHEX") - return ishex(); - - if (o == "ISSYM") - return issym(); - - // hexadecimal string to int - if (o == "X2A") - { - copy_return_on_error(this, arithmetic_expression); - return arithmetic_expression::from_string(value_, 16); - } - - if (o == "B2C") - return b2c(); - - if (o == "B2D") - return b2d(); - - if (o == "B2X") - return b2x(); - - if (o == "C2B") - return c2b(); - - if (o == "C2D") - return c2d(); - - if (o == "C2X") - return c2x(); - - if (o == "D2B") - return d2b(); - - if (o == "D2C") - return d2c(); - - if (o == "D2X") - return d2x(); - - if (o == "DCVAL") - return dcval(); - - if (o == "DEQUOTE") - return dequote(); - - if (o == "DOUBLE") - return double_quote(); - - if (o == "ESYM") - { - /*TODO*/ - return default_expr_with_error(error_messages::not_implemented()); - } - - if (o == "LOWER") - { - copy_return_on_error(this, character_expression); - std::string rv = value_; - std::transform(rv.begin(), rv.end(), rv.begin(), [](char c) { return static_cast(tolower(c)); }); - return make_char(std::move(rv)); - } - - if (o == "SYSATTRA") - { - /*TODO*/ - return default_expr_with_error(error_messages::not_implemented()); - } - - if (o == "SYSATTRP") - { - /*TODO*/ - return default_expr_with_error(error_messages::not_implemented()); - } - - if (o == "UPPER") - { - copy_return_on_error(this, character_expression); - std::string rv = value_; - std::transform(rv.begin(), rv.end(), rv.begin(), [](char c) { return static_cast(toupper(c)); }); - return make_char(std::move(rv)); - } - - if (o == "X2B") - return x2b(); - - if (o == "X2C") - return x2c(); - - if (o == "X2D") - return x2d(); - - return default_expr_with_error(error_messages::ec05()); -} - -// str len -expr_ptr character_expression::dclen() const -{ - copy_return_on_error(this, arithmetic_expression); - int32_t v = 0; - for (auto i = this->value_.cbegin(); i != this->value_.cend(); ++i) - { - // escaping double apostrophe '' and double ampersand && - if ((*i == '\'' && i + 1 != this->value_.end() && *(i + 1) == '\'') - || (*i == '&' && i + 1 != this->value_.end() && *(i + 1) == '&')) - ++i; - ++v; - } - return make_arith(v); -} - -expr_ptr character_expression::isbin() const -{ - copy_return_on_error(this, logic_expression); - if (value_.empty()) - return default_expr_with_error(error_messages::ec04()); - - return make_logic(!value_.empty() && value_.size() < 33 - && std::all_of(value_.cbegin(), value_.cend(), [](char c) { return c == '0' || c == '1'; })); -} - -expr_ptr character_expression::isdec() const -{ - copy_return_on_error(this, logic_expression); - size_t t = 0; - if (value_.empty()) - return default_expr_with_error(error_messages::ec04()); - try - { - std::stoi(value_, &t); - } - catch (...) - { - t = 0; - } - return make_logic(t == value_.length() && value_.length() <= 10 && isdigit(value_[0])); -} - -expr_ptr character_expression::ishex() const -{ - copy_return_on_error(this, logic_expression); - size_t t = 0; - if (value_.empty()) - return default_expr_with_error(error_messages::ec04()); - - return make_logic( - t == value_.length() && value_.length() <= 8 && std::all_of(value_.cbegin(), value_.cend(), [](char c) { - return isdigit(c) || (toupper(c) >= 'A' && toupper(c) <= 'F'); - })); -} - -expr_ptr character_expression::issym() const -{ - copy_return_on_error(this, logic_expression); - if (value_.empty()) - return default_expr_with_error(error_messages::ec04()); - - return make_logic(value_.length() < 64 && isalpha_hlasm(value_[0]) - && std::all_of(value_.cbegin(), value_.cend(), [](char c) { return isdigit(c) || isalpha_hlasm(c); })); -} - -// interpret binary string as EBCDIC string -expr_ptr character_expression::b2c() const -{ - copy_return_on_error(this, character_expression); - if (value_.empty()) - return make_char(""); - - int32_t offset = value_.length() % 8 > 0 ? -8 + value_.length() % 8 : 0; - std::string res; - for (int32_t i = offset; i < static_cast(value_.length());) - { - unsigned char val = 0; - auto e = i + 8; - for (; i < e; ++i) - { - unsigned char num = i >= 0 ? value_[i] - '0' : 0; - if (num > 1) - return default_expr_with_error(error_messages::ec06()); - val = (val << 1) + num; - } - res.append(ebcdic_encoding::to_ascii(val)); - } - - return make_char(std::move(res)); -} - -/** - * convert binary string to decimal - * convert to string with sign - * */ -expr_ptr character_expression::b2d() const -{ - copy_return_on_error(this, character_expression); - if (value_.empty()) - return make_char("+0"); - - auto val = arithmetic_expression::from_string(value_, 2); - - auto rv = std::to_string(val->get_numeric_value()); - if (rv[0] == '-') - return make_char(std::move(rv)); - else - return make_char("+" + rv); -} - -/** - * convert binary string to hexadecimal - * convert to string with sign - * */ -expr_ptr character_expression::b2x() const -{ - copy_return_on_error(this, character_expression); - if (value_.empty()) - return make_char(""); - - if (!std::all_of(value_.cbegin(), value_.cend(), [](char c) { return c == '1' || c == '0'; })) - return default_expr_with_error(error_messages::ec06()); - - auto inp = value_; - if (inp.length() % 4 > 0) - inp = std::string(4 - inp.length() % 4, '0') + inp; - - std::string v; - for (size_t i = 0; i < inp.length(); i += 4) - { - int32_t off = - ((inp[i] - '0') << 3) + ((inp[i + 1] - '0') << 2) + ((inp[i + 2] - '0') << 1) + (inp[i + 3] - '0'); - - v.push_back(num_to_hex_char(off)); - } - return make_char(std::move(v)); -} - -/** - * EBCDIC characters as binary - * */ -expr_ptr character_expression::c2b() const -{ - copy_return_on_error(this, character_expression); - if (value_.empty()) - return make_char(""); - - std::string rv; - rv.reserve(32); - for (const char* j = value_.c_str(); *j != 0; ++j) - { - int32_t v = ebcdic_encoding::to_ebcdic(ebcdic_encoding::to_pseudoascii(j)); - for (size_t i = 0; i < 8; i++) - { - rv.push_back('0' + ((v >> (7 - i)) & 1)); - } - } - return make_char(std::move(rv)); -} - -/** - * EBCDIC characters as decimal string with sign - * */ -expr_ptr character_expression::c2d() const -{ - copy_return_on_error(this, character_expression); - if (value_.empty()) - return make_char("+0"); - int32_t val = 0; - for (const char* j = value_.c_str(); *j != 0; ++j) - val = (val << 8) + ebcdic_encoding::to_ebcdic(ebcdic_encoding::to_pseudoascii(j)); - std::string rv = std::to_string(val); - if (rv[0] == '-') - return make_char(std::move(rv)); - else - return make_char("+" + rv); -} - -/** - * EBCDIC characters as hexadecimal string with sign - * */ -expr_ptr character_expression::c2x() const -{ - copy_return_on_error(this, character_expression); - if (value_.empty()) - return make_char(""); - - std::string rv; - rv.reserve(value_.size() * 2); - for (const char* j = value_.c_str(); *j != 0; ++j) - { - auto v = ebcdic_encoding::to_ebcdic(ebcdic_encoding::to_pseudoascii(j)); - rv.push_back(num_to_hex_char(v >> 4)); - rv.push_back(num_to_hex_char(v & 15)); - } - return make_char(std::move(rv)); -} - -/** - * decimal string to binary string - * */ -expr_ptr character_expression::d2b() const -{ - copy_return_on_error(this, character_expression); - size_t t = 0; - if (value_.empty()) - return make_char(""); - - int32_t val = 0; - try - { - val = std::stoi(value_, &t, 10); - } - catch (...) - { - t = 0; - } - - if (t != value_.length()) - return default_expr_with_error(error_messages::ec06()); - - return make_char(std::bitset<32>(val).to_string()); -} - -/** - * decimal string to EBCDIC string - * */ -expr_ptr character_expression::d2c() const -{ - copy_return_on_error(this, character_expression); - size_t t = 0; - if (value_.empty()) - return default_expr_with_error(error_messages::ec04()); - - try - { - int32_t val = std::stoi(value_, &t, 10); - if (t != value_.length()) - return default_expr_with_error(error_messages::ec06()); - return make_char(num_to_ebcdic(val)); - } - catch (...) - { - return default_expr_with_error(error_messages::ec08()); - } -} - -/** - * decimal string to headecimal string - * */ -expr_ptr character_expression::d2x() const -{ - copy_return_on_error(this, character_expression); - size_t t = 0; - if (value_.empty()) - return default_expr_with_error(error_messages::ec04()); - - try - { - int32_t val = std::stoi(value_, &t, 10); - if (t != value_.length()) - return default_expr_with_error(error_messages::ec07()); - - return make_char(num_to_hex(val)); - } - catch (...) - { - return default_expr_with_error(error_messages::ec08()); - } -} -/** - * dequote double_quote() string - * */ -expr_ptr character_expression::dcval() const -{ - copy_return_on_error(this, character_expression); - std::string v; - v.reserve(value_.length()); - for (auto i = value_.cbegin(); i != value_.end(); ++i) - { - // escaping double apostrophe '' and double ampersand && - if ((*i == '\'' && i + 1 != this->value_.end() && *(i + 1) == '\'') - || (*i == '&' && i + 1 != this->value_.end() && *(i + 1) == '&')) - ++i; - v.push_back(*i); - } - return make_char(v); -} - -/** - * remove quotation of ' from ends - * */ -expr_ptr character_expression::dequote() const -{ - copy_return_on_error(this, character_expression); - if (value_.empty()) - return make_char(""); - auto begin = value_.cbegin(); - auto end = value_.cend(); - if (value_[0] == '\'') - begin = std::next(begin); - if (value_[value_.length() - 1] == '\'') - end = std::prev(end); - if (begin <= end) - return make_char(std::string(begin, end)); - else - return make_char(""); -} - -/** - * double ' and & characters in string - * */ -expr_ptr character_expression::double_quote() const -{ - copy_return_on_error(this, character_expression); - std::string v; - for (char c : value_) - { - v.push_back(c); - if (c == '\'' || c == '&') - v.push_back(c); - } - return make_char(std::move(v)); -} - -/** - * hexadecimal string as binary string - * */ -expr_ptr character_expression::x2b() const -{ - copy_return_on_error(this, character_expression); - if (value_.empty()) - return make_char(""); - size_t tt = 0; - int32_t val = 0; - try - { - val = std::stoul(value_.c_str(), &tt, 16); - } - catch (...) - { - tt = 0; - } - if (tt != value_.length()) - return default_expr_with_error(error_messages::ec09()); - - auto rv = std::bitset<32>(val).to_string(); - // remove leading zeros - return make_char(rv.substr(32 - value_.length() * 4, value_.length() * 4)); -} - -/** - * hexadecimal string to number - * number interpreted as EBCDIC string - * */ -expr_ptr character_expression::x2c() const -{ - copy_return_on_error(this, character_expression); - size_t t = 0; - if (value_.empty()) - return make_char(""); - auto val = value_; - std::string rv; - auto it = val.cbegin(); - - if (val.length() % 2 == 1) - rv.append(ebcdic_encoding::to_ascii(hex_to_num(*(it++), &t))); - - for (; it != val.cend(); ++it) - { - char c = (char)hex_to_num(*it, &t); - if (t == 0) - break; - - c = (c << 4) + (char)hex_to_num(*(++it), &t); - if (t == 0) - break; - - rv.append(ebcdic_encoding::to_ascii(c)); - } - - if (t == 0) - return default_expr_with_error(error_messages::ec09()); - - return make_char(std::move(rv)); -} - -/** - * hexadecimal string as decimal string with sign - * */ -expr_ptr character_expression::x2d() const -{ - copy_return_on_error(this, character_expression); - if (value_.empty()) - return make_char("+0"); - - size_t tt = 0; - int32_t val = 0; - try - { - val = std::stoul(value_.c_str(), &tt, 16); - } - catch (...) - { - tt = 0; - } - if (tt != value_.length()) - return default_expr_with_error(error_messages::ec09()); - - return make_char((val >= 0 ? "+" : "") + std::to_string(val)); -} - -std::string character_expression::num_to_ebcdic(int32_t val) -{ - std::string c; - c.append(ebcdic_encoding::to_ascii((val >> 24) & 255)); - c.append(ebcdic_encoding::to_ascii((val >> 16) & 255)); - c.append(ebcdic_encoding::to_ascii((val >> 8) & 255)); - c.append(ebcdic_encoding::to_ascii((val >> 0) & 255)); - return c; -} - -char character_expression::num_to_hex_char(int32_t val) -{ - if (val < 0 || val >= 16) - throw std::runtime_error("value must be less than 16"); - return "0123456789ABCDEF"[val]; -} - -char character_expression::hex_to_num(char c, size_t* t) -{ - c = static_cast(toupper(c)); - *t = 1; - if (c >= '0' && c <= '9') - return c - '0'; - else if (c >= 'A' && c <= 'F') - return 10 + c - 'A'; - *t = 0; - return 0; -} - - -std::string character_expression::num_to_hex(int32_t val) -{ - std::string v; - for (size_t i = 0; i < 8; i++) - { - v.push_back(num_to_hex_char(15 & (val >> (28 - 4 * i)))); - } - return v; -} diff --git a/parser_library/src/expressions/character_expression.h b/parser_library/src/expressions/character_expression.h deleted file mode 100644 index b627ea687..000000000 --- a/parser_library/src/expressions/character_expression.h +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c) 2019 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_PARSER_HLASMCEXPRESSION_H -#define HLASMPLUGIN_PARSER_HLASMCEXPRESSION_H - -#include - -#include "expression.h" -#include "logic_expression.h" - -namespace hlasm_plugin::parser_library::expressions { - -class expression; -class character_expression; -using char_ptr = std::shared_ptr; -/** - * logic for character expression and operations on this type - * */ -class character_expression : public expression -{ -public: - character_expression() = default; - character_expression(character_expression&&) = default; - character_expression& operator=(character_expression&&) = default; - character_expression(const character_expression&); - character_expression(std::string); - - /** - * all operations involving arguments check for errors - * in all arguments immediately before accessing their values - * - * if any argument contains an error, it is copied - * and an erroneous expression (meaning with en error) - * is returned - * - * see: copy_return_on_error and copy_return_on_error_binary - * */ - - void append(std::string); - char_ptr append(const char_ptr& arg) const; - char_ptr append(const character_expression* arg) const; - - virtual expr_ptr binary_operation(str_ref operation_name, expr_ref arg2) const override; - virtual expr_ptr unary_operation(str_ref operation_name) const override; - - context::SET_t get_set_value() const override; - - /** - * special HLASM CA substring - * */ - template - char_ptr substring(int32_t dupl, const T& s, const T& e) const - { - if (dupl < 0) - return default_expr_with_error(error_messages::ec01()); - - int32_t start = 0; - int32_t len = static_cast(value_.length()); - - if (s != nullptr) - start = s->get_numeric_value() - 1; - - - if (e != nullptr) - len = e->get_numeric_value(); - - if (start < 0 || len < 0) - return default_expr_with_error(error_messages::ec02()); - - if ((size_t)start > value_.size()) - return default_expr_with_error(error_messages::ec02()); - - auto value = value_.substr(start, len); - - if (dupl > 1) - { - value.reserve(dupl * value.length()); - auto val = value; - for (int32_t i = 1; i < dupl; ++i) - value.append(val); - } - - return std::make_shared(std::move(value)); - } - - std::string get_str_val() const override; - - static std::string num_to_hex(int32_t val); - static char num_to_hex_char(int32_t val); - /** - * number as EBCDIC string - * */ - static std::string num_to_ebcdic(int32_t val); - static bool isalpha_hlasm(char c); - static char hex_to_num(char c, size_t*); - -private: - // str len - expr_ptr dclen() const; - expr_ptr isbin() const; - expr_ptr isdec() const; - expr_ptr ishex() const; - expr_ptr issym() const; - // interpret binary string as EBCDIC string - expr_ptr b2c() const; - /** - * convert binary string to decimal - * convert to string with sign - * */ - expr_ptr b2d() const; - /** - * convert binary string to hexadecimal - * convert to string with sign - * */ - expr_ptr b2x() const; - /** - * EBCDIC characters as binary - * */ - expr_ptr c2b() const; - /** - * EBCDIC characters as decimal string with sign - * */ - expr_ptr c2d() const; - /** - * EBCDIC characters as hexadecimal string with sign - * */ - expr_ptr c2x() const; - /** - * decimal string to binary string - * */ - expr_ptr d2b() const; - /** - * decimal string to EBCDIC string - * */ - expr_ptr d2c() const; - /** - * decimal string to headecimal string - * */ - expr_ptr d2x() const; - /** - * dequote double_quote() string - * */ - expr_ptr dcval() const; - /** - * remove quotation of ' from ends - * */ - expr_ptr dequote() const; - /** - * double ' and & characters in string - * */ - expr_ptr double_quote() const; - /** - * hexadecimal string as binary string - * */ - expr_ptr x2b() const; - /** - * hexadecimal string to number - * number interpreted as EBCDIC string - * */ - expr_ptr x2c() const; - /** - * hexadecimal string as decimal string with sign - * */ - expr_ptr x2d() const; - - std::string value_ = ""; -}; - -} // namespace hlasm_plugin::parser_library::expressions - -#endif diff --git a/parser_library/src/expressions/conditional_assembly/ca_expr_policy.cpp b/parser_library/src/expressions/conditional_assembly/ca_expr_policy.cpp new file mode 100644 index 000000000..41cf4fba2 --- /dev/null +++ b/parser_library/src/expressions/conditional_assembly/ca_expr_policy.cpp @@ -0,0 +1,405 @@ +#include "ca_expr_policy.h" +/* + * Copyright (c) 2019 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 "ca_expr_policy.h" + +namespace hlasm_plugin::parser_library::expressions { + +bool ca_arithmetic_policy::is_unary(ca_expr_ops op) { return op == ca_expr_ops::NOT; } +bool ca_binary_policy::is_unary(ca_expr_ops op) { return op == ca_expr_ops::NOT; } +bool ca_character_policy::is_unary(ca_expr_ops op) +{ + return op == ca_expr_ops::BYTE || op == ca_expr_ops::DOUBLE || op == ca_expr_ops::LOWER || op == ca_expr_ops::SIGNED + || op == ca_expr_ops::UPPER; +} + +bool ca_arithmetic_policy::multiple_words(ca_expr_ops) { return false; } +bool ca_binary_policy::multiple_words(ca_expr_ops op) +{ + return op == ca_expr_ops::AND || op == ca_expr_ops::OR || op == ca_expr_ops::XOR; +} +bool ca_character_policy::multiple_words(ca_expr_ops) { return false; } + +bool ca_arithmetic_policy::is_binary(ca_expr_ops op) +{ + return op == ca_expr_ops::SLA || op == ca_expr_ops::SLL || op == ca_expr_ops::SRA || op == ca_expr_ops::SRL + || op == ca_expr_ops::FIND || op == ca_expr_ops::INDEX || op == ca_expr_ops::AND || op == ca_expr_ops::OR + || op == ca_expr_ops::XOR; +} + +bool ca_binary_policy::is_binary(ca_expr_ops op) +{ + return op == ca_expr_ops::EQ || op == ca_expr_ops::NE || op == ca_expr_ops::LE || op == ca_expr_ops::LT + || op == ca_expr_ops::GE || op == ca_expr_ops::GT || op == ca_expr_ops::AND || op == ca_expr_ops::OR + || op == ca_expr_ops::XOR || op == ca_expr_ops::AND_NOT || op == ca_expr_ops::OR_NOT + || op == ca_expr_ops::XOR_NOT; +} + +bool ca_character_policy::is_binary(ca_expr_ops) { return false; } + +bool ca_arithmetic_policy::is_operator(ca_expr_ops op) { return is_unary(op) || is_binary(op); }; +bool ca_binary_policy::is_operator(ca_expr_ops op) { return is_unary(op) || is_binary(op); }; +bool ca_character_policy::is_operator(ca_expr_ops op) { return is_unary(op) || is_binary(op); }; + +bool ca_arithmetic_policy::is_function(ca_expr_funcs func) +{ + switch (func) + { + case ca_expr_funcs::B2A: + case ca_expr_funcs::C2A: + case ca_expr_funcs::D2A: + case ca_expr_funcs::DCLEN: + case ca_expr_funcs::FIND: + case ca_expr_funcs::INDEX: + case ca_expr_funcs::ISBIN: + case ca_expr_funcs::ISDEC: + case ca_expr_funcs::ISHEX: + case ca_expr_funcs::ISSYM: + case ca_expr_funcs::X2A: + return true; + default: + return false; + } +}; +bool ca_binary_policy::is_function(ca_expr_funcs) { return false; }; +bool ca_character_policy::is_function(ca_expr_funcs func) +{ + switch (func) + { + case ca_expr_funcs::A2B: + case ca_expr_funcs::A2C: + case ca_expr_funcs::A2D: + case ca_expr_funcs::A2X: + case ca_expr_funcs::B2C: + case ca_expr_funcs::B2D: + case ca_expr_funcs::B2X: + case ca_expr_funcs::BYTE: + case ca_expr_funcs::C2B: + case ca_expr_funcs::C2D: + case ca_expr_funcs::C2X: + case ca_expr_funcs::D2B: + case ca_expr_funcs::D2C: + case ca_expr_funcs::D2X: + case ca_expr_funcs::DCVAL: + case ca_expr_funcs::DEQUOTE: + case ca_expr_funcs::DOUBLE: + case ca_expr_funcs::ESYM: + case ca_expr_funcs::LOWER: + case ca_expr_funcs::SIGNED: + case ca_expr_funcs::SYSATTRA: + case ca_expr_funcs::SYSATTRP: + case ca_expr_funcs::UPPER: + case ca_expr_funcs::X2B: + case ca_expr_funcs::X2C: + case ca_expr_funcs::X2D: + return true; + default: + return false; + } +}; + +int ca_arithmetic_policy::get_priority(ca_expr_ops op) +{ + switch (op) + { + case ca_expr_ops::FIND: + case ca_expr_ops::INDEX: + return 0; + case ca_expr_ops::NOT: + return 1; + case ca_expr_ops::AND: + case ca_expr_ops::OR: + case ca_expr_ops::XOR: + return 2; + case ca_expr_ops::SLA: + case ca_expr_ops::SLL: + case ca_expr_ops::SRA: + case ca_expr_ops::SRL: + return 3; + default: + return 0; + } +} + +int ca_binary_policy::get_priority(ca_expr_ops op) +{ + switch (op) + { + case ca_expr_ops::EQ: + case ca_expr_ops::NE: + case ca_expr_ops::LE: + case ca_expr_ops::LT: + case ca_expr_ops::GE: + case ca_expr_ops::GT: + return 0; + case ca_expr_ops::NOT: + return 1; + case ca_expr_ops::AND: + case ca_expr_ops::AND_NOT: + return 2; + case ca_expr_ops::OR: + case ca_expr_ops::OR_NOT: + return 3; + case ca_expr_ops::XOR: + case ca_expr_ops::XOR_NOT: + return 4; + default: + return 0; + } +} + +int ca_character_policy::get_priority(ca_expr_ops) { return 0; } + +std::pair ca_arithmetic_policy::get_function_param_info(ca_expr_funcs func) +{ + if (func == ca_expr_funcs::FIND || func == ca_expr_funcs::INDEX) + return std::make_pair(2, context::SET_t_enum::C_TYPE); + else if (is_function(func)) + return std::make_pair(1, context::SET_t_enum::C_TYPE); + else + return std::make_pair(0, context::SET_t_enum::UNDEF_TYPE); +} +std::pair ca_binary_policy::get_function_param_info(ca_expr_funcs) +{ + return std::make_pair(0, context::SET_t_enum::UNDEF_TYPE); +} +std::pair ca_character_policy::get_function_param_info(ca_expr_funcs func) +{ + switch (func) + { + case ca_expr_funcs::A2B: + case ca_expr_funcs::A2C: + case ca_expr_funcs::A2D: + case ca_expr_funcs::A2X: + case ca_expr_funcs::BYTE: + case ca_expr_funcs::SIGNED: + return std::make_pair(1, context::SET_t_enum::A_TYPE); + case ca_expr_funcs::B2C: + case ca_expr_funcs::B2D: + case ca_expr_funcs::B2X: + case ca_expr_funcs::C2B: + case ca_expr_funcs::C2D: + case ca_expr_funcs::C2X: + case ca_expr_funcs::D2B: + case ca_expr_funcs::D2C: + case ca_expr_funcs::D2X: + case ca_expr_funcs::DCVAL: + case ca_expr_funcs::DEQUOTE: + case ca_expr_funcs::DOUBLE: + case ca_expr_funcs::ESYM: + case ca_expr_funcs::LOWER: + case ca_expr_funcs::SYSATTRA: + case ca_expr_funcs::SYSATTRP: + case ca_expr_funcs::UPPER: + case ca_expr_funcs::X2A: + case ca_expr_funcs::X2B: + case ca_expr_funcs::X2C: + case ca_expr_funcs::X2D: + return std::make_pair(1, context::SET_t_enum::C_TYPE); + default: + return std::make_pair(0, context::SET_t_enum::UNDEF_TYPE); + } +} + +context::SET_t_enum ca_arithmetic_policy::get_operands_type(ca_expr_ops op) +{ + switch (op) + { + case ca_expr_ops::FIND: + case ca_expr_ops::INDEX: + return context::SET_t_enum::C_TYPE; + case ca_expr_ops::NOT: + case ca_expr_ops::AND: + case ca_expr_ops::OR: + case ca_expr_ops::XOR: + case ca_expr_ops::SLA: + case ca_expr_ops::SLL: + case ca_expr_ops::SRA: + case ca_expr_ops::SRL: + return context::SET_t_enum::A_TYPE; + default: + return context::SET_t_enum::UNDEF_TYPE; + } +} + +context::SET_t_enum ca_binary_policy::get_operands_type(ca_expr_ops op) +{ + if (is_operator(op)) + return context::SET_t_enum::B_TYPE; + else + return context::SET_t_enum::UNDEF_TYPE; +} + +context::SET_t_enum ca_character_policy::get_operands_type(ca_expr_ops op) +{ + switch (op) + { + case ca_expr_ops::BYTE: + case ca_expr_ops::SIGNED: + return context::SET_t_enum::A_TYPE; + case ca_expr_ops::DOUBLE: + case ca_expr_ops::LOWER: + case ca_expr_ops::UPPER: + return context::SET_t_enum::C_TYPE; + default: + return context::SET_t_enum::UNDEF_TYPE; + } +} + +// string to op +#define S2O(X) \ + if (op == #X) \ + return ca_expr_ops::X + +ca_expr_ops get_expr_operator(const std::string& op) +{ + S2O(SLA); + S2O(SLL); + S2O(SRA); + S2O(SRL); + S2O(FIND); + S2O(INDEX); + S2O(AND_NOT); + S2O(OR_NOT); + S2O(XOR_NOT); + S2O(EQ); + S2O(NE); + S2O(LE); + S2O(LT); + S2O(GE); + S2O(GT); + S2O(AND); + S2O(OR); + S2O(XOR); + S2O(NOT); + S2O(BYTE); + S2O(DOUBLE); + S2O(LOWER); + S2O(SIGNED); + S2O(UPPER); + + return ca_expr_ops::UNKNOWN; +} + +ca_expr_ops ca_arithmetic_policy::get_operator(const std::string& symbol) { return get_expr_operator(symbol); } +ca_expr_ops ca_binary_policy::get_operator(const std::string& symbol) { return get_expr_operator(symbol); } +ca_expr_ops ca_character_policy::get_operator(const std::string& symbol) { return get_expr_operator(symbol); } + +ca_expr_funcs ca_arithmetic_policy::get_function(const std::string& symbol) +{ + return ca_common_expr_policy::get_function(symbol); +} +ca_expr_funcs ca_binary_policy::get_function(const std::string& symbol) +{ + return ca_common_expr_policy::get_function(symbol); +} +ca_expr_funcs ca_character_policy::get_function(const std::string& symbol) +{ + return ca_common_expr_policy::get_function(symbol); +} + +std::pair ca_common_expr_policy::get_function_param_info( + ca_expr_funcs func, context::SET_t_enum expr_kind) +{ + switch (expr_kind) + { + case context::SET_t_enum::A_TYPE: + return ca_arithmetic_policy::get_function_param_info(func); + case context::SET_t_enum::B_TYPE: + return ca_binary_policy::get_function_param_info(func); + case context::SET_t_enum::C_TYPE: + return ca_character_policy::get_function_param_info(func); + default: + return std::make_pair(0, context::SET_t_enum::UNDEF_TYPE); + } +} + +context::SET_t_enum ca_common_expr_policy::get_function_type(ca_expr_funcs func) +{ + if (ca_arithmetic_policy::is_function(func)) + return context::SET_t_enum::A_TYPE; + else if (ca_binary_policy::is_function(func)) + return context::SET_t_enum::B_TYPE; + else if (ca_character_policy::is_function(func)) + return context::SET_t_enum::C_TYPE; + return context::SET_t_enum::UNDEF_TYPE; +} + +context::SET_t_enum ca_common_expr_policy::get_operands_type(ca_expr_ops op, context::SET_t_enum expr_kind) +{ + switch (expr_kind) + { + case context::SET_t_enum::A_TYPE: + return ca_arithmetic_policy::get_operands_type(op); + case context::SET_t_enum::B_TYPE: + return ca_binary_policy::get_operands_type(op); + case context::SET_t_enum::C_TYPE: + return ca_character_policy::get_operands_type(op); + default: + return context::SET_t_enum::UNDEF_TYPE; + } +} + +// string to func +#define S2F(X) \ + if (op == #X) \ + return ca_expr_funcs::X + +ca_expr_funcs ca_common_expr_policy::get_function(const std::string& op) +{ + S2F(B2A); + S2F(C2A); + S2F(D2A); + S2F(DCLEN); + S2F(FIND); + S2F(INDEX); + S2F(ISBIN); + S2F(ISDEC); + S2F(ISHEX); + S2F(ISSYM); + S2F(X2A); + S2F(A2B); + S2F(A2C); + S2F(A2D); + S2F(A2X); + S2F(B2C); + S2F(B2D); + S2F(B2X); + S2F(BYTE); + S2F(C2B); + S2F(C2D); + S2F(C2X); + S2F(D2B); + S2F(D2C); + S2F(D2X); + S2F(DCVAL); + S2F(DEQUOTE); + S2F(DOUBLE); + S2F(ESYM); + S2F(LOWER); + S2F(SIGNED); + S2F(SYSATTRA); + S2F(SYSATTRP); + S2F(UPPER); + S2F(X2B); + S2F(X2C); + S2F(X2D); + + return ca_expr_funcs::UNKNOWN; +} + + +} // namespace hlasm_plugin::parser_library::expressions diff --git a/parser_library/src/expressions/conditional_assembly/ca_expr_policy.h b/parser_library/src/expressions/conditional_assembly/ca_expr_policy.h new file mode 100644 index 000000000..b5c8b2e70 --- /dev/null +++ b/parser_library/src/expressions/conditional_assembly/ca_expr_policy.h @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2019 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_CA_EXPR_POLICY_H +#define HLASMPLUGIN_PARSERLIBRARY_CA_EXPR_POLICY_H + +#include "context/common_types.h" +#include "context/id_storage.h" + +// the file contains policy classes for retrieving properties +// of built-in functions and function operators + +namespace hlasm_plugin::parser_library::expressions { + +enum class ca_expr_ops +{ + // arithmetic + SLA, + SLL, + SRA, + SRL, + FIND, + INDEX, + + // logical + AND_NOT, + OR_NOT, + XOR_NOT, + EQ, + NE, + LE, + LT, + GE, + GT, + + // arithmetic & logical + AND, + OR, + XOR, + NOT, + + // character + BYTE, + DOUBLE, + LOWER, + SIGNED, + UPPER, + + UNKNOWN +}; + +enum class ca_expr_funcs +{ + // arithmetic + B2A, + C2A, + D2A, + DCLEN, + FIND, + INDEX, + ISBIN, + ISDEC, + ISHEX, + ISSYM, + X2A, + + // character + A2B, + A2C, + A2D, + A2X, + B2C, + B2D, + B2X, + BYTE, + C2B, + C2D, + C2X, + D2B, + D2C, + D2X, + DCVAL, + DEQUOTE, + DOUBLE, + ESYM, + LOWER, + SIGNED, + SYSATTRA, + SYSATTRP, + UPPER, + X2B, + X2C, + X2D, + + UNKNOWN +}; + +// policy class for arithmetic functions and operators +class ca_arithmetic_policy +{ +public: + static constexpr context::SET_t_enum set_type = context::SET_t_enum::A_TYPE; + + // is unary arithmetic operation + static bool is_unary(ca_expr_ops op); + + // is binary arithmetic operation + static bool is_binary(ca_expr_ops op); + + // true if op can consist of multiple words (eg AND NOT) + static bool multiple_words(ca_expr_ops op); + + // get priority relative to rest of arithmetic operators + static int get_priority(ca_expr_ops op); + + // is arithmetic operator + static bool is_operator(ca_expr_ops op); + + // is arithmetic function + static bool is_function(ca_expr_funcs func); + + // transforms string operator to enum + static ca_expr_ops get_operator(const std::string& symbol); + + // transforms string function to enum + static ca_expr_funcs get_function(const std::string& symbol); + + // return number of required parameters and return type + static std::pair get_function_param_info(ca_expr_funcs func); + + // get operand types of operator op + static context::SET_t_enum get_operands_type(ca_expr_ops op); +}; + +// policy class for binary functions and operators +class ca_binary_policy +{ +public: + static constexpr context::SET_t_enum set_type = context::SET_t_enum::B_TYPE; + + // is unary binary operation + static bool is_unary(ca_expr_ops op); + + // is binary binary operation + static bool is_binary(ca_expr_ops op); + + // true if op can consist of multiple words (eg AND NOT) + static bool multiple_words(ca_expr_ops op); + + // get priority relative to rest of binary operators + static int get_priority(ca_expr_ops op); + + // is binary operator + static bool is_operator(ca_expr_ops op); + + // is binary function + static bool is_function(ca_expr_funcs func); + + // transforms string operator to enum + static ca_expr_ops get_operator(const std::string& symbol); + + // transforms string function to enum + static ca_expr_funcs get_function(const std::string& symbol); + + // return number of required parameters and return type + static std::pair get_function_param_info(ca_expr_funcs func); + + // get operand types of operator op + static context::SET_t_enum get_operands_type(ca_expr_ops op); +}; + +// policy class for character functions and operators +class ca_character_policy +{ +public: + static constexpr context::SET_t_enum set_type = context::SET_t_enum::C_TYPE; + + // is unary character operation + static bool is_unary(ca_expr_ops op); + + // is binary character operation + static bool is_binary(ca_expr_ops op); + + // true if op can consist of multiple words (eg AND NOT) + static bool multiple_words(ca_expr_ops op); + + // get priority relative to rest of character operators + static int get_priority(ca_expr_ops op); + + // is character operator + static bool is_operator(ca_expr_ops op); + + // is character function + static bool is_function(ca_expr_funcs func); + + // transforms string operator to enum + static ca_expr_ops get_operator(const std::string& symbol); + + // transforms string function to enum + static ca_expr_funcs get_function(const std::string& symbol); + + // return number of required parameters and return type + static std::pair get_function_param_info(ca_expr_funcs func); + + // get operand types of operator op + static context::SET_t_enum get_operands_type(ca_expr_ops op); +}; + +// policy class that aggregates some methods of specific policy classes above +class ca_common_expr_policy +{ +public: + static std::pair get_function_param_info( + ca_expr_funcs func, context::SET_t_enum expr_kind); + + static context::SET_t_enum get_function_type(ca_expr_funcs func); + + static context::SET_t_enum get_operands_type(ca_expr_ops op, context::SET_t_enum expr_kind); + + static ca_expr_funcs get_function(const std::string& symbol); +}; + +template +struct ca_expr_traits +{}; + +template<> +struct ca_expr_traits +{ + using policy_t = ca_arithmetic_policy; +}; + +template<> +struct ca_expr_traits +{ + using policy_t = ca_binary_policy; +}; + +template<> +struct ca_expr_traits +{ + using policy_t = ca_character_policy; +}; + +} // namespace hlasm_plugin::parser_library::expressions + + +#endif diff --git a/parser_library/src/expressions/conditional_assembly/ca_expression.cpp b/parser_library/src/expressions/conditional_assembly/ca_expression.cpp new file mode 100644 index 000000000..807a576ad --- /dev/null +++ b/parser_library/src/expressions/conditional_assembly/ca_expression.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019 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 "ca_expression.h" + +#include "expressions/evaluation_context.h" + +namespace hlasm_plugin::parser_library::expressions { + +ca_expression::ca_expression(context::SET_t_enum expr_kind, range expr_range) + : expr_range(std::move(expr_range)) + , expr_kind(expr_kind) +{} + +context::SET_t ca_expression::convert_return_types( + context::SET_t retval, context::SET_t_enum type, const evaluation_context& eval_ctx) const +{ + if (type != retval.type) + { + if (retval.type == context::SET_t_enum::A_TYPE && type == context::SET_t_enum::B_TYPE + && (retval.access_a() == 0 || retval.access_a() == 1)) + return retval.access_a() == 1; + + eval_ctx.add_diagnostic(diagnostic_op::error_CE004(expr_range)); + return context::SET_t(expr_kind); + } + return retval; +} + +} // namespace hlasm_plugin::parser_library::expressions diff --git a/parser_library/src/expressions/conditional_assembly/ca_expression.h b/parser_library/src/expressions/conditional_assembly/ca_expression.h new file mode 100644 index 000000000..1e37d584a --- /dev/null +++ b/parser_library/src/expressions/conditional_assembly/ca_expression.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2019 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_CA_EXPRESSION_H +#define HLASMPLUGIN_PARSERLIBRARY_CA_EXPRESSION_H + +#include +#include + +#include "context/common_types.h" +#include "context/ordinary_assembly/dependable.h" +#include "diagnosable_impl.h" + +namespace hlasm_plugin::parser_library::expressions { + +class ca_expression; +using ca_expr_ptr = std::unique_ptr; +using undef_sym_set = std::set; + +struct evaluation_context; + +// base class for conditional assembly expressions +class ca_expression : public diagnosable_op_impl +{ +public: + range expr_range; + context::SET_t_enum expr_kind; + + ca_expression(context::SET_t_enum expr_kind, range expr_range); + + // retrieves set of attributed symbols that are not yet defined + virtual undef_sym_set get_undefined_attributed_symbols(const context::dependency_solver& solver) const = 0; + + // builds parts of the expression tree that could not be built during parsing + virtual void resolve_expression_tree(context::SET_t_enum kind) = 0; + + virtual bool is_character_expression() const = 0; + + template + T evaluate(const evaluation_context& eval_ctx) const; + + virtual context::SET_t evaluate(const evaluation_context& eval_ctx) const = 0; + + virtual ~ca_expression() = default; + +protected: + context::SET_t convert_return_types( + context::SET_t retval, context::SET_t_enum type, const evaluation_context& eval_ctx) const; +}; + + +template +inline T ca_expression::evaluate(const evaluation_context& eval_ctx) const +{ + static_assert(context::object_traits::type_enum != context::SET_t_enum::UNDEF_TYPE); + auto ret = evaluate(eval_ctx); + + ret = convert_return_types(std::move(ret), context::object_traits::type_enum, eval_ctx); + + if constexpr (context::object_traits::type_enum == context::SET_t_enum::A_TYPE) + return ret.access_a(); + if constexpr (context::object_traits::type_enum == context::SET_t_enum::B_TYPE) + return ret.access_b(); + if constexpr (context::object_traits::type_enum == context::SET_t_enum::C_TYPE) + return std::move(ret.access_c()); +} + +} // namespace hlasm_plugin::parser_library::expressions + +#endif diff --git a/parser_library/src/expressions/conditional_assembly/ca_operator_binary.cpp b/parser_library/src/expressions/conditional_assembly/ca_operator_binary.cpp new file mode 100644 index 000000000..9ea96285b --- /dev/null +++ b/parser_library/src/expressions/conditional_assembly/ca_operator_binary.cpp @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2019 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 "ca_operator_binary.h" + +#include + +#include "ebcdic_encoding.h" +#include "expressions/evaluation_context.h" +#include "terms/ca_function.h" +#include "terms/ca_string.h" + +namespace hlasm_plugin::parser_library::expressions { + +ca_binary_operator::ca_binary_operator( + ca_expr_ptr left_expr, ca_expr_ptr right_expr, context::SET_t_enum expr_kind, range expr_range) + : ca_expression(expr_kind, std::move(expr_range)) + , left_expr(std::move(left_expr)) + , right_expr(std::move(right_expr)) +{} + +undef_sym_set ca_binary_operator::get_undefined_attributed_symbols(const context::dependency_solver& solver) const +{ + auto tmp = left_expr->get_undefined_attributed_symbols(solver); + tmp.merge(right_expr->get_undefined_attributed_symbols(solver)); + return tmp; +} + +void ca_binary_operator::resolve_expression_tree(context::SET_t_enum kind) +{ + if (expr_kind != kind) + add_diagnostic(diagnostic_op::error_CE004(expr_range)); + else + { + left_expr->resolve_expression_tree(kind); + right_expr->resolve_expression_tree(kind); + } +} + +void ca_binary_operator::collect_diags() const +{ + collect_diags_from_child(*left_expr); + collect_diags_from_child(*right_expr); +} + +bool ca_binary_operator::is_character_expression() const { return left_expr->is_character_expression(); } + +context::SET_t ca_binary_operator::evaluate(const evaluation_context& eval_ctx) const +{ + return operation(left_expr->evaluate(eval_ctx), right_expr->evaluate(eval_ctx), eval_ctx); +} + +ca_function_binary_operator::ca_function_binary_operator(ca_expr_ptr left_expr, + ca_expr_ptr right_expr, + ca_expr_ops function, + context::SET_t_enum expr_kind, + range expr_range) + : ca_binary_operator(std::move(left_expr), std::move(right_expr), expr_kind, std::move(expr_range)) + , function(function) +{} + +void ca_function_binary_operator::resolve_expression_tree(context::SET_t_enum kind) +{ + if (expr_kind != kind) + add_diagnostic(diagnostic_op::error_CE004(expr_range)); + else if ((function == ca_expr_ops::FIND || function == ca_expr_ops::INDEX) && !left_expr->is_character_expression()) + add_diagnostic(diagnostic_op::error_CE004(left_expr->expr_range)); + else + { + context::SET_t_enum operands_kind; + + if (is_relational()) + { + operands_kind = + left_expr->is_character_expression() ? context::SET_t_enum::C_TYPE : context::SET_t_enum::A_TYPE; + } + else + operands_kind = ca_common_expr_policy::get_operands_type(function, kind); + + left_expr->resolve_expression_tree(operands_kind); + right_expr->resolve_expression_tree(operands_kind); + } +} + +context::A_t shift_operands(context::A_t lhs, context::A_t rhs, ca_expr_ops shift) +{ + auto shift_part = rhs & 0x3f; // first 6 bits + if (shift_part == 0) + return rhs; + + std::uint32_t unsigned_lhs = lhs; + auto sign_bit = unsigned_lhs & (1U << 31); + + unsigned int result; + + if (shift_part >= 32) + { + switch (shift) + { + case ca_expr_ops::SLA: + result = sign_bit; + break; + case ca_expr_ops::SRA: + result = ~0U; + break; + default: + result = 0; + break; + } + return result; + } + + switch (shift) + { + case ca_expr_ops::SLA: + result = (unsigned_lhs << shift_part) | sign_bit; + break; + case ca_expr_ops::SLL: + result = unsigned_lhs << shift_part; + break; + case ca_expr_ops::SRA: + if (sign_bit) + result = (unsigned_lhs >> shift_part) | (~0U << (32 - shift_part)); + else + result = unsigned_lhs >> shift_part; + break; + case ca_expr_ops::SRL: + result = unsigned_lhs >> shift_part; + break; + default: + result = 0; + break; + } + + return result; +} + +context::SET_t ca_function_binary_operator::operation( + context::SET_t lhs, context::SET_t rhs, const evaluation_context&) const +{ + if (expr_kind == context::SET_t_enum::A_TYPE) + { + switch (function) + { + case ca_expr_ops::SLA: + case ca_expr_ops::SLL: + case ca_expr_ops::SRA: + case ca_expr_ops::SRL: + return shift_operands(lhs.access_a(), rhs.access_a(), function); + case ca_expr_ops::FIND: + return ca_function::FIND(lhs.access_c(), rhs.access_c()); + case ca_expr_ops::INDEX: + return ca_function::INDEX(lhs.access_c(), rhs.access_c()); + case ca_expr_ops::AND: + return lhs.access_a() & rhs.access_a(); + case ca_expr_ops::OR: + return lhs.access_a() | rhs.access_a(); + case ca_expr_ops::XOR: + return lhs.access_a() ^ rhs.access_a(); + default: + break; + } + } + else if (expr_kind == context::SET_t_enum::B_TYPE) + { + int comp = 0; + if (is_relational()) + comp = compare_relational(lhs, rhs, left_expr->expr_kind); + + switch (function) + { + case ca_expr_ops::EQ: + return comp == 0; + case ca_expr_ops::NE: + return comp != 0; + case ca_expr_ops::LE: + return comp <= 0; + case ca_expr_ops::LT: + return comp < 0; + case ca_expr_ops::GE: + return comp >= 0; + case ca_expr_ops::GT: + return comp > 0; + case ca_expr_ops::AND: + return lhs.access_b() && rhs.access_b(); + case ca_expr_ops::OR: + return lhs.access_b() || rhs.access_b(); + case ca_expr_ops::XOR: + return lhs.access_b() != rhs.access_b(); + case ca_expr_ops::AND_NOT: + return lhs.access_b() && !rhs.access_b(); + case ca_expr_ops::OR_NOT: + return lhs.access_b() || !rhs.access_b(); + case ca_expr_ops::XOR_NOT: + return lhs.access_b() != !rhs.access_b(); + default: + break; + } + } + return context::SET_t(expr_kind); +} + +int ca_function_binary_operator::compare_string(const context::C_t& lhs, const context::C_t& rhs) +{ + int diff = (int)lhs.size() - (int)rhs.size(); + + if (diff != 0) + return diff; + + return ebcdic_encoding::to_ebcdic(lhs).compare(ebcdic_encoding::to_ebcdic(rhs)); +} + +int ca_function_binary_operator::compare_relational( + const context::SET_t& lhs, const context::SET_t& rhs, context::SET_t_enum type) +{ + switch (type) + { + case context::SET_t_enum::A_TYPE: + return lhs.access_a() - rhs.access_a(); + case context::SET_t_enum::C_TYPE: + return compare_string(lhs.access_c(), rhs.access_c()); + default: + return 0; + } +} + +bool ca_function_binary_operator::is_relational() const +{ + switch (function) + { + case ca_expr_ops::EQ: + case ca_expr_ops::NE: + case ca_expr_ops::LE: + case ca_expr_ops::LT: + case ca_expr_ops::GE: + case ca_expr_ops::GT: + return true; + default: + return false; + } +} + +context::A_t overflow_transform(std::int64_t val, range expr_range, const evaluation_context& eval_ctx) +{ + if (val > std::numeric_limits::max()) + { + eval_ctx.add_diagnostic(diagnostic_op::error_CE013(expr_range)); + return 0; + } + else if (val < std::numeric_limits::min()) + { + eval_ctx.add_diagnostic(diagnostic_op::error_CE014(expr_range)); + return 0; + } + else + return (context::A_t)val; +} + +context::SET_t ca_add::operation( + const context::SET_t& lhs, const context::SET_t& rhs, range expr_range, const evaluation_context& eval_ctx) +{ + return overflow_transform((std::int64_t)lhs.access_a() + (std::int64_t)rhs.access_a(), expr_range, eval_ctx); +} + +context::SET_t ca_sub::operation( + const context::SET_t& lhs, const context::SET_t& rhs, range expr_range, const evaluation_context& eval_ctx) +{ + return overflow_transform((std::int64_t)lhs.access_a() - (std::int64_t)rhs.access_a(), expr_range, eval_ctx); +} + +context::SET_t ca_mul::operation( + const context::SET_t& lhs, const context::SET_t& rhs, range expr_range, const evaluation_context& eval_ctx) +{ + return overflow_transform((std::int64_t)lhs.access_a() * (std::int64_t)rhs.access_a(), expr_range, eval_ctx); +} + +context::SET_t ca_div::operation( + const context::SET_t& lhs, const context::SET_t& rhs, range expr_range, const evaluation_context& eval_ctx) +{ + if (rhs.access_a() == 0) + return 0; + return overflow_transform((std::int64_t)lhs.access_a() / (std::int64_t)rhs.access_a(), expr_range, eval_ctx); +} + +context::SET_t ca_conc::operation( + context::SET_t lhs, context::SET_t rhs, range expr_range, const evaluation_context& eval_ctx) +{ + if (lhs.access_c().size() + rhs.access_c().size() > ca_string::MAX_STR_SIZE) + { + eval_ctx.add_diagnostic(diagnostic_op::error_CE011(expr_range)); + return context::object_traits::default_v(); + } + auto& ret = lhs.access_c(); + ret.reserve(ret.size() + rhs.access_c().size()); + ret.append(rhs.access_c().begin(), rhs.access_c().end()); + return lhs; +} + +} // namespace hlasm_plugin::parser_library::expressions diff --git a/parser_library/src/expressions/conditional_assembly/ca_operator_binary.h b/parser_library/src/expressions/conditional_assembly/ca_operator_binary.h new file mode 100644 index 000000000..1564ef27f --- /dev/null +++ b/parser_library/src/expressions/conditional_assembly/ca_operator_binary.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2019 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_CA_OPERATOR_BINARY_H +#define HLASMPLUGIN_PARSERLIBRARY_CA_OPERATOR_BINARY_H + +#include "ca_expr_policy.h" +#include "ca_expression.h" + +namespace hlasm_plugin::parser_library::expressions { + +// abstract class for binary CA operators +class ca_binary_operator : public ca_expression +{ +public: + const ca_expr_ptr left_expr; + const ca_expr_ptr right_expr; + + ca_binary_operator(ca_expr_ptr left_expr, ca_expr_ptr right_expr, context::SET_t_enum expr_kind, range expr_range); + + virtual undef_sym_set get_undefined_attributed_symbols(const context::dependency_solver& solver) const override; + + virtual void resolve_expression_tree(context::SET_t_enum kind) override; + + virtual void collect_diags() const override; + + virtual bool is_character_expression() const override; + + virtual context::SET_t evaluate(const evaluation_context& eval_ctx) const override; + + virtual context::SET_t operation( + context::SET_t lhs, context::SET_t rhs, const evaluation_context& eval_ctx) const = 0; +}; + +// binary CA operators - + - * / . +template +class ca_basic_binary_operator : public ca_binary_operator +{ +public: + ca_basic_binary_operator(ca_expr_ptr left_expr, ca_expr_ptr right_expr, range expr_range) + : ca_binary_operator(std::move(left_expr), std::move(right_expr), OP::type, std::move(expr_range)) + {} + + virtual context::SET_t operation( + context::SET_t lhs, context::SET_t rhs, const evaluation_context& eval_ctx) const override + { + return OP::operation(std::move(lhs), std::move(rhs), expr_range, eval_ctx); + } +}; + +// function binary CA operators - AND, SLL, OR, ... +class ca_function_binary_operator : public ca_binary_operator +{ +public: + ca_expr_ops function; + + ca_function_binary_operator(ca_expr_ptr left_expr, + ca_expr_ptr right_expr, + ca_expr_ops function, + context::SET_t_enum expr_kind, + range expr_range); + + virtual void resolve_expression_tree(context::SET_t_enum kind) override; + + virtual context::SET_t operation( + context::SET_t lhs, context::SET_t rhs, const evaluation_context& eval_ctx) const override; + + static int compare_string(const context::C_t& lhs, const context::C_t& rhs); + static int compare_relational(const context::SET_t& lhs, const context::SET_t& rhs, context::SET_t_enum type); + +private: + bool is_relational() const; +}; + +struct ca_add +{ + static constexpr context::SET_t_enum type = context::SET_t_enum::A_TYPE; + + static context::SET_t operation( + const context::SET_t& lhs, const context::SET_t& rhs, range expr_range, const evaluation_context& eval_ctx); +}; + +struct ca_sub +{ + static constexpr context::SET_t_enum type = context::SET_t_enum::A_TYPE; + + static context::SET_t operation( + const context::SET_t& lhs, const context::SET_t& rhs, range expr_range, const evaluation_context& eval_ctx); +}; + +struct ca_mul +{ + static constexpr context::SET_t_enum type = context::SET_t_enum::A_TYPE; + + static context::SET_t operation( + const context::SET_t& lhs, const context::SET_t& rhs, range expr_range, const evaluation_context& eval_ctx); +}; + +struct ca_div +{ + static constexpr context::SET_t_enum type = context::SET_t_enum::A_TYPE; + + static context::SET_t operation( + const context::SET_t& lhs, const context::SET_t& rhs, range expr_range, const evaluation_context& eval_ctx); +}; + +struct ca_conc +{ + static constexpr context::SET_t_enum type = context::SET_t_enum::C_TYPE; + + static context::SET_t operation( + context::SET_t lhs, context::SET_t rhs, range expr_range, const evaluation_context& eval_ctx); +}; + +} // namespace hlasm_plugin::parser_library::expressions + + +#endif diff --git a/parser_library/src/expressions/conditional_assembly/ca_operator_unary.cpp b/parser_library/src/expressions/conditional_assembly/ca_operator_unary.cpp new file mode 100644 index 000000000..ae9cba74a --- /dev/null +++ b/parser_library/src/expressions/conditional_assembly/ca_operator_unary.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2019 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 "ca_operator_unary.h" + +#include + +#include "ebcdic_encoding.h" +#include "expressions/evaluation_context.h" +#include "terms/ca_function.h" + +namespace hlasm_plugin::parser_library::expressions { + +ca_unary_operator::ca_unary_operator(ca_expr_ptr expr, context::SET_t_enum expr_kind, range expr_range) + : ca_expression(expr_kind, std::move(expr_range)) + , expr(std::move(expr)) +{} + +undef_sym_set ca_unary_operator::get_undefined_attributed_symbols(const context::dependency_solver& solver) const +{ + return expr->get_undefined_attributed_symbols(solver); +} + +void ca_unary_operator::resolve_expression_tree(context::SET_t_enum kind) +{ + if (expr_kind != kind) + add_diagnostic(diagnostic_op::error_CE004(expr_range)); + else + expr->resolve_expression_tree(kind); +} + +void ca_unary_operator::collect_diags() const { collect_diags_from_child(*expr); } + +bool ca_unary_operator::is_character_expression() const { return false; } + +context::SET_t ca_unary_operator::evaluate(const evaluation_context& eval_ctx) const +{ + return operation(expr->evaluate(eval_ctx), eval_ctx); +} + +ca_function_unary_operator::ca_function_unary_operator( + ca_expr_ptr expr, ca_expr_ops function, context::SET_t_enum kind, range expr_range) + : ca_unary_operator(std::move(expr), kind, std::move(expr_range)) + , function(function) +{} + +void ca_function_unary_operator::resolve_expression_tree(context::SET_t_enum kind) +{ + if (expr_kind != kind) + add_diagnostic(diagnostic_op::error_CE004(expr_range)); + else + expr->resolve_expression_tree(ca_common_expr_policy::get_operands_type(function, kind)); +} + +context::SET_t ca_function_unary_operator::operation(context::SET_t operand, const evaluation_context& eval_ctx) const +{ + if (expr_kind == context::SET_t_enum::A_TYPE) + { + if (function == ca_expr_ops::NOT) + return ~operand.access_a(); + } + else if (expr_kind == context::SET_t_enum::B_TYPE) + { + if (function == ca_expr_ops::NOT) + return !operand.access_b(); + } + else if (expr_kind == context::SET_t_enum::C_TYPE) + { + diagnostic_adder add_diagnostic(&eval_ctx, expr_range); + switch (function) + { + case ca_expr_ops::BYTE: + return ca_function::BYTE(operand.access_a(), add_diagnostic); + case ca_expr_ops::DOUBLE: + return ca_function::DOUBLE(operand.access_c(), add_diagnostic); + case ca_expr_ops::LOWER: + return ca_function::LOWER(std::move(operand.access_c())); + case ca_expr_ops::SIGNED: + return ca_function::SIGNED(operand.access_a()); + case ca_expr_ops::UPPER: + return ca_function::UPPER(std::move(operand.access_c())); + default: + break; + } + } + return context::SET_t(expr_kind); +} + +ca_plus_operator::ca_plus_operator(ca_expr_ptr expr, range expr_range) + : ca_unary_operator(std::move(expr), context::SET_t_enum::A_TYPE, std::move(expr_range)) +{} + +context::SET_t ca_plus_operator::operation(context::SET_t operand, const evaluation_context&) const +{ + return operand.access_a(); +} + +ca_minus_operator::ca_minus_operator(ca_expr_ptr expr, range expr_range) + : ca_unary_operator(std::move(expr), context::SET_t_enum::A_TYPE, std::move(expr_range)) +{} + +context::SET_t ca_minus_operator::operation(context::SET_t operand, const evaluation_context&) const +{ + return -operand.access_a(); +} + +ca_par_operator::ca_par_operator(ca_expr_ptr expr, range expr_range) + : ca_unary_operator(std::move(expr), context::SET_t_enum::UNDEF_TYPE, std::move(expr_range)) +{} + +void ca_par_operator::resolve_expression_tree(context::SET_t_enum kind) +{ + expr->resolve_expression_tree(kind); + expr_kind = expr->expr_kind; +} + +context::SET_t ca_par_operator::operation(context::SET_t operand, const evaluation_context&) const { return operand; } + +} // namespace hlasm_plugin::parser_library::expressions diff --git a/parser_library/src/expressions/conditional_assembly/ca_operator_unary.h b/parser_library/src/expressions/conditional_assembly/ca_operator_unary.h new file mode 100644 index 000000000..a5a8a4541 --- /dev/null +++ b/parser_library/src/expressions/conditional_assembly/ca_operator_unary.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2019 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_CA_OPERATOR_UNARY_H +#define HLASMPLUGIN_PARSERLIBRARY_CA_OPERATOR_UNARY_H + +#include "ca_expr_policy.h" +#include "ca_expression.h" + +namespace hlasm_plugin::parser_library::expressions { + +class ca_unary_operator : public ca_expression +{ +public: + const ca_expr_ptr expr; + + ca_unary_operator(ca_expr_ptr expr, context::SET_t_enum expr_kind, range expr_range); + + virtual undef_sym_set get_undefined_attributed_symbols(const context::dependency_solver& solver) const override; + + virtual void resolve_expression_tree(context::SET_t_enum kind) override; + + virtual void collect_diags() const override; + + virtual bool is_character_expression() const override; + + virtual context::SET_t evaluate(const evaluation_context& eval_ctx) const override; + + virtual context::SET_t operation(context::SET_t operand, const evaluation_context& eval_ctx) const = 0; +}; + +class ca_plus_operator : public ca_unary_operator +{ +public: + ca_plus_operator(ca_expr_ptr expr, range expr_range); + + virtual context::SET_t operation(context::SET_t operand, const evaluation_context& eval_ctx) const override; +}; + +class ca_minus_operator : public ca_unary_operator +{ +public: + ca_minus_operator(ca_expr_ptr expr, range expr_range); + + virtual context::SET_t operation(context::SET_t operand, const evaluation_context& eval_ctx) const override; +}; + +class ca_par_operator : public ca_unary_operator +{ +public: + ca_par_operator(ca_expr_ptr expr, range expr_range); + + virtual void resolve_expression_tree(context::SET_t_enum kind) override; + + virtual context::SET_t operation(context::SET_t operand, const evaluation_context& eval_ctx) const override; +}; + +// NOT, BYTE, ... +class ca_function_unary_operator : public ca_unary_operator +{ +public: + ca_expr_ops function; + + ca_function_unary_operator(ca_expr_ptr expr, ca_expr_ops function, context::SET_t_enum expr_kind, range expr_range); + + virtual void resolve_expression_tree(context::SET_t_enum kind) override; + + virtual context::SET_t operation(context::SET_t operand, const evaluation_context& eval_ctx) const override; +}; + +} // namespace hlasm_plugin::parser_library::expressions + + +#endif diff --git a/parser_library/src/expressions/conditional_assembly/terms/ca_constant.cpp b/parser_library/src/expressions/conditional_assembly/terms/ca_constant.cpp new file mode 100644 index 000000000..0ff93217d --- /dev/null +++ b/parser_library/src/expressions/conditional_assembly/terms/ca_constant.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2019 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 "ca_constant.h" + +#include "ca_function.h" + +namespace hlasm_plugin::parser_library::expressions { + +ca_constant::ca_constant(context::A_t value, range expr_range) + : ca_expression(context::SET_t_enum::A_TYPE, std::move(expr_range)) + , value(value) +{} + +undef_sym_set ca_constant::get_undefined_attributed_symbols(const context::dependency_solver&) const +{ + return undef_sym_set(); +} + +void ca_constant::resolve_expression_tree(context::SET_t_enum kind) +{ + if (kind == context::SET_t_enum::C_TYPE) + add_diagnostic(diagnostic_op::error_CE004(expr_range)); +} + +void ca_constant::collect_diags() const +{ + // nothing to collect +} + +bool ca_constant::is_character_expression() const { return false; } + +context::SET_t ca_constant::evaluate(const evaluation_context&) const { return value; } + +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) + { + add_diagnostic(diagnostic_op::error_CE015); + return context::object_traits::default_v(); + } + + switch (std::toupper(type.front())) + { + 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(); + } +} + +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); + else + return self_defining_term("D", value, add_diagnostic); +} + +std::optional ca_constant::try_self_defining_term(const std::string& value) +{ + auto empty_add = diagnostic_adder(); + auto ret = self_defining_term(value, empty_add); + if (empty_add.diagnostics_present) + return std::nullopt; + else + return ret; +} + +} // namespace hlasm_plugin::parser_library::expressions diff --git a/parser_library/src/expressions/conditional_assembly/terms/ca_constant.h b/parser_library/src/expressions/conditional_assembly/terms/ca_constant.h new file mode 100644 index 000000000..415dfb49e --- /dev/null +++ b/parser_library/src/expressions/conditional_assembly/terms/ca_constant.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2019 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_CA_CONSTANT_H +#define HLASMPLUGIN_PARSERLIBRARY_CA_CONSTANT_H + +#include +#include + +#include "../ca_expression.h" +#include "diagnosable_ctx.h" +#include "diagnostic_adder.h" + +namespace hlasm_plugin::parser_library::expressions { + +// represents CA expression constant +class ca_constant : public ca_expression +{ +public: + const context::A_t value; + + ca_constant(context::A_t value, range expr_range); + + virtual undef_sym_set get_undefined_attributed_symbols(const context::dependency_solver& solver) const override; + + virtual void resolve_expression_tree(context::SET_t_enum kind) override; + + virtual void collect_diags() const override; + + virtual bool is_character_expression() const override; + + virtual context::SET_t evaluate(const evaluation_context& eval_ctx) const override; + + static context::A_t self_defining_term( + std::string_view type, std::string_view value, diagnostic_adder& add_diagnostic); + + static context::A_t self_defining_term(const std::string& value, diagnostic_adder& add_diagnostic); + + static std::optional try_self_defining_term(const std::string& value); +}; + +} // namespace hlasm_plugin::parser_library::expressions + + +#endif diff --git a/parser_library/src/expressions/conditional_assembly/terms/ca_expr_list.cpp b/parser_library/src/expressions/conditional_assembly/terms/ca_expr_list.cpp new file mode 100644 index 000000000..996f000ef --- /dev/null +++ b/parser_library/src/expressions/conditional_assembly/terms/ca_expr_list.cpp @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2019 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 "ca_expr_list.h" + +#include + +#include "../ca_operator_binary.h" +#include "../ca_operator_unary.h" +#include "ca_function.h" +#include "ca_symbol.h" + +namespace hlasm_plugin::parser_library::expressions { + +ca_expr_list::ca_expr_list(std::vector expr_list, range expr_range) + : ca_expression(context::SET_t_enum::UNDEF_TYPE, std::move(expr_range)) + , expr_list(std::move(expr_list)) +{} + +undef_sym_set ca_expr_list::get_undefined_attributed_symbols(const context::dependency_solver& solver) const +{ + undef_sym_set tmp; + for (auto&& expr : expr_list) + tmp.merge(expr->get_undefined_attributed_symbols(solver)); + return tmp; +} + +bool is_symbol(const ca_expr_ptr& expr) { return dynamic_cast(expr.get()) != nullptr; } + +const std::string& get_symbol(const ca_expr_ptr& expr) { return *dynamic_cast(expr.get())->symbol; } + +void tidy_list(std::vector& expr_list) +{ + for (int idx = (int)expr_list.size() - 1; idx >= 0; --idx) + { + if (!expr_list[idx]) + expr_list.erase(expr_list.begin() + idx); + } +} + +void ca_expr_list::resolve_expression_tree(context::SET_t_enum kind) +{ + expr_kind = kind; + + tidy_list(expr_list); + if (kind == context::SET_t_enum::B_TYPE) + unknown_functions_to_operators(); + + if (kind == context::SET_t_enum::A_TYPE) + resolve(); + else if (kind == context::SET_t_enum::B_TYPE) + resolve(); + else if (kind == context::SET_t_enum::C_TYPE) + resolve(); + else + assert(false); +} + +void ca_expr_list::collect_diags() const +{ + for (auto&& expr : expr_list) + collect_diags_from_child(*expr); +} + +bool ca_expr_list::is_character_expression() const { return false; } + +context::SET_t ca_expr_list::evaluate(const evaluation_context& eval_ctx) const +{ + assert(expr_list.size() <= 1); + + if (expr_list.empty()) + return context::SET_t(expr_kind); + return expr_list.front()->evaluate(eval_ctx); +} + +void ca_expr_list::unknown_functions_to_operators() +{ + for (int idx = (int)expr_list.size() - 1; idx >= 0; --idx) + { + if (auto expr_func = dynamic_cast(expr_list[idx].get()); + expr_func && expr_func->function == ca_expr_funcs::UNKNOWN && expr_func->parameters.size() == 1) + { + auto holder = std::move(expr_list[idx]); + auto true_func = dynamic_cast(holder.get()); + if (true_func->duplication_factor) + { + auto expr_r = true_func->duplication_factor->expr_range; + expr_list[idx] = std::make_unique(std::move(true_func->duplication_factor), expr_r); + + expr_r = true_func->parameters.front()->expr_range; + expr_list.insert(expr_list.begin() + idx + 1, + std::make_unique(std::move(true_func->parameters.front()), expr_r)); + + expr_r = true_func->expr_range; + expr_list.insert( + expr_list.begin() + idx + 1, std::make_unique(true_func->function_name, expr_r)); + } + else + { + auto expr_r = true_func->expr_range; + expr_list[idx] = std::make_unique(true_func->function_name, expr_r); + + expr_r = true_func->parameters.front()->expr_range; + expr_list.insert(expr_list.begin() + idx + 1, + std::make_unique(std::move(true_func->parameters.front()), expr_r)); + } + } + } +} + +template +void ca_expr_list::resolve() +{ + if (expr_list.empty()) + { + add_diagnostic(diagnostic_op::error_CE003(expr_range)); + return; + } + + size_t it = 0; + bool err = false; + + ca_expr_ptr final_expr = retrieve_term::policy_t>(it, 0); + err |= final_expr == nullptr; + + while (it != expr_list.size() && !err) + { + auto op_range = expr_list[it]->expr_range; + + auto [prio, op_type] = retrieve_binary_operator::policy_t>(it, err); + + auto r_expr = retrieve_term::policy_t>(++it, prio); + err |= r_expr == nullptr; + + final_expr = std::make_unique( + std::move(final_expr), std::move(r_expr), op_type, context::object_traits::type_enum, op_range); + } + + if (err) + { + expr_list.clear(); + return; + } + + // resolve created tree + final_expr->resolve_expression_tree(context::object_traits::type_enum); + + // move resolved tree to the front of the array + expr_list.clear(); + expr_list.emplace_back(std::move(final_expr)); +} + +template +ca_expr_ptr ca_expr_list::retrieve_term(size_t& it, int priority) +{ + // list is exhausted + if (it == expr_list.size()) + { + auto r = expr_list[it - 1]->expr_range; + r.start = r.end; + r.end.column++; + add_diagnostic(diagnostic_op::error_CE003(r)); + return nullptr; + } + + // first possible term + auto& curr_expr = expr_list[it]; + + // is unary op + if (is_symbol(curr_expr)) + { + if (auto op_type = EXPR_POLICY::get_operator(get_symbol(curr_expr)); EXPR_POLICY::is_unary(op_type)) + { + auto new_expr = retrieve_term(++it, EXPR_POLICY::get_priority(op_type)); + if (!new_expr) + return nullptr; + + return std::make_unique( + std::move(new_expr), op_type, EXPR_POLICY::set_type, curr_expr->expr_range); + } + } + + // is only term + if (it + 1 == expr_list.size()) + return std::move(expr_list[it++]); + + // tries to get binary operator + auto op_it = ++it; + auto op_range = expr_list[op_it]->expr_range; + bool err = false; + + auto [op_prio, op_type] = retrieve_binary_operator(op_it, err); + if (err) + return nullptr; + + // if operator is of lower priority than the calling operator, finish + if (op_prio >= priority) + return std::move(curr_expr); + else + it = op_it; + + auto right_expr = retrieve_term(++it, op_prio); + if (!right_expr) + return nullptr; + + return std::make_unique( + std::move(curr_expr), std::move(right_expr), op_type, EXPR_POLICY::set_type, op_range); +} + +template +std::pair ca_expr_list::retrieve_binary_operator(size_t& it, bool& err) +{ + const auto& op = expr_list[it]; + + if (!is_symbol(op)) + { + add_diagnostic(diagnostic_op::error_CE001(expr_range)); + err = true; + return std::make_pair(0, ca_expr_ops::UNKNOWN); + } + else if (!EXPR_POLICY::is_operator(EXPR_POLICY::get_operator(get_symbol(op)))) + { + add_diagnostic(diagnostic_op::error_CE002(get_symbol(op), expr_range)); + err = true; + return std::make_pair(0, ca_expr_ops::UNKNOWN); + } + + ca_expr_ops op_type = EXPR_POLICY::get_operator(get_symbol(expr_list[it])); + + if (EXPR_POLICY::multiple_words(op_type) && it + 1 < expr_list.size() && is_symbol(expr_list[it + 1]) + && get_symbol(expr_list[it + 1]) == "NOT") + { + op_type = EXPR_POLICY::get_operator(get_symbol(expr_list[it]) + "_NOT"); + ++it; + } + + auto op_prio = EXPR_POLICY::get_priority(op_type); + + return std::make_pair(op_prio, op_type); +} + +} // namespace hlasm_plugin::parser_library::expressions diff --git a/parser_library/src/expressions/conditional_assembly/terms/ca_expr_list.h b/parser_library/src/expressions/conditional_assembly/terms/ca_expr_list.h new file mode 100644 index 000000000..2dbfa9efe --- /dev/null +++ b/parser_library/src/expressions/conditional_assembly/terms/ca_expr_list.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2019 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_CA_EXPR_LIST_H +#define HLASMPLUGIN_PARSERLIBRARY_CA_EXPR_LIST_H + +#include + +#include "../ca_expr_policy.h" +#include "../ca_expression.h" + +namespace hlasm_plugin::parser_library::expressions { + +// represents unresolved list of terms in logical CA expression +class ca_expr_list : public ca_expression +{ +public: + std::vector expr_list; + + ca_expr_list(std::vector expr_list, range expr_range); + + virtual undef_sym_set get_undefined_attributed_symbols(const context::dependency_solver& solver) const override; + + virtual void resolve_expression_tree(context::SET_t_enum kind) override; + + virtual void collect_diags() const override; + + virtual bool is_character_expression() const override; + + virtual context::SET_t evaluate(const evaluation_context& eval_ctx) const override; + +private: + // this function is present due to the fact that in hlasm you can omit space between operator and operands if + // operators are in parentheses (eg. ('A')FIND('B') ) + // however, the parser recognizes it as a function with one parameter and a duplication factor + // this function checks whether any function in expr_list is unknown + // if so, then it breaks it to three objects so the resolve method can handle it + void unknown_functions_to_operators(); + + // in a loop it tries to retrieve first term, binary operator, second term + // each loop iteration it pastes them together and continue until list is exhausted + template + void resolve(); + // retrieves single term with possible unary operators before it + // also checks for following binary operator, + // if it has higher prio than the current one, recursively calls retrieve_term for the second term for the higher + // priority operator + template + ca_expr_ptr retrieve_term(size_t& it, int priority); + // retrieves following binary operator with its priority + template + std::pair retrieve_binary_operator(size_t& it, bool& err); +}; + +} // namespace hlasm_plugin::parser_library::expressions + +#endif diff --git a/parser_library/src/expressions/conditional_assembly/terms/ca_function.cpp b/parser_library/src/expressions/conditional_assembly/terms/ca_function.cpp new file mode 100644 index 000000000..3ce798363 --- /dev/null +++ b/parser_library/src/expressions/conditional_assembly/terms/ca_function.cpp @@ -0,0 +1,693 @@ +/* + * Copyright (c) 2019 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 "ca_function.h" + +#include +#include +#include +#include + +#include "ca_string.h" +#include "ebcdic_encoding.h" +#include "expressions/evaluation_context.h" +#include "lexing/lexer.h" + +#define RET_ERRPARM \ + do \ + { \ + add_diagnostic(diagnostic_op::error_CE007); \ + return context::SET_t(); \ + } while (0) + +namespace hlasm_plugin::parser_library::expressions { + +ca_function::ca_function(context::id_index function_name, + ca_expr_funcs function, + std::vector parameters, + ca_expr_ptr duplication_factor, + range expr_range) + : ca_expression(ca_common_expr_policy::get_function_type(function), std::move(expr_range)) + , function_name(function_name) + , function(function) + , parameters(std::move(parameters)) + , duplication_factor(std::move(duplication_factor)) +{} + +undef_sym_set ca_function::get_undefined_attributed_symbols(const context::dependency_solver& solver) const +{ + undef_sym_set ret; + for (auto&& expr : parameters) + ret.merge(expr->get_undefined_attributed_symbols(solver)); + if (duplication_factor) + ret.merge(duplication_factor->get_undefined_attributed_symbols(solver)); + return ret; +} + +void ca_function::resolve_expression_tree(context::SET_t_enum kind) +{ + if (kind != expr_kind) + add_diagnostic(diagnostic_op::error_CE004(expr_range)); + else if (duplication_factor && expr_kind != context::SET_t_enum::C_TYPE) + add_diagnostic(diagnostic_op::error_CE005(duplication_factor->expr_range)); + else + { + auto [param_size, param_kind] = ca_common_expr_policy::get_function_param_info(function, expr_kind); + if (parameters.size() != param_size) + add_diagnostic(diagnostic_op::error_CE006(expr_range)); + else + { + for (auto&& expr : parameters) + expr->resolve_expression_tree(param_kind); + } + } +} + +void ca_function::collect_diags() const +{ + // nothing to collect +} + +bool ca_function::is_character_expression() const { return false; } + +context::SET_t ca_function::evaluate(const evaluation_context& eval_ctx) const +{ + context::SET_t str_ret; + diagnostic_adder add_diagnostic(&eval_ctx, expr_range); + + switch (function) + { + case ca_expr_funcs::B2A: + return B2A(get_ith_param(0, eval_ctx).access_c(), add_diagnostic); + case ca_expr_funcs::C2A: + return C2A(get_ith_param(0, eval_ctx).access_c(), add_diagnostic); + case ca_expr_funcs::D2A: + return D2A(get_ith_param(0, eval_ctx).access_c(), add_diagnostic); + case ca_expr_funcs::DCLEN: + return DCLEN(get_ith_param(0, eval_ctx).access_c()); + case ca_expr_funcs::FIND: + return FIND(get_ith_param(0, eval_ctx).access_c(), get_ith_param(1, eval_ctx).access_c()); + case ca_expr_funcs::INDEX: + return INDEX(get_ith_param(0, eval_ctx).access_c(), get_ith_param(1, eval_ctx).access_c()); + case ca_expr_funcs::ISBIN: + return ISBIN(get_ith_param(0, eval_ctx).access_c(), add_diagnostic); + case ca_expr_funcs::ISDEC: + return ISDEC(get_ith_param(0, eval_ctx).access_c(), add_diagnostic); + case ca_expr_funcs::ISHEX: + return ISHEX(get_ith_param(0, eval_ctx).access_c(), add_diagnostic); + case ca_expr_funcs::ISSYM: + return ISSYM(get_ith_param(0, eval_ctx).access_c(), add_diagnostic); + case ca_expr_funcs::X2A: + return X2A(get_ith_param(0, eval_ctx).access_c(), add_diagnostic); + + case ca_expr_funcs::A2B: + str_ret = A2B(get_ith_param(0, eval_ctx).access_a()); + break; + case ca_expr_funcs::A2C: + str_ret = A2C(get_ith_param(0, eval_ctx).access_a()); + break; + case ca_expr_funcs::A2D: + str_ret = A2D(get_ith_param(0, eval_ctx).access_a()); + break; + case ca_expr_funcs::A2X: + str_ret = A2X(get_ith_param(0, eval_ctx).access_a()); + break; + case ca_expr_funcs::B2C: + str_ret = B2C(get_ith_param(0, eval_ctx).access_c(), add_diagnostic); + break; + case ca_expr_funcs::B2D: + str_ret = B2D(get_ith_param(0, eval_ctx).access_c(), add_diagnostic); + break; + case ca_expr_funcs::B2X: + str_ret = B2X(get_ith_param(0, eval_ctx).access_c(), add_diagnostic); + break; + case ca_expr_funcs::BYTE: + str_ret = BYTE(get_ith_param(0, eval_ctx).access_a(), add_diagnostic); + break; + case ca_expr_funcs::C2B: + str_ret = C2B(get_ith_param(0, eval_ctx).access_c(), add_diagnostic); + break; + case ca_expr_funcs::C2D: + str_ret = C2D(get_ith_param(0, eval_ctx).access_c(), add_diagnostic); + break; + case ca_expr_funcs::C2X: + str_ret = C2X(get_ith_param(0, eval_ctx).access_c(), add_diagnostic); + break; + case ca_expr_funcs::D2B: + str_ret = D2B(get_ith_param(0, eval_ctx).access_c(), add_diagnostic); + break; + case ca_expr_funcs::D2C: + str_ret = D2C(get_ith_param(0, eval_ctx).access_c(), add_diagnostic); + break; + case ca_expr_funcs::D2X: + str_ret = D2X(get_ith_param(0, eval_ctx).access_c(), add_diagnostic); + break; + case ca_expr_funcs::DCVAL: + str_ret = DCVAL(get_ith_param(0, eval_ctx).access_c()); + break; + case ca_expr_funcs::DEQUOTE: + str_ret = DEQUOTE(get_ith_param(0, eval_ctx).access_c()); + break; + case ca_expr_funcs::DOUBLE: + str_ret = DOUBLE(get_ith_param(0, eval_ctx).access_c(), add_diagnostic); + break; + case ca_expr_funcs::ESYM: + str_ret = ESYM(get_ith_param(0, eval_ctx).access_c()); + break; + case ca_expr_funcs::LOWER: + str_ret = LOWER(get_ith_param(0, eval_ctx).access_c()); + break; + case ca_expr_funcs::SIGNED: + str_ret = SIGNED(get_ith_param(0, eval_ctx).access_a()); + break; + case ca_expr_funcs::SYSATTRA: + str_ret = SYSATTRA(get_ith_param(0, eval_ctx).access_c()); + break; + case ca_expr_funcs::SYSATTRP: + str_ret = SYSATTRP(get_ith_param(0, eval_ctx).access_c()); + break; + case ca_expr_funcs::UPPER: + str_ret = UPPER(get_ith_param(0, eval_ctx).access_c()); + break; + case ca_expr_funcs::X2B: + str_ret = X2B(get_ith_param(0, eval_ctx).access_c(), add_diagnostic); + break; + case ca_expr_funcs::X2C: + str_ret = X2C(get_ith_param(0, eval_ctx).access_c(), add_diagnostic); + break; + case ca_expr_funcs::X2D: + str_ret = X2D(get_ith_param(0, eval_ctx).access_c(), add_diagnostic); + break; + default: + return context::SET_t(); + } + + return ca_string::duplicate(duplication_factor, std::move(str_ret.access_c()), expr_range, eval_ctx); +} + +context::SET_t ca_function::B2A(std::string_view param, diagnostic_adder& add_diagnostic) +{ + if (param.empty()) + return 0; + + if (param.size() > 32) + RET_ERRPARM; + + unsigned int res; + auto conv = std::from_chars(param.data(), param.data() + param.size(), res, 2); + + if (conv.ec != std::errc() || conv.ptr != param.data() + param.size()) + RET_ERRPARM; + + return *reinterpret_cast(&res); +} + +context::SET_t ca_function::C2A(std::string_view param, diagnostic_adder& add_diagnostic) +{ + if (param.empty()) + return 0; + + if (param.size() > 4) + RET_ERRPARM; + + context::A_t ret = 0; + for (const char* c = param.data(); c < param.data() + param.size(); ++c) + { + ret <<= 8; + ret += ebcdic_encoding::to_ebcdic(ebcdic_encoding::to_pseudoascii(c)); + } + + return ret; +} + +context::SET_t ca_function::D2A(std::string_view param, diagnostic_adder& add_diagnostic) +{ + if (param.empty()) + return 0; + + if (param.size() > 11) + RET_ERRPARM; + + int res; + + auto it = std::find_if(param.begin(), param.end(), [](int c) { return c != '-' && c != '+'; }); + + if (it - param.begin() > 1) + RET_ERRPARM; + + size_t start = param.front() == '+' ? 1 : 0; + + auto conv = std::from_chars(param.data() + start, param.data() + param.size(), res, 10); + + if (conv.ec != std::errc() || conv.ptr != param.data() + param.size()) + RET_ERRPARM; + + return res; +} + +context::SET_t ca_function::DCLEN(const context::C_t& param) +{ + context::A_t ret = 0; + const char* c = param.c_str(); + while (c < param.c_str() + param.size()) + { + if ((*c == '\'' && *(c + 1) == '\'') || (*c == '&' && *(c + 1) == '&')) + ++c; + ++ret; + ++c; + } + return ret; +} + +context::SET_t ca_function::FIND(const context::C_t& lhs, const context::C_t& rhs) +{ + auto idx = lhs.find_first_of(rhs); + return idx == std::string::npos ? 0 : (context::A_t)idx + 1; +} + +context::SET_t ca_function::INDEX(const context::C_t& lhs, const context::C_t& rhs) +{ + auto idx = lhs.find(rhs); + return idx == std::string::npos ? 0 : (context::A_t)idx + 1; +} + +context::SET_t ca_function::ISBIN(const context::C_t& param, diagnostic_adder& add_diagnostic) +{ + if (param.empty()) + RET_ERRPARM; + + if (param.size() <= 32 && std ::all_of(param.cbegin(), param.cend(), [](char c) { return c == '0' || c == '1'; })) + return 1; + return 0; +} + +context::SET_t ca_function::ISDEC(const context::C_t& param, diagnostic_adder& add_diagnostic) +{ + if (param.empty()) + RET_ERRPARM; + + context::A_t ret; + + if (param.size() > 10 || param.front() == '-') + ret = 0; + else + { + context::A_t tmp; + auto conv = std::from_chars(param.c_str(), param.c_str() + param.size(), tmp, 10); + + if (conv.ec != std::errc() || conv.ptr != param.c_str() + param.size()) + ret = 0; + else + ret = 1; + } + return ret; +} + +context::SET_t ca_function::ISHEX(const context::C_t& param, diagnostic_adder& add_diagnostic) +{ + if (param.empty()) + RET_ERRPARM; + + if (param.size() <= 8 && std::all_of(param.cbegin(), param.cend(), [](char c) { return std::isxdigit(c); })) + return 1; + return 0; +} + +context::SET_t ca_function::ISSYM(const context::C_t& param, diagnostic_adder& add_diagnostic) +{ + if (param.empty()) + RET_ERRPARM; + + if (!std::isdigit(param.front()) && param.size() < 64 + && std::all_of(param.cbegin(), param.cend(), lexing::lexer::ord_char)) + return 1; + return 0; +} + +context::SET_t ca_function::X2A(std::string_view param, diagnostic_adder& add_diagnostic) +{ + if (param.empty()) + return 0; + + if (param.size() > 8) + RET_ERRPARM; + + unsigned int res; + + auto conv = std::from_chars(param.data(), param.data() + param.size(), res, 16); + + if (conv.ec != std::errc() || conv.ptr != param.data() + param.size()) + RET_ERRPARM; + + return *reinterpret_cast(&res); +} + +context::SET_t ca_function::A2B(context::A_t param) { return std::bitset<32>(param).to_string(); } + +context::SET_t ca_function::A2C(context::A_t param) +{ + std::uint32_t sign_mask = 1U << 31; + std::uint32_t char_mask = 0xffU << 3 * 8; + + std::string ret; + ret.reserve(4); + + for (size_t i = 0; i < 4; ++i) + { + auto sign = param & sign_mask; + auto rest = param & char_mask; + auto c = (unsigned char)(rest >> (3 - i) * 8); + c |= sign >> (3 - i) * 8; + + ret.append(ebcdic_encoding::to_ascii(c)); + + sign_mask >>= 8; + char_mask >>= 8; + } + return ret; +} + +context::SET_t ca_function::A2D(context::A_t param) +{ + auto ret = std::to_string(param); + if (ret.front() == '-') + return ret; + else + return '+' + ret; +} + +context::SET_t ca_function::A2X(context::A_t param) +{ + std::stringstream stream; + stream << std::setfill('0') << std::setw(8) << std::uppercase << std::hex << param; + return stream.str(); +} + +context::SET_t ca_function::B2C(const context::C_t& param, diagnostic_adder& add_diagnostic) +{ + if (param.empty()) + return ""; + + size_t algn = 0; + if (param.size() % 8 != 0) + algn = 8 - param.size() % 8; + + std::string new_str; + + for (size_t i = 0; i < algn; ++i) + new_str.push_back('0'); + + new_str += param; + + std::string ret; + ret.reserve(new_str.size() / 8); + + for (size_t i = 0; i < new_str.size() / 8; ++i) + { + unsigned char c = 0; + for (size_t j = 0; j < 8; ++j) + { + unsigned char bit = new_str[i * 8 + j] - '0'; + if (bit != 0 && bit != 1) + RET_ERRPARM; + c = (c << 1) + bit; + } + ret.append(ebcdic_encoding::to_ascii(c)); + } + + return ret; +} + +context::SET_t ca_function::B2D(const context::C_t& param, diagnostic_adder& add_diagnostic) +{ + auto tmp = B2A(param, add_diagnostic); + if (tmp.type == context::SET_t_enum::UNDEF_TYPE) + return tmp; + return A2D(tmp.access_a()); +} + +context::SET_t ca_function::B2X(const context::C_t& param, diagnostic_adder& add_diagnostic) +{ + if (param.empty()) + return ""; + + size_t algn = 0; + if (param.size() % 4 != 0) + algn = 4 - param.size() % 4; + + std::string new_str; + + for (size_t i = 0; i < algn; ++i) + new_str.push_back('0'); + + new_str += param; + + std::string ret; + ret.resize(new_str.size() / 4); + + for (size_t i = 0; i < new_str.size() / 4; ++i) + { + unsigned char c = 0; + for (size_t j = 0; j < 4; ++j) + { + unsigned char bit = new_str[i * 4 + j] - '0'; + if (bit != 0 && bit != 1) + RET_ERRPARM; + c = (c << 1) + bit; + } + ret[i] = "0123456789ABCDEF"[c]; + } + + return ret; +} + +context::SET_t ca_function::BYTE(context::A_t param, diagnostic_adder& add_diagnostic) +{ + if (param > 255 || param < 0) + RET_ERRPARM; + else + return ebcdic_encoding::to_ascii((unsigned char)param); +} + +context::SET_t ca_function::C2B(const context::C_t& param, diagnostic_adder& add_diagnostic) +{ + if (param.empty()) + return ""; + + if (param.size() * 8 > ca_string::MAX_STR_SIZE) + RET_ERRPARM; + + std::string ret; + ret.reserve(param.size() * 8); + for (const char* c = param.c_str(); c != param.c_str() + param.size(); ++c) + { + auto value = ebcdic_encoding::to_ebcdic(ebcdic_encoding::to_pseudoascii(c)); + ret.append(std::bitset<8>(value).to_string()); + } + return ret; +} + +context::SET_t ca_function::C2D(const context::C_t& param, diagnostic_adder& add_diagnostic) +{ + auto tmp = C2A(param, add_diagnostic); + if (tmp.type == context::SET_t_enum::UNDEF_TYPE) + return tmp; + return A2D(tmp.access_a()); +} + +context::SET_t ca_function::C2X(const context::C_t& param, diagnostic_adder& add_diagnostic) +{ + if (param.empty()) + return ""; + + if (param.size() * 2 > ca_string::MAX_STR_SIZE) + RET_ERRPARM; + + std::string ret; + ret.reserve(param.size() * 2); + for (const char* c = param.c_str(); c != param.c_str() + param.size(); ++c) + { + int value = ebcdic_encoding::to_ebcdic(ebcdic_encoding::to_pseudoascii(c)); + + std::stringstream stream; + stream << std::setfill('0') << std::setw(2) << std::uppercase << std::hex << value; + ret.append(stream.str()); + } + return ret; +} + +context::SET_t ca_function::D2B(const context::C_t& param, diagnostic_adder& add_diagnostic) +{ + if (param.empty()) + return ""; + + auto tmp = D2A(param, add_diagnostic); + if (tmp.type == context::SET_t_enum::UNDEF_TYPE) + return tmp; + return A2B(tmp.access_a()); +} + +context::SET_t ca_function::D2C(const context::C_t& param, diagnostic_adder& add_diagnostic) +{ + if (param.empty()) + RET_ERRPARM; + + auto tmp = D2A(param, add_diagnostic); + if (tmp.type == context::SET_t_enum::UNDEF_TYPE) + return tmp; + return A2C(tmp.access_a()); +} + +context::SET_t ca_function::D2X(const context::C_t& param, diagnostic_adder& add_diagnostic) +{ + if (param.empty()) + RET_ERRPARM; + + auto tmp = D2A(param, add_diagnostic); + if (tmp.type == context::SET_t_enum::UNDEF_TYPE) + return tmp; + return A2X(tmp.access_a()); +} + +context::SET_t ca_function::DCVAL(const context::C_t& param) +{ + std::string ret; + const char* c = param.c_str(); + while (c < param.c_str() + param.size()) + { + if ((*c == '\'' && *(c + 1) == '\'') || (*c == '&' && *(c + 1) == '&')) + ++c; + ret.push_back(*c); + ++c; + } + return ret; +} + +context::SET_t ca_function::DEQUOTE(context::C_t param) +{ + if (param.empty()) + return ""; + + if (param.front() == '\'') + param.erase(param.begin()); + + if (param.size() && param.back() == '\'') + param.pop_back(); + + return param; +} + +context::SET_t ca_function::DOUBLE(const context::C_t& param, diagnostic_adder& add_diagnostic) +{ + std::string ret; + ret.reserve(param.size()); + for (char c : param) + { + ret.push_back(c); + if (c == '\'' || c == '&') + ret.push_back(c); + } + + if (ret.size() > ca_string::MAX_STR_SIZE) + RET_ERRPARM; + + return ret; +} + +context::SET_t ca_function::ESYM(const context::C_t&) { return context::SET_t(); } + +context::SET_t ca_function::LOWER(context::C_t param) +{ + std::transform(param.begin(), param.end(), param.begin(), [](char c) { return (char)tolower(c); }); + return param; +} + +context::SET_t ca_function::SIGNED(context::A_t param) { return std::to_string(param); } + +context::SET_t ca_function::SYSATTRA(const context::C_t&) { return context::SET_t(); } + +context::SET_t ca_function::SYSATTRP(const context::C_t&) { return context::SET_t(); } + +context::SET_t ca_function::UPPER(context::C_t param) +{ + std::transform(param.begin(), param.end(), param.begin(), [](char c) { return (char)toupper(c); }); + return param; +} + +context::SET_t ca_function::X2B(const context::C_t& param, diagnostic_adder& add_diagnostic) +{ + if (param.empty()) + return ""; + + if (param.size() * 4 > ca_string::MAX_STR_SIZE) + RET_ERRPARM; + + std::string ret; + ret.reserve(param.size() * 4); + for (auto c = param.c_str(); c != param.c_str() + param.size(); ++c) + { + unsigned char value = 0; + if (std::isxdigit(*c)) + std::from_chars(c, c + 1, value, 16); + else + RET_ERRPARM; + + ret.append(std::bitset<4>(value).to_string()); + } + return ret; +} + +context::SET_t ca_function::X2C(const context::C_t& param, diagnostic_adder& add_diagnostic) +{ + if (param.empty()) + return ""; + + std::string new_string; + new_string.reserve(param.size()); + + if (param.size() % 2 == 1) + new_string.push_back('0'); + new_string += param; + + std::string ret; + for (auto c = new_string.c_str(); c != new_string.c_str() + new_string.size(); c += 2) + { + unsigned char value = 0; + if (std::isxdigit(*c)) + std::from_chars(c, c + 2, value, 16); + else + RET_ERRPARM; + + ret.append(ebcdic_encoding::to_ascii(value)); + } + return ret; +} + +context::SET_t ca_function::X2D(const context::C_t& param, diagnostic_adder& add_diagnostic) +{ + auto tmp = X2A(param, add_diagnostic); + if (tmp.type == context::SET_t_enum::UNDEF_TYPE) + return tmp; + return A2D(tmp.access_a()); +} + +context::SET_t ca_function::get_ith_param(size_t idx, const evaluation_context& eval_ctx) const +{ + if (idx < parameters.size()) + return parameters[idx]->evaluate(eval_ctx); + else + return context::SET_t(); +} + +} // namespace hlasm_plugin::parser_library::expressions diff --git a/parser_library/src/expressions/conditional_assembly/terms/ca_function.h b/parser_library/src/expressions/conditional_assembly/terms/ca_function.h new file mode 100644 index 000000000..d5f84a791 --- /dev/null +++ b/parser_library/src/expressions/conditional_assembly/terms/ca_function.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2019 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_CA_FUNCTION_H +#define HLASMPLUGIN_PARSERLIBRARY_CA_FUNCTION_H + +#include +#include + +#include "../ca_expr_policy.h" +#include "../ca_expression.h" +#include "diagnostic_adder.h" + +namespace hlasm_plugin::parser_library::expressions { + +// represents CA expression built-in function +class ca_function : public ca_expression +{ +public: + context::id_index function_name; + const ca_expr_funcs function; + std::vector parameters; + ca_expr_ptr duplication_factor; + + + ca_function(context::id_index function_name, + ca_expr_funcs function, + std::vector parameters, + ca_expr_ptr duplication_factor, + range expr_range); + + virtual undef_sym_set get_undefined_attributed_symbols(const context::dependency_solver& solver) const override; + + virtual void resolve_expression_tree(context::SET_t_enum kind) override; + + virtual void collect_diags() const override; + + virtual bool is_character_expression() const override; + + virtual context::SET_t evaluate(const evaluation_context& eval_ctx) const override; + + static context::SET_t B2A(std::string_view param, diagnostic_adder& add_diagnostic); + static context::SET_t C2A(std::string_view param, diagnostic_adder& add_diagnostic); + static context::SET_t D2A(std::string_view param, diagnostic_adder& add_diagnostic); + static context::SET_t DCLEN(const context::C_t& param); + static context::SET_t FIND(const context::C_t& lhs, const context::C_t& rhs); + static context::SET_t INDEX(const context::C_t& lhs, const context::C_t& rhs); + static context::SET_t ISBIN(const context::C_t& param, diagnostic_adder& add_diagnostic); + static context::SET_t ISDEC(const context::C_t& param, diagnostic_adder& add_diagnostic); + static context::SET_t ISHEX(const context::C_t& param, diagnostic_adder& add_diagnostic); + static context::SET_t ISSYM(const context::C_t& param, diagnostic_adder& add_diagnostic); + static context::SET_t X2A(std::string_view param, diagnostic_adder& add_diagnostic); + static context::SET_t A2B(context::A_t param); + static context::SET_t A2C(context::A_t param); + static context::SET_t A2D(context::A_t param); + static context::SET_t A2X(context::A_t param); + static context::SET_t B2C(const context::C_t& param, diagnostic_adder& add_diagnostic); + static context::SET_t B2D(const context::C_t& param, diagnostic_adder& add_diagnostic); + static context::SET_t B2X(const context::C_t& param, diagnostic_adder& add_diagnostic); + static context::SET_t BYTE(context::A_t param, diagnostic_adder& add_diagnostic); + static context::SET_t C2B(const context::C_t& param, diagnostic_adder& add_diagnostic); + static context::SET_t C2D(const context::C_t& param, diagnostic_adder& add_diagnostic); + static context::SET_t C2X(const context::C_t& param, diagnostic_adder& add_diagnostic); + static context::SET_t D2B(const context::C_t& param, diagnostic_adder& add_diagnostic); + static context::SET_t D2C(const context::C_t& param, diagnostic_adder& add_diagnostic); + static context::SET_t D2X(const context::C_t& param, diagnostic_adder& add_diagnostic); + static context::SET_t DCVAL(const context::C_t& param); + static context::SET_t DEQUOTE(context::C_t param); + static context::SET_t DOUBLE(const context::C_t& param, diagnostic_adder& add_diagnostic); + static context::SET_t ESYM(const context::C_t& param); + static context::SET_t LOWER(context::C_t param); + static context::SET_t SIGNED(context::A_t param); + static context::SET_t SYSATTRA(const context::C_t& param); + static context::SET_t SYSATTRP(const context::C_t& param); + static context::SET_t UPPER(context::C_t param); + static context::SET_t X2B(const context::C_t& param, diagnostic_adder& add_diagnostic); + static context::SET_t X2C(const context::C_t& param, diagnostic_adder& add_diagnostic); + static context::SET_t X2D(const context::C_t& param, diagnostic_adder& add_diagnostic); + +private: + context::SET_t get_ith_param(size_t idx, const evaluation_context& eval_ctx) const; +}; + +} // namespace hlasm_plugin::parser_library::expressions + + +#endif diff --git a/parser_library/src/expressions/conditional_assembly/terms/ca_string.cpp b/parser_library/src/expressions/conditional_assembly/terms/ca_string.cpp new file mode 100644 index 000000000..5cd1c4100 --- /dev/null +++ b/parser_library/src/expressions/conditional_assembly/terms/ca_string.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2019 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 "ca_string.h" + +#include "expressions/evaluation_context.h" + +namespace hlasm_plugin::parser_library::expressions { + +ca_string::substring_t::substring_t() + : start(nullptr) + , count(nullptr) + , substring_range() +{} + +ca_string::ca_string( + semantics::concat_chain value, ca_expr_ptr duplication_factor, substring_t substring, range expr_range) + : ca_expression(context::SET_t_enum::C_TYPE, std::move(expr_range)) + , value(std::move(value)) + , duplication_factor(std::move(duplication_factor)) + , substring(std::move(substring)) +{} + +undef_sym_set ca_string::get_undefined_attributed_symbols(const context::dependency_solver& solver) const +{ + undef_sym_set tmp; + if (duplication_factor) + tmp = duplication_factor->get_undefined_attributed_symbols(solver); + if (substring.start) + tmp.merge(substring.start->get_undefined_attributed_symbols(solver)); + if (substring.count) + tmp.merge(substring.count->get_undefined_attributed_symbols(solver)); + return tmp; +} + +void ca_string::resolve_expression_tree(context::SET_t_enum kind) +{ + if (expr_kind != kind) + add_diagnostic(diagnostic_op::error_CE004(expr_range)); +} + +void ca_string::collect_diags() const +{ + if (duplication_factor) + collect_diags_from_child(*duplication_factor); + if (substring.start) + collect_diags_from_child(*substring.start); + if (substring.count) + collect_diags_from_child(*substring.count); +} + +bool ca_string::is_character_expression() const { return duplication_factor == nullptr; } + +context::SET_t ca_string::evaluate(const evaluation_context& eval_ctx) const +{ + context::C_t str = semantics::concatenation_point::evaluate(value, eval_ctx); + + if (str.size() > MAX_STR_SIZE) + { + eval_ctx.add_diagnostic(diagnostic_op::error_CE011(expr_range)); + return context::object_traits::default_v(); + } + + if (substring.start) + { + auto start = substring.start->evaluate(eval_ctx).access_a(); + auto count = + substring.count ? substring.count->evaluate(eval_ctx).access_a() : (context::A_t)str.size() - start + 1; + + if (start < 0 || count < 0 || (start == 0 && count > 0)) + { + eval_ctx.add_diagnostic(diagnostic_op::error_CE008(substring.substring_range)); + return context::object_traits::default_v(); + } + if (start > (context::A_t)str.size()) + { + eval_ctx.add_diagnostic(diagnostic_op::error_CE009(substring.start->expr_range)); + return context::object_traits::default_v(); + } + /* uncomment when compiler options will be implemented + if (start + count - 1 > (int)str.size()) + eval_ctx.add_diagnostic(diagnostic_op::error_CW001(substring.count->expr_range)); + */ + if (count != 0) + str = str.substr(start - 1, count); + else + str = ""; + } + + return duplicate(duplication_factor, std::move(str), expr_range, eval_ctx); +} + +std::string ca_string::duplicate( + const ca_expr_ptr& dupl_factor, std::string value, range expr_range, const evaluation_context& eval_ctx) +{ + if (dupl_factor) + { + auto dupl = dupl_factor->evaluate(eval_ctx).access_a(); + + if (dupl < 0) + { + eval_ctx.add_diagnostic(diagnostic_op::error_CE010(dupl_factor->expr_range)); + return ""; + } + + if (value.size() * dupl > MAX_STR_SIZE) + { + eval_ctx.add_diagnostic(diagnostic_op::error_CE011(expr_range)); + return ""; + } + + if (dupl == 0 || value.empty()) + value = ""; + else + { + value.reserve(value.size() * dupl); + auto begin = value.begin(); + auto end = value.end(); + for (auto i = 1; i < dupl; ++i) + value.append(begin, end); + } + } + return value; +} + +} // namespace hlasm_plugin::parser_library::expressions diff --git a/parser_library/src/expressions/conditional_assembly/terms/ca_string.h b/parser_library/src/expressions/conditional_assembly/terms/ca_string.h new file mode 100644 index 000000000..f21584254 --- /dev/null +++ b/parser_library/src/expressions/conditional_assembly/terms/ca_string.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2019 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_CA_STRING_H +#define HLASMPLUGIN_PARSERLIBRARY_CA_STRING_H + +#include "../ca_expression.h" +#include "semantics/concatenation.h" + +namespace hlasm_plugin::parser_library::expressions { + +// represents CA expression string +class ca_string : public ca_expression +{ +public: + struct substring_t + { + ca_expr_ptr start; + ca_expr_ptr count; + range substring_range; + substring_t(); + }; + + const semantics::concat_chain value; + ca_expr_ptr duplication_factor; + substring_t substring; + static constexpr size_t MAX_STR_SIZE = 4064; + + ca_string(semantics::concat_chain value, ca_expr_ptr duplication_factor, substring_t substring, range expr_range); + + virtual undef_sym_set get_undefined_attributed_symbols(const context::dependency_solver& solver) const override; + + virtual void resolve_expression_tree(context::SET_t_enum kind) override; + + virtual void collect_diags() const override; + + virtual bool is_character_expression() const override; + + virtual context::SET_t evaluate(const evaluation_context& eval_ctx) const override; + + static std::string duplicate( + const ca_expr_ptr& dupl_factor, std::string value, range expr_range, const evaluation_context& eval_ctx); +}; + +} // namespace hlasm_plugin::parser_library::expressions + + +#endif diff --git a/parser_library/src/expressions/conditional_assembly/terms/ca_symbol.cpp b/parser_library/src/expressions/conditional_assembly/terms/ca_symbol.cpp new file mode 100644 index 000000000..4783239b8 --- /dev/null +++ b/parser_library/src/expressions/conditional_assembly/terms/ca_symbol.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2019 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 "ca_symbol.h" + +#include "expressions/evaluation_context.h" + +namespace hlasm_plugin::parser_library::expressions { + +ca_symbol::ca_symbol(context::id_index symbol, range expr_range) + : ca_expression(context::SET_t_enum::A_TYPE, std::move(expr_range)) + , symbol(symbol) +{} + +undef_sym_set ca_symbol::get_undefined_attributed_symbols(const context::dependency_solver&) const +{ + return undef_sym_set(); +} + +void ca_symbol::resolve_expression_tree(context::SET_t_enum kind) +{ + if (kind == context::SET_t_enum::C_TYPE) + add_diagnostic(diagnostic_op::error_CE004(expr_range)); +} + +void ca_symbol::collect_diags() const +{ + // nothing to collect +} + +bool ca_symbol::is_character_expression() const { return false; } + +context::SET_t ca_symbol::evaluate(const evaluation_context& eval_ctx) const +{ + auto tmp_symbol = eval_ctx.hlasm_ctx.ord_ctx.get_symbol(symbol); + + if (tmp_symbol && tmp_symbol->kind() == context::symbol_value_kind::ABS) + return tmp_symbol->value().get_abs(); + else + { + eval_ctx.add_diagnostic(diagnostic_op::error_CE012(expr_range)); + return context::object_traits::default_v(); + } +} + +} // namespace hlasm_plugin::parser_library::expressions diff --git a/parser_library/src/expressions/conditional_assembly/terms/ca_symbol.h b/parser_library/src/expressions/conditional_assembly/terms/ca_symbol.h new file mode 100644 index 000000000..210acce8a --- /dev/null +++ b/parser_library/src/expressions/conditional_assembly/terms/ca_symbol.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2019 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_CA_SYMBOL_H +#define HLASMPLUGIN_PARSERLIBRARY_CA_SYMBOL_H + +#include "../ca_expression.h" + +namespace hlasm_plugin::parser_library::expressions { + +// represents CA expression ordinary symbol +class ca_symbol : public ca_expression +{ +public: + const context::id_index symbol; + + ca_symbol(context::id_index symbol, range expr_range); + + virtual undef_sym_set get_undefined_attributed_symbols(const context::dependency_solver& solver) const override; + + virtual void resolve_expression_tree(context::SET_t_enum kind) override; + + virtual void collect_diags() const override; + + virtual bool is_character_expression() const override; + + virtual context::SET_t evaluate(const evaluation_context& eval_ctx) const override; +}; + +} // namespace hlasm_plugin::parser_library::expressions + + +#endif 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 new file mode 100644 index 000000000..7f2300b3b --- /dev/null +++ b/parser_library/src/expressions/conditional_assembly/terms/ca_symbol_attribute.cpp @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2019 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 "ca_symbol_attribute.h" + +#include "ca_var_sym.h" +#include "context/ordinary_assembly/dependable.h" +#include "expressions/evaluation_context.h" +#include "processing/context_manager.h" + +namespace hlasm_plugin::parser_library::expressions { + +context::SET_t_enum get_attribute_type(context::data_attr_kind attr) +{ + switch (attr) + { + case context::data_attr_kind::T: + case context::data_attr_kind::O: + return context::SET_t_enum::C_TYPE; + case context::data_attr_kind::L: + case context::data_attr_kind::S: + case context::data_attr_kind::I: + case context::data_attr_kind::K: + case context::data_attr_kind::N: + case context::data_attr_kind::D: + return context::SET_t_enum::A_TYPE; + default: + return context::SET_t_enum::UNDEF_TYPE; + } +} + +ca_symbol_attribute::ca_symbol_attribute(context::id_index symbol, context::data_attr_kind attribute, range expr_range) + : ca_expression(get_attribute_type(attribute), std::move(expr_range)) + , attribute(attribute) + , symbol(symbol) + +{} + +ca_symbol_attribute::ca_symbol_attribute(semantics::vs_ptr symbol, context::data_attr_kind attribute, range expr_range) + : ca_expression(get_attribute_type(attribute), std::move(expr_range)) + , attribute(attribute) + , symbol(std::move(symbol)) +{} + +undef_sym_set ca_symbol_attribute::get_undefined_attributed_symbols(const context::dependency_solver& solver) const +{ + if (std::holds_alternative(symbol)) + { + if (context::symbol_attributes::is_ordinary_attribute(attribute) + && !solver.get_symbol(std::get(symbol))) + return { std::get(symbol) }; + return undef_sym_set(); + } + else if (std::holds_alternative(symbol)) + return ca_var_sym::get_undefined_attributed_symbols_vs(std::get(symbol), solver); + else + { + assert(false); + return undef_sym_set(); + } +} + +void ca_symbol_attribute::resolve_expression_tree(context::SET_t_enum kind) +{ + if (kind == context::SET_t_enum::C_TYPE && kind != expr_kind) + add_diagnostic(diagnostic_op::error_CE004(expr_range)); + else if (std::holds_alternative(symbol)) + ca_var_sym::resolve_expression_tree_vs(std::get(symbol)); +} + +void ca_symbol_attribute::collect_diags() const +{ + if (std::holds_alternative(symbol)) + { + auto&& sym = std::get(symbol); + for (auto&& expr : sym->subscript) + collect_diags_from_child(*expr); + } +} + +bool ca_symbol_attribute::is_character_expression() const +{ + return get_attribute_type(attribute) == context::SET_t_enum::C_TYPE; +} + +context::SET_t ca_symbol_attribute::evaluate(const evaluation_context& eval_ctx) const +{ + if (std::holds_alternative(symbol)) + { + return evaluate_ordsym(std::get(symbol), eval_ctx); + } + + if (std::holds_alternative(symbol)) + { + return evaluate_varsym(std::get(symbol), eval_ctx); + } + + return context::SET_t(expr_kind); +} + +context::SET_t ca_symbol_attribute::get_ordsym_attr_value( + context::id_index name, const evaluation_context& eval_ctx) const +{ + auto ord_symbol = eval_ctx.hlasm_ctx.ord_ctx.get_symbol(name); + + if (!ord_symbol) + { + auto found = eval_ctx.attr_provider.lookup_forward_attribute_references({ name }); + + if (auto it = found.find(name); it != found.end()) + return retrieve_value(&it->second, eval_ctx); + } + return retrieve_value(ord_symbol, eval_ctx); +} + +context::SET_t ca_symbol_attribute::retrieve_value( + const context::symbol* ord_symbol, const evaluation_context& eval_ctx) const +{ + if (attribute == context::data_attr_kind::T) + return eval_ctx.hlasm_ctx.get_attribute_value_ca(attribute, ord_symbol); + + if (!ord_symbol) + { + eval_ctx.add_diagnostic(diagnostic_op::warning_W013(expr_range)); + return context::symbol_attributes::default_value(attribute); + } + + if ((attribute == context::data_attr_kind::S || attribute == context::data_attr_kind::I) + && !ord_symbol->attributes().can_have_SI_attr()) + { + eval_ctx.add_diagnostic(diagnostic_op::error_E066(expr_range)); + return context::symbol_attributes::default_value(attribute); + } + + if (!ord_symbol->attributes().is_defined(attribute)) + { + eval_ctx.add_diagnostic(diagnostic_op::warning_W013(expr_range)); + return context::symbol_attributes::default_value(attribute); + } + + return eval_ctx.hlasm_ctx.get_attribute_value_ca(attribute, ord_symbol); +} + +context::SET_t ca_symbol_attribute::evaluate_ordsym(context::id_index name, const evaluation_context& eval_ctx) const +{ + if (context::symbol_attributes::is_ordinary_attribute(attribute)) + { + return get_ordsym_attr_value(name, eval_ctx); + } + else if (attribute == context::data_attr_kind::D) + { + return eval_ctx.hlasm_ctx.get_attribute_value_ca(attribute, name); + } + else if (attribute == context::data_attr_kind::O) + { + auto tmp = eval_ctx.hlasm_ctx.get_attribute_value_ca(attribute, name); + if (tmp.access_c() == "U" && eval_ctx.lib_provider.has_library(*name, eval_ctx.hlasm_ctx)) + return std::string("S"); + return tmp; + } + else + { + eval_ctx.add_diagnostic(diagnostic_op::error_E066(expr_range)); + return context::symbol_attributes::default_ca_value(attribute); + } +} + +std::vector transform(const std::vector& v) +{ + std::vector ret; + for (auto val : v) + ret.push_back((size_t)val); + return ret; +} + +context::SET_t ca_symbol_attribute::evaluate_varsym( + const semantics::vs_ptr& vs, const evaluation_context& eval_ctx) const +{ + processing::context_manager mngr(&eval_ctx); + + auto [var_name, expr_subscript] = vs->evaluate_symbol(eval_ctx); + + // get symbol + auto var_symbol = eval_ctx.hlasm_ctx.get_var_sym(var_name); + + if (!var_symbol) + { + eval_ctx.add_diagnostic(diagnostic_op::error_E010("variable", vs->symbol_range)); + return context::symbol_attributes::default_ca_value(attribute); + } + + // must substitute var sym + if (context::symbol_attributes::requires_ordinary_symbol(attribute)) + { + return evaluate_substituted(var_name, std::move(expr_subscript), vs->symbol_range, eval_ctx); + } + else if (attribute == context::data_attr_kind::T) + { + if (!mngr.test_symbol_for_read(var_symbol, expr_subscript, vs->symbol_range)) + return std::string("U"); + + context::SET_t value = + eval_ctx.hlasm_ctx.get_attribute_value_ca(attribute, var_symbol, transform(expr_subscript)).access_c(); + + if (value.access_c() != "U") + return value; + return evaluate_substituted( + var_name, std::move(expr_subscript), vs->symbol_range, eval_ctx); // is type U, must substitute var sym + } + else + { + if (attribute == context::data_attr_kind::K + && !mngr.test_symbol_for_read(var_symbol, expr_subscript, vs->symbol_range)) + return context::symbol_attributes::default_ca_value(attribute); + return eval_ctx.hlasm_ctx.get_attribute_value_ca(attribute, var_symbol, transform(expr_subscript)); + } +} + +context::SET_t ca_symbol_attribute::evaluate_substituted(context::id_index var_name, + std::vector expr_subscript, + range var_range, + const evaluation_context& eval_ctx) const +{ + processing::context_manager mngr(&eval_ctx); + + context::SET_t substituted_name = mngr.get_var_sym_value(var_name, expr_subscript, var_range); + + if (substituted_name.type != context::SET_t_enum::C_TYPE) + { + if (attribute != context::data_attr_kind::O && attribute != context::data_attr_kind::T) + eval_ctx.add_diagnostic(diagnostic_op::error_E066(expr_range)); + return context::symbol_attributes::default_ca_value(attribute); + } + + auto [valid, ord_name] = mngr.try_get_symbol_name(substituted_name.access_c()); + + if (!valid) + { + if (attribute != context::data_attr_kind::O && attribute != context::data_attr_kind::T) + eval_ctx.add_diagnostic(diagnostic_op::error_E065(expr_range)); + return context::symbol_attributes::default_ca_value(attribute); + } + else + return evaluate_ordsym(ord_name, eval_ctx); +} + +} // namespace hlasm_plugin::parser_library::expressions 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 new file mode 100644 index 000000000..cae3c72cd --- /dev/null +++ b/parser_library/src/expressions/conditional_assembly/terms/ca_symbol_attribute.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2019 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_CA_SYMBOL_ATTRIBUTE_H +#define HLASMPLUGIN_PARSERLIBRARY_CA_SYMBOL_ATTRIBUTE_H + +#include + +#include "../ca_expression.h" +#include "semantics/variable_symbol.h" + +namespace hlasm_plugin::parser_library::expressions { + +// 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; + +public: + const context::data_attr_kind attribute; + ca_attr_variant_t symbol; + + ca_symbol_attribute(context::id_index symbol, context::data_attr_kind attribute, range expr_range); + ca_symbol_attribute(semantics::vs_ptr symbol, context::data_attr_kind attribute, range expr_range); + + virtual undef_sym_set get_undefined_attributed_symbols(const context::dependency_solver& solver) const override; + + virtual void resolve_expression_tree(context::SET_t_enum kind) override; + + virtual void collect_diags() const override; + + virtual bool is_character_expression() const override; + + virtual context::SET_t evaluate(const evaluation_context& eval_ctx) const override; + +private: + context::SET_t get_ordsym_attr_value(context::id_index name, const evaluation_context& eval_ctx) const; + context::SET_t retrieve_value(const context::symbol* ord_symbol, const evaluation_context& eval_ctx) const; + + context::SET_t evaluate_ordsym(context::id_index symbol, const evaluation_context& eval_ctx) const; + context::SET_t evaluate_varsym(const semantics::vs_ptr& symbol, const evaluation_context& eval_ctx) const; + context::SET_t evaluate_substituted(context::id_index var_name, + std::vector expr_subscript, + range var_range, + const evaluation_context& eval_ctx) const; +}; + +} // namespace hlasm_plugin::parser_library::expressions + + +#endif diff --git a/parser_library/src/expressions/conditional_assembly/terms/ca_var_sym.cpp b/parser_library/src/expressions/conditional_assembly/terms/ca_var_sym.cpp new file mode 100644 index 000000000..1e1ffaac9 --- /dev/null +++ b/parser_library/src/expressions/conditional_assembly/terms/ca_var_sym.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2019 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 "ca_var_sym.h" + +#include "ca_constant.h" +#include "processing/context_manager.h" +#include "semantics/concatenation_term.h" + +namespace hlasm_plugin::parser_library::expressions { + +ca_var_sym::ca_var_sym(semantics::vs_ptr symbol, range expr_range) + : ca_expression(context::SET_t_enum::A_TYPE, std::move(expr_range)) + , symbol(std::move(symbol)) +{} + +undef_sym_set ca_var_sym::get_undefined_attributed_symbols_vs( + const semantics::vs_ptr& symbol, const context::dependency_solver& solver) +{ + undef_sym_set tmp; + for (auto&& expr : symbol->subscript) + tmp.merge(expr->get_undefined_attributed_symbols(solver)); + + if (symbol->created) + { + auto created = symbol->access_created(); + for (auto&& point : created->created_name) + if (point->type == semantics::concat_type::VAR) + tmp.merge(get_undefined_attributed_symbols_vs(point->access_var()->symbol, solver)); + } + return tmp; +} + +void ca_var_sym::resolve_expression_tree_vs(const semantics::vs_ptr&) +{ + // already resolved in parser +} + +undef_sym_set ca_var_sym::get_undefined_attributed_symbols(const context::dependency_solver& solver) const +{ + return get_undefined_attributed_symbols_vs(symbol, solver); +} + +void ca_var_sym::resolve_expression_tree(context::SET_t_enum kind) +{ + expr_kind = kind; + resolve_expression_tree_vs(symbol); +} + +void ca_var_sym::collect_diags() const +{ + for (auto&& expr : symbol->subscript) + collect_diags_from_child(*expr); +} + +bool ca_var_sym::is_character_expression() const { return false; } + +context::SET_t ca_var_sym::evaluate(const evaluation_context& eval_ctx) const +{ + return convert_return_types(symbol->evaluate(eval_ctx), expr_kind, eval_ctx); +} + +context::SET_t ca_var_sym::convert_return_types( + context::SET_t retval, context::SET_t_enum type, const evaluation_context& eval_ctx) const +{ + if (retval.type == context::SET_t_enum::C_TYPE) + { + diagnostic_adder add_diags(&eval_ctx, expr_range); + switch (type) + { + case context::SET_t_enum::A_TYPE: + case context::SET_t_enum::B_TYPE: + return ca_constant::self_defining_term(retval.access_c(), add_diags); + case context::SET_t_enum::C_TYPE: + return retval; + default: + return context::SET_t(expr_kind); + } + } + else if (retval.type == context::SET_t_enum::B_TYPE && type == context::SET_t_enum::A_TYPE) + { + retval.type = context::SET_t_enum::A_TYPE; + } + else if (retval.type == context::SET_t_enum::A_TYPE && type == context::SET_t_enum::B_TYPE) + { + retval.type = context::SET_t_enum::B_TYPE; + } + return retval; +} + +} // namespace hlasm_plugin::parser_library::expressions diff --git a/parser_library/src/expressions/conditional_assembly/terms/ca_var_sym.h b/parser_library/src/expressions/conditional_assembly/terms/ca_var_sym.h new file mode 100644 index 000000000..000d88c21 --- /dev/null +++ b/parser_library/src/expressions/conditional_assembly/terms/ca_var_sym.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2019 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_CA_VAR_SYM_H +#define HLASMPLUGIN_PARSERLIBRARY_CA_VAR_SYM_H + +#include "../ca_expression.h" +#include "semantics/variable_symbol.h" + +namespace hlasm_plugin::parser_library::expressions { + +// represents CA expression variable symbol +class ca_var_sym : public ca_expression +{ +public: + const semantics::vs_ptr symbol; + + ca_var_sym(semantics::vs_ptr symbol, range expr_range); + + virtual undef_sym_set get_undefined_attributed_symbols(const context::dependency_solver& solver) const override; + + virtual void resolve_expression_tree(context::SET_t_enum kind) override; + + virtual void collect_diags() const override; + + virtual bool is_character_expression() const override; + + virtual context::SET_t evaluate(const evaluation_context& eval_ctx) const override; + + static undef_sym_set get_undefined_attributed_symbols_vs( + const semantics::vs_ptr& symbol, const context::dependency_solver& solver); + static void resolve_expression_tree_vs(const semantics::vs_ptr& symbol); + +private: + context::SET_t convert_return_types( + context::SET_t retval, context::SET_t_enum type, const evaluation_context& eval_ctx) const; +}; + +} // namespace hlasm_plugin::parser_library::expressions + + +#endif diff --git a/parser_library/src/expressions/evaluation_context.h b/parser_library/src/expressions/evaluation_context.h index d9f6da81d..3e3599eeb 100644 --- a/parser_library/src/expressions/evaluation_context.h +++ b/parser_library/src/expressions/evaluation_context.h @@ -16,6 +16,7 @@ #define HLASMPLUGIN_PARSER_HLASM_EVALUATION_CONTEXT_H #include "context/hlasm_context.h" +#include "diagnosable_ctx.h" #include "processing/attribute_provider.h" #include "workspaces/parse_lib_provider.h" @@ -24,11 +25,27 @@ namespace parser_library { namespace expressions { // structure holding required objects to correcly perform evaluation of expressions -struct evaluation_context +struct evaluation_context : diagnosable_ctx { context::hlasm_context& hlasm_ctx; processing::attribute_provider& attr_provider; workspaces::parse_lib_provider& lib_provider; + + evaluation_context(context::hlasm_context& hlasm_ctx, + processing::attribute_provider& attr_provider, + workspaces::parse_lib_provider& lib_provider) + : diagnosable_ctx(hlasm_ctx) + , hlasm_ctx(hlasm_ctx) + , attr_provider(attr_provider) + , lib_provider(lib_provider) + {} + + evaluation_context(const evaluation_context&) = delete; + + virtual void collect_diags() const override + { + // nothing to collect + } }; } // namespace expressions diff --git a/parser_library/src/expressions/expression.cpp b/parser_library/src/expressions/expression.cpp deleted file mode 100644 index 2bb958c0f..000000000 --- a/parser_library/src/expressions/expression.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (c) 2019 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 "expression.h" - -#include -#include -#include -#include - -#include "arithmetic_expression.h" -#include "character_expression.h" -#include "diagnosable.h" -#include "keyword_expression.h" -#include "logic_expression.h" -#include "visitors/expression_evaluator.h" - -using namespace hlasm_plugin::parser_library; -using namespace hlasm_plugin::parser_library::expressions; - -void expression::copy_diag(expr_ref o) { diag = std::make_unique(*o->diag); } - -void expression::copy_diag(const expression* o) { diag = std::make_unique(*o->diag); } - -void expression::copy_diag(const expression& o) { diag = std::make_unique(*o.diag); } - -expr_ptr expression::binary_operation(str_ref, expr_ref) const -{ - return default_expr_with_error(error_messages::e001()); -} - -expr_ptr expression::unary_operation(str_ref) const -{ - return default_expr_with_error(error_messages::e001()); -} - -expr_ptr expression::resolve_ord_symbol(str_ref symbol) -{ - if (keyword_expression::is_keyword(symbol)) - return std::make_unique(symbol); - - // TODO: resolve identifier - if (std::all_of(symbol.cbegin(), symbol.cend(), [](char c) { return isdigit(c); })) - return arithmetic_expression::from_string(symbol, 10); - - - - return default_expr_with_error(error_messages::not_implemented()); -} - -#define front_keyword(exprs) dynamic_cast(exprs.front().get()) - -expr_ptr expression::evaluate(std::deque exprs) -{ - size_t operator_count = 0; - auto e = evaluate_term(exprs, 5, operator_count); - - if (exprs.size() > 0) - return default_expr_with_error(error_messages::e001()); - - return e; -} - -expr_ptr expression::evaluate_term(std::deque& exprs, uint8_t priority, size_t& operator_count) -{ - expr_ptr a1; - if (priority == 1) - a1 = evaluate_factor(exprs, operator_count); - else - a1 = evaluate_term(exprs, priority - 1, operator_count); - - if (exprs.size() > 0 && exprs.front()->is_keyword() && front_keyword(exprs)->priority() == priority) - { - auto o = std::move(exprs.front()); - exprs.pop_front(); - - std::string keyword(o->get_str_val()); - if (dynamic_cast(a1.get()) && o->is_complex_keyword() && exprs.front()->is_keyword() - && exprs.front()->get_str_val() == "NOT") - { - exprs.pop_front(); - keyword.append(" NOT"); - } - /* - ++operator_count; - //maximum operator count, see reference - if (operator_count > 24) - return default_expr_with_error - (error_messages::e001()); - */ - auto a2 = evaluate_term(exprs, priority, operator_count); - return a1->binary_operation(keyword, a2); - } - return a1; -} - -expr_ptr expression::evaluate_factor(std::deque& exprs, size_t& operator_count) -{ - if (exprs.size() == 0) - return default_expr_with_error(error_messages::e001()); - - // value - if (!exprs.front()->is_keyword() || (exprs.front()->is_keyword() && exprs.size() == 1)) - { - auto e = std::move(exprs.front()); - exprs.pop_front(); - if (!e->is_keyword()) - return e; - return dynamic_cast(e.get())->to_expression(); - } - - // unary operator factor - if (exprs.front()->is_keyword() && dynamic_cast(exprs.front().get())->is_unary()) - { - ++operator_count; - if (operator_count > 24) - return default_expr_with_error(error_messages::e002()); - auto op = std::move(exprs.front()); - exprs.pop_front(); - auto e = evaluate_factor(exprs, operator_count); - return e->unary_operation(op->get_str_val()); - } - - return default_expr_with_error(error_messages::e001()); -} - -expr_ptr expression::operator+(expression_ref) const -{ - return default_expr_with_error(error_messages::e001()); -} - -expr_ptr expression::operator-(expression_ref) const -{ - return default_expr_with_error(error_messages::e001()); -} - -expr_ptr expression::operator*(expression_ref) const -{ - return default_expr_with_error(error_messages::e001()); -} - -expr_ptr expression::operator/(expression_ref) const -{ - return default_expr_with_error(error_messages::e001()); -} - -expr_ptr expression::operator|(expression_ref) const -{ - return default_expr_with_error(error_messages::e001()); -} - -expr_ptr expression::operator&(expression_ref) const -{ - return default_expr_with_error(error_messages::e001()); -} - -expr_ptr expression::operator+() const -{ - return default_expr_with_error(error_messages::e001()); -} - -expr_ptr expression::operator-() const -{ - return default_expr_with_error(error_messages::e001()); -} - -context::SET_t expression::get_set_value() const { return context::SET_t(); } - -int32_t expression::get_numeric_value() const -{ - auto t = retype(); - if (t == NULL) - { - auto tl = retype(); - if (tl == NULL) - return 0; - return static_cast(tl->get_value()); - } - else - return t->get_value(); -} - -expr_ptr expression::self_defining_term(str_ref type, str_ref val, bool dbcs) -{ - assert(type.length() > 0); - char t = static_cast(toupper(type[0])); - - if (t == 'D' || t == 'B' || t == 'X' || t == 'C' || t == 'D' || t == 'G') - return arithmetic_expression::from_string(type, val, dbcs); - - return default_expr_with_error(error_messages::e003()); -} diff --git a/parser_library/src/expressions/expression.h b/parser_library/src/expressions/expression.h deleted file mode 100644 index 834b65868..000000000 --- a/parser_library/src/expressions/expression.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2019 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_PARSER_HLASMEXPRESSION_H -#define HLASMPLUGIN_PARSER_HLASMEXPRESSION_H -#include -#include -#include - -#include "antlr4-runtime.h" - -#include "context/common_types.h" -#include "diagnosable.h" -#include "error_messages.h" - -namespace hlasm_plugin::parser_library::expressions { - -class expression; -using expr_ptr = std::shared_ptr; -using expr_list = std::vector; -using str_ref = const std::string&; -using expr_ref = const expr_ptr&; -using expression_ref = const expression&; -class character_expression; -class arithmetic_expression; -class expression -{ -public: - std::unique_ptr diag; - bool has_error() const { return diag != nullptr; } - virtual ~expression() = default; - - virtual expr_ptr binary_operation(str_ref operation_name, expr_ref arg2) const; - virtual expr_ptr unary_operation(str_ref operation_name) const; - - static expr_ptr resolve_ord_symbol(str_ref symbol); - /** - * evaluates space separated expression - * see visitos/expression_evaluator.h:visitExpr() - * */ - static expr_ptr evaluate(std::deque exprs); - static expr_ptr self_defining_term(str_ref type, str_ref val, bool dbcs); - - virtual expr_ptr operator+(expression_ref) const; - virtual expr_ptr operator-(expression_ref) const; - virtual expr_ptr operator*(expression_ref) const; - virtual expr_ptr operator/(expression_ref) const; - virtual expr_ptr operator|(expression_ref) const; - virtual expr_ptr operator&(expression_ref) const; - virtual expr_ptr operator+() const; - virtual expr_ptr operator-() const; - - virtual int32_t get_numeric_value() const; - - virtual context::SET_t get_set_value() const; - - virtual bool is_keyword() const { return false; } - virtual bool is_complex_keyword() const { return false; } - virtual std::string get_str_val() const = 0; - - template - T* retype() - { - return dynamic_cast(this); - } - - template - const T* retype() const - { - return dynamic_cast(this); - } - - - expression(expression&&) = default; - expression& operator=(expression&&) = default; - -protected: - expression() = default; - void copy_diag(expr_ref o); - void copy_diag(const expression* o); - void copy_diag(const expression& o); - - template - static typename std::shared_ptr default_expr_with_error(std::unique_ptr diag) - { - auto ex = std::make_shared(); - ex->diag = std::move(diag); - return ex; - } - - /** - * all operations involving arguments check for errors - * in all arguments immediately before accessing their values - * - * if any argument contains an error, it is copied - * and an erroneous expression (meaning with an error) - * is returned - * - * see: copy_return_on_error and copy_return_on_error_binary - * */ - - template - static typename std::shared_ptr test_and_copy_error(const expression* e) - { - if (e->has_error()) - { - auto ex = std::make_shared(); - ex->copy_diag(e); - return ex; - } - return std::unique_ptr(); - } - - template - static typename std::shared_ptr test_and_copy_error(const expression& e) - { - if (e.has_error()) - { - auto ex = std::make_shared(); - ex->copy_diag(e); - return ex; - } - return std::unique_ptr(); - } - - static expr_ptr evaluate_term(std::deque& exprs, uint8_t priority, size_t& operator_count); - static expr_ptr evaluate_factor(std::deque& exprs, size_t& operator_count); -}; - -} // namespace hlasm_plugin::parser_library::expressions - -#define make_arith(val) std::make_shared(val) -#define make_logic(val) std::make_shared(val) -#define make_char(val) std::make_shared(val) - -/** - * helper macro - * so that we do not have to write - * copy error, test & return - * */ -#define copy_return_on_error(arg, type) \ - do \ - { \ - auto te = test_and_copy_error(arg); \ - if (te != nullptr) \ - return te; \ - } while (0) - -/** - * same as previos - * plus checks self and second arg - * */ -#define copy_return_on_error_binary(arg2, type) \ - do \ - { \ - copy_return_on_error(this, type); \ - copy_return_on_error(arg2, type); \ - } while (0) - -#endif diff --git a/parser_library/src/expressions/keyword_expression.cpp b/parser_library/src/expressions/keyword_expression.cpp deleted file mode 100644 index aca2445f9..000000000 --- a/parser_library/src/expressions/keyword_expression.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2019 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 "keyword_expression.h" - -#include -#include - -#include "arithmetic_expression.h" -#include "error_messages.h" - -using namespace hlasm_plugin::parser_library::expressions; - -std::map - keyword_expression::keywords_ = { -#define X(k) { #k, keyword_expression::keyword_type::k }, - KEYWORDS -#undef X - { "*", keyword_expression::keyword_type::ASTERISK } - }; - -keyword_expression::keyword_expression(str_ref k) -{ - std::string kw = k; - // again, we accept lowercase keywords too - std::transform(kw.begin(), kw.end(), kw.begin(), [](char c) { return static_cast(toupper(c)); }); - auto f = keywords_.find(kw); - if (f != keywords_.cend()) - value_ = f->second; - else - throw std::runtime_error("symbol is not a keyword"); - s_val_ = std::move(kw); -} - -keyword_expression::keyword_expression(const keyword_expression& expr) - : s_val_(expr.s_val_) - , value_(expr.value_) -{ - if (expr.diag) - diag = std::make_unique(*expr.diag); -} - -bool keyword_expression::is_unary() const -{ - return value_ == keyword_type::NOT || value_ == keyword_type::BYTE || value_ == keyword_type::LOWER - || value_ == keyword_type::SIGNED || value_ == keyword_type::UPPER || value_ == keyword_type::DOUBLE; -} - -uint8_t keyword_expression::priority() const -{ - if (is_unary()) - return 0; - - switch (value_) - { - case keyword_type::AND: - case keyword_type::AND_NOT: - return 2; - case keyword_type::OR: - case keyword_type::OR_NOT: - return 3; - case keyword_type::XOR: - case keyword_type::XOR_NOT: - return 4; - case keyword_type::SLA: - case keyword_type::SLL: - case keyword_type::SRA: - case keyword_type::SRL: - return 5; - default: - return 1; - } -} - -bool keyword_expression::is_keyword() const { return true; } - -bool keyword_expression::is_complex_keyword() const -{ - return value_ == keyword_type::AND || value_ == keyword_type::OR || value_ == keyword_type::XOR; -} - -std::string keyword_expression::get_str_val() const { return s_val_; } - -expr_ptr keyword_expression::to_expression() const -{ - return default_expr_with_error(error_messages::not_implemented()); -} - -bool keyword_expression::is_keyword(str_ref k) { return keywords_.find(k) != keywords_.cend(); } diff --git a/parser_library/src/expressions/keyword_expression.h b/parser_library/src/expressions/keyword_expression.h deleted file mode 100644 index 4f9e46c26..000000000 --- a/parser_library/src/expressions/keyword_expression.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2019 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_PARSER_HLASMKEXPRESSION_H -#define HLASMPLUGIN_PARSER_HLASMKEXPRESSION_H -#include -#include -#include - -#include "expression.h" - -namespace hlasm_plugin { -namespace parser_library { -namespace expressions { -/** - * helper type, not an actual expression - * represents unary and binary operators - * */ -class keyword_expression : public expression -{ -public: - keyword_expression(str_ref); - keyword_expression(const keyword_expression& expr); - keyword_expression(keyword_expression&&) = default; - keyword_expression& operator=(keyword_expression&&) = default; - expr_ptr to_expression() const; - static bool is_keyword(str_ref kw); - - -#define KEYWORDS \ - X(AND) \ - X(AND_NOT) \ - X(OR) \ - X(OR_NOT) \ - X(XOR) \ - X(XOR_NOT) \ - X(NOT) \ - X(EQ) \ - X(NE) \ - X(LE) \ - X(LT) \ - X(GE) \ - X(GT) \ - X(ASTERISK) \ - X(FIND) \ - X(INDEX) \ - X(SLA) \ - X(SLL) \ - X(SRA) \ - X(SRL) \ - X(BYTE) \ - X(LOWER) \ - X(SIGNED) \ - X(UPPER) \ - X(DOUBLE) - -#define X(k) k, - enum class keyword_type - { - KEYWORDS - }; -#undef X - - bool is_unary() const; - uint8_t priority() const; - bool is_keyword() const override; - bool is_complex_keyword() const override; - std::string get_str_val() const override; - -private: - /** - * HLASM is case insensitive - * */ - struct upper_equal - { - bool operator()(const char l, const char r) const { return toupper(l) < toupper(r); } - bool operator()(const std::string& l, const std::string& r) const - { - return std::lexicographical_compare(l.cbegin(), l.cend(), r.cbegin(), r.cend(), upper_equal()); - } - }; - /** - * mapping of string to keyword_type - * */ - static std::map keywords_; - std::string s_val_; - keyword_type value_; -}; -} // namespace expressions -} // namespace parser_library -} // namespace hlasm_plugin - -#endif diff --git a/parser_library/src/expressions/logic_expression.cpp b/parser_library/src/expressions/logic_expression.cpp deleted file mode 100644 index 5289e46ce..000000000 --- a/parser_library/src/expressions/logic_expression.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (c) 2019 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 "logic_expression.h" - -#include - -#include "error_messages.h" -#include "numeric_wrapper.h" - -using namespace hlasm_plugin; -using namespace parser_library; -using namespace expressions; - -logic_expression::logic_expression(bool v) - : value_(v) -{} - -logic_expression::logic_expression(const logic_expression& expr) - : value_(expr.value_) -{ - if (expr.diag) - diag = std::make_unique(*expr.diag); -} - -logic_expression::logic_expression(int32_t v) - : value_(v != 0) -{} - -expr_ptr logic_expression::to_arith() const { return make_arith(static_cast(value_)); } - -expr_ptr logic_expression::binary_operation(str_ref o, expr_ref arg2) const -{ - std::string operation_name = o; - // normalize operation name - // all text is in HLASM capitalized by default, but we expect lowercase too (for easier work on PC) - std::transform(operation_name.begin(), operation_name.end(), operation_name.begin(), [](char c) { - return static_cast(toupper(c)); - }); - - bool val = false; - // second operand can be either logical or arithmetic - auto e = arg2->retype(); - if (e == nullptr) - { - auto ae = arg2->retype(); - if (ae == nullptr) - return default_expr_with_error(error_messages::el01()); - // arithmetic value is converted into logical - val = ae->get_value() != 0; - } - else - val = e->get_value(); - - // check if the second operand contains error - // is so, copy it and return - copy_return_on_error_binary(arg2.get(), logic_expression); - - /** - * standard logical operations - * */ - - if (operation_name == "EQ") - return make_logic(value_ == val); - - if (operation_name == "NE") - return make_logic(value_ != val); - - if (operation_name == "OR") - return make_logic(value_ || val); - - if (operation_name == "OR NOT") - return make_logic(value_ || !val); - - if (operation_name == "AND") - return make_logic(value_ && val); - - if (operation_name == "AND NOT") - return make_logic(value_ && !val); - - if (operation_name == "XOR") - return make_logic(value_ ^ val); - - if (operation_name == "XOR NOT") - return make_logic(value_ ^ !val); - - return default_expr_with_error(error_messages::el02()); -} - -int32_t logic_expression::get_numeric_value() const { return static_cast(value_); } - -std::string logic_expression::get_str_val() const { return std::to_string(get_numeric_value()); } - -context::SET_t logic_expression::get_set_value() const { return value_; } - -bool logic_expression::get_value() const { return value_; } - -expr_ptr logic_expression::operator+(expression_ref e) const -{ - copy_return_on_error_binary(e, arithmetic_expression); - - auto w = al_wrap(e); - if (!w) - return default_expr_with_error(error_messages::ea09()); - auto value = w.value(); - - auto res = static_cast(value_) + static_cast(value); - if (res > INT32_MAX || res < INT32_MIN) - return default_expr_with_error(error_messages::ea10()); - - return make_arith(static_cast(res)); -} - -expr_ptr logic_expression::operator-(expression_ref e) const -{ - copy_return_on_error_binary(e, arithmetic_expression); - - auto w = al_wrap(e); - if (!w) - return default_expr_with_error(error_messages::ea09()); - auto value = w.value(); - - auto res = static_cast(value_) - static_cast(value); - if (res > INT32_MAX || res < INT32_MIN) - return default_expr_with_error(error_messages::ea10()); - - return make_arith(static_cast(res)); -} - -expr_ptr logic_expression::operator*(expression_ref e) const -{ - copy_return_on_error_binary(e, arithmetic_expression); - - auto w = al_wrap(e); - if (!w) - return default_expr_with_error(error_messages::ea09()); - auto value = w.value(); - - auto res = static_cast(value_) * static_cast(value); - if (res > INT32_MAX || res < INT32_MIN) - return default_expr_with_error(error_messages::ea10()); - - return make_arith(static_cast(res)); -} - -expr_ptr logic_expression::operator/(expression_ref e) const -{ - copy_return_on_error_binary(e, arithmetic_expression); - - auto w = al_wrap(e); - if (!w) - return default_expr_with_error(error_messages::ea09()); - auto value = w.value(); - - if (value == 0) - return make_arith(0); - - return make_arith(get_numeric_value() / value); -} - -expr_ptr logic_expression::operator|(expression_ref e) const -{ - copy_return_on_error_binary(e, arithmetic_expression); - - auto w = al_wrap(e); - if (!w) - return default_expr_with_error(error_messages::ea09()); - auto value = w.value() != 0; - - return make_logic(value_ || value); -} - -expr_ptr logic_expression::operator&(expression_ref e) const -{ - copy_return_on_error_binary(e, arithmetic_expression); - - auto w = al_wrap(e); - if (!w) - return default_expr_with_error(error_messages::ea09()); - auto value = w.value() != 0; - - return make_logic(value_ && value); -} - -expr_ptr logic_expression::operator+() const -{ - copy_return_on_error(this, arithmetic_expression); - - return make_arith(static_cast(value_)); -} - -expr_ptr logic_expression::operator-() const -{ - copy_return_on_error(this, arithmetic_expression); - - return make_arith(-static_cast(value_)); -} - -expr_ptr logic_expression::unary_operation(str_ref o) const -{ - std::string operation_name = o; - std::transform(operation_name.begin(), operation_name.end(), operation_name.begin(), [](char c) { - return static_cast(toupper(c)); - }); - if (operation_name == "NOT") - { - copy_return_on_error(this, logic_expression); - return make_logic(!value_); - } - - auto ax = to_arith(); - return ax->unary_operation(operation_name); -} diff --git a/parser_library/src/expressions/logic_expression.h b/parser_library/src/expressions/logic_expression.h deleted file mode 100644 index d51f8655a..000000000 --- a/parser_library/src/expressions/logic_expression.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2019 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_PARSER_HLASMLEXPRESSION_H -#define HLASMPLUGIN_PARSER_HLASMLEXPRESSION_H -#include - -#include "arithmetic_expression.h" -#include "expression.h" - -namespace hlasm_plugin { -namespace parser_library { -namespace expressions { -class arithmetic_expression; -class expression; -/** - * wraps logic and value of logic expression - * */ -class logic_expression : public expression -{ -public: - virtual ~logic_expression() = default; - logic_expression() = default; - logic_expression(bool); - logic_expression(const logic_expression& expr); - logic_expression(logic_expression&&) = default; - logic_expression& operator=(logic_expression&&) = default; - logic_expression(int32_t); - - expr_ptr to_arith() const; - - /** - * all operations involving arguments check for errors - * in all arguments immediately before accessing their values - * - * if any argument contains an error, it is copied - * and an erroneous expression (meaning with en error) - * is returned - * - * see: copy_return_on_error and copy_return_on_error_binary - * */ - - expr_ptr unary_operation(str_ref operation_name) const override; - expr_ptr binary_operation(str_ref operation_name, expr_ref arg2) const override; - - int32_t get_numeric_value() const override; - - std::string get_str_val() const override; - bool get_value() const; - context::SET_t get_set_value() const override; - - /** - * all operations are in INT32 - * but we compute them in INT64 - * and checking for overflow -> we return error - * - * second operand is always converted to arithmetic expression - * */ - - virtual expr_ptr operator+(expression_ref) const override; - virtual expr_ptr operator-(expression_ref) const override; - virtual expr_ptr operator*(expression_ref) const override; - virtual expr_ptr operator/(expression_ref) const override; - virtual expr_ptr operator+() const override; - virtual expr_ptr operator-() const override; - - /** - * logical expressions - * return logical value - * */ - virtual expr_ptr operator|(expression_ref) const override; - virtual expr_ptr operator&(expression_ref) const override; - -private: - bool value_ = false; -}; -} // namespace expressions -} // namespace parser_library -} // namespace hlasm_plugin - -#endif diff --git a/parser_library/src/expressions/mach_expr_term.cpp b/parser_library/src/expressions/mach_expr_term.cpp index adc8e4a55..cefc33aee 100644 --- a/parser_library/src/expressions/mach_expr_term.cpp +++ b/parser_library/src/expressions/mach_expr_term.cpp @@ -14,8 +14,10 @@ #include "mach_expr_term.h" -#include "arithmetic_expression.h" +#include + #include "checking/checker_helper.h" +#include "conditional_assembly/terms/ca_constant.h" using namespace hlasm_plugin::parser_library::expressions; using namespace hlasm_plugin::parser_library; @@ -85,13 +87,8 @@ const mach_expression* mach_expr_symbol::leftmost_term() const { return this; } mach_expr_self_def::mach_expr_self_def(std::string option, std::string value, range rng) : mach_expression(rng) { - auto ae = arithmetic_expression::from_string( - std::move(option), std::move(value), false); // could generate diagnostic + DBCS - ae->diag->diag_range = rng; - if (ae->has_error()) - add_diagnostic(*ae->diag); - else - value_ = ae->get_numeric_value(); + diagnostic_adder add_diagnostic(this, rng); + value_ = ca_constant::self_defining_term(option, value, add_diagnostic); } context::dependency_collector mach_expr_self_def::get_dependencies(context::dependency_solver&) const diff --git a/parser_library/src/expressions/numeric_wrapper.h b/parser_library/src/expressions/numeric_wrapper.h deleted file mode 100644 index efb195d95..000000000 --- a/parser_library/src/expressions/numeric_wrapper.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2019 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_PARSER_NUMERIC_WRAPPER_H -#define HLASMPLUGIN_PARSER_NUMERIC_WRAPPER_H -#include "arithmetic_expression.h" -#include "expression.h" -#include "logic_expression.h" - -namespace hlasm_plugin::parser_library::expressions { - -/** - * Wrapper for logic and arithmetic expressions - * HLASM supports expressions with mixed operand types - * logic expression is then converted to arithmetic - * */ -template -class arithmetic_logic_expr_wrapper -{ - typename std::enable_if_t< - std::is_base_of_v>>, - T>&& ref; - arithmetic_logic_expr_wrapper() = delete; - arithmetic_logic_expr_wrapper(T&& r) - : ref(std::forward(r)) - {} - -public: - arithmetic_logic_expr_wrapper(const arithmetic_logic_expr_wrapper&) = default; - arithmetic_logic_expr_wrapper(arithmetic_logic_expr_wrapper&&) = default; - static arithmetic_logic_expr_wrapper wrap(T&& u) { return arithmetic_logic_expr_wrapper(std::forward(u)); } - operator bool() const { return is_valid(); } - bool operator!() const { return !is_valid(); } - bool is_valid() const - { - if (ref.template retype()) - return true; - if (ref.template retype()) - return true; - return false; - } - int32_t value() const - { - if (auto p = ref.template retype()) - { - return p->get_value(); - } - if (auto p = ref.template retype()) - { - return p->get_value(); - } - throw std::bad_cast(); - } -}; - -template -static arithmetic_logic_expr_wrapper al_wrap(U&& u) -{ - return arithmetic_logic_expr_wrapper::wrap(std::forward(u)); -} - -} // namespace hlasm_plugin::parser_library::expressions - -#endif diff --git a/parser_library/src/expressions/visitors/expression_analyzer.cpp b/parser_library/src/expressions/visitors/expression_analyzer.cpp deleted file mode 100644 index e732606e5..000000000 --- a/parser_library/src/expressions/visitors/expression_analyzer.cpp +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (c) 2019 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 "expression_analyzer.h" - -#include "processing/context_manager.h" -#include "semantics/range_provider.h" - -using namespace hlasm_plugin::parser_library; -using namespace hlasm_plugin::parser_library::expressions; - -antlrcpp::Any expression_analyzer::visitExpr(parsing::hlasmparser::ExprContext* ctx) -{ - return visit(ctx->expr_p_space_c()); -} - -antlrcpp::Any expression_analyzer::visitExpr_p(parsing::hlasmparser::Expr_pContext* ctx) -{ - if (ctx->expr_sContext != nullptr) - return visit(ctx->expr_sContext); - else - return visit(ctx->expr_p()); -} - -antlrcpp::Any expression_analyzer::visitExpr_s(parsing::hlasmparser::Expr_sContext* ctx) -{ - if (ctx->t != nullptr) - return visit(ctx->t); - - auto a = visit_ref(ctx->tmp); - auto b = visit_ref(ctx->term_c()); - - a.merge(std::move(b)); - return a; -} - -antlrcpp::Any expression_analyzer::visitExpr_p_space_c(parsing::hlasmparser::Expr_p_space_cContext* ctx) -{ - std::set result; - if (ctx->exs != nullptr) - result = visit_ref(ctx->exs); - result.merge(visit_ref(ctx->expr_p())); - return result; -} - -antlrcpp::Any expression_analyzer::visitTerm_c(parsing::hlasmparser::Term_cContext* ctx) -{ - if (ctx->t != nullptr) - return visit(ctx->t); - - auto a = visit_ref(ctx->tmp); - auto b = visit_ref(ctx->term()); - - a.merge(std::move(b)); - return a; -} - -antlrcpp::Any expression_analyzer::visitTerm(parsing::hlasmparser::TermContext* ctx) -{ - if (ctx->var_symbolContext != nullptr) - { - std::set result; - - for (auto expr : ctx->var_symbolContext->vs->subscript) - result.merge(visit_ref(expr)); - - if (ctx->var_symbolContext->vs->created) - result.merge(get_undefined_symbol_references(ctx->var_symbolContext->vs->access_created()->created_name)); - - return result; - } - else if (ctx->expr() != nullptr) - return visit(ctx->expr()); - else if (ctx->ca_string() != nullptr) - return visit(ctx->ca_string()); - else if (ctx->data_attribute() != nullptr) - return visit(ctx->data_attribute()); - else if (ctx->id_sub() != nullptr) - return visit(ctx->id_sub()); - - return std::set {}; -} - -antlrcpp::Any expression_analyzer::visitId_sub(parsing::hlasmparser::Id_subContext* ctx) -{ - return visit(ctx->subscriptContext); -} - -antlrcpp::Any expression_analyzer::visitExpr_p_comma_c(parsing::hlasmparser::Expr_p_comma_cContext* ctx) -{ - std::set result; - if (ctx->exs != nullptr) - result = visit_ref(ctx->exs); - result.merge(visit_ref(ctx->expr_p())); - return result; -} - -antlrcpp::Any expression_analyzer::visitSubscript(parsing::hlasmparser::SubscriptContext* ctx) -{ - if (ctx->children.size() >= 3) - return visit(ctx->expr_p_comma_cContext); - else - return std::set(); -} - -antlrcpp::Any expression_analyzer::visitCa_string(parsing::hlasmparser::Ca_stringContext* ctx) -{ - std::set result; - if (ctx->tmp != nullptr) - { - result = visit_ref(ctx->tmp); - result.merge(visit_ref(ctx->ca_string_b())); - } - else - result = visit_ref(ctx->ca_string_b()); - return result; -} - -antlrcpp::Any expression_analyzer::visitCa_string_b(parsing::hlasmparser::Ca_string_bContext* ctx) -{ - auto result = get_undefined_symbol_references(ctx->string_ch_v_c()->chain); - - if (ctx->substring() && ctx->substring()->e1 != nullptr) - result.merge(visit_ref(ctx->substring()->e1)); - if (ctx->substring() && ctx->substring()->e2 != nullptr) - result.merge(visit_ref(ctx->substring()->e2)); - - return result; -} - -antlrcpp::Any expression_analyzer::visitCa_dupl_factor(parsing::hlasmparser::Ca_dupl_factorContext* ctx) -{ - if (ctx->expr_p() != nullptr) - return visit(ctx->expr_p()); - else - return std::set {}; -} - -antlrcpp::Any expression_analyzer::visitData_attribute(parsing::hlasmparser::Data_attributeContext* ctx) -{ - std::set result; - - auto attr = ctx->attribute; - - if (!ctx->id() || attr == context::data_attr_kind::D || attr == context::data_attr_kind::O - || attr == context::data_attr_kind::N || attr == context::data_attr_kind::K - || eval_ctx_.hlasm_ctx.ord_ctx.get_symbol(ctx->id()->name)) - return std::set {}; - - result.insert(ctx->id()->name); - - return result; -} - -expression_analyzer::expression_analyzer(evaluation_context eval_ctx) - : eval_ctx_(eval_ctx) -{} - -std::set expression_analyzer::get_undefined_symbol_references( - antlr4::ParserRuleContext* expr_context) -{ - return visit(expr_context).as>(); -} - -std::set expression_analyzer::get_undefined_symbol_references(const semantics::concat_chain& chain) -{ - std::set result; - - for (auto& point : chain) - { - if (point == nullptr) - continue; - if (point->type == semantics::concat_type::VAR) - { - result = get_undefined_symbol_references(*point->access_var()); - } - if (point->type == semantics::concat_type::SUB) - { - for (auto& entry : point->access_sub()->list) - { - result.merge(get_undefined_symbol_references(entry)); - } - } - } - - return result; -} - -std::set expression_analyzer::get_undefined_symbol_references(const semantics::var_sym& symbol) -{ - std::set result; - - for (auto expr : symbol.subscript) - result.merge(visit_ref(expr)); - - if (symbol.created) - result.merge(get_undefined_symbol_references(symbol.access_created()->created_name)); - - return result; -} - -std::set expression_analyzer::visit_ref(antlr4::ParserRuleContext* expr_context) -{ - return visit(expr_context).as>(); -} diff --git a/parser_library/src/expressions/visitors/expression_analyzer.h b/parser_library/src/expressions/visitors/expression_analyzer.h deleted file mode 100644 index 4cf477684..000000000 --- a/parser_library/src/expressions/visitors/expression_analyzer.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2019 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 SEMANTICS_EXPRESSION_ANALYZER_H -#define SEMANTICS_EXPRESSION_ANALYZER_H - -#include "../evaluation_context.h" -#include "hlasmparser.h" -#include "hlasmparserBaseVisitor.h" - -namespace hlasm_plugin::parser_library::expressions { - -// visitor for analyzing any undefined symbol attribute references -class expression_analyzer : public parsing::hlasmparserBaseVisitor -{ - evaluation_context eval_ctx_; - -public: - expression_analyzer(evaluation_context eval_ctx); - - // retrieves yet not defined symbols from the structures - std::set get_undefined_symbol_references(antlr4::ParserRuleContext* expr_context); - std::set get_undefined_symbol_references(const semantics::concat_chain& chain); - std::set get_undefined_symbol_references(const semantics::var_sym& symbol); - -private: - std::set visit_ref(antlr4::ParserRuleContext* expr_context); - - virtual antlrcpp::Any visitExpr(parsing::hlasmparser::ExprContext* ctx) override; - virtual antlrcpp::Any visitExpr_p(parsing::hlasmparser::Expr_pContext* ctx) override; - virtual antlrcpp::Any visitExpr_s(parsing::hlasmparser::Expr_sContext* ctx) override; - virtual antlrcpp::Any visitExpr_p_space_c(parsing::hlasmparser::Expr_p_space_cContext* ctx) override; - virtual antlrcpp::Any visitTerm_c(parsing::hlasmparser::Term_cContext* ctx) override; - virtual antlrcpp::Any visitTerm(parsing::hlasmparser::TermContext* ctx) override; - virtual antlrcpp::Any visitId_sub(parsing::hlasmparser::Id_subContext* ctx) override; - virtual antlrcpp::Any visitExpr_p_comma_c(parsing::hlasmparser::Expr_p_comma_cContext* ctx) override; - virtual antlrcpp::Any visitSubscript(parsing::hlasmparser::SubscriptContext* ctx) override; - virtual antlrcpp::Any visitCa_string(parsing::hlasmparser::Ca_stringContext* ctx) override; - virtual antlrcpp::Any visitCa_string_b(parsing::hlasmparser::Ca_string_bContext* ctx) override; - virtual antlrcpp::Any visitCa_dupl_factor(parsing::hlasmparser::Ca_dupl_factorContext* ctx) override; - virtual antlrcpp::Any visitData_attribute(parsing::hlasmparser::Data_attributeContext* ctx) override; -}; - -} // namespace hlasm_plugin::parser_library::expressions -#endif diff --git a/parser_library/src/expressions/visitors/expression_evaluator.cpp b/parser_library/src/expressions/visitors/expression_evaluator.cpp deleted file mode 100644 index 455d0dc30..000000000 --- a/parser_library/src/expressions/visitors/expression_evaluator.cpp +++ /dev/null @@ -1,589 +0,0 @@ -/* - * Copyright (c) 2019 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 "expression_evaluator.h" - -#include "ebcdic_encoding.h" -#include "expression_analyzer.h" -#include "processing/context_manager.h" - -using namespace hlasm_plugin::parser_library; -using namespace hlasm_plugin::parser_library::expressions; - -expression_evaluator::expression_evaluator(evaluation_context eval_ctx) - : diagnosable_ctx(eval_ctx.hlasm_ctx) - , eval_ctx_(eval_ctx) - , resolved_refs_(nullptr) -{} - -expr_ptr expression_evaluator::evaluate_expression(antlr4::ParserRuleContext* expr_context) -{ - expression_analyzer analyzer(eval_ctx_); - - auto refs = analyzer.get_undefined_symbol_references(expr_context); - - resolved_refs_ = &eval_ctx_.attr_provider.lookup_forward_attribute_references(std::move(refs)); - - auto result = visit(expr_context).as(); - - if (result->diag) - { - result->diag->diag_range = semantics::range_provider().get_range(expr_context); - add_diagnostic(*result->diag); - } - - return result; -} - -std::vector expression_evaluator::evaluate_expressions(std::vector exprs_context) -{ - expression_analyzer analyzer(eval_ctx_); - - processing::attribute_provider::forward_reference_storage collected_refs; - - for (auto& expr : exprs_context) - { - auto refs = analyzer.get_undefined_symbol_references(expr); - - for (auto& ref : refs) - collected_refs.insert(ref); - } - - resolved_refs_ = &eval_ctx_.attr_provider.lookup_forward_attribute_references(std::move(collected_refs)); - - std::vector sublist; - - for (auto expr_ctx : exprs_context) - { - auto e = visit(expr_ctx).as(); - if (e->diag) - { - e->diag->diag_range = semantics::range_provider().get_range(expr_ctx); - add_diagnostic(*e->diag); - } - sublist.push_back(std::move(e)); - } - - return sublist; -} - -std::string expression_evaluator::concatenate_chain(const semantics::concat_chain& chain) -{ - expression_analyzer analyzer(eval_ctx_); - - auto tmp = analyzer.get_undefined_symbol_references(chain); - - resolved_refs_ = &eval_ctx_.attr_provider.lookup_forward_attribute_references(std::move(tmp)); - - return concatenate(chain); -} - -void expression_evaluator::collect_diags() const {} - -antlrcpp::Any expression_evaluator::visitExpr(parsing::hlasmparser::ExprContext* ctx) -{ - return antlrcpp::Any(expression::evaluate(visit(ctx->expr_p_space_c()))); -} - -antlrcpp::Any expression_evaluator::visitExpr_test(parsing::hlasmparser::Expr_testContext* ctx) -{ - return visit(ctx->expr_statement()); -} - -antlrcpp::Any expression_evaluator::visitExpr_statement(parsing::hlasmparser::Expr_statementContext* ctx) -{ - std::string res; - - if (ctx->tmp != nullptr) - { - res = visit(ctx->tmp).as(); - res.push_back('\n'); - } - res.append(visit(ctx->expr_p()).as()->get_str_val()); - return res; -} - -antlrcpp::Any expression_evaluator::visitExpr_p(parsing::hlasmparser::Expr_pContext* ctx) -{ - if (ctx->expr_sContext != nullptr) - return visit(ctx->expr_sContext); - else if (ctx->children.at(0)->getText() == "+") - return visit(ctx->expr_p()); - else - return (-*visitE(ctx->expr_p())); -} - -antlrcpp::Any expression_evaluator::visitExpr_s(parsing::hlasmparser::Expr_sContext* ctx) -{ - if (ctx->t != nullptr) - return visit(ctx->t); - - auto a = visitE(ctx->tmp); - auto b = visitE(ctx->term_c()); - - if (ctx->children.at(1)->getText() == "+") - return (*a + *b); - else - return (*a - *b); -} - -antlrcpp::Any expression_evaluator::visitTerm_c(parsing::hlasmparser::Term_cContext* ctx) -{ - if (ctx->t != nullptr) - return visit(ctx->t); - - auto a = visitE(ctx->tmp); - auto b = visitE(ctx->term()); - - if (ctx->children.at(1)->getText() == "*") - return (*a * *b); - else - return (*a / *b); -} - -antlrcpp::Any expression_evaluator::visitTerm(parsing::hlasmparser::TermContext* ctx) -{ - if (ctx->var_symbolContext != nullptr) - { - auto value = get_var_sym_value(ctx->var_symbolContext->vs.get()); - switch (value.type) - { - case context::SET_t_enum::A_TYPE: - return (expr_ptr)make_arith(value.access_a()); - case context::SET_t_enum::B_TYPE: - return (expr_ptr)make_logic(value.access_b()); - case context::SET_t_enum::C_TYPE: - return (expr_ptr)arithmetic_expression::from_string(value.access_c(), false); - default: - return (expr_ptr)make_arith(0); - } - } - - if (ctx->expr() != nullptr) - return visit(ctx->expr()); - - if (ctx->ca_string() != nullptr) - return (expr_ptr)visit(ctx->ca_string()).as(); - - if (ctx->data_attribute() != nullptr) - return visit(ctx->data_attribute()); - - if (ctx->string() != nullptr) - return expression::self_defining_term( - ctx->children.at(0)->getText(), visit(ctx->string()).as(), false); /*TODO: dbcs*/ - - if (ctx->id_sub() != nullptr) - { - return visit(ctx->id_sub()); - } - - if (ctx->children.size() == 1) - { - return visit(ctx->children.at(0)); - } - - assert(ctx->exception); - return (expr_ptr)make_arith(0); -} - -antlrcpp::Any expression_evaluator::visitId_sub(parsing::hlasmparser::Id_subContext* ctx) -{ - auto subscript = visit(ctx->subscriptContext).as>(); - if (subscript.empty()) - { - auto symbol_name = ctx->id_no_dotContext->name; - if (keyword_expression::is_keyword(*symbol_name)) - return static_cast(std::make_unique(*symbol_name)); - - auto tmp_symbol = eval_ctx_.hlasm_ctx.ord_ctx.get_symbol(symbol_name); - - if (tmp_symbol && tmp_symbol->kind() == context::symbol_value_kind::ABS) - return static_cast(make_arith(tmp_symbol->value().get_abs())); - else - { - auto err_ex = make_arith(0); - err_ex->diag = error_messages::e005(); - return static_cast(err_ex); - } - } - else - { - assert(subscript.size() <= 2 && subscript.size() > 0); - if (subscript.size() == 1) - return subscript[0]->unary_operation(*ctx->id_no_dotContext->name); - else - return subscript[0]->binary_operation(*ctx->id_no_dotContext->name, subscript[1]); - } -} - -antlrcpp::Any expression_evaluator::visitExpr_p_comma_c(parsing::hlasmparser::Expr_p_comma_cContext* ctx) -{ - std::vector exs; - if (ctx->exs != nullptr) - exs = visit(ctx->exs).as>(); - auto expr = visit(ctx->expr_pContext); - exs.push_back(expr.as()); - return exs; -} - -antlrcpp::Any expression_evaluator::visitSubscript(parsing::hlasmparser::SubscriptContext* ctx) -{ - if (ctx->children.size() >= 3) - { - return visit(ctx->expr_p_comma_cContext).as>(); - } - - return std::vector(); -} - -antlrcpp::Any expression_evaluator::visitString(parsing::hlasmparser::StringContext* ctx) -{ - return ctx->string_ch_cContext->value; -} - -antlrcpp::Any expression_evaluator::visitCa_string(parsing::hlasmparser::Ca_stringContext* ctx) -{ - if (ctx->tmp != nullptr) - return visit(ctx->tmp).as()->append(visit(ctx->ca_string_b()).as()); - else - return visit(ctx->ca_string_b()); -} - -antlrcpp::Any expression_evaluator::visitCa_string_b(parsing::hlasmparser::Ca_string_bContext* ctx) -{ - auto tmp = concatenate(ctx->string_ch_v_c()->chain); - auto ex = make_char(tmp); - expr_ptr s, e; - if (ctx->substring() && ctx->substring()->e1 != nullptr) - s = visit(ctx->substring()->e1); - if (ctx->substring() && ctx->substring()->e2 != nullptr) - e = visit(ctx->substring()->e2); - return ex->substring(visit(ctx->ca_dupl_factor()).as(), s, e); -} - -antlrcpp::Any expression_evaluator::visitCa_dupl_factor(parsing::hlasmparser::Ca_dupl_factorContext* ctx) -{ - if (ctx->expr_p() != nullptr) - return visit(ctx->expr_p()).as()->get_numeric_value(); - else - return 1; -} - -antlrcpp::Any expression_evaluator::visitExpr_p_space_c(parsing::hlasmparser::Expr_p_space_cContext* ctx) -{ - std::deque exs; - if (ctx->exs != nullptr) - exs = visit(ctx->exs).as>(); - exs.push_back(visitE(ctx->expr_p())); - return exs; -} - -antlrcpp::Any expression_evaluator::visitData_attribute(parsing::hlasmparser::Data_attributeContext* ctx) -{ - processing::context_manager mngr(eval_ctx_.hlasm_ctx); - std::optional SET_val; - context::id_index symbol_name = nullptr; - - auto attr = ctx->attribute; - - if (ctx->var_symbol()) - { - auto [name, expr_subscript] = evaluate_var_sym(ctx->var_symbol()->vs.get()); - - // get evaluated_subscript - std::vector subscript; - for (auto tree : expr_subscript) - { - subscript.push_back((size_t)mngr.convert_to(tree->get_set_value(), - semantics::range_provider().get_range(ctx->var_symbol()->vs->subscript[subscript.size()]))); - } - - // get symbol - auto symbol = eval_ctx_.hlasm_ctx.get_var_sym(name); - - // get value - if (context::symbol_attributes::needs_ordinary(attr)) - { - // get substituted name - auto tmp_val = mngr.get_var_sym_value(name, expr_subscript, ctx->var_symbol()->vs->symbol_range); - auto val = mngr.convert_to(tmp_val, ctx->var_symbol()->vs->symbol_range); - auto [valid, new_name] = mngr.try_get_symbol_name(val, ctx->var_symbol()->vs->symbol_range); - - if (!valid) - { - SET_val.emplace((attr == context::data_attr_kind::O) ? "U" : 0); - symbol_name = new_name; - } - else - { - if (!eval_ctx_.hlasm_ctx.ord_ctx.get_symbol(new_name) - && context::symbol_attributes::ordinary_allowed(attr)) // requires attribute lookahead - SET_val.emplace( - lookup_variable_symbol_attribute(attr, new_name, ctx->var_symbol()->vs->symbol_range)); - else - SET_val.emplace(eval_ctx_.hlasm_ctx.get_data_attribute(attr, new_name)); - } - } - else if (attr == context::data_attr_kind::T) - { - if (!mngr.test_symbol_for_read(symbol, expr_subscript, ctx->var_symbol()->vs->symbol_range)) - SET_val.emplace(std::string("U")); - - auto t_attr_value = eval_ctx_.hlasm_ctx.get_data_attribute(attr, symbol, subscript).access_c(); - if (t_attr_value == "U" && symbol) - { - auto tmp_val = mngr.get_var_sym_value(name, expr_subscript, ctx->var_symbol()->vs->symbol_range); - auto val = mngr.convert_to(tmp_val, ctx->var_symbol()->vs->symbol_range); - auto [valid, new_name] = processing::context_manager(eval_ctx_.hlasm_ctx) - .try_get_symbol_name(val, ctx->var_symbol()->vs->symbol_range); - - if (valid && !eval_ctx_.hlasm_ctx.ord_ctx.get_symbol(new_name)) // requires attribute lookahead - SET_val.emplace( - lookup_variable_symbol_attribute(attr, new_name, ctx->var_symbol()->vs->symbol_range)); - else - SET_val.emplace(std::string("U")); - } - else - SET_val.emplace(t_attr_value); - } - else - { - if (attr == context::data_attr_kind::K - && !mngr.test_symbol_for_read(symbol, expr_subscript, ctx->var_symbol()->vs->symbol_range)) - SET_val.emplace(1); - else - SET_val.emplace(eval_ctx_.hlasm_ctx.get_data_attribute(attr, symbol, subscript)); - } - } - else if (ctx->id()) - { - symbol_name = ctx->id()->name; - if (context::symbol_attributes::ordinary_allowed(attr)) - { - auto symbol = eval_ctx_.hlasm_ctx.ord_ctx.get_symbol(symbol_name); - - SET_val.emplace(get_ord_attr_value(attr, symbol, symbol_name, semantics::range_provider().get_range(ctx))); - } - else if (attr == context::data_attr_kind::D || attr == context::data_attr_kind::O) - { - SET_val.emplace(eval_ctx_.hlasm_ctx.get_data_attribute(attr, ctx->id()->name)); - } - else - { - SET_val.emplace(context::symbol_attributes::default_value(attr)); - add_diagnostic(diagnostic_op::error_E066(semantics::range_provider().get_range(ctx))); - } - } - - if (attr == context::data_attr_kind::O && SET_val->type == context::SET_t_enum::C_TYPE && SET_val->access_c() == "U" - && symbol_name) // check for external libraries - { - std::string right_value = eval_ctx_.lib_provider.has_library(*symbol_name, eval_ctx_.hlasm_ctx) ? "S" : "U"; - SET_val.emplace(right_value); - } - - collect_diags_from_child(mngr); - - if (SET_val) - switch (SET_val->type) - { - case context::SET_t_enum::A_TYPE: - return static_cast(make_arith(SET_val->access_a())); - case context::SET_t_enum::B_TYPE: - return static_cast(make_logic(SET_val->access_b())); - case context::SET_t_enum::C_TYPE: - return static_cast(make_char(SET_val->access_c())); - default: - break; - } - - return static_cast(make_arith(0)); -} - -antlrcpp::Any expression_evaluator::visitNum(parsing::hlasmparser::NumContext* ctx) -{ - return (expr_ptr)make_arith(ctx->value); -} - -context::SET_t expression_evaluator::get_ord_attr_value( - context::data_attr_kind attr, const context::symbol* symbol, context::id_index symbol_name, range symbol_range) -{ - if (!symbol) - { - auto it = resolved_refs_->find(symbol_name); - if (it != resolved_refs_->end()) - symbol = &it->second; - } - - if (!symbol) - { - if (attr == context::data_attr_kind::T) - return std::string("U"); - else - { - add_diagnostic(diagnostic_op::warning_W013(symbol_range)); - return context::symbol_attributes::default_value(attr); - } - } - else - { - if (attr == context::data_attr_kind::T) - return std::string({ (char)ebcdic_encoding::e2a[symbol->attributes().type()] }); - else if (!symbol->attributes().can_have_SI_attr() - && (attr == context::data_attr_kind::S || attr == context::data_attr_kind::I)) - { - add_diagnostic(diagnostic_op::error_E066(symbol_range)); - return context::symbol_attributes::default_value(attr); - } - else if (!symbol->attributes().is_defined(attr)) - { - add_diagnostic(diagnostic_op::warning_W013(symbol_range)); - return context::symbol_attributes::default_value(attr); - } - else - return symbol->attributes().get_attribute_value(attr); - } -} - -std::string expression_evaluator::concatenate(const semantics::concat_chain& chain) -{ - std::string result; - bool last_was_var = false; - - for (auto& point : chain) - { - if (!point) - continue; - switch (point->type) - { - case semantics::concat_type::STR: - last_was_var = false; - result.append(concat(point->access_str())); - break; - case semantics::concat_type::DOT: - if (last_was_var) - { - last_was_var = false; - continue; - } - result.append(concat(point->access_dot())); - break; - case semantics::concat_type::EQU: - last_was_var = false; - result.append(concat(point->access_equ())); - break; - case semantics::concat_type::VAR: - last_was_var = true; - result.append(concat(point->access_var())); - break; - case semantics::concat_type::SUB: - last_was_var = false; - result.append(concat(point->access_sub())); - break; - default: - break; - } - } - return result; -} - -expr_ptr expression_evaluator::visitE(antlr4::ParserRuleContext* ctx) { return visit(ctx).as(); } - -std::string expression_evaluator::concat(semantics::char_str* str) { return str->value; } - -std::string expression_evaluator::concat(semantics::var_sym* vs) -{ - return processing::context_manager(eval_ctx_.hlasm_ctx) - .convert_to(get_var_sym_value(vs), vs->symbol_range); -} - -std::string expression_evaluator::concat(semantics::dot*) { return "."; } - -std::string expression_evaluator::concat(semantics::equals*) { return "="; } - -std::string expression_evaluator::concat(semantics::sublist* sublist) -{ - std::string ret("("); - for (size_t i = 0; i < sublist->list.size(); ++i) - { - ret.append(concatenate(sublist->list[i])); - if (i != sublist->list.size() - 1) - ret.append(","); - } - ret.append(")"); - - return ret; -} - -context::SET_t expression_evaluator::get_var_sym_value(semantics::var_sym* vs) -{ - processing::context_manager mngr(eval_ctx_.hlasm_ctx); - - context::id_index id; - if (!vs->created) - id = vs->access_basic()->name; - else - { - auto [valid, name] = - mngr.try_get_symbol_name(concatenate(vs->access_created()->created_name), vs->symbol_range); - if (!valid) - return context::SET_t(); - id = name; - } - - std::vector subscript; - - for (const auto& tree : vs->subscript) - subscript.push_back(visit(tree).as()); - - auto value = mngr.get_var_sym_value(id, subscript, vs->symbol_range); - - collect_diags_from_child(mngr); - - return value; -} - -std::pair> expression_evaluator::evaluate_var_sym(semantics::var_sym* vs) -{ - expression_evaluator evaluator(eval_ctx_); - - context::id_index name; - if (vs->created) - name = eval_ctx_.hlasm_ctx.ids().add(concatenate_chain(vs->access_created()->created_name)); - else - name = vs->access_basic()->name; - - std::vector subscript; - - for (auto& tree : vs->subscript) - subscript.push_back(evaluator.evaluate_expression(tree)); - - collect_diags_from_child(evaluator); - - return std::make_pair(name, std::move(subscript)); -} - -context::SET_t expression_evaluator::lookup_variable_symbol_attribute( - context::data_attr_kind attr, context::id_index symbol_name, range symbol_range) -{ - auto res = eval_ctx_.attr_provider.lookup_forward_attribute_references({ symbol_name }); - - context::symbol* symbol = nullptr; - - auto it = res.find(symbol_name); - if (it != res.end()) - symbol = &it->second; - - return get_ord_attr_value(attr, symbol, symbol_name, symbol_range); -} diff --git a/parser_library/src/expressions/visitors/expression_evaluator.h b/parser_library/src/expressions/visitors/expression_evaluator.h deleted file mode 100644 index 6c131ae0d..000000000 --- a/parser_library/src/expressions/visitors/expression_evaluator.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2019 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 SEMANTICS_EXPRESSION_EVALUATOR_H -#define SEMANTICS_EXPRESSION_EVALUATOR_H - -#include "../evaluation_context.h" -#include "diagnosable_ctx.h" -#include "hlasmparser.h" -#include "hlasmparserBaseVisitor.h" - -namespace hlasm_plugin::parser_library::expressions { - -/** - * visitor that evaluates expressions - * matches grammar (for each grammar rule there is a visit...() function - * that is called when a rule is matched in grammar) - * */ -class expression_evaluator : public parsing::hlasmparserBaseVisitor, public diagnosable_ctx -{ - evaluation_context eval_ctx_; - // storage of resolved symbol attribute references - const processing::attribute_provider::resolved_reference_storage* resolved_refs_; - -public: - expression_evaluator(evaluation_context eval_ctx); - - expr_ptr evaluate_expression(antlr4::ParserRuleContext* expr_context); - - std::vector evaluate_expressions(std::vector exprs_context); - - std::string concatenate_chain(const semantics::concat_chain& chain); - - virtual void collect_diags() const override; - -private: - std::string concatenate(const semantics::concat_chain& chain); - - expr_ptr visitE(antlr4::ParserRuleContext* ctx); - - /** - * entry expression rule - * children are expr_p_space_c - * expr_p_space_c are a space separated sub-expressions - * this is needed as some tokens might represent a keyword (such as AND) or a variable name - * this depends solely on the position of the token within a expr - * and it is known after evaluation of the left-hand side of the expression - * */ - virtual antlrcpp::Any visitExpr(parsing::hlasmparser::ExprContext* ctx) override; - /** - * helper grammar rule used in unit tests - * */ - virtual antlrcpp::Any visitExpr_test(parsing::hlasmparser::Expr_testContext* ctx) override; - virtual antlrcpp::Any visitExpr_statement(parsing::hlasmparser::Expr_statementContext* ctx) override; - virtual antlrcpp::Any visitExpr_p(parsing::hlasmparser::Expr_pContext* ctx) override; - virtual antlrcpp::Any visitExpr_s(parsing::hlasmparser::Expr_sContext* ctx) override; - /** - * generates space separated expressions - * these are evaluated in visitExpr() - * */ - virtual antlrcpp::Any visitExpr_p_space_c(parsing::hlasmparser::Expr_p_space_cContext* ctx) override; - virtual antlrcpp::Any visitTerm_c(parsing::hlasmparser::Term_cContext* ctx) override; - virtual antlrcpp::Any visitTerm(parsing::hlasmparser::TermContext* ctx) override; - virtual antlrcpp::Any visitId_sub(parsing::hlasmparser::Id_subContext* ctx) override; - - virtual antlrcpp::Any visitExpr_p_comma_c(parsing::hlasmparser::Expr_p_comma_cContext* ctx) override; - virtual antlrcpp::Any visitSubscript(parsing::hlasmparser::SubscriptContext* ctx) override; - virtual antlrcpp::Any visitString(parsing::hlasmparser::StringContext* ctx) override; - virtual antlrcpp::Any visitCa_string(parsing::hlasmparser::Ca_stringContext* ctx) override; - virtual antlrcpp::Any visitCa_string_b(parsing::hlasmparser::Ca_string_bContext* ctx) override; - virtual antlrcpp::Any visitCa_dupl_factor(parsing::hlasmparser::Ca_dupl_factorContext* ctx) override; - virtual antlrcpp::Any visitData_attribute(parsing::hlasmparser::Data_attributeContext* ctx) override; - virtual antlrcpp::Any visitNum(parsing::hlasmparser::NumContext* ctx) override; - - context::SET_t get_ord_attr_value( - context::data_attr_kind attr, const context::symbol* symbol, context::id_index symbol_name, range symbol_range); - - std::string concat(semantics::char_str* str); - std::string concat(semantics::var_sym* vs); - std::string concat(semantics::dot*); - std::string concat(semantics::equals*); - std::string concat(semantics::sublist* sublist); - - context::SET_t get_var_sym_value(semantics::var_sym* vs); - std::pair> evaluate_var_sym(semantics::var_sym* vs); - - context::SET_t lookup_variable_symbol_attribute( - context::data_attr_kind attr, context::id_index symbol_name, range symbol_range); -}; -} // namespace hlasm_plugin::parser_library::expressions - - -#endif \ No newline at end of file diff --git a/parser_library/src/parsing/grammar/ca_expr_rules.g4 b/parser_library/src/parsing/grammar/ca_expr_rules.g4 index 341713b3a..0d860d488 100644 --- a/parser_library/src/parsing/grammar/ca_expr_rules.g4 +++ b/parser_library/src/parsing/grammar/ca_expr_rules.g4 @@ -15,105 +15,164 @@ //rules for CA expresssions, variable symbol, CA string parser grammar ca_expr_rules; - -expr // returns [expr_ptr e] - : SPACE* expr_p_space_c SPACE*; - -expr_p returns [vs_ptr* vs_link = nullptr] - : expr_s +expr returns [ca_expr_ptr ca_expr] + : begin=expr_s { - $vs_link = std::move($expr_s.vs_link); + $ca_expr = std::move($begin.ca_expr); + } + ((plus|minus) next=expr_s + { + auto r = provider.get_range($begin.ctx->getStart(), $next.ctx->getStop()); + if ($plus.ctx) + $ca_expr = std::make_unique>(std::move($ca_expr), std::move($next.ca_expr), r); + else + $ca_expr = std::make_unique>(std::move($ca_expr), std::move($next.ca_expr), r); + $plus.ctx = nullptr; } - | plus tmp=expr_p - | minus tmp=expr_p; + )*; -expr_s returns [vs_ptr* vs_link = nullptr] - : t=term_c +expr_s returns [ca_expr_ptr ca_expr] + : begin=term_c + { + $ca_expr = std::move($begin.ca_expr); + } + ((slash|asterisk) next=term_c { - $vs_link = std::move($term_c.vs_link); + auto r = provider.get_range($begin.ctx->getStart(), $next.ctx->getStop()); + if ($slash.ctx) + $ca_expr = std::make_unique>(std::move($ca_expr), std::move($next.ca_expr), r); + else + $ca_expr = std::make_unique>(std::move($ca_expr), std::move($next.ca_expr), r); + $slash.ctx = nullptr; } - | tmp=expr_s minus term_c - | tmp=expr_s plus term_c; + )*; -term_c returns [vs_ptr* vs_link = nullptr] - : t=term +term_c returns [ca_expr_ptr ca_expr] + : term { - $vs_link = std::move($term.vs_link); + $ca_expr = std::move($term.ca_expr); } - | tmp=term_c slash term - | tmp=term_c asterisk term; + | plus tmp=term_c + { + auto r = provider.get_range($plus.ctx->getStart(), $tmp.ctx->getStop()); + $ca_expr = std::make_unique(std::move($tmp.ca_expr), r); + } + | minus tmp=term_c + { + auto r = provider.get_range($minus.ctx->getStart(), $tmp.ctx->getStop()); + $ca_expr = std::make_unique(std::move($tmp.ca_expr), r); + }; -term returns [vs_ptr* vs_link = nullptr] - : lpar expr rpar +term returns [ca_expr_ptr ca_expr] + : expr_list + { + $ca_expr = std::move($expr_list.ca_expr); + } | var_symbol { - $vs_link = &$var_symbol.vs; + auto r = provider.get_range($var_symbol.ctx); + $ca_expr = std::make_unique(std::move($var_symbol.vs), r); } - | ca_string + | ca_string { - collector.add_hl_symbol(token_info(provider.get_range( $ca_string.ctx),hl_scopes::string)); + auto r = provider.get_range($ca_string.ctx); + collector.add_hl_symbol(token_info(r, hl_scopes::string)); + $ca_expr = std::move($ca_string.ca_expr); } | data_attribute - | {is_self_def()}? ORDSYMBOL string + { + 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); + else if (std::holds_alternative($data_attribute.value)) + $ca_expr = std::make_unique(std::move(std::get($data_attribute.value)), $data_attribute.attribute, r); + } + | {is_self_def()}? self_def_term + { + auto r = provider.get_range($self_def_term.ctx); + $ca_expr = std::make_unique($self_def_term.value, r); + } | num - | id_sub + { + auto r = provider.get_range($num.ctx); + $ca_expr = std::make_unique($num.value, r); + } + | ca_dupl_factor id_no_dot subscript_ne { - $vs_link = &$id_sub.vs; - }; + auto r = provider.get_range($ca_dupl_factor.ctx->getStart(), $subscript_ne.ctx->getStop()); -id_sub returns [vs_ptr vs] - : id_no_dot subscript - { - $vs = std::make_unique($id_no_dot.name,std::move($subscript.value),provider.get_range( $id_no_dot.ctx->getStart(),$subscript.ctx->getStop())); - }; + auto func = ca_common_expr_policy::get_function(*$id_no_dot.name); + auto [param_size, param_kind] = ca_common_expr_policy::get_function_param_info(func, ca_common_expr_policy::get_function_type(func)); + resolve_expression($subscript_ne.value, param_kind); -expr_p_comma_c returns [std::vector ext] - : expr_p - { - $ext.push_back($expr_p.ctx); + $ca_expr = std::make_unique($id_no_dot.name, func, std::move($subscript_ne.value), std::move($ca_dupl_factor.value), r); } - | exs=expr_p_comma_c comma expr_p - { - $exs.ext.push_back($expr_p.ctx); - $ext = $exs.ext; + | id_no_dot + { + auto r = provider.get_range($id_no_dot.ctx); + $ca_expr = std::make_unique($id_no_dot.name, r); + }; + +expr_list returns [ca_expr_ptr ca_expr] + : lpar SPACE* expr_space_c SPACE* rpar + { + auto r = provider.get_range($lpar.ctx->getStart(), $rpar.ctx->getStop()); + $ca_expr = std::make_unique(std::move($expr_space_c.ca_exprs), r); }; -expr_p_space_c returns [std::deque ext] - : expr_p +expr_space_c returns [std::vector ca_exprs] + : expr { - $ext.push_back($expr_p.ctx); + $ca_exprs.push_back(std::move($expr.ca_expr)); } - | exs=expr_p_space_c SPACE* expr_p + | tmp=expr_space_c SPACE* expr { - $exs.ext.push_back($expr_p.ctx); - $ext = $exs.ext; + $tmp.ca_exprs.push_back(std::move($expr.ca_expr)); + $ca_exprs = std::move($tmp.ca_exprs); }; seq_symbol returns [seq_sym ss] - : dot_ id_no_dot + : dot id_no_dot { - $ss = seq_sym{$id_no_dot.name,provider.get_range( $dot_.ctx->getStart(),$id_no_dot.ctx->getStop())}; + $ss = seq_sym{$id_no_dot.name,provider.get_range( $dot.ctx->getStart(),$id_no_dot.ctx->getStop())}; }; +subscript_ne returns [std::vector value] + : lpar expr_comma_c rpar + { + $value = std::move($expr_comma_c.ca_exprs); + }; - -subscript returns [std::vector value] - : lpar expr_p_comma_c rpar +subscript returns [std::vector value] + : subscript_ne { - $value = $expr_p_comma_c.ext; + $value = std::move($subscript_ne.value); + resolve_expression($value, context::SET_t_enum::A_TYPE); } | ; +expr_comma_c returns [std::vector ca_exprs] + : expr + { + $ca_exprs.push_back(std::move($expr.ca_expr)); + } + | tmp=expr_comma_c comma expr + { + $tmp.ca_exprs.push_back(std::move($expr.ca_expr)); + $ca_exprs = std::move($tmp.ca_exprs); + }; + + created_set_body returns [concat_point_ptr point] - : ORDSYMBOL {$point = std::make_unique($ORDSYMBOL->getText());} - | IDENTIFIER {$point = std::make_unique($IDENTIFIER->getText());} - | NUM {$point = std::make_unique($NUM->getText());} - | var_symbol {$point = std::move($var_symbol.vs);} - | dot_ {$point = std::make_unique();}; + : ORDSYMBOL {$point = std::make_unique($ORDSYMBOL->getText());} + | IDENTIFIER {$point = std::make_unique($IDENTIFIER->getText());} + | NUM {$point = std::make_unique($NUM->getText());} + | var_symbol {$point = std::make_unique(std::move($var_symbol.vs));} + | dot {$point = std::make_unique();}; created_set_body_c returns [concat_chain concat_list] : cl=created_set_body {$concat_list.push_back(std::move($cl.point));} @@ -122,16 +181,16 @@ created_set_body_c returns [concat_chain concat_list] created_set_symbol returns [vs_ptr vs] : AMPERSAND lpar clc=created_set_body_c rpar subscript { - $vs = std::make_unique(std::move($clc.concat_list),std::move($subscript.value),provider.get_range( $AMPERSAND,$subscript.ctx->getStop())); + $vs = std::make_unique(std::move($clc.concat_list),std::move($subscript.value),provider.get_range($AMPERSAND,$subscript.ctx->getStop())); } - | ampersand lpar rpar subscript; //empty set symbol err; + | ampersand lpar rpar subscript; //empty set symbol err TODO 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(id, std::move($tmp.value), r); + $vs = std::make_unique(id, std::move($tmp.value), r); collector.add_lsp_symbol(id,r,symbol_type::var); collector.add_hl_symbol(token_info(r,hl_scopes::var_symbol)); } @@ -151,26 +210,79 @@ vs_id returns [id_index name = id_storage::empty_id] -ca_dupl_factor // returns [int32_t df] - : lpar expr_p rpar +var_def returns [vs_ptr vs] + : var_def_name var_def_substr + { + auto r = provider.get_range($var_def_name.ctx); + if ($var_def_name.created_name.empty()) + { + $vs = std::make_unique($var_def_name.name, std::move($var_def_substr.value), r); + collector.add_lsp_symbol($var_def_name.name,r,symbol_type::var); + collector.add_hl_symbol(token_info(r,hl_scopes::var_symbol)); + } + else + $vs = std::make_unique(std::move($var_def_name.created_name), std::move($var_def_substr.value), r); + }; + +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);}; + +var_def_substr returns [std::vector value] + : lpar num rpar + { + auto r = provider.get_range($num.ctx); + $value.emplace_back(std::make_unique($num.value, r)); + } |; -substring // returns [expr_ptr start, expr_ptr end] - : lpar e1=expr_p comma e2=expr_p rpar - | lpar expr_p comma ASTERISK rpar - | lpar expr_p rpar + +ca_dupl_factor returns [ca_expr_ptr value] + : lpar expr rpar + { + $value =std::move($expr.ca_expr); + resolve_expression($value, context::SET_t_enum::A_TYPE); + } |; -ca_string_b // returns [std::unique_ptr e] - : ca_dupl_factor (apostrophe|attr) string_ch_v_c (apostrophe|attr) substring; +substring returns [expressions::ca_string::substring_t value] + : lpar e1=expr comma e2=expr 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); + } + |; -ca_string // returns [std::unique_ptr e] - : ca_string_b // {$e = std::move($ca_string_b.e);} - | tmp=ca_string dot_ ca_string_b; +ca_string_b returns [ca_expr_ptr ca_expr] + : ca_dupl_factor (apostrophe|attr) string_ch_v_c (apostrophe|attr) substring + { + auto r = provider.get_range($ca_dupl_factor.ctx->getStart(), $substring.ctx->getStop()); + $ca_expr = std::make_unique(std::move($string_ch_v_c.chain), std::move($ca_dupl_factor.value), std::move($substring.value), r); + }; + +ca_string returns [ca_expr_ptr ca_expr] + : ca_string_b + { + $ca_expr = std::move($ca_string_b.ca_expr); + } + | tmp=ca_string dot ca_string_b + { + auto r = provider.get_range($tmp.ctx->getStart(), $ca_string_b.ctx->getStop()); + $ca_expr = std::make_unique>(std::move($tmp.ca_expr), std::move($ca_string_b.ca_expr), r); + }; string_ch_v returns [concat_point_ptr point] : l_sp_ch_v {$point = std::move($l_sp_ch_v.point);} - | (APOSTROPHE|ATTR) (APOSTROPHE|ATTR) {$point = std::make_unique("'");}; + | (APOSTROPHE|ATTR) (APOSTROPHE|ATTR) {$point = std::make_unique("'");}; string_ch_v_c returns [concat_chain chain] : diff --git a/parser_library/src/parsing/grammar/ca_operand_rules.g4 b/parser_library/src/parsing/grammar/ca_operand_rules.g4 index b50cad6aa..ba1748bec 100644 --- a/parser_library/src/parsing/grammar/ca_operand_rules.g4 +++ b/parser_library/src/parsing/grammar/ca_operand_rules.g4 @@ -17,11 +17,14 @@ parser grammar ca_operand_rules; ca_op returns [operand_ptr op] - : lpar expr rpar seq_symbol + : expr_list seq_symbol { collector.add_hl_symbol(token_info(provider.get_range($seq_symbol.ctx),hl_scopes::seq_symbol)); collector.add_lsp_symbol($seq_symbol.ss.name,provider.get_range($seq_symbol.ctx),symbol_type::seq); - $op = std::make_unique(std::move($seq_symbol.ss),$expr.ctx,provider.get_range($lpar.ctx->getStart(),$seq_symbol.ctx->getStop())); + + resolve_expression($expr_list.ca_expr); + auto r = provider.get_range($expr_list.ctx->getStart(),$seq_symbol.ctx->getStop()); + $op = std::make_unique(std::move($seq_symbol.ss), std::move($expr_list.ca_expr), r); } | seq_symbol { @@ -29,16 +32,12 @@ ca_op returns [operand_ptr op] collector.add_lsp_symbol($seq_symbol.ss.name,provider.get_range($seq_symbol.ctx),symbol_type::seq); $op = std::make_unique(std::move($seq_symbol.ss),provider.get_range($seq_symbol.ctx)); } - | expr_p + | {!is_var_def()}? expr + { + resolve_expression($expr.ca_expr); + $op = std::make_unique(std::move($expr.ca_expr), provider.get_range($expr.ctx)); + } + | { is_var_def()}? var_def { - if($expr_p.vs_link && is_var_def()) - { - - auto tmp = std::make_unique(std::move(*$expr_p.vs_link),provider.get_range($expr_p.ctx)); - $op = std::move(tmp); - } - else - { - $op = std::make_unique($expr_p.ctx,provider.get_range($expr_p.ctx)); - } + $op = std::make_unique(std::move($var_def.vs), provider.get_range($var_def.ctx)); }; \ No newline at end of file diff --git a/parser_library/src/parsing/grammar/hlasmparser.g4 b/parser_library/src/parsing/grammar/hlasmparser.g4 index b06192aeb..cf2c0bac0 100644 --- a/parser_library/src/parsing/grammar/hlasmparser.g4 +++ b/parser_library/src/parsing/grammar/hlasmparser.g4 @@ -34,11 +34,15 @@ deferred_operand_rules; @header { #include "parsing/parser_impl.h" - #include "expressions/expression.h" - #include "expressions/arithmetic_expression.h" - #include "expressions/logic_expression.h" - #include "expressions/character_expression.h" - #include "expressions/keyword_expression.h" + #include "expressions/conditional_assembly/ca_operator_unary.h" + #include "expressions/conditional_assembly/ca_operator_binary.h" + #include "expressions/conditional_assembly/terms/ca_constant.h" + #include "expressions/conditional_assembly/terms/ca_expr_list.h" + #include "expressions/conditional_assembly/terms/ca_function.h" + #include "expressions/conditional_assembly/terms/ca_string.h" + #include "expressions/conditional_assembly/terms/ca_symbol.h" + #include "expressions/conditional_assembly/terms/ca_symbol_attribute.h" + #include "expressions/conditional_assembly/terms/ca_var_sym.h" #include "expressions/mach_expr_term.h" #include "expressions/mach_operator.h" #include "expressions/data_definition.h" @@ -185,7 +189,7 @@ num_ch : NUM+; num returns [self_def_t value] - : num_ch {$value = parse_self_def_term("",$num_ch.ctx->getText(),provider.get_range($num_ch.ctx));}; + : num_ch {$value = parse_self_def_term("D",$num_ch.ctx->getText(),provider.get_range($num_ch.ctx));}; self_def_term returns [self_def_t value] : ORDSYMBOL string @@ -207,7 +211,7 @@ id_ch_c returns [std::string value] id returns [id_index name, id_index using_qualifier] : id_no_dot {$name = $id_no_dot.name;} - | q=id_no_dot dot_ n=id_no_dot {$name = $n.name; $using_qualifier = $q.name; }; + | q=id_no_dot dot n=id_no_dot {$name = $n.name; $using_qualifier = $q.name; }; id_no_dot returns [id_index name = id_storage::empty_id] : ORDSYMBOL id_ch_c @@ -222,7 +226,7 @@ id_no_dot returns [id_index name = id_storage::empty_id] opt_dot returns [std::string value] - : dot_ id_ch_c {$value = std::move($id_ch_c.value); } + : dot id_ch_c {$value = std::move($id_ch_c.value); } | ; id_comma_c: id @@ -246,7 +250,7 @@ remark_o returns [std::optional value] //***** highlighting rules comma : COMMA {collector.add_hl_symbol(token_info(provider.get_range( $COMMA),hl_scopes::operator_symbol)); }; -dot_ +dot : DOT {collector.add_hl_symbol(token_info(provider.get_range( $DOT),hl_scopes::operator_symbol)); }; apostrophe : APOSTROPHE {collector.add_hl_symbol(token_info(provider.get_range( $APOSTROPHE),hl_scopes::operator_symbol)); }; @@ -258,7 +262,7 @@ rpar : RPAR {collector.add_hl_symbol(token_info(provider.get_range( $RPAR),hl_scopes::operator_symbol)); }; ampersand : AMPERSAND { collector.add_hl_symbol(token_info(provider.get_range( $AMPERSAND),hl_scopes::operator_symbol)); }; -equals_ +equals : EQUALS { collector.add_hl_symbol(token_info(provider.get_range( $EQUALS),hl_scopes::operator_symbol)); }; asterisk : ASTERISK {collector.add_hl_symbol(token_info(provider.get_range( $ASTERISK),hl_scopes::operator_symbol)); }; @@ -273,8 +277,8 @@ plus expr_statement - : expr_p - | tmp=expr_statement EOLLN expr_p + : expr + | tmp=expr_statement EOLLN expr ; expr_test diff --git a/parser_library/src/parsing/grammar/label_field_rules.g4 b/parser_library/src/parsing/grammar/label_field_rules.g4 index b638eb88a..ff266951a 100644 --- a/parser_library/src/parsing/grammar/label_field_rules.g4 +++ b/parser_library/src/parsing/grammar/label_field_rules.g4 @@ -69,12 +69,12 @@ l_common_rules returns [concat_chain chain] } | l_string_poss_space_c l_string_v { - $chain.push_back(std::make_unique(std::move($l_string_poss_space_c.value))); + $chain.push_back(std::make_unique(std::move($l_string_poss_space_c.value))); $chain.insert($chain.end(), std::make_move_iterator($l_string_v.chain.begin()), std::make_move_iterator($l_string_v.chain.end())); } | l_string_v_apo_sp l_string { - $l_string_v_apo_sp.chain.push_back(std::make_unique(std::move($l_string.value))); + $l_string_v_apo_sp.chain.push_back(std::make_unique(std::move($l_string.value))); $chain = std::move($l_string_v_apo_sp.chain); }; @@ -89,12 +89,12 @@ l_model_sp returns [concat_chain chain] | l_common_rules l_string_no_space_c { $chain = std::move($l_common_rules.chain); - $chain.push_back(std::make_unique(std::move($l_string_no_space_c.value))); + $chain.push_back(std::make_unique(std::move($l_string_no_space_c.value))); } | l_string_poss_space_c l_string l_string_v_apo { - $chain.push_back(std::make_unique(std::move($l_string_poss_space_c.value))); - $chain.push_back(std::make_unique(std::move($l_string.value))); + $chain.push_back(std::make_unique(std::move($l_string_poss_space_c.value))); + $chain.push_back(std::make_unique(std::move($l_string.value))); $chain.insert($chain.end(), std::make_move_iterator($l_string_v_apo.chain.begin()), std::make_move_iterator($l_string_v_apo.chain.end())); }; @@ -105,7 +105,7 @@ l_model returns [concat_chain chain] } | l_string l_string_v_apo { - $chain.push_back(std::make_unique(std::move($l_string.value))); + $chain.push_back(std::make_unique(std::move($l_string.value))); $chain.insert($chain.end(), std::make_move_iterator($l_string_v_apo.chain.begin()), std::make_move_iterator($l_string_v_apo.chain.end())); } | l_string_v l_string_v_apo @@ -116,7 +116,7 @@ l_model returns [concat_chain chain] | l_string_v l_string_no_space_c { $chain = std::move($l_string_v.chain); - $chain.push_back(std::make_unique(std::move($l_string_no_space_c.value))); + $chain.push_back(std::make_unique(std::move($l_string_no_space_c.value))); }; @@ -144,27 +144,27 @@ l_ch returns [std::string value] | RPAR {$value = ")";}; common_ch_v returns [concat_point_ptr point] - : ASTERISK {$point = std::make_unique("*");} - | MINUS {$point = std::make_unique("-");} - | PLUS {$point = std::make_unique("+");} - | LT {$point = std::make_unique("<");} - | GT {$point = std::make_unique(">");} - | SLASH {$point = std::make_unique("/");} - | EQUALS {$point = std::make_unique();} - | AMPERSAND AMPERSAND {$point = std::make_unique("&&");} - | VERTICAL {$point = std::make_unique("|");} - | IDENTIFIER {$point = std::make_unique($IDENTIFIER->getText());} - | NUM {$point = std::make_unique($NUM->getText());} - | ORDSYMBOL {$point = std::make_unique($ORDSYMBOL->getText());} - | DOT {$point = std::make_unique();} - | var_symbol {$point = std::move($var_symbol.vs);}; + : ASTERISK {$point = std::make_unique("*");} + | MINUS {$point = std::make_unique("-");} + | PLUS {$point = std::make_unique("+");} + | LT {$point = std::make_unique("<");} + | GT {$point = std::make_unique(">");} + | SLASH {$point = std::make_unique("/");} + | EQUALS {$point = std::make_unique();} + | AMPERSAND AMPERSAND {$point = std::make_unique("&&");} + | VERTICAL {$point = std::make_unique("|");} + | IDENTIFIER {$point = std::make_unique($IDENTIFIER->getText());} + | NUM {$point = std::make_unique($NUM->getText());} + | ORDSYMBOL {$point = std::make_unique($ORDSYMBOL->getText());} + | DOT {$point = std::make_unique();} + | var_symbol {$point = std::make_unique(std::move($var_symbol.vs));}; l_ch_v returns [concat_point_ptr point] : common_ch_v {$point = std::move($common_ch_v.point);} - | EQUALS {$point = std::make_unique("=");} - | COMMA {$point = std::make_unique(",");} - | LPAR {$point = std::make_unique("(");} - | RPAR {$point = std::make_unique(")");}; + | EQUALS {$point = std::make_unique("=");} + | COMMA {$point = std::make_unique(",");} + | LPAR {$point = std::make_unique("(");} + | RPAR {$point = std::make_unique(")");}; l_str_v returns [concat_chain chain] : @@ -177,8 +177,8 @@ l_string returns [std::string value] l_string_v returns [concat_chain chain] : l_string_o var_symbol l_str_v { - $chain.push_back(std::make_unique(std::move($l_string_o.value))); - $chain.push_back(std::move($var_symbol.vs)); + $chain.push_back(std::make_unique(std::move($l_string_o.value))); + $chain.push_back(std::make_unique(std::move($var_symbol.vs))); $chain.insert($chain.end(), std::make_move_iterator($l_str_v.chain.begin()), std::make_move_iterator($l_str_v.chain.end())); }; @@ -200,21 +200,21 @@ l_string_no_space_v returns [concat_chain chain] : l_apo l_string_o l_apo l_string_v { std::string tmp("'"); tmp.append(std::move($l_string_o.value)); tmp.append("'"); - $chain.push_back(std::make_unique(std::move(tmp))); + $chain.push_back(std::make_unique(std::move(tmp))); $chain.insert($chain.end(), std::make_move_iterator($l_string_v.chain.begin()), std::make_move_iterator($l_string_v.chain.end())); } | l_apo l_string_v l_apo l_string_o { - $chain.push_back(std::make_unique("'")); + $chain.push_back(std::make_unique("'")); $chain.insert($chain.end(), std::make_move_iterator($l_string_v.chain.begin()), std::make_move_iterator($l_string_v.chain.end())); - $chain.push_back(std::make_unique("'")); - $chain.push_back(std::make_unique(std::move($l_string_o.value))); + $chain.push_back(std::make_unique("'")); + $chain.push_back(std::make_unique(std::move($l_string_o.value))); } | l_apo str1=l_string_v l_apo str2=l_string_v { - $chain.push_back(std::make_unique("'")); + $chain.push_back(std::make_unique("'")); $chain.insert($chain.end(), std::make_move_iterator($str1.chain.begin()), std::make_move_iterator($str1.chain.end())); - $chain.push_back(std::make_unique("'")); + $chain.push_back(std::make_unique("'")); $chain.insert($chain.end(), std::make_move_iterator($str2.chain.begin()), std::make_move_iterator($str2.chain.end())); }; @@ -223,7 +223,7 @@ l_string_no_space_u returns [concat_chain chain] | l_apo str1=l_string_o l_apo str2=l_string_o { std::string tmp("'"); tmp.append(std::move($str1.value)); tmp.append("'"); tmp.append(std::move($str2.value)); - $chain.push_back(std::make_unique(std::move(tmp))); + $chain.push_back(std::make_unique(std::move(tmp))); }; l_string_no_space_u_c returns [concat_chain chain] @@ -241,7 +241,7 @@ l_string_no_space_c_o returns [std::string value] l_string_v_apo returns [concat_chain chain] : cl1=l_string_no_space_c_o cl2=l_string_no_space_v cl3=l_string_no_space_u_c { - $chain.push_back(std::make_unique(std::move($cl1.value))); + $chain.push_back(std::make_unique(std::move($cl1.value))); $chain.insert($chain.end(), std::make_move_iterator($cl2.chain.begin()), std::make_move_iterator($cl2.chain.end())); $chain.insert($chain.end(), std::make_move_iterator($cl3.chain.begin()), std::make_move_iterator($cl3.chain.end())); }; @@ -254,7 +254,7 @@ l_sp_ch returns [std::string value] //l_ch with SPACE | SPACE {$value = $SPACE->getText();}; l_sp_ch_v returns [concat_point_ptr point] : l_ch_v {$point = std::move($l_ch_v.point);} - | SPACE {$point = std::make_unique($SPACE->getText());}; + | SPACE {$point = std::make_unique($SPACE->getText());}; l_sp_str_v returns [concat_chain chain] : @@ -267,8 +267,8 @@ l_sp_string returns [std::string value] l_sp_string_v returns [concat_chain chain] : l_sp_string var_symbol l_sp_str_v { - $chain.push_back(std::make_unique(std::move($l_sp_string.value))); - $chain.push_back(std::move($var_symbol.vs)); + $chain.push_back(std::make_unique(std::move($l_sp_string.value))); + $chain.push_back(std::make_unique(std::move($var_symbol.vs))); $chain.insert($chain.end(), std::make_move_iterator($l_sp_str_v.chain.begin()), std::make_move_iterator($l_sp_str_v.chain.end())); }; @@ -285,13 +285,13 @@ l_string_poss_space_u returns [concat_chain chain] : l_apo l_sp_string l_apo { std::string tmp("'"); tmp.append(std::move($l_sp_string.value)); tmp.append("'"); - $chain.push_back(std::make_unique(std::move(tmp))); + $chain.push_back(std::make_unique(std::move(tmp))); } | l_apo l_sp_string_v l_apo { - $chain.push_back(std::make_unique("'")); + $chain.push_back(std::make_unique("'")); $chain.insert($chain.end(), std::make_move_iterator($l_sp_string_v.chain.begin()), std::make_move_iterator($l_sp_string_v.chain.end())); - $chain.push_back(std::make_unique("'")); + $chain.push_back(std::make_unique("'")); }; l_string_poss_space_u_c returns [concat_chain chain] @@ -306,8 +306,8 @@ l_string_v_apo_sp returns [concat_chain chain] : cl1=l_string_poss_space_c_o l_apo cl2=l_sp_string_v l_apo cl3=l_string_poss_space_u_c { $cl1.value.append("'"); - $cl2.chain.push_back(std::make_unique("'")); - $chain.push_back(std::make_unique(std::move($cl1.value))); + $cl2.chain.push_back(std::make_unique("'")); + $chain.push_back(std::make_unique(std::move($cl1.value))); $chain.insert($chain.end(), std::make_move_iterator($cl2.chain.begin()), std::make_move_iterator($cl2.chain.end())); $chain.insert($chain.end(), std::make_move_iterator($cl3.chain.begin()), std::make_move_iterator($cl3.chain.end())); }; diff --git a/parser_library/src/parsing/grammar/machine_expr_rules.g4 b/parser_library/src/parsing/grammar/machine_expr_rules.g4 index 8740ec6a2..a3ad7c1c6 100644 --- a/parser_library/src/parsing/grammar/machine_expr_rules.g4 +++ b/parser_library/src/parsing/grammar/machine_expr_rules.g4 @@ -16,32 +16,34 @@ parser grammar machine_expr_rules; mach_expr returns [mach_expr_ptr m_e] - : l=mach_expr plus r=mach_expr_s + : begin=mach_expr_s { - $m_e = std::make_unique>(std::move($l.m_e), std::move($r.m_e), provider.get_range( $l.ctx->getStart(), $r.ctx->getStop())); - } - | l=mach_expr minus r=mach_expr_s + $m_e = mach_expression::assign_expr(std::move($begin.m_e),provider.get_range($begin.ctx)); + } + ((plus|minus) next=mach_expr_s { - $m_e = std::make_unique>(std::move($l.m_e), std::move($r.m_e), provider.get_range( $l.ctx->getStart(), $r.ctx->getStop())); + if ($plus.ctx) + $m_e = std::make_unique>(std::move($m_e), std::move($next.m_e), provider.get_range( $begin.ctx->getStart(), $next.ctx->getStop())); + else + $m_e = std::make_unique>(std::move($m_e), std::move($next.m_e), provider.get_range( $begin.ctx->getStart(), $next.ctx->getStop())); + $plus.ctx = nullptr; } - | mach_expr_s - { - $m_e = mach_expression::assign_expr(std::move($mach_expr_s.m_e),provider.get_range($mach_expr_s.ctx)); - }; + )*; mach_expr_s returns [mach_expr_ptr m_e] - : mach_term_c + : begin=mach_term_c { - $m_e = std::move($mach_term_c.m_e); - } - | l=mach_expr_s slash r=mach_term_c + $m_e = std::move($begin.m_e); + } + ((slash|asterisk) next=mach_term_c { - $m_e = std::make_unique>(std::move($l.m_e), std::move($r.m_e), provider.get_range( $l.ctx->getStart(), $r.ctx->getStop())); + if ($slash.ctx) + $m_e = std::make_unique>(std::move($m_e), std::move($next.m_e), provider.get_range( $begin.ctx->getStart(), $next.ctx->getStop())); + else + $m_e = std::make_unique>(std::move($m_e), std::move($next.m_e), provider.get_range( $begin.ctx->getStart(), $next.ctx->getStop())); + $slash.ctx = nullptr; } - | l=mach_expr_s asterisk r=mach_term_c - { - $m_e = std::make_unique>(std::move($l.m_e), std::move($r.m_e), provider.get_range( $l.ctx->getStart(), $r.ctx->getStop())); - }; + )*; mach_term_c returns [mach_expr_ptr m_e] : mach_term @@ -95,17 +97,24 @@ mach_term returns [mach_expr_ptr m_e] literal - : equals_ data_def; + : equals data_def; mach_data_attribute returns [std::string attribute, id_index data = nullptr] : ORDSYMBOL ATTR literal | ORDSYMBOL ATTR ASTERISK | ORDSYMBOL ATTR id {$attribute = $ORDSYMBOL->getText(); $data = $id.name;}; -data_attribute returns [context::data_attr_kind attribute] - : ORDSYMBOL ATTR literal {$attribute = get_attribute($ORDSYMBOL->getText(), provider.get_range($ORDSYMBOL));} - | ORDSYMBOL ATTR var_symbol {$attribute = get_attribute($ORDSYMBOL->getText(), provider.get_range($ORDSYMBOL));} - | ORDSYMBOL ATTR id {$attribute = get_attribute($ORDSYMBOL->getText(), provider.get_range($ORDSYMBOL));}; +data_attribute returns [context::data_attr_kind attribute, std::variant value] + : ORDSYMBOL ATTR data_attribute_value + { + $attribute = get_attribute($ORDSYMBOL->getText(), provider.get_range($ORDSYMBOL)); + $value = std::move($data_attribute_value.value); + }; + +data_attribute_value returns [std::variant value] + : literal + | var_symbol {$value = std::move($var_symbol.vs);} + | id {$value = $id.name;}; string_ch returns [std::string value] @@ -114,7 +123,7 @@ string_ch returns [std::string value] string_ch_v returns [concat_point_ptr point] : l_sp_ch_v {$point=std::move($l_sp_ch_v.point);} - | (APOSTROPHE|ATTR) (APOSTROPHE|ATTR) {$point = std::make_unique("'");}; + | (APOSTROPHE|ATTR) (APOSTROPHE|ATTR) {$point = std::make_unique("'");}; string_ch_c returns [std::string value] : @@ -136,11 +145,11 @@ string returns [std::string value] string_v returns [concat_chain chain] : ap1=APOSTROPHE string_ch_v_c ap2=(APOSTROPHE|ATTR) { - $chain.push_back(std::make_unique("'")); + $chain.push_back(std::make_unique("'")); $chain.insert($chain.end(), std::make_move_iterator($string_ch_v_c.chain.begin()), std::make_move_iterator($string_ch_v_c.chain.end()) ); - $chain.push_back(std::make_unique("'")); + $chain.push_back(std::make_unique("'")); collector.add_hl_symbol(token_info(provider.get_range($ap1,$ap2),hl_scopes::string)); }; diff --git a/parser_library/src/parsing/grammar/macro_operand_rules.g4 b/parser_library/src/parsing/grammar/macro_operand_rules.g4 index 456f33d4b..ba7cadc96 100644 --- a/parser_library/src/parsing/grammar/macro_operand_rules.g4 +++ b/parser_library/src/parsing/grammar/macro_operand_rules.g4 @@ -45,12 +45,12 @@ mac_preproc_c | LT | GT | slash - | equals_ + | equals | VERTICAL | IDENTIFIER {collector.add_hl_symbol(token_info(provider.get_range($IDENTIFIER), hl_scopes::operand));} | NUM {collector.add_hl_symbol(token_info(provider.get_range($NUM), hl_scopes::operand));} | ORDSYMBOL {collector.add_hl_symbol(token_info(provider.get_range($ORDSYMBOL), hl_scopes::operand));} - | dot_ + | dot | AMPERSAND ORDSYMBOL { auto r = provider.get_range($AMPERSAND,$ORDSYMBOL); @@ -66,10 +66,10 @@ mac_preproc_c mac_str_ch returns [concat_point_ptr point] : common_ch_v {$point = std::move($common_ch_v.point);} - | SPACE {$point = std::make_unique($SPACE->getText());}//here next are for deferred - | LPAR {$point = std::make_unique("(");} - | RPAR {$point = std::make_unique(")");} - | COMMA {$point = std::make_unique(",");}; + | SPACE {$point = std::make_unique($SPACE->getText());}//here next are for deferred + | LPAR {$point = std::make_unique("(");} + | RPAR {$point = std::make_unique(")");} + | COMMA {$point = std::make_unique(",");}; mac_str_b returns [concat_chain chain] : @@ -78,9 +78,9 @@ mac_str_b returns [concat_chain chain] mac_str returns [concat_chain chain] : ap1=APOSTROPHE mac_str_b ap2=(APOSTROPHE|ATTR) { - $chain.push_back(std::make_unique("'")); + $chain.push_back(std::make_unique("'")); $chain.insert($chain.end(), std::make_move_iterator($mac_str_b.chain.begin()), std::make_move_iterator($mac_str_b.chain.end())); - $chain.push_back(std::make_unique("'")); + $chain.push_back(std::make_unique("'")); collector.add_hl_symbol(token_info(provider.get_range($ap1,$ap2),hl_scopes::string)); }; @@ -90,7 +90,7 @@ mac_ch returns [concat_chain chain] if (token->getType() == lexing::lexer::Tokens::ORDSYMBOL && $common_ch_v.ctx->getStop()->getType() == lexing::lexer::Tokens::ORDSYMBOL) collector.add_lsp_symbol(ctx->ids().add(token->getText()),provider.get_range(token),symbol_type::ord); ;} - | ATTR {$chain.push_back(std::make_unique("'"));} + | ATTR {$chain.push_back(std::make_unique("'"));} | mac_str {$chain = std::move($mac_str.chain);} | mac_sublist {$chain.push_back(std::move($mac_sublist.point));}; @@ -104,13 +104,13 @@ mac_ch_c returns [concat_chain chain] mac_entry returns [concat_chain chain] : mac_ch {$chain = std::move($mac_ch.chain);} - | literal {$chain.push_back(std::make_unique($literal.ctx->getText()));} + | literal {$chain.push_back(std::make_unique($literal.ctx->getText()));} | ORDSYMBOL EQUALS literal { collector.add_hl_symbol(token_info(provider.get_range($ORDSYMBOL), hl_scopes::operand)); - $chain.push_back(std::make_unique($ORDSYMBOL->getText())); - $chain.push_back(std::make_unique("=")); - $chain.push_back(std::make_unique($literal.ctx->getText())); + $chain.push_back(std::make_unique($ORDSYMBOL->getText())); + $chain.push_back(std::make_unique("=")); + $chain.push_back(std::make_unique($literal.ctx->getText())); } | tmp=mac_entry mac_ch { @@ -120,7 +120,7 @@ mac_entry returns [concat_chain chain] mac_sublist_b_c returns [concat_chain chain] : mac_ch_c {$chain = std::move($mac_ch_c.chain);} - | literal {$chain.push_back(std::make_unique($literal.ctx->getText()));}; + | literal {$chain.push_back(std::make_unique($literal.ctx->getText()));}; mac_sublist_b returns [std::vector chains] : mac_sublist_b_c {$chains.push_back(std::move($mac_sublist_b_c.chain));} @@ -131,4 +131,4 @@ mac_sublist_b returns [std::vector chains] }; mac_sublist returns [concat_point_ptr point] - : lpar mac_sublist_b rpar { $point = std::make_unique(std::move($mac_sublist_b.chains)); }; \ No newline at end of file + : lpar mac_sublist_b rpar { $point = std::make_unique(std::move($mac_sublist_b.chains)); }; \ No newline at end of file diff --git a/parser_library/src/parsing/grammar/model_operand_rules.g4 b/parser_library/src/parsing/grammar/model_operand_rules.g4 index 3981e1122..199b6c83f 100644 --- a/parser_library/src/parsing/grammar/model_operand_rules.g4 +++ b/parser_library/src/parsing/grammar/model_operand_rules.g4 @@ -29,10 +29,10 @@ op_ch_c returns [std::string value] op_ch_v returns [concat_point_ptr point] : common_ch_v {$point = std::move($common_ch_v.point);} - | lpar {$point = std::make_unique("("); } - | rpar {$point = std::make_unique(")"); } - | comma {$point = std::make_unique(","); } - | ATTR {$point = std::make_unique("'"); }; + | lpar {$point = std::make_unique("("); } + | rpar {$point = std::make_unique(")"); } + | comma {$point = std::make_unique(","); } + | ATTR {$point = std::make_unique("'"); }; op_ch_v_c returns [concat_chain chain] : @@ -54,7 +54,7 @@ before_var_sym_model returns [std::string value] | tmp=before_var_sym_model before_var_sym_model_b {$tmp.value.append(std::move($before_var_sym_model_b.value)); $value = std::move($tmp.value);}; var_sym_model returns [concat_chain chain] - : var_symbol {$chain.push_back(std::move($var_symbol.vs));} + : var_symbol {$chain.push_back(std::make_unique(std::move($var_symbol.vs)));} | string_v_actual {$chain = std::move($string_v_actual.chain);}; after_var_sym_model_b returns [concat_chain chain] @@ -78,7 +78,7 @@ model_op returns [std::optional chain_opt] else { concat_chain chain; - chain.push_back(std::make_unique(std::move($before_var_sym_model.value))); + chain.push_back(std::make_unique(std::move($before_var_sym_model.value))); chain.insert(chain.end(), std::make_move_iterator($var_sym_model.chain.begin()), std::make_move_iterator($var_sym_model.chain.end()) @@ -97,7 +97,7 @@ model_string_ch returns [std::string value] model_string_ch_v returns [concat_point_ptr point] : l_sp_ch_v {$point = std::move($l_sp_ch_v.point);} - | (APOSTROPHE|ATTR) (APOSTROPHE|ATTR) {$point = std::make_unique("''");}; + | (APOSTROPHE|ATTR) (APOSTROPHE|ATTR) {$point = std::make_unique("''");}; model_string_ch_v_c returns [concat_chain chain] : @@ -110,25 +110,25 @@ model_string_ch_c returns [std::string value] string_v_actual returns [concat_chain chain] : ap1=(APOSTROPHE|ATTR) model_string_ch_c var_symbol model_string_ch_v_c ap2=(APOSTROPHE|ATTR) { - $chain.push_back(std::make_unique("'")); - $chain.push_back(std::make_unique(std::move($model_string_ch_c.value))); - $chain.push_back(std::move($var_symbol.vs)); + $chain.push_back(std::make_unique("'")); + $chain.push_back(std::make_unique(std::move($model_string_ch_c.value))); + $chain.push_back(std::make_unique(std::move($var_symbol.vs))); $chain.insert($chain.end(), std::make_move_iterator($model_string_ch_v_c.chain.begin()), std::make_move_iterator($model_string_ch_v_c.chain.end()) ); - $chain.push_back(std::make_unique("'")); + $chain.push_back(std::make_unique("'")); collector.add_hl_symbol(token_info(provider.get_range($ap1,$ap2),hl_scopes::string)); }; model_string_v returns [concat_chain chain] : ap1=(APOSTROPHE|ATTR) string_ch_v_c ap2=(APOSTROPHE|ATTR) { - $chain.push_back(std::make_unique("'")); + $chain.push_back(std::make_unique("'")); $chain.insert($chain.end(), std::make_move_iterator($string_ch_v_c.chain.begin()), std::make_move_iterator($string_ch_v_c.chain.end()) ); - $chain.push_back(std::make_unique("'")); + $chain.push_back(std::make_unique("'")); collector.add_hl_symbol(token_info(provider.get_range($ap1,$ap2),hl_scopes::string)); }; \ No newline at end of file diff --git a/parser_library/src/parsing/parser_impl.cpp b/parser_library/src/parsing/parser_impl.cpp index 0c96e125d..02ecfa270 100644 --- a/parser_library/src/parsing/parser_impl.cpp +++ b/parser_library/src/parsing/parser_impl.cpp @@ -17,19 +17,18 @@ #include #include "error_strategy.h" -#include "expressions/arithmetic_expression.h" +#include "expressions/conditional_assembly/terms/ca_constant.h" #include "hlasmparser.h" #include "lexing/token_stream.h" #include "parser_error_listener_ctx.h" #include "processing/context_manager.h" #include "processing/statement.h" -using namespace hlasm_plugin::parser_library; -using namespace hlasm_plugin::parser_library::lexing; -using namespace hlasm_plugin::parser_library::parsing; +namespace hlasm_plugin::parser_library::parsing { parser_impl::parser_impl(antlr4::TokenStream* input) : Parser(input) + , input(dynamic_cast(*input)) , ctx(nullptr) , lsp_proc(nullptr) , processor(nullptr) @@ -48,15 +47,17 @@ void parser_impl::initialize(context::hlasm_context* hlasm_ctx, semantics::lsp_i pushed_state_ = false; } -bool parser_impl::is_last_line() { return dynamic_cast(*_input->getTokenSource()).is_last_line(); } +bool parser_impl::is_last_line() const +{ + return dynamic_cast(*_input->getTokenSource()).is_last_line(); +} void parser_impl::rewind_input(context::source_position pos) { finished_flag = false; last_line_processed_ = false; _matchedEOF = false; - dynamic_cast(*_input).rewind_input( - lexer::stream_position { pos.file_line, pos.file_offset }, line_end_pushed_); + input.rewind_input(lexing::lexer::stream_position { pos.file_line, pos.file_offset }, line_end_pushed_); line_end_pushed_ = false; } @@ -64,16 +65,26 @@ void parser_impl::push_line_end() { line_end_pushed_ = true; } context::source_position parser_impl::statement_start() const { - auto pos = dynamic_cast(*_input->getTokenSource()).last_lln_begin_position(); + auto pos = dynamic_cast(*_input->getTokenSource()).last_lln_begin_position(); return { pos.line, pos.offset }; } context::source_position parser_impl::statement_end() const { - auto pos = dynamic_cast(*_input->getTokenSource()).last_lln_end_position(); + auto pos = dynamic_cast(*_input->getTokenSource()).last_lln_end_position(); return { pos.line, pos.offset }; } +std::unique_ptr create_parser_holder() +{ + std::string s; + auto h = std::make_unique(); + h->input = std::make_unique(s); + h->lex = std::make_unique(h->input.get(), nullptr); + h->stream = std::make_unique(h->lex.get()); + h->parser = std::make_unique(h->stream.get()); + return h; +} std::pair parser_impl::parse_operand_field( context::hlasm_context* hlasm_ctx, @@ -83,14 +94,7 @@ std::pair parser_impl::parse_oper processing::processing_status status) { if (!reparser_) - { - std::string s; - reparser_ = std::make_unique(); - reparser_->input = std::make_unique(s); - reparser_->lex = std::make_unique(reparser_->input.get(), nullptr); - reparser_->stream = std::make_unique(reparser_->lex.get()); - reparser_->parser = std::make_unique(reparser_->stream.get()); - } + reparser_ = create_parser_holder(); hlasm_ctx->metrics.reparsed_statements++; parser_holder& h = *reparser_; @@ -100,13 +104,13 @@ std::pair parser_impl::parse_oper sub = field; parser_error_listener_ctx listener(*hlasm_ctx, std::move(sub)); - h.input->append(field); + h.input->reset(field); - h.lex->append(); + h.lex->reset(); h.lex->set_file_offset(field_range.original_range.start); h.lex->set_unlimited_line(after_substitution); - h.stream->append(); + h.stream->reset(); h.parser->initialize(hlasm_ctx, field_range, status); h.parser->setErrorHandler(std::make_shared()); @@ -120,7 +124,7 @@ std::pair parser_impl::parse_oper ctx->ids().add(ctx->processing_stack().back().proc_location.file, true)); } - // h.parser->append(); + h.parser->reset(); h.parser->_matchedEOF = false; h.parser->collector.prepare_for_next_statement(); @@ -187,13 +191,13 @@ void parser_impl::collect_diags() const -void parser_impl::enable_continuation() { dynamic_cast(*_input).enable_continuation(); } +void parser_impl::enable_continuation() { input.enable_continuation(); } -void parser_impl::disable_continuation() { dynamic_cast(*_input).disable_continuation(); } +void parser_impl::disable_continuation() { input.disable_continuation(); } -void parser_impl::enable_hidden() { dynamic_cast(*_input).enable_hidden(); } +void parser_impl::enable_hidden() { input.enable_hidden(); } -void parser_impl::disable_hidden() { dynamic_cast(*_input).disable_hidden(); } +void parser_impl::disable_hidden() { input.disable_hidden(); } bool parser_impl::is_self_def() { @@ -219,16 +223,12 @@ 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) { - auto ae = expressions::arithmetic_expression::from_string(option, value, false); // could generate diagnostic + DBCS - if (ae->has_error()) - { - ae->diag->diag_range = term_range; - add_diagnostic(diagnostic_s(ctx->opencode_file_name(), *ae->diag)); - } - else - return ae->get_numeric_value(); + diagnostic_adder add_diagnostic(this, term_range); + auto val = expressions::ca_constant::self_defining_term(option, value, add_diagnostic); - return 0; + if (add_diagnostic.diagnostics_present) + diags().back().file_name = ctx->processing_stack().back().proc_location.file; + return val; } context::data_attr_kind parser_impl::get_attribute(std::string attr_data, range data_range) @@ -281,6 +281,42 @@ void parser_impl::parse_macro_operands(semantics::op_rem& line) } } +void parser_impl::resolve_expression(expressions::ca_expr_ptr& expr, context::SET_t_enum type) const +{ + expr->resolve_expression_tree(type); + expr->collect_diags(); + for (auto& d : expr->diags()) + add_diagnostic(diagnostic_s(ctx->processing_stack().back().proc_location.file, std::move(d))); + expr->diags().clear(); +} + +void parser_impl::resolve_expression(std::vector& expr_list, context::SET_t_enum type) const +{ + for (auto& expr : expr_list) + resolve_expression(expr, type); +} + +void parser_impl::resolve_expression(expressions::ca_expr_ptr& expr) const +{ + auto [_, opcode] = *proc_status; + if (opcode.value == ctx->ids().add("SETA") || opcode.value == ctx->ids().add("ACTR") + || opcode.value == ctx->ids().add("ASPACE") || opcode.value == ctx->ids().add("AGO")) + resolve_expression(expr, context::SET_t_enum::A_TYPE); + else if (opcode.value == ctx->ids().add("SETB") || opcode.value == ctx->ids().add("AIF")) + resolve_expression(expr, context::SET_t_enum::B_TYPE); + else if (opcode.value == ctx->ids().add("SETC")) + resolve_expression(expr, context::SET_t_enum::C_TYPE); + else if (opcode.value == ctx->ids().add("AREAD")) + { + // aread operand is just enumeration + } + else + { + assert(false); + resolve_expression(expr, context::SET_t_enum::UNDEF_TYPE); + } +} + void parser_impl::process_instruction() { ctx->set_source_position(collector.current_instruction().field_range.start); @@ -467,14 +503,7 @@ semantics::operand_list parser_impl::parse_macro_operands( std::string operands, range field_range, std::vector operand_ranges) { if (!reparser_) - { - std::string s; - reparser_ = std::make_unique(); - reparser_->input = std::make_unique(s); - reparser_->lex = std::make_unique(reparser_->input.get(), nullptr); - reparser_->stream = std::make_unique(reparser_->lex.get()); - reparser_->parser = std::make_unique(reparser_->stream.get()); - } + reparser_ = create_parser_holder(); parser_holder& h = *reparser_; @@ -482,20 +511,20 @@ semantics::operand_list parser_impl::parse_macro_operands( parser_error_listener_ctx listener(*ctx, std::nullopt, tmp_provider); - h.input->append(operands); + h.input->reset(operands); - h.lex->append(); + h.lex->reset(); h.lex->set_file_offset(field_range.start); h.lex->set_unlimited_line(true); - h.stream->append(); + h.stream->reset(); h.parser->initialize(ctx, tmp_provider, *proc_status); h.parser->setErrorHandler(std::make_shared()); h.parser->removeErrorListeners(); h.parser->addErrorListener(&listener); - // h.parser->reset(); + h.parser->reset(); h.parser->_matchedEOF = false; h.parser->collector.prepare_for_next_statement(); @@ -508,40 +537,31 @@ semantics::operand_list parser_impl::parse_macro_operands( collect_diags_from_child(listener); - // parsers_.emplace_back(std::move(h)); - return list; } void parser_impl::parse_rest(std::string text, range text_range) { if (!rest_parser_) - { - std::string s; - rest_parser_ = std::make_unique(); - rest_parser_->input = std::make_unique(s); - rest_parser_->lex = std::make_unique(rest_parser_->input.get(), nullptr); - rest_parser_->stream = std::make_unique(rest_parser_->lex.get()); - rest_parser_->parser = std::make_unique(rest_parser_->stream.get()); - } + rest_parser_ = create_parser_holder(); parser_holder& h = *rest_parser_; parser_error_listener_ctx listener(*ctx, std::nullopt); - h.input->append(text); + h.input->reset(text); - h.lex->append(); + h.lex->reset(); h.lex->set_file_offset(text_range.start); - h.stream->append(); + h.stream->reset(); h.parser->initialize(this); h.parser->setErrorHandler(std::make_shared()); h.parser->removeErrorListeners(); h.parser->addErrorListener(&listener); - // h.parser->reset(); + h.parser->reset(); h.parser->_matchedEOF = false; h.parser->collector.prepare_for_next_statement(); @@ -583,21 +603,12 @@ void parser_impl::parse_rest(std::string text, range text_range) collect_diags_from_child(listener); collector.append_operand_field(std::move(h.parser->collector)); - - // parsers_.emplace_back(std::move(h)); } void parser_impl::parse_lookahead(std::string text, range text_range) { if (!reparser_) - { - std::string s; - reparser_ = std::make_unique(); - reparser_->input = std::make_unique(s); - reparser_->lex = std::make_unique(reparser_->input.get(), nullptr); - reparser_->stream = std::make_unique(reparser_->lex.get()); - reparser_->parser = std::make_unique(reparser_->stream.get()); - } + reparser_ = create_parser_holder(); if (proc_status->first.form == processing::processing_form::IGNORED) { @@ -623,20 +634,20 @@ void parser_impl::parse_lookahead(std::string text, range text_range) parser_error_listener_ctx listener(*ctx, std::nullopt); - h.input->append(text); + h.input->reset(text); - h.lex->append(); + h.lex->reset(); h.lex->set_file_offset(text_range.start); h.lex->set_unlimited_line(true); - h.stream->append(); + h.stream->reset(); h.parser->initialize(this); h.parser->setErrorHandler(std::make_shared()); h.parser->removeErrorListeners(); h.parser->addErrorListener(&listener); - // h.parser->append(); + h.parser->reset(); h.parser->_matchedEOF = false; h.parser->collector.prepare_for_next_statement(); @@ -657,3 +668,5 @@ antlr4::misc::IntervalSet parser_impl::getExpectedTokens() } parser_holder::~parser_holder() {} + +} // namespace hlasm_plugin::parser_library::parsing \ No newline at end of file diff --git a/parser_library/src/parsing/parser_impl.h b/parser_library/src/parsing/parser_impl.h index 20b109672..2d4fe33b2 100644 --- a/parser_library/src/parsing/parser_impl.h +++ b/parser_library/src/parsing/parser_impl.h @@ -53,7 +53,7 @@ class parser_impl : public antlr4::Parser, void initialize(context::hlasm_context* hlasm_ctx, semantics::lsp_info_processor* lsp_prc); - bool is_last_line(); + bool is_last_line() const; virtual void rewind_input(context::source_position pos) override; virtual void push_line_end() override; context::source_position statement_start() const; @@ -81,6 +81,10 @@ class parser_impl : public antlr4::Parser, context::id_index parse_identifier(std::string value, range id_range); void parse_macro_operands(semantics::op_rem& line); + void resolve_expression(expressions::ca_expr_ptr& expr, context::SET_t_enum type) const; + void resolve_expression(std::vector& expr, context::SET_t_enum type) const; + void resolve_expression(expressions::ca_expr_ptr& expr) const; + void process_instruction(); void process_statement(); void process_statement(semantics::op_rem line, range op_range); @@ -88,6 +92,7 @@ class parser_impl : public antlr4::Parser, virtual void process_next(processing::statement_processor& processor) override; virtual bool finished() const override; + lexing::token_stream& input; context::hlasm_context* ctx; semantics::lsp_info_processor* lsp_proc; processing::statement_processor* processor; diff --git a/parser_library/src/processing/context_manager.cpp b/parser_library/src/processing/context_manager.cpp index 9d27d1f13..0622e2dce 100644 --- a/parser_library/src/processing/context_manager.cpp +++ b/parser_library/src/processing/context_manager.cpp @@ -15,149 +15,24 @@ #include "context_manager.h" #include "context/variables/system_variable.h" -#include "expressions/visitors/expression_evaluator.h" #include "lexing/lexer.h" -using namespace hlasm_plugin::parser_library; -using namespace hlasm_plugin::parser_library::processing; +namespace hlasm_plugin::parser_library::processing { context_manager::context_manager(context::hlasm_context& hlasm_ctx) : diagnosable_ctx(hlasm_ctx) + , eval_ctx_(nullptr) , hlasm_ctx(hlasm_ctx) {} -context::SET_t context_manager::evaluate_expression( - antlr4::ParserRuleContext* expr_context, expressions::evaluation_context eval_ctx) const -{ - expressions::expression_evaluator evaluator(eval_ctx); - - auto result = evaluator.evaluate_expression(expr_context); - - collect_diags_from_child(evaluator); - - return result->get_set_value(); -} - -context::SET_t context_manager::convert(context::SET_t source, context::SET_t_enum target_type, range value_range) const -{ - expressions::expr_ptr tmp_e; - using namespace context; - switch (target_type) - { - case SET_t_enum::A_TYPE: - switch (source.type) - { - case SET_t_enum::A_TYPE: - return source.access_a(); - case SET_t_enum::B_TYPE: - return (int)source.access_b(); - case SET_t_enum::C_TYPE: - tmp_e = expressions::arithmetic_expression::from_string(source.access_c(), false); - if (!tmp_e->diag) - return tmp_e->get_numeric_value(); - break; - default: - break; - } - break; - case SET_t_enum::B_TYPE: - switch (source.type) - { - case SET_t_enum::A_TYPE: - return (bool)source.access_a(); - case SET_t_enum::B_TYPE: - return source.access_b(); - case SET_t_enum::C_TYPE: - tmp_e = expressions::arithmetic_expression::from_string(source.access_c(), false); - if (!tmp_e->diag) - return tmp_e->get_numeric_value(); - break; - default: - break; - } - break; - case context::SET_t_enum::C_TYPE: - switch (source.type) - { - case SET_t_enum::A_TYPE: - return std::to_string(std::abs(source.access_a())); - case SET_t_enum::B_TYPE: - return source.access_b() ? std::string("1") : std::string("0"); - case SET_t_enum::C_TYPE: - return std::move(source.access_c()); - default: - break; - } - break; - default: - break; - } - - auto diag = error_messages::e001(); - diag->diag_range = value_range; - add_diagnostic(std::move(*diag)); - return SET_t(); -} - -context::id_index context_manager::concatenate( - const semantics::concat_chain& chain, expressions::evaluation_context eval_ctx) const -{ - return hlasm_ctx.ids().add(concatenate_str(chain, eval_ctx)); -} - -std::string context_manager::concatenate_str( - const semantics::concat_chain& chain, expressions::evaluation_context eval_ctx) const -{ - expressions::expression_evaluator evaluator(eval_ctx); - - auto result = evaluator.concatenate_chain(chain); - - collect_diags_from_child(evaluator); - - return result; -} - -context::macro_data_ptr context_manager::create_macro_data(const semantics::concat_chain& chain) const -{ - auto tmp = semantics::concatenation_point::contains_var_sym(chain); - if (tmp) - { - add_diagnostic(diagnostic_op::error_E064(tmp->symbol_range)); - return std::make_unique(); - } - - return create_macro_data(chain, semantics::concatenation_point::to_string); -} - -context::macro_data_ptr context_manager::create_macro_data( - const semantics::concat_chain& chain, expressions::evaluation_context eval_ctx) const -{ - expressions::expression_evaluator evaluator(eval_ctx); - - auto data = create_macro_data(chain, [&](const auto& chain) { return evaluator.concatenate_chain(chain); }); - - collect_diags_from_child(evaluator); - - return data; -} - -context::SET_t context_manager::get_var_sym_value( - const semantics::var_sym& symbol, expressions::evaluation_context eval_ctx) const -{ - auto id = - symbol.created ? concatenate(symbol.access_created()->created_name, eval_ctx) : symbol.access_basic()->name; - - expressions::expression_evaluator evaluator(eval_ctx); - - auto subscript = evaluator.evaluate_expressions(symbol.subscript); - - collect_diags_from_child(evaluator); - - return get_var_sym_value(id, subscript, symbol.symbol_range); -} +context_manager::context_manager(const expressions::evaluation_context* eval_ctx) + : diagnosable_ctx(eval_ctx->hlasm_ctx) + , eval_ctx_(eval_ctx) + , hlasm_ctx(eval_ctx->hlasm_ctx) +{} context::SET_t context_manager::get_var_sym_value( - context::id_index name, const expressions::expr_list& subscript, const range& symbol_range) const + context::id_index name, const std::vector& subscript, range symbol_range) const { auto var = hlasm_ctx.get_var_sym(name); @@ -176,62 +51,52 @@ context::SET_t context_manager::get_var_sym_value( { case context::SET_t_enum::A_TYPE: return set_sym->access_set_symbol()->get_value(); - break; case context::SET_t_enum::B_TYPE: return set_sym->access_set_symbol()->get_value(); - break; case context::SET_t_enum::C_TYPE: return set_sym->access_set_symbol()->get_value(); - break; default: return context::SET_t(); - break; } } else { - idx = (size_t)(subscript[0] ? subscript[0]->get_numeric_value() - 1 : 0); + idx = (size_t)(subscript.front() - 1); switch (set_sym->type) { case context::SET_t_enum::A_TYPE: return set_sym->access_set_symbol()->get_value(idx); - break; case context::SET_t_enum::B_TYPE: return set_sym->access_set_symbol()->get_value(idx); - break; case context::SET_t_enum::C_TYPE: return set_sym->access_set_symbol()->get_value(idx); - break; default: return context::SET_t(); - break; } } } else if (auto mac_par = var->access_macro_param_base()) { std::vector tmp; - for (auto& e : subscript) + for (auto& v : subscript) { - tmp.push_back((size_t)e->get_numeric_value()); + tmp.push_back((size_t)v); } return mac_par->get_value(tmp); } return context::SET_t(); } -context_manager::name_result context_manager::try_get_symbol_name( - const semantics::var_sym* symbol, expressions::evaluation_context eval_ctx) const +context::id_index context_manager::get_symbol_name(const std::string& symbol, range symbol_range) const { - if (!symbol->created) - return make_pair(true, symbol->access_basic()->name); - else - return try_get_symbol_name( - concatenate_str(symbol->access_created()->created_name, eval_ctx), symbol->symbol_range); + auto tmp = try_get_symbol_name(symbol); + if (!tmp.first) + add_diagnostic(diagnostic_op::error_E065(symbol_range)); + return tmp.second; } -context_manager::name_result context_manager::try_get_symbol_name(const std::string& symbol, range symbol_range) const +context_manager::name_result context_manager::try_get_symbol_name(const std::string& symbol) const { size_t i; for (i = 0; i < symbol.size(); ++i) @@ -239,16 +104,12 @@ context_manager::name_result context_manager::try_get_symbol_name(const std::str break; if (i == 0 || i > 63) - { - add_diagnostic(diagnostic_op::error_E065(symbol_range)); return std::make_pair(false, context::id_storage::empty_id); - } - return std::make_pair(true, hlasm_ctx.ids().add(symbol.substr(0, i))); } bool context_manager::test_symbol_for_read( - context::var_sym_ptr var, const expressions::expr_list& subscript, const range& symbol_range) const + const context::var_sym_ptr& var, const std::vector& subscript, range symbol_range) const { if (!var) { @@ -272,7 +133,7 @@ bool context_manager::test_symbol_for_read( return false; } - if (!set_sym->is_scalar && (!subscript[0] || subscript[0]->get_numeric_value() < 1)) + if (!set_sym->is_scalar && (subscript.front() < 1)) { add_diagnostic(diagnostic_op::error_E012( "subscript value has to be 1 or more", symbol_range)); // error - subscript is less than 1 @@ -283,11 +144,10 @@ bool context_manager::test_symbol_for_read( { for (size_t i = 0; i < subscript.size(); ++i) { - auto& e = subscript[i]; - if (!e || e->get_numeric_value() < 1) + if (subscript[i] < 1) { - if (i == 0 && e && e->get_numeric_value() == 0 - && dynamic_cast(mac_par)) // if syslist and subscript = 0, ok + // if syslist and subscript = 0, ok + if (i == 0 && subscript[i] == 0 && dynamic_cast(mac_par)) continue; add_diagnostic(diagnostic_op::error_E012( @@ -302,23 +162,12 @@ bool context_manager::test_symbol_for_read( void context_manager::collect_diags() const {} -context::macro_data_ptr context_manager::create_macro_data(const semantics::concat_chain& chain, - const std::function& to_string) const +void context_manager::add_diagnostic(diagnostic_s diagnostic) const { - context_manager mngr(hlasm_ctx); - - if (chain.size() == 0) - return std::make_unique(); - else if (chain.size() > 1 || (chain.size() == 1 && chain[0]->type != semantics::concat_type::SUB)) - return std::make_unique(to_string(chain)); - - const auto& inner_chains = chain[0]->access_sub()->list; - - std::vector sublist; - - for (auto& inner_chain : inner_chains) - { - sublist.push_back(create_macro_data(inner_chain, to_string)); - } - return std::make_unique(std::move(sublist)); + if (eval_ctx_) + eval_ctx_->add_diagnostic(std::move(diagnostic)); + else + diagnosable_ctx::add_diagnostic(std::move(diagnostic)); } + +} // namespace hlasm_plugin::parser_library::processing diff --git a/parser_library/src/processing/context_manager.h b/parser_library/src/processing/context_manager.h index 0c3dddcaa..fee85ebf5 100644 --- a/parser_library/src/processing/context_manager.h +++ b/parser_library/src/processing/context_manager.h @@ -15,12 +15,9 @@ #ifndef PROCESSING_CONTEXT_MANAGER_H #define PROCESSING_CONTEXT_MANAGER_H -#include "antlr4-runtime.h" - #include "context/hlasm_context.h" #include "diagnosable_ctx.h" #include "expressions/evaluation_context.h" -#include "expressions/expression.h" #include "processing_format.h" #include "semantics/range_provider.h" #include "workspaces/parse_lib_provider.h" @@ -31,59 +28,30 @@ namespace hlasm_plugin::parser_library::processing { // class wrapping context providing ranges, checks and diagnostics to hlasm_context class context_manager : public diagnosable_ctx { + const expressions::evaluation_context* eval_ctx_; + public: using name_result = std::pair; // wrapped context context::hlasm_context& hlasm_ctx; - context_manager(context::hlasm_context& hlasm_ctx); - - context::SET_t evaluate_expression( - antlr4::ParserRuleContext* expr_context, expressions::evaluation_context eval_ctx) const; - template - T evaluate_expression_to(antlr4::ParserRuleContext* expr_context, expressions::evaluation_context eval_ctx) const - { - return convert_to( - evaluate_expression(expr_context, eval_ctx), semantics::range_provider().get_range(expr_context)); - } - - context::SET_t convert(context::SET_t source, context::SET_t_enum target_type, range value_range) const; - template - T convert_to(context::SET_t source, range value_range) const - { - auto tmp = convert(std::move(source), context::object_traits::type_enum, value_range); + explicit context_manager(context::hlasm_context& hlasm_ctx); + explicit context_manager(const expressions::evaluation_context* eval_ctx); - if constexpr (std::is_same_v) - return tmp.access_a(); - if constexpr (std::is_same_v) - return tmp.access_b(); - if constexpr (std::is_same_v) - return std::move(tmp.access_c()); - } - - context::SET_t get_var_sym_value(const semantics::var_sym& symbol, expressions::evaluation_context eval_ctx) const; context::SET_t get_var_sym_value( - context::id_index name, const expressions::expr_list& subscript, const range& symbol_range) const; - - name_result try_get_symbol_name(const semantics::var_sym* symbol, expressions::evaluation_context eval_ctx) const; - name_result try_get_symbol_name(const std::string& symbol, range symbol_range) const; - - context::id_index concatenate(const semantics::concat_chain& chain, expressions::evaluation_context eval_ctx) const; - std::string concatenate_str(const semantics::concat_chain& chain, expressions::evaluation_context eval_ctx) const; + context::id_index name, const std::vector& subscript, range symbol_range) const; - context::macro_data_ptr create_macro_data(const semantics::concat_chain& chain) const; - context::macro_data_ptr create_macro_data( - const semantics::concat_chain& chain, expressions::evaluation_context eval_ctx) const; + context::id_index get_symbol_name(const std::string& symbol, range symbol_range) const; + name_result try_get_symbol_name(const std::string& symbol) const; bool test_symbol_for_read( - context::var_sym_ptr var, const expressions::expr_list& subscript, const range& symbol_range) const; + const context::var_sym_ptr& var, const std::vector& subscript, range symbol_range) const; virtual void collect_diags() const override; private: - context::macro_data_ptr create_macro_data(const semantics::concat_chain& chain, - const std::function& to_string) const; + virtual void add_diagnostic(diagnostic_s diagnostic) const override; }; } // namespace hlasm_plugin::parser_library::processing diff --git a/parser_library/src/processing/instruction_sets/ca_processor.cpp b/parser_library/src/processing/instruction_sets/ca_processor.cpp index 1ca52c12d..250dc773f 100644 --- a/parser_library/src/processing/instruction_sets/ca_processor.cpp +++ b/parser_library/src/processing/instruction_sets/ca_processor.cpp @@ -27,7 +27,6 @@ ca_processor::ca_processor(context::hlasm_context& hlasm_ctx, processing_state_listener& listener) : instruction_processor(hlasm_ctx, attr_provider, branch_provider, lib_provider) , table_(create_table(hlasm_ctx)) - , mngr_(hlasm_ctx) , listener_(listener) {} @@ -84,7 +83,7 @@ void ca_processor::register_seq_sym(const semantics::complete_statement& stmt) } } -bool ca_processor::test_symbol_for_assignment(const semantics::var_sym* symbol, +bool ca_processor::test_symbol_for_assignment(const semantics::variable_symbol* symbol, context::SET_t_enum type, int& idx, context::set_symbol_base*& set_symbol, @@ -93,10 +92,10 @@ bool ca_processor::test_symbol_for_assignment(const semantics::var_sym* symbol, set_symbol = nullptr; idx = -1; - name = symbol->created ? mngr_.concatenate(symbol->access_created()->created_name, eval_ctx) - : symbol->access_basic()->name; + auto [tmp_name, subscript] = symbol->evaluate_symbol(eval_ctx); + name = tmp_name; - auto var_symbol = mngr_.hlasm_ctx.get_var_sym(name); + auto var_symbol = hlasm_ctx.get_var_sym(name); if (var_symbol && var_symbol->access_macro_param_base()) { @@ -104,16 +103,16 @@ bool ca_processor::test_symbol_for_assignment(const semantics::var_sym* symbol, return false; } - if (symbol->subscript.size() > 1) + if (subscript.size() > 1) { add_diagnostic(diagnostic_op::error_E020("variable symbol subscript", symbol->symbol_range)); return false; } - else if (symbol->subscript.size() == 1) + else if (subscript.size() == 1) { - idx = mngr_.evaluate_expression_to(symbol->subscript[0], eval_ctx); + idx = symbol->subscript.front()->evaluate(eval_ctx); - if (idx < 1) + if (subscript.front() < 1) { add_diagnostic(diagnostic_op::error_E012("subscript value has to be 1 or more", symbol->symbol_range)); return false; @@ -161,7 +160,7 @@ bool ca_processor::prepare_SET_symbol(const semantics::complete_statement& stmt, } bool ca_processor::prepare_SET_operands( - const semantics::complete_statement& stmt, std::vector& values, std::vector& ranges) + const semantics::complete_statement& stmt, std::vector& expr_values) { bool has_operand = false; for (auto& op : stmt.operands_ref().value) @@ -180,11 +179,7 @@ bool ca_processor::prepare_SET_operands( return false; } - context::SET_t value = mngr_.evaluate_expression(ca_op->access_expr()->expression, eval_ctx); - range value_range = semantics::range_provider().get_range(ca_op->access_expr()->expression); - - values.push_back(std::move(value)); - ranges.push_back(value_range); + expr_values.push_back(ca_op->access_expr()->expression.get()); } if (!has_operand) @@ -195,21 +190,6 @@ bool ca_processor::prepare_SET_operands( return true; } -context::SET_t ca_processor::convert_SET_operand(context::SET_t& value, context::SET_t_enum type, range operand_range) -{ - if ((type == context::SET_t_enum::A_TYPE && value.type == context::SET_t_enum::C_TYPE) - || (type == context::SET_t_enum::B_TYPE && value.type == context::SET_t_enum::C_TYPE) - || (type == context::SET_t_enum::C_TYPE && value.type != context::SET_t_enum::C_TYPE)) - { - auto diag = error_messages::e001(); - diag->diag_range = operand_range; - mngr_.add_diagnostic(std::move(*diag)); - return context::SET_t(); - } - - return mngr_.convert(value, type, operand_range); -} - bool ca_processor::prepare_GBL_LCL( const semantics::complete_statement& stmt, std::vector& ids, std::vector& scalar_info) { @@ -226,10 +206,9 @@ bool ca_processor::prepare_GBL_LCL( if (ca_op->kind == semantics::ca_kind::VAR) { - auto var = ca_op->access_var()->variable_symbol.get(); + auto [id, subscript] = ca_op->access_var()->variable_symbol->evaluate_symbol(eval_ctx); - auto [valid, id] = mngr_.try_get_symbol_name(var, eval_ctx); - if (!valid) + if (id == context::id_storage::empty_id) continue; if (auto var_sym = hlasm_ctx.get_var_sym(id)) @@ -249,7 +228,7 @@ bool ca_processor::prepare_GBL_LCL( else { ids.push_back(id); - scalar_info.push_back(var->subscript.empty()); + scalar_info.push_back(subscript.empty()); } } else @@ -287,7 +266,7 @@ bool ca_processor::prepare_ACTR(const semantics::complete_statement& stmt, conte if (ca_op->kind == semantics::ca_kind::EXPR || ca_op->kind == semantics::ca_kind::VAR) { - ctr = mngr_.evaluate_expression_to(ca_op->access_expr()->expression, eval_ctx); + ctr = ca_op->access_expr()->expression->evaluate(eval_ctx); return true; } else @@ -347,7 +326,7 @@ bool ca_processor::prepare_AGO(const semantics::complete_statement& stmt, if (ca_op->kind == semantics::ca_kind::BRANCH) { auto br_op = ca_op->access_branch(); - branch = mngr_.evaluate_expression_to(br_op->expression, eval_ctx); + branch = br_op->expression->evaluate(eval_ctx); targets.emplace_back(br_op->sequence_symbol.name, br_op->sequence_symbol.symbol_range); for (size_t i = 1; i < stmt.operands_ref().value.size(); ++i) @@ -366,8 +345,9 @@ bool ca_processor::prepare_AGO(const semantics::complete_statement& stmt, return false; } } + return true; } - return true; + return false; } void ca_processor::process_AGO(const semantics::complete_statement& stmt) @@ -418,7 +398,7 @@ bool ca_processor::prepare_AIF( if (!condition) { auto br = ca_op->access_branch(); - condition = mngr_.evaluate_expression_to(br->expression, eval_ctx); + condition = br->expression->evaluate(eval_ctx); target = br->sequence_symbol.name; target_range = br->sequence_symbol.symbol_range; @@ -504,12 +484,12 @@ void ca_processor::process_AREAD(const semantics::complete_statement& stmt) return; if (!set_symbol) - set_symbol = mngr_.hlasm_ctx.create_local_variable(name, index == -1).get(); + set_symbol = hlasm_ctx.create_local_variable(name, index == -1).get(); - set_symbol->access_set_symbol()->set_value( - " ", index - 1); + // TODO read proper input line + auto empty_line = " "; + + set_symbol->access_set_symbol()->set_value(empty_line, index - 1); } void ca_processor::process_empty(const semantics::complete_statement&) {} - -void ca_processor::collect_diags() const { collect_diags_from_child(mngr_); } \ No newline at end of file diff --git a/parser_library/src/processing/instruction_sets/ca_processor.h b/parser_library/src/processing/instruction_sets/ca_processor.h index b1c1d3110..12fbb2f40 100644 --- a/parser_library/src/processing/instruction_sets/ca_processor.h +++ b/parser_library/src/processing/instruction_sets/ca_processor.h @@ -28,7 +28,6 @@ class ca_processor : public instruction_processor std::unordered_map>; const process_table_t table_; - context_manager mngr_; processing_state_listener& listener_; public: @@ -55,7 +54,7 @@ class ca_processor : public instruction_processor void register_seq_sym(const semantics::complete_statement& stmt); - bool test_symbol_for_assignment(const semantics::var_sym* symbol, + bool test_symbol_for_assignment(const semantics::variable_symbol* symbol, context::SET_t_enum type, int& idx, context::set_symbol_base*& set_symbol, @@ -66,70 +65,16 @@ class ca_processor : public instruction_processor context::set_symbol_base*& set_symbol, context::id_index& name); bool prepare_SET_operands( - const semantics::complete_statement& stmt, std::vector& values, std::vector& ranges); - context::SET_t convert_SET_operand(context::SET_t& value, context::SET_t_enum type, range operand_range); - template - T convert_SET_operand_to(context::SET_t& value, range operand_range) - { - auto tmp = convert_SET_operand(value, context::object_traits::type_enum, operand_range); - - if constexpr (std::is_same_v) - return tmp.access_a(); - if constexpr (std::is_same_v) - return tmp.access_b(); - if constexpr (std::is_same_v) - return std::move(tmp.access_c()); - } + const semantics::complete_statement& stmt, std::vector& expr_values); template - void process_SET(const semantics::complete_statement& stmt) - { - std::vector values; - std::vector ranges; - int index; - context::id_index name; - context::set_symbol_base* set_symbol; - bool ok = prepare_SET_symbol(stmt, context::object_traits::type_enum, index, set_symbol, name); - - if (!ok) - return; - - if (!set_symbol) - set_symbol = mngr_.hlasm_ctx.create_local_variable(name, index == -1).get(); - - ok = prepare_SET_operands(stmt, values, ranges); - - if (!ok) - return; - - for (size_t i = 0; i < values.size(); i++) - set_symbol->access_set_symbol()->set_value( - convert_SET_operand_to(values[i], ranges[i]), index - 1 + i); - } + void process_SET(const semantics::complete_statement& stmt); bool prepare_GBL_LCL( const semantics::complete_statement& stmt, std::vector& ids, std::vector& scalar_info); template - void process_GBL_LCL(const semantics::complete_statement& stmt) - { - register_seq_sym(stmt); - - std::vector ids; - std::vector scalar_info; - bool ok = prepare_GBL_LCL(stmt, ids, scalar_info); - - if (!ok) - return; - - for (size_t i = 0; i < ids.size(); ++i) - { - if (global) - hlasm_ctx.create_global_variable(ids[i], scalar_info[i]); - else - hlasm_ctx.create_local_variable(ids[i], scalar_info[i]); - } - } + void process_GBL_LCL(const semantics::complete_statement& stmt); void process_ANOP(const semantics::complete_statement& stmt); @@ -155,9 +100,52 @@ class ca_processor : public instruction_processor void process_AREAD(const semantics::complete_statement& stmt); void process_empty(const semantics::complete_statement&); - - virtual void collect_diags() const override; }; +template +inline void ca_processor::process_SET(const semantics::complete_statement& stmt) +{ + std::vector expr_values; + int index; + context::id_index name; + context::set_symbol_base* set_symbol; + bool ok = prepare_SET_symbol(stmt, context::object_traits::type_enum, index, set_symbol, name); + + if (!ok) + return; + + if (!set_symbol) + set_symbol = hlasm_ctx.create_local_variable(name, index == -1).get(); + + ok = prepare_SET_operands(stmt, expr_values); + + if (!ok) + return; + + for (size_t i = 0; i < expr_values.size(); i++) + set_symbol->access_set_symbol()->set_value(expr_values[i]->evaluate(eval_ctx), index - 1 + i); +} + +template +inline void ca_processor::process_GBL_LCL(const semantics::complete_statement& stmt) +{ + register_seq_sym(stmt); + + std::vector ids; + std::vector scalar_info; + bool ok = prepare_GBL_LCL(stmt, ids, scalar_info); + + if (!ok) + return; + + for (size_t i = 0; i < ids.size(); ++i) + { + if (global) + hlasm_ctx.create_global_variable(ids[i], scalar_info[i]); + else + hlasm_ctx.create_local_variable(ids[i], scalar_info[i]); + } +} + } // namespace hlasm_plugin::parser_library::processing #endif \ No newline at end of file diff --git a/parser_library/src/processing/instruction_sets/instruction_processor.h b/parser_library/src/processing/instruction_sets/instruction_processor.h index 8426bd513..80983cd9d 100644 --- a/parser_library/src/processing/instruction_sets/instruction_processor.h +++ b/parser_library/src/processing/instruction_sets/instruction_processor.h @@ -37,7 +37,7 @@ class instruction_processor : public diagnosable_ctx virtual void process(context::unique_stmt_ptr stmt) = 0; virtual void process(context::shared_stmt_ptr stmt) = 0; - virtual void collect_diags() const override {} + virtual void collect_diags() const override { collect_diags_from_child(eval_ctx); } protected: context::hlasm_context& hlasm_ctx; 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 fa726e037..fa2db8540 100644 --- a/parser_library/src/processing/instruction_sets/low_language_processor.cpp +++ b/parser_library/src/processing/instruction_sets/low_language_processor.cpp @@ -51,10 +51,9 @@ context::id_index low_language_processor::find_label_symbol(const rebuilt_statem if (stmt.label_ref().type == semantics::label_si_type::ORD) { context_manager mngr(hlasm_ctx); - auto ret = - mngr.try_get_symbol_name(std::get(stmt.label_ref().value), stmt.label_ref().field_range); + auto ret = mngr.get_symbol_name(std::get(stmt.label_ref().value), stmt.label_ref().field_range); collect_diags_from_child(mngr); - return ret.second; + return ret; } else return context::id_storage::empty_id; @@ -88,12 +87,12 @@ low_language_processor::preprocessed_part low_language_processor::preprocess_inn { case semantics::label_si_type::CONC: label.emplace(stmt.label_ref().field_range, - mngr.concatenate_str(std::get(stmt.label_ref().value), eval_ctx)); + semantics::concatenation_point::evaluate( + std::get(stmt.label_ref().value), eval_ctx)); break; case semantics::label_si_type::VAR: - new_label = mngr.convert_to( - mngr.get_var_sym_value(*std::get(stmt.label_ref().value), eval_ctx), - std::get(stmt.label_ref().value)->symbol_range); + new_label = semantics::var_sym_conc::evaluate( + std::get(stmt.label_ref().value)->evaluate(eval_ctx)); if (new_label.empty() || new_label[0] == ' ') label.emplace(stmt.label_ref().field_range); else @@ -114,7 +113,8 @@ low_language_processor::preprocessed_part low_language_processor::preprocess_inn if (!stmt.operands_ref().value.empty() && stmt.operands_ref().value[0]->type == semantics::operand_type::MODEL) { assert(stmt.operands_ref().value.size() == 1); - std::string field(mngr.concatenate_str(stmt.operands_ref().value[0]->access_model()->chain, eval_ctx)); + std::string field( + semantics::concatenation_point::evaluate(stmt.operands_ref().value[0]->access_model()->chain, eval_ctx)); operands.emplace(parser .parse_operand_field(&hlasm_ctx, std::move(field), @@ -350,7 +350,7 @@ checking::check_op_ptr low_language_processor::get_check_op(const semantics::ope void low_language_processor::check(const resolved_statement& stmt, context::hlasm_context& hlasm_ctx, checking::instruction_checker& checker, - diagnosable_ctx& diagnoser) + const diagnosable_ctx& diagnoser) { auto postponed_stmt = dynamic_cast(&stmt); diagnostic_collector collector( 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 f8cc441e8..4091a3cda 100644 --- a/parser_library/src/processing/instruction_sets/low_language_processor.h +++ b/parser_library/src/processing/instruction_sets/low_language_processor.h @@ -28,7 +28,7 @@ class low_language_processor : public instruction_processor static void check(const resolved_statement& stmt, context::hlasm_context& hlasm_ctx, checking::instruction_checker& checker, - diagnosable_ctx& diagnoser); + const diagnosable_ctx& diagnoser); protected: statement_fields_parser& parser; diff --git a/parser_library/src/processing/instruction_sets/macro_processor.cpp b/parser_library/src/processing/instruction_sets/macro_processor.cpp index e3dc17315..5abd1bdaa 100644 --- a/parser_library/src/processing/instruction_sets/macro_processor.cpp +++ b/parser_library/src/processing/instruction_sets/macro_processor.cpp @@ -14,19 +14,17 @@ #include "macro_processor.h" +#include #include #include "processing/context_manager.h" -#include "processing/statement_processors/macrodef_processor.h" -using namespace hlasm_plugin::parser_library; -using namespace hlasm_plugin::parser_library::processing; -using namespace hlasm_plugin::parser_library::workspaces; +namespace hlasm_plugin::parser_library::processing { macro_processor::macro_processor(context::hlasm_context& hlasm_ctx, attribute_provider& attr_provider, branching_provider& branch_provider, - parse_lib_provider& lib_provider) + workspaces::parse_lib_provider& lib_provider) : instruction_processor(hlasm_ctx, attr_provider, branch_provider, lib_provider) {} @@ -182,112 +180,172 @@ context::macro_data_ptr macro_processor::string_to_macrodata(std::string data) macro_arguments macro_processor::get_args(const resolved_statement& statement) const { - context_manager mngr(hlasm_ctx); + macro_arguments args; - context::macro_data_ptr label_value; + args.name_param = get_label_args(statement); - macro_arguments args; + args.symbolic_params = get_operand_args(statement); + + return args; +} - // label +context::macro_data_ptr macro_processor::get_label_args(const resolved_statement& statement) const +{ switch (statement.label_ref().type) { - case semantics::label_si_type::SEQ: - case semantics::label_si_type::EMPTY: - label_value = nullptr; - break; case semantics::label_si_type::CONC: - label_value = std::make_unique( - mngr.concatenate_str(std::get(statement.label_ref().value), eval_ctx)); - break; + return std::make_unique(semantics::concatenation_point::evaluate( + std::get(statement.label_ref().value), eval_ctx)); case semantics::label_si_type::ORD: case semantics::label_si_type::MAC: - label_value = - std::make_unique(std::get(statement.label_ref().value)); - break; + return std::make_unique( + std::get(statement.label_ref().value)); case semantics::label_si_type::VAR: - label_value = std::make_unique(mngr.convert_to( - mngr.get_var_sym_value(*std::get(statement.label_ref().value), eval_ctx), - std::get(statement.label_ref().value)->symbol_range)); - break; + return std::make_unique(semantics::var_sym_conc::evaluate( + std::get(statement.label_ref().value)->evaluate(eval_ctx))); default: - break; + return context::macro_data_ptr(); } +} - args.name_param = std::move(label_value); +bool is_keyword(const semantics::concat_chain& chain, const context_manager& mngr) +{ + return chain.size() >= 2 && chain[0]->type == semantics::concat_type::STR + && chain[1]->type == semantics::concat_type::EQU + && mngr.try_get_symbol_name(chain[0]->access_str()->value).first; +} - // op +std::vector macro_processor::get_operand_args(const resolved_statement& statement) const +{ + context_manager mngr(hlasm_ctx); + std::vector args; std::vector keyword_params; for (const auto& op : statement.operands_ref().value) { if (op->type == semantics::operand_type::EMPTY) { - args.symbolic_params.push_back({ std::make_unique(), nullptr }); + args.push_back({ std::make_unique(), nullptr }); continue; } auto tmp = op->access_mac(); assert(tmp); - // auto tmp_chain = tmp->chain; + auto& tmp_chain = tmp->chain; - semantics::concatenation_point::clear_concat_chain(tmp->chain); + semantics::concatenation_point::clear_concat_chain(tmp_chain); - if (tmp->chain.size() >= 2 && tmp->chain[0]->type == semantics::concat_type::STR - && tmp->chain[1]->type == semantics::concat_type::EQU - && context_manager(mngr).try_get_symbol_name(tmp->chain[0]->access_str()->value, range()).first) + if (is_keyword(tmp_chain, mngr)) // keyword { - auto tmp_chain = semantics::concatenation_point::clone(tmp->chain); - auto [valid, id] = mngr.try_get_symbol_name(tmp_chain[0]->access_str()->value, op->operand_range); - assert(valid); - auto named = hlasm_ctx.get_macro_definition(statement.opcode_ref().value)->named_params().find(id); - if (named == hlasm_ctx.get_macro_definition(statement.opcode_ref().value)->named_params().end() - || named->second->param_type == context::macro_param_type::POS_PAR_TYPE) - { - add_diagnostic(diagnostic_op::error_E010( - "keyword parameter", tmp->operand_range)); // error - unknown name of keyword parameter + get_keyword_arg(statement, tmp_chain, args, keyword_params, tmp->operand_range); + } + else if (tmp_chain.size() == 1 && tmp_chain.front()->type == semantics::concat_type::VAR) // single varsym + { + context::macro_data_ptr data = string_to_macrodata( + semantics::var_sym_conc::evaluate(tmp_chain.front()->access_var()->symbol->evaluate(eval_ctx))); - // MACROCASE TODO - auto name = tmp_chain[0]->access_str()->value; + args.push_back({ std::move(data), nullptr }); + } + else // rest + args.push_back({ create_macro_data(tmp_chain.begin(), tmp_chain.end(), eval_ctx), nullptr }); + } - tmp_chain.erase(tmp_chain.begin()); - tmp_chain.erase(tmp_chain.begin()); + return args; +} - args.symbolic_params.push_back({ std::make_unique( - name + "=" + semantics::concatenation_point::to_string(tmp_chain)), - nullptr }); - } - else - { - if (std::find(keyword_params.begin(), keyword_params.end(), id) != keyword_params.end()) - { - add_diagnostic( - diagnostic_op::error_E011("Keyword", tmp->operand_range)); // error - keyword already defined - } - else - { - keyword_params.push_back(id); - } - - tmp_chain.erase(tmp_chain.begin()); - tmp_chain.erase(tmp_chain.begin()); - - if (tmp_chain.size() == 1 && tmp_chain.front()->type == semantics::concat_type::SUB) - args.symbolic_params.push_back({ mngr.create_macro_data(std::move(tmp_chain), eval_ctx), id }); - else - args.symbolic_params.push_back( - { string_to_macrodata(mngr.concatenate_str(tmp_chain, eval_ctx)), id }); - } - } - else if (tmp->chain.size() == 1 && tmp->chain.front()->type == semantics::concat_type::VAR) - args.symbolic_params.push_back({ string_to_macrodata(mngr.convert_to( - mngr.get_var_sym_value(*tmp->chain.front()->access_var(), eval_ctx), - tmp->chain.front()->access_var()->symbol_range)), - nullptr }); +void macro_processor::get_keyword_arg(const resolved_statement& statement, + const semantics::concat_chain& chain, + std::vector& args, + std::vector& keyword_params, + range op_range) const +{ + context_manager mngr(hlasm_ctx); + + auto id = mngr.try_get_symbol_name(chain[0]->access_str()->value).second; + assert(id != context::id_storage::empty_id); + + auto named = hlasm_ctx.get_macro_definition(statement.opcode_ref().value)->named_params().find(id); + if (named == hlasm_ctx.get_macro_definition(statement.opcode_ref().value)->named_params().end() + || named->second->param_type == context::macro_param_type::POS_PAR_TYPE) + { + add_diagnostic(diagnostic_op::error_E010("keyword parameter", op_range)); + + // MACROCASE TODO + auto name = chain[0]->access_str()->value; + + args.push_back({ std::make_unique( + name + "=" + semantics::concatenation_point::to_string(chain.begin() + 2, chain.end())), + nullptr }); + } + else + { + if (std::find(keyword_params.begin(), keyword_params.end(), id) != keyword_params.end()) + add_diagnostic(diagnostic_op::error_E011("Keyword", op_range)); + else + keyword_params.push_back(id); + + auto chain_begin = chain.begin() + 2; + auto chain_end = chain.end(); + auto chain_size = chain.size() - 2; + context::macro_data_ptr data; + + if (chain_size == 1 && (*chain_begin)->type == semantics::concat_type::SUB) + data = create_macro_data(chain_begin, chain_end, eval_ctx); else - args.symbolic_params.push_back( - { mngr.create_macro_data(semantics::concatenation_point::clone(tmp->chain), eval_ctx), nullptr }); + data = string_to_macrodata(semantics::concatenation_point::evaluate(chain_begin, chain_end, eval_ctx)); + + args.push_back({ std::move(data), id }); } +} - return args; +context::macro_data_ptr create_macro_data_inner(semantics::concat_chain::const_iterator begin, + semantics::concat_chain::const_iterator end, + const std::function& + to_string) +{ + auto size = end - begin; + if (size == 0) + return std::make_unique(); + else if (size > 1 || (size == 1 && (*begin)->type != semantics::concat_type::SUB)) + return std::make_unique(to_string(begin, end)); + + const auto& inner_chains = (*begin)->access_sub()->list; + + std::vector sublist; + + for (auto& inner_chain : inner_chains) + { + sublist.push_back(create_macro_data_inner(inner_chain.begin(), inner_chain.end(), to_string)); + } + return std::make_unique(std::move(sublist)); } + +context::macro_data_ptr macro_processor::create_macro_data(semantics::concat_chain::const_iterator begin, + semantics::concat_chain::const_iterator end, + diagnostic_adder& add_diagnostic) +{ + auto tmp = semantics::concatenation_point::contains_var_sym(begin, end); + if (tmp) + { + add_diagnostic(diagnostic_op::error_E064); + return std::make_unique(); + } + + auto f = [](semantics::concat_chain::const_iterator b, semantics::concat_chain::const_iterator e) { + return semantics::concatenation_point::to_string(b, e); + }; + return create_macro_data_inner(begin, end, f); +} + +context::macro_data_ptr macro_processor::create_macro_data(semantics::concat_chain::const_iterator begin, + semantics::concat_chain::const_iterator end, + const expressions::evaluation_context& eval_ctx) +{ + auto f = [&eval_ctx](semantics::concat_chain::const_iterator b, semantics::concat_chain::const_iterator e) { + return semantics::concatenation_point::evaluate(b, e, eval_ctx); + }; + return create_macro_data_inner(begin, end, f); +} + +} // namespace hlasm_plugin::parser_library::processing diff --git a/parser_library/src/processing/instruction_sets/macro_processor.h b/parser_library/src/processing/instruction_sets/macro_processor.h index f5e659738..bc71b97ad 100644 --- a/parser_library/src/processing/instruction_sets/macro_processor.h +++ b/parser_library/src/processing/instruction_sets/macro_processor.h @@ -16,6 +16,7 @@ #define PROCESSING_MACRO_PROCESSOR_H #include "context/macro.h" +#include "diagnostic_adder.h" #include "instruction_processor.h" namespace hlasm_plugin { @@ -41,8 +42,24 @@ class macro_processor : public instruction_processor static context::macro_data_ptr string_to_macrodata(std::string data); + static context::macro_data_ptr create_macro_data(semantics::concat_chain::const_iterator begin, + semantics::concat_chain::const_iterator end, + diagnostic_adder& add_diagnostic); + + static context::macro_data_ptr create_macro_data(semantics::concat_chain::const_iterator begin, + semantics::concat_chain::const_iterator end, + const expressions::evaluation_context& eval_ctx); + private: macro_arguments get_args(const resolved_statement& statement) const; + context::macro_data_ptr get_label_args(const resolved_statement& statement) const; + std::vector get_operand_args(const resolved_statement& statement) const; + + void get_keyword_arg(const resolved_statement& statement, + const semantics::concat_chain& chain, + std::vector& args, + std::vector& keyword_params, + range op_range) const; }; } // namespace processing diff --git a/parser_library/src/processing/statement_processors/empty_processor.cpp b/parser_library/src/processing/statement_processors/empty_processor.cpp index c48b568c6..9bdf72773 100644 --- a/parser_library/src/processing/statement_processors/empty_processor.cpp +++ b/parser_library/src/processing/statement_processors/empty_processor.cpp @@ -25,7 +25,7 @@ empty_processor::empty_processor(context::hlasm_context& hlasm_ctx) processing_status empty_processor::get_processing_status(const semantics::instruction_si&) const { - return std::make_pair(processing_format(processing_kind::ORDINARY, processing_form::CA), op_code()); + return std::make_pair(processing_format(processing_kind::ORDINARY, processing_form::IGNORED), op_code()); } void empty_processor::process_statement(context::unique_stmt_ptr) {} diff --git a/parser_library/src/processing/statement_processors/lookahead_processor.cpp b/parser_library/src/processing/statement_processors/lookahead_processor.cpp index 1b544c391..3377e9349 100644 --- a/parser_library/src/processing/statement_processors/lookahead_processor.cpp +++ b/parser_library/src/processing/statement_processors/lookahead_processor.cpp @@ -333,7 +333,7 @@ void lookahead_processor::find_ord(const resolved_statement& statement) return; auto name = std::get(statement.label_ref().value); - auto [valid, id] = context_manager(hlasm_ctx).try_get_symbol_name(std::move(name), range()); + auto [valid, id] = context_manager(hlasm_ctx).try_get_symbol_name(std::move(name)); if (!valid) return; diff --git a/parser_library/src/processing/statement_processors/macrodef_processor.cpp b/parser_library/src/processing/statement_processors/macrodef_processor.cpp index fb521b9f4..e4110ee12 100644 --- a/parser_library/src/processing/statement_processors/macrodef_processor.cpp +++ b/parser_library/src/processing/statement_processors/macrodef_processor.cpp @@ -16,17 +16,16 @@ #include "processing/context_manager.h" #include "processing/instruction_sets/asm_processor.h" +#include "processing/instruction_sets/macro_processor.h" #include "processing/statement.h" #include "semantics/concatenation.h" #include "semantics/statement.h" -using namespace hlasm_plugin::parser_library; -using namespace hlasm_plugin::parser_library::processing; -using namespace hlasm_plugin::parser_library::workspaces; +namespace hlasm_plugin::parser_library::processing { macrodef_processor::macrodef_processor(context::hlasm_context& hlasm_context, processing_state_listener& listener, - parse_lib_provider& provider, + workspaces::parse_lib_provider& provider, macrodef_start_data start) : statement_processor(processing_kind::MACRO, hlasm_context) , listener_(listener) @@ -222,9 +221,17 @@ void macrodef_processor::process_statement(const context::hlasm_statement& state void macrodef_processor::process_prototype(const resolved_statement& statement) { std::vector param_names; - processing::context_manager mngr(hlasm_ctx); - // label processing + process_prototype_label(statement, param_names); + + process_prototype_instruction(statement); + + process_prototype_operand(statement, param_names); +} + +void macrodef_processor::process_prototype_label( + const resolved_statement& statement, std::vector& param_names) +{ if (statement.label_ref().type == semantics::label_si_type::VAR) { auto var = std::get(statement.label_ref().value).get(); @@ -238,8 +245,10 @@ void macrodef_processor::process_prototype(const resolved_statement& statement) } else if (statement.label_ref().type != semantics::label_si_type::EMPTY) add_diagnostic(diagnostic_op::error_E044(statement.label_ref().field_range)); +} - // instr +void macrodef_processor::process_prototype_instruction(const resolved_statement& statement) +{ auto macro_name = statement.opcode_ref().value; if (start_.is_external && macro_name != start_.external_name) { @@ -249,8 +258,13 @@ void macrodef_processor::process_prototype(const resolved_statement& statement) return; } result_.prototype.macro_name = statement.opcode_ref().value; +} + +void macrodef_processor::process_prototype_operand( + const resolved_statement& statement, std::vector& param_names) +{ + processing::context_manager mngr(hlasm_ctx); - // ops for (auto& op : statement.operands_ref().value) { if (op->type == semantics::operand_type::EMPTY) @@ -262,77 +276,74 @@ void macrodef_processor::process_prototype(const resolved_statement& statement) auto tmp = op->access_mac(); assert(tmp); - semantics::concatenation_point::clear_concat_chain(tmp->chain); - - if (tmp->chain.size() == 1 && tmp->chain[0]->type == semantics::concat_type::VAR) // if operand is varsym - { - auto var = tmp->chain[0]->access_var(); + auto& tmp_chain = tmp->chain; - if (var->created || !var->subscript.empty()) - { - add_diagnostic(diagnostic_op::error_E043(var->symbol_range)); - result_.prototype.symbolic_params.emplace_back(nullptr, nullptr); - continue; - } + semantics::concatenation_point::clear_concat_chain(tmp_chain); - auto var_id = var->access_basic()->name; + if (tmp_chain.size() == 1 && tmp_chain[0]->type == semantics::concat_type::VAR) // if operand is varsym + { + auto var = tmp_chain[0]->access_var()->symbol.get(); - if (std::find(param_names.begin(), param_names.end(), var_id) != param_names.end()) - { - add_diagnostic(diagnostic_op::error_E011("Symbolic parameter", tmp->operand_range)); - result_.prototype.symbolic_params.emplace_back(nullptr, nullptr); - } - else + if (test_varsym_validity(var, param_names, tmp->operand_range, true)) { + auto var_id = var->access_basic()->name; param_names.push_back(var_id); result_.prototype.symbolic_params.emplace_back(nullptr, var_id); } } - else if (tmp->chain.size() == 0) // if operand is empty + else if (tmp_chain.size() > 1) { - result_.prototype.symbolic_params.emplace_back(nullptr, nullptr); - } - else if (tmp->chain.size() > 1) - { - if (tmp->chain[0]->type == semantics::concat_type::VAR - && tmp->chain[1]->type == semantics::concat_type::EQU) // if operand is in form of key param + if (tmp_chain[0]->type == semantics::concat_type::VAR + && tmp_chain[1]->type == semantics::concat_type::EQU) // if operand is in form of key param { - auto var = tmp->chain[0]->access_var(); + auto var = tmp_chain[0]->access_var()->symbol.get(); - if (var->created || !var->subscript.empty()) + if (test_varsym_validity(var, param_names, tmp->operand_range, false)) { - add_diagnostic(diagnostic_op::error_E043(var->symbol_range)); - result_.prototype.symbolic_params.emplace_back(nullptr, nullptr); - continue; - } + auto var_id = var->access_basic()->name; - auto var_id = var->access_basic()->name; - - if (std::find(param_names.begin(), param_names.end(), var_id) != param_names.end()) - { - add_diagnostic(diagnostic_op::error_E011("Symbolic parameter", tmp->operand_range)); - } - else - { param_names.push_back(var_id); - semantics::concat_chain tmp_chain = semantics::concatenation_point::clone(tmp->chain); - - tmp_chain.erase(tmp_chain.begin()); - tmp_chain.erase(tmp_chain.begin()); + diagnostic_adder add_diags(this, op->operand_range); result_.prototype.symbolic_params.emplace_back( - mngr.create_macro_data(std::move(tmp_chain)), var_id); + macro_processor::create_macro_data(tmp_chain.begin() + 2, tmp_chain.end(), add_diags), var_id); } } else add_diagnostic(diagnostic_op::error_E043(op->operand_range)); } + else if (tmp_chain.size() == 0) // if operand is empty + result_.prototype.symbolic_params.emplace_back(nullptr, nullptr); } collect_diags_from_child(mngr); } +bool macrodef_processor::test_varsym_validity(const semantics::variable_symbol* var, + const std::vector& param_names, + range op_range, + bool add_empty) +{ + if (var->created || !var->subscript.empty()) + { + add_diagnostic(diagnostic_op::error_E043(var->symbol_range)); + result_.prototype.symbolic_params.emplace_back(nullptr, nullptr); + return false; + } + + auto var_id = var->access_basic()->name; + + if (std::find(param_names.begin(), param_names.end(), var_id) != param_names.end()) + { + add_diagnostic(diagnostic_op::error_E011("Symbolic parameter", op_range)); + if (add_empty) + result_.prototype.symbolic_params.emplace_back(nullptr, nullptr); + return false; + } + return true; +} + void macrodef_processor::process_MACRO() { ++macro_nest_; } void macrodef_processor::process_MEND() @@ -398,3 +409,5 @@ void macrodef_processor::add_correct_copy_nest() result_.nests.back().push_back(std::move(loc)); } } + +} // namespace hlasm_plugin::parser_library::processing diff --git a/parser_library/src/processing/statement_processors/macrodef_processor.h b/parser_library/src/processing/statement_processors/macrodef_processor.h index e7028f73e..5316d8362 100644 --- a/parser_library/src/processing/statement_processors/macrodef_processor.h +++ b/parser_library/src/processing/statement_processors/macrodef_processor.h @@ -65,6 +65,16 @@ class macrodef_processor : public statement_processor void process_statement(const context::hlasm_statement& statement); void process_prototype(const resolved_statement& statement); + void process_prototype_label(const resolved_statement& statement, std::vector& param_names); + void process_prototype_instruction(const resolved_statement& statement); + void process_prototype_operand(const resolved_statement& statement, std::vector& param_names); + + bool test_varsym_validity(const semantics::variable_symbol* var, + const std::vector& param_names, + range op_range, + bool add_empty); + + void process_MACRO(); void process_MEND(); void process_COPY(const resolved_statement& statement); diff --git a/parser_library/src/processing/statement_processors/ordinary_processor.cpp b/parser_library/src/processing/statement_processors/ordinary_processor.cpp index 0c9a7709a..d19471110 100644 --- a/parser_library/src/processing/statement_processors/ordinary_processor.cpp +++ b/parser_library/src/processing/statement_processors/ordinary_processor.cpp @@ -179,6 +179,7 @@ void ordinary_processor::collect_diags() const collect_diags_from_child(asm_proc_); collect_diags_from_child(mac_proc_); collect_diags_from_child(mach_proc_); + collect_diags_from_child(eval_ctx); } void ordinary_processor::check_postponed_statements(std::vector stmts) @@ -236,9 +237,7 @@ bool ordinary_processor::check_fatals(range line_range) context::id_index ordinary_processor::resolve_instruction( const semantics::concat_chain& chain, range instruction_range) const { - context_manager ctx_mngr(hlasm_ctx); - auto tmp = ctx_mngr.concatenate_str(chain, eval_ctx); - collect_diags_from_child(ctx_mngr); + auto tmp = semantics::concatenation_point::evaluate(chain, eval_ctx); // trimright while (tmp.size() && tmp.back() == ' ') diff --git a/parser_library/src/processing/statement_providers/macro_statement_provider.h b/parser_library/src/processing/statement_providers/macro_statement_provider.h index d8c3e09ac..4d8cd04f1 100644 --- a/parser_library/src/processing/statement_providers/macro_statement_provider.h +++ b/parser_library/src/processing/statement_providers/macro_statement_provider.h @@ -35,4 +35,5 @@ class macro_statement_provider : public common_statement_provider } // namespace processing } // namespace parser_library } // namespace hlasm_plugin + #endif diff --git a/parser_library/src/semantics/collector.cpp b/parser_library/src/semantics/collector.cpp index ed9fa079d..6f084e1ee 100644 --- a/parser_library/src/semantics/collector.cpp +++ b/parser_library/src/semantics/collector.cpp @@ -87,9 +87,7 @@ void collector::set_label_field(concat_chain label, range symbol_range) concatenation_point::clear_concat_chain(label); if (label.size() == 1 && label[0]->type == concat_type::VAR) // label is variable symbol { - auto vs = std::unique_ptr(label[0]->access_var()); - label[0].release(); - lbl_->emplace(symbol_range, std::move(vs)); + lbl_->emplace(symbol_range, std::move(label[0]->access_var()->symbol)); } else // label is concatenation { @@ -115,6 +113,7 @@ void collector::set_instruction_field(concat_chain instr, range symbol_range) { if (*instr_) throw std::runtime_error("field already assigned"); + concatenation_point::clear_concat_chain(instr); instr_->emplace(symbol_range, std::move(instr)); } diff --git a/parser_library/src/semantics/concatenation.cpp b/parser_library/src/semantics/concatenation.cpp index 9974a6e5e..fcbc7c5da 100644 --- a/parser_library/src/semantics/concatenation.cpp +++ b/parser_library/src/semantics/concatenation.cpp @@ -14,78 +14,99 @@ #include "concatenation.h" -using namespace hlasm_plugin::parser_library::semantics; -using namespace hlasm_plugin::parser_library::context; -using namespace hlasm_plugin::parser_library; +#include "concatenation_term.h" + +namespace hlasm_plugin::parser_library::semantics { concatenation_point::concatenation_point(const concat_type type) : type(type) {} -char_str* concatenation_point::access_str() +char_str_conc* concatenation_point::access_str() { - return type == concat_type::STR ? static_cast(this) : nullptr; + return type == concat_type::STR ? static_cast(this) : nullptr; } -var_sym* concatenation_point::access_var() { return type == concat_type::VAR ? static_cast(this) : nullptr; } - -dot* concatenation_point::access_dot() { return type == concat_type::DOT ? static_cast(this) : nullptr; } - -equals* concatenation_point::access_equ() { return type == concat_type::EQU ? static_cast(this) : nullptr; } - -sublist* concatenation_point::access_sub() { return type == concat_type::SUB ? static_cast(this) : nullptr; } - -char_str::char_str(std::string value) - : concatenation_point(concat_type::STR) - , value(std::move(value)) -{} - -basic_var_sym::basic_var_sym( - id_index name, std::vector subscript, hlasm_plugin::parser_library::range symbol_range) - : var_sym(false, std::move(subscript), std::move(symbol_range)) - , name(name) -{} +var_sym_conc* concatenation_point::access_var() +{ + return type == concat_type::VAR ? static_cast(this) : nullptr; +} +dot_conc* concatenation_point::access_dot() +{ + return type == concat_type::DOT ? static_cast(this) : nullptr; +} -created_var_sym::created_var_sym(concat_chain created_name, - std::vector subscript, - hlasm_plugin::parser_library::range symbol_range) - : var_sym(true, std::move(subscript), std::move(symbol_range)) - , created_name(std::move(created_name)) -{} +equals_conc* concatenation_point::access_equ() +{ + return type == concat_type::EQU ? static_cast(this) : nullptr; +} -dot::dot() - : concatenation_point(concat_type::DOT) -{} +sublist_conc* concatenation_point::access_sub() +{ + return type == concat_type::SUB ? static_cast(this) : nullptr; +} -equals::equals() - : concatenation_point(concat_type::EQU) -{} +std::string concatenation_point::evaluate(const concat_chain& chain, const expressions::evaluation_context& eval_ctx) +{ + return evaluate(chain.begin(), chain.end(), eval_ctx); +} -sublist::sublist(std::vector list) - : concatenation_point(concat_type::SUB) - , list(std::move(list)) -{} +std::string concatenation_point::evaluate(concat_chain::const_iterator begin, + concat_chain::const_iterator end, + const expressions::evaluation_context& eval_ctx) +{ + std::string ret; + bool was_var = false; + for (auto it = begin; it != end; ++it) + { + auto&& point = *it; + switch (point->type) + { + case concat_type::DOT: + if (!was_var) + ret.append(point->evaluate(eval_ctx)); + was_var = false; + break; + case concat_type::EQU: + case concat_type::STR: + case concat_type::SUB: + ret.append(point->evaluate(eval_ctx)); + was_var = false; + break; + case concat_type::VAR: + ret.append(point->evaluate(eval_ctx)); + was_var = true; + break; + default: + break; + } + } + return ret; +} void concatenation_point::clear_concat_chain(concat_chain& chain) { size_t offset = 0; for (size_t i = 0; i < chain.size(); ++i) { - if (chain[i] - && !(chain[i]->type == concat_type::STR - && chain[i]->access_str()->value.empty())) // if not empty ptr and not empty string + // if not empty ptr and not empty string and not empty var + if (chain[i] && !(chain[i]->type == concat_type::STR && chain[i]->access_str()->value.empty()) + && !(chain[i]->type == concat_type::VAR && !chain[i]->access_var()->symbol)) chain[offset++] = std::move(chain[i]); } chain.resize(offset); } -std::string concatenation_point::to_string(const concat_chain& chain) +std::string concatenation_point::to_string(const concat_chain& chain) { return to_string(chain.begin(), chain.end()); } + +std::string concatenation_point::to_string(concat_chain::const_iterator begin, concat_chain::const_iterator end) { std::string ret; - for (auto& point : chain) + for (auto it = begin; it != end; ++it) { + auto&& point = *it; switch (point->type) { case concat_type::DOT: @@ -99,10 +120,14 @@ std::string concatenation_point::to_string(const concat_chain& chain) break; case concat_type::VAR: ret.push_back('&'); - if (point->access_var()->created) - ret.append(to_string(point->access_var()->access_created()->created_name)); + if (point->access_var()->symbol->created) + { + ret.push_back('('); + ret.append(to_string(point->access_var()->symbol->access_created()->created_name)); + ret.push_back(')'); + } else - ret.append(*point->access_var()->access_basic()->name); + ret.append(*point->access_var()->symbol->access_basic()->name); break; case concat_type::SUB: ret.push_back('('); @@ -121,10 +146,12 @@ std::string concatenation_point::to_string(const concat_chain& chain) return ret; } -var_sym* concatenation_point::contains_var_sym(const concat_chain& chain) +var_sym_conc* concatenation_point::contains_var_sym( + concat_chain::const_iterator begin, concat_chain::const_iterator end) { - for (const auto& point : chain) + for (auto it = begin; it != end; ++it) { + auto&& point = *it; if (point->type == concat_type::VAR) { return point->access_var(); @@ -133,7 +160,7 @@ var_sym* concatenation_point::contains_var_sym(const concat_chain& chain) { for (const auto& entry : point->access_sub()->list) { - auto tmp = contains_var_sym(entry); + auto tmp = contains_var_sym(entry.begin(), entry.end()); if (tmp) return tmp; } @@ -144,69 +171,4 @@ var_sym* concatenation_point::contains_var_sym(const concat_chain& chain) return nullptr; } -concat_chain hlasm_plugin::parser_library::semantics::concatenation_point::clone(const concat_chain& chain) -{ - concat_chain res; - res.reserve(chain.size()); - - for (auto& point : chain) - { - switch (point->type) - { - case concat_type::DOT: - res.push_back(std::make_unique()); - break; - case concat_type::EQU: - res.push_back(std::make_unique()); - break; - case concat_type::STR: - res.push_back(std::make_unique(point->access_str()->value)); - break; - case concat_type::SUB: { - std::vector tmp; - for (auto& ch : point->access_sub()->list) - tmp.emplace_back(clone(ch)); - res.push_back(std::make_unique(std::move(tmp))); - } - break; - case concat_type::VAR: - if (!point->access_var()->created) - { - auto tmp = point->access_var()->access_basic(); - res.push_back(std::make_unique(tmp->name, tmp->subscript, tmp->symbol_range)); - } - else - { - auto tmp = point->access_var()->access_created(); - res.push_back( - std::make_unique(clone(tmp->created_name), tmp->subscript, tmp->symbol_range)); - } - break; - default: - break; - } - } - - return res; -} - -basic_var_sym* var_sym::access_basic() { return created ? nullptr : static_cast(this); } - -const basic_var_sym* var_sym::access_basic() const -{ - return created ? nullptr : static_cast(this); -} - -created_var_sym* var_sym::access_created() { return created ? static_cast(this) : nullptr; } - -const created_var_sym* var_sym::access_created() const -{ - return created ? static_cast(this) : nullptr; -} - -var_sym::var_sym(const bool created, std::vector subscript, const range symbol_range) - : concatenation_point(concat_type::VAR) - , created(created) - , subscript(std::move(subscript)) - , symbol_range(std::move(symbol_range)) -{} +} // namespace hlasm_plugin::parser_library::semantics diff --git a/parser_library/src/semantics/concatenation.h b/parser_library/src/semantics/concatenation.h index 1c34b0cf0..4eace56eb 100644 --- a/parser_library/src/semantics/concatenation.h +++ b/parser_library/src/semantics/concatenation.h @@ -15,21 +15,20 @@ #ifndef SEMANTICS_CONCATENATION_H #define SEMANTICS_CONCATENATION_H -#include #include #include #include -#include "antlr4-runtime.h" - -#include "context/id_storage.h" -#include "range.h" +#include "context/common_types.h" // this file is a composition of structures that create concat_chain // concat_chain is used to represent model statement fields namespace hlasm_plugin { namespace parser_library { +namespace expressions { +struct evaluation_context; +} namespace semantics { enum class concat_type @@ -41,11 +40,11 @@ enum class concat_type EQU }; -struct char_str; -struct var_sym; -struct dot; -struct equals; -struct sublist; +struct char_str_conc; +struct var_sym_conc; +struct dot_conc; +struct equals_conc; +struct sublist_conc; struct concatenation_point; using concat_point_ptr = std::unique_ptr; @@ -60,88 +59,28 @@ struct concatenation_point static void clear_concat_chain(concat_chain& conc_list); static std::string to_string(const concat_chain& chain); + static std::string to_string(concat_chain::const_iterator begin, concat_chain::const_iterator end); - static var_sym* contains_var_sym(const concat_chain& chain); - - static concat_chain clone(const concat_chain& chain); + static var_sym_conc* contains_var_sym(concat_chain::const_iterator begin, concat_chain::const_iterator end); const concat_type type; concatenation_point(const concat_type type); - char_str* access_str(); - var_sym* access_var(); - dot* access_dot(); - equals* access_equ(); - sublist* access_sub(); + char_str_conc* access_str(); + var_sym_conc* access_var(); + dot_conc* access_dot(); + equals_conc* access_equ(); + sublist_conc* access_sub(); - virtual ~concatenation_point() = default; -}; + static std::string evaluate(const concat_chain& chain, const expressions::evaluation_context& eval_ctx); + static std::string evaluate(concat_chain::const_iterator begin, + concat_chain::const_iterator end, + const expressions::evaluation_context& eval_ctx); -// concatenation point representing character string -struct char_str : public concatenation_point -{ - char_str(std::string value); + virtual std::string evaluate(const expressions::evaluation_context& eval_ctx) const = 0; - std::string value; -}; - -struct basic_var_sym; -struct created_var_sym; - -struct var_sym : public concatenation_point -{ - const bool created; - - std::vector subscript; - - const range symbol_range; - - basic_var_sym* access_basic(); - const basic_var_sym* access_basic() const; - created_var_sym* access_created(); - const created_var_sym* access_created() const; - -protected: - var_sym(const bool created, std::vector subscript, const range symbol_range); -}; - -using vs_ptr = std::unique_ptr; - -// concatenation point representing variable symbol -struct basic_var_sym : public var_sym -{ - basic_var_sym(context::id_index name, std::vector subscript, range symbol_range); - - const context::id_index name; -}; - -// concatenation point representing created variable symbol -struct created_var_sym : public var_sym -{ - created_var_sym(concat_chain created_name, std::vector subscript, range symbol_range); - - const concat_chain created_name; -}; - -// concatenation point representing dot -struct dot : public concatenation_point -{ - dot(); -}; - -// concatenation point representing equals sign -struct equals : public concatenation_point -{ - equals(); -}; - -// concatenation point representing macro operand sublist -struct sublist : public concatenation_point -{ - sublist(std::vector list); - - std::vector list; + virtual ~concatenation_point() = default; }; } // namespace semantics diff --git a/parser_library/src/semantics/concatenation_term.cpp b/parser_library/src/semantics/concatenation_term.cpp new file mode 100644 index 000000000..636306731 --- /dev/null +++ b/parser_library/src/semantics/concatenation_term.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2019 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 "concatenation_term.h" + +#include + +namespace hlasm_plugin::parser_library::semantics { + +char_str_conc::char_str_conc(std::string value) + : concatenation_point(concat_type::STR) + , value(std::move(value)) +{} + +std::string char_str_conc::evaluate(const expressions::evaluation_context&) const { return value; } + +var_sym_conc::var_sym_conc(vs_ptr symbol) + : concatenation_point(concat_type::VAR) + , symbol(std::move(symbol)) +{} + +std::string var_sym_conc::evaluate(const expressions::evaluation_context& eval_ctx) const +{ + auto value = symbol->evaluate(eval_ctx); + + return evaluate(std::move(value)); +} + +std::string var_sym_conc::evaluate(context::SET_t varsym_value) +{ + switch (varsym_value.type) + { + case context::SET_t_enum::A_TYPE: + return std::to_string(std::abs(varsym_value.access_a())); + case context::SET_t_enum::B_TYPE: + return varsym_value.access_b() ? "1" : "0"; + case context::SET_t_enum::C_TYPE: + return std::move(varsym_value.access_c()); + default: + return ""; + } +} + +dot_conc::dot_conc() + : concatenation_point(concat_type::DOT) +{} + +std::string dot_conc::evaluate(const expressions::evaluation_context&) const { return "."; } + +equals_conc::equals_conc() + : concatenation_point(concat_type::EQU) +{} + +std::string equals_conc::evaluate(const expressions::evaluation_context&) const { return "="; } + +sublist_conc::sublist_conc(std::vector list) + : concatenation_point(concat_type::SUB) + , list(std::move(list)) +{} + +std::string sublist_conc::evaluate(const expressions::evaluation_context& eval_ctx) const +{ + std::string ret; + ret.push_back('('); + for (size_t i = 0; i < list.size(); ++i) + { + ret.append(concatenation_point::evaluate(list[i], eval_ctx)); + if (i + 1 != list.size()) + ret.push_back(','); + } + ret.push_back(')'); + return ret; +} + +} // namespace hlasm_plugin::parser_library::semantics diff --git a/parser_library/src/semantics/concatenation_term.h b/parser_library/src/semantics/concatenation_term.h new file mode 100644 index 000000000..05adaef19 --- /dev/null +++ b/parser_library/src/semantics/concatenation_term.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2019 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 SEMANTICS_CONCATENATION_TERM_H +#define SEMANTICS_CONCATENATION_TERM_H + +#include "concatenation.h" +#include "variable_symbol.h" + +// this file is a composition of structures that create concat_chain +// concat_chain is used to represent model statement fields + +namespace hlasm_plugin::parser_library::semantics { + +// concatenation point representing character string +struct char_str_conc : concatenation_point +{ + explicit char_str_conc(std::string value); + + std::string value; + + virtual std::string evaluate(const expressions::evaluation_context& eval_ctx) const override; +}; + +// concatenation point representing variable symbol +struct var_sym_conc : concatenation_point +{ + explicit var_sym_conc(vs_ptr); + + vs_ptr symbol; + + virtual std::string evaluate(const expressions::evaluation_context& eval_ctx) const override; + + static std::string evaluate(context::SET_t varsym_value); +}; + +// concatenation point representing dot +struct dot_conc : concatenation_point +{ + dot_conc(); + + virtual std::string evaluate(const expressions::evaluation_context& eval_ctx) const override; +}; + +// concatenation point representing equals sign +struct equals_conc : concatenation_point +{ + equals_conc(); + + virtual std::string evaluate(const expressions::evaluation_context& eval_ctx) const override; +}; + +// concatenation point representing macro operand sublist +struct sublist_conc : concatenation_point +{ + explicit sublist_conc(std::vector list); + + std::vector list; + + virtual std::string evaluate(const expressions::evaluation_context& eval_ctx) const override; +}; + +} // namespace hlasm_plugin::parser_library::semantics +#endif diff --git a/parser_library/src/semantics/highlighting_info.h b/parser_library/src/semantics/highlighting_info.h index c7f82cf2d..c869744f9 100644 --- a/parser_library/src/semantics/highlighting_info.h +++ b/parser_library/src/semantics/highlighting_info.h @@ -19,7 +19,6 @@ #include #include -#include "operand.h" #include "protocol.h" namespace hlasm_plugin { diff --git a/parser_library/src/semantics/lsp_info_processor.cpp b/parser_library/src/semantics/lsp_info_processor.cpp index dd368901d..919d2fa8b 100644 --- a/parser_library/src/semantics/lsp_info_processor.cpp +++ b/parser_library/src/semantics/lsp_info_processor.cpp @@ -14,7 +14,7 @@ #include "lsp_info_processor.h" -#include +#include #include "context/instruction.h" diff --git a/parser_library/src/semantics/operand.cpp b/parser_library/src/semantics/operand.cpp index 4529d7f0c..2178b405d 100644 --- a/parser_library/src/semantics/operand.cpp +++ b/parser_library/src/semantics/operand.cpp @@ -14,8 +14,7 @@ #include "operand.h" -using namespace hlasm_plugin::parser_library::semantics; -using namespace hlasm_plugin::parser_library; +namespace hlasm_plugin::parser_library::semantics { //***************** operand ********************* @@ -49,7 +48,9 @@ empty_operand::empty_operand(range operand_range) model_operand::model_operand(concat_chain chain, range operand_range) : operand(operand_type::MODEL, std::move(operand_range)) , chain(std::move(chain)) -{} +{ + concatenation_point::clear_concat_chain(this->chain); +} evaluable_operand::evaluable_operand(const operand_type type, range operand_range) : operand(type, std::move(operand_range)) @@ -111,6 +112,24 @@ std::unique_ptr expr_machine_operand::get_operand_value( return make_check_operand(info, *expression, type_hint); } +// suppress MSVC warning 'inherits via dominance' +bool expr_machine_operand::has_dependencies(expressions::mach_evaluate_info 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 +{ + return simple_expr_operand::has_error(info); +} + +// suppress MSVC warning 'inherits via dominance' +std::vector expr_machine_operand::get_resolvables() const +{ + return simple_expr_operand::get_resolvables(); +} + void expr_machine_operand::collect_diags() const { collect_diags_from_child(*expression); } //***************** address_machine_operand ********************* @@ -270,6 +289,24 @@ std::unique_ptr expr_assembler_operand::get_operand_value(exp } } +// suppress MSVC warning 'inherits via dominance' +bool expr_assembler_operand::has_dependencies(expressions::mach_evaluate_info 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 +{ + return simple_expr_operand::has_error(info); +} + +// suppress MSVC warning 'inherits via dominance' +std::vector expr_assembler_operand::get_resolvables() const +{ + return simple_expr_operand::get_resolvables(); +} + void expr_assembler_operand::collect_diags() const { collect_diags_from_child(*expression); } //***************** end_instr_machine_operand ********************* @@ -402,9 +439,9 @@ var_ca_operand::var_ca_operand(vs_ptr variable_symbol, range operand_range) , variable_symbol(std::move(variable_symbol)) {} -expr_ca_operand::expr_ca_operand(antlr4::ParserRuleContext* expression, range operand_range) +expr_ca_operand::expr_ca_operand(expressions::ca_expr_ptr expression, range operand_range) : ca_operand(ca_kind::EXPR, std::move(operand_range)) - , expression(expression) + , expression(std::move(expression)) {} seq_ca_operand::seq_ca_operand(seq_sym sequence_symbol, range operand_range) @@ -412,11 +449,10 @@ seq_ca_operand::seq_ca_operand(seq_sym sequence_symbol, range operand_range) , sequence_symbol(std::move(sequence_symbol)) {} -branch_ca_operand::branch_ca_operand( - seq_sym sequence_symbol, antlr4::ParserRuleContext* expression, range operand_range) +branch_ca_operand::branch_ca_operand(seq_sym sequence_symbol, expressions::ca_expr_ptr expression, range operand_range) : ca_operand(ca_kind::BRANCH, std::move(operand_range)) , sequence_symbol(std::move(sequence_symbol)) - , expression(expression) + , expression(std::move(expression)) {} @@ -539,3 +575,5 @@ macro_operand_string::macro_operand_string(std::string value, const range operan : operand(operand_type::MAC, operand_range) , value(std::move(value)) {} + +} // namespace hlasm_plugin::parser_library::semantics \ No newline at end of file diff --git a/parser_library/src/semantics/operand.h b/parser_library/src/semantics/operand.h index 62592af70..416728bdf 100644 --- a/parser_library/src/semantics/operand.h +++ b/parser_library/src/semantics/operand.h @@ -19,7 +19,7 @@ #include "checking/data_definition/data_definition_operand.h" #include "checking/instr_operand.h" -#include "concatenation.h" +#include "concatenation_term.h" #include "expressions/data_definition.h" #include "expressions/mach_expression.h" @@ -169,6 +169,10 @@ struct expr_machine_operand final : public machine_operand, public simple_expr_o virtual std::unique_ptr get_operand_value( expressions::mach_evaluate_info info, checking::machine_operand_type type_hint) const override; + virtual bool has_dependencies(expressions::mach_evaluate_info info) const override; + virtual bool has_error(expressions::mach_evaluate_info info) const override; + virtual std::vector get_resolvables() const override; + virtual void collect_diags() const override; }; @@ -238,6 +242,10 @@ struct expr_assembler_operand final : public assembler_operand, public simple_ex virtual std::unique_ptr get_operand_value(expressions::mach_evaluate_info info) const override; + virtual bool has_dependencies(expressions::mach_evaluate_info info) const override; + virtual bool has_error(expressions::mach_evaluate_info info) const override; + virtual std::vector get_resolvables() const override; + virtual void collect_diags() const override; }; @@ -426,9 +434,9 @@ struct var_ca_operand final : public ca_operand // CA expression operand struct expr_ca_operand final : public ca_operand { - expr_ca_operand(antlr4::ParserRuleContext* expression, const range operand_range); + expr_ca_operand(expressions::ca_expr_ptr expression, const range operand_range); - antlr4::ParserRuleContext* expression; + expressions::ca_expr_ptr expression; }; // CA sequence symbol operand @@ -442,10 +450,10 @@ struct seq_ca_operand final : public ca_operand // CA branching operand (i.e. (5).here) struct branch_ca_operand final : public ca_operand { - branch_ca_operand(seq_sym sequence_symbol, antlr4::ParserRuleContext* expression, const range operand_range); + branch_ca_operand(seq_sym sequence_symbol, expressions::ca_expr_ptr expression, const range operand_range); seq_sym sequence_symbol; - antlr4::ParserRuleContext* expression; + expressions::ca_expr_ptr expression; }; diff --git a/parser_library/src/semantics/variable_symbol.cpp b/parser_library/src/semantics/variable_symbol.cpp new file mode 100644 index 000000000..6c5cf9d6d --- /dev/null +++ b/parser_library/src/semantics/variable_symbol.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2019 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 "variable_symbol.h" + +#include "expressions/conditional_assembly/terms/ca_constant.h" +#include "processing/context_manager.h" + +namespace hlasm_plugin::parser_library::semantics { + +basic_variable_symbol::basic_variable_symbol( + context::id_index name, std::vector subscript, range symbol_range) + : variable_symbol(false, std::move(subscript), std::move(symbol_range)) + , name(name) +{} + +context::id_index basic_variable_symbol::evaluate_name(const expressions::evaluation_context&) const { return name; } + +created_variable_symbol::created_variable_symbol( + concat_chain created_name, std::vector subscript, range symbol_range) + : variable_symbol(true, std::move(subscript), std::move(symbol_range)) + , created_name(std::move(created_name)) +{} + +context::id_index created_variable_symbol::evaluate_name(const expressions::evaluation_context& eval_ctx) const +{ + auto str_name = concatenation_point::evaluate(created_name, eval_ctx); + + auto mngr = processing::context_manager(&eval_ctx); + + return mngr.get_symbol_name(str_name, symbol_range); +} + +basic_variable_symbol* variable_symbol::access_basic() +{ + return created ? nullptr : static_cast(this); +} + +const basic_variable_symbol* variable_symbol::access_basic() const +{ + return created ? nullptr : static_cast(this); +} + +created_variable_symbol* variable_symbol::access_created() +{ + return created ? static_cast(this) : nullptr; +} + +const created_variable_symbol* variable_symbol::access_created() const +{ + return created ? static_cast(this) : nullptr; +} + +vs_eval variable_symbol::evaluate_symbol(const expressions::evaluation_context& eval_ctx) const +{ + auto name = evaluate_name(eval_ctx); + std::vector eval_subscript; + for (const auto& expr : subscript) + { + auto val = expr->evaluate(eval_ctx); + eval_subscript.push_back(val); + } + + return vs_eval(name, std::move(eval_subscript)); +} + +context::SET_t variable_symbol::evaluate(const expressions::evaluation_context& eval_ctx) const +{ + auto [name, evaluated_subscript] = evaluate_symbol(eval_ctx); + + processing::context_manager mngr(&eval_ctx); + + auto val = mngr.get_var_sym_value(name, evaluated_subscript, symbol_range); + + return val; +} + +variable_symbol::variable_symbol( + const bool created, std::vector subscript, range symbol_range) + : created(created) + , subscript(std::move(subscript)) + , symbol_range(std::move(symbol_range)) +{} + +} // namespace hlasm_plugin::parser_library::semantics diff --git a/parser_library/src/semantics/variable_symbol.h b/parser_library/src/semantics/variable_symbol.h new file mode 100644 index 000000000..5353ecb88 --- /dev/null +++ b/parser_library/src/semantics/variable_symbol.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2019 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 SEMANTICS_VARIABLE_SYMBOL_H +#define SEMANTICS_VARIABLE_SYMBOL_H + +#include +#include +#include + +#include "concatenation.h" +#include "context/id_storage.h" +#include "expressions/conditional_assembly/ca_expression.h" +#include "range.h" + +// this file is a composition of structures that create concat_chain +// concat_chain is used to represent model statement fields + +namespace hlasm_plugin::parser_library::semantics { + +struct variable_symbol; +struct basic_variable_symbol; +struct created_variable_symbol; + +using vs_ptr = std::unique_ptr; +using vs_eval = std::pair>; + +struct variable_symbol +{ + const bool created; + + std::vector subscript; + + const range symbol_range; + + basic_variable_symbol* access_basic(); + const basic_variable_symbol* access_basic() const; + created_variable_symbol* access_created(); + const created_variable_symbol* access_created() const; + + vs_eval evaluate_symbol(const expressions::evaluation_context& eval_ctx) const; + context::SET_t evaluate(const expressions::evaluation_context& eval_ctx) const; + + virtual ~variable_symbol() = default; + +protected: + variable_symbol(const bool created, std::vector subscript, range symbol_range); + + virtual context::id_index evaluate_name(const expressions::evaluation_context& eval_ctx) const = 0; +}; + +struct basic_variable_symbol : variable_symbol +{ + basic_variable_symbol(context::id_index name, std::vector subscript, range symbol_range); + + const context::id_index name; + + virtual context::id_index evaluate_name(const expressions::evaluation_context& eval_ctx) const; +}; + +struct created_variable_symbol : variable_symbol +{ + created_variable_symbol( + concat_chain created_name, std::vector subscript, range symbol_range); + + const concat_chain created_name; + + virtual context::id_index evaluate_name(const expressions::evaluation_context& eval_ctx) const; +}; + +} // namespace hlasm_plugin::parser_library::semantics + +#endif diff --git a/parser_library/src/workspaces/processor_file_impl.cpp b/parser_library/src/workspaces/processor_file_impl.cpp index f17f518f7..dc0e8a9ef 100644 --- a/parser_library/src/workspaces/processor_file_impl.cpp +++ b/parser_library/src/workspaces/processor_file_impl.cpp @@ -79,7 +79,7 @@ parse_result processor_file_impl::parse_macro( parse_result processor_file_impl::parse_no_lsp_update( parse_lib_provider& lib_provider, context::hlasm_context& hlasm_ctx, const library_data data) { - no_update_analyzer_ = + auto no_update_analyzer_ = std::make_unique(get_text(), get_file_name(), hlasm_ctx, lib_provider, data, get_lsp_editing()); no_update_analyzer_->analyze(); return true; diff --git a/parser_library/src/workspaces/processor_file_impl.h b/parser_library/src/workspaces/processor_file_impl.h index f8ebde394..a8c7a27f2 100644 --- a/parser_library/src/workspaces/processor_file_impl.h +++ b/parser_library/src/workspaces/processor_file_impl.h @@ -53,8 +53,6 @@ class processor_file_impl : public virtual file_impl, public virtual processor_f private: std::unique_ptr analyzer_; - // This is here only because CA expressions need parser to be alive to evaluate - std::unique_ptr no_update_analyzer_; bool parse_inner(analyzer&); diff --git a/parser_library/test/common_testing.h b/parser_library/test/common_testing.h index 6e1d2f8db..7f2317e49 100644 --- a/parser_library/test/common_testing.h +++ b/parser_library/test/common_testing.h @@ -22,7 +22,6 @@ #include "analyzer.h" #include "ebcdic_encoding.h" -#include "expressions/visitors/expression_analyzer.h" #include "hlasmparser.h" #include "lexing/input_source.h" #include "lexing/token_stream.h" diff --git a/parser_library/test/context/context_test.cpp b/parser_library/test/context/context_test.cpp index 52fd8e1e9..eec20ae16 100644 --- a/parser_library/test/context/context_test.cpp +++ b/parser_library/test/context/context_test.cpp @@ -550,13 +550,13 @@ TEST(context, id_check) hlasm_context ctx; processing::context_manager mngr(ctx); - EXPECT_TRUE(mngr.try_get_symbol_name("LIST", range()).first); - EXPECT_TRUE(mngr.try_get_symbol_name("T_A", range()).first); - EXPECT_TRUE(mngr.try_get_symbol_name("T1", range()).first); - EXPECT_TRUE(mngr.try_get_symbol_name("a1-", range()).first); + EXPECT_TRUE(mngr.try_get_symbol_name("LIST").first); + EXPECT_TRUE(mngr.try_get_symbol_name("T_A").first); + EXPECT_TRUE(mngr.try_get_symbol_name("T1").first); + EXPECT_TRUE(mngr.try_get_symbol_name("a1-").first); - EXPECT_FALSE(mngr.try_get_symbol_name("*1", range()).first); - EXPECT_FALSE(mngr.try_get_symbol_name("1av", range()).first); + EXPECT_FALSE(mngr.try_get_symbol_name("*1").first); + EXPECT_FALSE(mngr.try_get_symbol_name("1av").first); } TEST(context_system_variables, SYSNEST_SYSMAC) diff --git a/parser_library/test/context/data_attribute_test.cpp b/parser_library/test/context/data_attribute_test.cpp index fef61287b..d07900c59 100644 --- a/parser_library/test/context/data_attribute_test.cpp +++ b/parser_library/test/context/data_attribute_test.cpp @@ -28,9 +28,9 @@ TEST(data_attributes, N) auto id2 = ctx.ids().add("id2"); macro_data_ptr data = std::make_unique("ada"); - EXPECT_EQ(positional_param(id, 0, *data).number(), 1); + EXPECT_EQ(positional_param(id, 0, *data).number({}), 1); data = std::make_unique(); - EXPECT_EQ(positional_param(id, 0, *data).number(), 0); + EXPECT_EQ(positional_param(id, 0, *data).number({}), 0); auto s0 = std::make_unique("first"); @@ -41,33 +41,33 @@ TEST(data_attributes, N) v.push_back(move(s1)); v.push_back(move(s2)); - EXPECT_EQ(keyword_param(id, std::make_unique(), nullptr).number(), 0); + EXPECT_EQ(keyword_param(id, std::make_unique(), nullptr).number({}), 0); data = std::make_unique(move(v)); auto kp = keyword_param(id, std::make_unique(), std::move(data)); - EXPECT_EQ(kp.number(), 3); + EXPECT_EQ(kp.number({}), 3); EXPECT_EQ(kp.number({ 1 }), 1); EXPECT_EQ(kp.number({ 4 }), 0); auto var = ctx.create_local_variable(id, true)->access_set_symbol(); - EXPECT_EQ(var->number(), 0); + EXPECT_EQ(var->number({}), 0); EXPECT_EQ(var->number({ 1 }), 0); var->set_value(1); - EXPECT_EQ(var->number(), 0); + EXPECT_EQ(var->number({}), 0); EXPECT_EQ(var->number({ 1 }), 0); auto var_ns = ctx.create_local_variable(id2, false)->access_set_symbol(); - EXPECT_EQ(var_ns->number(), 0); + EXPECT_EQ(var_ns->number({}), 0); EXPECT_EQ(var_ns->number({ 1 }), 0); var_ns->set_value(1, 0); - EXPECT_EQ(var_ns->number(), 1); + EXPECT_EQ(var_ns->number({}), 1); EXPECT_EQ(var_ns->number({ 1 }), 1); var_ns->set_value(1, 14); - EXPECT_EQ(var_ns->number(), 15); + EXPECT_EQ(var_ns->number({}), 15); EXPECT_EQ(var_ns->number({ 1 }), 15); } @@ -81,9 +81,9 @@ TEST(data_attributes, K) auto idC = ctx.ids().add("id3"); macro_data_ptr data = std::make_unique("ada"); - EXPECT_EQ(positional_param(idA, 0, *data).count(), 3); + EXPECT_EQ(positional_param(idA, 0, *data).count({}), 3); data = std::make_unique(); - EXPECT_EQ(positional_param(idA, 0, *data).count(), 0); + EXPECT_EQ(positional_param(idA, 0, *data).count({}), 0); auto s0 = std::make_unique("first"); @@ -94,10 +94,10 @@ TEST(data_attributes, K) v.push_back(move(s1)); v.push_back(move(s2)); - EXPECT_EQ(keyword_param(idA, std::make_unique(), nullptr).count(), 0); + EXPECT_EQ(keyword_param(idA, std::make_unique(), nullptr).count({}), 0); auto kp = keyword_param( idA, std::make_unique(), std::make_unique(move(v))); - EXPECT_EQ(kp.count(), 20); + EXPECT_EQ(kp.count({}), 20); EXPECT_EQ(kp.count({ 2 }), 6); EXPECT_EQ(kp.count({ 4 }), 0); @@ -105,19 +105,19 @@ TEST(data_attributes, K) auto varB = ctx.create_local_variable(idB, true)->access_set_symbol(); auto varC = ctx.create_local_variable(idC, true)->access_set_symbol(); - EXPECT_EQ(varA->count(), 1); + EXPECT_EQ(varA->count({}), 1); EXPECT_EQ(varA->count({ 1 }), 1); - EXPECT_EQ(varB->count(), 1); + EXPECT_EQ(varB->count({}), 1); EXPECT_EQ(varB->count({ 1 }), 1); - EXPECT_EQ(varC->count(), 0); + EXPECT_EQ(varC->count({}), 0); EXPECT_EQ(varC->count({ 1 }), 0); varA->set_value(1); - EXPECT_EQ(varA->count(), 1); + EXPECT_EQ(varA->count({}), 1); varA->set_value(10); - EXPECT_EQ(varA->count(), 2); + EXPECT_EQ(varA->count({}), 2); varA->set_value(-10); - EXPECT_EQ(varA->count(), 3); + EXPECT_EQ(varA->count({}), 3); } TEST(data_attributes, N_var_syms) diff --git a/parser_library/test/expressions/arithmetic_expression_test.cpp b/parser_library/test/expressions/arithmetic_expression_test.cpp new file mode 100644 index 000000000..b4925ce66 --- /dev/null +++ b/parser_library/test/expressions/arithmetic_expression_test.cpp @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2019 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" + +// test for +// arithmetic SETA expressions + +#define SETAEQ(X, Y) \ + EXPECT_EQ(a.context() \ + .get_var_sym(a.context().ids().add(X)) \ + ->access_set_symbol_base() \ + ->access_set_symbol() \ + ->get_value(), \ + Y) + +TEST(arithmetic_expressions, valid_self_defining_term) +{ + std::string input = + R"( +&A1 SETA 1 +&A2 SETA C'D' +&C3 SETC 'C''A''' +&A3 SETA &C3+&C3 +&A4 SETA &A4 +)"; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + ASSERT_EQ(a.diags().size(), (size_t)0); + + SETAEQ("A1", 1); + SETAEQ("A2", 196); + SETAEQ("A3", 386); + SETAEQ("A4", 0); +} + +TEST(arithmetic_expressions, invalid_self_defining_term) +{ + std::string input = + R"( +&C1 SETC 'D' +&A1 SETA C'&C1' +)"; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + ASSERT_EQ(a.diags().size(), (size_t)1); +} + +TEST(arithmetic_expressions, substitution_to_character_expression) +{ + std::string input = + R"( +&A1 SETA 10 +&C1 SETC '5-10*&A1' +&A2 SETA -10 +&C2 SETC '5-10*&A2' +)"; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + ASSERT_EQ(a.diags().size(), (size_t)0); + + EXPECT_EQ(a.context() + .get_var_sym(a.context().ids().add("C1")) + ->access_set_symbol_base() + ->access_set_symbol() + ->get_value(), + "5-10*10"); + + EXPECT_EQ(a.context() + .get_var_sym(a.context().ids().add("C2")) + ->access_set_symbol_base() + ->access_set_symbol() + ->get_value(), + "5-10*10"); +} + +TEST(arithmetic_expressions, subscript_use) +{ + std::string input = + R"( +&A1(10) SETA 10 +&A2 SETA &A1(10 OR 2) +)"; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + ASSERT_EQ(a.diags().size(), (size_t)1); +} + +TEST(arithmetic_expressions, unary_operators) +{ + std::string input = + R"( +&A SETA 6 +&B SETA 4 +&C SETA +++&A*---&B +)"; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + ASSERT_EQ(a.diags().size(), (size_t)0); + + SETAEQ("C", -24); +} + +TEST(arithmetic_expressions, binary_space_separated_operator) +{ + std::string input = + R"( +&A SETA ('ABC' INDEX 'B') +)"; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + ASSERT_EQ(a.diags().size(), (size_t)0); + + SETAEQ("A", 2); +} + +// requires proper lexer token that recognises number with minus sign +#if 0 +TEST(arithmetic_expressions, limits) +{ + std::string input = + R"( +&A SETA 2147483647 +&B SETA -2147483648 +&C SETA &A+1 +&D SETA &B-1 +&E SETC '&B' +&F SETA &E +)"; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + ASSERT_EQ(a.diags().size(), (size_t)3); +} +#endif + +TEST(arithmetic_expressions, division) +{ + std::string input = + R"( +&A(1) SETA 0,1,2 +&B1 SETA &A(1)/2 +&B2 SETA &A(2)/2 +&B3 SETA &A(3)/2 +&B4 SETA &A(3)/0 +)"; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + ASSERT_EQ(a.diags().size(), (size_t)0); + + SETAEQ("B1", 0); + SETAEQ("B2", 0); + SETAEQ("B3", 1); + SETAEQ("B4", 0); +} + +TEST(arithmetic_expressions, operator_priorities) +{ + std::string input = + R"( +&A SETA 3+-4 +&B SETA 3+4*2 +&C SETA (10 OR 1+1) +&D SETA (10 SLL 10 AND 2) +&E SETA 4-2+5 +)"; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + ASSERT_EQ(a.diags().size(), (size_t)0); + + SETAEQ("A", -1); + SETAEQ("B", 11); + SETAEQ("C", 10); + SETAEQ("D", 40); + SETAEQ("E", 7); +} + +TEST(arithmetic_expressions, invalid_operator) +{ + std::string input = + R"( +&A SETA (1 AND 1 EQ 2) +)"; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + ASSERT_EQ(a.diags().size(), (size_t)1); + EXPECT_EQ(a.diags().front().code, "CE002"); +} + +TEST(character_expresssion, illegal_dupl_factor) +{ + std::string input = + R"( +&A SETA (1)FIND('A','B') +)"; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + ASSERT_EQ(a.diags().size(), (size_t)1); + EXPECT_EQ(a.diags().front().code, "CE005"); +} diff --git a/parser_library/test/expressions/ca_constant_test.cpp b/parser_library/test/expressions/ca_constant_test.cpp new file mode 100644 index 000000000..07e60a881 --- /dev/null +++ b/parser_library/test/expressions/ca_constant_test.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2019 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 "gmock/gmock.h" + +#include "expr_mocks.h" +#include "expressions/conditional_assembly/terms/ca_constant.h" +#include "expressions/evaluation_context.h" + +using namespace hlasm_plugin::parser_library::expressions; +using namespace hlasm_plugin::parser_library::semantics; +using namespace hlasm_plugin::parser_library; + +TEST(ca_constant, undefined_attributes) +{ + dep_sol_mock m; + ca_constant c(1, range()); + + ASSERT_EQ(c.get_undefined_attributed_symbols(m).size(), 0U); +} + +class collectable_mock : public diagnosable_op_impl +{ + virtual void collect_diags() const override {} +}; + +TEST(ca_constant, self_def_term_invalid_input) +{ + { + collectable_mock m; + diagnostic_adder add_diags(&m, range()); + ca_constant::self_defining_term("", add_diags); + ASSERT_TRUE(add_diags.diagnostics_present); + EXPECT_EQ(m.diags().front().code, "CE015"); + } + { + collectable_mock m; + diagnostic_adder add_diags(&m, range()); + ca_constant::self_defining_term("Q'dc'", add_diags); + ASSERT_TRUE(add_diags.diagnostics_present); + EXPECT_EQ(m.diags().front().code, "CE015"); + } +} + +TEST(ca_constant, self_def_term_valid_input) +{ + { + diagnostic_adder add_diags; + auto res = ca_constant::self_defining_term("B'10'", add_diags); + ASSERT_FALSE(add_diags.diagnostics_present); + EXPECT_EQ(res, 2); + } + { + diagnostic_adder add_diags; + auto res = ca_constant::self_defining_term("C'1'", add_diags); + ASSERT_FALSE(add_diags.diagnostics_present); + EXPECT_EQ(res, 241); + } + { + diagnostic_adder add_diags; + auto res = ca_constant::self_defining_term("X'f'", add_diags); + ASSERT_FALSE(add_diags.diagnostics_present); + EXPECT_EQ(res, 15); + } +} diff --git a/parser_library/test/expressions/ca_expr_list_test.cpp b/parser_library/test/expressions/ca_expr_list_test.cpp new file mode 100644 index 000000000..ef360b24e --- /dev/null +++ b/parser_library/test/expressions/ca_expr_list_test.cpp @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2019 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 "gmock/gmock.h" + +#include "expr_mocks.h" +#include "expressions/conditional_assembly/terms/ca_constant.h" +#include "expressions/conditional_assembly/terms/ca_expr_list.h" +#include "expressions/conditional_assembly/terms/ca_function.h" +#include "expressions/conditional_assembly/terms/ca_string.h" +#include "expressions/conditional_assembly/terms/ca_symbol.h" +#include "expressions/conditional_assembly/terms/ca_symbol_attribute.h" +#include "expressions/evaluation_context.h" + +using namespace hlasm_plugin::parser_library::expressions; +using namespace hlasm_plugin::parser_library::semantics; +using namespace hlasm_plugin::parser_library; + +TEST(ca_expr_list, unknown_function_to_operator) +{ + context::hlasm_context ctx; + attr_prov_mock attr; + lib_prov_mock lib; + evaluation_context eval_ctx { ctx, attr, lib }; + + std::string name = "AND"; + auto c = std::make_unique(1, range()); + auto dupl = std::make_unique(1, range()); + std::vector params; + params.emplace_back(std::move(c)); + auto unknown_func = + std::make_unique(&name, ca_expr_funcs::UNKNOWN, std::move(params), std::move(dupl), range()); + + std::vector list; + list.emplace_back(std::move(unknown_func)); + ca_expr_list expr_list(std::move(list), range()); + + // function => operator + // ((1)AND(1)) => ((1) AND (1)) + expr_list.resolve_expression_tree(context::SET_t_enum::B_TYPE); + auto res = expr_list.evaluate(eval_ctx); + + ASSERT_TRUE(expr_list.diags().empty()); + ASSERT_TRUE(eval_ctx.diags().empty()); + ASSERT_EQ(res.access_b(), true); +} + +TEST(ca_expr_list, resolve_C_type) +{ + context::hlasm_context ctx; + attr_prov_mock attr; + lib_prov_mock lib; + evaluation_context eval_ctx { ctx, attr, lib }; + + std::string name = "UPPER"; + auto sym = std::make_unique(&name, range()); + + concat_chain value; + value.push_back(std::make_unique("low")); + auto str = std::make_unique(std::move(value), nullptr, ca_string::substring_t(), range()); + + std::vector list; + list.emplace_back(std::move(sym)); + list.emplace_back(std::move(str)); + // (UPPER 'low') + ca_expr_list expr_list(std::move(list), range()); + expr_list.resolve_expression_tree(context::SET_t_enum::C_TYPE); + auto res = expr_list.evaluate(eval_ctx); + + ASSERT_TRUE(expr_list.diags().empty()); + ASSERT_TRUE(eval_ctx.diags().empty()); + ASSERT_EQ(res.access_c(), "LOW"); +} + +TEST(ca_expr_list, get_undefined_attributed_symbols) +{ + std::string name = "X"; + auto sym = std::make_unique(&name, context::data_attr_kind::L, range()); + + concat_chain value; + value.push_back(std::make_unique("low")); + auto str = std::make_unique(std::move(value), nullptr, ca_string::substring_t(), range()); + + std::vector list; + list.emplace_back(std::move(sym)); + list.emplace_back(std::move(str)); + // (L'X 'low') + ca_expr_list expr_list(std::move(list), range()); + + dep_sol_mock m; + auto res = expr_list.get_undefined_attributed_symbols(m); + + ASSERT_TRUE(res.size()); +} + +TEST(ca_expr_list, is_character_expression) +{ + concat_chain value; + value.push_back(std::make_unique("low")); + auto str = std::make_unique(std::move(value), nullptr, ca_string::substring_t(), range()); + + std::vector list; + list.emplace_back(std::move(str)); + // ('low') + ca_expr_list expr_list(std::move(list), range()); + + ASSERT_FALSE(expr_list.is_character_expression()); +} + +TEST(ca_expr_list, unfinished_expressions) +{ + // () + { + ca_expr_list expr_list({}, range()); + expr_list.resolve_expression_tree(context::SET_t_enum::B_TYPE); + + ASSERT_FALSE(expr_list.diags().empty()); + } + // (NOT) + { + std::string name = "NOT"; + auto sym = std::make_unique(&name, range()); + + std::vector list; + list.emplace_back(std::move(sym)); + + ca_expr_list expr_list(std::move(list), range()); + expr_list.resolve_expression_tree(context::SET_t_enum::B_TYPE); + + ASSERT_FALSE(expr_list.diags().empty()); + } + // (1 AND) + { + auto c = std::make_unique(1, range()); + + std::string name = "AND"; + auto sym = std::make_unique(&name, range()); + + std::vector list; + list.emplace_back(std::move(c)); + list.emplace_back(std::move(sym)); + + ca_expr_list expr_list(std::move(list), range()); + expr_list.resolve_expression_tree(context::SET_t_enum::B_TYPE); + + ASSERT_FALSE(expr_list.diags().empty()); + } + // (1 AND 1 EQ) + { + auto c = std::make_unique(1, range()); + auto c2 = std::make_unique(1, range()); + + std::string and_name = "AND"; + std::string eq_name = "EQ"; + auto and_sym = std::make_unique(&and_name, range()); + auto eq_sym = std::make_unique(&eq_name, range()); + + std::vector list; + list.emplace_back(std::move(c)); + list.emplace_back(std::move(and_sym)); + list.emplace_back(std::move(c2)); + list.emplace_back(std::move(eq_sym)); + + ca_expr_list expr_list(std::move(list), range()); + expr_list.resolve_expression_tree(context::SET_t_enum::B_TYPE); + + ASSERT_FALSE(expr_list.diags().empty()); + } +} diff --git a/parser_library/test/expressions/ca_function_test.cpp b/parser_library/test/expressions/ca_function_test.cpp new file mode 100644 index 000000000..7731fb482 --- /dev/null +++ b/parser_library/test/expressions/ca_function_test.cpp @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2019 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 "gmock/gmock.h" + +#include "expr_mocks.h" +#include "expressions/conditional_assembly/terms/ca_function.h" +#include "expressions/evaluation_context.h" + +using namespace std::string_literals; +using namespace hlasm_plugin::parser_library; +using namespace hlasm_plugin::parser_library::expressions; + +struct func_test_param +{ + ca_expr_funcs function; + std::vector params; + context::SET_t true_result; + bool erroneous; + std::string name; +}; + +std::ostream& operator<<(std::ostream& os, const func_test_param& param) +{ + for (auto& p : param.params) + { + if (p.type == context::SET_t_enum::A_TYPE) + os << p.access_a(); + else if (p.type == context::SET_t_enum::B_TYPE) + os << p.access_b(); + else if (p.type == context::SET_t_enum::C_TYPE) + os << p.access_c(); + os << " "; + } + return os; +} + +struct stringer +{ + std::string operator()(::testing::TestParamInfo p) { return p.param.name; } +}; + +class set_expr : public ca_expression +{ +public: + context::SET_t value; + + set_expr(context::SET_t value) + : ca_expression(context::SET_t_enum::A_TYPE, range()) + , value(std::move(value)) + {} + + virtual undef_sym_set get_undefined_attributed_symbols(const context::dependency_solver&) const override + { + return {}; + }; + + virtual void resolve_expression_tree(context::SET_t_enum) override {} + + virtual bool is_character_expression() const override { return false; } + + virtual context::SET_t evaluate(const evaluation_context&) const override { return value; } + + virtual void collect_diags() const override {} +}; + +class ca_func : public ::testing::TestWithParam +{ +protected: + context::hlasm_context ctx; + attr_prov_mock attr; + lib_prov_mock lib; + evaluation_context eval_ctx { ctx, attr, lib }; + + context::SET_t get_result() + { + std::vector params; + for (auto& param : GetParam().params) + params.push_back(std::make_unique(std::move(param))); + + + ca_function f(nullptr, GetParam().function, std::move(params), nullptr, range()); + + return f.evaluate(eval_ctx); + } +}; + +INSTANTIATE_TEST_SUITE_P(func_parameters_suite, + ca_func, + ::testing::Values(func_test_param { ca_expr_funcs::B2A, { "" }, 0, false, "B2A_empty" }, + func_test_param { ca_expr_funcs::B2A, { "0000000101" }, 5, false, "B2A_padding" }, + func_test_param { ca_expr_funcs::B2A, { "11111111111111111111111111111110" }, -2, false, "B2A_whole" }, + func_test_param { ca_expr_funcs::B2A, { "1021" }, {}, true, "B2A_bad_char" }, + func_test_param { ca_expr_funcs::B2A, { "111111111111111111111111111111101" }, {}, true, "B2A_exceeds" }, + + func_test_param { ca_expr_funcs::C2A, { "" }, 0, false, "C2A_empty" }, + func_test_param { ca_expr_funcs::C2A, { "+" }, 78, false, "C2A_padding" }, + func_test_param { ca_expr_funcs::C2A, { "0000" }, -252645136, false, "C2A_whole" }, + func_test_param { ca_expr_funcs::C2A, { "00001" }, {}, true, "C2A_exceeds" }, + + func_test_param { ca_expr_funcs::D2A, { "" }, 0, false, "D2A_empty" }, + func_test_param { ca_expr_funcs::D2A, { "000" }, 0, false, "D2A_zeros" }, + func_test_param { ca_expr_funcs::D2A, { "10" }, 10, false, "D2A_basic" }, + func_test_param { ca_expr_funcs::D2A, { "+12" }, 12, false, "D2A_leading_plus" }, + func_test_param { ca_expr_funcs::D2A, { "-45" }, -45, false, "D2A_leading_minus" }, + func_test_param { ca_expr_funcs::D2A, { "0f1" }, {}, true, "D2A_bad_char" }, + func_test_param { ca_expr_funcs::D2A, { "0000000000001" }, {}, true, "D2A_too_large" }, + func_test_param { ca_expr_funcs::D2A, { "99999999999" }, {}, true, "D2A_overflow" }, + func_test_param { ca_expr_funcs::D2A, { "+" }, {}, true, "D2A_only_sign" }, + func_test_param { ca_expr_funcs::D2A, { "--1" }, {}, true, "D2A_multiple_signs" }, + + func_test_param { ca_expr_funcs::DCLEN, { "" }, 0, false, "DCLEN_empty" }, + func_test_param { ca_expr_funcs::DCLEN, { "'" }, 1, false, "DCLEN_single_apo" }, + func_test_param { ca_expr_funcs::DCLEN, { "''" }, 1, false, "DCLEN_double_apo" }, + func_test_param { ca_expr_funcs::DCLEN, { "&&" }, 1, false, "DCLEN_single_amp" }, + func_test_param { ca_expr_funcs::DCLEN, { "a''b" }, 3, false, "DCLEN_apo_char" }, + func_test_param { ca_expr_funcs::DCLEN, { "a''b&&c" }, 5, false, "DCLEN_apo_amp_char" }, + + func_test_param { ca_expr_funcs::FIND, { "abcdef", "cde" }, 3, false, "FIND_basic1" }, + func_test_param { ca_expr_funcs::FIND, { "abcdef", "gde" }, 4, false, "FIND_basic2" }, + func_test_param { ca_expr_funcs::FIND, { "", "" }, 0, false, "FIND_empty" }, + func_test_param { ca_expr_funcs::FIND, { "", "a" }, 0, false, "FIND_l_empty" }, + func_test_param { ca_expr_funcs::FIND, { "a", "" }, 0, false, "FIND_r_empty" }, + + func_test_param { ca_expr_funcs::INDEX, { "abc", "b" }, 2, false, "INDEX_found" }, + func_test_param { ca_expr_funcs::INDEX, { "abc", "ca" }, 0, false, "INDEX_not_found" }, + + func_test_param { ca_expr_funcs::ISBIN, { "10101" }, 1, false, "ISBIN_valid" }, + func_test_param { ca_expr_funcs::ISBIN, { "101010101010101010101010101010101" }, 0, false, "ISBIN_exceeds" }, + func_test_param { ca_expr_funcs::ISBIN, { "1210" }, 0, false, "ISBIN_bad_char" }, + func_test_param { ca_expr_funcs::ISBIN, { "" }, {}, true, "ISBIN_empty" }, + + func_test_param { ca_expr_funcs::ISDEC, { "12345678" }, 1, false, "ISDEC_valid" }, + func_test_param { ca_expr_funcs::ISDEC, { "+25" }, 0, false, "ISDEC_bad_char" }, + func_test_param { ca_expr_funcs::ISDEC, { "2147483648" }, 0, false, "ISDEC_overflow" }, + func_test_param { ca_expr_funcs::ISDEC, { "00000000005" }, 0, false, "ISDEC_exceeds" }, + func_test_param { ca_expr_funcs::ISDEC, { "" }, {}, true, "ISDEC_empty" }, + + func_test_param { ca_expr_funcs::ISHEX, { "ab34CD9F" }, 1, false, "ISHEX_valid" }, + func_test_param { ca_expr_funcs::ISHEX, { "abcdEFGH" }, 0, false, "ISHEX_bad_char" }, + func_test_param { ca_expr_funcs::ISHEX, { "123456789" }, 0, false, "ISHEX_exceeds" }, + func_test_param { ca_expr_funcs::ISHEX, { "" }, {}, true, "ISHEX_empty" }, + + func_test_param { ca_expr_funcs::ISSYM, { "Abcd_1234" }, 1, false, "ISSYM_valid1" }, + func_test_param { ca_expr_funcs::ISSYM, { "_abcd1234" }, 1, false, "ISSYM_valid2" }, + func_test_param { ca_expr_funcs::ISSYM, { "##@$_" }, 1, false, "ISSYM_valid3" }, + func_test_param { ca_expr_funcs::ISSYM, { "1234_Abcd" }, 0, false, "ISSYM_invalid" }, + func_test_param { ca_expr_funcs::ISSYM, { "" }, {}, true, "ISSYM_empty" }, + + func_test_param { ca_expr_funcs::X2A, { "" }, 0, false, "X2A_empty" }, + func_test_param { ca_expr_funcs::X2A, { "C1" }, 193, false, "X2A_padding" }, + func_test_param { ca_expr_funcs::X2A, { "FFFFfFF0" }, -16, false, "X2A_whole" }, + func_test_param { ca_expr_funcs::X2A, { "FfFFFFF00" }, {}, true, "X2A_exceeds" }, + func_test_param { ca_expr_funcs::X2A, { "FFFfG0" }, {}, true, "X2A_bad_char" }, + + func_test_param { ca_expr_funcs::A2B, { 0 }, "00000000000000000000000000000000", false, "A2B_zero" }, + func_test_param { ca_expr_funcs::A2B, { 1022 }, "00000000000000000000001111111110", false, "A2B_positive" }, + func_test_param { ca_expr_funcs::A2B, { -7 }, "11111111111111111111111111111001", false, "A2B_negative" }, + + func_test_param { ca_expr_funcs::A2C, { 0 }, "\0\0\0\0"s, false, "A2C_zero" }, + func_test_param { ca_expr_funcs::A2C, { 241 }, "\0\0\0"s + "1", false, "A2C_positive" }, + func_test_param { ca_expr_funcs::A2C, { -252645136 }, "0000", false, "A2C_negative" }, + + func_test_param { ca_expr_funcs::A2D, { 0 }, "+0", false, "A2D_zero" }, + func_test_param { ca_expr_funcs::A2D, { 241 }, "+241", false, "A2D_positive" }, + func_test_param { ca_expr_funcs::A2D, { -3 }, "-3", false, "A2D_negative" }, + + func_test_param { ca_expr_funcs::A2X, { 0 }, "00000000", false, "A2X_zero" }, + func_test_param { ca_expr_funcs::A2X, { 1022 }, "000003FE", false, "A2X_positive" }, + func_test_param { ca_expr_funcs::A2X, { -7 }, "FFFFFFF9", false, "A2X_negative" }, + + func_test_param { ca_expr_funcs::B2C, { "101110011110001" }, "*1", false, "B2C_valid" }, + func_test_param { ca_expr_funcs::B2C, { "0" }, "\0"s, false, "B2C_padding" }, + func_test_param { ca_expr_funcs::B2C, { "00010010001" }, "\0j"s, false, "B2C_padding_zero" }, + func_test_param { ca_expr_funcs::B2C, { "" }, "", false, "B2C_empty" }, + func_test_param { ca_expr_funcs::B2C, { "12" }, {}, true, "B2C_bad_char" }, + + func_test_param { ca_expr_funcs::B2D, { "11110001" }, "+241", false, "B2D_positive" }, + func_test_param { ca_expr_funcs::B2D, { "11111111111111111111111111110001" }, "-15", false, "B2D_negative" }, + func_test_param { ca_expr_funcs::B2D, { "" }, "+0", false, "B2D_empty" }, + func_test_param { ca_expr_funcs::B2D, { "111111111111111111111111111100011" }, {}, true, "B2D_exceeds" }, + func_test_param { ca_expr_funcs::B2D, { "12" }, {}, true, "B2D_bad_char" }, + + func_test_param { ca_expr_funcs::B2X, { "0000010010001" }, "0091", false, "B2X_padding" }, + func_test_param { ca_expr_funcs::B2X, { "" }, "", false, "B2X_empty" }, + func_test_param { ca_expr_funcs::B2X, { "12" }, {}, true, "B2X_bad_char" }, + + func_test_param { ca_expr_funcs::BYTE, { 0 }, "\0"s, false, "BYTE_zero" }, + func_test_param { ca_expr_funcs::BYTE, { 97 }, "/", false, "BYTE_valid" }, + func_test_param { ca_expr_funcs::BYTE, { 2000 }, {}, true, "BYTE_exceeds" }, + + func_test_param { ca_expr_funcs::C2B, { "" }, "", false, "C2B_empty" }, + func_test_param { ca_expr_funcs::C2B, { "\0"s }, "00000000", false, "C2B_zero" }, + func_test_param { ca_expr_funcs::C2B, { "1234" }, "11110001111100101111001111110100", false, "C2B_valid" }, + func_test_param { ca_expr_funcs::C2B, { big_string() }, {}, true, "C2B_exceeds" }, + + func_test_param { ca_expr_funcs::C2D, { "" }, "+0", false, "C2D_empty" }, + func_test_param { ca_expr_funcs::C2D, { "\0"s }, "+0", false, "C2D_zero" }, + func_test_param { ca_expr_funcs::C2D, { "\0j"s }, "+145", false, "C2D_positive" }, + func_test_param { ca_expr_funcs::C2D, { "0000" }, "-252645136", false, "C2D_negative" }, + func_test_param { ca_expr_funcs::C2D, { big_string() }, {}, true, "C2D_exceeds" }, + + func_test_param { ca_expr_funcs::C2X, { "" }, "", false, "C2X_empty" }, + func_test_param { ca_expr_funcs::C2X, { "\0"s }, "00", false, "C2X_zero" }, + func_test_param { ca_expr_funcs::C2X, { "1234567R" }, "F1F2F3F4F5F6F7D9", false, "C2X_valid" }, + func_test_param { ca_expr_funcs::C2X, { big_string() }, {}, true, "C2X_exceeds" }, + + func_test_param { ca_expr_funcs::D2B, { "" }, "", false, "D2B_empty" }, + func_test_param { ca_expr_funcs::D2B, { "000" }, "00000000000000000000000000000000", false, "D2B_zeros" }, + func_test_param { ca_expr_funcs::D2B, { "1022" }, "00000000000000000000001111111110", false, "D2B_basic" }, + func_test_param { ca_expr_funcs::D2B, { "+5" }, "00000000000000000000000000000101", false, "D2B_leading_plus" }, + func_test_param { + ca_expr_funcs::D2B, { "-7" }, "11111111111111111111111111111001", false, "D2B_leading_minus" }, + func_test_param { ca_expr_funcs::D2B, { "0f1" }, {}, true, "D2B_bad_char" }, + func_test_param { ca_expr_funcs::D2B, { "0000000000001" }, {}, true, "D2B_too_large" }, + func_test_param { ca_expr_funcs::D2B, { "99999999999" }, {}, true, "D2B_overflow" }, + func_test_param { ca_expr_funcs::D2B, { "+" }, {}, true, "D2B_only_sign" }, + func_test_param { ca_expr_funcs::D2B, { "--1" }, {}, true, "D2B_multiple_signs" }, + + func_test_param { ca_expr_funcs::D2C, { "" }, {}, true, "D2C_empty" }, + func_test_param { ca_expr_funcs::D2C, { "000" }, "\0\0\0\0"s, false, "D2C_zeros" }, + func_test_param { ca_expr_funcs::D2C, { "23793" }, "\0\0*1"s, false, "D2C_basic" }, + func_test_param { ca_expr_funcs::D2C, { "0f1" }, {}, true, "D2C_bad_char" }, + func_test_param { ca_expr_funcs::D2C, { "0000000000001" }, {}, true, "D2C_too_large" }, + func_test_param { ca_expr_funcs::D2C, { "99999999999" }, {}, true, "D2C_overflow" }, + func_test_param { ca_expr_funcs::D2C, { "+" }, {}, true, "D2C_only_sign" }, + func_test_param { ca_expr_funcs::D2C, { "--1" }, {}, true, "D2C_multiple_signs" }, + + func_test_param { ca_expr_funcs::D2X, { "" }, {}, true, "D2X_empty" }, + func_test_param { ca_expr_funcs::D2X, { "000" }, "00000000", false, "D2X_zeros" }, + func_test_param { ca_expr_funcs::D2X, { "1022" }, "000003FE", false, "D2X_basic" }, + func_test_param { ca_expr_funcs::D2X, { "+5" }, "00000005", false, "D2X_leading_plus" }, + func_test_param { ca_expr_funcs::D2X, { "-7" }, "FFFFFFF9", false, "D2X_leading_minus" }, + func_test_param { ca_expr_funcs::D2X, { "0f1" }, {}, true, "D2X_bad_char" }, + func_test_param { ca_expr_funcs::D2X, { "0000000000001" }, {}, true, "D2X_too_large" }, + func_test_param { ca_expr_funcs::D2X, { "99999999999" }, {}, true, "D2X_overflow" }, + func_test_param { ca_expr_funcs::D2X, { "+" }, {}, true, "D2X_only_sign" }, + func_test_param { ca_expr_funcs::D2X, { "--1" }, {}, true, "D2X_multiple_signs" }, + + func_test_param { ca_expr_funcs::DCVAL, { "" }, "", false, "DCVAL_empty" }, + func_test_param { ca_expr_funcs::DCVAL, { "'" }, "'", false, "DCVAL_single_apo" }, + func_test_param { ca_expr_funcs::DCVAL, { "''" }, "'", false, "DCVAL_double_apo" }, + func_test_param { ca_expr_funcs::DCVAL, { "&&" }, "&", false, "DCVAL_single_amp" }, + func_test_param { ca_expr_funcs::DCVAL, { "a''b" }, "a'b", false, "DCVAL_apo_char" }, + func_test_param { ca_expr_funcs::DCVAL, { "a''b&&c" }, "a'b&c", false, "DCVAL_apo_amp_char" }, + + func_test_param { ca_expr_funcs::DEQUOTE, { "adam" }, "adam", false, "DEQUOTE_char" }, + func_test_param { ca_expr_funcs::DEQUOTE, { "" }, "", false, "DEQUOTE_empty" }, + func_test_param { ca_expr_funcs::DEQUOTE, { "''abc'''" }, "'abc''", false, "DEQUOTE_apo_char" }, + func_test_param { ca_expr_funcs::DEQUOTE, { "''" }, "", false, "DEQUOTE_apo" }, + func_test_param { ca_expr_funcs::DEQUOTE, { "'a" }, "a", false, "DEQUOTE_apo_char_one_side" }, + func_test_param { ca_expr_funcs::DEQUOTE, { "'" }, "", false, "DEQUOTE_apo_one_side" }, + + func_test_param { ca_expr_funcs::DOUBLE, { "a&&''&b" }, "a&&&&''''&&b", false, "DOUBLE_simple" }, + func_test_param { ca_expr_funcs::DOUBLE, { big_string('\'') }, {}, true, "DOUBLE_exceeds" }, + + func_test_param { ca_expr_funcs::LOWER, { "aBcDefG321&^%$" }, "abcdefg321&^%$", false, "LOWER_simple" }, + + func_test_param { ca_expr_funcs::SIGNED, { 0 }, "0", false, "SIGNED_zero" }, + func_test_param { ca_expr_funcs::SIGNED, { 241 }, "241", false, "SIGNED_positive" }, + func_test_param { ca_expr_funcs::SIGNED, { -3 }, "-3", false, "SIGNED_negative" }, + + func_test_param { ca_expr_funcs::UPPER, { "aBcDefG321&^%$" }, "ABCDEFG321&^%$", false, "UPPER_simple" }, + + func_test_param { ca_expr_funcs::X2B, { "" }, "", false, "X2B_empty" }, + func_test_param { ca_expr_funcs::X2B, { "00" }, "00000000", false, "X2B_zeros" }, + func_test_param { ca_expr_funcs::X2B, { "f3" }, "11110011", false, "X2B_basic" }, + func_test_param { ca_expr_funcs::X2B, { "0g1" }, {}, true, "X2B_bad_char" }, + func_test_param { ca_expr_funcs::X2B, { big_string() }, {}, true, "X2B_exceeds" }, + + func_test_param { ca_expr_funcs::X2C, { "" }, "", false, "X2C_empty" }, + func_test_param { ca_expr_funcs::X2C, { "0" }, "\0"s, false, "X2C_zeros" }, + func_test_param { ca_expr_funcs::X2C, { "F1f2F3F4F5" }, "12345", false, "X2C_basic" }, + func_test_param { ca_expr_funcs::X2C, { "000F1" }, "\0\0"s + "1", false, "X2C_basic2" }, + func_test_param { ca_expr_funcs::X2C, { "0g1" }, {}, true, "X2C_bad_char" }, + + func_test_param { ca_expr_funcs::X2D, { "" }, "+0", false, "X2D_empty" }, + func_test_param { ca_expr_funcs::X2D, { "00" }, "+0", false, "X2D_zeros" }, + func_test_param { ca_expr_funcs::X2D, { "7FFfFFFF" }, "+2147483647", false, "X2D_positive" }, + func_test_param { ca_expr_funcs::X2D, { "FFFFfFF1" }, "-15", false, "X2D_negative" }, + func_test_param { ca_expr_funcs::X2D, { "0g1" }, {}, true, "X2D_bad_char" }, + func_test_param { ca_expr_funcs::X2D, { "000000f000" }, {}, true, "X2D_exceeds" }), + stringer()); + +TEST_P(ca_func, test) +{ + auto result = get_result(); + + ASSERT_EQ(eval_ctx.diags().size(), GetParam().erroneous); + + if (!GetParam().erroneous) + { + ASSERT_EQ(result.type, GetParam().true_result.type); + + if (result.type == context::SET_t_enum::A_TYPE) + EXPECT_EQ(result.access_a(), GetParam().true_result.access_a()); + else if (result.type == context::SET_t_enum::B_TYPE) + EXPECT_EQ(result.access_b(), GetParam().true_result.access_b()); + else if (result.type == context::SET_t_enum::C_TYPE) + EXPECT_EQ(result.access_c(), GetParam().true_result.access_c()); + else + FAIL(); + } +} diff --git a/parser_library/test/expressions/ca_operator_test.cpp b/parser_library/test/expressions/ca_operator_test.cpp new file mode 100644 index 000000000..7526d8ad0 --- /dev/null +++ b/parser_library/test/expressions/ca_operator_test.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2019 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 "gmock/gmock.h" + +#include "expr_mocks.h" +#include "expressions/conditional_assembly/ca_operator_binary.h" +#include "expressions/conditional_assembly/ca_operator_unary.h" +#include "expressions/conditional_assembly/terms/ca_constant.h" +#include "expressions/conditional_assembly/terms/ca_string.h" +#include "expressions/evaluation_context.h" + +using namespace std::string_literals; +using namespace hlasm_plugin::parser_library; +using namespace hlasm_plugin::parser_library::expressions; +using namespace hlasm_plugin::parser_library::context; + +struct op_test_param +{ + ca_expr_ops operation; + SET_t_enum kind; + std::vector params; + SET_t true_result; + std::string name; +}; + +std::ostream& operator<<(std::ostream& os, const op_test_param& param) +{ + for (auto& p : param.params) + { + if (p.type == context::SET_t_enum::A_TYPE) + os << p.access_a(); + else if (p.type == context::SET_t_enum::B_TYPE) + os << p.access_b(); + else if (p.type == context::SET_t_enum::C_TYPE) + os << p.access_c(); + os << " "; + } + return os; +} + +struct stringer +{ + std::string operator()(::testing::TestParamInfo p) { return p.param.name; } +}; + +class ca_op : public ::testing::TestWithParam +{ +protected: + hlasm_context ctx; + attr_prov_mock attr; + lib_prov_mock prov; + evaluation_context eval_ctx { ctx, attr, prov }; + + SET_t get_result() + { + if (GetParam().operation == ca_expr_ops::NOT || GetParam().kind == SET_t_enum::C_TYPE) + { + ca_function_unary_operator op(nullptr, GetParam().operation, GetParam().kind, range()); + + return op.operation(GetParam().params[0], eval_ctx); + } + else + { + ca_expr_ptr left; + if (GetParam().params[0].type == SET_t_enum::A_TYPE) + left = std::make_unique(1, range()); + else + left = + std::make_unique(semantics::concat_chain {}, nullptr, ca_string::substring_t(), range()); + + ca_function_binary_operator op(std::move(left), nullptr, GetParam().operation, GetParam().kind, range()); + + return op.operation(GetParam().params[0], GetParam().params[1], eval_ctx); + } + } +}; + +INSTANTIATE_TEST_SUITE_P(op_parameters_suite, + ca_op, + ::testing::Values(op_test_param { ca_expr_ops::SLA, SET_t_enum::A_TYPE, { 2, 2 }, 8, "SLA_positive" }, + op_test_param { ca_expr_ops::SLA, SET_t_enum::A_TYPE, { -2, 2 }, -8, "SLA_negative_zero" }, + op_test_param { ca_expr_ops::SLA, SET_t_enum::A_TYPE, { -2147483647, 1 }, -2147483646, "SLA_negative_one" }, + op_test_param { ca_expr_ops::SLA, SET_t_enum::A_TYPE, { 2, -2147483646 }, 8, "SLA_trunc" }, + + op_test_param { ca_expr_ops::SLL, SET_t_enum::A_TYPE, { 10, 2 }, 40, "SLL_positive" }, + op_test_param { ca_expr_ops::SLL, SET_t_enum::A_TYPE, { -2, 2 }, -8, "SLL_negative_zero" }, + op_test_param { ca_expr_ops::SLL, SET_t_enum::A_TYPE, { -2147483647, 1 }, 2, "SLL_negative_one" }, + op_test_param { ca_expr_ops::SLL, SET_t_enum::A_TYPE, { 2, -2147483646 }, 8, "SLL_trunc" }, + + op_test_param { ca_expr_ops::SRA, SET_t_enum::A_TYPE, { 10, 2 }, 2, "SRA_positive" }, + op_test_param { ca_expr_ops::SRA, SET_t_enum::A_TYPE, { -344, 40 }, -1, "SRA_negative_all" }, + op_test_param { ca_expr_ops::SRA, SET_t_enum::A_TYPE, { -2147483390, 2 }, -536870848, "SRA_negative_some" }, + op_test_param { ca_expr_ops::SRA, SET_t_enum::A_TYPE, { 10, -2147483646 }, 2, "SRA_trunc" }, + + op_test_param { ca_expr_ops::SRL, SET_t_enum::A_TYPE, { 10, 2 }, 2, "SRL_positive" }, + op_test_param { ca_expr_ops::SRL, SET_t_enum::A_TYPE, { -344, 40 }, 0, "SRL_negative_all" }, + op_test_param { ca_expr_ops::SRL, SET_t_enum::A_TYPE, { -2147483390, 2 }, 536870976, "SRL_negative_some" }, + op_test_param { ca_expr_ops::SRL, SET_t_enum::A_TYPE, { 10, -2147483646 }, 2, "SRL_trunc" }, + + op_test_param { ca_expr_ops::FIND, SET_t_enum::A_TYPE, { "abcdef", "cde" }, 3, "FIND" }, + + op_test_param { ca_expr_ops::INDEX, SET_t_enum::A_TYPE, { "abc", "b" }, 2, "INDEX" }, + + op_test_param { ca_expr_ops::AND, SET_t_enum::A_TYPE, { 10, 2 }, 2, "ANDA" }, + op_test_param { ca_expr_ops::OR, SET_t_enum::A_TYPE, { 10, 2 }, 10, "ORA" }, + op_test_param { ca_expr_ops::XOR, SET_t_enum::A_TYPE, { 10, 2 }, 8, "XORA" }, + op_test_param { ca_expr_ops::NOT, SET_t_enum::A_TYPE, { 10 }, -11, "NOTA" }, + + op_test_param { ca_expr_ops::AND, SET_t_enum::B_TYPE, { false, true }, false, "ANDB" }, + op_test_param { ca_expr_ops::AND_NOT, SET_t_enum::B_TYPE, { true, false }, true, "AND_NOT" }, + op_test_param { ca_expr_ops::OR, SET_t_enum::B_TYPE, { false, true }, true, "ORB" }, + op_test_param { ca_expr_ops::OR_NOT, SET_t_enum::B_TYPE, { false, true }, false, "OR_NOT" }, + op_test_param { ca_expr_ops::XOR, SET_t_enum::B_TYPE, { false, true }, true, "XORB" }, + op_test_param { ca_expr_ops::XOR_NOT, SET_t_enum::B_TYPE, { true, false }, false, "XOR_NOT" }, + op_test_param { ca_expr_ops::NOT, SET_t_enum::B_TYPE, { false }, true, "NOTB" }, + + op_test_param { ca_expr_ops::EQ, SET_t_enum::B_TYPE, { 1, 0 }, false, "EQA" }, + op_test_param { ca_expr_ops::NE, SET_t_enum::B_TYPE, { 1, 0 }, true, "NEA" }, + op_test_param { ca_expr_ops::LE, SET_t_enum::B_TYPE, { 1, 0 }, false, "LEA" }, + op_test_param { ca_expr_ops::LT, SET_t_enum::B_TYPE, { 1, 0 }, false, "LTA" }, + op_test_param { ca_expr_ops::GE, SET_t_enum::B_TYPE, { 1, 0 }, true, "GEA" }, + op_test_param { ca_expr_ops::GT, SET_t_enum::B_TYPE, { 1, 0 }, true, "GTA" }, + + op_test_param { ca_expr_ops::EQ, SET_t_enum::B_TYPE, { "ab", "c" }, false, "EQB" }, + op_test_param { ca_expr_ops::EQ, SET_t_enum::B_TYPE, { "ab", "ac" }, false, "EQB_same_length" }, + op_test_param { ca_expr_ops::NE, SET_t_enum::B_TYPE, { "ab", "c" }, true, "NEB" }, + op_test_param { ca_expr_ops::LE, SET_t_enum::B_TYPE, { "ab", "c" }, false, "LEB" }, + op_test_param { ca_expr_ops::LE, SET_t_enum::B_TYPE, { "ab", "ac" }, true, "LEB_same_length" }, + op_test_param { ca_expr_ops::LT, SET_t_enum::B_TYPE, { "ab", "c" }, false, "LTB" }, + op_test_param { ca_expr_ops::GE, SET_t_enum::B_TYPE, { "ab", "c" }, true, "GEB" }, + op_test_param { ca_expr_ops::GT, SET_t_enum::B_TYPE, { "ab", "c" }, true, "GTB" }, + + op_test_param { ca_expr_ops::BYTE, SET_t_enum::C_TYPE, { 97 }, "/", "BYTE" }, + + op_test_param { ca_expr_ops::DOUBLE, SET_t_enum::C_TYPE, { "a&&''&b" }, "a&&&&''''&&b", "DOUBLE" }, + + op_test_param { ca_expr_ops::LOWER, SET_t_enum::C_TYPE, { "aBcDefG321&^%$" }, "abcdefg321&^%$", "LOWER" }, + + op_test_param { ca_expr_ops::SIGNED, SET_t_enum::C_TYPE, { 0 }, "0", "SIGNED" }, + + op_test_param { ca_expr_ops::UPPER, SET_t_enum::C_TYPE, { "aBcDefG321&^%$" }, "ABCDEFG321&^%$", "UPPER" }), + + stringer()); + +TEST_P(ca_op, test) +{ + auto result = get_result(); + + ASSERT_EQ(result.type, GetParam().true_result.type); + + if (result.type == SET_t_enum::A_TYPE) + EXPECT_EQ(result.access_a(), GetParam().true_result.access_a()); + else if (result.type == SET_t_enum::B_TYPE) + EXPECT_EQ(result.access_b(), GetParam().true_result.access_b()); + else if (result.type == SET_t_enum::C_TYPE) + EXPECT_EQ(result.access_c(), GetParam().true_result.access_c()); + else + FAIL(); +} diff --git a/parser_library/test/expressions/ca_string_test.cpp b/parser_library/test/expressions/ca_string_test.cpp new file mode 100644 index 000000000..4274b32d8 --- /dev/null +++ b/parser_library/test/expressions/ca_string_test.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2019 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 "gmock/gmock.h" + +#include "expr_mocks.h" +#include "expressions/conditional_assembly/terms/ca_constant.h" +#include "expressions/conditional_assembly/terms/ca_string.h" +#include "expressions/evaluation_context.h" + +using namespace hlasm_plugin::parser_library::expressions; +using namespace hlasm_plugin::parser_library::semantics; +using namespace hlasm_plugin::parser_library; + +TEST(ca_string, undefined_attributes) +{ + dep_sol_mock m; + + concat_chain value; + value.push_back(std::make_unique("gfds")); + + ca_expr_ptr dupl = std::make_unique(1, range()); + + ca_string::substring_t substr; + substr.start = std::make_unique(1, range()); + substr.count = std::make_unique(1, range()); + + + ca_string s(std::move(value), std::move(dupl), std::move(substr), range()); + + auto res = s.get_undefined_attributed_symbols(m); + + ASSERT_EQ(res.size(), 0U); +} + +struct test_param +{ + std::string value; + int factor; + std::string result; + bool error; + std::string name; +}; + +struct stringer +{ + std::string operator()(::testing::TestParamInfo p) { return p.param.name; } +}; + +class ca_string_suite : public ::testing::TestWithParam +{}; + +INSTANTIATE_TEST_SUITE_P(param_suite, + ca_string_suite, + ::testing::Values(test_param { "abc", 0, "", false, "dupl_zero" }, + test_param { "abc", -5, "", true, "dupl_negative" }, + test_param { big_string() + big_string(), 1, "", true, "too_big_value" }, + test_param { big_string(), 2, "", true, "too_big_dupl_factor" }), + stringer()); + +TEST(ca_string, test) +{ + concat_chain value; + value.push_back(std::make_unique("gfds")); + + ca_expr_ptr dupl = std::make_unique(0, range()); + + ca_string s(std::move(value), std::move(dupl), ca_string::substring_t(), range()); + + context::hlasm_context ctx; + attr_prov_mock a; + lib_prov_mock l; + + evaluation_context eval { ctx, a, l }; + + auto res = s.evaluate(eval); + + ASSERT_EQ(eval.diags().size(), 0U); + + EXPECT_EQ(res.access_c(), ""); +} + +TEST_P(ca_string_suite, dupl) +{ + concat_chain value; + value.push_back(std::make_unique(GetParam().value)); + + ca_expr_ptr dupl = std::make_unique(GetParam().factor, range()); + + ca_string s(std::move(value), std::move(dupl), ca_string::substring_t(), range()); + + context::hlasm_context ctx; + attr_prov_mock a; + lib_prov_mock l; + + evaluation_context eval { ctx, a, l }; + + auto res = s.evaluate(eval); + + ASSERT_EQ(eval.diags().size(), GetParam().error); + + if (!GetParam().error) + EXPECT_EQ(res.access_c(), GetParam().result); +} diff --git a/parser_library/test/expressions/ca_symbol_attribute_test.cpp b/parser_library/test/expressions/ca_symbol_attribute_test.cpp new file mode 100644 index 000000000..ffe57b5d6 --- /dev/null +++ b/parser_library/test/expressions/ca_symbol_attribute_test.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2019 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 "gmock/gmock.h" + +#include "expr_mocks.h" +#include "expressions/conditional_assembly/terms/ca_constant.h" +#include "expressions/conditional_assembly/terms/ca_symbol_attribute.h" +#include "expressions/evaluation_context.h" + +using namespace hlasm_plugin::parser_library::expressions; +using namespace hlasm_plugin::parser_library::semantics; +using namespace hlasm_plugin::parser_library; + +TEST(ca_symbol_attr, undefined_attributes) +{ + dep_sol_mock m; + std::string name = "n"; + std::vector subscript; + + subscript.push_back(std::make_unique(1, range())); + + auto vs = std::make_unique(&name, std::move(subscript), range()); + + ca_symbol_attribute attr(std::move(vs), context::data_attr_kind::D, range()); + + auto res = attr.get_undefined_attributed_symbols(m); + + ASSERT_EQ(res.size(), 0U); +} + +ca_symbol_attribute create_var_sym_attr(context::data_attr_kind kind, context::id_storage& ids) +{ + auto name = ids.add("n"); + + auto vs = std::make_unique(name, std::vector {}, range()); + + return ca_symbol_attribute(std::move(vs), kind, range()); +} + +TEST(ca_symbol_attr, evaluate_undef_varsym) +{ + context::hlasm_context ctx; + attr_prov_mock a; + lib_prov_mock l; + + evaluation_context eval { ctx, a, l }; + + auto res = create_var_sym_attr(context::data_attr_kind::D, ctx.ids()).evaluate(eval); + + ASSERT_EQ(eval.diags().size(), 1U); + EXPECT_EQ(eval.diags().front().code, "E010"); +} + +TEST(ca_symbol_attr, evaluate_substituted_varsym_not_char) +{ + context::hlasm_context ctx; + attr_prov_mock a; + lib_prov_mock l; + auto name = ctx.ids().add("n"); + + auto var = ctx.create_local_variable(name, true); + var->access_set_symbol()->set_value(12); + + evaluation_context eval { ctx, a, l }; + + auto res = create_var_sym_attr(context::data_attr_kind::L, ctx.ids()).evaluate(eval); + + ASSERT_EQ(eval.diags().size(), 1U); + EXPECT_EQ(eval.diags().front().code, "E066"); +} + +TEST(ca_symbol_attr, evaluate_substituted_varsym_char_not_sym) +{ + context::hlasm_context ctx; + attr_prov_mock a; + lib_prov_mock l; + auto name = ctx.ids().add("n"); + + auto var = ctx.create_local_variable(name, true); + var->access_set_symbol()->set_value("(abc"); + + evaluation_context eval { ctx, a, l }; + + auto res = create_var_sym_attr(context::data_attr_kind::L, ctx.ids()).evaluate(eval); + + ASSERT_EQ(eval.diags().size(), 1U); + EXPECT_EQ(eval.diags().front().code, "E065"); +} diff --git a/parser_library/test/expressions/ca_symbol_test.cpp b/parser_library/test/expressions/ca_symbol_test.cpp new file mode 100644 index 000000000..2e04dcee2 --- /dev/null +++ b/parser_library/test/expressions/ca_symbol_test.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2019 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 "gmock/gmock.h" + +#include "diagnostic_adder.h" +#include "expr_mocks.h" +#include "expressions/conditional_assembly/terms/ca_symbol.h" + +using namespace hlasm_plugin::parser_library::expressions; +using namespace hlasm_plugin::parser_library::semantics; +using namespace hlasm_plugin::parser_library; + +TEST(ca_symbol, undefined_attributes) +{ + dep_sol_mock m; + std::string name = "n"; + + ca_symbol sym(&name, range()); + + auto res = sym.get_undefined_attributed_symbols(m); + + ASSERT_EQ(res.size(), 0U); +} + +TEST(ca_symbol, resolve_expr_tree) +{ + diagnostic_adder add_diags; + + ca_symbol sym(nullptr, range()); + + sym.resolve_expression_tree(context::SET_t_enum::C_TYPE); + + ASSERT_NE(sym.diags().size(), 0U); +} + +TEST(ca_symbol, is_char) { ASSERT_FALSE(ca_symbol(nullptr, range()).is_character_expression()); } diff --git a/parser_library/test/expressions/ca_var_sym_test.cpp b/parser_library/test/expressions/ca_var_sym_test.cpp new file mode 100644 index 000000000..3b507bab0 --- /dev/null +++ b/parser_library/test/expressions/ca_var_sym_test.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2019 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 "gmock/gmock.h" + +#include "expr_mocks.h" +#include "expressions/conditional_assembly/terms/ca_constant.h" +#include "expressions/conditional_assembly/terms/ca_var_sym.h" +#include "expressions/evaluation_context.h" + +using namespace hlasm_plugin::parser_library::expressions; +using namespace hlasm_plugin::parser_library::semantics; +using namespace hlasm_plugin::parser_library; + +TEST(ca_var_sym_basic, undefined_attributes) +{ + dep_sol_mock m; + std::string name = "n"; + std::vector subscript; + + subscript.push_back(std::make_unique(1, range())); + + auto vs = std::make_unique(&name, std::move(subscript), range()); + + ca_var_sym var(std::move(vs), range()); + + auto res = var.get_undefined_attributed_symbols(m); + + ASSERT_EQ(res.size(), 0U); +} + +TEST(ca_var_sym_created, undefined_attributes) +{ + dep_sol_mock m; + std::string name = "n"; + concat_chain created_name; + std::vector subscript; + + created_name.push_back(std::make_unique("n")); + + subscript.push_back(std::make_unique(1, range())); + + auto vs = std::make_unique(std::move(created_name), std::move(subscript), range()); + + ca_var_sym var(std::move(vs), range()); + + auto res = var.get_undefined_attributed_symbols(m); + + ASSERT_EQ(res.size(), 0U); +} diff --git a/parser_library/test/expressions/character_expression_test.cpp b/parser_library/test/expressions/character_expression_test.cpp new file mode 100644 index 000000000..95c213683 --- /dev/null +++ b/parser_library/test/expressions/character_expression_test.cpp @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2019 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" + +// test for +// arithmetic SETC expressions + +#define SETCEQ(X, Y) \ + EXPECT_EQ(a.context() \ + .get_var_sym(a.context().ids().add(X)) \ + ->access_set_symbol_base() \ + ->access_set_symbol() \ + ->get_value(), \ + Y) + +TEST(character_expresssion, operator_priority) +{ + std::string input = + R"( +&C SETC 'ABC'.(3)'ABCDEF'(4,3) +)"; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + ASSERT_EQ(a.diags().size(), (size_t)0); + + SETCEQ("C", "ABCDEFDEFDEF"); +} + +TEST(character_expresssion, substring_notation) +{ + std::string input = + R"( +&C1 SETC 'ABC'(1,3) +&C2 SETC '&C1'(1,2).'DEF' +&C3 SETC ''(0,0) +&C4 SETC 'XYZ'(2,*) +&C5 SETC 'XYZ'(1,0) +&C6 SETC (2)UPPER('x') +)"; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + ASSERT_EQ(a.diags().size(), (size_t)0); + + SETCEQ("C1", "ABC"); + SETCEQ("C2", "ABDEF"); + SETCEQ("C3", ""); + SETCEQ("C4", "YZ"); + SETCEQ("C5", ""); + SETCEQ("C6", "XX"); +} + +TEST(character_expresssion, invalid_substring_notation) +{ + std::string input = + R"( +&C SETC 'ABC'(0,1) +&C SETC 'ABCDE'(7,3) +&C SETC 'ABCDE'(6,*) +&C SETC 'ABCDE'(3,-2) +)"; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + ASSERT_EQ(a.diags().size(), (size_t)4); +} +/*uncomment when compiler options will be implemented +TEST(character_expresssion, exceeds_warning) +{ + std::string input = + R"( +&C SETC 'ABC'(2,3) +)"; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + ASSERT_EQ(a.diags().size(), (size_t)1); + EXPECT_EQ(a.diags().front().severity, diagnostic_severity::warning); +} +*/ +TEST(character_expresssion, invalid_string) +{ + std::string input = + R"( +&C SETC '&' +&C SETC (5000)'A' +)"; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + ASSERT_EQ(a.diags().size(), (size_t)2); +} + +TEST(character_expresssion, escaping) +{ + std::string input = + R"( +&C1 SETC 'L''SYMBOL' +&C2 SETC '&&'(1,1) +&C3 SETC 'HALF&&' +&C4 SETC '&C1..S' +&DOT SETC '.' +&C5 SETC 'A&DOT.&DOT' +&C6 SETC '&C2.A' +)"; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + ASSERT_EQ(a.diags().size(), (size_t)0); + + SETCEQ("C1", "L'SYMBOL"); + SETCEQ("C2", "&"); + SETCEQ("C3", "HALF&&"); + SETCEQ("C4", "L'SYMBOL.S"); + SETCEQ("C5", "A.."); + SETCEQ("C6", "&A"); +} diff --git a/parser_library/test/expressions/expr_mocks.h b/parser_library/test/expressions/expr_mocks.h new file mode 100644 index 000000000..2e1973076 --- /dev/null +++ b/parser_library/test/expressions/expr_mocks.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2019 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_TEST_EXPR_MOCK_H +#define HLASMPLUGIN_PARSERLIBRARY_TEST_EXPR_MOCK_H + +#include "processing/attribute_provider.h" +#include "workspaces/parse_lib_provider.h" + +using namespace hlasm_plugin::parser_library; + +class dep_sol_mock : public context::dependency_solver +{ + virtual const context::symbol* get_symbol(context::id_index) const { return nullptr; }; +}; + +class attr_prov_mock : public processing::attribute_provider +{ + virtual const resolved_reference_storage& lookup_forward_attribute_references(forward_reference_storage) override + { + static resolved_reference_storage st; + return st; + } +}; + +class lib_prov_mock : public workspaces::parse_lib_provider +{ + virtual workspaces::parse_result parse_library( + const std::string&, context::hlasm_context&, const workspaces::library_data) + { + return false; + }; + + virtual bool has_library(const std::string&, context::hlasm_context&) const { return false; } +}; + +inline std::string big_string(char c = '1') +{ + std::string s; + s.reserve(4000); + for (size_t i = 0; i < 4000; i++) + s.push_back(c); + return s; +} + +#endif diff --git a/parser_library/test/expressions/logical_expression_test.cpp b/parser_library/test/expressions/logical_expression_test.cpp new file mode 100644 index 000000000..8e5b8972e --- /dev/null +++ b/parser_library/test/expressions/logical_expression_test.cpp @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2019 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" + +// test for +// arithmetic SETB expressions + +#define SETBEQ(X, Y) \ + EXPECT_EQ(a.context() \ + .get_var_sym(a.context().ids().add(X)) \ + ->access_set_symbol_base() \ + ->access_set_symbol() \ + ->get_value(), \ + Y) + +TEST(logical_expressions, valid_assignment) +{ + std::string input = + R"( +&A1 SETB 1 +&A2 SETB 0 +)"; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + ASSERT_EQ(a.diags().size(), (size_t)0); + + SETBEQ("A1", 1); + SETBEQ("A2", 0); +} + +TEST(logical_expressions, invalid_assignment) +{ + std::string input = + R"( +&A1 SETB C'D' +&A2 SETB &A2 +&A3 SETB 10 +&A4 SETB -1 +)"; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + ASSERT_EQ(a.diags().size(), (size_t)4); +} + +TEST(logical_expressions, invalid_expression) +{ + std::string input = + R"( +NOT EQU 1 +&A1 SETB (AND AND 1) +&A2 SETB (1 AND NOT) +&C3 SETB (1 OR AND 1) +)"; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + ASSERT_EQ(a.diags().size(), (size_t)3); +} + +TEST(logical_expressions, valid_expression) +{ + std::string input = + R"( +AND EQU 1 +&A1 SETB (AND AND 1) +&A2 SETB (1 OR NOT 0) +&A3 SETB (1 OR AND) +&A4 SETB (NOT 1 AND NOT NOT 1) +)"; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + ASSERT_EQ(a.diags().size(), (size_t)0); + + SETBEQ("A1", 1); + SETBEQ("A2", 1); + SETBEQ("A3", 1); + SETBEQ("A4", 0); +} + +TEST(logical_expressions, valid_relational_expression) +{ + std::string input = + R"( +AND EQU 1 +&A1 SETB ('a' EQ 'A') +&A2 SETB ('a' LT 'A') +&A3 SETB ('abc' GT 'b') +&A4 SETB ('A' EQ UPPER('a')) +&A5 SETB (D2A('10') EQ 10) +)"; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + ASSERT_EQ(a.diags().size(), (size_t)0); + + SETBEQ("A1", 0); + SETBEQ("A2", 1); + SETBEQ("A3", 1); + SETBEQ("A4", 1); + SETBEQ("A5", 1); +} + +TEST(logical_expressions, invalid_relational_expression) +{ + std::string input = + R"( +&A1 SETB (UPPER('a') EQ 'A') +&A2 SETB (13 LT 'A') +&A3 SETB ('a' LT 12) +)"; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + ASSERT_EQ(a.diags().size(), (size_t)4); +} + +TEST(logical_expressions, priority) +{ + std::string input = + R"( +&A1 SETB (1 OR 1 EQ 0 OR 0) +&A2 SETB (1 AND NOT 0) +&A3 SETB (1 XOR 1 AND 0) +&A4 SETB (1 XOR 0 OR 1) 0 +&A5 SETB (1 AND 0 OR 1 AND 1) +&A6 SETB (NOT 0 AND NOT 0 AND 50 GT 126+4) +)"; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + ASSERT_EQ(a.diags().size(), (size_t)0); + + SETBEQ("A1", 1); + SETBEQ("A2", 1); + SETBEQ("A3", 1); + SETBEQ("A4", 0); + SETBEQ("A5", 1); + SETBEQ("A6", 0); +} + +TEST(logical_expressions, arithmetic_logical_clash) +{ + std::string input = + R"( +&A1 SETB (NOT 0 AND NOT 0 AND 50 GT 126+4) +&A2 SETB (1 AND 10 EQ (10 OR 2)) +)"; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + ASSERT_EQ(a.diags().size(), (size_t)0); + + SETBEQ("A1", 0); + SETBEQ("A2", 1); +} + +TEST(logical_expressions, no_spaces) +{ + std::string input = + R"( +&A1 SETB (NOT(0)) +&A2 SETB ((1)AND(1)) +&A3 SETB ('3'ge'2') +)"; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + ASSERT_EQ(a.diags().size(), (size_t)0); + + SETBEQ("A1", 1); + SETBEQ("A2", 1); + SETBEQ("A3", 1); +} + +TEST(logical_expressions, bad_number_of_operands) +{ + std::string input = + R"( +&A SETA FIND('A','B','C') +)"; + analyzer a(input); + a.analyze(); + + a.collect_diags(); + ASSERT_EQ(a.diags().size(), (size_t)1); + EXPECT_EQ(a.diags().front().code, "CE006"); +} diff --git a/parser_library/test/lexing/lexer_test.cpp b/parser_library/test/lexing/lexer_test.cpp index ea6e12e2a..2adf0ea09 100644 --- a/parser_library/test/lexing/lexer_test.cpp +++ b/parser_library/test/lexing/lexer_test.cpp @@ -22,6 +22,7 @@ #include "hlasmparser.h" #include "lexing/input_source.h" #include "lexing/lexer.h" +#include "lexing/token_stream.h" // tests lexer class: // AREAD, continuation statements, rewinding, token creation @@ -81,7 +82,7 @@ EOF hlasm_plugin::parser_library::semantics::lsp_info_processor lsp_proc = { "aread", "", nullptr, false }; hlasm_plugin::parser_library::lexing::input_source input(in); hlasm_plugin::parser_library::lexing::lexer l(&input, &lsp_proc); - antlr4::CommonTokenStream tokens(&l); + hlasm_plugin::parser_library::lexing::token_stream tokens(&l); parser parser(&tokens); l.ainsert_back("INSERTED BACK 1"); @@ -121,7 +122,7 @@ EOF hlasm_plugin::parser_library::semantics::lsp_info_processor lsp_proc = { "rntest", "", nullptr, false }; hlasm_plugin::parser_library::lexing::input_source input("TEST TEST \r\n TEST1 TEST2"); hlasm_plugin::parser_library::lexing::lexer l(&input, &lsp_proc); - antlr4::CommonTokenStream tokens(&l); + hlasm_plugin::parser_library::lexing::token_stream tokens(&l); parser parser(&tokens); tokens.fill(); @@ -145,7 +146,7 @@ TEST(lexer_test, new_line_in_ignored) label lr 1,1)"); hlasm_plugin::parser_library::lexing::lexer l(&input, &lsp_proc); - antlr4::CommonTokenStream tokens(&l); + hlasm_plugin::parser_library::lexing::token_stream tokens(&l); parser parser(&tokens); tokens.fill(); @@ -215,7 +216,7 @@ EOF hlasm_plugin::parser_library::semantics::lsp_info_processor lsp_proc = { "unlimited_line", "", nullptr, false }; hlasm_plugin::parser_library::lexing::input_source input(in); hlasm_plugin::parser_library::lexing::lexer l(&input, &lsp_proc); - antlr4::CommonTokenStream tokens(&l); + hlasm_plugin::parser_library::lexing::token_stream tokens(&l); parser parser(&tokens); l.set_unlimited_line(true); @@ -257,7 +258,7 @@ EOF hlasm_plugin::parser_library::lexing::input_source input(in); hlasm_plugin::parser_library::semantics::lsp_info_processor lsp_proc = { "rewind_input", "", nullptr, false }; hlasm_plugin::parser_library::lexing::lexer l(&input, &lsp_proc); - antlr4::CommonTokenStream tokens(&l); + hlasm_plugin::parser_library::lexing::token_stream tokens(&l); parser parser(&tokens); std::stringstream token_stream; diff --git a/parser_library/test/parsing/parser_test.cpp b/parser_library/test/parsing/parser_test.cpp index 4565e6cc6..5499c5b32 100644 --- a/parser_library/test/parsing/parser_test.cpp +++ b/parser_library/test/parsing/parser_test.cpp @@ -15,7 +15,6 @@ #include "gtest/gtest.h" #include "../common_testing.h" -#include "expressions/visitors/expression_evaluator.h" #include "parsing/parser_tools.h" // tests for @@ -44,31 +43,6 @@ class library_test : public testing::Test std::string input; }; -TEST_F(library_test, expression_test) -{ - std::string tcase = "expression_test"; - - setup(tcase); - auto tree = holder->parser().expr_test(); - context_manager m(holder->context()); - empty_attribute_provider attr_mock; - auto v = std::make_unique( - evaluation_context { holder->context(), attr_mock, empty_parse_lib_provider::instance }); - auto id = holder->context().ids().add("TEST_VAR"); - holder->context().create_local_variable(id, true); - holder->context().get_var_sym(id)->access_set_symbol_base()->access_set_symbol()->set_value(11); - - auto res = v->visit(tree).as(); - res.erase(std::remove(res.begin(), res.end(), '\r'), res.end()); - - std::string expected; - get_content("test/library/output/" + tcase + ".output", expected); - ASSERT_EQ(res, expected); - - // no errors found while parsing - ASSERT_EQ(holder->parser().getNumberOfSyntaxErrors(), size_t_zero); -} - // 3 instruction statements and 3 EOLLN TEST_F(library_test, simple) { diff --git a/parser_library/test/processing/ca_instr_test.cpp b/parser_library/test/processing/ca_instr_test.cpp index 09bbaa14f..7a6261d9e 100644 --- a/parser_library/test/processing/ca_instr_test.cpp +++ b/parser_library/test/processing/ca_instr_test.cpp @@ -98,7 +98,7 @@ TEST(var_subs, set_to_var) ASSERT_TRUE(ctx.get_var_sym(it)); - int tmp = m.get_var_sym_value(it, {}, {}).access_a(); + int tmp = m.get_var_sym_value(it, std::vector {}, {}).access_a(); EXPECT_EQ(tmp, 3); } @@ -114,8 +114,8 @@ TEST(var_subs, set_to_var_idx) auto it = ctx.ids().find("var"); ASSERT_TRUE(ctx.get_var_sym(it)); - std::vector subscript1; - subscript1.push_back(make_arith(2)); + std::vector subscript1; + subscript1.push_back(2); int tmp = m.get_var_sym_value(it, std::move(subscript1), {}).access_a(); EXPECT_EQ(tmp, 3); } @@ -141,16 +141,16 @@ TEST(var_subs, set_to_var_idx_many) ASSERT_TRUE(ctx.get_var_sym(it)); int tmp; - std::vector subscript1; - subscript1.push_back(make_arith(2)); + std::vector subscript1; + subscript1.push_back(2); tmp = m.get_var_sym_value(it, std::move(subscript1), {}).access_a(); EXPECT_EQ(tmp, 3); - std::vector subscript2; - subscript2.push_back(make_arith(3)); + std::vector subscript2; + subscript2.push_back(3); tmp = m.get_var_sym_value(it, std::move(subscript2), {}).access_a(); EXPECT_EQ(tmp, 4); - std::vector subscript3; - subscript3.push_back(make_arith(4)); + std::vector subscript3; + subscript3.push_back(4); tmp = m.get_var_sym_value(it, std::move(subscript3), {}).access_a(); EXPECT_EQ(tmp, 5); } @@ -168,7 +168,7 @@ TEST(var_subs, var_sym_reset) ASSERT_TRUE(ctx.get_var_sym(it)); - std::string tmp = m.get_var_sym_value(it, {}, {}).access_c(); + std::string tmp = m.get_var_sym_value(it, std::vector {}, {}).access_c(); EXPECT_EQ(tmp, "XXX"); } @@ -185,7 +185,7 @@ TEST(var_subs, created_set_sym) ASSERT_TRUE(ctx.get_var_sym(it)); - auto tmp = m.get_var_sym_value(it, {}, {}).access_a(); + auto tmp = m.get_var_sym_value(it, std::vector {}, {}).access_a(); EXPECT_EQ(tmp, 11); } @@ -226,7 +226,7 @@ TEST(var_concatenation, concatenated_string_dot_last) ASSERT_TRUE(ctx.get_var_sym(it)); - auto tmp = m.get_var_sym_value(it, {}, {}).access_c(); + auto tmp = m.get_var_sym_value(it, std::vector {}, {}).access_c(); EXPECT_EQ(tmp, "avc"); } @@ -243,7 +243,7 @@ TEST(var_concatenation, concatenated_string_dot) ASSERT_TRUE(ctx.get_var_sym(it)); - auto tmp = m.get_var_sym_value(it, {}, {}).access_c(); + auto tmp = m.get_var_sym_value(it, std::vector {}, {}).access_c(); EXPECT_EQ(tmp, "avc-get"); } @@ -260,7 +260,7 @@ TEST(var_concatenation, concatenated_string_double_dot) ASSERT_TRUE(ctx.get_var_sym(it)); - auto tmp = m.get_var_sym_value(it, {}, {}).access_c(); + auto tmp = m.get_var_sym_value(it, std::vector {}, {}).access_c(); EXPECT_EQ(tmp, "avc."); } @@ -434,7 +434,7 @@ TEST(SET, conversions_invalid) a.collect_diags(); - ASSERT_EQ(a.diags().size(), (size_t)4); + ASSERT_EQ(a.diags().size(), (size_t)6); } TEST(CA_instructions, undefined_relocatable) @@ -454,5 +454,5 @@ B EQU 1 a.collect_diags(); - ASSERT_EQ(a.diags().size(), (size_t)2); + ASSERT_EQ(a.diags().size(), (size_t)3); } diff --git a/parser_library/test/processing/dc_test.cpp b/parser_library/test/processing/dc_test.cpp index a99bd083f..af7ec2bf5 100644 --- a/parser_library/test/processing/dc_test.cpp +++ b/parser_library/test/processing/dc_test.cpp @@ -104,7 +104,7 @@ R EQU C-B analyzer a(input); a.analyze(); a.collect_diags(); - EXPECT_EQ(a.diags().size(), (size_t)1); + ASSERT_EQ(a.diags().size(), (size_t)1); EXPECT_EQ(a.diags()[0].code, "D022"); } diff --git a/parser_library/test/processing/lookahead_test.cpp b/parser_library/test/processing/lookahead_test.cpp index c7bbe66fb..66f8f5b1a 100644 --- a/parser_library/test/processing/lookahead_test.cpp +++ b/parser_library/test/processing/lookahead_test.cpp @@ -190,13 +190,9 @@ TEST(attribute_lookahead, lookup_triggered) { std::string input("L'X"); analyzer a(input); - auto expr = a.parser().expr(); + auto& expr = a.parser().expr()->ca_expr; - empty_attribute_provider prov; - - expression_analyzer ea(evaluation_context { a.context(), prov, empty_parse_lib_provider::instance }); - - EXPECT_EQ(ea.get_undefined_symbol_references(expr).size(), (size_t)1); + EXPECT_EQ(expr->get_undefined_attributed_symbols(a.context().ord_ctx).size(), (size_t)1); EXPECT_EQ(a.diags().size(), (size_t)0); } @@ -205,19 +201,15 @@ TEST(attribute_lookahead, lookup_not_triggered) { std::string input("L'X"); analyzer a(input); - auto expr = a.parser().expr(); + auto& expr = a.parser().expr()->ca_expr; // define symbol with undefined length auto tmp = a.context().ord_ctx.create_symbol( a.context().ids().add("X"), symbol_value(), symbol_attributes(symbol_origin::DAT, 200), {}); ASSERT_TRUE(tmp); - empty_attribute_provider prov; - - expression_analyzer ea(evaluation_context { a.context(), prov, empty_parse_lib_provider::instance }); - // although length is undefined the actual symbol is defined so no lookup should happen - EXPECT_EQ(ea.get_undefined_symbol_references(expr).size(), (size_t)0); + EXPECT_EQ(expr->get_undefined_attributed_symbols(a.context().ord_ctx).size(), (size_t)0); EXPECT_EQ(a.diags().size(), (size_t)0); } @@ -226,13 +218,9 @@ TEST(attribute_lookahead, lookup_of_two_refs) { std::string input("L'X+L'Y"); analyzer a(input); - auto expr = a.parser().expr(); + auto& expr = a.parser().expr()->ca_expr; - empty_attribute_provider prov; - - expression_analyzer ea(evaluation_context { a.context(), prov, empty_parse_lib_provider::instance }); - - EXPECT_EQ(ea.get_undefined_symbol_references(expr).size(), (size_t)2); + EXPECT_EQ(expr->get_undefined_attributed_symbols(a.context().ord_ctx).size(), (size_t)2); EXPECT_EQ(a.diags().size(), (size_t)0); } @@ -241,13 +229,9 @@ TEST(attribute_lookahead, lookup_of_two_refs_but_one_symbol) { std::string input("S'X+L'X"); analyzer a(input); - auto expr = a.parser().expr(); - - empty_attribute_provider prov; - - expression_analyzer ea(evaluation_context { a.context(), prov, empty_parse_lib_provider::instance }); + auto& expr = a.parser().expr()->ca_expr; - EXPECT_EQ(ea.get_undefined_symbol_references(expr).size(), (size_t)1); + EXPECT_EQ(expr->get_undefined_attributed_symbols(a.context().ord_ctx).size(), (size_t)1); EXPECT_EQ(a.diags().size(), (size_t)0); } diff --git a/parser_library/test/res/input/expression_test.in b/parser_library/test/res/input/expression_test.in deleted file mode 100644 index 62aade752..000000000 --- a/parser_library/test/res/input/expression_test.in +++ /dev/null @@ -1,172 +0,0 @@ -123 -1+2 -3*12 -3+5*2 -2*5+3 -5*3*2 -(3)+(++3)-(2*(9)) -((1 EQ 1) AND 2) -(2 AND 10) -B2A('') -B2A('0000000101') -B2A('11111111111111111111111111111110') -C2A('') -C2A('+') -C2A('1') -C2A('0000') -D2A('000') -D2A('10') -D2A('+100') -D2A('-5') -DCLEN('') -DCLEN('''') -DCLEN('''''') -DCLEN('&&') -DCLEN('a''''b') -DCLEN('a''''b&&c') -DCLEN('&&&&'.'''''''') -FIND('abcdef','cde') -('abcdef' FIND 'cde') -('abcdef' FIND 'gde') -INDEX('ABC','B') -INDEX('ABC','D') -ISBIN('10101') -ISBIN('101010101010101010101010101010101') -ISBIN('12121') -ISDEC('12345678') -ISDEC('+25') -ISDEC('2147483648') -ISDEC('00000000005') -ISSYM('Abcd_1234') -ISSYM('_Abcd1234') -ISSYM('##@$_') -ISSYM('1234_Abcd') -(NOT 10) -(10 OR 2) -(2 SLA 2) -(10 SLL 2) -(10 SRA 2) -(-344 SRA 40) -(10 SRL 2) -(-344 SRL 40) -X2A('00000101') -X2A('C1') -X2A('') -X2A('FFFFFFF0') -(10 XOR 2) -(3)'ABC' -'ABC'.(3)'ABCDEF'(4,3) -(3)'<.A>' -(3)'<.A.B>'(2,4) -A2B(0) -A2B(5) -A2B(1022) -A2B(-7) -A2C(0) -A2C(241) -A2C(20046) -A2C(-252645136) -A2D(0) -A2D(241) -A2D(16488) -A2D(-3) -A2X(0) -A2X(10) -A2X(257) -A2X(1022) -A2X(-7) -B2C('11110011') -B2C('101110011110001') -B2C('0') -B2C('00010010001') -B2C('000000000') -B2C('') -B2D('') -B2D('00010010001') -B2D('11110001') -B2D('01111111111111111111111111111111') -B2D('11111111111111111111111111110001') -B2X('') -B2X('00000') -B2X('0000010010001') -B2X('11110001') -B2X('1111110001') -BYTE(0) -BYTE(97) -BYTE(129) -C2B('') -C2B(' ') -C2B('1') -C2B('1234') -C2D('') -C2D('1') -C2D('0000') -C2X('') -C2X('1') -C2X('a') -C2X('1234567R') -D2B('') -D2B('0') -D2B('+5') -D2B('1022') -D2B('-7') -D2C('0') -D2C('126') -D2C('247') -D2C('23793') -D2X('0') -D2X('+5') -D2X('255') -D2X('01022') -D2X('-7') -D2X('2345678901') -DCVAL('') -DCVAL('''') -DCVAL('&&') -DCVAL('a''''b') -DCVAL('a''''b&&c') -DEQUOTE('charstring') -DEQUOTE('') -DEQUOTE('a') -DEQUOTE('''a''') -DEQUOTE('a''b') -DEQUOTE('''''') -DOUBLE('test') -DOUBLE('&&''') -(DOUBLE 'test') -LOWER('aBcDeF') -(LOWER 'XXAaa123') -SIGNED(10) -SIGNED(-10) -UPPER('aBcDeF') -(UPPER 'XXAaa123') -X2B('') -X2B('00') -X2B('1') -X2B('F3') -X2B('00F3') -X2C('') -X2C('F3') -X2C('0') -X2C('F1F2F3F4F5') -X2C('000F1') -X2D('') -X2D('91') -X2D('000F1') -X2D('7FFFFFFF') -X2D('FFFFFFF1') -('abc' eq 'abc') -('abc' eq'abc') -('abc'eq 'abc') -('abc'eq'abc') -('abc' eq 'abcd') -('abc' EQ 'abc') -('abc' EQ 'abcd') -('abc'EQ 'abcd') -('abc' EQ'abcd') -('abc'EQ'abcd') -&TEST_VAR -&TEST_VAR+&TEST_VAR -(&TEST_VAR*&TEST_VAR) -('3' LT '23') -(NOT 1 AND NOT 1 AND NOT 'E' EQ 'E') \ No newline at end of file diff --git a/parser_library/test/res/output/expression_test.output b/parser_library/test/res/output/expression_test.output deleted file mode 100644 index 3ad52d301f4268b247f635b199f2188e6099128a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 981 zcma)5%TB{E5X^Z#q>+eHynf^%0a8lqZ|F6Y@;Y#6d+6sg8`l*GD2%=KI^K-eyI!#l zYz@R|cLuds2rLW&YMt5+)(iDu8y|$W2BMv|LG`IQntP?HKK8(P)r z92;6l?`U32!@Xf~pSo(xRZJZ>^WiQF=EHoE1?CT2HV{K!e}rW40+(ROP!Kw(R#g)r zDuYTxS4rc$4mGcMLRN;PoLz8ng_zJYlviX!@kUBaWa7h#(TZ<<=NjKKXaS^Q?*&od zCg;1jB(ndeUHX~_jGv(KN>t)!h&M;l%AF~lae%U%z?jLQb+OMfFt z?x<(~kNd3#zvaM~Wx}lRl}?B;DPN)tl$c>GA5>-=Y+lCQ{;+#}e+EOy#vL5C`vYb~ zStfma*gS5Za6FFVD6Ap6T2s=4#d(&name, std::vector(), range()); + + concat_chain created_name; + created_name.push_back(std::make_unique("n")); + + auto vsc = std::make_unique(std::move(created_name), std::vector(), range()); + + concat_chain chain; + + chain.push_back(std::make_unique("ada")); + chain.push_back(std::make_unique(std::move(vs))); + chain.push_back(std::make_unique()); + chain.push_back(std::make_unique()); + + std::vector list; + concat_chain elem; + elem.push_back(std::make_unique("ada")); + list.push_back(std::move(elem)); + elem.push_back(std::make_unique("ada")); + list.push_back(std::move(elem)); + elem.push_back(std::make_unique(std::move(vsc))); + list.push_back(std::move(elem)); + + chain.push_back(std::make_unique(std::move(list))); + + return chain; +} + + +TEST(concatenation, to_string) { EXPECT_EQ(concatenation_point::to_string(create_chain()), "ada&n.=(ada,ada,&(n))"); } + +TEST(concatenation, contains_var_sym) +{ + auto chain = create_chain(); + + { + auto var = concatenation_point::contains_var_sym(chain.cbegin(), chain.cend()); + + auto pos = dynamic_cast(chain[1].get()); + + EXPECT_EQ(var, pos); + } + + chain.erase(chain.begin() + 1); + + { + auto var = concatenation_point::contains_var_sym(chain.cbegin(), chain.cend()); + + auto pos = dynamic_cast(chain.back()->access_sub()->list.back().front().get()); + + EXPECT_EQ(var, pos); + } + + chain.erase(chain.begin() + (chain.size() - 1)); + + { + auto var = concatenation_point::contains_var_sym(chain.cbegin(), chain.cend()); + + EXPECT_EQ(var, nullptr); + } +} \ No newline at end of file