Skip to content

Case: How to extend WRITE keyword

Jackie Ju edited this page Jul 6, 2020 · 1 revision

Prepare

  • You need have ruby >=2.6.3

  • Clone this repo

git clone https://github.com/jackieju/abap2ruby.git
  • Clone CPP2Ruby
cd ..
git clone https://github.com/jackieju/CPP2Ruby.git
cd abap2ruby
  • Strongly recommend:

Install syntax highlight for EBNF file(.atg) on you code editor(textmate, sublime...)

You can download it here https://github.com/jackieju/abap2ruby/tree/master/ebnf_cocor_syntax_highlight.txt

Case 1: extend WRITE keyword

The abap.code:

...
WRITE  SY-ABCDE .
...

Please open cocoR/abap.atg, find rule for 'WriteStatement':

WriteStatement =  "WRITE" 
    (
        {["AT"] ["/"][number][ "(" (Expression | "*" | "**") ")" ]} [Expression] 
...
 ["DD/MM/YY"|"MM/DD/YY"|"DD/MM/YYYY"|"MM/DD/YYYY"|"DDMMYY"|"MMDDYY"|"YYMMDD"] 
    )  
    "." .

If you do nothing, the translator will generate original ABAP code.

WRITE  SY-ABCDE 

Now Let's put some code in abap.atg

WriteStatement =   (. param_hash = {} .) "WRITE" 
    (
        {["AT"] ["/"][number][ "(" (Expression | "*" | "**") ")" ]} [Expression] 
         (.
             param_hash["s"] = lus
         .)
          {
...
 ["DD/MM/YY"|"MM/DD/YY"|"DD/MM/YYYY"|"MM/DD/YYYY"|"DDMMYY"|"MMDDYY"|"YYMMDD"] 
    )  
    "." 
  (.
  
  params = []
  param_hash.each{|k,v|
      params.push "#{k}: #{v}"
  }
  src("write(#{params.join(", ")})\n")
  .)
  . 

Save abap.atg, and run ./go under cocoR/, will regenerate the translator.

The code between "(." and ".)" will be placed in generated parser. You can find it in cparser.rb

The first code block initialize a hash.

The 2nd code block get value from last parsed unterminal and store it into the hash.

"lus" means last unterminal string, the string value return from last unterminal.

The last code block set the translation result for current rule.

"src()" set the result for current parsing unterminal(rule).

Then run "ruby translate.rb ", It will generate ruby code:

write(s: sy.abcde)

Done !

Case 2: extend more for WRITE keyword

Now you'd like this translator can work for more syntax of WRITE keyword. e.g.

WRITE /5 'SY-ABCDE' .

To make this work, you just add more code in the rule for WriteStatement:

WriteStatement =   (. param_hash = {} .) "WRITE" 
    (
        {["AT"] ["/"][number 
         (. param_hash["col"] = curString().to_i .)
         ][ "(" (Expression | "*" | "**") ")" ]} [Expression] 
         (.
             param_hash["s"] = lus
         .)
          {

This will generate code:

write(col: 0, s: 'SY-ABCDE')

Done !

Case 3: Extend in easy mode

e.g.

stASSERT = "ASSERT" [ ["ID" identifier ["SUBKEY" identifier]] 
         ["FIELDS" identifier ] 
         "CONDITION" ] LogExp  "." (.make.) .

It will translate ASSERT statment to ruby code

     assert()

But it's actually an empty call. So you can add more work in abap.atg

stASSERT = "ASSERT" [ ["ID" identifier (.cp[:id]=prevString.)["SUBKEY" identifier(.cp[:subkey]=prevString.)]] 
         ["FIELDS" identifier (.cp[:fields]=lus.)] 
         "CONDITION" ] LogExp (.cp[:o]=lus.) "." (.make.) .

then it will translate the real assert statment. e.g.

ASSERT sy-subrc = 0.

will output ruby code:

  assert(o:sy.subrc == 0)