1

I am trying to figure out how to include both HLASM and Metal C definitions for the same DSECT/struct in a single dataset/file.

Before trying this, I tried what I described in How do I go about making this work with a #include? It works fine when dropped straight into the code

So, I went down another path and figured I could use a #define to alter the MACRO statement within the assembler to something that the C compiler would use:

  • Change "MACRO" to "#pragma margins(2,72)"
  • Change "MEND" to "#pragma nomargins"

    EDIT       SSAF.METALC.H(CKKTEST) - 01.01                          Columns 00001 00080 
    Command ===>                                                          Scroll ===> CSR  
    ****** ********************************* Top of Data **********************************
    000001          MACRO                                                                  
    000002 */* First line of macro prolog                                       */         
    000003 */* Last line of macro prolog                                        */         
    000004 *#if 0!=0                               // Bypass asm in C                      
    000005 Test     DSECT                                                                  
    000006 Test@    DS A                                                                   
    000007 TestINT  DS F                                                                   
    000008 TestChar DS C                                                                   
    000009 *#endif                                                                         
    000010  MEND                                                                           
    000011 struct Test {                                                                   
    000012   void *Test@;                                                                  
    000013   int TestInt;                                                                  
    000014   char TestChar;                                                                
    000015 };                                                                              
    ****** ******************************** Bottom of Data ********************************
    

And I figured that I could use #define to change "MACRO" and "MEND" to stuff that the C compiler would like, first I tried with no quotes:

    EDIT       SSAF.METALC.C(CKLTHING) - 01.01                         Columns 00001 00080 
    Command ===>                                                          Scroll ===> CSR  
    000207 #define MACRO #pragma margins(2,72)                                          
    000208 #define MEND #pragma nomargins                                              
    000209 #include"ckktest.h"                                                             

Which did not yield the desired results:

    |
      207       |#define MACRO #pragma margins(2,72)                                         
      208       |#define MEND #pragma nomargins                                              
      209       |#include"ckktest.h"                                                         
    *=ERROR===========>     CCN3191 The character # is not a valid C source character.       
    *=ERROR===========>     CCN3166 Definition of function pragma requires parentheses.      
    *=ERROR===========>     CCN3191 The character # is not a valid C source character.       
    *=ERROR===========>     CCN3191 The character # is not a valid C source character.       
    *=ERROR===========>     CCN3191 The character # is not a valid C source character.       
    *=ERROR===========>     CCN3276 Syntax error: possible missing '{'?                                            

Then I tried enclosing the #define value in quotes:

      207       |#define MACRO "#pragma margins(2,72)"                                       
      208       |#define MEND "#pragma nomargins"                                            
      209       |#include"ckktest.h"                                                         
    *=ERROR===========>     CCN3191 The character # is not a valid C source character.       
    *=ERROR===========>     CCN3191 The character # is not a valid C source character.       
      210       |                                                                            

This gives fewer error messages, but is still not what I need.

Note: the # I'm using is EBCDIC 7B.

The description for the error message is rather terse:

CCN3191 The character &1 is not a valid C source character. Explanation Refer to the C/C++ Language Reference for information on valid characters.

In the message text:

&1 is a character.

User response Change the character.

I referred to the C/C++ Language Reference and could not find anything that says I can't use a "#" inside a #define. As a matter of fact there are some words about the # and ## operators...

Is there a way to get around this?

