The code you posted had three uses of ERRORHANDLER. Two had a
trailing semicolon. The fact that you can't follow the rule you set
yourself is a string argument in favour of avoiding the need for it.
I have switched over to the Bacarisse Backwards rule although it gives
one a *frisson* since one has to realize that you're just kidding
about the while, and that the code is executed once. I agree that
macro calls should have final semicolons.
Here is the code as of today, Tue 18 Aug. I spent both of my 30 mn
commutes making improvements and desk checking before I submit it for
a compile again, so there will be errors, in all probability. And
after it compiles the first time, I need to instrument it with
routines to display the rope and inspect it for errors.
// ***************************************************************
// * *
// * Rope implementation *
// * *
// * This program implements strings, called ropes, which can *
// * contain any character and can be of any length.
*
// * *
// * This code is best viewed using a monospace font such as *
// * Courier New, in a line length of 67 characters. *
// * *
// * The rest of this header addresses these topics: *
// * *
// * *
// * * The "rope" as represented in this code *
// * * Configuring this code for testing *
// * *
// * *
// * Note that the contributions of the following people are *
// * acknowledged: *
// * *
// * *
// * * Ben Bacarisse *
// * * Richard Heathfield *
// * *
// * *
// * THE "ROPE" AS REPRESENTED IN THIS CODE -------------------- *
// * *
// * The rope is defined as the binary tree of its nodes, where *
// * each node points to up to SEGMENT_MAX_LENGTH characters of *
// * the string. Each node of the binary tree contains: *
// * *
// * *
// * * A pointer to the start of the segment *
// * *
// * * The node type: *
// * *
// * + ENUnodeType.child indicates that the node is a *
// * child node of another node.
*
// * *
// * + ENUnodeType.ancestor indicates that the node is *
// * not a child of another node *
// * *
// * * The node length type: *
// * *
// * + ENUnodeLengthType.known indicates that the length *
// * (of the ancestor's complete string or the child *
// * subtree's substring) is known *
// * *
// * + ENUnodeLengthType.tooLarge indicates that the *
// * length exceeds the maximum value and is unknown. *
// * *
// * By default, this maximum value is 2^63-1, the *
// * maximum length of an unsigned "long long" less a *
// * margin to allow for testing the length. The *
// * maximum value, however, can be set to smaller *
// * values for testing. *
// * *
// * * The 64 bit unsigned string length. Note that this *
// * value may be unusable because the length may exceed *
// * the max value: here the node length type will be *
// * ENUnodeLengthType.unknown. *
// * *
// * * The start index of the rope segment (substring) *
// * within the full string; note that in rare cases this*
// * is unknown when the string is longer than 2^64-1 *
// * characters, and the segment is located on the right *
// * of the string, this value may also be unknown. Here *
// * it is set to -1. *
// * *
// * * The length of the rope segment (substring) *
// * *
// * * The address of the parent of the node or NULL *
// * *
// * * The address of the left child of the node (holding *
// * characters to the left of the segment) or NULL *
// * *
// * * The address of the right child of the node (holding *
// * characters to the right of the segment) or NULL *
// * *
// * *
// * CONFIGURING THIS CODE FOR TESTING ------------------------- *
// * *
// * The following symbols may be set to configure a test of this*
// * code. *
// * *
// * *
// * * SEGMENT_MAX_LENGTH: maximum length of a rope string *
// * segment *
// * *
// * * STRING_MAX_RECORDABLE_LENGTH: maximum recordable *
// * length of a string, beyond which the string length *
// * is officially "unknown". *
// * *
// * To test strings whose lengths are not known without *
// * having to generate oodlemegaterabytes of data, this *
// * value can be set to a small value. For actual use, a*
// * recommended value is 2^63-1. *
// * *
// * *
// * C H A N G E R E C O R D --------------------------------- *
// * DATE PROGRAMMER DESCRIPTION OF CHANGE *
// * -------- ---------- --------------------------------- *
// * 08 14 09 Nilges Started version 1 *
// * *
// * 08 18 09 Nilges 1. Revised implementation of *
// * statement macros per *
// * Bacarisse *
// * 2. Using typedef instead of *
// * #define per Heathfield *
// * 3. Using typename in cast in *
// * place of length per Heathfield*
// * *
// * I S S U E S ----------------------------------------------- *
// * DATE POSTER DESCRIPTION AND RESOLUTION *
// * -------- ---------- --------------------------------- *
// * 08 18 09 Nilges To be implemented: rope names and *
// * Dewey decimal numbers of rope *
// * nodes. Routines for inspection and*
// * display of ropes. Code *
// * instrumentation of debug displays.*
// * *
// * 08 14 09 Nilges To be implemented: use extra *
// * precision arithmetic for unbounded*
// * strings, representing big nums as *
// * big strings but in a big base such*
// * as 256 for chars & 32768 for *
// * wchars. *
// * *
// * *
// * ----------------------------------------------------------- *
// * *
// * The scientific industry has its exact counterpart in the *
// * kind of minds it harnesses: they no longer need to do *
// * themselves any violence in becoming their own voluntary and *
// * zealous overseers. Even if they show themselves, outside *
// * their official capacity, to be quite human and sensible *
// * being, they are paralysed by pathic stupidity the moment *
// * they begin to think professionally. *
// * *
// * - T. W. Adorno, Minima Moralia, 1948 *
// * *
// * *
// ***************************************************************
// ***** Standard includes ***************************************
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <stddef.h>
// ***** Configuration *******************************************
#define SEGMENT_MAX_LENGTH 32
#define STRING_MAX_RECORDABLE_LENGTH 1024 // Set to 2^63-1 for
// actual use
#define UNKNOWN_START_INDEX -1
// ***** Macros **************************************************
// * *
// * Macros are of two types: *
// * *
// * *
// * * Statement macros can be used anywhere a C statement *
// * is valid. They are surrounded by curly braces, prefixed*
// * with do, and suffixed with while(0). When used, *
// * statement macros must be followed with a semicolon. *
// * Their names are suffixed with _STMT. *
// * *
// * This is the Bacarisse Backward method, since you need *
// * to look at the while and then go backward to realize *
// * that the body of the macro definition will be executed *
// * once. *
// * *
// * * Expression macros can be used anywhere a C expression *
// * is valid. Their definitions are surrounded by round *
// * parentheses. Their names are suffixed with _EXP. *
// * *
// * *
// ***************************************************************
// --- Statement macro to handle errors
#define ERRORHANDLER_STMT(strMessage) \
do { \
printf("%s\n", (strMessage)); abort(); \
} while(0)
// --- Expression macro to return smaller value
#define MIN_EXP(value1, value2) \
( (value1) < (value2) ? (value1) : (value2) )
// --- Expression macro to perform malloc
#define MALLOC_EXP(typeName) \
( (typeName)(malloc(sizeof(typeName))) )
// --- Statement macros to perform malloc with error checking
// Allocate using a type
#define MALLOCTYPE_STMT(ptr, mallocType, mallocPurpose)
do { \
MALLOCSIZE_STMT(ptr, \
mallocType, \
sizeof(mallocType), \
mallocPurpose); \
} \
} while(0)
// Allocate using a size
#define MALLOCSIZE_STMT(ptr, \
mallocType, \
mallocSize, \
mallocPurpose)
do { \
if (((ptr) = MALLOC_EXP(mallocType) == NULL)) \
{ \
printf \
("Can't get %d bytes of storage\n", mallocSize); \
printf \
("Trying to allocate type %s\n", (mallocType)); \
printf \
("My purpose was: %s...sorry it didn't work out\n",
(mallocPurpose)); \
ERRORHANDLER_STMT("Malloc failed"); \
} \
} while(0)
// ***** Rope definition *****************************************
enum ENUnodeType { child, ancestor };
enum ENUnodeLengthType
{
known, tooLarge
};
typedef struct TYPropeNode ROPE;
typedef ROPE * Rope;
struct TYPropeNode
{
enum ENUnodeType enuNodeType;
enum ENUnodeLengthType enuNodeLengthType;
char * ptrNodeCharacters;
unsigned long long ulngStringLength;
unsigned long long lngSegmentStartIndex;
unsigned int uintSegmentLength;
Rope ptrParent;
Rope ptrLeft;
Rope ptrRight;
};
// ***** Procedures **********************************************
// ---------------------------------------------------------------
// Create a rope node
//
//
Rope mkRopeNode
(char * ptrNodeCharacters,
long long lngSegmentStartIndex,
unsigned int uintSegmentLength,
Rope ptrParent,
Rope ptrLeft,
Rope ptrRight)
{
Rope ptrNewNode;
(*ptrNewNode).ptrNodeCharacters = ptrNodeCharacters;
(*ptrNewNode).enuNodeType =
ptrParent == NULL
?
ENUnodeType.ancestor
:
ENUnodeType.child;
(*ptrNewNode).lngSegmentStartIndex = lngSegmentStartIndex;
(*ptrNewNode).uintSegmentLength = uintSegmentLength;
(*ptrNewNode).ptrParent = ptrParent;
(*ptrNewNode).ptrLeft = ptrLeft;
(*ptrNewNode).ptrRight = ptrRight;
(*ptrNewNode).ulngStringLength =
ulngSegmentLength
+
(ptrLeft != NULL ? (*ptrLeft).ulngStringLength : 0)
+
(ptrRight != NULL ? (*ptrRight).ulngStringLength : 0);
return ptrNewNode;
}
// ---------------------------------------------------------------
// Make rope
//
//
Rope mkRope
(Rope ptrParent,
char * ptrSourceChars,
long long lngStartIndex,
unsigned long long ulngStringLength)
{
Rope ptrLeft = NULL;
Rope ptrRight = NULL;
unsigned int uintNodes;
unsigned int uintDoubleSegmentLength;
if (uintStringLength <= SEGMENT_MAX_LENGTH)
uintNodes = 1;
else
{
if (ulngStringLength
<=
(uintDoubleSegmentLength = SEGMENT_MAX_LENGTH << 1))
uintNodes = 2;
else
uintNodes = 3;
}
Rope ptrRopeNode =
mkRopeNode
(// ----- Pointer to source chars -----------------------
(uintNodes > 1
?
ptrSourceChars + SEGMENT_MAX_LENGTH
:
ptrSourceChars),
// ----- Parent segment start index --------------------
(mkRope_calcStartIndex
(lngStartIndex,
uintNodes > 1 ? SEGMENT_MAX_LENGTH : 0)),
// ----- Parent segment length (screw you Heathfield) --
(uintNodes > 1
?
MIN_EXP((uintSegmentLength - SEGMENT_MAX_LENGTH),
(uintSegmentLength))
:
uintSegmentLength),
// ----- Parent's own parent or null -------------------
ptrParent,
// ----- Left child node exists when segments > 1 ------
(uintNodes > 1
?
(ptrLeft = mkRopeNode
(ptrSourceChars,
lngStartIndex,
SEGMENT_MAX_LENGTH,
NULL, NULL, NULL))
:
NULL),
// ----- Right child node exists when segments > 1 ----
(uintNodes > 2
?
(ptrRight = mkRope
(NULL,
ptrSourceChars
+
uintDoubleSegmentLength,
mkRope_calcStartIndex
(lngStartIndex, uintDoubleSegmentLength),
uintSegmentLength
-
uintDoubleSegmentLength))
:
NULL);
if (ptrRopeNode != NULL)
{
(*ptrRopeNode).ptrLeft = ptrLeft;
(*ptrRopeNode).ptrRight = ptrRight;
if (ptrLeft != NULL)
(*((*ptrRopeNode).ptrLeft)).ptrParent =
ptrRopeNode;
if (ptrRight != NULL)
(*((*ptrRopeNode).ptrRight)).ptrParent =
ptrRopeNode;
(*ptrRopeNode).ulngStringLength =
ulngStringLength;
}
return ptrRopeNode;
}
// ---------------------------------------------------------------
// Calculate next start index on behalf of mkRope()
//
//
long long mkRope_calcStartIndex(long long lngOld,
unsigned int uintOffset)
{
if (lngOld == UNKNOWN_START_INDEX)
return UNKNOWN_START_INDEX;
unsigned long long ulngNew = lngOld + uintOffset;
if (ulngNew <= STRING_MAX_RECORDABLE_LENGTH)
return (long long)ulngNew;
return UNKNOWN_START_INDEX;
}
int main()
{
printf("Unlimited strings in basic C");
// ***** Insert test code *****
return 0;
}