blob: bf49db4f8d21f2ba0c54913c25221afa10356236 [file] [log] [blame]
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
//*********************************************************************
//*********************************************************************
//-****************************************************************************
// rosgen.h
//
// This file contains defines, typedefs, and inline function definitions
// which will be used to make Rosetta-translated code less cluttered and
// confusing.
//
// The utilities in the "rosgen.h" include file are all the most
// frequently used utilities.
//-****************************************************************************
#ifndef _rosgenh_
#define _rosgenh_
// Set pTAL defaults for pragmas FIELDALIGN, OVERFLOW_TRAPS, and GP_OK
#ifndef set_fieldalign
#endif /* set_fieldalign */
#ifndef set_overflow
#endif /* set_overflow */
#ifndef set_map
#endif /* set_map */
#ifndef set_extern_data
#endif /* set_extern_data */
#include <math.h>
#include <stdlib.h>
#include <stddef.h>
#include <setjmp.h>
#include <memory.h>
#include <string.h>
#include <ctype.h>
// Defines and typedefs to get non-Tandem C++ to accept the source:
#define _far
#define _near
#define _baddr
#define _waddr
#define _sg
#define _sgx
#define _procaddr
#define _cspace
#define _lowmem
#define _lowmem64
#define _lowmem256
#define _tal
#define _optional(a,b) b
// #define _arg_present(a) 1
#define _arg_present_always(a) 1
#define _arg_present_ifnot0(a) (a!=0)
#define _arg_present_ifge0(a) (a>=0)
#define _arg_present_ifnot4321(a) (a!=4321)
// Likewise, 'fixed' is because C++ doesn't support long long:
class long_long {public: long high; long low;};
// Defines to allow compilation of procs etc with Tandem's proc attributes:
#define _alias(name)
#define _interrupt
#define _priv
#define _resident
#define _extensible
#define _extensible_n(n)
#define _callable
#define _c
#define _cobol
#define _fortran
#define _pascal
#define _unspecified
#define _variable
// Translation of the $TYPE builtin is one of the following defines:
#define _type_undef 0
#define _type_char 1
#define _type_int_16 2
#define _type_int_32 3
#define _type_fixed 4
#define _type_real_32 5
#define _type_real_64 6
#define _type_substruct 7
#define _type_struct 8
#define _type_bitfield 9
#define _type_int_ptr 10
#ifndef ROSETTA_LITTLE_ENDIAN
#define ROSETTA_BIG_ENDIAN 1
#else
#define ROSETTA_BIG_ENDIAN 0
#endif
// Does the compiler understand the LL suffix on long long constants?
#ifdef _MSC_VER
#define USE_LL 0
#define USE_L 1
#elif defined(__linux__)
#define USE_LL 1
#define USE_L 1
#else
#define USE_LL 0
#define USE_L 0
#endif
//-------------------------------------------------------------------------
// Punctuation in Macro Bodies and in Macro Actual Parameters
//
// The C++ language contains a macro substitution mechanism. A list of
// actual parameters supplied in an invocation of a parameterized
// macro is enclosed in parentheses. Each parameter in that list is
// separated by a comma.
//
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
#if 0
Embedded Comma and Parentheses
It is possible for the pTAL to C++ Translator to generate macro actual
parameters that contain unbalanced parentheses or commas that are embedded
in a macro actual parameter and do not function as parameter delimiters.
Invocations of the macros _lparen, _rparen, and _comma take the place of
these punctuation marks. These macros are expanded after the macro to
which they are passed as parameter text, so the enclosing macro invocation
is not confused by the punctuation.
In the following example, parentheses are necessary in the generated C++
code to preserve the precedence of the shift operator over the
multiplication operator, thus preserving the meaning of the original pTAL
expression. The generated right parenthesis sits in the macro actual
parameter.
pTAL Code Generated C++ Code
DEFINE fred(a,b) = a + b#; #define fred(a,b) a + b
... ...
j := 6 >> fred(7 * 8, 9); j = (6 >> fred(7 _rparen * 8, 9);
The C++ macro substitution mechanism expands the macro fred first, yielding
the following expanded statement.
j = (6 >> 7 _rparen * 8 + 9;
The C++ macro substitution mechanism then expands the macro invoked within
the actual parameter: _rparen.
j = (6 >> 7 ) * 8 + 9;
The following example illustrates a use of the _comma macro in a macro
actual parameter.
pTAL Code Generated C++ Code
PROC p(x,y) EXTENSIBLE; extern "C" _extensible
INT(16) x; void P(int_16 x,
INT(16) y; int_16 y);
EXTERNAL;
DEFINE callp(a) = p(a)#; #define callp(a) P(a)
PROC q; extern "C" void Q()
BEGIN {
callp(2); callp(2);
callp(4 ',' 5); callp(4 _comma 5);
The C++ macro substitution mechanism expands the macro callp first,
yielding the following expanded statement.
P(4 _comma 5)
The C++ macro substitution mechanism then expands the macro invoked within
the actual parameter: _comma.
P(4 , 5)
#endif
//-------------------------------------------------------------------------
#define _comma ,
#define _lparen (
#define _rparen )
//-------------------------------------------------------------------------
#if 0
Embedded Braces
The C++ language requires a semicolon terminator on statements, except on
compound statements. The following examples are all correctly terminated
C++ statements.
a = b + c;
while (a < 10) do
FOO(a);
while (a < 10) do {
FOO(a);
}
A semicolon immediately following a compound statement terminates a null
statement. The following example depicts a null statement following a while
statement which contains a compound statement.
while (a < 10) do {
FOO(a);
};
The null statement is harmless when it appears in a simple statement
sequence. In some contexts it can be harmful because it can mislead
the programmer. For example, the C++ language if..else statement
contains two embedded statements.
if ( condition ) true_action else false_action
condition
is the controlling expression of the if statement.
true_action
is the statement that is executed if the value of condition is nonzero.
false_action
is the statement that is executed if the value of condition is zero.
If true_action were a simple statement, it would be terminated by a
semicolon. If it were a compound statement, it would be terminated
by the closing brace ( } ). For example:
if (a < 10) if (a < 10) {
a = 10; a = 10;
else FOO(a);
a = 20; }
else
a = 20;
The true_action embedded in this if..else statement can be encapsulated by
a macro, which is invoked as if it were a statement. A straightforward
encapsulation of the examples above, however, require slightly different
syntax at the point of invocation. The invocation of the macro containing
the compound statement cannot be followed by a semicolon.
#define mac1 a = 10 #define mac2 { \
a = 10; \
FOO(a); \
}
... ...
if (a < 10) if (a < 10) {
mac1; mac2
else else
a = 20; a = 20;
This code would be more maintainable if the programmer did not have to
know whether or not the macro contained a compound statement in order to
use it correctly.
The pTAL to C++ Translator translates a pTAL macro that contains a statement
in such a way that the generated C++ macro is always used as if it were a
simple statement; it is always followed by semicolon. The pTAL to C++
Translator generates uses of the macros _begin and _end in place of the
opening brace ( { ) and closing brace ( } ) respectively. The latter
example would appear as follows.
pTAL Code Generated C++ Code
DEFINE mac2 = BEGIN #define mac2 _begin \
a := 10; a = 10; \
CALL FOO(a); FOO(a); \
END#; _end
... ...
IF a < 10 THEN if (a < 10)
mac2; mac2;
ELSE else
a := 20; a = 20;
_begin
The _begin macro is expanded to do { and is used to begin a compound
statement. That compound statement must end with the _end macro.
_end
The _end macro is expanded to } while (0) and is used to end a compound
statement. That compound statement must begin with the _begin macro. That
compound statement also requires a semicolon terminator.
#endif
//-------------------------------------------------------------------------
// Defines '_begin' and '_end' may be used whereever the reserved words
// 'begin' and 'end' were used in pTAL. Curly braces ("{" and "}")
// in general cannot.
#define _begin do {
#define _end } while (0)
//-------------------------------------------------------------------------
#if 0
Global Variables (_global, _value(initial_value), and _export_globals)
The pTAL and C++ languages use slightly different mechanisms to define and
initialize global variables that are visible in more than one separately
compiled module. Code generated by the pTAL to C++ Translator emulates
the pTAL mechanism. This section describes the two mechanisms and the
code generated by the pTAL to C++ Translator to emulate the pTAL mechanism
in C++.
The pTAL to C++ Translator produces a straightforward translation of
static global variables, which are only visible in the module in which
they are defined.
Definitions of Terms
The following terms are used in this discussion:
A variable definition states the variable s type and causes storage to
be allocated. A variable may be initialized when it is defined. A variable
is defined in exactly one module.
A variable declaration makes a variable known to a module of code. It does
not cause storage to be allocated, and variable initialization does not
take place when it is declared.
A global variable that is visible in more than one separately compiled
module is exported from the module that defines it. The variable is
exported from exactly one module.
A global variable that is visible in more than one separately compiled
module is imported to the modules that declare it.
C++ Global Variables
In C++, a programmer usually defines a variable in one module''s
implementation file and declares it in a header file.
In the following example, the compilation unit pebbles contains a
definition of the global variable fred which causes the variable to
be allocated and initialized. The variable is visible in the
compilation unit bambam. The compilation unit pebbles exports the
variable, and the compilation unit bambam imports it.
--------------
C++ file inclh
--------------
extern int_16 fred;
----------------
C++ file pebbles
----------------
#include "incl.h"
int_16 fred = 13;
...
if (fred == 13) ...
---------------
C++ file bambam
---------------
#include "incl.h"
...
x = fred;
pTAL Global Variables
In pTAL, a global variable is declared and defined with exactly the same
syntax. If the pTAL EXPORT_GLOBALS directive is set for a particular
compilation unit, then the variable is declared. If not, then the variable
is defined. A programmer usually supplies that syntax in a header file
that defines the variable in one compilation unit, in which the
EXPORT_GLOBALS directive is set, and declares it in all of the others.
In the following example, the compilation unit pebbles contains a definition
of the global variable fred which causes the variable to be allocated and
initialized. The variable is visible in the compilation unit bambam. The
compilation unit pebbles exports the variable, and the compilation unit
bambam imports it.
---------------
pTAL file inclh
---------------
BLOCK fred;
INT(16) f := 13;
END BLOCK;
-----------------
pTAL file pebbles
-----------------
?EXPORT_GLOBALS
?SOURCE inclh
...
IF f = 13 THEN ...
----------------
pTAL file bambam
----------------
?SOURCE inclh
...
x := f;
Generated C++ Global Variables
The pTAL to C++ Translator emulates pTAL-style global variable definition
and declaration. It generates the same text for defining exported variables
as for declaring imported variables.
In the following example, the compilation unit pebbles contains a definition
of the global variable fred which causes the variable to be allocated and
initialized. The variable is visible in the compilation unit bambam. The
compilation unit pebbles exports the variable, and the compilation unit
bambam imports it.
--------------
C++ file inclh
--------------
_global int_16 fred _value(13);
----------------
C++ file pebbles
----------------
#define _export_globals
#include "inclh"
...
if (fred == 13) ...
---------------
C++ file bambam
---------------
#include "inclh"
...
x = fred;
_global
The _global macro is expanded to nothing if the preprocessor symbol
_export_globals is defined. It is expanded to the keyword extern if
_export_globals is not defined. The extern keyword identifies a
declaration of an imported variable.
_global
_value
The _value macro initializes the global variable if the preprocessor symbol
_export_globals is defined. It is expanded to nothing if _export_globals
is not defined.
_value(initial_value)
initial_value
is an expression that evaluates to the initial value for the global
variable.
Usage Considerations
A comma-separated list of constants is often used to initialize arrays.
This style of initialization cannot appear as the argument to the _value
macro without addressing the problem of commas acting as constant separators
in the list rather than as macro actual parameter separators. In this case,
the pTAL to C++ Translator emits the variable initialization protected by a
conditional compilation toggle.
For example:
-- pTAL Code Generated C++ Code
--
-- INT(16) ROGER [0:5] _global int_16 ROGER[6]
-- := [0,1,2,3,4,5]; #ifdef _export_globals
-- ={0,1,2,3,4,5}
-- #endif
-- ;
--
#endif
//-------------------------------------------------------------------------
#ifdef _export_globals
#define _global
#define _value(x) = x
#else
#define _global extern
#define _value(x)
#endif /* _export_globals */
//-------------------------------------------------------------------------
#if 0
Relational expressions, conditional expressions, and group comparison
expressions produce boolean results in both pTAL and C++. The pTAL
language produces the value -1 to represents the boolean value TRUE,
and the C++ language produces the value 1 to represent the boolean value
TRUE. Both languages produce the value zero to represent the boolean
value FALSE.
Equivalent Boolean Value
Both pTAL and C++ accept a nonzero value as indicating the boolean value
true in a conditional expression or in an IF statement. For example:
INT(16) PROC maggie(a);
INT(16) a;
BEGIN
RETURN a < 4;
END;
INT(16) PROC joel(a,b);
INT(16) a,b;
BEGIN
RETURN a AND b;
END;
...
result0 := data '=' [4,5,6];
IF result0 THEN ...
result1 := (a > 0) AND (a < 10);
IF result1 AND result0 THEN ...
result2 := (a AND 4) + (b > 2);
result3 := (a < 4) LAND 7;
result4 := (b = 6) << 2;
...
A boolean value is most often used as:
- an IF statement conditional expression
- an operand to a conditional operator
Both consider any nonzero value to be TRUE, so it does not matter whether
the value is represented as a -1 or a 1.
result0 := data '=' [4,5,6];
IF result0 THEN ...
result1 := (a > 0) AND (a < 10);
IF result1 AND result0 THEN ...
Differing Boolean Value
The pTAL language produces the value -1 to represents the boolean value
TRUE, and the C++ language produces the value 1 to represent the boolean
value TRUE. This can be significant if the boolean value is used as an
operand to:
- a bitwise logical operator
- an arithmetic operator
- a bit extraction
- a shift operator
These expressions might evaluate to a different result if the value of
TRUE were represented as 1 than they would if the value of TRUE were
represented as -1. It is usually appropriate to direct the pTAL to C++
Translator to generate the pTAL representation of TRUE when this boolean
value is used in a bitwise logical operator, an arithmetic operator, or
a shift operator.
result2 := (a AND 4) + (b > 2);
result3 := (a < 4) LAND 7;
result4 := (b = 6) << 2;
To ensure a faithful translation of the original pTAL code, the code
generated by the pTAL to C++ Translator converts a C++ boolean value
to a pTAL boolean value, via the _tbv macro. The following example
illustrates the C++ translation of the previous examples.
extern "C" int_16 MAGGIE(int_16 a) {
return _tbv(a < 4);
};
int_16 JOEL(int_16 a, int_16 b) {
return _tbv(a AND b);
};
...
const int_16 _temp1[] = {4,5,6};
result0 = _tbv(_mov_const_list(word,data,_temp1) == 0);
if (result0) ...
result1 = _tbv((a > 0) && (a < 10));
if (result1 && result0) ...
result2 = (_tbv(a && 4)) + (b > 2);
result3 = (_tbv(a < 4)) & 7;
result4 = (_tbv(b = 6)) << 2;
If the correctness of your program does not depend on the pTAL
representation, you can create more attractive and efficient code
by removing the invocation of _tbv.
_tbv
The _tbv macro, supplied in the rosgen.h include file, converts a boolean
expression value from a C++ representation to a pTAL representation.
int_16 _tbv(int_16 expr)
expr
is a C++ boolean expression.
Usage Considerations
The _tbv macro converts the representation of the boolean value expr
by negating the value of the expression given as an argument.
In a context which accepts any nonzero value as indicating the boolean
value true, an IF statement conditional expression or an operand to a
conditional operator, the invocation of the _tbv macro can be removed
without disturbing the behavior of the code.
#endif
//-------------------------------------------------------------------------
// This define is used to map boolean expression values from the C++
// canonical value to the pTAL canonical value.
#define _tbv(expr) ((expr) ? -1 : 0)
//---------------------
// Simple type defines:
//---------------------
#define unsigned_char unsigned char
#define int_16 short
// This typedef and the those below for unsigned short and unsigned long are
// here so token pasting in the _item2, _redef2, _array2, and _redefarray2
// defines works correctly. They insure that type-denoting defines always have
// at most one token.
// dg64 - vvv - Add xint_32/xunsigned_32
// xint_32 is a REAL 32-bit item
typedef int _xint_32;
#define xint_32 _xint_32
typedef unsigned int _xunsigned_32;
#define xunsigned_32 _xunsigned_32
// dg64 - ^^^
#ifdef NA_64BIT
typedef struct { long l1; long l2; } _int_128;
#define int_128 _int_128
#endif
typedef long Long;
typedef int _int_32;
#define int_32 _int_32
typedef long _int_ptr;
#define int_ptr _int_ptr
#define long_ptraddr_val Long
#ifdef _MSC_VER
#ifdef NA_64BIT
// dg64 - the right type
typedef unsigned int _unsigned_32;
typedef unsigned long _unsigned_64;
#else
typedef unsigned long _unsigned_32;
#endif
//typedef __int64 _int_64;
#else
#ifdef NA_64BIT
// dg64 - the right type
typedef unsigned int _unsigned_32;
typedef unsigned long _unsigned_64; // sss use the define in sqtypes.h
typedef long _int_64;
#else
typedef unsigned long _unsigned_32;
typedef unsigned long long int _unsigned_64;
typedef long long _int_64;
#endif
#endif
#define unsigned_64 _unsigned_64
#define unsigned_32 _unsigned_32
#define int_64 _int_64
typedef float _real_32;
#define real_32 _real_32
typedef double _real_64;
#define real_64 _real_64
typedef unsigned short _unsigned_16;
#define unsigned_16 _unsigned_16
#define fixed_n19 int_64
#define fixed_n18 int_64
#define fixed_n17 int_64
#define fixed_n16 int_64
#define fixed_n15 int_64
#define fixed_n14 int_64
#define fixed_n13 int_64
#define fixed_n12 int_64
#define fixed_n11 int_64
#define fixed_n10 int_64
#define fixed_n9 int_64
#define fixed_n8 int_64
#define fixed_n7 int_64
#define fixed_n6 int_64
#define fixed_n5 int_64
#define fixed_n4 int_64
#define fixed_n3 int_64
#define fixed_n2 int_64
#define fixed_n1 int_64
#define fixed_0 int_64
#define fixed_1 int_64
#define fixed_2 int_64
#define fixed_3 int_64
#define fixed_4 int_64
#define fixed_5 int_64
#define fixed_6 int_64
#define fixed_7 int_64
#define fixed_8 int_64
#define fixed_9 int_64
#define fixed_10 int_64
#define fixed_11 int_64
#define fixed_12 int_64
#define fixed_13 int_64
#define fixed_14 int_64
#define fixed_15 int_64
#define fixed_16 int_64
#define fixed_17 int_64
#define fixed_18 int_64
#define fixed_19 int_64
#define fixed_star int_64
//------------------
// Address typedefs:
//------------------
typedef void _near _baddr * baddr;
typedef void _near _waddr * waddr;
typedef void _far * extaddr;
typedef void _procaddr * procaddr;
typedef unsigned_char _cspace const _baddr _near * cbaddr;
typedef int_16 _cspace const _waddr _near * cwaddr;
//-------------------------------------------------------------------------
#if 0
Bit Field Data Type
The pTAL language supports the declaration of a bit field within a structure
or as a variable in its own right. The C++ language only supports the
declaration of a bit field within a structure.
Bit Field Declared as a Structure Item
The pTAL to C++ Translator translates a pTAL bit field within a structure
to a C++ bit field within a structure. It declares the bit field with
either the conventional C++ bit field declaration syntax or the _bitfield
macro. Either means of declaring the data item directs the compiler to
allocate a bit field with the same size and position within the structure
as its pTAL counterpart.
The following example illustrates one pTAL bit field structure item that
is translated to a conventional C++ bit field declaration and one that is
translated to the _bitfield macro which declares the data and an access
function.
pTAL Code Generated C++ Code
?ENCAPSULATE_STRUCT ttype
STRUCT stype(*); struct stype {
BEGIN unsigned a:4;
UNSIGNED(4) a; };
END;
STRUCT ttype (*); class ttype {
BEGIN public:
UNSIGNED(4) a; _bitfield(ttype,a,4);
END; };
STRUCT s(stype); stype s;
STRUCT t(ttype); ttype t;
INT(16) x; int_16 x;
s.a := 7; s.a = 7;
x := s.a; x = s.a;
t.a := 7; t.a() = 7;
x := t.a; x = t.a();
Bit Field Declared as a Variable
A bit field variable generated by the pTAL to C++ Translator occupies a
16-bit or 32-bit container. Values that are stored into a bit field are
trimmed to occupy the appropriate number of bits. The classes _unsigned_1,
_unsigned_2, through _unsigned_15 and _unsigned_17 through _unsigned_31
implement bit fields.
_unsigned_n
The classes _unsigned_1, _unsigned_2, _unsigned_3, _unsigned_4,
_unsigned_5 _unsigned_6, _unsigned_7, _unsigned_8, _unsigned_9
_unsigned_10, _unsigned_11, _unsigned_12, _unsigned_13, _unsigned_14,
_unsigned_15, _unsigned_17, _unsigned_18, _unsigned_19, _unsigned_20,
_unsigned_21, _unsigned_22, _unsigned_23, _unsigned_24, _unsigned_25,
_unsigned_26, _unsigned_27, _unsigned_28, _unsigned_29, _unsigned_30,
and _unsigned_31 implement bit field variables.
These classes each provide a default constructor and a type conversion
constructor that trims an integer to fit into the bit field. They each
also provide an assignment operator.
_unsigned_n()
_unsigned_n(int_type value)
n
is an integer 1 through 15 or 17 through 31.
int_type
is a 16-bit integer if n is 1 through 15 and a 32-bit integer if n is 17
through 31.
value
is a 16-bit integer value being converted to an _unsigned_1 through
_unsigned_15 or a 32-bit integer value being converted to an _unsigned_17
through _unsigned_31.
unsigned_type& operator=(const int_type value)
unsigned_type& operator=(_unsigned_n unsigned_class)
n
is an integer 1 through 15 or 17 through 31.
int_type
is a 16-bit integer if n is 1 through 15 and a 32-bit integer if n is 17
through 31.
unsigned_type
is a 16-bit unsigned integer if n is 1 through 15 and a 32-bit unsigned
integer if n is 17 through 31.
value
is a 16-bit integer value being converted to an _unsigned_1 through
_unsigned_15 or a 32-bit integer value being converted to an _unsigned_17
through _unsigned_31.
unsigned_class
is an _unsigned_1 through _unsigned_15 if this is an _unsigned_1 through
_unsigned_15 and is an _unsigned_17 through _unsigned_31 if this is an
_unsigned_17 through _unsigned_31.
Example
The following example illustrates the declaration of a 6-bit variable named
a and an array named b made up of four 4-bit cells. The _unsigned_n classes
define an assignment operator and an access function which must be employed
to use the value stored in the bit field variable as an lvalue. In this
example, the value 15 can fit into the six bits that make up the storage
available to the variable a. The value 18 cannot fit into the four bits
that make up the storage available to the second cell of the variable b,
so the most significant bits of that value are trimmed. The value 3 is
stored in b[1] after the trimming.
pTAL Code Generated C++ Code
unsigned(6) a; _unsigned_6 a;
unsigned(4) b[0:3]; _unsigned_4 b[4];
int_16 x; int_16 x;
a := 15; a = 15;
x := a; x = a();
b[1] := 18; b[1] = 18;
x := b[1]; x = b[1]();
#endif
//-------------------------------------------------------------------------
class _bitfield16_outside_struct {
public:
_bitfield16_outside_struct(){};
_bitfield16_outside_struct(int_16 d){d = d;};
unsigned_16& operator ()(){return data;};
protected:
unsigned_16 data;
};
class _bitfield32_outside_struct {
public:
_bitfield32_outside_struct(){};
_bitfield32_outside_struct(int_16 d){d = d;};
unsigned_32& operator ()(){return data;};
protected:
unsigned_32 data;
};
#define _decl_bitfield_outside_struct(bitcount) \
class _unsigned_##bitcount : public _bitfield16_outside_struct { \
public: \
_unsigned_##bitcount () { data = 0;} \
_unsigned_##bitcount (int_16 d) { data = d & ((1u << bitcount)-1);} \
unsigned_16& operator=(const int d) { \
data = d & ((1u << bitcount)-1); \
return data;} \
unsigned_16& operator=(_bitfield16_outside_struct d) { \
data = d() & ((1u << bitcount)-1); \
return data;} \
unsigned_16& operator=(_bitfield32_outside_struct d) { \
data = d() & ((1u << bitcount)-1); \
return data;} \
operator int() {return data;} /*pdv*/ \
}
_decl_bitfield_outside_struct(1);
_decl_bitfield_outside_struct(2);
_decl_bitfield_outside_struct(3);
_decl_bitfield_outside_struct(4);
_decl_bitfield_outside_struct(5);
_decl_bitfield_outside_struct(6);
_decl_bitfield_outside_struct(7);
_decl_bitfield_outside_struct(8);
_decl_bitfield_outside_struct(9);
_decl_bitfield_outside_struct(10);
_decl_bitfield_outside_struct(11);
_decl_bitfield_outside_struct(12);
_decl_bitfield_outside_struct(13);
_decl_bitfield_outside_struct(14);
_decl_bitfield_outside_struct(15);
#undef _decl_bitfield_outside_struct
#define _decl_bitfield_outside_struct(bitcount) \
class _unsigned_##bitcount : public _bitfield32_outside_struct { \
public: \
_unsigned_##bitcount () { data = 0;} \
_unsigned_##bitcount (int_32 d) { data = d & ((1u << bitcount)-1);} \
unsigned_32& operator=(const int d) { \
data = d & ((1u << bitcount)-1); \
return data;} \
unsigned_32& operator=(_bitfield16_outside_struct d) { \
data = d() & ((1u << bitcount)-1); \
return data;} \
unsigned_32& operator=(_bitfield32_outside_struct d) { \
data = d() & ((1u << bitcount)-1); \
return data;} \
}
_decl_bitfield_outside_struct(17);
_decl_bitfield_outside_struct(18);
_decl_bitfield_outside_struct(19);
_decl_bitfield_outside_struct(20);
_decl_bitfield_outside_struct(21);
_decl_bitfield_outside_struct(22);
_decl_bitfield_outside_struct(23);
_decl_bitfield_outside_struct(24);
_decl_bitfield_outside_struct(25);
_decl_bitfield_outside_struct(26);
_decl_bitfield_outside_struct(27);
_decl_bitfield_outside_struct(28);
_decl_bitfield_outside_struct(29);
_decl_bitfield_outside_struct(30);
_decl_bitfield_outside_struct(31);
#undef _decl_bitfield_outside_struct
//-------------------------------------------------------------------------
#if 0
The pTAL language allows you to explicitly check whether or not an
arithmetic operation produced an arithmetic overflow by disabling
OVERFLOW_TRAPS and checking the value returned by the $OVERFLOW
standard function.
This section describes the code generated by the pTAL to C++ Translator
to emulate pTAL overflow checking.
If your code uses the routines described in this section, you must bind
the overflow trapping library, roselib.o, into your program before
executing it. This library implements all of the routines described
in this section.
Emulating pTAL Overflow Checking
The pTAL to C++ Translator emulates pTAL overflow checking by generating
calls to functions that perform the arithmetic operation and return an
indication of whether or not the operation resulted in an arithmetic overflow.
For example:
pTAL Code Generated C++ Code
#pragma push overflow_traps
#pragma nooverflow_traps
PROC jed NOOVERFLOW_TRAPS; extern "C" void JED()
BEGIN {
... ...
x := a + b; x = _int16_ov_add(a,b,
IF $OVERFLOW THEN ... &_ov_temp);
if (_ov_temp) ...
x := $FIXI(f); x = _int64_to_int16_ov(f,
&_ov_temp);
if $OVERFLOW THEN ... if (_ov_temp) ...
_int16_ov_add,
_int32_ov_add,
_real32_ov_add,
_real64_ov_add, and
_fixed_ov_add
The _int16_ov_add, _int32_ov_add, _real32_ov_add, _real64_ov_add, and
_fixed_ov_add functions add two values and explicitly check for overflow.
Explicit overflow checking is only appropriate when the nooverflow_traps
pragma is in effect.
int_16 _int16_ov_add(int_16 first_operand,
int_16 second_operand,
int_16 *overflow_result)
int_32 _int32_ov_add(int_32 first_operand,
int_32 second_operand,
int_16 *overflow_result)
real_32 _real32_ov_add(real_32 first_operand,
real_32 second_operand,
int_16 *overflow_result)
real_64 _real64_ov_add(real_64 first_operand,
real_64 second_operand,
int_16 *overflow_result)
int_64 _fixed_ov_add(int_64 first_operand,
int_64 second_operand,
int_16 *overflow_result)
first_operand
is an expression that is the first operand of the addition operator.
second_operand
is an expression that is the second operand of the addition operator.
overflow_result
is a pointer to a 16-bit integer variable into which the value 0 is
placed if the addition does not result in an overflow and the value 1
is placed if the addition does result in an overflow.
Usage Considerations
first_operand is added to second_operand to calculate the returned result.
The following example illustrates a use of the _int16_ov_add function.
pTAL Code Generated C++ Code
?NOOVERFLOW_TRAPS #pragma nooverflow_traps
... ...
int_16 _ov_temp;
INT(16) a := 13; int_16 a = 13;
INT(16) b := 14; int_16 b = 14;
INT(16) x; int_16 x;
x := a + b; x = _int16_ov_add(a,b,&_ov_temp);
IF $OVERFLOW THEN if (_ov_temp)
_int16_ov_sub,
_int32_ov_sub,
_real32_ov_sub,
_real64_ov_sub, and
_fixed_ov_sub
The _int16_ov_sub, _int32_ov_sub, _real32_ov_sub, _real64_ov_sub, and
_fixed_ov_sub functions subtract one value from another and explicitly
check for overflow. Explicit overflow checking is only appropriate
when the nooverflow_traps pragma is in effect.
int_16 _int16_ov_sub(int_16 first_operand,
int_16 second_operand,
int_16 *overflow_result)
int_32 _int32_ov_sub(int_32 first_operand,
int_32 second_operand,
int_16 *overflow_result)
real_32 _real32_ov_sub(real_32 first_operand,
real_32 second_operand,
int_16 *overflow_result)
real_64 _real64_ov_sub(real_64 first_operand,
real_64 second_operand,
int_16 *overflow_result)
int_64 _fixed_ov_sub(int_64 first_operand,
int_64 second_operand,
int_16 *overflow_result)
first_operand
is an expression that is the first operand of the subtraction operator.
second_operand
is an expression that is the second operand of the subtraction operator.
overflow_result
is a pointer to a 16-bit integer variable into which the value 0 is
placed if the subtraction does not result in an overflow and the value
1 is placed if the subtraction does result in an overflow.
Usage Considerations
second_operand is subtracted from first_operand to calculate the result.
The following example illustrates a use of the _int16_ov_sub function.
pTAL Code Generated C++ Code
?NOOVERFLOW_TRAPS #pragma nooverflow_traps
... ...
int_16 _ov_temp;
INT(16) a := 13; int_16 a = 13;
INT(16) b := 14; int_16 b = 14;
INT(16) x; int_16 x;
x := a - b; x = _int16_ov_sub(a,b,&_ov_temp);
IF $OVERFLOW THEN if (_ov_temp)
_int16_ov_mul,
_int32_ov_mul,
_real32_ov_mul,
_real64_ov_mul, and
_fixed_ov_mul
The _int16_ov_mul, _int32_ov_mul, _real32_ov_mul, _real64_ov_mul, and
_fixed_ov_mul functions multiply one value by another and explicitly
check for overflow. Explicit overflow checking is only appropriate
when the nooverflow_traps pragma is in effect.
int_16 _int16_ov_mul(int_16 first_operand,
int_16 second_operand,
int_16 *overflow_result)
int_32 _int32_ov_mul(int_32 first_operand,
int_32 second_operand,
int_16 *overflow_result)
real_32 _real32_ov_mul(real_32 first_operand,
real_32 second_operand,
int_16 *overflow_result)
real_64 _real64_ov_mul(real_64 first_operand,
real_64 second_operand,
int_16 *overflow_result)
int_64 _fixed_ov_mul(int_64 first_operand,
int_64 second_operand,
int_16 *overflow_result)
first_operand
is an expression that is the first operand of the multiplication operator.
second_operand
is an expression that is the second operand of the multiplication operator.
overflow_result
is a pointer to a 16-bit integer variable into which the value 0 is
placed if the multiplication does not result in an overflow and the
value 1 is placed if the multiplication does result in an overflow.
Usage Considerations
first_operand is multiplied by second_operand to calculate the returned result.
The following example illustrates a use of the _int16_ov_mul function.
pTAL Code Generated C++ Code
?NOOVERFLOW_TRAPS #pragma nooverflow_traps
... ...
int_16 _ov_temp;
INT(16) a := 13; int_16 a = 13;
INT(16) b := 14; int_16 b = 14;
INT(16) x; int_16 x;
x := a * b; x = _int16_ov_mul(a,b,&_ov_temp);
IF $OVERFLOW THEN if (_ov_temp)
_int16_ov_div,
_int32_ov_div,
_real32_ov_div,
_real64_ov_div, and
_fixed_ov_div
The _int16_ov_div, _int32_ov_div, _real32_ov_div, _real64_ov_div, and
_fixed_ov_div functions divide one value by another and explicitly check
for overflow. Explicit overflow checking is only appropriate when the
nooverflow_traps pragma is in effect.
int_16 _int16_ov_div(int_16 first_operand,
int_16 second_operand,
int_16 *overflow_result)
int_32 _int32_ov_div(int_32 first_operand,
int_32 second_operand,
int_16 *overflow_result)
real_32 _real32_ov_div(real_32 first_operand,
real_32 second_operand,
int_16 *overflow_result)
real_64 _real64_ov_div(real_64 first_operand,
real_64 second_operand,
int_16 *overflow_result)
int_64 _fixed_ov_div(int_64 first_operand,
int_64 second_operand,
int_16 *overflow_result)
first_operand
is an expression that is the first operand of the division operator.
second_operand
is an expression that is the second operand of the division operator.
overflow_result
is a pointer to a 16-bit integer variable into which the value 0 is placed
if the division does not result in an overflow and the value 1 is placed
if the division does result in an overflow.
Usage Considerations
first_operand is divided by second_operand to calculate the returned result.
The following example illustrates a use of the _int16_ov_div function.
pTAL Code Generated C++ Code
?NOOVERFLOW_TRAPS #pragma nooverflow_traps
... ...
int_16 _ov_temp;
INT(16) a := 13; int_16 a = 13;
INT(16) b := 14; int_16 b = 14;
INT(16) x; int_16 x;
x := a / b; x = _int16_ov_div(a,b,&_ov_temp);
IF $OVERFLOW THEN if (_ov_temp)
_int16_ov_negate
_int32_ov_negate
_fixed_ov_negate
The _int16_ov_negate, _int32_ov_negate, and _fixed_ov_negate functions
negate a value and explicitly check for overflow. Explicit overflow
checking is only appropriate when the nooverflow_traps pragma is in effect.
int_16 _int16_ov_negate(int_16 operand)
int_32 _int32_ov_negate(int_32 operand)
int_64 _fixed_ov_negate(int_64 operand)
operand
is an expression to be negated.
Usage Considerations
operand is negated to obtain the returned result.
The following example illustrates a use of the _int16_ov_negate function.
pTAL Code Generated C++ Code
?NOOVERFLOW_TRAPS #pragma nooverflow_traps
... ...
int_16 _ov_temp;
INT(16) a := 13; int_16 a = 13;
INT(16) x; int_16 x;
x := -a; x = _int16_ov_negate(a,
&_ov_temp);
IF $OVERFLOW THEN if (_ov_temp)
_int64_to_int16_ov
The _int64_to_int16_ov function converts an int_64 value to an int_16 value
and explicitly checks for overflow. Explicit overflow checking is only
appropriate when the nooverflow_traps pragma is in effect.
int_16 _int64_to_int16_ov(int_64 argument
int_16 *overflow_result)
argument
is the value to be converted to the return type.
overflow_result
is a pointer to a 16-bit integer variable into which the value 0 is
placed if the conversion does not result in an overflow and the value
1 is placed if the conversion does result in an overflow.
Usage Considerations
The _int_64_to_int16_ov function is equivalent to the pTAL $FIXI standard
function.
pTAL Code Generated C++ Code
?NOOVERFLOW_TRAPS #pragma nooverflow_traps
... ...
int_16 _ov_temp;
INT(16) i16; int_16 i16;
FIXED(0) f0 := 25F; fixed_0 f0 = 25LL;
i16 := $FIXI(f0); i16 = (int_16) _int64_to_int16_ov
(f0,&_ov_temp);
IF $OVERFLOW THEN if (_ov_temp)
_int64_to_uint16_ov
The _int64_to_uint16_ov function converts an int_64 value to an unsigned_16
value and explicitly checks for overflow. Explicit overflow checking is only
appropriate when the nooverflow_traps pragma is in effect.
unsigned_16 _int64_to_uint16_ov(int_64 argument
int_16 *overflow_result)
argument
is the value to be converted to the return type.
overflow_result
is a pointer to a 16-bit integer variable into which the value 0 is
placed if the conversion does not result in an overflow and the value
1 is placed if the conversion does result in an overflow.
Usage Considerations
The _int64_to_uint16_ov function is equivalent to the pTAL $FIXL standard
function.
pTAL Code Generated C++ Code
?NOOVERFLOW_TRAPS #pragma nooverflow_traps
... ...
int_16 _ov_temp;
INT(16) i16; int_16 i16;
FIXED(0) f0 := 25F; fixed_0 f0 = 25LL;
i16 := $FIXL(f0); i16 = (int_16)_int64_to_uint16_ov
(f0,&_ov_temp);
IF $OVERFLOW THEN if (_ov_temp)
_int64_to_int32_ov
The _int64_to_int32_ov function converts an int_64 value to an int_32
value and explicitly checks for overflow. Explicit overflow checking
is only appropriate when the nooverflow_traps pragma is in effect.
int_32 _int64_to_int32_ov(int_64 argument
int_16 *overflow_result)
argument
is the value to be converted to the return type.
overflow_result
is a pointer to a 16-bit integer variable into which the value 0 is
placed if the conversion does not result in an overflow and the value 1
is placed if the conversion does result in an overflow.
Usage Considerations
The _int64_to_int32_ov function is equivalent to the pTAL $FIXD standard
function.
pTAL Code Generated C++ Code
?NOOVERFLOW_TRAPS #pragma nooverflow_traps
... ...
int_16 _ov_temp;
INT(32) i32; int_32 i32;
FIXED(0) f0 := 35F; fixed_0 f0 = 35LL;
i16 := $FIXD(f0); i16 = (int_32) _int64_to_int32_ov
(f0,&_ov_temp);
IF $OVERFLOW THEN if (_ov_temp)
_real32_to_int64_ov
The _real32_to_int64_ov function converts a real_32 value to an int_64
value and explicitly checks for overflow. Explicit overflow checking
is only appropriate when the nooverflow_traps pragma is in effect.
int_64 _real32_to_int64_ov(real_32 argument
int_16 *overflow_result)
argument
is the value to be converted to the return type.
overflow_result
is a pointer to a 16-bit integer variable into which the value 0 is
placed if the conversion does not result in an overflow and the value 1
is placed if the conversion does result in an overflow.
Usage Considerations
The _real32_to_int64_ov function is equivalent to the pTAL $FIX standard
function.
pTAL Code Generated C++ Code
?NOOVERFLOW_TRAPS #pragma nooverflow_traps
... ...
int_16 _ov_temp;
REAL(32) r32 := 2.2E00; real_32 r32 = 2.2E+00F;
FIXED(0) f0; fixed_0 f0;
f0 := $FIX(r32); f0 = _real32_to_int64_ov
(r32,&_ov_temp);
IF $OVERFLOW THEN if (_ov_temp)
_real64_to_int64_ov
The _real64_to_int64_ov function converts a real_64 value to an int_64
value and explicitly checks for overflow. Explicit overflow checking
is only appropriate when the nooverflow_traps pragma is in effect.
int_64 _real64_to_int64_ov(real_64 argument
int_16 *overflow_result)
argument
is the value to be converted to the return type.
overflow_result
is a pointer to a 16-bit integer variable into which the value 0 is
placed if the conversion does not result in an overflow and the value 1
is placed if the conversion does result in an overflow.
Usage Considerations
The _real64_to_int64_ov function is equivalent to the pTAL $FIX standard
function.
pTAL Code Generated C++ Code
?NOOVERFLOW_TRAPS #pragma nooverflow_traps
... ...
int_16 _ov_temp;
REAL(64) r64 := 2.2L00; real_64 r64 = 2.2E+00;
FIXED(0) f0; fixed_0 f0;
f0 := $FIX(r64); f0 = _real64_to_int64_ov
(r64,&_ov_temp);
IF $OVERFLOW THEN if (_ov_temp)
_real32_to_int64_rnd_ov
The _real32_to_int64_rnd_ov function converts a real_32 value to an int_64
value, rounds the result, and explicitly checks for overflow. Explicit
overflow checking is only appropriate when the nooverflow_traps pragma is
in effect.
int_64 _real32_to_int64_rnd_ov(real_32 argument
int_16 *overflow_result)
argument
is the value to be converted to the return type.
overflow_result
is a pointer to a 16-bit integer variable into which the value 0 is
placed if the conversion does not result in an overflow and the value 1
is placed if the conversion does result in an overflow.
Usage Considerations
The _real32_to_int64_rnd_ov function is equivalent to the pTAL $FIXR standard
function.
pTAL Code Generated C++ Code
?ROUND
?NOOVERFLOW_TRAPS #pragma nooverflow_traps
... ...
int_16 _ov_temp;
REAL(32) r32 := 2.2E00; real_32 r32 = 2.2E+00F;
FIXED(0) f0; fixed_0 f0;
f0 := $FIXR(r32); f0 = _real32_to_int64_rnd_ov
(r32,&_ov_temp);
IF $OVERFLOW THEN if (_ov_temp)
_real64_to_int64_rnd_ov
The _real64_to_int64_rnd_ov function converts a real_64 value to an int_64
value, rounds the result and explicitly checks for overflow. Explicit
overflow checking is only appropriate when the nooverflow_traps pragma is
in effect.
int_64 _real64_to_int64_rnd_ov(real_64 argument
int_16 *overflow_result)
argument
is the value to be converted to the return type.
overflow_result
is a pointer to a 16-bit integer variable into which the value 0 is
placed if the conversion does not result in an overflow and the value 1
is placed if the conversion does result in an overflow.
Usage Considerations
The _real64_to_int64_rnd_ov function is equivalent to the pTAL $FIXR standard
function.
pTAL Code Generated C++ Code
?NOOVERFLOW_TRAPS #pragma nooverflow_traps
... ...
int_16 _ov_temp;
REAL(64) r64 := 2.2L00; real_64 r64 = 2.2E+00;
FIXED(0) f0; fixed_0 f0;
f0 := $FIXR(r64); f0 = _real64_to_int64_rnd_ov
(r64,&_ov_temp);
IF $OVERFLOW THEN if (_ov_temp)
#endif
//-------------------------------------------------------------------------
// Interfaces for overflow check routines (implementation in roslib.tal)
#define _binary_ov_proc(outType, inType, cppName, ptalName) \
extern "C" _alias (ptalName) outType cppName (inType x, \
inType y, \
int_16 _near *ov)
#define _unary_ov_proc(outType, inType, cppName, ptalName) \
extern "C" _alias (ptalName) outType cppName (inType x, \
int_16 _near *ov)
#define _unary_proc(outType, inType, cppName, ptalName) \
extern "C" _alias (ptalName) outType cppName (inType x)
_binary_ov_proc (int_16, int_16, _int16_ov_add, "_INT16_OV_ADD");
_binary_ov_proc (int_32, int_32, _int32_ov_add, "_INT32_OV_ADD");
_binary_ov_proc (real_32, real_32, _real32_ov_add, "_REAL32_OV_ADD");
_binary_ov_proc (real_64, real_64, _real64_ov_add, "_REAL64_OV_ADD");
_binary_ov_proc (int_64, int_64, _fixed_ov_add, "_FIXED_OV_ADD");
_binary_ov_proc (int_16, int_16, _int16_ov_sub, "_INT16_OV_SUB");
_binary_ov_proc (int_32, int_32, _int32_ov_sub, "_INT32_OV_SUB");
_binary_ov_proc (real_32, real_32, _real32_ov_sub, "_REAL32_OV_SUB");
_binary_ov_proc (real_64, real_64, _real64_ov_sub, "_REAL64_OV_SUB");
_binary_ov_proc (int_64, int_64, _fixed_ov_sub, "_FIXED_OV_SUB");
_binary_ov_proc (int_16, int_16, _int16_ov_mul, "_INT16_OV_MUL");
_binary_ov_proc (int_32, int_32, _int32_ov_mul, "_INT32_OV_MUL");
_binary_ov_proc (real_32, real_32, _real32_ov_mul, "_REAL32_OV_MUL");
_binary_ov_proc (real_64, real_64, _real64_ov_mul, "_REAL64_OV_MUL");
_binary_ov_proc (int_64, int_64, _fixed_ov_mul, "_FIXED_OV_MUL");
_binary_ov_proc (int_16, int_16, _int16_ov_div, "_INT16_OV_DIV");
_binary_ov_proc (int_32, int_32, _int32_ov_div, "_INT32_OV_DIV");
_binary_ov_proc (real_32, real_32, _real32_ov_div, "_REAL32_OV_DIV");
_binary_ov_proc (real_64, real_64, _real64_ov_div, "_REAL64_OV_DIV");
_binary_ov_proc (int_64, int_64, _fixed_ov_div, "_FIXED_OV_DIV");
_unary_proc (int_64, real_32, _real32_to_int64, "_REAL32_TO_INT64");
_unary_proc (int_64, real_64, _real64_to_int64, "_REAL64_TO_INT64");
_unary_proc (int_64, real_32, _real32_to_int64_rnd, "_REAL32_TO_INT64_RND");
_unary_proc (int_64, real_64, _real64_to_int64_rnd, "_REAL64_TO_INT64_RND");
_unary_proc (real_32, int_32, _int32_to_real32_rnd, "_INT32_TO_REAL32_RND");
_unary_proc (real_64, int_32, _int32_to_real64_rnd, "_INT32_TO_REAL64_RND");
_unary_proc (real_32, int_64, _int64_to_real32_rnd, "_INT64_TO_REAL32_RND");
_unary_proc (real_64, int_64, _int64_to_real64_rnd, "_INT64_TO_REAL64_RND");
_unary_proc (real_32, real_64, _real64_to_real32_rnd, "_REAL64_TO_REAL32_RND");
_unary_ov_proc (int_64, real_32, _real32_to_int64_ov, "_REAL32_TO_INT64_OV");
_unary_ov_proc (int_64, real_64, _real64_to_int64_ov, "_REAL64_TO_INT64_OV");
_unary_ov_proc
(int_64, real_32, _real32_to_int64_rnd_ov, "_REAL32_TO_INT64_RND_OV");
_unary_ov_proc
(int_64, real_64, _real64_to_int64_rnd_ov, "_REAL64_TO_INT64_RND_OV");
_unary_ov_proc
(real_32, real_64, _real64_to_real32_rnd_ov, "_REAL64_TO_REAL32_RND_OV");
_unary_ov_proc (int_16, int_64, _int64_to_int16_ov, "_INT64_TO_INT16_OV");
_unary_ov_proc
(unsigned_16, int_64, _int64_to_uint16_ov, "_INT64_TO_UINT16_OV");
_unary_ov_proc (int_32, int_64, _int64_to_int32_ov, "_INT64_TO_INT32_OV");
_unary_ov_proc (int_16, int_16, _int16_ov_negate, "_INT16_OV_NEGATE");
_unary_ov_proc (int_32, int_32, _int32_ov_negate, "_INT32_OV_NEGATE");
_unary_ov_proc (int_64, int_64, _fixed_ov_negate, "_FIXED_OV_NEGATE");
#undef _binary_ov_proc
#undef _unary_ov_proc
#undef _unary_proc
//-------------------------------------------------------------------------
#if 0
_pow_of_10
The _pow_of_10 function returns a constant that is the appropriate power
of 10.
int_64 _pow_of_10(int_16 expr)
expr
is an expression.
Usage Considerations
The _pow_of_10 function returns 10 raised to the expr power.
This function is useful for converting a fixed-point value to a real value.
The following example converts a fixed-point value stored in the variable
f2 to a real_32 type value, and stores the resultant value in the variable
result.
pTAL Code Generated C++ Code
REAL(32) r32; real_32 r32;
REAL(64) r64; real_64 r64;
FIXED(2) f2 := 2F; fixed_2 f2 = _scale_up(2LL,2);
r32 := $FLT(f2); r32 = (real_32)f2/
(real_32)_pow_of_10(2);
r64 := $EFLT(f2); r64 = (real_64)f2/_pow_of_10(2);
#endif
//-------------------------------------------------------------------------
_resident inline int_64 _pow_of_10 (int_16 exp) {
switch (exp) {
case -9: return (int_64)1000000000;
case -8: return (int_64)100000000;
case -7: return (int_64)10000000;
case -6: return (int_64)1000000;
case -5: return (int_64)100000;
case -4: return (int_64)10000;
case -3: return (int_64)1000;
case -2: return (int_64)100;
case -1: return (int_64)10;
case 0: return (int_64)1;
case 1: return (int_64)10;
case 2: return (int_64)100;
case 3: return (int_64)1000;
case 4: return (int_64)10000;
case 5: return (int_64)100000;
case 6: return (int_64)1000000;
case 7: return (int_64)10000000;
case 8: return (int_64)100000000;
case 9: return (int_64)1000000000;
}
#if USE_LL
return 0x7FFFFFFFFFFFFFFFLL;
#else
#if USE_L
#if (defined(NA_LINUX) || defined(SQ_LINUX)) && !defined(NA_64BIT)
return -1;
#else
return 0x7FFFFFFFFFFFFFFFL;
#endif
#else
return 0x7FFFFFFFFFFFFFFF;
#endif
#endif
} // _pow_of_10
//-------------------------------------------------------------------------
#if 0
FIXED Data Type
The Tandem C++ language has no types equivalent to pTAL fixed point types
with a nonzero fixed point setting. The pTAL to C++ Translator emits code
to explicitly scale 64-bit integer values in order to emulate fixed point
type operations. For example:
pTAL Code Generated C++ Code
FIXED(0) f0 := 2.0F; fixed_0 f0 = _scale_down(20,1);
FIXED(1) f1 := 2.0F; fixed_1 f1 = 20;
FIXED(2) f2 := 2.0F; fixed_2 f2 = _scale_up(20,1);
f0 := f0 + 1F; f0 = f0 + 1;
f1 := f1 + 1F; f1 = f1 + _scale_up(1,1);
f2 := f2 + 1F; f2 = f2 + _scale_up(1,2);
f1 := f0 + 2F; f1 = _scale_up(f0 + 2,1);
f1 := f2 + 3F; f1 = _scale_down(f2 +
_scale_up(3,2),1);
The macros fixed_0, fixed_1, fixed_2, through fixed_1 and fixed_n1 through
fixed_n19 are aliases for int_64 which is itself an alias for long long
which is a 64-bit integer type on Tandem machines.
Scaling up multiplies the argument by a power of ten, and scaling down
divides the argument by a power of ten.
#endif
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
#if 0
_point
The _point macro returns the scale factor associated with a fixed point
expression.
int_16 _point(fixed_n expr_to_scale,
int_16 scale_factor)
expr
is a fixed-point type expression.
scale_factor
is the number of decimal points by which to scale expr_to_scale.
Usage Considerations
The _point macro is intended to document a use of the pTAL $POINT standard
function. In the following example, the variable x is assigned the value 3,
to which the macro _point evaluates.
pTAL Code Generated C++ Code
INT(16) x; int_16 x;
FIXED(3) f3; fixed_3 f3;
x := $POINT(f3); x = _point(f3,3);
#endif
//-------------------------------------------------------------------------
#define _point(expr, scale) (scale)
//-------------------------------------------------------------------------
#if 0
_scale_up
The _scale_up macro scales an expression up by the given number of decimal
points.
int_64 _scale_up(fixed_n expr_to_scale,
int_16 scale_factor)
expr_to_scale
is an expression whose value is to be scaled.
scale_factor
is an integer value that is the number of decimal points by which to scale
expr_to_scale.
Usage Considerations
A value is scaled up by moving its decimal point to the right.
In the following example, the 64-bit integer variable f2 gets the value 4500,
the result of moving the decimal point two places to the right.
pTAL Code Generated C++ Code
FIXED(2) f2 := 45F; fixed_2 f2 := _scale_up(45,2)
#endif
//-------------------------------------------------------------------------
#define _scale_up(x, factor) \
((x) * _pow_of_10 (factor))
//-------------------------------------------------------------------------
#if 0
_scale_up_ov
The _scale_up_ov macro scales an expression up by the given number of decimal
points and explicitly checks for overflow.
int_64 _scale_up_ov(fixed_n expr_to_scale,
int_16 scale_factor
int_16 *overflow_result)
expr_to_scale
is an expression whose value is to be scaled.
scale_factor
is an integer value that is the number of decimal points by which to scale
expr_to_scale.
overflow_result
is a pointer to a 16-bit integer variable into which the value 0 is placed
if the scaling does not result in an overflow and the value 1 is placed if
the scaling does result in an overflow.
Usage Considerations
A value is scaled up by moving its decimal point to the right.
Explicit overflow checking is only appropriate when the nooverflow_traps
pragma is in effect.
In the following example, the 64-bit integer variable f2 gets the value 4500,
the result of moving the decimal point two places to the right.
pTAL Code Generated C++ Code
?NOOVERFLOW_TRAPS #pragma nooverflow_traps
int_16 _ov_temp;
FIXED(2) f2 := 45F; fixed_2 f2 := _scale_up_ov(45,2,
&_ov_temp);
if $OVERFLOW then ... if (_ov_temp) ...
#endif
//-------------------------------------------------------------------------
_resident inline fixed_star _scale_up_ov (fixed_star x,
int_16 factor,
int_16* ov) {
if (factor > 18) {
*ov = 1;
return 0;
}
return _fixed_ov_mul (x, _pow_of_10 (factor), ov);
} // _scale_up_ov
//-------------------------------------------------------------------------
#if 0
_scale_down
The _scale_down macro scales an expression down by the given number of
decimal points.
int_64 _scale_down(fixed_n expr_to_scale,
int_16 scale_factor)
expr_to_scale
is an expression whose value is to be scaled.
scale_factor
is the number of decimal points by which to scale expr_to_scale.
Usage Considerations
A value is scaled down by moving its decimal point to the left.
In the following example, the 64-bit integer variable f0 gets the value .45,
the result of moving the decimal point two places to the left in the
expression 45.
pTAL Code Generated C++ Code
FIXED(0) f0 := 0.45F; fixed_0 f0 = _scale_down(45,2);
#endif
//-------------------------------------------------------------------------
_resident inline fixed_star _scale_down (fixed_star x, int_16 factor) {
if (factor > 18)
return 0;
return x / _pow_of_10 (factor);
} // _scale_down
//-------------------------------------------------------------------------
#if 0
_scale_down_ov
The _scale_down_ov macro scales an expression down by the given number of
decimal points and explicitly checks for overflow.
int_64 _scale_down_ov(fixed_n expr_to_scale,
int_16 scale_factor,
int_16 *overflow_result)
expr_to_scale
is an expression whose value is to be scaled.
scale_factor
is the number of decimal points by which to scale expr_to_scale.
overflow_result
is a pointer to a 16-bit integer variable into which the value 0 is placed
if the scaling does not result in an overflow and the value 1 is placed if
the scaling does result in an overflow.
Usage Considerations
A value is scaled down by moving its decimal point to the left.
Explicit overflow checking is only appropriate when the nooverflow_traps
pragma is in effect.
In the following example, the 64-bit integer variable f2 gets the value
stored in the variable f7, scaling the value and checking for overflow.
pTAL Code Generated C++ Code
?NOOVERFLOW_TRAPS #pragma nooverflow_traps
int_16 _ov_temp;
FIXED(2) f2 := 2.0F; fixed_2 f2 = _scale_up(20,1);
FIXED(7) f7; fixed_7 f7;
f2 := f7; f2 = _scale_down_ov(f7,5,
&_ov_temp);
if $OVERFLOW then ... if (_ov_temp) ...
#endif
//-------------------------------------------------------------------------
_resident inline fixed_star _scale_down_ov (fixed_star x,
int_16 factor,
int_16* ov) {
if (factor > 18) {
*ov = 0;
return 0;
}
return _fixed_ov_div (x, _pow_of_10 (factor), ov);
} // _scale_down_ov
//-------------------------------------------------------------------------
#if 0
_scale_down_rnd
The _scale_down_rnd macro scales an expression down by the given number of
decimal points, applying rounding to the result.
int_64 _scale_down_rnd(fixed_n expr_to_scale,
int_16 scale_factor)
expr_to_scale
is an expression whose value is to be scaled.
scale_factor
is the number of decimal points by which to scale expr_to_scale.
Usage Considerations
A value is scaled down by moving its decimal point to the left.
In the following example, the 64-bit integer variable f2 gets the value
stored in the variable f7, scaling the value and rounding the result.
pTAL Code Generated C++ Code
?ROUND
FIXED(2) f2 := 2.0F; fixed_2 f2 = _scale_up(20,1);
FIXED(7) f7; fixed_7 f7;
f2 := f7; f2 = _scale_down_rnd(f7,4);
#endif
//-------------------------------------------------------------------------
_resident inline fixed_star _scale_down_rnd (fixed_star x, int_16 factor) {
if (factor < 0)
factor = -factor;
if ((factor - 1) > 0)
x = x / _pow_of_10 (factor - 1);
x = x + (x < 0 ? -5 : 5);
return factor > 0 ? x / 10 : x;
} // _scale_down_rnd
//-------------------------------------------------------------------------
#if 0
_scale_down_rnd_ov
The _scale_down_rnd_ov macro scales an expression down by the given number
of decimal points, rounds the result and explicitly checks for overflow.
int_64 _scale_down_rnd_ov(fixed_n expr_to_scale,
int_16 scale_factor,
int_16 *overflow_result)
expr_to_scale
is an expression whose value is to be scaled.
scale_factor
is the number of decimal points by which to scale expr_to_scale.
overflow_result
is a pointer to a 16-bit integer variable into which the value 0 is
placed if the scaling does not result in an overflow and the value 1
is placed if the scaling does result in an overflow.
Usage Considerations
A value is scaled down by moving its decimal point to the left.
Explicit overflow checking is only appropriate when the nooverflow_traps
pragma is in effect.
In the following example, the 64-bit integer variable f2 gets the value
stored in the variable f7, scaling the value, rounding the result, and
checking for overflow.
pTAL Code Generated C++ Code
?ROUND
?NOOVERFLOW_TRAPS #pragma nooverflow_traps
int_16 _ov_temp;
FIXED(2) f2 := 2.0F; fixed_2 f2 = _scale_up(20,1);
FIXED(7) f7; fixed_7 f7;
f2 := f7; f2 = _scale_down_rnd_ov(f7,5,
&_ov_temp);
if $OVERFLOW then ... if (_ov_temp) ...
#endif
//-------------------------------------------------------------------------
inline fixed_star _scale_down_rnd_ov (fixed_star x, int_16 factor, int_16 *ov) {
if (factor < 0)
factor = -factor;
if ((factor - 1) > 0)
x = x / _pow_of_10 (factor - 1);
x = _fixed_ov_add (x, x < 0 ? -5 : 5, ov);
return factor > 0 ? x / 10 : x;
} // _scale_down_rnd_ov
//-------------------------------------------------------------------------
#if 0
Structure Data Types
By default, the pTAL to C++ Translator translates structure elements to
straightforward C++ structure elements. For example:
pTAL Code Generated C++ Code
STRUCT fred(*); struct fred {
BEGIN int_16 a;
INT(16) a; struct {
STRUCT ralph; int_32 b;
BEGIN union {
INT(32) b; int_16 c;
INT(16) c; int_16 ccc;
INT(16) ccc = c; };
END; } ralph;
INT(16) d[0:3]; int_16 d[4];
END; };
The pTAL to C++ Translator uses special macros to declare structure fields
whose types cannot be declared in a straightforward way in C++. This
section describes the pTAL to C++ Translator''s translation of pTAL structure
fields that do not map directly to C++.
Inline Substructure Declarations
The TNS/R native C++ compiler uses different layout rules for inline
substructures than for substructures declared with separately declared
structure template types, when field alignment is shared2 or shared8.
The pTAL to C++ Translator generates a typedef in the structure to create
a name for the substructure type without disturbing the inline substructure
layout rules. For example:
pTAL Code Generated C++ Code
STRUCT samantha(*); struct samantha {
BEGIN unsigned_char i;
STRING i; typedef struct {
STRUCT tabitha; unsigned_char j;
BEGIN } __tabitha;
STRING j; __tabitha tabitha;
END; };
END;
You can use this name whenever you need a type name for the substructure.
For example:
sizeof(samantha::__tabitha)
Macros That Declare Structure Fields
Some pTAL constructs cannot be translated to straightforward C++ structure
elements. These include:
- a bit array
- a larger data item overlaying a smaller data item, by equating the larger
to the smaller, or by declaring the larger as a zero-length array
- a data item with larger alignment requirements overlaying a data item
with smaller alignment requirements whose size is not a multiple of the
larger alignment requirement
- an array with a nonzero lower bound
To translate these pTAL constructs to C++, the pTAL to C++ Translator emits
an invocation of a macro, defined in the rosgen.h include file, to declare
the data and access functions for each of these pTAL structure items. For
example:
pTAL Code Generated C++ Code
STRUCT paul(*); class paul {
BEGIN public:
UNSIGNED(4) a[0:3]; _bitarray(paul,a,4,0,3)
INT(16) b[0:-1]; _redef(int_16,b,x);
STRING x; unsigned_char x;
STRING y; unsigned_char y;
INT(32) c[-2:2]; _array(int_32,c,-2,2);
END; };
The pTAL to C++ Translator s ENCAPSULATE_STRUCT option results in a
structure with macro invocations declaring data and access functions for
every field in the structure, whether or not a simple mapping to C++ exists.
#endif
//-------------------------------------------------------------------------
// This section handles mis-aligned struct items that require 4- or 8-byte
// alignment, but are only 2-byte aligned, and are accessed by member
// functions.
typedef _unsigned_32 *_p2__unsigned_32;
typedef _unsigned_32 &_r2__unsigned_32;
typedef _int_64 *_p2__int_64;
#ifdef _MSC_VER
typedef _int_64 *_p2___int64;
#endif
typedef _int_64 &_r2__int_64;
#ifdef _MSC_VER
typedef _int_64 &_r2___int64;
#endif
typedef int_32 *_p2__int_32;
typedef int_32 &_r2__int_32;
typedef int_ptr *_p2__int_ptr;
typedef int_ptr &_r2__int_ptr;
typedef real_32 *_p2__real_32;
typedef real_32 &_r2__real_32;
typedef real_64 *_p2__real_64;
typedef real_64 &_r2__real_64;
#ifdef NA_64BIT
typedef xint_32 &_r2__xint_32;
#endif
typedef long_ptraddr_val *_p2_Long;
//------------------
// Address typedefs:
//------------------
typedef baddr *_p2_baddr;
typedef baddr *_r2_baddr;
typedef waddr *_p2_waddr;
typedef waddr *_r2_waddr;
typedef extaddr *_p2_extaddr;
typedef extaddr *_r2_extaddr;
typedef procaddr *_p2_procaddr;
typedef procaddr *_r2_procaddr;
typedef cbaddr *_p2_cbaddr;
typedef cbaddr *_r2_cbaddr;
typedef cwaddr *_p2_cwaddr;
typedef cwaddr *_r2_cwaddr;
#define _prepend_r2_(p) _r2_##p
#define _prepend_p2_(p) _p2_##p
//-------------------------------------------------------------------------
// For structure data items:
//
// The define _item declares the actual data by prepending "__" to the
// given name, and an access function of the given name.
#define _cpp_dataname(name) ___##name
#define _cpp_lowdataname(name) ___##name##_low
//-------------------------------------------------------------------------
#if 0
_item and _item2
The _item macro and the _item2 macro declare a data field in a structure
and defines an access function for that data field.
_item(field_type,
field_access_name)
_item2(field_type,
field_access_name)
field_type
is the type of the data field.
field_access_name
is the name of the access function for the data field.
Usage Considerations
The _item macro and the _item2 macro declare a data field in a structure and
defines an access function for that data field.
The _item2 macro declares a structure item that requires 4- or 8-byte
alignment but is only aligned on a 2-byte boundary. This item is declared
in a structure with the FIELDALIGN(SHARED2) attribute.
The pTAL to C++ Translator generates the _item macro or the _item2 macro to
declare a data field if the ENCAPSULATE_STRUCT option is enabled during the
translation session.
The access function returns a reference to the data field, so it can be used
on both the left and right side of an assignment statement. For example:
pTAL Code Generated C++ Code
STRUCT structtype(*); class structtype {
BEGIN public:
INT(16) i; _item(int_16,i);
END; };
STRUCT fred(*) #pragma fieldalign shared2 fred
FIELDALIGN(SHARED2); class fred {
BEGIN public:
INT(16) i; _item(int_16,i);
INT(32) j; _item2(int_32,j);
END; };
STRUCT s(structtype); structtype s;
STRUCT f(fred); fred f;
... ...
s.i := 2; s.i() = 2;
x := s.i; x = s.i();
f.j := 10D; f.j() = 10;
#endif
//-------------------------------------------------------------------------
#define _item(type,name) \
type _cpp_dataname(name); \
_resident inline type & name (void) {return _cpp_dataname(name);}
#define _item2(type,name) \
type _cpp_dataname(name); \
typedef _prepend_r2_(type) _r2_##type; \
_resident inline _r2_##type name (void) {return _cpp_dataname(name);}
//-------------------------------------------------------------------------
#if 0
_array and _array2
The _array macro and the _array2 macro declare an array data field in a
structure and defines an access function for that data field. The array
need not have a lower bound of zero.
_array(element_type,
field_access_name,
lower_bound,
upper_bound)
_array2(element_type,
field_access_name,
lower_bound,
upper_bound)
element_type
is the type of the array elements.
field_access_name
is the name of the access function for the data field.
lower_bound
is an integer constant that specifies the lower bound of the array.
upper_bound
is an integer constant that specifies the upper bound of the array.
Usage Considerations
The _array macro and the _array2 macro declare an array data field in a
structure and defines an access function for that data field. The array
need not have a lower bound of zero.
The _array2 macro declares a structure item that requires 4- or 8-byte
alignment but is only aligned on a 2-byte boundary. This item is declared
in a structure with the FIELDALIGN(SHARED2) attribute.
The _array macro and the _array2 macro define the constant
_lb_field_access_name, in the class implementing the enclosing structure,
which represents the lower bound of the array. It represents the value
given as lower_bound.
The _array macro and the _array2 macro define the constant
_ub_field_access_name, in the class implementing the enclosing structure,
which represents the upper bound of the array. It represents the value
given as upper_bound.
The pTAL to C++ Translator generates the _array macro or the _array2 macro to
declare a data field if the ENCAPSULATE_STRUCT option is enabled during the
translation session.
The access function returns a reference to the data field, so it can be
used on both the left and right side of an assignment statement. The data
field contains cells numbered from the lower bound to the upper bound,
inclusive. The data field cells are indexed from the lower bound to the
upper bound, inclusive. For example:
pTAL Code Generated C++ Code
STRUCT s(*); class s {
BEGIN public:
INT(16) alvin [5:7]; _array(int_16,alvin,5,7);
END; };
STRUCT chip(s); s chip;
... ...
chip.alvin[5] := 2; chip.alvin()[5] = 2;
x := chip.alvin[5]; x = chip.alvin()[7];
for (x = chip._lb_alvin;
x <= chip._ub_alvin; x++)
...
#endif
//-------------------------------------------------------------------------
// The define _array declares normal (non-zero length, non-redefined) arrays,
// and defines an accessing member function.
// It subtracts the lower bound inside the accessing member function, so that
// it does not need to be subtracted at the indexing site.
#define _array(type,name,lb,ub) \
type _cpp_dataname(name)[((ub)-(lb))+1]; \
_resident inline type _far * name(void) \
{return &(_cpp_dataname(name)[(-(lb))]);}; \
enum {_num_elem_##name = (ub)-(lb)+1}; \
enum {_lb_##name = lb}; \
enum {_ub_##name = ub}
#define _array2(type,name,lb,ub) \
type _cpp_dataname(name)[((ub)-(lb))+1]; \
typedef _prepend_p2_(type) _p2_##type; \
_resident inline _p2_##type name(void) \
{return &(_cpp_dataname(name)[-(lb)]);}; \
enum {_num_elem_##name = (ub)-(lb)+1}; \
enum {_lb_##name = lb}; \
enum {_ub_##name = ub}
//-------------------------------------------------------------------------
#if 0
_bitfield
The _bitfield macro declares a bit field in a structure and defines an
access function for that data field.
_bitfield(enclosing_struct_type,
field_access_name,
bit_field_width)
enclosing_struct_type
is the type name of the structure in which this bit field is declared.
field_access_name
is the name of the access function for the data field.
bit_field_width
is an integer constant that indicates the number of bits in the bit field.
Usage Considerations
The _bitfield macro declares a bit field in a structure and defines an
access function for that data field.
The pTAL to C++ Translator generates the _bitfield macro to declare a
data field if the ENCAPSULATE_STRUCT option is enabled during the
translation session.
The access function returns a reference to the data field, so it can be
used on both the left and right side of an assignment statement. For
example:
pTAL Code Generated C++ Code
STRUCT s(*); class s {
BEGIN public:
UNSIGNED(4) i; _bitfield(s,i,4);
END; };
STRUCT sam(s); s sam;
... ...
sam.i := 2; sam.i() = 2;
x := sam.i; x = sam.i();
#endif
//-------------------------------------------------------------------------
// Unsigned pTAL items are declared using the _bitfield define, which
// declares a nested class specifically designed to allow easy access
// to a single item of the containing struct. This class represents a
// type that these values assume during assignment; the assignment
// operator in this class is what allows the member function representing
// the bitfield to be on the left hand side of the assignment. The
// define delcares the C++ bitfield itself, and an accessing function
// that can be used on the left or right side of an assignment.
#define _bitfield(type,name,size) \
unsigned int _cpp_dataname(name):size; \
struct __##type##_bitfield##name; \
friend struct __##type##_bitfield##name; \
struct __##type##_bitfield##name { \
__##type##_bitfield##name(int) {}; \
_resident inline operator int () \
{return ((type _far *)this)->_cpp_dataname(name);}; \
_resident inline __##type##_bitfield##name _far & operator=(const int i) \
{((type _far *)this)->_cpp_dataname(name) = i; \
return *this;}; \
}; \
_resident inline __##type##_bitfield##name &name() \
{return *(__##type##_bitfield##name _far *)this;}
//-------------------------------------------------------------------------
#if 0
_bitarray _bitarray_neglb and _bigbitarray
The _bitarray macro, the _bitarray_neglb macro, and the _bigbitarray
macro each declare an array of bit fields in a structure and define access
functions for that array. The declaration and its accompanying access
functions emulate the pTAL bit array construct, which is not available
in the C++ programming language.
_bitarray(enclosing_struct_type,
field_access_name,
element_width,
lower_bound,
upper_bound)
_bitarray_neglb(enclosing_struct_type,
field_access_name,
element_width,
lower_bound,
upper_bound)
_bigbitarray(enclosing_struct_type,
field_access_name,
element_width,
lower_bound,
upper_bound)
enclosing_struct_type
is the type name of the structure in which this bit array is declared.
field_access_name
is the name of the access function for the data field.
element_width
is an integer constant that specifies the number of bits in each array
element.
lower_bound
is an integer constant that specifies the lower bound of the array.
upper_bound
is an integer constant that specifies the upper bound of the array.
Usage Considerations
The _bitarray macro, the _bitarray_neglb macro, and the _bigbitarray
macro each declare an array of bit fields in a structure and define
access functions for that array. This declaration and its accompanying
access functions emulate the pTAL bit array construct, which is not
available in the C++ programming language.
This C++ simulation of a pTAL bit array does not perform as well at
execution time as the original pTAL bit array construct. You should
consider avoiding this construct in performance-critical software.
The _bitarray macro declares an array of bit fields with a lower bound
greater than or equal to zero. The bit array may not occupy more than
32 bits.
The _bitarray_neglb macro declares an array of bit fields with a lower
bound less than zero. The bit array may not occupy more than 32 bits.
The two nearly identical declarations are necessary to emulate pTAL bit
array structure field data layout rules.
The _bigbitarray macro declares an array of bit fields that occupies at
least 32 bits. The bit array must occupy a multiple of 16 bits.
The data field contains cells numbered from the lower bound to the upper
bound, inclusive. The data field cells are indexed from the lower bound
to the upper bound, inclusive.
Both the _bitarray macro, the _bitarray_neglb macro, and the _bigbitarray
macro define the access functions _deposit and _extract in the class that
implements the bit array. You must use the _deposit and _extract functions
to store and retrieve values to and from cells in the bit field.
For example, the following code declares a structure field i that is an
array of four cells, indexed from 2 to 5 inclusively, each of which is
four bits wide.
pTAL Code Generated C++ Code
STRUCT structtype(*); class structtype {
BEGIN public:
UNSIGNED(4) i [2:5]; _bitarray(structtype,i,4,2,5);
END; };
STRUCT s(structtype); structtype s;
... ...
s.i[2] := 2; s.i()._deposit(2,2);
x := s.i[5]; x = s.i()._extract(5);
The following code declares a structure field i that is an array of six
cells, indexed from -2 to 3 inclusively, each of which is four bits wide.
pTAL Code Generated C++ Code
STRUCT stype(*); class stype {
BEGIN public:
UNSIGNED(4) i [-2:3]; _bitarray_neglb(
END; stype,i,4,-2,3);
};
STRUCT s(stype); stype s;
... ...
s.i[-2] := 2; s.i()._deposit(-2,2);
x := s.i[3]; x = s.i()._extract(3);
The following code declares a structure field fred that is an array of
16 cells, indexed from 0 to 15 inclusively, each of which is four bits wide.
pTAL Code Generated C++ Code
STRUCT stype(*); class stype {
BEGIN public:
UNSIGNED(4) fred [0:15]; _bigbitarray(
END; stype,fred,4,0,15);
};
STRUCT s(stype); stype s;
... ...
s.fred[3] := 2; s.fred()._deposit(3,2);
x := s.fred[10]; x = s.fred()._extract(10);
Constants
The _bitarray macro, the _bitarray_neglb macro, and the _bigbitarray
macro define the following constants:
- _width_field_access_name, defined in the class implementing the enclosing
structure, represents the number of bits in each cell of the bit array.
It represents the value given as element_width.
- _lb_field_access_name, defined in the class implementing the enclosing
structure, represents the lower bound of the bit array. It represents
the value given as lower_bound.
- _ub_field_access_name, defined in the class implementing the enclosing
structure, represents the upper bound of the bit array. It represents
the value given as upper_bound.
In the following example, the _bitarray macro creates a constant called
structtype::_lb_i representing the lower bound of the bit array field i in
the class structtype. It also creates a constant called structtype::_ub_i
representing the upper bound of the bit array field i in the class structtype,
and a constant called structtype::_width_i representing the number of bits
in each cell of the bit array field i in the class structtype.
class structtype {
public:
_bitarray(structtype,i,4,2,5);
} s;
for (x = s._lb_i; x <= s._lb_i; x++)
_deposit
The _deposit function, which is a member function defined by invoking the
_bitarray macro, the _bitarray_neglb macro, or the _bigbitarray macro,
deposits a value at a particular index in the bit array field.
void _deposit(int index,
unsigned int value)
index
is an index into the bit array.
value
is the value to be deposited at the given index in the bit array.
In the following example, the field opie is a bit array indexed from -1
to 3, in which each cell is four bits wide. The value 5 is deposited
into cell 1 of the bit array field opie.
pTAL Code Generated C++ Code
STRUCT sheriff(*); class sheriff {
BEGIN public:
UNSIGNED(4) opie[-1,3]; _bitarray(sheriff,opie,4,-1,3);
END; };
STRUCT andy(sheriff); sheriff andy;
... ...
andy.opie[1] := 5; andy.opie()._deposit(1,5);
_extract
The _extract function, which is a member function defined by invoking the
_bitarray macro, the _bitarray_neglb macro, or the _bigbitarray macro,
extracts a value from a particular index in the bit array field.
unsigned int _extract(int index)
index
is an index into the bit array.
The _extract function returns the value stored in the bit array at index index.
In the following example, the field barney is a bit array indexed from 0
to 3, in which each cell is four bits wide. The value extracted from
cell 0 of the bit array field barney is stored in the variable x.
pTAL Code Generated C++ Code
LITERAL BULLET = 1; enum { BULLET = 1};
STRUCT deputy(*); class deputy {
BEGIN public:
UNSIGNED(4) pocket[0:3]; _bitarray(deputy,pocket,4,0,3);
END; };
STRUCT barney(deputy); deputy barney;
... ...
x := barney.pocket[BULLET]; x = barney.pocket()._extract(BULLET);
#endif
//-------------------------------------------------------------------------
// declare array of bitfields
#define _bitarray(type,name,width,lb,ub) \
enum {_num_elem_##name = (ub)-(lb)+1}; \
enum {_lb_##name = lb}; \
enum {_ub_##name = ub}; \
enum {_width_##name = width}; \
unsigned int _cpp_dataname(name):(((ub)-(lb))+1)*(width); \
struct __##type##_bitarray##name; \
friend struct __##type##_bitarray##name; \
struct __##type##_bitarray##name { \
__##type##_bitarray##name(int) {}; \
_resident inline operator int () \
{return ((type _far *)this)->_cpp_dataname(name);}; \
_resident inline unsigned int _extract(int i) { \
return (_extract_bits(((type _far *)this)->_cpp_dataname(name), \
((((_ub_##name) - (_lb_##name)) + 1) * _width_##name), \
((i - _lb_##name) * _width_##name), \
(((i - _lb_##name) + 1) * _width_##name - 1)));\
}; \
_resident inline void _deposit(int i,unsigned int v) { \
_deposit_bits(((type _far *)this)->_cpp_dataname(name), \
((((_ub_##name) - (_lb_##name)) + 1) * _width_##name), \
(unsigned int_16)v, \
((i - _lb_##name) * _width_##name), \
(((i - _lb_##name) + 1) * _width_##name - 1)); \
}; \
_resident inline __##type##_bitarray##name _far & operator=(const int i) \
{((type _far *)this)->_cpp_dataname(name) = i; \
return *this;}; \
}; \
_resident inline __##type##_bitarray##name &name() \
{return *(__##type##_bitarray##name _far *)this;}
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
#define _bitarray_neglb(type,name,width,lb,ub) \
enum {_lb_##name = lb}; \
enum {_ub_##name = ub}; \
enum {_width_##name = width}; \
unsigned int _cpp_lowdataname(name):(-(lb))*width; \
unsigned int _cpp_dataname(name):((ub)+1)*(width); \
struct __##type##_bitarray##name; \
friend struct __##type##_bitarray##name; \
struct __##type##_bitarray##name { \
__##type##_bitarray##name(int) {}; \
_resident inline operator int () \
{return ((type _far *)this)->_cpp_dataname(name);}; \
_resident inline unsigned_16 _extract(int i) { \
if (i < 0) { \
return (_extract_bits( \
((type _far *)this)->_cpp_lowdataname(name), \
((-(_lb_##name)) * _width_##name), \
((i - _lb_##name) * _width_##name), \
(((i - _lb_##name) + 1) * _width_##name - 1))); \
} else { \
return (_extract_bits( \
((type _far *)this)->_cpp_dataname(name), \
(((_ub_##name) + 1) * _width_##name), \
(i * _width_##name), \
(((i + 1) * _width_##name) - 1))); \
} \
}; \
_resident inline void _deposit(int i,unsigned_16 v) { \
if (i < 0) { \
_deposit_bits(((type _far *)this)->_cpp_lowdataname(name), \
((-(_lb_##name)) * _width_##name), \
(unsigned_16)v, \
((i - _lb_##name) * _width_##name), \
(((i - _lb_##name) + 1) * _width_##name - 1)); \
} else { \
_deposit_bits(((type _far *)this)->_cpp_dataname(name), \
(((_ub_##name) + 1) * _width_##name), \
(unsigned_16)v, \
(i * _width_##name), \
(((i + 1) * _width_##name) - 1)); \
} \
}; \
_resident inline __##type##_bitarray##name _far & operator=(const int i) \
{((type _far *)this)->_cpp_dataname(name) = i; \
return *this;}; \
}; \
_resident inline __##type##_bitarray##name &name() \
{return *(__##type##_bitarray##name _far *)this;}
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
#define _bigbitarray(type,name,width,lb,ub) \
enum {_lb_##name = lb}; \
enum {_ub_##name = ub}; \
enum {_width_##name = width}; \
unsigned short _cpp_dataname(name)[((((ub)-(lb))+1)*(width)+15)/16]; \
struct __##type##_bitarray##name; \
friend struct __##type##_bitarray##name; \
struct __##type##_bitarray##name { \
_resident inline unsigned int _extract(int i) { \
return _extract_bits((((type _far *)this)-> \
_cpp_dataname(name)[((i-(lb))*(width))/16]), \
16, \
(((i-(lb))*(width)) % 16), \
((((i-(lb))*(width)) % 16)+(width)-1)); \
}; \
_resident inline void _deposit(int i,unsigned int v) { \
_deposit_bits((((type _far *)this)-> \
_cpp_dataname(name)[((i-(lb))*(width))/16]), \
16, \
v, \
(((i-(lb))*(width)) % 16), \
((((i-(lb))*(width)) % 16)+(width)-1)); \
}; \
}; \
_resident inline __##type##_bitarray##name &name() \
{return *(__##type##_bitarray##name _far *)this;}
/////////////////
//-------------------------------------------------------------------------
#if 0
_coerce
The _coerce macro creates a variable into which the result of a conversion
with the _xadr macro can be assigned. It makes type conversion within a
macro body more attractive than straightforward type casts would be.
_coerce(type,var)
type
is the type of variable that would make var assignment compatible with
the left-hand-side of the assignment.
var
is a variable into which the assignment is to take place.
Usage Considerations
The _coerce macro operates on the variable which resides on the
left-hand-side of an assignment statement. It appears in macro bodies
when the left-hand-side of the assignment statement is contained in a
macro actual parameter and the right-hand-side is a call to _xadr.
It exists to improve the presevation of the macro body during translation.
pTAL Code Generated C++ Code
define gets(x,y) #define gets(x,y) \
= @x := y#; _coerce(void *,x) = y
... ...
gets(a,$extaddr(fred)); gets(a,_xadr(fred));
#endif
//-------------------------------------------------------------------------
#if 0
_redef and _redef2
The _redef macro and the _redef2 macro declare a data field that overlays
another data field in a structure. It defines an access function for that
data field. The declaration allocates no data.
_redef(field_type,
field_access_name,
space_allocating_data_name)
_redef2(field_type,
field_access_name,
space_allocating_data_name)
field_type
is the type of the data field.
field_access_name
is the name of the access function for the data field.
space_allocating_data_name
is the name of a space-allocating data field which this field will overlay.
Usage Considerations
The _redef macro and the _redef2 macro declare a data field that overlays
another data field in a structure. It defines an access function for that
data field. The declaration allocates no data.
The _redef2 macro declares a structure item that requires 4- or 8-byte
alignment but is only aligned on a 2-byte boundary. This item is declared
in a structure with the FIELDALIGN(SHARED2) attribute.
A C++ union is the preferred way to declare structure data fields that
overlay one another, but not all pTAL redefinition and zero-length array
fields can be declared using a union. The pTAL to C++ Translator generates
an invocation of the _redef macro when it cannot generate a correct C++ union.
The access function returns a reference to the data field, so it can be used
on both the left and right side of an assignment statement.
In the following example, the fields a and b each allocate 16 bits. The
field jed begins at the same place as field a and extends for 32 bits.
pTAL Code Generated C++ Code
STRUCT stype(*); class stype {
BEGIN public:
INT(16) a; int_16 a;
INT(16) b; int_16 b;
INT(32) jed = a; _redef(int_32,jed,a);
END; };
STRUCT s(stype); stype s;
... ...
s.jed := 13; s.jed() = 13;
x := s.jed; x = s.jed();
In the following example, the fields huey, dewey, and louie each allocate
16 bits. The field x begins at the same place as field dewey and extends
for 32 bits. Field x is a 4-byte field that is not aligned on a 4-byte
boundary.
pTAL Code Generated C++ Code
#define set_fieldalign
?FIELDALIGN(SHARED2) #pragma fieldalign shared2
STRUCT dtype(*); class dtype {
BEGIN public:
INT(16) huey; int_16 huey;
INT(32) x[0:-1]; _redef2(int_32,x,dewey);
INT(16) dewey; int_16 dewey;
INT(16) louie; int_16 louie;
END; };
STRUCT d(dtype); dtype d;
... ...
d.x := 13D; d.x() = 13;
x := d.x; x = d.x();
#endif
//-------------------------------------------------------------------------
// Redefinition is handled by creating a member function that takes
// the address of the defining item, and uses it to form a pointer
// or reference to the appropriate type. Redefinitions of non-arrays
// use the _redef define. Redefinitions of arrays use the _redefarray
// define.
#define _coerce(type,var) (*((type _far *)(&var)))
#define _redef(type,name1,name2) \
_resident inline type _far & name1 (void) {return _coerce(type,name2);}
#define _redef2(type,name1,name2) \
typedef _prepend_r2_(type) _r2_##type; \
_resident inline _r2_##type name1 (void) {return _coerce(type,name2);}
//-------------------------------------------------------------------------
#if 0
_to
The _to macro converts a field access name of a macro-defined structure
field into the name of the actual data item, which is normally known only
to the access function.
When defining a field via _redef, _redef2, _redefarray, _redefarray2,
_redefafter, _redefafter2, _redefarrayafter or _redefarrayafter2, you
must supply the name of the space allocating item that the new field will
overlay. If that space-allocating field were defined using a special
macro _item, or _array, you would use the _to macro to create the name of
that space-allocating item.
_to(field_access_name)
field_access_name
is the name of the access function for the space-allocating data field.
In the following example, the fields a, b, and c each allocate 16 bits.
The array field sam begins at the same place as field a and extends for
three 16-bit cells.
pTAL Code Generated C++ Code
STRUCT stype(*); class stype {
BEGIN public:
INT(16) a; _item(int_16,a);
INT(16) b; _item(int_16,b);
INT(16) c; _item(int_16,c);
INT(16) sam[0:2] = a; _redefarray(int_16,sam,0,2,
END; _to(a));
};
STRUCT s(stype); stype s;
... ...
s.sam[0] := 13; s.sam()[0] = 13;
x := s.sam[2]; x = s.sam()[2];
#endif
//-------------------------------------------------------------------------
#define _to(fl) _cpp_dataname(fl)
//-------------------------------------------------------------------------
#if 0
_redefarray and _redefarray2
The _redefarray macro and the _redefarray2 macro declare an array data
field that overlays another data field in a structure. It defines an
access function for that array. The declaration allocates no data.
_redefarray(field_type,
field_access_name,
lower_bound,
upper_bound,
space_allocating_data_name)
_redefarray2(field_type,
field_access_name,
lower_bound,
upper_bound,
space_allocating_data_name)
field_type
is the type of the data field.
field_access_name
is the name of the access function for the data field.
lower_bound
is an integer constant that specifies the lower bound of the array.
upper_bound
is an integer constant that specifies the upper bound of the array.
space_allocating_data_name
is the name of a space-allocating data field which this field will overlay.
Usage Considerations
The _redefarray macro and the _redefarray2 macro declare an array data
field that overlays another data field in a structure. It defines an
access function for that array. The declaration allocates no data.
The _redefarray2 macro declares a structure item that requires 4- or 8-byte
alignment but is only aligned on a 2-byte boundary. This item is declared
in a structure with the FIELDALIGN(SHARED2) attribute.
A C++ union is the preferred way to declare structure data fields that
overlay one another, but not all pTAL redefinition and zero-length array
fields can be declared using a union. The pTAL to C++ Translator
generates an invocation of the _redefarray macro when it cannot generate
a correct C++ union.
The access function returns a reference to the array, so it can be used
on both the left and right side of an assignment statement.
The _redefarray macro and the _redefarray2 macro define the constant
_lb_field_access_name, in the class implementing the enclosing structure,
which represents the lower bound of the array. It represents the value
given as lower_bound.
The _redefarray macro and the _redefarray2 macro define the constant
_ub_field_access_name, in the class implementing the enclosing structure,
which represents the upper bound of the array. It represents the value
given as upper_bound.
In the following example, the fields a and b each allocate 16 bits.
The array field sam begins at the same place as field a and extends
for two 16-bit cells.
pTAL Code Generated C++ Code
STRUCT stype(*); class stype {
BEGIN public:
INT(16) a; int_16 a;
INT(16) b; int_16 b;
INT(16) sam[0:1] = a; _redefarray(int_16,sam,0,1,a);
END; };
STRUCT s(stype); stype s;
s.sam[0] := 13; s.sam()[0] = 13;
x := s.sam[1]; x = s.sam()[1];
In the following example, the fields a, b, c, d, and e each allocate 16 bits.
The array joe begins at the same place as field b and extends for two 32-bit
cells. Array joe has 4-byte cells that are not aligned on a 4-byte boundary.
pTAL Code Generated C++ Code
#define set_fieldalign
?FIELDALIGN(SHARED2) #pragma fieldalign shared2
STRUCT jtype(*); class jtype {
BEGIN public:
INT(16) a; int_16 a;
INT(16) b; int_16 b;
INT(16) c; int_16 c;
INT(16) d; int_16 d;
INT(16) e; int_16 e;
INT(32) joe[0:1] = b; _redefarray2(int_32,joe,0,1,b);
END; };
STRUCT j(jtype); jtype j;
j.joe[0] := 17D; j.joe()[0] = 13;
x := j.joe[1]; x = j.joe()[1];
The _redefarray macro or the _redefarray2 macro can be used to declare an
array with a nonzero lower bound. That array s lower bound is aligned with
the zero cell (whether it is allocated or not) of the space allocating data
item that it overlays. In the following example, the array field b aligns
its lower bound with the zero cell of field a. The cell b[3] is aligned
with the cell a[0].
pTAL Code Generated C++ Code
STRUCT ttype(*); class ttype {
BEGIN public:
INT(16) a[0:4]; int_16 a[5];
INT(16) b[3:6] = a; _redefarray(int_16,b,3,6,a);
END; };
STRUCT t(ttype); ttype t;
s.a[0] := 13; s.a[0] = 13;
x := s.b[2]; x = s.b()[2];
#endif
//-------------------------------------------------------------------------
#define _redefarray(type,name1,lb,ub,name2) \
_resident inline type _far * name1 (void) \
{return (type _far *) \
&(((type _far *)&name2)[(-(lb))]);}; \
enum {_num_elem_##name1 = (ub)-(lb)+1}; \
enum {_lb_##name1 = lb}; \
enum {_ub_##name1 = ub}
#define _redefarray2(type,name1,lb,ub,name2) \
typedef _prepend_p2_(type) _p2_##type; \
_resident inline _p2_##type name1 (void) \
{return (type _far *) \
&(((type _far *)&name2)[-(lb)]);}; \
enum {_num_elem_##name1 = (ub)-(lb)+1}; \
enum {_lb_##name1 = lb}; \
enum {_ub_##name1 = ub}
//-------------------------------------------------------------------------
#if 0
_tobitfield
The _tobitfield macro specifies a space-allocating bit field or bit array item.
When defining a field via _redef, _redef2, _redefarray or _redefarray2, you
must supply the name of the space allocating item that the new field will
overlay. If that space-allocating item were a bit field or a bit array
then you would use the _tobitfield macro to specify the bit field
space-allocating item that the new field is to overlay.
_tobitfield(enclosing_struct_type,
space_allocating_data_name)
enclosing_struct_type
is the type name of the structure in which this bit array is declared.
space_allocating_data_name
is the name of a space-allocating data field which this field will overlay.
In the following example, the field a overlays the data fields beginning
with i. The field b overlays the data field z.
pTAL Code Generated C++ Code
STRUCT stype(*); class stype {
BEGIN public:
INT(16) a[0:-1]; _redef(int_16,a,
UNSIGNED(2) i; _tobitfield(stype,i));
UNSIGNED(2) j; unsigned_16 i:2;
UNSIGNED(2) k; unsigned_16 j:2;
BIT_FILLER 10; unsigned_16 k:2;
INT(16) b[0:-1]; unsigned_16 filler:10
UNSIGNED(2) z[0:8]; _redef(int_16,b,
END; _tobitfield(stype,_to(z)));
_bitarray(stype,z,2,0,8);
};
STRUCT s(stype); stype s;
... ...
s.a[0] := 13; s.a() = 13;
If the space-allocating item were defined with a macro, then you would
use the _to macro to obtain the name of the actual data item, given the
name of the access function.
pTAL Code Generated C++ Code
STRUCT stype(*); class stype {
BEGIN public:
INT(16) a[0:-1]; _redef(int_16,a,
UNSIGNED(2) i; _tobitfield(stype,_to(i)));
UNSIGNED(2) j; _bitfield(int_16,i);
UNSIGNED(2) k; _bitfield(int_16,j);
INT(16) b[0:-1]; _bitfield(int_16,k);
UNSIGNED(2) z[0:8]; _redef(int_16,b,
END; _tobitfield(stype,_to(z)));
_bitarray(stype,z,2,0,8);
};
STRUCT s(stype); stype s;
... ...
s.a[0] := 13; s.a() = 13;
#endif
//-------------------------------------------------------------------------
// Beware: Tandem C++ does not tolerate parens around _bitoffset arguments
#ifdef _MSC_VER
#define _bitoffset(x,y) 0
#elif defined(__linux__)
#define _bitoffset(x,y) 0 // TODO __linux__
#endif
#define _tobitfield(st,fl) (((unsigned_char *)this)[_bitoffset(st,fl)/8])
//-------------------------------------------------------------------------
#if 0
_redefafter and _redefafter2
The _redefafter macro and the _redefafter2 macro declare a data field that
overlays the data field following the field specified in this declaration
macro. It defines an access function for that data field. The declaration
allocates no data.
_redefafter(field_type,
field_access_name,
space_allocating_data_name)
_redefafter2(field_type,
field_access_name,
space_allocating_data_name)
field_type
is the type of the data field.
field_access_name
is the name of the access function for the data field.
space_allocating_data_name
is the name of a space-allocating data field after which resides the
field which this field will overlay.
Usage Considerations
The _redefafter macro and the _redefafter2 macro declare a data field that
overlays the data field following the field specified in this declaration
macro. It defines an access function for that data field. The declaration
allocates no data.
The _redefafter2 macro declares a structure item that requires 4- or 8-byte
alignment but is only aligned on a 2-byte boundary. This item is declared
in a structure with the FIELDALIGN(SHARED2) attribute.
A C++ union is the preferred way to declare structure data fields that
overlay one another, but not all pTAL redefinition and zero-length array
fields can be declared using a union. The pTAL to C++ Translator generates
an invocation of the _redefafter macro when it cannot generate a correct
C++ union, and when an invocation of _redef might lead to a textual mismatch
in the translation of a define or file section.
The access function returns a reference to the data field, so it can be
used on both the left and right side of an assignment statement.
In the following example, the fields a, c and d each allocate 16 bits.
The field b begins at the same place as field c in structure stype and
begins at the same place as field d in structure ttype. Field b extends
for 16 bits.
pTAL Code Generated C++ Code
define fields = #define fields \
INT(16) a; int_16 a; \
INT(16) b[0:-1]#; _redefafter(int_16,b,a)
STRUCT stype(*); class stype {
BEGIN public:
fields; fields;
INT(16) c; int_16 c;
END; };
STRUCT ttype(*); class ttype {
BEGIN public:
fields; fields;
INT(16) d; int_16 d;
END; };
STRUCT s(stype); stype s;
... ...
s.b := 13; s.b() = 13;
x := s.b; x = s.b();
In the following example, the field x allocates 16 bits and field z
allocates 32 bits. The field k begins at the same place as field y
in structure ytype and begins at the same place as field z in structure
ztype. Field k extends for 32 bits. Field k is a 4-byte field that is
not aligned on a 4-byte boundary.
pTAL Code Generated C++ Code
#define set_fieldalign
?FIELDALIGN(SHARED2) #pragma fieldalign shared2
define fields = #define fields \
INT(16) x; int_16 x; \
INT(32) k[0:-1]#; _redefafter2(int_32,k,x)
STRUCT ytype(*); class ytype {
BEGIN public:
fields; fields;
INT(32) y; int_32 y;
END; };
STRUCT ztype(*); class ztype {
BEGIN public:
fields; fields;
INT(32) z; int_32 z;
END; };
STRUCT y(ytype); ytype y;
... ...
y.k := 13D; y.k() = 13;
x := y.k; x = y.k();
#endif
//-------------------------------------------------------------------------
#define _redefafter(type,name1,name2) \
_resident inline type _far & name1 (void) \
{return _coerce(type,(*(((unsigned_char *)&name2)+sizeof(name2))));}
#define _redefafter2(type,name1,name2) \
typedef _prepend_r2_(type) _r2_##type; \
_resident inline _r2_##type name1 (void) \
{return _coerce(type,(*(((unsigned_char *)&name2)+sizeof(name2))));}
//-------------------------------------------------------------------------
#if 0
_redefarrayafter and _redefarrayafter2
The _redefarrayafter macro and the _redefarrayafter2 macro declare an
array data field that overlays the data field following the field specified
in this declaration macro. It defines an access function for that array.
The declaration allocates no data.
_redefarrayafter(field_type,
field_access_name,
lower_bound,
upper_bound,
space_allocating_data_name)
_redefarrayafter2(field_type,
field_access_name,
lower_bound,
upper_bound,
space_allocating_data_name)
field_type
is the type of the data field.
field_access_name
is the name of the access function for the data field.
lower_bound
is an integer constant that specifies the lower bound of the array.
upper_bound
is an integer constant that specifies the upper bound of the array.
space_allocating_data_name
is the name of a space-allocating data field after which resides the
field which this field will overlay.
Usage Considerations
The _redefarrayafter macro and the _redefarrayafter2 macro declare an
array data field that overlays the data field following the field specified
in this declaration macro. It defines an access function for that array.
The declaration allocates no data.
The _redefarrayafter2 macro declares a structure item that requires
4- or 8-byte alignment but is only aligned on a 2-byte boundary. This
item is declared in a structure with the FIELDALIGN(SHARED2) attribute.
A C++ union is the preferred way to declare structure data fields that
overlay one another, but not all pTAL redefinition and zero-length array
fields can be declared using a union. The pTAL to C++ Translator generates
an invocation of the _redefarrayafter macro when it cannot generate a
correct C++ union, and when an invocation of _redefarray might lead to a
textual mismatch in the translation of a define or file section.
The access function returns a reference to the array, so it can be used
on both the left and right side of an assignment statement.
The _redefarrayafter macro and the _redefarrayafter2 macro define the
constant _lb_field_access_name, in the class implementing the enclosing
structure, which represents the lower bound of the array. It represents
the value given as lower_bound.
The _redefarrayafter macro and the _redefarrayafter2 macro define the
constant _ub_field_access_name, in the class implementing the enclosing
structure, which represents the upper bound of the array. It represents
the value given as upper_bound.
In the following example, the fields a and c each allocate four 16-bit cells.
The array field b begins at the same place as field c.
pTAL Code Generated C++ Code
define fields = #define fields \
INT(16) a[0:3]; int_16 a[4]; \
INT(16) b[0:-1]#; _redefarrayafter(int_16,b,a)
STRUCT stype(*); class stype {
BEGIN public:
fields; fields;
INT(16) c[0:3]; INT(16) c[0:3];
END; };
STRUCT s(stype); stype s;
s.b[0] := 13; s.b()[0] = 13;
x := s.b[1]; x = s.b()[1];
In the following example, the array a allocates four 16-bit cells and the
array c allocates four 32-bit cells. The array b begins at the same place
as field c. Array b has 4-byte cells that are not aligned on a 4-byte
boundary.
pTAL Code Generated C++ Code
#define set_fieldalign
?FIELDALIGN(SHARED2) #pragma fieldalign shared2
define fields = #define fields \
INT(16) a[0:3]; int_16 a[4]; \
INT(32) b[0:-1]#; _redefarrayafter2(int_32,b,a)
STRUCT ttype(*); class ttype {
BEGIN public:
fields; fields;
INT(32) c[0:3]; int_32 c[4];
END; };
STRUCT t(ttype); ttype t;
t.b[0] := 13D; t.b()[0] = 13;
x := t.b[1]; x = t.b()[1];
#endif
//-------------------------------------------------------------------------
#define _redefarrayafter(type,name1,lb,ub,name2) \
_resident inline type _far * name1 (void) \
{return (type _far *) \
(((unsigned_char *)&(((type _far *)&name2)[(-(lb))]))+sizeof(name2));};\
enum {_num_elem_##name1 = (ub)-(lb)+1}; \
enum {_lb_##name1 = lb}; \
enum {_ub_##name1 = ub}
#define _redefarrayafter2(type,name1,lb,ub,name2) \
typedef _prepend_p2_(type) _p2_##type; \
_resident inline _p2_##type name1 (void) \
{return (type _far *) \
(((unsigned_char *)&(((type _far *)(&name2))[(-(lb))]))+sizeof(name2));};\
enum {_num_elem_##name1 = (ub)-(lb)+1}; \
enum {_lb_##name1 = lb}; \
enum {_ub_##name1 = ub}
//-------------------------------------------------------------------------
#if 0
Array Data Types
The pTAL to C++ Translator translates array variables with a zero lower
bound in a straightforward way. For example:
pTAL Code Generated C++ Code
STRUCT norton[0:9]; struct __norton {
BEGIN int_16 a;
INT(16) a; int_16 b[10];
INT(16) b [0:9]; } norton [10];
END;
STRING ralph [0:9] char ralph [10]
:= [0,1,2,3,4,5,6,7,8,9]; = {0,1,2,3,4,5,6,7,8,9};
The pTAL to C++ Translator uses special macros to declare array variables
with nonzero lower bounds and read-only arrays. This subsection describes
these macros.
Array With a Nonzero Lower Bound
The pTAL language allows you to declare an array with a lower bound that
is any constant value. The C++ language requires that arrays have a lower
bound of zero. The pTAL to C++ Translator generates macros that expand to
array types in variable declarations to emulate arrays with nonzero lower
bounds.
Read-Only Array
The pTAL to C++ Translator emits macro invocations to declare read-only
arrays with a nonzero lower bound.
#endif
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
#if 0
_array_type
The _array_type macro defines an array type with nonzero lower bounds.
_array_type(element_type,
lower_bound,
upper_bound)
element_type
is the type of the array elements.
lower_bound
is an integer constant that specifies the lower bound of the array.
upper_bound
is an integer constant that specifies the upper bound of the array.
Usage Considerations
The _array_type macro defines an array type with nonzero lower bounds. An
invocation of this macro is used as the type in a variable definition. The
_array_type macro expands to a class containing a data item and access
functions for the array container.
Use the _struct_array_type macro to define an array with a nonzero lower
bound whose elements are structures.
Access to the array variable requires no special syntax.
The following example defines an array type variable, fred, which has
six int_16 type cells, indexed from -2 to 3 inclusively.
pTAL Code Generated C++ Code
INT(16) PROC TOP_HAT; extern "C" int_16 TOP_HAT()
BEGIN {
INT(16) x; int_16 x;
INT(16) fred[-2:3]; _array_type(int_16,-2,3) fred;
... ...
fred[-2] := 13; fred[-2] = 13;
x := fred[0]; x = fred[0];
END; }
#endif
//-------------------------------------------------------------------------
template <class type, const int lb, const int ub> class _at_template {
public:
_resident inline type& operator [] (int i) { return __data [i - (lb)]; };
_resident inline type* operator & () { return &__data [-(lb)]; };
_resident inline operator type * () { return &__data [-(lb)]; };
/* _resident inline operator void * () { return &__data [-(lb)]; }; */
private:
type __data [(ub) - (lb) + 1];
};
#define _array_type(type, lb, ub) _at_template<type,lb,ub>
//-------------------------------------------------------------------------
#if 0
_struct_array_type
The _struct_array_type macro defines an array type with nonzero lower bounds
whose elements are structures.
_struct_array_type(element_type,
lower_bound,
upper_bound)
element_type
is the type of the array elements.
lower_bound
is an integer constant that specifies the lower bound of the array.
upper_bound
is an integer constant that specifies the upper bound of the array.
Usage Considerations
An invocation of this macro is used as the type in a variable definition.
The _struct_array_type macro expands to a class containing a data item and
access functions for the array container. This class differs from that
defined by the _array_type macro in that the pointer dereference and field
access operator -> is defined for structure elements.
The following example defines an array type variable, ginger, which has four
structure g type cells, indexed from 2 to 5 inclusively. It is necessary to
define the structure type before declaring the array of structures. Access
to the array variable requires no special syntax.
pTAL Code Generated C++ Code
INT(16) PROC STAGE_DOOR; extern "C" int_16 STAGE_DOOR()
BEGIN {
INT(16) x; int_16 x;
STRUCT k(*); struct k{
BEGIN int_16 i;
INT(16) i; int_16 j;
INT(16) j; };
END; _struct_array_type(k,2,5)
STRUCT hepburn(k)[2:5]; hepburn;
... ...
hepburn[2].i := 13; hepburn[2].i = 13;
x := hepburn[5].j; x = hepburn[5].j;
x := $LEN(hepburn.i); x = _len(hepburn->i);
return 0; return 0;
END; }
#endif
//-------------------------------------------------------------------------
#define _struct_array_type(type, lb, ub) \
class { \
public: \
_resident inline type& operator [] (int i) { return __data [i-(lb)];}; \
_resident inline type* operator -> () { return &__data [0 - (lb)]; }; \
_resident inline type* operator & () { return &__data [-(lb)]; }; \
_resident inline operator type * () { return &__data [-(lb)]; }; \
/* _resident inline operator void * () { return &__data [-(lb)]; }; */ \
private: \
type __data [(ub) - (lb) + 1]; \
}
//-----------------------------------------------
// Initialized Arrays With Non-Zero Lower Bounds:
//-----------------------------------------------
//-------------------------------------------------------------------------
#if 0
_initialized_array
The _initialized_array macro expands to the definition of an initialized
array variable with a nonzero lower bound.
_initialized_array(element_type,
variable_name,
lower_bound,
upper_bound)
element_type
is the type of the array elements.
variable_name
is the name of the variable that this macro invocation defines.
lower_bound
is an integer constant that specifies the lower bound of the array.
upper_bound
is an integer constant that specifies the upper bound of the array.
Usage Considerations
The _initialized_array macro expands to the definition of an initialized
array variable with a nonzero lower bound.
The _initialized_array macro defines an enumeration,
_num_elems_variable-name, which evaluates to the number of elements in
the array variable.
Use the _initialized_char_array macro to define an initialized array with a
nonzero lower bound and with character type elements.
You must immediately precede a use of this macro with a use of the
_init_array_value macro. For an example, see the description of
_init_array_value.
#endif
//-------------------------------------------------------------------------
#define _initialized_array(type, name, lb, ub) \
type * const name _value( ((type * const) __value_for_##name) - (lb) ); \
enum {_num_elems_##name = (ub) - (lb) + 1}
//-------------------------------------------------------------------------
#if 0
_init_array_value
The _init_array_value macro expands to the definition of an initialized
array variable.
_init_array_value(element_type,
variable_name)
element_type
is the type of the array elements.
variable_name
is the name of the variable that this macro invocation defines.
Usage Considerations
The _init_array_value macro expands to the definition of an initialized
array variable. The array, declared with no bounds, holds the list of
initial values.
You must immediately follow a use of this macro with a use of the
_initialized_array macro.
Access to the array variable requires no special syntax.
The following example defines an initialized array type variable, scarlett,
which has four int_32 type cells, indexed from 2 to 5 inclusively.
pTAL Code Generated C++ Code
INT(16) PROC WIND; extern "C" int_16 WIND()
BEGIN {
INT(32) x; int_32 x;
INT(32) scarlett[2:5] _init_array_value(
:= [0D,1D]; int_32,scarlett)={0,1};
_initialized_array(
int_32,scarlett,2,5);
... ...
scarlett[2] := 13; scarlett[2] = 13;
x := scarlett[5]; x = scarlett[5];
END; }
#endif
//-------------------------------------------------------------------------
#define _init_array_value(type, name) \
type __value_for_##name []
//-------------------------------------------------------------------------
#if 0
_initialized_char_array
The _initialized_char_array macro expands to the definition of an initialized
character type array variable with a nonzero lower bound.
_initialized_char_array(element_type,
variable_name,
lower_bound,
upper_bound,
initial_value)
element_type
is the type of the array elements.
variable_name
is the name of the variable that this macro invocation defines.
lower_bound
is an integer constant that specifies the lower bound of the array.
upper_bound
is an integer constant that specifies the upper bound of the array.
initial_value
is a string constant that specifies the initial value of this array of
characters.
Usage Considerations
The _initialized_char_array macro expand to the definition of an initialized
character array variable with a nonzero lower bound.
The _initialized_char_array macro defines an enumeration,
_num_elems_variable-name, which evaluates to the number of elements in
the array variable.
Use the _initialized_array macro to define an initialized array with a nonzero
lower bound whose elements are not characters.
Access to the array variable requires no special syntax.
The following example defines an initialized array of characters, ilsa,
which has five character type cells, indexed from -2 to 2 inclusively.
pTAL Code Generated C++ Code
INT(16) PROC RICKS; extern "C" int_16 RICKS()
BEGIN {
STRING x; char x;
STRING ilsa[-2:2] _initialized_char_array(
:= "paris"; char,ilsa,-2,2,"paris");
ilsa[-2] := "m"; ilsa[-2] = 'm';
END; }
#endif
//-------------------------------------------------------------------------
#define _initialized_char_array(type, name, lb, ub, value) \
_init_array_value(unsigned_char, name) = value; \
_initialized_array (type, name, lb, ub)
//---------------------------------------------
// Read-only Arrays With Non-Zero Lower Bounds:
//---------------------------------------------
//-------------------------------------------------------------------------
#if 0
_const_array
The _const_array macro expands to the definition of a read-only array
variable with a nonzero lower bound.
You must immediately precede a use of one of these macros with a use of the
_const_array_value macro.
Use the _const_char_array macro to define a read-only array with a nonzero
lower bound whose elements are characters.
_const_array(element_type,
variable_name,
lower_bound,
upper_bound)
element_type
is the type of the array elements.
variable_name
is the name of the variable that this macro invocation defines.
lower_bound
is an integer constant that specifies the lower bound of the array.
upper_bound
is an integer constant that specifies the upper bound of the array.
Usage Considerations
The _const_array macro expands to the definition of a read-only array
variable with a nonzero lower bound.
The _const_array macro defines an enumeration,
_num_elems_variable-name, which evaluates to the number of elements in
the array variable.
Use the _const_char_array macro to define a read-only array with a nonzero
lower bound and with character type elements.
You must immediately precede each use of this macro with a use of the
_const_array_value macro. For an example, see the description of
_const_array_value.
#endif
//-------------------------------------------------------------------------
#define _const_array(type, name, lb, ub) \
type _cspace const _near* const name = \
((type _cspace const _near* const) __value_for_##name) - (lb); \
enum {_num_elems_##name = (ub) - (lb) + 1}
//-------------------------------------------------------------------------
#if 0
_const_array_value
The _const_array_value macro expands to the definition of a read-only array
variable.
_const_array_value(element_type,
variable_name)
element_type
is the type of the array elements.
variable_name
is the name of the variable that this macro invocation defines.
Usage Considerations
The _const_array_value macro expands to the definition of a read-only array
variable. The array, declared with no bounds, holds the list of initial
values.
You must immediately follow each use of this macro with a use of the
_const_array macro.
Access to the array variable requires no special syntax.
The following example defines an initialized array type variable, rhett,
which has four int_32 type cells, indexed from 2 to 5 inclusively.
pTAL Code Generated C++ Code
INT(32) rhett _global _const_array_value(
:= [0D,1D,2D,3D]; int_32,rhett)
// #ifdef _export_globals
// = {0,1,2,3}
// #endif
;
_global _const_array(
int_32,rhett,2,5);
... ...
INT(32) .darn; int_32 *darn;
darn := rhett; *darn = rhett;
#endif
//-------------------------------------------------------------------------
#define _const_array_value(type, name) \
const _cspace type __value_for_##name []
//-------------------------------------------------------------------------
#if 0
_const_char_array
The _const_char_array macro expands to the definition of a read-only character
type array variable with a nonzero lower bound.
_const_char_array(element_type,
variable_name,
lower_bound,
upper_bound,
initial_value)
element_type
is the type of the array elements.
variable_name
is the name of the variable that this macro invocation defines.
lower_bound
is an integer constant that specifies the lower bound of the array.
upper_bound
is an integer constant that specifies the upper bound of the array.
initial_value
is a string constant that specifies the initial value of this array of
characters.
Usage Considerations
The _const_char_array macro expands to the definition of a read-only character
array variable with a nonzero lower bound.
The _const_char_array macro defines an enumeration,
_num_elems_variable-name, which evaluates to the number of elements in
the array variable.
Use the _const_array macro to define an initialized array with a nonzero lower
bound whose elements are not characters.
Access to the array variable requires no special syntax.
The following example defines a read-only array of characters, lazlo, which
has five character type cells, indexed from -2 to 2 inclusively.
pTAL Code Generated C++ Code
INT(16) PROC RICKS; extern "C" int_16 RICKS()
BEGIN {
STRING x; char x;
STRING lazlo[-2,2] _const_char_array(
:= "lisbon"; char,lazlo,-2,2,"lisbon");
x := lazlo[-2]; x = lazlo[-2];
END; }
#endif
//-------------------------------------------------------------------------
#define _const_char_array(var, name, lb, ub, value) \
_const_array_value(unsigned_char, name) = value; \
_const_array (var, name, lb, ub)
//---------------
// Equivalencing:
//---------------
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
#define _cast(type, var) *((type *)&(var))
//-------------------------------------------------------------------------
#if 0
_equiv
The _equiv macro defines a local variable that overlays a previously
defined variable. The previously defined variable can be an array cell,
a structure, or a scalar variable.
_equiv(variable_type,
variable_name,
previous_identifier)
variable_type
is the type of the equivalenced variable that this macro defines.
variable_name
is the name of the equivalenced variable.
previous_identifier
is the name of a previously defined variable which this variable is to
overlay.
Usage Considerations
An equivalenced variable causes no space to be allocated.
Use the _equiv_global macro to define a global variable that overlays a
previously defined variable.
Use the _equiv_array macro or _equiv_array_global macro to define an array
type variable that overlays a previously defined variable.
Access to an equivalenced variable requires no special syntax.
The following example defines a variable graham which is equivalenced to the
variable patti. It also defines a variable jordan which is equivalenced to
the array angela beginning at its cell zero.
pTAL Code Generated C++ Code
PROC SO_CALLED; extern "C" void SO_CALLED()
BEGIN {
INT(16) patti; int_16 patti;
INT(16) graham = patti; _equiv(int_16,graham,patti);
INT(16) angela[0:1]; int_16 angela[2];
INT(32) jordan = angela; _equiv(int_32,jordan,
angela[0]);
patti := 13; patti = 13;
graham := 14; graham = 14;
angela[1] := 4; angela[1] = 4;
jordan := 5D; jordan = 5;
END; }
The following example defines a variable rayanne which is equivalenced to
the variable rickie. It also defines a variable b which is equivalenced
to the array a beginning at its cell zero.
pTAL Code Generated C++ Code
PROC LIFE; extern C void LIFE()
BEGIN {
STRUCT r(*); struct r {
BEGIN int_16 i;
INT(16) i; int_16 j;
INT(16) j; };
END;
STRUCT rickie(r); r rickie;
INT(32) rayanne = rickie; _equiv(int_32,rayanne,rickie);
INT(16) a[-1:3]; _array_type(int_16,-1,3) a;
INT(16) b = a; _equiv(int_16,b,a[0]);
rayanne := 3D; rayanne = 3;
END; }
#endif
//-------------------------------------------------------------------------
#define _equiv(type, var, prev) type & var = _cast (type, prev)
//-------------------------------------------------------------------------
#if 0
_equiv_global
The _equiv_global macro defines a global variable that overlays a previously
defined variable. The previously defined variable can be an array cell, a
structure, or a scalar variable.
_equiv_global(variable_type,
variable_name,
previous_identifier)
variable_type
is the type of the equivalenced variable that this macro defines.
variable_name
is the name of the equivalenced variable.
previous_identifier
is the name of a previously defined variable which this variable is to
overlay.
Usage Considerations
An equivalenced variable causes no space to be allocated.
Use the _equiv macro to define a local variable that overlays a previously
defined variable. Use the _equiv_array macro or the _equiv_array_global
macro to define an array type variable that overlays a previously defined
variable.
Access to an equivalenced variable requires no special syntax.
The following example defines a variable chandler that is equivalenced to
the variable joey. It also defines a variable manana that is equivalenced
to the zero cell of the array mon. It also defines the variable ross that
is equivalenced to the zero cell of the array rachel.
pTAL Code Generated C++ Code
INT(16) joey; _global int_16 JOEY;
INT(16) chandler = joey; _equiv_global(int_16,CHANDLER, JOEY);
INT(16) phoebe[0:1]; _global int_16 PHOEBE[3];
INT(32) monica = phoebe; _equiv_global(int_16,MONICA,PHOEBE[0]);
INT(16) rachel[-1:1]; _global _array_type(int_16,-1,1) RACHEL;
INT(16) ross = rachel; _equiv_global(int_16,ROSS, RACHEL[0]);
#endif
//-------------------------------------------------------------------------
#define _equiv_global(type, var, prev) _resident inline type & var(void) \
{return _cast (type, prev);}
//-------------------------------------------------------------------------
#if 0
_equiv_array
The _equiv_array macro defines a local array variable that overlays a
previously defined variable. The previously defined variable can be
an array cell, a structure, or a scalar variable.
_equiv_array(element_type,
variable_name,
lower_bound,
upper_bound,
previous_identifier)
element_type
is the type of the array elements.
variable_name
is the name of the equivalenced variable.
lower_bound
is an integer constant that specifies the lower bound of the array.
upper_bound
is an integer constant that specifies the upper bound of the array.
previous_identifier
is the name of a previously defined variable which this variable is
to overlay.
Usage Considerations
Cell zero of the equivalenced array variable is aligned with the beginning
of a previously defined scalar variable. Cell zero of the equivalenced
array variable is aligned with cell zero of the previously defined array
variable, even if either array is defined with a nonzero lower bound.
The _equiv_array macro defines an enumeration,
_num_elems_variable-name, which evaluates to the number of elements in
the array variable.
Use the _equiv or _equiv_global macro to define a variable that is not
an array and that overlays a previously defined variable.
An equivalenced variable causes no space to be allocated.
Access to an equivalenced variable requires no special syntax.
The following example defines an array variable bing which overlays the
variable cherries. It also defines an array variable granny_smith which
overlays the array apples beginning at its cell zero; the variable
granny_smith does not overlay apples[-2] or apples[-1]. The array variable
pippin also overlays the array apples with pippin[0] aligned with apples[0].
The array variable concord overlays the structure grapes.
pTAL Code Generated C++ Code
PROC SALAD; extern "C" void SALAD()
BEGIN {
INT(32) cherries; int_32 cherries;
INT(16) bing[0:1] _equiv_array(int_16,bing,0,1,
= cherries; cherries);
INT(16) apples[-2:7]; _array_type(int_16,-2,7)
apples;
INT(16) granny_smith[0:7] _equiv_array(int_16,
= apples; granny_smith,0,7,
apples[0]);
INT(16) pippin[-1:5] _equiv_array(int_16,pippin,
= apples; -1,5,apples[0]);
STRUCT g(*); struct g {
BEGIN int_16 i;
INT(16) i; int_16 j;
INT(16) j; };
END; g grapes;
STRUCT grapes(g); _equiv_array(int_16,concord,
INT(16) concord[0:1] 0,1,grapes);
= grapes;
cherries := 3D; cherries = 3;
bing[0] := 4; bing[0] = 4;
apples[-2] := 5; apples[-2] = 5;
granny_smith[0] := 6; granny_smith[0] = 6;
pippin[-1] := 7; pippin[-1] = 7;
grapes.i := 8; grapes.i = 8;
concord[0] := 9; concord[0] = 9;
END; }
#endif
//-------------------------------------------------------------------------
#define _equiv_array(type, array, lb, ub, prev) \
type * const array = ((type * const) &(prev)); /*- (lb)*/ \
enum {_num_elems_##array = (ub) - (lb) + 1}
//-------------------------------------------------------------------------
#if 0
_equiv_array_global
The _equiv_array_global macro defines a global array variable that
overlays a previously defined variable. The previously defined variable
can be an array cell, a structure, or a scalar variable.
_equiv_array_global(element_type,
variable_name,
lower_bound,
upper_bound,
previous_identifier)
element_type
is the type of the array elements.
variable_name
is the name of the equivalenced variable.
lower_bound
is an integer constant that specifies the lower bound of the array.
upper_bound
is an integer constant that specifies the upper bound of the array.
previous_identifier
is the name of a previously defined variable which this variable is
to overlay.
Usage Considerations
Cell zero of the equivalenced array variable is aligned with the beginning
of a previously defined scalar variable. Cell zero of the equivalenced
array variable is aligned with cell zero of the previously defined array
variable, even if either array is defined with a nonzero lower bound.
The _equiv_array_global macro defines an enumeration,
_num_elems_variable-name, which evaluates to the number of elements in
the array variable.
Use the _equiv_array macro to define a local array variable that overlays
a previously defined variable. Use the _equiv or _equiv_global macro to
define a variable that is not an array and that overlays a previously
defined variable.
An equivalenced variable causes no space to be allocated.
Access to an equivalenced variable requires no special syntax.
#endif
//-------------------------------------------------------------------------
#define _equiv_array_global(type, array, lb, ub, prev) \
_resident inline type * const array(void) \
{return ((type * const) &(prev)) /*- (lb)*/;}; \
enum {_num_elems_##array = (ub) - (lb) + 1}
//-------------------------------------------------------------------------
#if 0
_equiv_offset
The _equiv_offset macro defines a local variable that overlays a previously
defined variable, offset by the given number of 16-bit words. The previously
defined variable can be an array cell, a structure, or a scalar variable.
_equiv_offset(variable_type,
variable_name,
previous_identifier,
16_bit_word_offset)
variable_type
is the type of the equivalenced variable that this macro defines.
variable_name
is the name of the equivalenced variable.
previous_identifier
is the name of a previously defined variable.
16_bit_word_offset
is an integer constant that specifies the number of 16-bit words to
offset from the storage address of the previous_identifier which is
the address which this variable is to overlay.
Usage Considerations
The equivalenced variable is aligned with the beginning of the previously
defined scalar variable plus the indicated offset. The equivalenced
variable is aligned with cell zero of the previously defined array
variable plust the indicated offset.
Use the _equiv_offset_global macro to define a global variable that overlays
a previously defined variable. Use the _equiv_array_offset macro or the
_equiv_array_offset_global macro to define an array type variable that
overlays a previously defined variable offset by a constant number of
16-bit words.
An equivalenced variable causes no space to be allocated.
Access to an equivalenced variable requires no special syntax.
The following example defines the variable brandon which is equivalenced
to the variable brenda but begins 16 bits past the beginning of the
variable brenda. It defines the variable donna which is equivalenced
to the variable david but begins 32 bits past the zero cell of the
variable david. It also defines the variable jesse which is equivalenced
to the variable andrea but begins 16 bits past the zero cell of the
variable andrea.
pTAL Code Generated C++ Code
PROC BH; extern "C" void BH()
BEGIN {
INT(32) brenda; int_32 brenda;
INT(16) brandon _equiv_offset(int_16,brandon,
= brenda + 1; brenda,1);
STRING david[0:9]; char david[10];
STRING donna = david + 2; _equiv_offset(char,donna,
*david,2);
INT(16) andrea[-2:2]; _array_type(int_16,-2,2)
andrea;
INT(16) jesse _equiv_offset(int_16,jesse,
= andrea + 1; *andrea,1);
brandon := 3; brandon = 3;
donna := "a"; donna = 'a';
jesse := 16; jesse = 16;
END; }
#endif
//-------------------------------------------------------------------------
#define _equiv_offset(type, var, prev, _16_bit_offset) \
type &var = _cast (type, *(((int_16*)&prev) + (_16_bit_offset)))
//-------------------------------------------------------------------------
#if 0
_equiv_offset_global
The _equiv_offset_global macro defines a global variable that overlays a
previously defined variable, offset by the given number of 16-bit words.
The previously defined variable can be an array cell, a structure, or a
scalar variable.
_equiv_offset_global(variable_type,
variable_name,
previous_identifier,
16_bit_word_offset)
variable_type
is the type of the equivalenced variable that this macro defines.
variable_name
is the name of the equivalenced variable.
previous_identifier
is the name of a previously defined variable.
16_bit_word_offset
is an integer constant that specifies the number of 16-bit words to
offset from the storage address of the previous_identifier which is
the address which this variable is to overlay.
Usage Considerations
The equivalenced variable is aligned with the beginning of the previously
defined scalar variable plus the indicated offset. The equivalenced
variable is aligned with cell zero of the previously defined array
variable plust the indicated offset.
Use the _equiv_offset macro to define a local variable that overlays
a previously defined variable. Use the _equiv_array_offset macro or the
_equiv_array_offset_global macro to define an array type variable that
overlays a previously defined variable offset by a constant number of
16-bit words.
An equivalenced variable causes no space to be allocated.
Access to an equivalenced variable requires no special syntax.
The following example defines the variable vera which is equivalenced to
the variable norm but begins 16 bits past the beginning of the variable
norm. It defines the variable coach which is equivalenced to the array
variable woody but begins 32 bits past the zero cell of the array woody.
It also defines the variable carla which is equivalenced to the array
variable diane but begins 16 bits past the zero cell of the variable diane.
pTAL Code Generated C++ Code
INT(32) norm; _global int_32 NORM;
INT(16) vera = norm + 1; _global _equiv_offset(int_16,VERA,NORM,1);
INT(16) woody[-1:2]; _global _array_type(int_16,-1,2) WOODY;
INT(16) coach = woody + 2; _equiv_offset_global(int_16,COACH,*WOODY,2);
INT(16) diane[0:3]; _global int_16 DIANE[4];
INT(16) carla = diane + 1; _equiv_offset_global(int_16,CARLA,*DIANE,1);
#endif
//-------------------------------------------------------------------------
#define _equiv_offset_global(type, var, prev, _16_bit_offset) \
_resident inline type &var(void) \
{return _cast (type, *(((int_16*)&prev) + (_16_bit_offset)));}
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
//---------------------------------------------------------------------------
// _equiv_array_offset:
// --------------------
// Note that, as in Ptal, the array bounds on an equivalenced array are
// for documentation only; it is the 0th element which gets equivalenced
// to the specified 16-bit offset above the previous variable:
//---------------------------------------------------------------------------
//-------------------------------------------------------------------------
#if 0
_equiv_array_offset
The _equiv_array_offset macro defines a local array variable that overlays
a previously defined variable, offset by the given number of 16-bit words.
The previously defined variable can be an array cell, a structure, or a
scalar variable.
_equiv_array_offset(element_type,
variable_name,
lower_bound,
upper_bound,
previous_identifier,
16_bit_word_offset)
element_type
is the type of the array elements.
variable_name
is the name of the equivalenced variable.
lower_bound
is an integer constant that specifies the lower bound of the array.
upper_bound
is an integer constant that specifies the upper bound of the array.
previous_identifier
is the name of a previously defined variable which this variable is
to overlay.
16_bit_word_offset
is an integer constant that specifies the number of 16-bit words to
offset from the storage address of the previous_identifier which is
the address which this variable is to overlay.
Usage Considerations
Cell zero of the equivalenced array variable is aligned with the beginning
of the previously defined scalar variable plus the indicated offset. Cell
zero of the equivalenced array variable is aligned with cell zero of the
previously defined array variable plus the indicated offset, even if that
array is defined with a nonzero lower bound.
The _equiv_array_offset macro defines an enumeration,
_num_elems_variable-name, which evaluates to the number of elements in
the array variable.
Use the _equiv_array_offset_global macro to define a global array variable
that overlays a previously defined variable offset by a constant number of
16-bit words. Use the _equiv_offset macro or the _equiv_offset_global macro
to define variable that is not an array and that overlays a previously
defined variable offset by a constant number of 16-bit words.
An equivalenced variable causes no space to be allocated.
Access to an equivalenced variable requires no special syntax.
The following example defines the array variable skipper which is
equivalenced to the variable gilligan but whose zero cell begins 16 bits
past the beginning of the variable gilligan. It defines the array
variable maryann which is equivalenced to the array variable ginger but
whose zero cell begins 32 bits past the zero cell of the array ginger.
It defines the array variable lovey which is equivalenced to the array
variable howell but whose zero cell begins 16 bits past the zero cell
of the variable howell. It also defines the array variable minnow which
is equivalenced to the array variable professor but whose virtual zero
cell begins 16 bits past the zero cell of the variable professor.
pTAL Code Generated C++ Code
PROC ISLAND; extern "C" void ISLAND()
BEGIN {
INT(32) gilligan; int_32 gilligan;
STRING skipper[0:1] _equiv_array_offset(char,
= gilligan + 1; skipper,0,1,gilligan,1);
INT(16) ginger[0:5]; int_16 ginger[6];
INT(16) maryann[0:3] _equiv_array_offset(int_16,
= ginger + 2; maryann,0,7,*ginger,2);
INT(16) howell[-2:2]; _array_type(int_16,-2,2) howell;
INT(16) lovey[0:1] _equiv_array_offset(int_16,
= howell + 1; lovey,0,1,*howell,1);
INT(16) prof[0:4]; int_16 prof[5];
INT(16) minnow[1:3] _equiv_array_offset(int_16,
= prof + 1; minnow,1,3,*professor,1);
skipper[0] := "a"; skipper[0] = 'a';
maryann[0] := 20; maryann[0] = 20;
lovey[0] := 21; lovey[0] = 21;
minnow[1] := 22; minnow[1] = 22;
END; }
#endif
//-------------------------------------------------------------------------
#define _equiv_array_offset(type, array, lb, ub, prev, _16_bit_offset) \
type * const array = \
(type * const) (((int_16*)&(prev))+(_16_bit_offset)); \
enum {_num_elems_##array = (ub) - (lb) + 1}
//-------------------------------------------------------------------------
#if 0
_equiv_array_offset_global
The _equiv_array_offset_global macro defines a global array variable that
overlays a previously defined variable, offset by the given number of
16-bit words. The previously defined variable can be an array cell, a
structure, or a scalar variable.
_equiv_array_offset_global(element_type,
variable_name,
lower_bound,
upper_bound,
previous_identifier,
16_bit_word_offset)
element_type
is the type of the array elements.
variable_name
is the name of the equivalenced variable.
lower_bound
is an integer constant that specifies the lower bound of the array.
upper_bound
is an integer constant that specifies the upper bound of the array.
previous_identifier
is the name of a previously defined variable which this variable is
to overlay.
16_bit_word_offset
is an integer constant that specifies the number of 16-bit words to
offset from the storage address of the previous_identifier which is
the address which this variable is to overlay.
Usage Considerations
Cell zero of the equivalenced array variable is aligned with the beginning
of the previously defined scalar variable plus the indicated offset. Cell
zero of the equivalenced array variable is aligned with cell zero of the
previously defined array variable plus the indicated offset, even if that
array is defined with a nonzero lower bound.
The _equiv_array_offset macro defines an enumeration,
_num_elems_variable-name, which evaluates to the number of elements in
the array variable.
Use the _equiv_array_offset macro to define a local array variable that
overlays a previously defined variable offset by a constant number of
16-bit words. Use the _equiv_offset macro or the _equiv_offset_global
macro to define variable that is not an array and that overlays a
previously defined variable offset by a constant number of 16-bit words.
An equivalenced variable causes no space to be allocated.
Access to an equivalenced variable requires no special syntax.
The following example defines the array variable frasier which is
equivalenced to the variable roz but whose cell zero is located 16
bits past the beginning of the variable roz. The array variable x
is also equivalenced to roz, and has a zero cell located 16 bits past
the beginning of the variable roz. It defines the array variable niles
which is equivalenced to the array variable daphne but has a zero cell
located 32 bits past the zero cell of the variable daphne.
pTAL Code Generated C++ Code
INT(32) roz; _global int_32 ROZ;
STRING frasier[0:1] _equiv_array_offset_global(unsigned_char,
= roz + 1; FRASIER,0,1,ROZ,1);
STRING x[-2:0] _equiv_array_offset_global(unsigned_char,
= roz + 1; X,-2,0,ROZ,1);
INT(16) daphne[-1:4]; _global _array_type(int_16,-1,4) DAPHNE;
INT(16) niles[-1:1] _equiv_array_offset_global(int_16,NILES,
= daphne + 2; -1,1,*DAPHNE,2);
#endif
//-------------------------------------------------------------------------
#define _equiv_array_offset_global(type, array, lb, ub, prev, _16_bit_offset) \
_resident inline type * const array(void) \
{return (type * const) (((int_16*)&(prev))+(_16_bit_offset));}; \
enum {_num_elems_##array = (ub) - (lb) + 1}
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
#if 0
The pTAL language allows you to extract a value stored in a bit or contiguous
sequence of bits in any 16-bit l-value. It also allows you to deposit a value into a bit or
contiguous sequence of bits in any 16-bit expression.
The pTAL to C++ Translator emulates pTAL bit deposit and bit extract operations
with calls to the functions _bit_deposit and _bit_extract. For example:
pTAL Code Generated C++ Code
INT(16) fields, x; int_16 fields, x;
fields.<0:3> := 9; _bit_deposit(fields,0,3,9);
x := fields.<0:3>; x = _bit_extract(fields,0,3);
fields.<4> := 1; _bit_deposit(fields,4,4,1);
x := fields.<4>; x = _bit_extract(fields,4,4);
Bit Extraction
The _bit_extract function, supplied in the rosgen.h include file,
extracts a value stored in a bit or contiguous sequence of bits in
any 16-bit expression.
int_16 _bit_extract(int_16 expr,
int_16 lower_bound,
int_16 upper_bound)
expr
is the expression from which this function will extract a value occupying
a bit field.
lower_bound
indicates the most significant bit in the field to be extracted, where
the most significant bit in a 16-bit word is numbered zero. lower_bound
is an integer constant in the range 0 through 15.
upper_bound
indicates the least significant bit in the field to be extracted, where
the least significant bit in a 16-bit word is numbered 15. upper_bound
is an integer constant in the range 0 through 15.
Usage Considerations
The value of upper_bound must be at least as large as lower_bound.
In the following example, the variable y gets the value that occupies the
field composed of bits 0, 1, and 2 (the most significant three bits) of
the variable x. The variable z gets the value that occupies bit 3 of the
variable x.
int_16 x,y,z;
y = _bit_extract(x,0,2);
z = _bit_extract(x,3,3);
Bit Deposit
The _bit_deposit function, supplied in the rosgen.h include file, deposits
a value into a bit or contiguous sequence of bits in any 16-bit expression.
int_16 _bit_deposit(int_16 expr,
int_16 lower_bound,
int_16 upper_bound,
int_16 value)
expr
is the expression from which this function will extract bits.
lower_bound
indicates the most significant bit in the field in which the value is
to be deposited, where the most significant bit in a 16-bit word is
numbered zero. lower_bound is an integer constant in the range 0
through 15.
upper_bound
indicates the least significant bit in the field in which the value is
to be deposited, where the least significant bit in a 16-bit word is
numbered 15. upper_bound is an integer constant in the range 0 through 15.
value
is the expression whose value is to be stored in the bit field delimited
by the bits numbered lower_bound and upper_bound.
Usage Considerations
The value of upper_bound must be at least as large as lower_bound.
In the following example, the value 7 is stored in the field composed
of bits 0, 1, and 2 (the most significant three bits) of the variable x.
The value 1 is stored in bit 3 of the variable x.
int_16 x;
_bit_deposit(x,0,2,7);
_bit_deposit(x,3,3,1);
#endif
//-------------------------------------------------------------------------
#define __mask(lb, rb) \
(((rb) - (lb) + 1) == 32 ? \
0xFFFFFFFF : \
(1u << ((rb) - (lb) + 1)) - 1)
#define __shifted_mask(wordlen, lb, rb) \
(__mask (lb, rb) << (((wordlen) - 1) - (rb)))
#define _deposit_bits(varble, wordlen, expr, lb, rb) \
(varble = ((varble & ~__shifted_mask (wordlen, lb, rb)) | \
((expr & __mask (lb, rb)) << (((wordlen) - 1) - (rb)))))
// Two versions of _bit_deposit to allow deposit in 8-bit or 16-bit target:
_resident inline short _bit_deposit (unsigned_32 &varble,
unsigned_16 lb,
unsigned_16 rb,
int_16 expr) {
_deposit_bits (varble, 32, expr, lb, rb);
return expr;
}
_resident inline short _bit_deposit (unsigned_16 &varble,
unsigned_16 lb,
unsigned_16 rb,
int_16 expr) {
_deposit_bits (varble, 16, expr, lb, rb);
return expr;
}
_resident inline short _bit_deposit (int_16 &varble,
unsigned_16 lb,
unsigned_16 rb,
int_16 expr) {
_deposit_bits (varble, 16, expr, lb, rb);
return expr;
}
_resident inline short _bit_deposit (unsigned_char &varble,
unsigned_16 lb,
unsigned_16 rb,
int_16 expr) {
_deposit_bits (varble, 16, expr, lb, rb);
return expr;
}
#define _bit_deposit_item(item, lb, rb, expr) \
_deposit_bits (item, 16, expr, lb, rb), expr;
#define _decl_bit_deposit_uns(bitcount) \
_resident inline short _bit_deposit_uns (_unsigned_##bitcount &varble, \
unsigned_16 lb, \
unsigned_16 rb, \
int_16 expr) { \
_deposit_bits (varble (), 16, expr, lb, rb); \
return expr; \
}
_decl_bit_deposit_uns (1)
_decl_bit_deposit_uns (2)
_decl_bit_deposit_uns (3)
_decl_bit_deposit_uns (4)
_decl_bit_deposit_uns (5)
_decl_bit_deposit_uns (6)
_decl_bit_deposit_uns (7)
_decl_bit_deposit_uns (8)
_decl_bit_deposit_uns (9)
_decl_bit_deposit_uns (10)
_decl_bit_deposit_uns (11)
_decl_bit_deposit_uns (12)
_decl_bit_deposit_uns (13)
_decl_bit_deposit_uns (14)
_decl_bit_deposit_uns (15)
#undef _decl_bit_deposit_uns
#define _decl_bit_deposit_uns(bitcount) \
_resident inline short _bit_deposit_uns (_unsigned_##bitcount &varble, \
unsigned_16 lb, \
unsigned_16 rb, \
int_32 expr) { \
_deposit_bits (varble (), 32, expr, lb, rb); \
return expr; \
}
_decl_bit_deposit_uns (17)
_decl_bit_deposit_uns (18)
_decl_bit_deposit_uns (19)
_decl_bit_deposit_uns (20)
_decl_bit_deposit_uns (21)
_decl_bit_deposit_uns (22)
_decl_bit_deposit_uns (23)
_decl_bit_deposit_uns (24)
_decl_bit_deposit_uns (25)
_decl_bit_deposit_uns (26)
_decl_bit_deposit_uns (27)
_decl_bit_deposit_uns (28)
_decl_bit_deposit_uns (29)
_decl_bit_deposit_uns (30)
_decl_bit_deposit_uns (31)
#undef _decl_bit_deposit_uns
_resident inline int_32 _bit_deposit_long (int_32 &varble,
unsigned_16 lb,
unsigned_16 rb,
int_32 expr) {
_deposit_bits (varble, 32, expr, lb, rb);
return expr;
}
#define _bit_deposit_long_item(item, lb, rb, expr) \
_deposit_bits (item, 32, expr, lb, rb), expr;
#define _extract_bits(expr, wordlen, lb, rb) \
(((wordlen) == ((rb) - (lb) + 1)) ? \
(expr) : \
(((expr) >> (((wordlen) - 1) - (rb))) & \
((1u << ((rb) - (lb) + 1)) - 1)))
// Define versions of _bit_extract, for use in contexts where inline
// functions can't be called:
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
#define _bit_extract_n(expr, lb, rb) _extract_bits(expr, 16, lb, rb)
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
#define _bit_extract_long_n(expr, lb, rb) _extract_bits(expr, 32, lb, rb)
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
#define _bit_extract_long_to_short_n(expr, lb, rb) \
((int_16)_extract_bits(expr, 32, lb, rb))
// Inline function versions of _bit_extract, for use in contexts where inline
// functions can be called:
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
_resident inline int_16 _bit_extract (int_16 expr, short lb, short rb) {
return (int_16)_extract_bits (expr, 16, lb, rb);
}
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
_resident inline int_32 _bit_extract_long (int_32 expr, short lb, short rb) {
return _extract_bits (expr, 32, lb, rb);
}
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
_resident inline int_16 _bit_extract_long_to_short
(int_32 expr, short lb, short rb) {
return (int_16)_extract_bits(expr, 32, lb, rb);
}
//-------------------------------------------------------------------------
#if 0
Emulating an Alternate Entry Point
A pTAL procedure can have multiple entry points; a C++ function cannot.
Local variables are initialized when control enters a pTAL procedure via
any entry point. Control entering a pTAL procedure from its primary
entry point begins executing statements at the beginning of the procedure;
control entering a pTAL procedure from an alternate entry point begins
executing statements at the label representing the alternate entry point.
The pTAL to C++ Translator translates a pTAL procedure that has alternate
entry points to a C++ function representing the body of the routine and a
set of interface routines, each of which represents an entry point.
Consider the following pTAL example:
INT(16) PROC jekyll(a);
INT(16) a;
BEGIN
ENTRY hyde;
INT(16) i := 13;
INT(16) j := 17;
i := i + 1;
hyde:
j := j - 1;
RETURN i + j + a;
END;
...
x := jekyll(2);
y := hyde(3);
This pTAL procedure contains two entry points. The pTAL to C++ Translator
emits the following C++ code that is equivalent to the pTAL code.
inline int_16 _inline_JEKYLL(int_16 a,
int entry)
{
int_16 i = 13;
int_16 j = 17;
Entry(HYDE,1);
++i;
HYDE: --j;
return i + j + a;
}
//--- Translator-generated shell for entry-point JEKYLL: ---
extern "C" int_16 JEKYLL(int_16 a)
{
return _inline_JEKYLL(a,0);
}
//--- Translator-generated shell for entry-point HYDE: ---
extern "C" int_16 HYDE(int_16 a)
{
return _inline_JEKYLL(a,1);
}
...
x = JEKYLL(2);
x = HYDE(3);
The common procedure body, _inline_JEKYLL, is an inline function. If
compiled with a C++ compiler that performs inlining, there is no
performance penalty associated with the call, but there is some expansion
of code file space which could adversely effect performance.
Entry
The Entry macro tests to see if the parameter entry passed into the
surrounding function is equal to the second parameter to the macro. If so,
it transfers control to the label whose name is given as the first parameter
to the macro.
void Entry(label_name, entry_num)
label_name
is the name of a label to which control transfers if the parameter
entry matches entry-num.
entry_num
is an integer constant associated with the entry point which is being invoked.
Optional Parameters
The translation of a pTAL procedure with multiple entry points that has
the EXTENSIBLE or VARIABLE attribute requires the C++-coded entry point
shells to pass parameters that might be optional to the routine
representing the main body of the procedure. The _pass_along macro
provides a shorthand way to pass an optional parameter to another routine
for which the parameter is optional.
Consider the following pTAL example:
INT(16) PROC CLARK_KENT(a) EXTENSIBLE;
INT(16) a;
BEGIN
INT(16) x;
ENTRY SUPERMAN;
...
SUPERMAN:
...
END;
...
z := CLARK_KENT(5);
z := SUPERMAN();
This pTAL procedure contains two entry points. The pTAL to C++ Translator
emits the following C++ code that is equivalent to the pTAL code.
inline int_16 _inline_CLARK_KENT(int_16 a
int entry)
{
int_16 x;
Entry(SUPERMAN,1);
...
SUPERMAN:
...
}
// Translator-generated shell for entry-point CLARK_KENT:
extern "C" _extensible int_16 CLARK_KENT(int_16 a)
{
return _inline_CLARK_KENT(_pass_along(a),0);
}
// Translator-generated shell for entry-point SUPERMAN:
extern "C" _extensible int_16 SUPERMAN(int_16 a)
{
return _inline_CLARK_KENT(_pass_along(a),1);
}
...
z = CLARK_KENT(5);
z = SUPERMAN();
Modifying an Entry Point
Suppose you were to add a new entry point to this function. You would add
a shell for the new entry point, add an invocation of the Entry macro which
transfers control to a new label, and add the label to the appropriate place
in the code. The following example illustrates the addition of the entry
point STEVENSON to the procedure.
inline int_16 _inline_JEKYLL(int_16 a,
int entry)
{
int_16 i = 13;
int_16 j = 17;
Entry(HYDE,1);
Entry(STEVENSON,2);
++i;
HYDE: --j;
STEVENSON:
return i + j + a;
}
//--- Translator-generated shell for entry-point JEKYLL: ---
extern "C" int_16 JEKYLL(int_16 a)
{
return _inline_JEKYLL(a,0);
}
//--- Translator-generated shell for entry-point HYDE: ---
extern "C" int_16 HYDE(int_16 a)
{
return _inline_JEKYLL(a,1);
}
//--- Additional entry-point STEVENSON: ---
extern "C" int_16 STEVENSON(int_16 a)
{
return _inline_JEKYLL(a,2);
}
...
x = JEKYLL(2);
x = HYDE(3);
x = STEVENSON(25);
#endif
//-------------------------------------------------------------------------
// Entry lets entry declarations translate almost 1:1; only parens are added:
#define Entry(name,entry_num) if (entry == entry_num) goto name
//-------------------------------------------------------------------------
#if 0
_pass_along
The _pass_along macro, supplied in the rosgen.h include file, provides a
shorthand way to pass an optional parameter in a function with the _variable
or _extensible attribute to another _variable or _extensible function for
which the parameter is optional.
_pass_along(formal_param_name)
formal_param_name
is the name of a formal parameter for a function with the _variable or
_extensible attribute.
The _pass_along macro expands to the following:
_optional(_arg_present(formal_param_name), formal_param_name)
#endif
//-------------------------------------------------------------------------
// _pass_along is used when invoking an extensible or variable proc from
// within a variable or extensible proc:
#define _pass_along(param) _optional (_arg_present (param), param)
//-------------------------------------------------------------------------
#if 0
The pTAL to C++ Translator emulates the pTAL ASSERT statement with the
assert macro, the _ASSERTION_LEVEL_ macro, and the _ASSERTION_PROC_ macro.
The assert macro invokes the procedure whose name is encapsulated by the
_ASSERTION_PROC_ if the level parameter passed to assert is at least as
large as _ASSERTION_LEVEL_ and the condition parameter passed to assert
evaluates to a nonzero value.
assert
The assert macro invokes a particular procedure.
assert(int level,
int condition)
level
is an integer expression.
condition
is an integer expression.
Usage Considerations
The macro _ASSERTION_LEVEL_ must be defined before the first invocation of
assert.
The macro _ASSERTION_PROC_ must be defined before the first invocation of
assert.
The macro _ASSERTION_LEVEL_ must expand to an integer expression.
The macro _ASSERTION_PROC_ must expand to the name of a procedure with the
following profile:
extern "C" void proc_name()
The procedure named in the body of the _ASSERTION_PROC_ macro must be
declared before the first invocation of assert.
If level is greater than or equal to the value of the expression in the body
of _ASSERTION_LEVEL_ and condition evaluates to a nonzero value, then the
procedure named in _ASSERTION_PROC_ is invoked.
In the following example, the procedure APROC is invoked by the assert
statement, which is given a level of at least 10 and a condition that
evaluates to a nonzero value.
pTAL Code Generated C++ Code
?ASSERTION = 10, APROC #undef _ASSERTION_LEVEL_
#define _ASSERTION_LEVEL_ 10
#undef _ASSERTION_PROC_
#define _ASSERTION_PROC_ APROC
... ...
PROC APROC; extern "C" void APROC()
BEGIN {
... ...
END; }
... ...
j := 2; j = 2
ASSERT 20:( j = 2 ); assert(20, (j == 2));
#endif
//-------------------------------------------------------------------------
// For pTAL assert statement
#define assert_at_level(level,expr) \
if (level >= _ASSERTION_LEVEL_ && (expr)) \
_ASSERTION_PROC_(); \
else
//-------------------------------------------------------------------------
#if 0
The pTAL language specifies that if a labeled CASE statement, an unlabeled
CASE statement, or a CASE expression contains no default CASE specification,
and the selector expression evaluates to a value that does not match a case
alternative, then a run-time error occurs.
Emulating pTAL Case Statements and Expressions
The pTAL to C++ Translator generates code to force an arithmetic trap in
the default case of a switch statement when the original pTAL CASE statement
or expression contained no OTHERWISE clause. The pTAL to C++ Translator
always generates this check for labeled CASE statements and for CASE
expressions, and it generates this check for unlabeled CASE statements when
the CHECK directive is in effect during translation.
The following example illustrates the translation of pTAL CASE statements
and expressions that contain no default cases.
pTAL Code Generated C++ Code
CASE x OF BEGIN switch (x) {
0 -> y := 10; case 0 : y = 10;
1 -> y := 11; break;
2 -> y := 12; case 1 : y = 11;
END; break;
case 2 : y = 12;
break;
default: {
_force_arith_trap();
}
}
?CHECK
CASE x OF BEGIN switch (x) {
y := 10; case 0 : y = 10;
y := 11; break;
y := 12; case 1 : y = 11;
END; break;
case 2 : y = 12;
break;
default: _force_arith_trap();
}
y := CASE x OF BEGIN x = (x == 0 ? 10 :
10; x == 1 ? 11 :
11; x == 2 ? 12 :
12; _force_arith_trap());
END;
#endif
//-------------------------------------------------------------------------
_resident inline short _zero (void) { return 0; }
_resident inline short _force_arith_trap (void) { return _zero () /_zero (); }
//-------------------------------------------------------------------------
#if 0
Emulating pTAL Optimized For Loops
A pTAL optimized FOR loop uses a reserved index register, declared in a
USE statement, as a control variable. The pTAL to C++ Translator generates
an invocation of the _for macro to emulate the intricate semantics of the
pTAL optimized FOR loop.
The _for macro emulates pTAL optimized FOR loop semantics.
_for(control_variable,
initial_value,
limit)
statement
control_variable
is a 16-bit integer variable.
initial_value
is a 16-bit integer expression whose value is assigned to the
control_variable before the first iteration through the loop.
limit
is a 16-bit integer expression that terminates the FOR loop s execution.
statement
is any statement.
Usage Considerations
A pTAL optimized FOR loop uses a reserved index register, declared in a USE
statement, as a control variable.
The _for define preserves the behavior of pTAL optimized FOR loops.
- The limit is calculated once, at the beginning of the first iteration
of the loop.
- If the initial_value is -32768, then the loop will execute zero times.
- If the limit is 32767, then overflow will not occur, as it does for
non-optimized FOR loops.
- The value of the control_variable after normal termination of the loop
is the limit, not the limit + 1 as it is for non-optimized FOR loops.
The following example illustrates the translation of a normal pTAL FOR
loop and an optimized pTAL FOR loop.
pTAL Code Generated C++ Code
INT(16) i; int_16 i;
FOR i := 1 TO 10 DO for (i = 1; i <= 10; ++i)
USE j; int_16 j;
FOR j := 1 TO 10 DO _for (j, 1, 10)
#endif
//-------------------------------------------------------------------------
// This define implements pTAL "optimized" for loop semantics. It
// preserves three funny behaviors of pTAL optimized for loops. 1) If
// lower bound is -32768, the loop will execute 0 times. 2) If the
// upper bound is 32767, overflow will not occur, as it does for
// non-optimized for loops. 3) The value of the control variable after
// normal termination of the loop is the limit, not the limit+1 as it is
// for non-optimized for loops.
#define _for(i,lb,ub) for (i = (unsigned)(lb)-1u;((int)(i) < \
(int)(ub)) ? i++,1 : 0;)
//-------------------------------------------------------------------------
#if 0
Emulating pTAL Condition Code Indicators
The pTAL to C++ Translator emulates pTAL condition code indicators by
generating Tandem C++ code that explicitly checks the outcome of the
procedure or assignment expression rather than checking the hardware
condition code settings.
Status of Condition Code
The following macros test a condition code value. These macros mask
architectural differences in the definition of condition code settings
between the TNS and TNS/R native C++ compilers.
int_16 _status_gt(int cc_value)
int_16 _status_lt(int cc_value)
int_16 _status_eq(int cc_value)
int_16 _status_ge(int cc_value)
int_16 _status_le(int cc_value)
int_16 _status_ne(int cc_value)
cc_value
is a condition code value.
Usage Considerations
These macros return the value 1 (TRUE) or the value 0 (FALSE).
Note
The _status_gt, _status_lt, and _status_eq defines are available in the
Tandem C++ runtime library. The _status_ge, _status_le, and _status_ne
defines are available in the rosgen.h include file.
Example
The following example checks the outcome of assignment expressions.
pTAL Code Generated C++ Code
PROC P; extern "C" void P()
BEGIN {
int_32 _cc_temp;
INT(16) i16 := 8; int_16 i16 = 8;
INT(32) i32 := 7; int_32 i32 = 7;
FIXED(0) f0 := 5F; fixed_0 f0 = 5LL;
REAL(32) r32; real_32 r32;
REAL(64) r64; real_64 r64;
i16 := i16 + 8; _cc_temp = i16 = i16 + 8;
IF < THEN; if (_status_lt(_cc_temp))
;
i32 := i32 + 2D; _cc_temp = i32 = i32 + 2;
IF > THEN if (_status_gt(_cc_temp))
BEGIN END {}
ELSE IF < THEN else if (_status_lt(_cc_temp))
BEGIN END; {};
f0 := f0 + 2F; _cc_temp = _determine_cc(
f0 = f0 + 2LL,0LL);
IF > THEN; if (_status_gt(_cc_temp)) ;
IF (f0 > 2F) THEN if (_status_gt(_cc_temp =
_determine_cc(
f0,(fixed_0)2LL)))
BEGIN END {}
ELSE IF < THEN else if (_status_lt(_cc_temp))
BEGIN END; {};
IF (r32 < 2.20E0) THEN if (_status_lt(_cc_temp =
_determine_cc(
r32,(real_32)2.20E+0F)))
BEGIN END {}
ELSE IF < THEN; else if (_status_lt(_cc_temp))
;
IF (r64 > 2.20L0) THEN if (_status_gt(_cc_temp =
_determine_cc(
r64,(real_64)2.20E+0)))
BEGIN END {}
ELSE IF < THEN; else if (_status_lt(_cc_temp))
;
END; }
The following example checks the outcome of a procedure.
pTAL Code Generated C++ Code
PROC FRED RETURNSCC; extern "C" _cc_status RETCC()
BEGIN {
RETURN ,1; return 1;
END; }
PROC Q; extern "C" void Q()
BEGIN {
int_32 _cc_temp;
FRED; _cc_temp = FRED();
IF > THEN; if (_status_lt(_cc_temp))
;
END; }
Note
This model of checking condition codes differs from the normal way of
checking condition codes in C++. See the C/C++ Programmer''s Guide for
more information about how to check condition codes in C++.
Returning Both a Value and a Condition Code
The pTAL language allows a function to return a value and also to set
condition codes. The pTAL to C++ Translator generates code to package
a return value and a condition code for function return, then separate
the two values after they are returned.
The code generated by the pTAL to C++ Translator does interoperate with
pTAL language code. A pTAL-coded function that returns a value and has
the RETURNSCC attribute can be called from a routine that has been
generated by the pTAL to C++ Translator, and vice versa, because the
format of the return result is identical.
The following example illustrates the code that the pTAL to C++ Translator
generates.
pTAL Code Generated C++ Code
PROC fred (x), RETURNSCC; extern "C" _cc_status FRED(
INT(16) x; int_16 x)
BEGIN {
RETURN ,0; return 0;
END; }
INT(16) PROC barney (x), extern "C" _int_16_CC BARNEY(
RETURNSCC; int_16 x)
INT(16) x; {
BEGIN _return_2(x*2,1);
RETURN x*2,1; }
END;
... ...
CALL fred(2); _cc_temp = FRED(2);
IF < THEN if (_status_lt(_cc_temp))
... ...
temp := barney(3); temp = _split_int_16_CC(
BARNEY(3),_cc_temp);
IF < THEN if (_status_lt(_cc_temp))
... ...
#endif
//-------------------------------------------------------------------------
// condition codes
#define _cc_status int
#define _status_lt(x) ((x) < 0)
#define _status_gt(x) ((x) > 0)
#define _status_eq(x) ((x) == 0)
#define _status_le(x) ((x) <= 0)
#define _status_ge(x) ((x) >= 0)
#define _status_ne(x) ((x) != 0)
//-------------------------------------------------------------------------
#if 0
Determining a Condition Code Value
The outcome of an assignment expression whose operand type is a 16-bit
integer or a 32-bit integer can be checked by using the value of the
expression as a condition code value. The outcome of a conditional
operation of any operand type or of an assignment expression with
another type requires that an integer condition code value be obtained
from the assignment expression or from the operands of the conditional
operation.
_determine_cc
The _determine_cc functions determine a condition code value from a pair of
values.
int _determine_cc(type first_operand,
type second_operand)
type
is a scalar type, such as: unsigned_char, int_16, int_32, int_64,
unsigned_16, unsigned_32, real_32, real_64.
first_operand
is the first operand.
second_operand
is the second operand.
Usage Considerations
The first_operand is the first operand of a conditional operation whose
result is to be checked via a condition code, or is an assignment
expression whose value''s relationship to zero is to be checked via a
condition code.
The second_operand is the second operand of a conditional operation
whose result is to be checked via a condition code, or is the value
zero which is to be checked against the value of an assignment
expression via a condition code.
#endif
//-------------------------------------------------------------------------
template<class T1, class T2> _resident inline int_32 _determine_cc(T1 x,T2 y) {
return ((int_32)((x) > (y)) - (int_32)((x) < (y)));
}
//----------------------------------------------------------------------------
// Implement Ptal RETURNSCC:
//----------------------------------------------------------------------------
#ifdef NA_64BIT
// dg64 - define structure to return value and cc
struct _val_cc_combo {
int_ptr _value;
int_32 _cc;
};
typedef _val_cc_combo _unsigned_char_CC;
typedef _val_cc_combo _int_16_CC;
typedef _val_cc_combo _int_32_CC;
typedef _val_cc_combo _real_32_CC;
typedef _val_cc_combo _unsigned_char_CC;
typedef _val_cc_combo _baddr_CC;
typedef _val_cc_combo _waddr_CC;
typedef _val_cc_combo _extaddr_CC;
typedef _val_cc_combo _procaddr_CC;
typedef _val_cc_combo _cbaddr_CC;
typedef _val_cc_combo _cwaddr_CC;
typedef _val_cc_combo _int_64_CC;
#else
typedef int_64 _unsigned_char_CC;
typedef int_64 _int_16_CC;
typedef int_64 _int_32_CC;
typedef int_64 _real_32_CC;
typedef int_64 _unsigned_char_CC;
typedef int_64 _baddr_CC;
typedef int_64 _waddr_CC;
typedef int_64 _extaddr_CC;
typedef int_64 _procaddr_CC;
typedef int_64 _cbaddr_CC;
typedef int_64 _cwaddr_CC;
struct _val_cc_combo {
union {
_int_32_CC _combo_item;
struct {
int_32 _value;
int_32 _cc;
} _parts;
};
};
#endif
//-------------------------------------------------------------------------
#if 0
_return_2
The _return_2 macro packages up a value and a condition code and returns
it from a function whose pTAL-coded counterpart returned both a value and
a condition code. The type of the value returned is one of those described
below.
_return_2(val, cc_value)
val
is a value to be returned by the function.
cc_value
is the condition code value to be returned by the function.
Usage Considerations
The type of val is an unsigned_char, an int_16, an int_32, a real_32,
a baddr, a waddr, an extaddr, a procaddr, a cbaddr, or a cwaddr.
cc_value can be decoded using the _status_gt, _status_lt, _status_eq,
_status_ge, _status_le, _status_ne macros.
#endif
//-------------------------------------------------------------------------
#ifdef NA_64BIT
// dg64 - fill in combo and return it
#define _return_2(val,cc) \
_begin \
_val_cc_combo _set_cc_combo; \
_set_cc_combo._cc = cc; \
_set_cc_combo._value = (int_ptr) val; \
return _set_cc_combo; \
_end
#else
#define _return_2(val,cc) \
_begin \
_val_cc_combo _set_cc_combo; \
_set_cc_combo._parts._cc = cc; \
_set_cc_combo._parts._value = (int_32) val; \
return _set_cc_combo._combo_item; \
_end
#endif
#ifdef NA_64BIT
// dg64 - set cc and return value
#define _create_split_val_cc(type, name) \
inline type name (_##type##_CC _vcc, int_32 &_cc) { \
_cc = _vcc._cc; \
return (type) _vcc._value; \
}
#else
#define _create_split_val_cc(type, name) \
inline type name (_##type##_CC _vcc, int_32 &_cc) { \
_val_cc_combo _combine_em; \
_combine_em._combo_item = _vcc; \
_cc = (int_16) _combine_em._parts._cc; \
return (type) _combine_em._parts._value; \
}
#endif
//-------------------------------------------------------------------------
#if 0
_split_int_16_CC, et. al.
The _split_int_16_CC function separates a return value from a condition
code. A combined return value and condition code is returned by a C++
function generated by the pTAL to C++ Translator whose pTAL counterpart
returned a value and implicitly set a condition code. Similar functions
exist for all types that can be returned from a pTAL function that sets
condition codes. The functions _split_sgbaddr_CC, _split_sgwaddr_CC,
_split_sgxbaddr_CC, and _split_sgxwaddr_CC are defined in the rossg.h
include file; all others are defined in the rosgen.h include file.
unsigned_char _split_unsigned_char_CC(_unsigned_char_CC value_and_cc,
int_32 &cc_value)
int_16 _split_int_16_CC(_int_16_CC value_and_cc,
int_32 &cc_value)
int_32 _split_int_32_CC(_int_32_CC value_and_cc,
int_32 &cc_value)
real_32 _split_real_32_CC(_real_32_CC value_and_cc,
int_32 &cc_value)
baddr _split_baddr_CC(_baddr_CC value_and_cc,
int_32 &cc_value)
waddr _split_waddr_CC(_waddr_CC value_and_cc,
int_32 &cc_value)
extaddr _split_extaddr_CC(_extaddr_CC value_and_cc,
int_32 &cc_value)
procaddr _split_procaddr_CC(_procaddr_CC value_and_cc,
int_32 &cc_value)
cbaddr _split_cbaddr_CC(_cbaddr_CC value_and_cc,
int_32 &cc_value)
cwaddr _split_cwaddr_CC(_cwaddr_CC value_and_cc,
int_32 &cc_value)
sgbaddr _split_sgbaddr_CC(_sgbaddr_CC value_and_cc,
int_32 &cc_value)
sgwaddr _split_sgwaddr_CC(_sgwaddr_CC value_and_cc,
int_32 &cc_value)
sgxbaddr _split_sgxbaddr_CC(_sgxbaddr_CC value_and_cc,
int_32 &cc_value)
sgxwaddr _split_sgxwaddr_CC(_sgxwaddr_CC value_and_cc,
int_32 &cc_value)
value_and_cc
is a combined value and condition code.
cc_value
is the condition code value separated from the value.
Usage Considerations
The functions return the value separated from the condition code.
#endif
//-------------------------------------------------------------------------
_create_split_val_cc(unsigned_char, _split_unsigned_char_CC)
_create_split_val_cc(int_16, _split_int_16_CC )
_create_split_val_cc(int_32, _split_int_32_CC )
_create_split_val_cc(real_32, _split_real_32_CC )
_create_split_val_cc(baddr, _split_baddr_CC )
_create_split_val_cc(waddr, _split_waddr_CC )
_create_split_val_cc(extaddr, _split_extaddr_CC )
_create_split_val_cc(procaddr, _split_procaddr_CC )
_create_split_val_cc(cbaddr, _split_cbaddr_CC )
_create_split_val_cc(cwaddr, _split_cwaddr_CC )
#ifdef NA_64BIT
// dg64 - return 64-bit
_create_split_val_cc(int_64, _split_int_64_CC )
#endif
#if 0 // Replace overloaded _determine_cc's with the template above.
//-------------------------------------------------------------------------
// These routines compare the input parameters and return
// the following results:
//
// if | then return
// ----------------------------+------------
// x > y (signed) | 1
// x < y (signed) | -1
// x > y (unsigned) | 1
// x < y (unsigned) | -1
// x = y (signed or unsigned) | 0
inline int_32 _determine_cc (unsigned_char x, unsigned_char y) {
return ((int_32)((x) > (y)) - (int_32)((x) < (y)));
} // _determine_cc
inline int_32 _determine_cc (int_16 x, int_16 y) {
return ((int_32)((x) > (y)) - (int_32)((x) < (y)));
} // _determine_cc
inline int_32 _determine_cc (unsigned_char x, int_16 y) {
return ((int_32)((x) > (y)) - (int_32)((x) < (y)));
} // _determine_cc
inline int_32 _determine_cc (int_16 x, unsigned_char y) {
return ((int_32)((x) > (y)) - (int_32)((x) < (y)));
} // _determine_cc
inline int_32 _determine_cc (unsigned_16 x, unsigned_16 y) {
return ((int_32)((x) > (y)) - (int_32)((x) < (y)));
} // _determine_cc
inline int_32 _determine_cc (unsigned_32 x, unsigned_32 y) {
return ((int_32)((x) > (y)) - (int_32)((x) < (y)));
} // _determine_cc
inline int_32 _determine_cc (int_32 x, int_32 y) {
return ((int_32)((x) > (y)) - (int_32)((x) < (y)));
} // _determine_cc
inline int_32 _determine_cc (real_32 x, real_32 y) {
return ((int_32)((x) > (y)) - (int_32)((x) < (y)));
} // _determine_cc
#endif
//-------------------------------------------------------------------------
#if 0
_abs
The _abs macro returns the absolute value of its argument.
int_16 _abs(int_16 expr)
int_32 _abs(int_32 expr)
int_64 _abs(int_64 expr)
real_32 _abs(real_32 expr)
real_64 _abs(real_64 expr)
expr
is an integer or real type expression.
Usage Considerations
The _abs macro returns the numerical value of expr without regard to its sign.
The absolute value of the most negative integer cannot be represented.
The result of the _abs macro has the same type as expr.
The _abs function is equivalent to the pTAL $ABS standard function
Unlike the C++ library function abs, the _abs macro can take a real number as an
argument.
The following example illustrates a use of the _abs function with an integer
expression and a use with a real expression.
pTAL Code Generated C++ Code
INT(32) x := -2; int_32 x = -2;
REAL(32) r := 2.20E0; real_32 r = 2.20E+0F;
x := $ABS(x); x = _abs((int_32)x);
r := $ABS(r); r = _abs((real_32)r);
#endif
//-------------------------------------------------------------------------
#undef _abs
#define _abs(x) ((x) < 0 ? -(x) : (x))
//-------------------------------------------------------------------------
#if 0
_alpha
The _alpha function returns the value -1 (TRUE) if the low-order 8 bits of
its argument contain the ASCII representation of an alphabetic character,
and returns the value 0 (FALSE) if not.
int_16 _alpha(int_16 expr)
expr
is an expression whose low-order byte might represent the ASCII encoding of an
alphabetic character.
Usage Considerations
The _alpha function is equivalent to the pTAL $ALPHA standard function,
except that it cannot be used in a static context, such as an array bounds
specification, an enumeration constant, a bit field width specifier, or a
case label constant.
Unlike the C++ standard function isalpha, the _alpha function ignores the
high-order 8 bits of expr.
The following example illustrates a use of the _alpha function with a 16-bit
integer argument, and a use with a char type argument that is automatically
promoted by the C++ compiler to a 16-bit integer.
pTAL Code Generated C++ Code
INT(16) result; int_16 result;
INT(16) int_val; int_16 int_val;
STRING c_val; char c_val;
int_val := "a"; int_val = 'a';
c_val := "Q"; c_val = 'Q';
IF $ALPHA(int_val) THEN ... if (_alpha(int_val)) ...
IF $ALPHA(c_val) THEN ... if (_alpha(c_val)) ...
#endif
//-------------------------------------------------------------------------
_resident inline int_16 _alpha (int_16 i) {
#if ROSETTA_BIG_ENDIAN
return -((int_16)((((unsigned)(i & 0xFF) - (unsigned)'A') <= 25u) |
(((unsigned)(i & 0xFF) - (unsigned)'a') <= 25u)));
#else
return -((int_16)((((unsigned)(i % 0x100) - (unsigned)'A') <= 25u) |
(((unsigned)(i % 0x100) - (unsigned)'a') <= 25u)));
#endif
} // _alpha
//-------------------------------------------------------------------------
#if 0
_exchange
The _exchange function exchanges the contents of the two variables given as
parameters.
void _exchange(type *var1,
type *var2)
type
is scalar type, such as: unsigned_char, int_16, int_32, int_64, unsigned_16,
unsigned_32, real_32, real_64, void *.
var1
is a pointer to a variable.
var2
is a pointer to a variable of the same type as var1.
Usage Considerations
var1 gets the value of var2 and var2 gets the value of var1.
Indexing and field selection are allowed in var1 and var2, but the
expression must be a nonstruct lvalue.
The _exchange function is equivalent to the pTAL $EXCHANGE standard
function, except that it cannot be used in a static context, such as
an array bounds specification, an enumeration constant, a bit field
width specifier, or a case label constant.
The following example illustrates the use of the _exchange function on
variables of type int_16 and on variables of type real_32.
pTAL Code Generated C++ Code
INT(16) a, b; int_16 a,b;
REAL(32) c, d; real_32 c,d;
$EXCHANGE(a,b); _exchange(&a,&b);
$EXCHANGE(c,d); _exchange(&c,&d);
#endif
//-------------------------------------------------------------------------
template<class T1, class T2> _resident inline void _exchange (T1 *p1, T2 *p2) {
T1 temp;
temp = (T1)*p1;
*p1 = (T1)*p2;
*p2 = (T2)temp;
}
#if 0 // the following overloaded _exchange's are replaced by the
// template above.
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
//pTAL no longer allows STRING arguments, so Rosetta should not generate char
//type arguments to _exchange (ditto for all types except int_16 and int_32)
inline void _exchange(unsigned_char *s1,
unsigned_char *s2) {
unsigned_char temp;
temp = *s1;
*s1 = *s2;
*s2 = temp;
}
inline void _exchange(int_16 *s1,
int_16 *s2) {
int_16 temp;
temp = *s1;
*s1 = *s2;
*s2 = temp;
}
inline void _exchange(int_32 *s1,
int_32 *s2) {
int_32 temp;
temp = *s1;
*s1 = *s2;
*s2 = temp;
}
inline void _exchange(unsigned_16 *s1,
unsigned_16 *s2) {
unsigned_16 temp;
temp = *s1;
*s1 = *s2;
*s2 = temp;
}
inline void _exchange(unsigned_32 *s1,
unsigned_32 *s2) {
unsigned_32 temp;
temp = *s1;
*s1 = *s2;
*s2 = temp;
}
inline void _exchange(real_32 *s1,
real_32 *s2) {
real_32 temp;
temp = *s1;
*s1 = *s2;
*s2 = temp;
}
inline void _exchange(real_64 *s1,
real_64 *s2) {
real_64 temp;
temp = *s1;
*s1 = *s2;
*s2 = temp;
}
inline void _exchange(void **s1,
void **s2) {
void *temp;
temp = *s1;
*s1 = *s2;
*s2 = temp;
}
#endif
//-------------------------------------------------------------------------
#if 0
_dbl
The _dbl macro creates an int_32 type value by placing the first int_16 type
argument in the high-order 16 bits and the second int_16 type argument in
the low-order 16 bits.
int_32 _dbl(int_16 expr1,
int_16 expr2)
expr1
is an expression.
expr2
is an expression.
Usage Considerations
The _dbl macro creates a value of type int_32 by placing expr1 in the
high-order 16 bits and expr2 in the low-order 16 bits.
The _dbl macro is equivalent to the pTAL $DBLL standard function.
The following example places the value 1 in the high-order 16 bits of the
variable result and places the value 125 in the low-order 16 bits of the
variable result.
pTAL Code Generated C++ Code
INT(32) result; int_32 result;
INT(16) a := 1; int_16 a = 1;
INT(16) b := 125; int_16 b = 125;
result := $DBLL(a,b); result = _dbl(a,b);
#endif
//-------------------------------------------------------------------------
// implements pTAL builtin $DBLL and $UDBL
#if ROSETTA_BIG_ENDIAN
#define _dbl(a,b) (((a) << 16) + (((int_32)(b)) & 0xffff))
#else
#define _dbl(a,b) (((b) << 16) + (((int_32)(a)) & 0xffff))
#endif
#ifdef NA_64BIT
// dg64 - make 64-bit dbl from 2 32-bit numbers
#define _xdbl(a,b) (((unsigned_64)(a) << 32) + (((unsigned_64)(b)) & 0xffffffff))
#else
#define _xdbl(a,b) (((unsigned_32)(a) << 16) + (((unsigned_32)(b)) & 0xffff))
#endif
//-------------------------------------------------------------------------
#if 0
_high
The _high macro returns the 16-bit value that occupies the high-order
16 bits of the 32-bit argument.
int_16 _high(int_32 expr)
expr
is an expression.
Usage Considerations
The _high macro returns the 16-bit value that occupies the high-order
16 bits of expr.
The _high macro ignores the low-order 16 bits of expr.
The _high macro is equivalent to the pTAL $HIGH standard function.
In the following example, the variable result gets the value 1, which is
the value that occupies the high-order 16 bits of the variable a.
pTAL Code Generated C++ Code
INT(16) result; int_16 result;
INT(32) a := %H1FFFF%D; int_32 a = 0x1FFFF;
result := $HIGH(a); result = _high(a);
#endif
//-------------------------------------------------------------------------
#if ROSETTA_BIG_ENDIAN
#define _high(a) ((int_16)((int_32)(a) >> 16))
#else
#define _high(a) ((int_16)((int_32)(a) / (unsigned_32)0x10000))
#endif
#ifdef NA_64BIT
#define _xhigh(a) ((int_32)((int_64)(a) >> 32))
#else
#define _xhigh(a) ((int_16)((int_32)(a) >> 16))
#endif
//-------------------------------------------------------------------------
#if 0
_int_ov
The _int_ov function returns the 16-bit value that occupies the low-order
16 bits of the 32-bit argument, setting the overflow indicator as necessary.
int_16 _int_ov(int_32 expr,
int_16 *ov_temp)
expr
is an expression.
ov_temp
is a reference paramter returning the overflow status.
Usage Considerations
The _int_ov function returns the 16-bit value that occupies the low-order
16 bits of expr.
The _int_ov function ignores the high-order 16 bits of expr.
The ov_temp reference parameter returns a nonzero value if the expr is
greater than 32767 or less than -32768.
The _int_ov function is equivalent to the pTAL $INT_OV standard function.
In the following example, the variable result gets the value 0xFFF0 which
is the value that occupies the low-order 16 bits of the variable a.
pTAL Code Generated C++ Code
?NOOVERFLOW_TRAPS #pragma nooverflow_traps
int_16 _ov_temp;
INT(16) result; int_16 result;
INT(32) a := %H1FFF0%D; int_32 a = 0x1FFF0;
result := $INT_OV(a); result = _int_ov(a,&_ov_temp);
IF $OVERFLOW THEN if (_ov_temp)
#endif
//-------------------------------------------------------------------------
#define _int_ov(i,ov) ((*(ov) = (_low (i) != (i))), _low (i))
//-------------------------------------------------------------------------
#if 0
_len
The _len macro returns the storage size of the argument, in bytes.
int_16 _len(expr)
int_16 _len(type_name)
expr
is an expression.
type_name
is the name of a type.
Usage Considerations
The size is determined from the declarations of the variables in the
expression expr or, if applied to a type_name, the result is the size
in bytes of a variable of the indicated type.
The storage size of an aggregate type is the total number of bytes in
the aggregate, including any filler bytes required for alignment purposes.
The _len macro is equivalent to the pTAL $LEN standard function except:
- The _len macro counts implicit filler bytes.
- The _len macro always returns a nonzero value, even for structures that
contain no space-allocating items. The pTAL to C++ Translator translates
an invocation of the $LEN standard funtion operating on a structure that
contains no space-allocating items to a reference to a constant representing
the correct size.
- For array variables, the _len macro returns the size of the entire array,
not the size of one element which $LEN returns. The pTAL to C++ Translator
translates an array argument found in a $LEN standard function call to a
single element argument in a _len macro invocation.
This macro differs from the operator sizeof in that it returns a signed
16-bit integer type value, while sizeof returns a size_t type value.
The following example illustrates the translation of the pTAL $LEN standard
function.
pTAL Code Generated C++ Code
STRUCT s(*); struct s {
BEGIN int_16 i;
INT(16) i; };
END;
INT(16) val; int_16 val;
STRUCT t(*); struct t {
BEGIN //*** If you add any data to
END; //*** this struct, change this
//*** literal to reflect the
//*** new size of the struct.
enum {_size = 0;};
};
INT(16) a[0:9]; int_16 a[10];
INT(16) result; int_16 result;
result := $LEN(s); result = _len(s);
result := $LEN(val); result = _len(val);
result := $LEN(t); result = t::_size;
result := $LEN(a); result = _len(*a);
#endif
//-------------------------------------------------------------------------
// sizeof returns an unsigned value; _len casts it to signed
#define _len(x) ((int)sizeof(x))
//-------------------------------------------------------------------------
#if 0
_lmax
The _lmax macro returns the greater of its arguments, comparing two unsigned
values.
int_16 _lmax(expr1,
expr2)
expr1
is a 16-bit integer expression.
expr2
is a 16-bit integer expression.
Usage Considerations
The _lmax macro evaluates to the greater of its arguments after the types
of those arguments have been cast to an unsigned_16 type. Its resultant
type is int_16.
The _lmax macro evaluates the greater argument more than once, so you should
avoid providing arguments with side-effects.
The _lmax macro is equivalent to the pTAL $LMAX standard function.
In the following example, the value of the second argument to _lmax is
greater than the value of the first argument, so the value of the second
argument, -2, is stored in the variable result.
pTAL Code Generated C++ Code
INT(16) k := 65534; int_16 k = -2;
INT(16) result; int_16 result;
result := $LMAX(13,k); result = _lmax(13,k);
#endif
//-------------------------------------------------------------------------
#define _lmax(a,b) (int_16)_max((unsigned_16)(a),(unsigned_16)(b))
//-------------------------------------------------------------------------
#if 0
_lmin
The _lmin macro returns the lesser of its arguments, comparing two unsigned
values.
int_16 _lmin(expr1,
expr2)
expr1
is a 16-bit integer expression.
expr2
is a 16-bit integer expression.
Usage Considerations
The _lmin macro evaluates to the lesser of its arguments after the types
of those arguments have been cast to an unsigned_16 type. Its resultant
type is int_16.
The _lmin macro evaluates the lesser argument more than once, so you should
avoid providing arguments with side-effects.
The _lmin macro is equivalent to the pTAL $LMIN standard function.
In the following example, the value of the second argument to _lmin is
lesser than the value of the first argument, so the value of the second
argument, 21, is stored in the variable result.
pTAL Code Generated C++ Code
INT(16) k := 21; int_16 k = 21;
INT(16) result; int_16 result;
result := $LMIN(65534,k); result = _lmin(-2,k);
#endif
//-------------------------------------------------------------------------
#define _lmin(a,b) (int_16)_min((unsigned_16)(a),(unsigned_16)(b))
//-------------------------------------------------------------------------
#if 0
_low
The _low function returns the 16-bit value that occupies the low-order
16 bits of the 32-bit argument.
int_16 _low(int_32 expr)
expr
is an expression.
Usage Considerations
The _low function returns the 16-bit value that occupies the low-order
16 bits of expr.
The _low function ignores the high-order 16 bits of expr.
The _low function is equivalent to the pTAL $INT standard function.
In the following example, the variable result gets the value 0xFFF0 which
is the value that occupies the low-order 16 bits of the variable a.
pTAL Code Generated C++ Code
INT(16) result; int_16 result;
INT(32) a := %H1FFF0%D; int_32 a = 0x1FFF0;
result := $INTR(a); result = _low(a);
#endif
//-------------------------------------------------------------------------
#define _low(x) ((int_16)((int_32)(x)))
#ifdef NA_64BIT
#define _xlow(x) ((int_32)((int_64)(x)))
#else
#define _xlow(x) ((int_16)((int_32)(x)))
#endif
//-------------------------------------------------------------------------
#if 0
_lowbyte
The _lowbyte macro returns the 8 bit value that occupies the low-order
byte of the argument.
int_16 _lowbyte(int expr)
expr
is a 16-bit or 32-bit integer expression.
Usage Considerations
The _lowbyte macro returns the value that occupies the low-order byte of expr.
The _lowbyte macro ignores the higher-order bits of expr.
In the following example, the variable result gets the value 0xF0 which
is the value that occupies the low-order byte of the variable a.
pTAL Code Generated C++ Code
STRING a[0:3] unsigned_char a[4]
:= ["a","b",34,12D]; = {'a','b',_lowbyte(34),
_lowbyte(12)};
#endif
//-------------------------------------------------------------------------
#if ROSETTA_BIG_ENDIAN
#define _lowbyte(p) ((unsigned_char)(((int)p) & 0xff))
#else
#define _lowbyte(p) ((unsigned_char)(((int)p) % 0x100))
#endif
//-------------------------------------------------------------------------
#if 0
_max
The _max macro returns the greater of its arguments.
_max(expr1,
expr2)
expr1
is an expression of a type for which the greater than operator ( > ) is defined.
expr2
is an expression of a type compatible with expr1.
Usage Considerations
The _max macro evaluates to the lesser of its arguments. Its resultant
type is the type of that argument.
The _max macro is equivalent to the pTAL $MAX standard function, except that
it evaluates the lesser argument more than once, so you should avoid providing
arguments with side-effects.
In the following example, the value of the second argument to _max is
greater than the value of the first argument, so the value of the second
argument, 21, is stored in the variable result.
pTAL Code Generated C++ Code
INT(16) k := 21; int_16 k = 21;
INT(16) result; int_16 result;
result := $MAX(13,k); result = _max(13,k);
_min
The _min macro returns the lesser of its arguments.
_min(expr1,
expr2)
expr1
is an expression of a type for which the less than operator ( < ) is defined.
expr2
is an expression of a type compatible with expr1.
Usage Considerations
The _min macro evaluates to the lesser of its arguments. Its resultant
type is the type of that argument.
The _min macro is equivalent to the pTAL $MIN standard function, except that
it evaluates the lesser argument more than once, so you should avoid providing
arguments with side-effects.
In the following example, the value of the first argument to _min is less
than the value of the second argument, so the value of the first argument,
13, is stored in the variable result.
pTAL Code Generated C++ Code
INT(16) k := 21; int_16 k = 21;
INT(16) result; int_16 result;
result := $MIN(13,k); result = _min(13,k);
#endif
//-------------------------------------------------------------------------
#ifdef _min
#undef _min
#endif
#ifdef _max
#undef _max
#endif
#define _min(a,b) (((a) < (b)) ? (a) : (b))
#define _max(a,b) (((a) > (b)) ? (a) : (b))
//-------------------------------------------------------------------------
#if 0
_numeric
The _numeric function returns the value -1 (TRUE) if the low-order 8 bits
of its argument contain the ASCII representation of a numeric character,
and returns the value 0 (FALSE) if not.
int_16 _numeric(int_16 expr)
expr
is an expression whose low-order byte might represent the ASCII encoding of a
numeric character.
Usage Considerations
The _numeric function is equivalent to the pTAL $NUMERIC standard function,
except that it cannot be used in a static context, such as an array bounds
specification, an enumeration constant, a bit field width specifier, or a
case label constant.
Unlike the C++ standard function isdigit, the _numeric function ignores the
high-order 8 bits of expr.
The following example illustrates a use of the _numeric macro with a 16-bit
integer argument, and a use with a char type argument that is automatically
promoted by the C++ compiler to a 16-bit integer.
pTAL Code Generated C++ Code
INT(16) result; int_16 result;
INT(16) int_val; int_16 int_val;
STRING c_val; char c_val;
int_val := "2"; int_val = '2';
c_val := "5"; c_val = '5';
IF $NUMERIC(int_val) THEN if (_numeric(int_val)) ...
IF $NUMERIC(c_val) THEN if (_numeric(c_val)) ...
#endif
//-------------------------------------------------------------------------
_resident inline int_16 _numeric (int_16 i) {
#if ROSETTA_BIG_ENDIAN
return -((int_16)(((unsigned)(i & 0xFF) - (unsigned)'0') <= 9u));
#else
return -((int_16)(((unsigned)(i % 0x100) - (unsigned)'0') <= 9u));
#endif
} // _numeric
//-------------------------------------------------------------------------
#if 0
_num_elems_varname
The _num_elems_variable_name enumeration evaluates to the number of
elements in the array variable.
_num_elems_variable_name
variable_name
is the name of an array variable defined by the macros listed below.
Usage Considerations
The _num_elems_variable_name enumeration is defined by the following macros,
all supplied in the rosgen.h include file, which expand to the definition of
an array.
- _equiv_array
- _equiv_array_global
- _equiv_array_offset
- _equiv_array_offset_global
- _const_array
- _const_char_array
- _initialized_array
- _initialized_char_array
The pTAL to C++ Translator generates the _num_elems_variable_name
enumeration as the translation of the pTAL $OCCURS standard function when
that function operates on an array variable defined with one of the macros
listed above.
pTAL Code Generated C++ Code
STRING hello[1:10] _initialized_char_array(
:= ["hello"]; unsigned_char,hello,1,10,
"hello");
STRING bye[0:9] := ["bye"]; unsigned_char bye[10] = {"bye"};
INT(16) x; int_16 x;
x := $OCCURS(hello); x = _num_elems_hello;
x := $OCCURS(bye); x = _occurs(bye);
For More Information. See the discussion of the _occurs macro for more
information about the translation of the pTAL $OCCURS standard function.
_occurs
The _occurs macro returns the number of elements in the variable provided as
a parameter.
size_t _occurs(array_variable)
array_variable
is the name of an array variable or structure field.
Usage Considerations
The _occurs macro returns unpredictable results when the array_variable
supplied is not actually an array variable or array structure field.
The _occurs macro is equivalent to the pTAL $OCCURS standard function, except
that it only operates on arrays.
In the following example, the first expansion of the _occurs macro
evaluates to the integer value 4. The second expansion of the _occurs
macro evaluates to the integer value 5.
pTAL Code Generated C++ Code
INT(16) x; int_16 x;
INT(16) a[0:3]; int_16 a[4];
STRUCT spade(*); struct spade {
BEGIN int_16 b[5];
INT(16) b[0:4]; };
END;
STRUCT sam(spade); spade sam;
x := $OCCURS(a); x = _occurs(a);
x := $OCCURS(sam.b); x = _occurs(sam.b);
x := $OCCURS(x); x = 1;
For More Information. See the discussion of the _num_elems_variable_name
macro for more information about the translation of the pTAL $OCCURS
standard function when the argument is an array variable declared with
one of the following macros:
_equiv_array, _equiv_array_global, _equiv_array_offset,
_equiv_array_offset_global, _const_array, _const_char_array,
_initialized_array, and _initialized_char_array.
#endif
//-------------------------------------------------------------------------
#define _occurs(a) ((sizeof (a)) / (sizeof ((a)[0])))
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
// Note: _pow_of_10 is described near fixed point scaling
//-------------------------------------------------------------------------
#if 0
_special
The _special function evaluates to the value -1 (TRUE) if the low-order
8 bits of its argument contain the ASCII representation of a character
that is neither alphabetic nor numeric, and evaluates to the value 0
(FALSE) if the low-order 8 bits of its argument contains the ASCII
representation of an alphabetic or numeric character.
int_16 _special(int_16 expr)
expr
is an expression whose low-order byte might represent the ASCII encoding
of a character.
Usage Considerations
The _special function is equivalent to the pTAL $SPECIAL standard function,
except that it cannot be used in a static context, such as an array bounds
specification, an enumeration constant, a bit field width specifier, or a
case label constant.
The _special function ignores the high-order 8 bits of expr.
The following example illustrates a use of the _special function with a
16-bit integer argument, and a use with a char type argument that is
automatically promoted by the C++ compiler to a 16-bit integer.
pTAL Code Generated C++ Code
INT(16) result; int_16 result;
INT(16) int_val; int_16 int_val;
STRING c_val; char c_val;
int_val := "!"; int_val = '!';
c_val := "@"; c_val = '@';
IF $SPECIAL(int_val) THEN if (_special(int_val)) ...
IF $SPECIAL(c_val) THEN if (_special(c_val)) ...
#endif
//-------------------------------------------------------------------------
_resident inline int_16 _special (int_16 i) {
#if ROSETTA_BIG_ENDIAN
return -((int_16)((((unsigned)(i & 0xFF) - (unsigned)'A') > 25u) &
(((unsigned)(i & 0xFF) - (unsigned)'a') > 25u) &
(((unsigned)(i & 0xFF) - (unsigned)'0') > 9u)));
#else
int_16 temp = i % 0x100;
return -((int_16)((((unsigned)(temp) - (unsigned)'A') > 25u) &
(((unsigned)(temp) - (unsigned)'a') > 25u) &
(((unsigned)(temp) - (unsigned)'0') > 9u)));
#endif
} // _special
//-------------------------------------------------------------------------
#if 0
_udivrem
The _udivrem function calculates a quotient and remainder for an integer
divisor and dividend, checking for overflow.
int_16 _udivrem(int_32 dividend,
int_16 divisor,
int_16 *quotient,
int_16 *remainder)
int_16 _udivrem(int_32 dividend,
int_16 divisor,
int_32 *quotient,
int_16 *remainder)
dividend
is the value to be divided.
divisor
is the value by which dividend is divided.
quotient
is a container for the result obtained by dividing dividend by divisor.
remainder
is a container for the difference between the divisor times the quotient
and the dividend.
Usage Considerations
The _udivrem function returns the value 1 if the divisor is zero. The
version of this function with a 16-bit quotient returns the value 1 if
the quotient cannot fit into a 16-bit container. Otherwise, this function
returns the value 0.
The quotient and remainder are undefined when an overflow is reported.
These functions are equivalent to the pTAL standard functions $UDIVREM16 and
$UDIVREM32.
The following example illustrates a use of each version of the _udivrem
function; one calculating a 16-bit quotient and the other calculating a
32-bit quotient.
pTAL Code Generated C++ Code
?NOOVERFLOW_TRAPS #pragma nooverflow_traps
... ...
INT(32) quotient1; int_32 quotient1;
INT(16) quotient2; int_16 quotient2;
INT(16) remainder; int_16 remainder;
int_16 _ov_temp;
$UDIVREM(100D,10, _udivrem(100,10,&quotient1,
quotient1,remainder); &remainder);
$UDIVREM(100D,10, _ov_temp = _udivrem(100,10,
quotient2,remainder); &quotient2,&remainder);
IF $OVERFLOW THEN ... if (_ov_temp) ...
#endif
//-------------------------------------------------------------------------
//#ifndef __TANDEM It appears _udivrem32 doesn't work in native C++
// This version of _udivrem32x is being used until it does. It is
// only called by the two overloaded _udivrem's that immediately follow.
_resident inline int_16 _udivrem32x(int_32 dividend,
int_16 divisor,
int_32 *quotient,
int_16 *remainder) {
if (divisor == 0)
return 1;
union {
int_32 signed_value;
unsigned_32 unsigned_value;
} quo;
union {
int_16 signed_value;
unsigned_16 unsigned_value;
} rem;
quo.unsigned_value = (unsigned_32)dividend / (unsigned_16)divisor;
*quotient = quo.signed_value;
rem.unsigned_value = (unsigned_32)dividend -
quo.unsigned_value * (unsigned_16)divisor;
*remainder = rem.signed_value;
return 0;
}
//#endif _udivrem32
_resident inline int_16 _udivrem(int_32 dividend,
int_16 divisor,
int_16 *quotient,
int_16 *remainder) {
union {
int_32 int32val;
int_16 int16val[2];
} quo;
int_16 result = _udivrem32x(dividend, divisor, &quo.int32val, remainder);
*quotient = quo.int16val[1];
return result || (quo.int16val[0] != 0);
}
_resident inline int_16 _udivrem(int_32 dividend,
int_16 divisor,
int_32 *quotient,
int_16 *remainder) {
return _udivrem32x(dividend, divisor, quotient, remainder);
}
//-------------------------------------------------------------------------
#if 0
_varify
The _varify macro returns what appears to be a field reference within a
structure variable rather than a field reference within a structure field.
_varify(struct_type_name,
field_name)
struct_type_name
is the name of a structure type.
field_name
is the name of a field within the structure struct_type_name.
Usage Considerations
The _varify macro, after expansion, appears to be a field reference within
a structure variable of type struct_type_name. This macro can be used as
an argument to the sizeof operator. It is not necessary to allocate a
variable of that type to inquire about the size of a field. The _varify
macro causes no space to be allocated.
The pTAL language allows a programmer to use the $LEN standard function to
find the length of a structure field, referring to a structure template
rather than a structure variable. The C++ language requires a field
reference in the sizeof operator to work with a structure variable.
The following example illustrates pTAL code that makes use of the length
of a structure template.
pTAL Code Generated C++ Code
STRUCT s(*); struct s {
BEGIN int_16 i;
INT(16) i; };
END;
STRING stuff unsigned_char STUFF
[0:$LEN(s.i)-1]; [_len(_varify(s,i))];
PROC P; extern C void P() {
BEGIN
... ...
STRUCT sal(s); s sal;
x := $LEN(sal.i); x = _len(sal.i);
... ...
#endif
//-------------------------------------------------------------------------
#define _varify(a,b) (((a *)0)->b)
//-------------------------------------------------------------------------
#if 0
_dblr
The _dblr macro returns an int_32 value converted from a real_32 or
real_64 value, applying rounding to the result.
int_32 _dblr(real_32 expr)
int_32 _dblr(real_64 expr)
expr
is a real type expression to be converted to an int_32 type value.
Usage Considerations
The _dblr macro is equivalent to the pTAL $DBLR standard function.
In the following example, the first assignment statement rounds up the
real value and stores the value 3 in the variable i32. The second
assignment statement rounds down the real value and stores the value 2
in the variable i32.
pTAL Code Generated C++ Code
INT(32) i32; int_32 i32;
REAL(32) r32 := 2.60E00; real_32 r32 = 2.60E+00F;
REAL(64) r64 := 4.20L00; real_64 r64 = 4.20E+00;
i32 := $DBLR(r32); i32 = _dblr(r32);
i32 := $DBLR(r64); i32 = _dblr(r64);
#endif
//-------------------------------------------------------------------------
#define _dblr(x) ((int_32)((x) + ((x) < 0.0 ? -0.5 : 0.5)))
//-------------------------------------------------------------------------
#if 0
_dfix
The _dfix macro returns a fixed-point type expression converted from an
int_32 type expression.
int_64 _dfix(int_32 expr,
int_16 scale_factor)
expr
is an expression to be converted to a fixed-point value.
scale_factor
is the number of decimal points by which to scale the value of the
expression.
Usage Considerations
The _dfix macro is equivalent to the pTAL $DFIX standard function.
In the following example, the value stored in the variable i32 is converted
to a fixed point value with the appropriate scale factor, and is then stored
in a fixed-point variable with the appropriate scale factor.
pTAL Code Generated C++ Code
FIXED(2) f2; fixed_2 f2;
FIXED(3) f3; fixed_3 f3;
INT(32) i32 := 35D; int_32 i32 = 35;
f2 := $DFIX(i32,2); f2 = _dfix(i32,2);
f3 := $DFIX(i32,3); f3 = _dfix(i32,3);
#endif
//-------------------------------------------------------------------------
#define _dfix(expr, scale) ((int_64)(expr))
//-------------------------------------------------------------------------
#if 0
_ifix
The _ifix macro returns a fixed-point type expression converted from an
int_16 type expression.
int_64 _ifix(int_16 expr,
int_16 scale_factor)
expr
is an expression to be converted to a fixed-point value.
scale_factor
is the number of decimal points by which to scale the value of the
expression.
Usage Considerations
The _ifix macro is equivalent to the pTAL $IFIX standard function.
In the following example, the value stored in the variable i16 is converted
to a fixed point value with the appropriate scale factor, and is then stored
in a fixed-point variable with the appropriate scale factor.
pTAL Code Generated C++ Code
FIXED(2) f2; fixed_2 f2;
FIXED(3) f3; fixed_3 f3;
INT(16) i16 := 25; int_16 i16 = 25;
f2 := $IFIX(i16,2); f2 = _ifix(i16,2);
f3 := $IFIX(i16,3); f3 = _ifix(i16,3);
#endif
//-------------------------------------------------------------------------
#define _ifix(expr, scale) ((int_64)(expr))
//-------------------------------------------------------------------------
#if 0
_intr
The _intr macro returns an int_16 value converted from a real_32 or real_64
value, applying rounding to the result.
int_16 _intr(real_32 expr)
int_16 _intr(real_64 expr)
expr
is an expression to be converted to a 16-bit integer.
Usage Considerations
The _intr macro is equivalent to the pTAL $INTR standard function.
In the following example, the first assignment statement rounds up the
real value and stores the value 3 in the variable i16. The second assignment
statement rounds down the real value and stores the value 2 in the variable
i16.
pTAL Code Generated C++ Code
REAL(32) r32 := 2.60E00; real_32 r32 = 2.60E+00F;
REAL(64) r64 := 4.20L00; real_64 r64 = 4.20E+00;
INT(16) i16; int_16 i16;
i16 := $INTR(r32); i16 = _intr(r32);
i16 := $INTR(r64); i16 = _intr(r64);
#endif
//-------------------------------------------------------------------------
#define _intr(x) ((int_16)((x) + ((x) < 0.0 ? -0.5 : 0.5)))
//-------------------------------------------------------------------------
#if 0
#endif
//-------------------------------------------------------------------------
// _int64_to_int16_ov is defined with the overflow trapping routines
// _int64_to_uint16_ov is defined with the overflow trapping routines
// _int64_to_int32_ov is defined with the overflow trapping routines
//-------------------------------------------------------------------------
#if 0
_lfix
The _lfix macro returns a fixed-point type expression converted from an
unsigned_16 type expression.
int_64 _lfix(unsigned_16 expr,
int_16 scale_factor)
expr
is an expression to be converted to a fixed-point value.
scale_factor
is the number of decimal points by which to scale the value of the
expression.
Usage Considerations
The result of the _lfix macro is a fixed-point type expression.
The _lfix macro is equivalent to the pTAL $LFIX standard function.
In the following example, the value stored in the variable i16 is converted
to a fixed point value with the appropriate scale factor, and is then stored
in a fixed-point variable with the appropriate scale factor.
pTAL Code Generated C++ Code
FIXED(2) f2; fixed_2 f2;
FIXED(3) f3; fixed_3 f3;
INT(16) i16 := %h0ff0; int_16 i16 = 0xFF0;
f2 := $LFIX(i16,2) f2 = _lfix(i16,2);
f3 := $LFIX(i16,3); f3 = _lfix(i16,3);
#endif
//-------------------------------------------------------------------------
#if ROSETTA_BIG_ENDIAN
#define _lfix(expr, scale) (((int_64)(expr)) & 0xFFFF)
#else
#define _lfix(expr, scale) ((int_64)((expr) % (unsigned_32)0x10000))
#endif
//-------------------------------------------------------------------------
#if 0
_make_int_16 and _make_int_16_d
The _make_int_16 function combines two character values into one 16-bit
integer value by extracting one or two characters from a string and placing
them in an integer container.
The _make_int_16_d macro combines two character values into one 16-bit
integer container.
unsigned_16 _make_int_16(char *char_string)
int_16 _make_int_16_d(char char_expr1,
char char_expr2)
char_string
is a character string.
char_expr1
is a character expression.
char_expr2
is a character expression.
Usage Considerations
The _make_int_16 function and _make_int_16_d macro place the ASCII
representation of the first character in the high-order byte and the
second in the low-order byte. If the parameter contains only one character,
its ASCII representation is placed in the low-order byte.
The _make_int_16 function ignores all characters past the second in
char_string and ignores the null terminator in char_string.
If char_string contains one character, then this character s ASCII
representation fills the low-order byte of the resultant 16-bit value.
The high-order byte contains the value zero. To obtain zero padding in
the low order byte (which mimicks pTAL-style initialization), use the
function _make_int_16_d which takes individual characters as parameters
rather than a character string.
Because _make_int_16_d is a macro rather than a function, it is appropriate
for use in the definition of an enumeration constant. To create a 16-bit
variable from a character string in other contexts, use the function
_make_int_16.
In the following example, the array b is initialized with four 16-bit
values, two of which are created from character values.
pTAL Code Generated C++ Code
int(16) b[0:3] := int_16 b[4] =
[12,"a","bc",24]; {12, _make_int_16_d('a','\0'),
_make_int_16_d('b','c') ,24};
#endif
//-------------------------------------------------------------------------
// does not pad with nulls: for padding during integer initialization,
// pass individual characters
_resident inline unsigned_16 _make_int_16 (void *str_) {
unsigned_char *str = (unsigned_char *)str_;
unsigned_16 ret_val = 0;
#ifndef _LITTLE_ENDIAN_
int num_chars = 0;
while (*str != '\0' && num_chars < 2) {
ret_val = (ret_val << 8) + (int_16)*str;
str++;
num_chars++;
}
#else
if (*str != '\0') {
unsigned_char a = *str;
str++;
unsigned_char b = *str;
ret_val = (b << 8) + (int_16)a;
}
#endif
return (ret_val);
}
// literal definition requires macro; function call not allowed
#ifndef _LITTLE_ENDIAN_
#define _make_int_16_d(a, b) (((unsigned_16)a << 8) + (unsigned_16)b)
#else
#define _make_int_16_d(a, b) (((unsigned_16)b << 8) + (unsigned_16)a)
#endif
//-------------------------------------------------------------------------
#if 0
_make_int_32 and _make_real_32
The _make_int_32 function combines four character values, passed as
separate parameters, into one 32-bit integer value by placing the ASCII
representation of the first character in the high-order byte, the second
in the next byte, and so on. The version that takes a character string
as a parameter right-justifies the characters ASCII representations within
the 32-bit integer.
The _make_real_32 function behaves exactly the same as the _make_int_32
function, but it casts the type of the resultant value to real_32.
unsigned_32 _make_int_32(char *char_string)
unsigned_32 _make_int_32(char char_expr1,
char char_expr2,
char char_expr3,
char char_expr4)
unsigned_32 _make_int_32(int_16 int_expr1,
int_16 int_expr2)
real_32 _make_real_32(char *char_string)
real_32 _make_real_32(char char_expr1,
char char_expr2,
char char_expr3,
char char_expr4)
char_string
is a character string.
char_exprn
is a character expression.
int_exprn
is a 16-bit integer expression.
Usage Considerations
The _make_int_32 function and the _make_real_32 function ignore all
characters past the fourth in char_string and ignore the null terminator
in char_string.
If char_string contains less than four characters, then the character''s
ASCII representations fill the low-order bytes. The remaining high-order
bytes contain zero values. To obtain zero padding in the low order bytes
(which mimicks pTAL-style initialization), use the function that takes
individual characters as parameters rather than a character string.
In the following example, the arrays are initialized with values from a
constant list; those values can be character strings.
pTAL Code Generated C++ Code
int(32) c[0:3] := int_32 c[4] =
["abcd",35D,36D,2,4]; {_make_int_32('a','b','c','d'),
35, 36, _make_int_32(2,4)};
real(32) d[0:3] := real_32 d[4] =
[1.2E00,"abcd"]; {1.2E+00F,
_make_real_32('a','b','c','d')};
#endif
//-------------------------------------------------------------------------
// does not pad with nulls: for padding during integer initialization,
// pass individual characters
_resident inline unsigned_32 _make_int_32 (void *str_) {
unsigned_char *str = (unsigned_char *)str_;
unsigned_32 ret_val = 0;
#ifndef _LITTLE_ENDIAN_
int num_chars = 0;
while (*str != '\0' && num_chars < 4) {
ret_val = (ret_val << 8) + (int_16)*str;
str++;
num_chars++;
}
#else
int num_chars = 0;
unsigned_char a = *str;
unsigned_char b = '\0';
unsigned_char c = '\0';
unsigned_char d = '\0';
struct {
union {
int_32 i;
struct {
unsigned_char w;
unsigned_char x;
unsigned_char y;
unsigned_char z;
} parts;
};
} s;
s.i = 0;
if (*str != '\0') {
a = *str;
num_chars++;
str++;
}
if (*str != '\0') {
b = *str;
num_chars++;
str++;
}
if (*str != '\0') {
c = *str;
num_chars++;
str++;
}
if (*str != '\0') {
d = *str;
num_chars++;
str++;
}
switch (num_chars) {
case 0: break;
case 1: s.parts.z = a;
break;
case 2: s.parts.y = a;
s.parts.z = b;
break;
case 3: s.parts.x = a;
s.parts.y = b;
s.parts.z = c;
break;
case 4: s.parts.w = a;
s.parts.x = b;
s.parts.y = c;
s.parts.z = d;
break;
}
ret_val = s.i;
#endif
return (ret_val);
}
// literal definition requires macro; function call not allowed
#ifndef _LITTLE_ENDIAN_
#define _make_int_32_d(a, b, c, d) \
(((unsigned_32)a << 24) + \
((unsigned_32)b << 16) + \
((unsigned_32)c << 8) + \
((unsigned_32)d << 0))
#else
#define _make_int_32_d(a, b, c, d) \
(((unsigned_32)d << 24) + \
((unsigned_32)c << 16) + \
((unsigned_32)b << 8) + \
((unsigned_32)a << 0))
#endif
_resident inline real_32 _make_real_32 (void *str_) {
unsigned_char *str = (unsigned_char *)str_;
union {
int_32 i;
real_32 r;
} ret_val;
ret_val.i = 0;
#ifndef _LITTLE_ENDIAN_
int num_chars = 0;
while (*str != '\0' && num_chars < 4) {
ret_val.i = (ret_val.i << 8) + (int_16)*str;
str++;
num_chars++;
}
#else
if (*str != '\0') {
unsigned_char a = *str;
str++;
unsigned_char b = *str;
if (*str != '\0')
str++;
ret_val.i = (b << 8) + (int_16)a;
if (*str != '\0') {
unsigned_char c = *str;
str++;
unsigned_char d = *str;
ret_val.i = (((d << 8) + (int_16)c) << 16) + ret_val.i;
}
}
#endif
return (ret_val.r);
}
_resident inline unsigned_32 _make_int_32 (unsigned_char a, unsigned_char b,
unsigned_char c, unsigned_char d) {
#ifndef _LITTLE_ENDIAN_
return ((((((unsigned_16)a << 8) + (unsigned_16)b) << 8) +
(unsigned_16)c) << 8) + (unsigned_16)d;
#else
return ((((((unsigned_16)d << 8) + (unsigned_16)c) << 8) +
(unsigned_16)b) << 8) + (unsigned_16)a;
#endif
}
_resident inline int_32 _make_int_32 (int_16 a, int_16 b) {
return (int_32)(((unsigned_16)a << 16) + (unsigned_16)b);
}
_resident inline real_32 _make_real_32 (unsigned_char a, unsigned_char b,
unsigned_char c, unsigned_char d) {
union {
int_32 i;
real_32 r;
} ret_val;
#ifndef _LITTLE_ENDIAN_
ret_val.i = ((((((unsigned_16)a << 8) + (unsigned_16)b) << 8) +
(unsigned_16)c) << 8) + (unsigned_16)d;
#else
ret_val.i = ((((((unsigned_16)d << 8) + (unsigned_16)c) << 8) +
(unsigned_16)b) << 8) + (unsigned_16)a;
#endif
return ret_val.r;
}
//-------------------------------------------------------------------------
#if 0
_make_int_64 and _make_real_64
The _make_int_64 function combines eight character values into one 64-bit
integer value by placing the ASCII representation of the first character
in the high-order byte, the second in the next byte, and so on. The
version that takes a character string as a parameter right-justifies the
characters ASCII representations within the 64-bit integer.
The _make_real_64 function behaves exactly the same as the _make_int_64
function, but it casts the type of the resultant value to real_64.
int_64 _make_int_64(char *char_string)
int_64 _make_int_64(char char_expr,
char char_expr,
char char_expr,
char char_expr,
char char_expr,
char char_expr,
char char_expr,
char char_expr)
int_64 _make_int_64(int_32 int_expr1,
int_32 int_expr2)
real_64 _make_real_64(char *char_string)
real_64 _make_real_64(char char_expr,
char char_expr,
char char_expr,
char char_expr,
char char_expr,
char char_expr,
char char_expr,
char char_expr)
char_string
is a character string.
char_expr
is a character constant or variable.
Usage Considerations
The _make_int_64 function and the _make_real_64 function ignore all characters
past the eighth in char_string and ignore the null terminator in char_string.
If char_string contains less than eight characters, then the character''s
ASCII representations fill the low-order bytes. The remaining high-order
bytes contain zero values. To obtain zero padding in the low order bytes
(which mimicks pTAL-style initialization), use the function that takes
individual characters as parameters rather than a character string.
In the following example, the arrays are initialized with values from a
constant list; those values can be character strings.
pTAL Code Generated C++ Code
int(64) e[0:3] := fixed_0 e[4] =
[34D,35D,10F,11F, {_make_int_64(34,35),10LL,11LL,
"abcdefgh"]; _make_int_64('a','b','c','d',
'e','f','g','h')};
real(64) f[0:3] := real_64 f[4] =
["abcdefgh"]; {_make_real_64('a','b','c','d',
'e','f','g','h')};
#endif
//-------------------------------------------------------------------------
// does not pad with nulls: for padding during integer initialization,
// pass individual characters
_resident inline int_64 _make_int_64 (void *str_) {
int_64 ret_val = 0;
#ifndef _LITTLE_ENDIAN_
unsigned_char *str = (unsigned_char *)str_;
int num_chars = 0;
while (*str != '\0' && num_chars < 8) {
ret_val = (ret_val << 8) + (int_16)*str;
str++;
num_chars++;
}
#else
#endif
return (ret_val);
}
_resident inline int_64 _make_int_64 (unsigned_char a, unsigned_char b,
unsigned_char c, unsigned_char d,
unsigned_char e, unsigned_char f,
unsigned_char g, unsigned_char h) {
#ifndef _LITTLE_ENDIAN_
return (((int_64)_make_int_32 (a,b,c,d) << 32) +
(int_64)_make_int_32 (e,f,g,h));
#else
return ((int_64)_make_int_32 (a,b,c,d) +
((int_64)_make_int_32 (e,f,g,h) << 32));
#endif
}
_resident inline int_64 _make_int_64 (int_32 a, int_32 b) {
#ifndef _LITTLE_ENDIAN_
return ((((int_64)(unsigned_32)a) << 32) + ((int_64)(unsigned_32)b));
#else
int_32 parts[2];
int_64 *i64 = (int_64 *)&parts[0];
parts[0] = b;
parts[1] = a;
return *i64;
#endif
}
_resident inline real_64 _make_real_64 (unsigned_char *str) {
union {
int_64 i;
real_64 r;
} ret_val;
ret_val.i = 0;
int num_chars = 0;
while (*str != '\0' && num_chars < 8) {
#ifndef _LITTLE_ENDIAN_
ret_val.i = (ret_val.i << 8) + (int_16)*str;
#else
ret_val.i = (ret_val.i * 0x100) + (int_16)*str;
#endif
str++;
num_chars++;
}
return (ret_val.r);
}
_resident inline real_64 _make_real_64 (unsigned_char a, unsigned_char b,
unsigned_char c, unsigned_char d,
unsigned_char e, unsigned_char f,
unsigned_char g, unsigned_char h) {
union {
int_64 i;
real_64 r;
} ret_val;
#ifndef _LITTLE_ENDIAN_
ret_val.i = (((int_64)_make_int_32 (a,b,c,d) << 32) +
(int_64)_make_int_32 (e,f,g,h));
#else
ret_val.i = ((int_64)_make_int_32 (a,b,c,d) +
((int_64)_make_int_32 (e,f,g,h) << 32));
#endif
return (ret_val.r);
}
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
// _real32_to_int64_ov is defined with the overflow trapping routines
// _real32_to_int64_rnd_ov is defined with the overflow trapping routines
// _real64_to_int64_ov is defined with the overflow trapping routines
// _real64_to_int64_rnd_ov is defined with the overflow trapping routines
//-------------------------------------------------------------------------
#if 0
_split32_in_2 and _split64_in_4
The _split32_in_2 macro converts one 32-bit constant value to two
comma-separated 16-bit constant values. The pTAL to C++ Translator
generates it to emulate pTAL constant lists that contained 32-bit
constants intended to fill two cells in its associated array of 16-bit
values.
The _split64_in_4 macro converts one 64-bit constant value to four
comma-separated int_16 constant values. The pTAL to C++ Translator
generates it to emulate pTAL constant lists that contained 64-bit constants
intended to fill four cells in its associated array of int_16 values.
_split32_in_2(32_bit_constant)
_split64_in_4(64_bit_constant)
_split64_in_2(64_bit_constant)
32_bit_constant
is a 32-bit constant.
64_bit_constant
is a 64-bit constant.
Usage Considerations
In the following example, the constant 35D is intended to fill two cells
in the array g. Likewise, the constant 35F is intended to fill four cells
in the array i, and the constant 35F is intended to fill two cells in the
array h.
pTAL Code Generated C++ Code
int(16) g[0:3] := int_16 g[4] =
[35D,10,11]; {_split32_in_2(35),10,11};
int(16) i[0:3] := int_16 i[4] =
[35F]; {_split64_in_4(35LL)};
int(32) h[0:3] := int_32 h[4] =
[35F,20D,21D]; {_split64_in_2(35LL),20,21};
#endif
//-------------------------------------------------------------------------
// convert 32-bit and 64-bit values to 8-bit and 16-bit values in
// constant lists
#if ROSETTA_BIG_ENDIAN
#define _split32_in_2(x) \
(int_16)(((x) & 0xffff0000) >> 16) _comma \
(int_16)((x) & 0x0000ffff)
#else
#define _split32_in_2(x) \
(int_16)((x) / (unsigned_32)0x00010000) _comma \
(int_16)((x) % (unsigned_32)0x00010000)
#endif
#if USE_LL
#define _split64_in_2(x) \
(int_32)(((x) & 0xffffffff00000000LL) >> 32) _comma \
(int_32)((x) & 0xffffffffLL)
#else
#if USE_L
#define _split64_in_2(x) \
(int_32)(((x) & 0xffffffff00000000L) >> 32) _comma \
(int_32)((x) & 0xffffffffL)
#else
#define _split64_in_2(x) \
(int_32)(((x) & 0xffffffff00000000) >> 32) _comma \
(int_32)((x) & 0xffffffff)
#endif
#endif /* USE_LL */
#if USE_LL
#define _split64_in_4(x) \
(int_16)(((x) & 0xffff000000000000LL) >> 48) _comma \
(int_16)(((x) & 0x0000ffff00000000LL) >> 32) _comma \
(int_16)(((x) & 0x00000000ffff0000LL) >> 16) _comma \
(int_16)((x) & 0x000000000000ffffLL)
#else
#if USE_L
#define _split64_in_4(x) \
(int_16)(((x) & 0xffff000000000000L) >> 48) _comma \
(int_16)(((x) & 0x0000ffff00000000L) >> 32) _comma \
(int_16)(((x) & 0x00000000ffff0000L) >> 16) _comma \
(int_16)((x) & 0x000000000000ffffL)
#else
#define _split64_in_4(x) \
(int_16)(((x) & 0xffff000000000000) >> 48) _comma \
(int_16)(((x) & 0x0000ffff00000000) >> 32) _comma \
(int_16)(((x) & 0x00000000ffff0000) >> 16) _comma \
(int_16)((x) & 0x000000000000ffff)
#endif
#endif /* USE_LL */
//-------------------------------------------------------------------------
#if 0
_unsigned_32
The _unsigned_32 macro casts an 8- or 16-bit signed value to a 32-bit
unsigned value without sign extension.
unsigned_32 _unsigned_32(int_16 value)
value
is an 8- or 16-bit signed value.
#endif
//-------------------------------------------------------------------------
// Define for casting to unsigned 32 without sign extension for 8 and
// 16 bit signed quantities.
#define _unsigned_32(p) ((unsigned_32)((unsigned_16)(int_32)(p)))
//----------------------------------------------------------------------------
_resident inline int _most_positive (void) {
return 0x7fffffff;
} // _most_positive
_resident inline int _do_overflow (void) {
return _most_positive () + _most_positive ();
} // _do_overflow
_resident inline void _force_ov_trap (void) {
(void)_do_overflow ();
} // _force_ov_trap
//-------------------------------------------------------------------------
#if 0
_uns_16_mul
The _uns_16_mul macro takes two unsigned 16-bit values and returns the
32-bit product of these values.
int_32 _uns_16_mul(int_16 first_operand,
int_16 second_operand)
first_operand
is a 16-bit unsigned value.
second_operand
is a 16-bit unsigned value.
Usage Considerations
The _uns_16_mul macro returns a 32-bit value that is the product of
first_operand and second_operand.
Overflow is not detected.
The following example illustrates a use of this macro.
pTAL Code Generated C++ Code
INT(16) i16a, i16b; int_16 i16a, i16b;
INT(32) r32; int_32 r32;
r32 := i16a '*' i16b; r32 = _uns_16_mul(i16a,i16b);
#endif
//-------------------------------------------------------------------------
#define _uns_16_mul(x, y) \
((int_32)(_unsigned_32 (x) * _unsigned_32 (y)))
//-------------------------------------------------------------------------
#if 0
_uns_32_mul
The _uns_32_mul macro takes two unsigned 32-bit values and returns the
63-bit product of these values.
int_64 _uns_32_mul(int_32 first_operand,
int_32 second_operand)
first_operand
is a 32-bit unsigned value.
second_operand
is a 32-bit unsigned value.
Usage Considerations
The _uns_32_mul macro returns a 63-bit value that is the product of
first_operand and second_operand.
Overflow is not detected.
The following example illustrates a use of this macro.
pTAL Code Generated C++ Code
INT(32) i32a, i32b; int_32 i32a, i32b;
INT(64) r64; int_64 r64;
r64 := i32a '*' i32b; r64 = _uns_32_mul(i32a,i32b);
#endif
//-------------------------------------------------------------------------
#define _uns_32_mul(x, y) \
((int_64)(unsigned_32)(x) * (int_64)(unsigned_32)(y))
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
// Inline function to determine if a 32-bit dividend divided by a 16-bit
// divisor will cause a 16-bit overflow.
//
// For the divide and modulo operation with a 32-bit unsigned dividend and
// a 16-bit unsigned divisor, overflow occurs when the most significant
// 16 bits of the dividend are greater than or equal to the divisor. This
// automatically includes the case of a zero divisor since the operation
// is unsigned.
_resident inline int_16 _check_for_uns_16_div_ov (int_32 dvnd, int_16 dvsr) {
return _tbv (((unsigned_16)((dvnd >> 16) & 0xFFFF)) >= (unsigned_16)dvsr);
} // _check_for_uns_16_div_ov
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
// Inline function to determine if a 63-bit dividend divided by a 32-bit
// divisor will cause overflow.
//
// For the divide and modulo operation with a 64-bit unsigned dividend and
// a 32-bit unsigned divisor, overflow occurs when the most significant
// 32 bits of the dividend are greater than or equal to the divisor. This
// automatically includes the case of a zero divisor since the operation
// is unsigned.
_resident inline int_16 _check_for_uns_32_div_ov (int_64 dvnd, int_32 dvsr) {
return _tbv (((unsigned_32)((dvnd >> 32) & 0xFFFFFFFF)) >= (unsigned_32)dvsr);
} // _check_for_uns_32_div_ov
//-------------------------------------------------------------------------
#if 0
_uns_16_div
The _uns_16_div macro takes an unsigned 32-bit dividend and an unsigned
16-bit divisor and returns the 16-bit quotient of these values.
int_16 _uns_16_div(int_32 dividend,
int_16 divisor)
dividend
is a 32-bit unsigned dividend.
divisor
is a 16-bit unsigned divisor.
Usage Considerations
The _uns_16_div macro returns a 16-bit quotient of the dividend and divisor.
Overflow trapping takes place if the quotient is greater than the largest
unsigned 16- bit value. The following example illustrates a use of this
macro.
pTAL Code Generated C++ Code
INT(16) r16, i16; int_16 r16, i16;
INT(32) i32; int_32 i32;
r16 := i32 '/' i16; r16 = _uns_16_div(i32,i16);
#endif
//-------------------------------------------------------------------------
#define _uns_16_div(dvnd, dvsr) \
((int_16)((unsigned_16)((unsigned_32)dvnd / _unsigned_32 (dvsr))))
//-------------------------------------------------------------------------
#if 0
_uns_32_div
The _uns_32_div macro takes an unsigned 63-bit dividend and an unsigned
32-bit divisor and returns the 32-bit quotient of these values.
int_32 _uns_32_div(int_64 dividend,
int_32 divisor)
dividend
is a 63-bit unsigned dividend.
divisor
is a 32-bit unsigned divisor.
Usage Considerations
The _uns_32_div macro returns a 32-bit quotient of the dividend and divisor.
Overflow trapping takes place if the quotient is greater than the largest
unsigned 32- bit value.
The following example illustrates a use of this macro.
pTAL Code Generated C++ Code
INT(32) r32, i32; int_32 r32, i32;
INT(64) i64; int_64 i64;
r32 := i64 '/' i32; r32 = _uns_32_div(i64,i32);
#endif
//-------------------------------------------------------------------------
#define _uns_32_div(dvnd, dvsr) \
((int_32)((unsigned_32)(dvnd / (int_64)((unsigned_32)(dvsr)))))
//-------------------------------------------------------------------------
#if 0
_uns_16_mod
The _uns_16_mod macro takes an unsigned 32-bit dividend and an unsigned
16-bit divisor and returns the 16-bit modulo of these values.
int_16 _uns_16_mod(int_32 dividend,
int_16 divisor)
dividend
is a 32-bit unsigned dividend.
divisor
is a 16-bit unsigned divisor.
Usage Considerations
The _uns_16_mod macro returns a 16-bit modulo of the dividend and divisor.
Overflow trapping takes place if the quotient is greater than the largest
unsigned 16-bit value.
The following example illustrates a use of this macro.
pTAL Code Generated C++ Code
INT(16) r16, i16; int_16 r16, i16;
INT(32) i32; int_32 i32;
r16 := i32 ''\'' i16; r16 = _uns_16_mod(i32,i16);
#endif
//-------------------------------------------------------------------------
// Define to modulo a 32-bit unsigned dividend by a 16-bit unsigned divisor.
#define _uns_16_mod(dvnd, dvsr) \
((int_16) \
((unsigned_16) \
((unsigned_32)(dvnd) - \
(_unsigned_32 (_uns_16_div (dvnd, dvsr)) * _unsigned_32 (dvsr)))))
//-------------------------------------------------------------------------
#if 0
_uns_32_mod
The _uns_32_mod macro takes an unsigned 63-bit dividend and an unsigned
32-bit divisor and returns the 32-bit modulo of these values.
int_32 _uns_32_mod(int_64 dividend,
int_32 divisor)
dividend
is a 63-bit unsigned dividend.
divisor
is a 32-bit unsigned divisor.
Usage Considerations
The _uns_32_mod macro returns a 32-bit modulo of the dividend and divisor.
Overflow trapping takes place if the quotient is greater than the largest
unsigned 32- bit value.
The following example illustrates a use of this macro.
pTAL Code Generated C++ Code
INT(32) r32, i32; int_32 r32, i32;
INT(64) i64; int_64 i64;
r32 := i64 ''\'' i32; r32 = _uns_32_mod(i64,i32);
#endif
//-------------------------------------------------------------------------
// Define to modulo a 63-bit unsigned dividend by a 32-bit unsigned divisor.
#define _uns_32_mod(dvnd, dvsr) \
((int_32) \
((unsigned_32) \
(dvnd - \
((int_64)((unsigned_32)_uns_32_div (dvnd, dvsr)) * \
(int_64)((unsigned_32)dvsr)))))
//-------------------------------------------------------------------------
#if 0
_uns_16_div_ov
The _uns_16_div_ov function takes an unsigned 32-bit dividend and an
unsigned 16-bit divisor and returns the 16-bit quotient of these values,
setting an overflow indicator.
int_16 _uns_16_div_ov(int_32 dividend,
int_16 divisor
int_16 *ov)
dividend
is a 32-bit unsigned dividend.
divisor
is a 16-bit unsigned divisor.
ov
is a reference parameter that indicates whether or not the quotient is
greater than the largest unsigned 16-bit value.
Usage Considerations
The _uns_16_div_ov function returns a 16-bit quotient of the dividend and
divisor.
The ov reference parameter returns -1 if the quotient (the function result)
is greater than the largest unsigned 16-bit value, and 0 otherwise.
The function result is undefined if overflow is detected.
The following example illustrates a use of this function.
pTAL Code Generated C++ Code
?NOOVERFLOW_TRAPS #pragma nooverflow_traps
int_16 _ov_temp;
INT(16) r16, i16; int_16 r16, i16;
INT(32) i32; int_32 i32;
r16 := i32 '/' i16; r16 = _uns_16_div_ov(i32,i16
&_ov_temp);
IF $OVERFLOW THEN if (_ov_temp)
#endif
//-------------------------------------------------------------------------
// Inline function to divide a 32-bit unsigned dividend by a 16-bit
// unsigned divisor. Overflow trapping does not occur; the formal
// reference parameter ov is set to -1 if overflow occured and 0
// otherwise. The result of the function is undefined if overflow is
// detected.
_resident inline int_16 _uns_16_div_ov (int_32 dvnd, int_16 dvsr, int_16* ov) {
*ov = _check_for_uns_16_div_ov (dvnd, dvsr);
return (int_16)((unsigned_16)((unsigned_32)dvnd / _unsigned_32 (dvsr)));
} // _uns_16_div_ov
//-------------------------------------------------------------------------
#if 0
_uns_32_div_ov
The _uns_32_div_ov function takes an unsigned 63-bit dividend and an
unsigned 32-bit divisor and returns the 32-bit quotient of these values,
setting an overflow indicator.
int_32 _uns_32_div_ov(int_64 dividend,
int_32 divisor
int_16 *ov)
dividend
is a 63-bit unsigned dividend.
divisor
is a 32-bit unsigned divisor.
ov
is a reference parameter that indicates whether or not the quotient is
greater than the largest unsigned 16-bit value.
Usage Considerations
The _uns_32_div_ov function returns a 16-bit quotient of the dividend and
divisor.
The ov reference parameter returns -1 if the quotient (the function result)
is greater than the largest unsigned 16-bit value, and 0 otherwise.
The function result is undefined if overflow is detected.
The following example illustrates a use of this function.
pTAL Code Generated C++ Code
?NOOVERFLOW_TRAPS #pragma nooverflow_traps
int_16 _ov_temp;
INT(32) r32, i32; int_32 r32, i32;
INT(64) i64; int_64 i64;
r32 := i64 '/' i32; r32 = _uns_32_div_ov(i64,i32
&_ov_temp);
IF $OVERFLOW THEN if (_ov_temp)
#endif
//-------------------------------------------------------------------------
// Inline function to divide a 63-bit unsigned dividend by a 32-bit
// unsigned divisor. Overflow trapping does not occur; the formal
// reference parameter ov is set to -1 if overflow occured and 0
// otherwise. The result of the function is undefined if overflow is
// detected.
_resident inline int_32 _uns_32_div_ov (int_64 dvnd, int_32 dvsr, int_16* ov) {
#define i32_to_i64(x) ((int_64)((unsigned_32)(x)))
*ov = _check_for_uns_32_div_ov (dvnd, dvsr);
return (int_32)((unsigned_32)(dvnd / i32_to_i64 (dvsr)));
#undef i32_to_i64
} // _uns_32_div_ov
//-------------------------------------------------------------------------
#if 0
_uns_16_mod_ov
The _uns_16_mod_ov macro takes an unsigned 32-bit dividend and an unsigned
16-bit divisor and returns the 16-bit modulo of these values, setting an
overflow indicator.
int_16 _uns_16_mod_ov(int_32 dividend,
int_16 divisor
int_16 *ov)
dividend
is a 32-bit unsigned dividend.
divisor
is a 16-bit unsigned divisor.
ov
is a reference parameter that indicates whether or not the quotient is
greater than the largest unsigned 16-bit value.
Usage Considerations
The _uns_16_mod_ov macro returns a 16-bit modulo of the dividend and
divisor.
The ov reference parameter returns -1 if the quotient of the dividend
and divisor is greater than the largest unsigned 16-bit value, and 0
otherwise.
The function result is undefined if overflow is detected.
The following example illustrates a use of this function.
pTAL Code Generated C++ Code
?NOOVERFLOW_TRAPS #pragma nooverflow_traps
int_16 _ov_temp;
INT(16) r16, i16; int_16 r16, i16;
INT(32) i32; int_32 i32;
r16 := i32 ''\'' i16; r16 = _uns_16_mod_ov(i32,i16
&_ov_temp);
IF $OVERFLOW THEN if (_ov_temp)
#endif
//-------------------------------------------------------------------------
// Inline function to modulo a 32-bit unsigned dividend by a 16-bit
// unsigned divisor. Overflow trapping does not occur; the formal
// reference parameter ov is set to -1 if overflow occured and 0
// otherwise. The result of the function is undefined if overflow is
// detected.
_resident inline int_16 _uns_16_mod_ov (int_32 dvnd, int_16 dvsr, int_16* ov) {
*ov = _check_for_uns_16_div_ov (dvnd, dvsr);
return
(int_16)
((unsigned_16)
((unsigned_32)(dvnd) -
(((unsigned_32)dvnd / _unsigned_32 (dvsr)) * _unsigned_32 (dvsr))));
} // _uns_16_mod_ov
//-------------------------------------------------------------------------
#if 0
_uns_32_mod_ov
The _uns_32_mod_ov macro takes an unsigned 63-bit dividend and an
unsigned 32-bit divisor and returns the 32-bit modulo of these values,
setting an overflow indicator.
int_32 _uns_32_mod_ov(int_64 dividend,
int_32 divisor
int_16 *ov)
dividend
is a 63-bit unsigned dividend.
divisor
is a 32-bit unsigned divisor.
ov
is a reference parameter that indicates whether or not the quotient is
greater than the largest unsigned 32-bit value.
Usage Considerations
The _uns_32_mod_ov macro returns a 32-bit modulo of the dividend and
divisor.
The ov reference parameter returns -1 if the quotient of the dividend and
divisor is greater than the largest unsigned 32-bit value, and 0 otherwise.
The function result is undefined if overflow is detected.
The following example illustrates a use of this function.
pTAL Code Generated C++ Code
?NOOVERFLOW_TRAPS #pragma nooverflow_traps
int_16 _ov_temp;
INT(32) r32, i32; int_32 r32, i32;
INT(64) i64; int_64 i64;
r32 := i64 ''\'' i32; r32 = _uns_32_mod_ov(i64,i32
&_ov_temp);
IF $OVERFLOW THEN if (_ov_temp)
#endif
//-------------------------------------------------------------------------
// Inline function to modulo a 63-bit unsigned dividend by a 32-bit
// unsigned divisor. Overflow trapping does not occur; the formal
// reference parameter ov is set to -1 if overflow occured and 0
// otherwise. The result of the function is undefined if overflow is
// detected.
_resident inline int_32 _uns_32_mod_ov (int_64 dvnd, int_32 dvsr, int_16* ov) {
#define i32_to_i64(x) ((int_64)((unsigned_32)(x)))
*ov = _check_for_uns_32_div_ov (dvnd, dvsr);
return
(int_32)
((unsigned_32)
(dvnd - ((dvnd / i32_to_i64 (dvsr)) * i32_to_i64 (dvsr))));
#undef i32_to_i64
} // _uns_32_mod_ov
//-------------------------------------------------------------------------
#if 0
_xadr
The _xadr function converts the pointer argument to type unsigned_char*.
unsigned_char _xadr(const void *address)
address
is an address to be converted.
Usage Considerations
The _xadr function is equivalent to the pTAL $XADR standard function.
pTAL Code Generated C++ Code
STRING .EXT xp; unsigned_char *xp;
INT(32) xa; int_32 xa;
@xp := $XADR(xp); xp = _xadr(xp);
@xp := $XADR(xa); xp = _xadr(&xa);
#endif
//-------------------------------------------------------------------------
// Implements Ptal builtin $XADR:
#define _xadr(addr) _xadr_Function((const void*)(addr))
_resident inline unsigned_char _far * _xadr_Function (const void *address) {
return (unsigned_char _far*) address;
} // _xadr_Function
#define _bit_length(a,b) _bitlength((a).(b))
//--------------------------------------------------------
#endif
//#endif