domain-specific programming in ABAP With the theme domain-specific languages
(DSL) I've been busy here and I will do it more often, because I think it is a promising field of programming.
The easiest and the ABAP developers most common form of domain-specific programming is it safe to to define Customizing tables
and used for the control of the system [1]: In a well-defined Customizing table include the possible fixed values of a (DDIC) domain directly traceable to the technical language of the application.
Sometimes the context of a database table for the desired form of the controllability of the system is inadequate: You want to be as flexible. Perhaps the relational data model, the only key and its value is derived, unsuitable for the imaging of the desired control. Or you want to control the deposit of the program in the source code of the class that performs the logic to it too close to the code themselves. A solution is then to program the logic in a method so that the source of this method is limited to the radical application context - the program itself runs to some extent behind the scenes. This can be done with macros in ABAP and the colon / comma-syntax [2].
an example. In a class called
ZCL_GDBW_SELECTOR I had implemented the task of selections from various external perform database tables that are structured substantially similar. The details in which they differ from each other, I have held in a static hash table that is built to load the class. The filling of this table is computationally a harmless, almost boring process. The
insert statements as well as the assignments to the fields of the work area are part of the "noise" of the language (syntactic noise
): necessary but for the machine, for humans but difficult for them to look at the essentials. In this case, I have hidden these in macros to stop so that only the essential, the controlling parameters in the source code of the method:
build_info_on_tables_and_conns method. data: ls_table_data type ty_table_data,
ls_con_data type ty_con_data. _add_table_data
* Connection Node added
* Databox table name
'GDBW' gdnf1bw '' ': ' INBOX 'V_INFO_DATEN_RECV'
'OUTBOX' V_INFO_DATEN_SEND '
' ALL 'V_INFO_DATEN_ALL'
'ARCH' 'V_INFO_DATEN_SEND_ARCH'. _add_table_data
'MVN' gdnf2bw '' X ':
' INBOX ' 'V_INFO_DATEN_RECV_NF'
'OUTBOX' V_INFO_DATEN_SEND_NF '
' ARCH 'V_INFO_DATEN_SEND_ARCHIV'. * ...
* Q compounds
_copy_table_data_from_to:
'MVN' QMVN '
' KMVN 'KQMVN'
* ...
The "domain expert" in this case is someone who is familiar with the external databases and their connections to the SAP system.
Note in this example, the use of the colon / comma notation: The number before the colon, part of the statement in sequence is the same as always Antecedent to all separated by commas used after the colon behind sentences. This also facilitates the view of the essentials. Alternatively, I would have the n-premisses must write down times. The colon / comma-notation and Macros have helped me in this example, to enforce a radical
Another example from my BSP thread ready for input in declarative syntax
shows the use of this technique to control for when and which buttons in one application is active, inactive, and when they are invisible - depending on the transaction mode (display, Edit, Create). Again, the reduction to the essentials. The actual manipulation of the Status field is behind the scenes, hidden in the macro:
_set_button_state_per_mode:
* FCODE \\ CREATE CHANGE DISPLAY
'ACTU' active active disabled,
'SAVE' active active disabled,
'UNDO' active invisible invisible,
'CANCEL' invisible active disabled,
'PRINT' invisible active active.
Again, it allows the application to record the control in table form. That is, would this type of control . It is in principle possible to define small Customizing tables that provide the same [3]
In both cases I have deliberately not customizing table chosen for reasons of economy, if I have all decisions and controls of this type would occurrences in Customizing tables would I flood the system with virtually customizing tables.
Also, I would have not only a place, but two, which are responsible for the control: Later, to understand in problem cases, why a particular state is chosen, I look at the entries in the Customizing table
and
the program that it is evaluating.
In the macro notation I have, however, everything in one place, in the same program object. The Macro me only serves to separate the program logic within the object
of the really important controlling values, since these are the essentials. The ongoing behind the scenes programming logic is the same for all buttons. Once programmed - and with a unit test secured - you will have to do to maintain no more with the code. But with the controlling values: It may, for example, a new button will be added. Or find a new principal is more tasteful than its predecessor, buttons to switch on principle
invisible when they are not suitable. These are typical cases of changes - And always have only the values in the above section of code to be adapted or extended.
macros and the colon / comma syntax thus help in ABAP to create
internal DSL
s, ie languages that are processed in the normal ABAP embedded context.
Opportunities are also integrated in the ABAP XSLT processors and JavaScript. In my
BSP Framework
the pronounced in the config.xml file
Flow Logic provides a DSL for the sequencing of the views in a BSP application you dar. is converted to a single ABAP statement in a set of internal tables ( see the constructor of the class
zcl_mvc_framework
:
* config.xml in ABAP data transform
call transformation (config_to_abap) source xml lv_sxml
result ls_application
application = tree = tree
controller = controllers
model = models.
may consider it more useful, instead of using XML to JavaScript Object Notation (JSON
) in other cases. Because XML itself also produced a significant
syntactic noise. The JavaScript data that could be put in as a standard text (
SO10
) may, either by me in this blog
presented JSON parser or with the available in ABAP JavaScript interpreter
cl_java_script
be read. Controlled, across sessions relevant information should, after they were converted into ABAP data to be buffered in any event on the Application Server. [4]
But JSON is not entirely free of syntactic noise
. The user - and the DSL Developers - really do not see the many braces and quotation marks, but at first glance already have the essential information. Then we gradually come into the realm of a "real" external DSL
. The notation of the data is designed for a given specific problem ad hoc. A typical example of such a DSL is a CSS stylesheet. The CSS notation is tailored to exactly one purpose: The appearance of HTML elements to control.
An external DSL needs to be translated into a semantic model. For each notation has its own translator is needed. That sounds like a significant extra cost because with such a translator so another software component is required. The effort to write a parser for DSLs or to a parser coupled translator, but tend to be overestimated. The more limited the use of DSL is - and limited language range is one of the characteristics of a DSL - the easier it will parse it, especially when working with test-driven development (see on this subject the beautiful Bliki
ParserFear
by Martin Fowler). Parsers are a prime example of the efficiency test-driven development, as they have as little dependencies: convert to a text-only form input in a syntax tree, or some semantic model. There are no other dependencies, such as database tables. Also need except basic functions - such as on string processing - no other API's are called.
For the work on the string level, we are in ABAP beyond the powerful regular expressions. The parsing of the actual often precedes
Tokenizing
can often involve only a series of simple regex replace
realize
constructs. To illustrate like a DSL used for the formulation of so-called
packaging rules. With a packaging rule can be used to control how the content from multiple SAP supplies pallets to individual or group is split. I have built for such a small packaging rules editor. The rules are maintained by our SAP CC to test different process and use cases. Here's an example: first Palette (
second range (
1st delivery, 1 item
) 3.Palette (
1. Delivery, rest
)
4.Palette ( second delivery, first item
second delivery, 2nd item, 50% )
5.Palette ( second delivery, rest
)
)
So here is a hierarchical handling unit is equipped with the contents of two deliveries, with one group of education delivery items or partial quantities of delivery items is possible. Such a rule can be given a name and used at run time in a test case for automatic packaging. A parser validates the syntactic correctness of the control at design time to create a semantic model in the form of internal tables. This semantic model is then used to Term to the real present supplies used.
follows to illustrate here the tokenizer for the DSL, which is listed complete with regular expressions. It generates from the user entered a series of well-defined rules, tokens in the form of a normalized
stringtab
:
lv_norm = iv_code. lv_norm translate to upper case. replace all occurrences of regex:
* comma as a separator
',' treated with lv_norm gc_space,
* normalization of the keywords
'\\ bLIEF (\\ in lv_norm with 'RAN',
'\\ BPOS (\\
in lv_norm with '$ 1 $ 2', * 2x as concatenate tokens can be: "(REST)" '([\\ d.] + any numeric argument required.
loop at lt_code into lv_token.
lv_token case. when '('.
_add_token ct_tokens bra space.
when ')'.
_add_token ct_tokens ket space. when 'REST'.
_add_token ct_tokens rest space. when 'PAL'.
_add_token ct_tokens lv_number pal.
when 'DELIVERY'.
_add_token ran ct_tokens lv_number. when 'POS'.
_add_token ct_tokens lv_number pos.
when 'MG'.
_add_token ct_tokens lv_number meng.
when 'CU' or '%'.
_add_token ct_tokens lv_token ont.
when others.
find regex '(\\ d +)' submatches in lv_token lv_number.
if sy-subrc ne 0
* error - unknown token lv_token
_raise_syntax lv_token text-003.
else. * No clear
lv_number!
continue.
endif.
endcase.
lv_number clear.
endloop.
In this form it can now be processed by the Builder command for command to generate the desired semantic model.
If we had in ABAP a parser from the powerful family of Parsing Expression Grammars
(PEG) are available, such as
OMeta
, it could write a parser for this DSL with much fewer lines of code. The following OMeta object serves as a parser, as builders of the semantic model (here in the form of an AST with nested JavaScript arrays) and used to define the grammar. Moreover, it is more readable than the above-programmed out of sequence of regular expressions, which serves the same purpose.
ometa handling unit definition
ordnum = digit +: ds'. " -> ParseInt (ds.join ('')),
/ / Complete delivery of all items Posnr gets 0:
dlv = ordnum: n ("delivery" An SSCC (Serial Shipment Container Code = ID of a handling unit)
sscc ordnum =: n ("Palette"
hu = sscc: s spaces "(spaces content: c spaces)"
-> ["HU", s [1], c],
/ / expr defines the entire rule, and thus the DSL:
expr = spaces hu: first (hu spaces) *: more
-> [first] concat (more)
}
OMeta This grammar is almost completely equivalent to the ABAP code-programmed by me, which I top one. extracts have shown! This shows prospects might get you to DSLs to formulate even faster and easier to define. Since there is a JavaScript implementation of OMeta, grammars could also be in the ABAP World be used - for there is the interconnect in the class
CL_JAVA_SCRIPT
JavaScript interpreter. The so-called semantic actions
, after each rule behind the arrow operator
-> Follow
could also include callbacks in ABAP. That the
CL_JAVA_SCRIPT
is resource intensive and that an interpreted language is not particularly fast, is there any reason for concern. Because the result of the parse operation will be buffered on the application server anyway, since it is the same for all users normally. fill
instead a semantic model in the form of internal tables, a DSL parser can of course also be used to generate ABAP code. Here again hold our SAP systems provides a number of examples. I intend to document this in future blogs.
[1] The fact that the entries of Customizing tables as a "DSL program can be seen, may cause surprise or even astonishment, I had already explained this point in my blog software
Stone Age.
[2] Macros are handled in the debugger as an execution, you can not hineindebuggen in a macro. Therefore, it is advisable to use the macro except in the simplest cases, only to call methods and program the logic of the macros in these methods. The macro then helps to write down the proposed controller in a more readable form.
avoided [3] To avoid typing errors, I've marked in this case, the possible states of a button in the form of constants. Behind the scenes there are constants
gc_state-active
,
gc_state-invisible
etc. This keeps me already the ABAP syntax checker on it, entering invalid state values.
[4] only in development systems are usually annoying buffering: The developer is more interested in seeing his development testing to have the most recent data, which he constantly changes in its tests. to buffer the development system, annoying debugging sessions . Cause In contrast, the controlled data in the production system change rather rare, while the other, the highest possible performance should be given to: buffer there so be sure! Finally, should not hundreds of users read in their meetings, all the same configuration file from the database or file system. For the same reason, customizing tables in DDIC with one click - without additional programming - buffered on the application server.