Thanks, Scott

  • 3
    That looks like trilingual, not bilingual. C and C++ are separate languages. Don't conflate them; it will earn you diatribes and down votes on SO. I note that you've only tagged the question with C and not C++; I suggest editing the question to remove references to C++. Granted, the preprocessor is essentially the same in C and C++, but then the preprocessor language is only loosely related to the rest of C and C++. – Jonathan Leffler Oct 07 '19 at 19:34
  • @Jonathan Leffler, in z/OS, the C and C++ manuals are one and the same; the title is C/C++ Reference. With what Scott is trying to do, in this case it does not matter which is which as far as the preprocessor. @Scott Fagen, turn on the `SHOWINC` compiler option. That will expand the `#include` in the listing. However, I may have bad news. The correct syntax for the `#pragma` is `#pragma options(blah)` But in the [doc](https://www.ibm.com/support/knowledgecenter/en/SSLTBW_2.4.0/com.ibm.zos.v2r4.cbcux01/pragopt.htm), MARGINS is not listed. – zarchasmpgmr Oct 07 '19 at 20:14
  • I've made no mention of C++ here, other than the IBM product is the XL C/C++ Compiler. I am coding in C. Ray - the #pragma margins(2,72) followed by #pragma nomargins works fine when just entered into the program (and the compiler faithfully ignores what's in column 1). The issue is getting the #define to "take" the string that begins with the # as something valid. – Scott Fagen Oct 07 '19 at 21:28
  • I think I see what is happening here.This is an object-like `#define` macro: "An _object-like macro definition_ replaces a single identifier with the specified replacement tokens." An _identifier_ is a name for one of the following language elements: functions, objects, labels, function parameters, macros and macro parameters, type definitions, enumerated types and enumerators, and structure and union names. # pragma is a preprocessor directive, which isn't an identifier. I think the compiler is interpreting it as part of the program, not preprocessing, which matches the doc. – zarchasmpgmr Oct 08 '19 at 00:54
  • 1
    Could I counter with why use "bilingual" headers/macros in the first place? I recognize that the header and macro describe the same structure, but it adds complexity while diminishing readability. – meat Oct 08 '19 at 13:18
  • IBM z/OS macros are bilingual, for assembler and a development language called PL/X (which was derived from PL/I). Many of the system macros are bilingual, using the derived PL/I margins of 2,72 to skip an asterisk in column 1 (comment) and use preprocessor directives like %GOTO to skip the assembler text. – zarchasmpgmr Oct 08 '19 at 19:58
  • Check out SYS1.MACLIB(IAZCMTCB) to see how it's done. The trick is to create nop assembler macros for #ifndef and #define :) – David Crayford Jan 28 '20 at 06:06
  • Actually, the trick is to create dummy opcodes - see SYS1.MACLIB(IAZDUMOP) – David Crayford Jan 28 '20 at 06:12

1 Answers1

2

Scott, the problem is that macro's can't expand into preprocessing directives. I'm guessing from the header you want to define the struct definition in one place and use it in hlasm and C/C++. I suggest looking at the dsect tool. This tool produces a C struct declaration from the DSECT declarations in the hlasm file. This could give an solution.

Another option using macro tricks is something like this for ckktest.h:

StructStart(Test)
MbrAddr(Test@)
MbrInt(TestINT)
MbrByte(TestChar)
StructEnd

In the C source you would include with:

#define StructStart(s) struct s {
#define MbrAddr(m) void *m;
#define MbrInt(m) int m;
#define MbrByte(m) char m;
#define StructEnd };
#include "ckktest.h"

And tend similar in hlasm.

I'd look at the dsect tool as it would give the mapping from hlasm to C and enable you to maintain one definition. Your makefile will have one extra rule to create the C header from the hlasm code using the dsect tool.

S Perry
  • 21
  • 2
  • 1
    Just wanted to second the idea of using the CCNEDSCT tool instead of what you're trying to do. It's not trivial to have truly compatible assembler DSECTs and C structures due to things like alignment, padding, ORGs/UNIONs and so on - building whatever you want in Assembler and converting it to C structures automatically is a much less error prone approach, and it also has the benefit of working for things like z/OS data areas so that you don't have to do these by hand. – Valerie R Oct 08 '19 at 14:29
  • 1
    I intend to use the DSECT tool. However, the tool has a number of "deficiencies" that render the output "not ready for prime time," including not preserving commentary that precedes the DSECT and an inability to divine the types for pointers, so there will almost always be "manual intervention," which will finish with copying the struct back to the same file as the assembler DSECT. – Scott Fagen Oct 08 '19 at 18:57
  • @Scott sounds like a job for a Rexx. :) – zarchasmpgmr Oct 08 '19 at 19:59