Interesting stuff. Good for you! > In contrast to C, PTRADD adds byte addresses, not elements.
Yes, in C, given foo *bar = &someFoo; then bar+1 is (counter-intuitively for those of us who came up through HLASM) not the address of someFoo plus one; it is the address of someFoo plus the length of a foo -- in other words, adding one to bar increments bar by the length of a foo, not by absolute 1. Adding 2 increments by twice the length of a foo, and so forth. That works well for fixed-element-length arrays -- if you have a pointer to an element in an array of integers then pointer+1 is the address of the next integer -- but it is inconvenient for certain z/OS tables -- e.g. the TIOT -- where each variable-length element contains its absolute length, i.e. the offset to the next element. Given tiot* tiot_p = &someTIOT, then adding tiot_p->tioelngh to tiot_p gives you an address somewhere out in the distant weeds, not the address of the next TIOT. The solution is a local function -- mine is called AddressIncrement -- that casts the address to an integer and adds the length algebraically. (Alternatively you can cast the address to a char* -- the elements of a char* have a length of 1, so the address of the next element is the address of the next byte, QED.) Charles -----Original Message----- From: IBM Mainframe Assembler List [mailto:[email protected]] On Behalf Of Bernd Oppolzer Sent: Sunday, September 13, 2020 10:54 AM To: [email protected] Subject: Re: Deep Cuts This is a very interesting discussion for me, as I am the current maintainer of "New Stanford Pascal". I am trying to extend the language to make it more usable, while not violating the Pascal spirit. Inspiration and motivation are the different versions of IBM's Pascal (Pascal/VS and VS/Pascal), available for MVS and VM/CMS starting from ca. 1980 on. I recently added MEMCPY, MEMSET and MEMCMP; I allowed to take the ADDR of every object (that is, pointers do not only exist for dynamically created variables, via NEW), and I added new functions ALLOC and FREE, which do a better job in storage allocating than NEW and DISPOSE (DISPOSE, in fact, was never implemented in the "old" Stanford compiler; it only had some global heap freeing mechanism using MARK and RELEASE). The NULL pointer (called NIL in Pascal) is implemented as 0xFFFFFFFF (minus one), so that MEMSETting a struct containing pointers indeed will not yield NIL pointers; you have to set the pointers explicitly to NIL after the MEMSET. Dereferencing a NIL pointer will give a 0C4 abend on the mainframe; if you want, you can create a DEBUG version of the program which checks for NIL before dereferencing and throws a Pascal runtime error. Regarding pointer arithmetic: it is not allowed to add an integer value to a pointer directly, but there is a function called PTRADD (p, i), which adds an integer value i to a pointer p. i may be positive or negative. The pointer p is of type ANYPTR (or VOIDPTR), which is a ptr type compatible to all other pointer types. The result of PTRADD is of type ANYPTR, too. In contrast to C, PTRADD adds byte addresses, not elements. PTRADD (p, 0) is used to cast pointer types (pointers are typed pointers in Pascal); it can be coded as PTRCAST (p), too. PTRDIFF (p1, p2) with integer result is the distance between two pointers.
