From: <bi...@us...> - 2007-04-17 11:23:07
|
Revision: 305 http://svn.sourceforge.net/oorexx/?rev=305&view=rev Author: bigrixx Date: 2007-04-17 04:23:02 -0700 (Tue, 17 Apr 2007) Log Message: ----------- Merge of 3.x changes. Modified Paths: -------------- interpreter/trunk/kernel/Makefile.am interpreter/trunk/kernel/Makefile.win interpreter/trunk/kernel/classes/DirectoryClass.cpp interpreter/trunk/kernel/classes/StringClass.hpp interpreter/trunk/kernel/classes/StringClassMisc.cpp interpreter/trunk/kernel/parser/InstructionParser.cpp interpreter/trunk/kernel/parser/SourceFile.cpp interpreter/trunk/kernel/runtime/GlobalData.cpp interpreter/trunk/kernel/runtime/RexxConstants.hpp interpreter/trunk/kernel/runtime/Setup.cpp Modified: interpreter/trunk/kernel/Makefile.am =================================================================== --- interpreter/trunk/kernel/Makefile.am 2007-04-16 15:17:01 UTC (rev 304) +++ interpreter/trunk/kernel/Makefile.am 2007-04-17 11:23:02 UTC (rev 305) @@ -207,6 +207,8 @@ expression/ExpressionDotVariable.hpp \ expression/ExpressionFunction.cpp \ expression/ExpressionFunction.hpp \ + expression/ExpressionLogical.cpp \ + expression/ExpressionLogical.hpp \ expression/ExpressionMessage.cpp \ expression/ExpressionMessage.hpp \ expression/ExpressionOperator.cpp \ Modified: interpreter/trunk/kernel/Makefile.win =================================================================== --- interpreter/trunk/kernel/Makefile.win 2007-04-16 15:17:01 UTC (rev 304) +++ interpreter/trunk/kernel/Makefile.win 2007-04-17 11:23:02 UTC (rev 305) @@ -67,7 +67,7 @@ StringClassSub.obj StringClassUtil.obj StringClassWord.obj \ SupplierClass.obj TableClass.obj BuiltinFunctions.obj \ CommonSysUtils.obj ExpressionCompoundVariable.obj \ - ExpressionDotVariable.obj ExpressionFunction.obj ExpressionMessage.obj \ + ExpressionDotVariable.obj ExpressionFunction.obj ExpressionLogical.obj ExpressionMessage.obj \ ExpressionOperator.obj ExpressionStack.obj ExpressionStem.obj ExpressionLogical.obj \ ExpressionVariable.obj IndirectVariableReference.obj QueueFunctions.obj \ AddressInstruction.obj AssignmentInstruction.obj CallInstruction.obj \ Modified: interpreter/trunk/kernel/classes/DirectoryClass.cpp =================================================================== --- interpreter/trunk/kernel/classes/DirectoryClass.cpp 2007-04-16 15:17:01 UTC (rev 304) +++ interpreter/trunk/kernel/classes/DirectoryClass.cpp 2007-04-17 11:23:02 UTC (rev 305) @@ -201,7 +201,7 @@ return result->supplier(); /* convert this to a supplier */ } -RexxArray *RexxDirectory::values(void) +RexxArray *RexxDirectory::allItems() /******************************************************************************/ /* Function: Create an array of all of the directory values, including the */ /* values of all the SETMETHOD methods */ Modified: interpreter/trunk/kernel/classes/StringClass.hpp =================================================================== --- interpreter/trunk/kernel/classes/StringClass.hpp 2007-04-16 15:17:01 UTC (rev 304) +++ interpreter/trunk/kernel/classes/StringClass.hpp 2007-04-17 11:23:02 UTC (rev 305) @@ -211,18 +211,26 @@ RexxObject *dataType(RexxString *); - RexxInteger *lastPosRexx(RexxString *, RexxInteger *); - RexxInteger *caselessLastPosRexx(RexxString *, RexxInteger *); + RexxInteger *lastPosRexx(RexxString *, RexxInteger *); + RexxInteger *caselessLastPosRexx(RexxString *, RexxInteger *); stringsize_t lastPos(RexxString *needle, stringsize_t start); stringsize_t caselessLastPos(RexxString *needle, stringsize_t start); - stringchar_t *lastPos(stringchar_t * needle, size_t needleLen, stringchar_t * haystack, stringsize_t haystackLen); + stringchar_t *lastPos(stringchar_t* needle, stringsize_t needleLen, stringchar_t * haystack, stringsize_t haystackLen); stringchar_t *caselessLastPos(stringchar_t * needle, stringsize_t needleLen, stringchar_t * haystack, stringsize_t haystackLen); - RexxInteger *posRexx(RexxString *, RexxInteger *); - RexxInteger *caselessPosRexx(RexxString *, RexxInteger *); - stringsize_t pos(RexxString *, stringsize_t); - stringsize_t caselessPos(RexxString *, stringsize_t); + RexxInteger *posRexx(RexxString *, RexxInteger *); + RexxInteger *caselessPosRexx(RexxString *, RexxInteger *); + stringsize_t pos(RexxString *, stringsize_t); + stringsize_t caselessPos(RexxString *, stringsize_t); + RexxInteger *match(RexxInteger *start_, RexxString *other, RexxInteger *offset_, RexxInteger *len_); + RexxInteger *caselessMatch(RexxInteger *start_, RexxString *other, RexxInteger *offset_, RexxInteger *len_); + bool primitiveMatch(stringsize_t start, RexxString *other, stringsize_t offset, stringsize_t len); + bool primitiveCaselessMatch(stringsize_t start, RexxString *other, stringsize_t offset, stringsize_t len); + RexxInteger *matchChar(RexxInteger *position_, RexxString *matchSet); + RexxInteger *caselessMatchChar(RexxInteger *position_, RexxString *matchSet); + + RexxString *translate(RexxString *, RexxString *, RexxString *); RexxInteger *verify(RexxString *, RexxString *, RexxInteger *); RexxInteger *countStrRexx(RexxString *); @@ -246,10 +254,6 @@ RexxString *x2d(RexxInteger *); RexxString *x2dC2d(RexxInteger *, bool); - RexxString *before(RexxString *needle, RexxInteger *start); - RexxString *beforeLast(RexxString *needle); - RexxString *after(RexxString *needle, RexxInteger *start); - RexxArray *makeArray(RexxString *); void copyIntoRxString(RxString *target); @@ -259,8 +263,6 @@ /* */ /****************************************************************************/ int isSymbol(); - stringsize_t pos(RexxString *, stringsize_t); - stringsize_t caselessPos(RexxString *, stringsize_t); stringsize_t validDBCS(); RexxString *DBCSreverse(); Modified: interpreter/trunk/kernel/classes/StringClassMisc.cpp =================================================================== --- interpreter/trunk/kernel/classes/StringClassMisc.cpp 2007-04-16 15:17:01 UTC (rev 304) +++ interpreter/trunk/kernel/classes/StringClassMisc.cpp 2007-04-17 11:23:02 UTC (rev 305) @@ -552,191 +552,6 @@ : new_string((stringchar_t *)"CHAR",4)); /* otherwise we return CHAR */ } - -RexxInteger *RexxString::lastPosRexx(RexxString *needle, RexxInteger *start) -{ - // if DBCS mode is turned on...pass it on. - if (DBCS_MODE) - { - return this->DBCSlastPos(needle, start); - } - needle = REQUIRED_STRING(needle, ARG_ONE); - // find out where to start the search. The default is at the very end. - stringsize_t startPos = optional_position(start, getLength(), ARG_TWO); - // now perform the actual search. - return new_integer(lastPos(needle, startPos)); -} - - -RexxInteger *RexxString::caselessLastPosRexx(RexxString *needle, RexxInteger *start) -{ - // validate that this is a good string argument - needle = REQUIRED_STRING(needle, ARG_ONE); - // find out where to start the search. The default is at the very end. - stringsize_t startPos = optional_position(start, getLength(), ARG_TWO); - // now perform the actual search. - return new_integer(caselessLastPos(needle, startPos)); -} - - - -/** - * Primitive implementation of a lastpos search. - * - * @param needle The search needle. - * @param start The starting position (origin 1). - * - * @return Returns the last match position, searching back from the start - * position. The starting position is the right-most character - * of the past possible match (as if the string was truncated - * at start). - */ -stringsize_t RexxString::lastPos(RexxString *needle, stringsize_t start) -{ - stringsize_t haystackLen = this->getLength(); /* get the haystack length */ - stringsize_t needleLen = needle->getLength(); /* and get the length too */ - - // no match possible if either string is null - if (needleLen == 0 || haystackLen == 0) - { - return 0; - } - else - { - // get the start position for the search. - start = min(start, haystackLen); - /* do the search */ - stringchar_t * matchLocation = lastPos((stringchar_t *)needle->getStringData(), needleLen, (stringchar_t * )this->getStringData(), haystackLen); - if (matchLocation == NULL) - { - return 0; - } - else - { - return matchLocation - (stringchar_t *)this->getStringData() + 1; - } - } -} - - -/** - * Primitive implementation of a caseless lastpos search. - * - * @param needle The search needle. - * @param start The starting position (origin 1). - * - * @return Returns the last match position, searching back from the start - * position. The starting position is the right-most character - * of the past possible match (as if the string was truncated - * at start). - */ -stringsize_t RexxString::caselessLastPos(RexxString *needle, stringsize_t start) -{ - stringsize_t haystackLen = this->getLength(); /* get the haystack length */ - stringsize_t needleLen = needle->getLength(); /* and get the length too */ - - // no match possible if either string is null - if (needleLen == 0 || haystackLen == 0) - { - return 0; - } - else - { - // get the start position for the search. - start = min(start, haystackLen); - /* do the search */ - stringchar_t * matchLocation = caselessLastPos((stringchar_t *)needle->getStringData(), needleLen, (stringchar_t * )this->getStringData(), haystackLen); - if (matchLocation == NULL) - { - return 0; - } - else - { - return matchLocation - (stringchar_t *)this->getStringData() + 1; - } - } -} - - -/** - * Absolutely most primitive version of a lastpos search. This - * version searches directly in a buffer rather than a Rexx - * String. - * - * @param needle Pointer to the needle string. - * @param needleLen Length of the needle string. - * @param haystack The pointer to the haystack string. - * @param haystackLen - * The length of the haystack string. - * - * @return A pointer to the match location or NULL if there is no match. - */ -stringchar_t * RexxString::lastPos(stringchar_t * needle, stringsize_t needleLen, stringchar_t * haystack, stringsize_t haystackLen) -{ - // if the needle's longer than the haystack, no chance of a match - if (needleLen > haystackLen) - { - return NULL; - } - // set the search startpoing point relative to the end of the search string - haystack = haystack + haystackLen - needleLen; - // this is the possible number of compares we might need to perform - stringsize_t count = haystackLen - needleLen + 1; - // now scan backward - while (count > 0) - { - // got a match at this position, return it directly - if (memcmp(haystack, needle, needleLen) == 0) - { - return haystack; - } - // decrement count and position - count--; - haystack--; - } - return NULL; // nothing to see here folks, move along -} - - -/** - * Absolutely most primitive version of a caseless lastpos - * search. This version searches directly in a buffer rather - * than a Rexx String. - * - * @param needle Pointer to the needle string. - * @param needleLen Length of the needle string. - * @param haystack The pointer to the haystack string. - * @param haystackLen - * The length of the haystack string. - * - * @return A pointer to the match location or NULL if there is no match. - */ -stringchar_t * RexxString::caselessLastPos(stringchar_t * needle, stringsize_t needleLen, stringchar_t * haystack, stringsize_t haystackLen) -{ - // if the needle's longer than the haystack, no chance of a match - if (needleLen > haystackLen) - { - return NULL; - } - // set the search startpoing point relative to the end of the search string - haystack = haystack + haystackLen - needleLen; - // this is the possible number of compares we might need to perform - stringsize_t count = haystackLen - needleLen + 1; - // now scan backward - while (count > 0) - { - // got a match at this position, return it directly - if (CaselessCompare(haystack, needle, needleLen) == 0) - { - return haystack; - } - // decrement count and position - count--; - haystack--; - } - return NULL; // nothing to see here folks, move along -} - stringsize_t RexxString::countStr(RexxString *needle) /******************************************************************************/ /* Function: Count occurrences of one string in another. */ @@ -824,154 +639,6 @@ return result; /* finished */ } - -/** - * Extract the substring that occurs before a needle match postion. - * - * @param needle The search needle. If this is a null string, it will match to the end. - * - * @return The substring before the match needle match position. If the - * needle is not found, the entire string is returned. Like the - * parse instruction, a null string matches to the end. - */ -RexxString *RexxString::before(RexxString *needle, RexxInteger *start) -{ - - // the needle must be a string value - needle = REQUIRED_STRING(needle, ARG_ONE); - - stringsize_t searchStart = optionalPositionArgument(start, 1, ARG_TWO); - - // if this a null string, it matches everything. - if (needle->getLength() == 0) - { - if (searchStart == 1) - { - return this; - } - else { - return this->extract(searchStart - 1, getLength() - (searchStart - 1)); - } - } - - // look for the first match - stringsize_t match = this->pos(needle, searchStart - 1); - // no match, we return the entire string - if (match == 0) - { - if (searchStart == 1) - { - return this; - } - else { - return this->extract(searchStart - 1, getLength() - (searchStart - 1)); - } - } - else - { - // just extract the substring - return this->extract(searchStart - 1, match - searchStart); - } -} - - - -/** - * Extract the substring that occurs before a last needle match - * postion. - * - * @param needle The search needle. If this is a null string, - * it will match to the beginning. - * - * @return The substring before the match needle match position. If the - * needle is not found, the entire string is returned. Like the - * parse instruction, a null string matches to the end. - */ -RexxString *RexxString::beforeLast(RexxString *needle) -{ - - // the needle must be a string value - needle = REQUIRED_STRING(needle, ARG_ONE); - - // if this a null string, it matches everything. - if (needle->getLength() == 0) - { - return this; - } - // look for the first match - stringsize_t match = this->pos(needle, 0); - // no match, we return the entire string - if (match == 0) - { - return this; - } - else - { - // just extract the substring - return this->extract(0, match - 1); - } -} - - - - -/** - * Extract the substring that occurs after a needle match - * postion. - * - * @param needle The search needle. If this is a null string, it will match to the end. - * - * @return The substring before the match needle match position. If the - * needle is not found, a null string is returned. Like - * the parse instruction, a null string matches to the - * end. - */ -RexxString *RexxString::after(RexxString *needle, RexxInteger *start) -{ - // the needle must be a string value - needle = REQUIRED_STRING(needle, ARG_ONE); - - stringsize_t searchStart = optionalPositionArgument(start, 0, ARG_TWO); - - // if this a null string, it matches to the end, so there's no - // "after life" - if (needle->getLength() == 0) - { - return OREF_NULLSTRING; - } - - // look for the first match - stringsize_t match = this->pos(needle, searchStart - 1); - // no match, we return a null string - if (match == 0) - { - if (searchStart == 1) - { - return this; - } - else { - return this->extract(searchStart - 1, getLength() - searchStart + 1); - } - } - else - { - // convert this to a 0-based offset for the extract, positioned after the needle. - match = match + needle->getLength() - 1; - stringsize_t length = this->getLength() - match; - - if (length == 0) - { - return OREF_NULLSTRING; - } - else - { - // just extract the substring - return this->extract(match, length); - - } - } -} - stringsize_t RexxString::memPos( stringchar_t * String, /* search string */ stringsize_t Length, /* string length */ @@ -995,6 +662,7 @@ return Position; /* return match position */ } + RexxString *RexxString::translate( RexxString *tableo, /* output table */ RexxString *tablei, /* input table */ @@ -1157,3 +825,554 @@ target->strlength = length - 1; } + + +/** + * Exported version of the lastpos method + * + * @param needle The search needle. + * @param start The starting position. + * + * @return The match position. Returns 0 for no matches. + */ +RexxInteger *RexxString::lastPosRexx(RexxString *needle, RexxInteger *start) +{ + // if DBCS mode is turned on...pass it on. + if (DBCS_MODE) + { + return this->DBCSlastPos(needle, start); + } + needle = REQUIRED_STRING(needle, ARG_ONE); + // find out where to start the search. The default is at the very end. + stringsize_t startPos = optional_position(start, getLength(), ARG_TWO); + // now perform the actual search. + return new_integer(lastPos(needle, startPos)); +} + + + +/** + * Exported version of the caseless lastpos method + * + * @param needle The search needle. + * @param start The starting position. + * + * @return The match position. Returns 0 for no matches. + */ +RexxInteger *RexxString::caselessLastPosRexx(RexxString *needle, RexxInteger *start) +{ + // validate that this is a good string argument + needle = REQUIRED_STRING(needle, ARG_ONE); + // find out where to start the search. The default is at the very end. + stringsize_t startPos = optional_position(start, getLength(), ARG_TWO); + // now perform the actual search. + return new_integer(caselessLastPos(needle, startPos)); +} + + + +/** + * Primitive implementation of a lastpos search. + * + * @param needle The search needle. + * @param start The starting position (origin 1). + * + * @return Returns the last match position, searching back from the start + * position. The starting position is the right-most character + * of the past possible match (as if the string was truncated + * at start). + */ +stringsize_t RexxString::lastPos(RexxString *needle, stringsize_t start) +{ + stringsize_t haystackLen = this->getLength(); /* get the haystack length */ + stringsize_t needleLen = needle->getLength(); /* and get the length too */ + + // no match possible if either string is null + if (needleLen == 0 || haystackLen == 0) + { + return 0; + } + else + { + // get the start position for the search. + start = min(start, haystackLen); + /* do the search */ + stringchar_t * matchLocation = lastPos((stringchar_t *)needle->getStringData(), needleLen, (stringchar_t * )this->getStringData(), haystackLen); + if (matchLocation == NULL) + { + return 0; + } + else + { + return matchLocation - (stringchar_t *)this->getStringData() + 1; + } + } +} + + +/** + * Primitive implementation of a caseless lastpos search. + * + * @param needle The search needle. + * @param start The starting position (origin 1). + * + * @return Returns the last match position, searching back from the start + * position. The starting position is the right-most character + * of the past possible match (as if the string was truncated + * at start). + */ +stringsize_t RexxString::caselessLastPos(RexxString *needle, stringsize_t start) +{ + stringsize_t haystackLen = this->getLength(); /* get the haystack length */ + stringsize_t needleLen = needle->getLength(); /* and get the length too */ + + // no match possible if either string is null + if (needleLen == 0 || haystackLen == 0) + { + return 0; + } + else + { + // get the start position for the search. + start = min(start, haystackLen); + /* do the search */ + stringchar_t * matchLocation = caselessLastPos((stringchar_t *)needle->getStringData(), needleLen, (stringchar_t * )this->getStringData(), haystackLen); + if (matchLocation == NULL) + { + return 0; + } + else + { + return matchLocation - (stringchar_t *)this->getStringData() + 1; + } + } +} + + +/** + * Absolutely most primitive version of a lastpos search. This + * version searches directly in a buffer rather than a Rexx + * String. + * + * @param needle Pointer to the needle string. + * @param needleLen Length of the needle string. + * @param haystack The pointer to the haystack string. + * @param haystackLen + * The length of the haystack string. + * + * @return A pointer to the match location or NULL if there is no match. + */ +stringchar_t * RexxString::lastPos(stringchar_t * needle, stringsize_t needleLen, stringchar_t * haystack, stringsize_t haystackLen) +{ + // if the needle's longer than the haystack, no chance of a match + if (needleLen > haystackLen) + { + return NULL; + } + // set the search startpoing point relative to the end of the search string + haystack = haystack + haystackLen - needleLen; + // this is the possible number of compares we might need to perform + stringsize_t count = haystackLen - needleLen + 1; + // now scan backward + while (count > 0) + { + // got a match at this position, return it directly + if (memcmp(haystack, needle, needleLen) == 0) + { + return haystack; + } + // decrement count and position + count--; + haystack--; + } + return NULL; // nothing to see here folks, move along +} + + +/** + * Absolutely most primitive version of a caseless lastpos + * search. This version searches directly in a buffer rather + * than a Rexx String. + * + * @param needle Pointer to the needle string. + * @param needleLen Length of the needle string. + * @param haystack The pointer to the haystack string. + * @param haystackLen + * The length of the haystack string. + * + * @return A pointer to the match location or NULL if there is no match. + */ +stringchar_t * RexxString::caselessLastPos(stringchar_t * needle, stringsize_t needleLen, stringchar_t * haystack, stringsize_t haystackLen) +{ + // if the needle's longer than the haystack, no chance of a match + if (needleLen > haystackLen) + { + return NULL; + } + // set the search startpoing point relative to the end of the search string + haystack = haystack + haystackLen - needleLen; + // this is the possible number of compares we might need to perform + stringsize_t count = haystackLen - needleLen + 1; + // now scan backward + while (count > 0) + { + // got a match at this position, return it directly + if (CaselessCompare(haystack, needle, needleLen) == 0) + { + return haystack; + } + // decrement count and position + count--; + haystack--; + } + return NULL; // nothing to see here folks, move along +} + + + + +/** + * Exported version of the pos method + * + * @param needle The search needle. + * @param start The starting position. + * + * @return The match position. Returns 0 for no matches. + */ +RexxInteger *RexxString::posRexx(RexxString *needle, RexxInteger *pstart) +{ + stringsize_t start; /* converted start position */ + + /* force needle to a string */ + needle = REQUIRED_STRING(needle, ARG_ONE); + /* get the starting position */ + start = optional_position(pstart, 1, ARG_TWO); + /* pass on to the primitive function */ + /* and return as an integer object */ + return new_integer(this->pos(needle, start - 1)); +} + + + + +/** + * Exported version of the caseless pos method + * + * @param needle The search needle. + * @param start The starting position. + * + * @return The match position. Returns 0 for no matches. + */ +RexxInteger *RexxString::caselessPosRexx(RexxString *needle, RexxInteger *pstart) +{ + stringsize_t start; /* converted start position */ + + /* force needle to a string */ + needle = REQUIRED_STRING(needle, ARG_ONE); + /* get the starting position */ + start = optional_position(pstart, 1, ARG_TWO); + /* pass on to the primitive function */ + /* and return as an integer object */ + return new_integer(this->caselessPos(needle, start - 1)); +} + + +stringsize_t RexxString::pos(RexxString *needle, stringsize_t start) +{ + // DBCS mode is handled elsewhere + if (DBCS_MODE) + { + return this->DBCSpos(needle, start); + } + + // get the two working lengths + stringsize_t haystack_length = getLength(); + stringsize_t needle_length = needle->getLength(); + + // ok, there are a few quick checks we can perform. If the needle is + // bigger than the haystack, or the needle is a null string or + // our haystack length after adjusting to the starting position + // zero, then we can quickly return zero. + if (needle_length > haystack_length + start || needle_length == 0 || start + needle_length > haystack_length) + { + return 0; + } + + // address the string value + stringchar_t * haypointer = (stringchar_t *)getStringData() + start; + stringchar_t * needlepointer = (stringchar_t *)needle->getStringData(); + stringsize_t location = start + 1; // this is the match location as an index + // calculate the number of probes we can make in this string + stringsize_t count = (haystack_length - start) - needle_length + 1; + + // now scan + while (count--) + { + /* get a hit? */ + if (memcmp((PCHAR)haypointer, (PCHAR)needlepointer, needle_length) == 0) + { + return location; + } + // step our pointers accordingly + location++; + haypointer++; + } + return 0; // we got nothing... +} + + +stringsize_t RexxString::caselessPos(RexxString *needle, stringsize_t start) +{ + // DBCS mode is handled elsewhere + if (DBCS_MODE) + { + return this->DBCScaselessPos(needle, start); + } + + // get the two working lengths + stringsize_t haystack_length = getLength(); + stringsize_t needle_length = needle->getLength(); + + // ok, there are a few quick checks we can perform. If the needle is + // bigger than the haystack, or the needle is a null string or + // our haystack length after adjusting to the starting position + // zero, then we can quickly return zero. + if (needle_length > haystack_length + start || needle_length == 0 || start + needle_length > haystack_length) + { + return 0; + } + + // address the string value + stringchar_t * haypointer = (stringchar_t *)getStringData() + start; + stringchar_t * needlepointer = (stringchar_t *)needle->getStringData(); + stringsize_t location = start + 1; // this is the match location as an index + // calculate the number of probes we can make in this string + stringsize_t count = (haystack_length - start) - needle_length + 1; + + // now scan + while (count--) + { + /* get a hit? */ + if (CaselessCompare(haypointer, needlepointer, needle_length) == 0) + { + return location; + } + // step our pointers accordingly + location++; + haypointer++; + } + return 0; // we got nothing... +} + + +/** + * Test if regions within two strings match. + * + * @param start_ The starting compare position within the target string. This + * must be within the bounds of the string. + * @param other The other compare string. + * @param offset_ The starting offset of the compare string. This must be + * within the string bounds. The default start postion is 1. + * @param len_ The length of the compare substring. The length and the + * offset must specify a valid substring of other. If not + * specified, this defaults to the substring from the + * offset to the end of the string. + * + * @return True if the two regions match, false for any mismatch. + */ +RexxInteger *RexxString::match(RexxInteger *start_, RexxString *other, RexxInteger *offset_, RexxInteger *len_) +{ + stringsize_t start = positionArgument(start_, ARG_ONE); + // the start position must be within the string bounds + if (start > getLength()) + { + reportException(Error_Incorrect_method_position, start); + } + other = stringArgument(other, ARG_TWO); + + stringsize_t offset = optionalPositionArgument(offset_, 1, ARG_THREE); + + if (offset > other->getLength()) + { + reportException(Error_Incorrect_method_position, offset); + } + + stringsize_t len = optionalLengthArgument(len_, other->getLength() - offset + 1, ARG_FOUR); + + if ((offset + len - 1) > other->getLength()) + { + reportException(Error_Incorrect_method_length, len); + } + + return primitiveMatch(start, other, offset, len) ? TheTrueObject : TheFalseObject; +} + + +/** + * Test if regions within two strings match. + * + * @param start_ The starting compare position within the target string. This + * must be within the bounds of the string. + * @param other The other compare string. + * @param offset_ The starting offset of the compare string. This must be + * within the string bounds. The default start postion is 1. + * @param len_ The length of the compare substring. The length and the + * offset must specify a valid substring of other. If not + * specified, this defaults to the substring from the + * offset to the end of the string. + * + * @return True if the two regions match, false for any mismatch. + */ +RexxInteger *RexxString::caselessMatch(RexxInteger *start_, RexxString *other, RexxInteger *offset_, RexxInteger *len_) +{ + stringsize_t start = positionArgument(start_, ARG_ONE); + // the start position must be within the string bounds + if (start > getLength()) + { + reportException(Error_Incorrect_method_position, start); + } + other = stringArgument(other, ARG_TWO); + + stringsize_t offset = optionalPositionArgument(offset_, 1, ARG_THREE); + + if (offset > other->getLength()) + { + reportException(Error_Incorrect_method_position, offset); + } + + stringsize_t len = optionalLengthArgument(len_, other->getLength() - offset + 1, ARG_FOUR); + + if ((offset + len - 1) > other->getLength()) + { + reportException(Error_Incorrect_method_length, len); + } + + return primitiveCaselessMatch(start, other, offset, len) ? TheTrueObject : TheFalseObject; +} + + +/** + * Perform a compare of regions of two string objects. Returns + * true if the two regions match, returns false for mismatches. + * + * @param start The starting offset within the target string. + * @param other The source string for the compare. + * @param offset The offset of the substring of the other string to use. + * @param len The length of the substring to compare. + * + * @return True if the regions match, false otherwise. + */ +bool RexxString::primitiveMatch(stringsize_t start, RexxString *other, stringsize_t offset, stringsize_t len) +{ + start--; // make the starting point origin zero + offset--; + + // if the match is not possible in the target string, just return false now. + if ((start + len) > getLength()) + { + return false; + } + + return memcmp(getStringData() + start, other->getStringData() + offset, len) == 0; +} + + +/** + * Perform a caselesee compare of regions of two string objects. + * Returns true if the two regions match, returns false for + * mismatches. + * + * @param start The starting offset within the target string. + * @param other The source string for the compare. + * @param offset The offset of the substring of the other string to use. + * @param len The length of the substring to compare. + * + * @return True if the regions match, false otherwise. + */ +bool RexxString::primitiveCaselessMatch(stringsize_t start, RexxString *other, stringsize_t offset, stringsize_t len) +{ + start--; // make the starting point origin zero + offset--; + + // if the match is not possible in the target string, just return false now. + if ((start + len) > getLength()) + { + return false; + } + + return CaselessCompare((stringchar_t *)(getStringData() + start), (stringchar_t *)(other->getStringData() + offset), len) == 0; +} + + +/** + * Compare a single character at a give position against + * a set of characters to see if any of the characters is + * a match. + * + * @param position_ The character position + * @param matchSet The set to compare against. + * + * @return true if the character at the give position is any of the characters, + * false if none of them match. + */ +RexxInteger *RexxString::matchChar(RexxInteger *position_, RexxString *matchSet) +{ + stringsize_t position = positionArgument(position_, ARG_ONE); + // the start position must be within the string bounds + if (position > getLength()) + { + reportException(Error_Incorrect_method_position, position); + } + matchSet = stringArgument(matchSet, ARG_TWO); + + stringsize_t setLength = matchSet->getLength(); + stringchar_t matchChar = getChar(position - 1); + + // iterate through the match set looking for a match + for (stringsize_t i = 0; i < setLength; i++) + { + if (matchChar == (stringchar_t)matchSet->getChar(i)) + { + return TheTrueObject; + } + } + return TheFalseObject; +} + + +/** + * Compare a single character at a give position against + * a set of characters to see if any of the characters is + * a match. + * + * @param position_ The character position + * @param matchSet The set to compare against. + * + * @return true if the character at the give position is any of the characters, + * false if none of them match. + */ +RexxInteger *RexxString::caselessMatchChar(RexxInteger *position_, RexxString *matchSet) +{ + stringsize_t position = positionArgument(position_, ARG_ONE); + // the start position must be within the string bounds + if (position > getLength()) + { + reportException(Error_Incorrect_method_position, position); + } + matchSet = stringArgument(matchSet, ARG_TWO); + + stringsize_t setLength = matchSet->getLength(); + stringchar_t matchChar = getChar(position - 1); + + // iterate through the match set looking for a match, using a + // caseless compare + for (stringsize_t i = 0; i < setLength; i++) + { + if (toupper(matchChar) == toupper(matchSet->getChar(i))) + { + return TheTrueObject; + } + } + return TheFalseObject; +} + Modified: interpreter/trunk/kernel/parser/InstructionParser.cpp =================================================================== --- interpreter/trunk/kernel/parser/InstructionParser.cpp 2007-04-16 15:17:01 UTC (rev 304) +++ interpreter/trunk/kernel/parser/InstructionParser.cpp 2007-04-17 11:23:02 UTC (rev 305) @@ -998,7 +998,7 @@ RexxToken *token; /* working token */ /* process the expression */ - condition = this->parseLogical(TERM_IF, condition); + condition = this->parseLogical(OREF_NULL, TERM_IF, condition); if ((RexxObject *)condition == OREF_NULL) { /* no expression here? */ if (type == KEYWORD_IF) /* IF form? */ /* issue the IF message */ @@ -2188,3 +2188,248 @@ new ((void *)newObject) RexxInstructionUse(variableCount, variable_list); return(RexxInstruction *)newObject; /* done, return this */ } + + +RexxInstruction *RexxSource::useNew() +/****************************************************************************/ +/* Function: Create a USE instruction object */ +/****************************************************************************/ +{ + // The STRICT keyword turns this into a different instruction with different + // syntax rules + RexxToken *token = nextReal(); + int subkeyword = this->subKeyword(token); + + if (subkeyword == SUBKEY_STRICT) + { + return useStrictNew(); + } + + // the only subkeyword supported is ARG + if (subkeyword != SUBKEY_ARG) + { + report_error_token(Error_Invalid_subkeyword_use, token); + } + size_t variableCount = 0; /* no variables yet */ + RexxQueue *variable_list = new_queue(); // we might be parsing message terms, so we can't use the subterms list. + saveObject(variable_list); + token = nextReal(); /* get the next token */ + // keep processing tokens to the end + while (token->classId != TOKEN_EOC) + { + // this could be a token to skip a variable + if (token->classId == TOKEN_COMMA) + { + // this goes on as a variable, but an empty entry to process + variable_list->push(OREF_NULL); + variableCount++; + } + else // something real. This could be a single symbol or a message term + { + previousToken(); // push the current token back for term processing + // see if we can get a variable or a message term from this + RexxObject *retriever = variableOrMessageTerm(); + if (retriever != OREF_NULL) + { + variable_list->push(retriever); + variableCount++; + token = nextReal(); + if (token->classId == TOKEN_EOC) + { + break; + } + else if (token->classId != TOKEN_COMMA) + { + report_error_token(Error_Translation_use_comma, token); + } + } + else // invalid assignment type + { + report_error_token(Error_Variable_expected_USE, token); + } + } + token = nextReal(); /* get the next token */ + } + /* create a new translator object */ + RexxObject *newObject = new_variable_instruction(USE, Use, sizeof(RexxInstructionUse) + (variableCount - 1) * sizeof(RexxObject *)); + /* now complete this */ + new ((void *)newObject) RexxInstructionUse(variableCount, variable_list); + removeObj(variable_list); + return(RexxInstruction *)newObject; /* done, return this */ +} + +/** + * Parse a USE STRICT ARG instruction. + * + * @return The executable instruction object. + */ +RexxInstruction *RexxSource::useStrictNew() +{ + RexxToken *token = nextReal(); + // the only subkeyword supported is ARG + if (subKeyword(token) != SUBKEY_ARG) + { + report_error_token(Error_Invalid_subkeyword_use, token); + } + + // we accumulate 3 sets of data here, so we need 3 queues to push them in + size_t variableCount = 0; + RexxQueue *variable_list = new_queue(); // we might be parsing message terms, so we can't use the subterms list. + saveObject(variable_list); + RexxQueue *defaults_list = new_queue(); + saveObject(defaults_list); + RexxQueue *assertions_list = new_queue(); + saveObject(assertions_list); + token = nextReal(); /* get the next token */ + + bool allowOptionals = false; // we don't allow trailing optionals unless the list ends with "..." + // keep processing tokens to the end + while (token->classId != TOKEN_EOC) + { + // this could be a token to skip a variable + if (token->classId == TOKEN_COMMA) + { + // this goes on as a variable, but an empty entry to process. + // we also need to push empty entries on the other queues to keep everything in sync. + variable_list->push(OREF_NULL); + defaults_list->push(OREF_NULL); + assertions_list->push(OREF_NULL); + variableCount++; + // step to the next token, and go process more + token = nextReal(); + continue; + } + else // something real. This could be a single symbol or a message term + { + // we might have an ellipsis (...) on the end of the list meaning stop argument checking at that point + if (token->classId == TOKEN_SYMBOL) + { + // is this an ellipsis symbol? + if (token->value->strCompare(CHAR_ELLIPSIS)) + { + // ok, this is the end of everything. Tell the instructions to not enforce the max rules + allowOptionals = true; + // but we still need to make sure it's at the end + token = nextReal(); + if (token->classId != TOKEN_EOC) + { + report_error(Error_Translation_use_strict_ellipsis); + } + break; // done parsing + } + } + + + previousToken(); // push the current token back for term processing + // see if we can get a variable or a message term from this + RexxObject *retriever = variableOrMessageTerm(); + if (retriever == OREF_NULL) + { + report_error_token(Error_Variable_expected_USE, token); + } + variable_list->push(retriever); + variableCount++; + token = nextReal(); + // a terminator takes us out. We need to keep all 3 lists in sync with dummy entries. + if (token->classId == TOKEN_EOC) + { + defaults_list->push(OREF_NULL); + assertions_list->push(OREF_NULL); + break; + } + // if we've hit a comma here, step to the next token and continue with the next variable + else if (token->classId == TOKEN_COMMA) + { + defaults_list->push(OREF_NULL); + assertions_list->push(OREF_NULL); + token = nextReal(); + continue; + } + // if this is NOT a comma, we potentially have a + // default value and/or and ASSERT to process. + if (token->subclass == OPERATOR_EQUAL) + { + // this is a constant expression value. Single token forms + // are fine without parens, more complex forms require parens as + // delimiters. + RexxObject *defaultValue = constantExpression(); + // no expression is an error + if (defaultValue == OREF_NULL) + { + report_error(Error_Invalid_expression_use_strict_default); + } + + // add this to the defaults + defaults_list->push(defaultValue); + // step to the next token + token = nextReal(); + // a terminator takes us out. We need to keep all 3 lists in sync with dummy entries. + if (token->classId == TOKEN_EOC) + { + assertions_list->push(OREF_NULL); + break; + } + // if we've hit a comma here, step to the next token and continue with the next variable + else if (token->classId == TOKEN_COMMA) + { + assertions_list->push(OREF_NULL); + token = nextReal(); + continue; + } + } + else + { + // we need a more defaults marker + defaults_list->push(OREF_NULL); + } + + // this MUST be the ASSERT keyword here. We've already taken care of other options, so + // it's do or die now. + if (token->classId != TOKEN_SYMBOL) + { + report_error_token(Error_Invalid_subkeyword_use_strict_option, token); + } + else + { + if (subKeyword(token) != SUBKEY_ASSERT) + { + report_error_token(Error_Invalid_subkeyword_use_strict_option, token); + } + RexxObject *condition = this->constantLogicalExpression(); + if (condition == OREF_NULL) + { + report_error(Error_Invalid_expression_use_strict_assert); + } + assertions_list->push(condition); + + // Sigh, yet another check for EOC or COMMA... + token = nextReal(); + if (token->classId == TOKEN_EOC) + { + break; + } + // if we've hit a comma here, step to the next token and continue with the next variable + else if (token->classId == TOKEN_COMMA) + { + // step to the next token and continue + token = nextReal(); + continue; + } + else + { + // all that work, and we still found something invalid + report_error_token(Error_Invalid_subkeyword_use_strict_option, token); + } + } + } + } + + /* create a new translator object */ + RexxObject *newObject = new_variable_instruction(USE, UseStrict, sizeof(RexxInstructionUseStrict) + (variableCount - 1) * sizeof(UseVariable)); + /* now complete this */ + new ((void *)newObject) RexxInstructionUseStrict(variableCount, allowOptionals, variable_list, defaults_list, assertions_list); + removeObj(variable_list); + removeObj(defaults_list); + removeObj(assertions_list); + return(RexxInstruction *)newObject; /* done, return this */ +} Modified: interpreter/trunk/kernel/parser/SourceFile.cpp =================================================================== --- interpreter/trunk/kernel/parser/SourceFile.cpp 2007-04-16 15:17:01 UTC (rev 304) +++ interpreter/trunk/kernel/parser/SourceFile.cpp 2007-04-17 11:23:02 UTC (rev 305) @@ -4362,7 +4362,7 @@ case SUBKEY_WHILE: /* DO WHILE exprw */ /* get next subexpression */ - condition = this->parseLogical(TERM_COND, condition); + condition = this->parseLogical(OREF_NULL, TERM_COND, condition); if ((RexxObject *)condition == OREF_NULL) /* nothing really there? */ /* another invalid DO */ reportError(Error_Invalid_expression_while); @@ -4376,7 +4376,7 @@ case SUBKEY_UNTIL: /* DO UNTIL expru */ /* get next subexpression */ /* get next subexpression */ - condition = this->parseLogical(TERM_COND, condition); + condition = this->parseLogical(OREF_NULL, TERM_COND, condition); if ((RexxObject *)condition == OREF_NULL) /* nothing really there? */ /* another invalid DO */ @@ -4462,9 +4462,9 @@ * element if a single expression is located, and a complex * logical expression operator for a list of expressions. */ -RexxObject *RexxSource::parseLogical(int terminators, ProtectedObject &expr) +RexxObject *RexxSource::parseLogical(RexxToken *first, int terminators, ProtectedObject &expr) { - size_t count = argList(OREF_NULL, terminators); + size_t count = argList(first, terminators); // arglist has swallowed the terminator token, so we need to back up one. previousToken(); // let the caller deal with completely missing expressions Modified: interpreter/trunk/kernel/runtime/GlobalData.cpp =================================================================== --- interpreter/trunk/kernel/runtime/GlobalData.cpp 2007-04-16 15:17:01 UTC (rev 304) +++ interpreter/trunk/kernel/runtime/GlobalData.cpp 2007-04-17 11:23:02 UTC (rev 305) @@ -324,6 +324,12 @@ CPPM(RexxString::isInteger), CPPM(RexxString::equals), CPPM(RexxString::equalsCaseless), +CPPM(RexxString::match), +CPPM(RexxString::caselessMatch), +CPPM(RexxString::matchChar), +CPPM(RexxString::caselessMatchChar), +CPPM(RexxString::caselessPos), +CPPM(RexxString::caselessLastPos), /* All BIF methods start here. They */ /* will be arranged according to the*/ Modified: interpreter/trunk/kernel/runtime/RexxConstants.hpp =================================================================== --- interpreter/trunk/kernel/runtime/RexxConstants.hpp 2007-04-16 15:17:01 UTC (rev 304) +++ interpreter/trunk/kernel/runtime/RexxConstants.hpp 2007-04-17 11:23:02 UTC (rev 305) @@ -84,6 +84,11 @@ CHARCONSTANT(CALL_PROGRAM, "CALL_PROGRAM"); CHARCONSTANT(CALL_STRING, "CALL_STRING"); CHARCONSTANT(CHAR, "CHAR"); +CHARCONSTANT(CASELESSEQUALS, "CASELESSEQUALS"); +CHARCONSTANT(CASELESSLASTPOS, "CASELESSLASTPOS"); +CHARCONSTANT(CASELESSMATCH, "CASELESSMATCH"); +CHARCONSTANT(CASELESSMATCHCHAR, "CASELESSMATCHCHAR"); +CHARCONSTANT(CASELESSPOS, "CASELESSPOS"); CHARCONSTANT(CLASS, "CLASS"); CHARCONSTANT(CLOSE, "CLOSE"); CHARCONSTANT(CODE, "CODE"); @@ -123,8 +128,7 @@ CHARCONSTANT(ENTRY, "ENTRY"); CHARCONSTANT(ENVELOPE, "ENVELOPE"); CHARCONSTANT(ENVIRONMENT, "ENVIRONMENT"); -CHARCONSTANT(ERROR, "EQUALS"); -CHARCONSTANT(ERROR, "EQUALSCASELESS"); +CHARCONSTANT(EQUALS, "EQUALS"); CHARCONSTANT(ERROR, "ERROR"); CHARCONSTANT(ERRORCONDITION, "ERRORCONDITION"); CHARCONSTANT(ERRORTEXT, "ERRORTEXT"); @@ -183,6 +187,8 @@ CHARCONSTANT(MAKEINTEGER, "MAKEINTEGER"); CHARCONSTANT(MAKESTRING, "MAKESTRING"); CHARCONSTANT(MAKE_PROXY, "MAKE_PROXY"); +CHARCONSTANT(MATCH, "MATCH"); +CHARCONSTANT(MATCHCHAR, "MATCHCHAR"); CHARCONSTANT(MEMORY, "MEMORY"); CHARCONSTANT(MERGE, "MERGE"); CHARCONSTANT(MESSAGE, "MESSAGE"); Modified: interpreter/trunk/kernel/runtime/Setup.cpp =================================================================== --- interpreter/trunk/kernel/runtime/Setup.cpp 2007-04-16 15:17:01 UTC (rev 304) +++ interpreter/trunk/kernel/runtime/Setup.cpp 2007-04-17 11:23:02 UTC (rev 305) @@ -637,6 +637,8 @@ defineKernelMethod(CHAR_COUNTSTR ,TheStringBehaviour, CPPM(RexxString::countStrRexx), 1); defineKernelMethod(CHAR_LASTPOS ,TheStringBehaviour, CPPM(RexxString::lastPosRexx), 2); defineKernelMethod(CHAR_POS ,TheStringBehaviour, CPPM(RexxString::posRexx), 2); + defineKernelMethod(CHAR_CASELESSLASTPOS ,TheStringBehaviour, CPPM(RexxString::caselessLastPosRexx), 2); + defineKernelMethod(CHAR_CASELESSPOS ,TheStringBehaviour, CPPM(RexxString::caselessPosRexx), 2); defineKernelMethod(CHAR_TRANSLATE ,TheStringBehaviour, CPPM(RexxString::translate), 3); defineKernelMethod(CHAR_VERIFY ,TheStringBehaviour, CPPM(RexxString::verify), 3); defineKernelMethod(CHAR_BITAND ,TheStringBehaviour, CPPM(RexxString::bitAnd), 2); @@ -691,6 +693,10 @@ defineKernelMethod(CHAR_MAKEARRAY ,TheStringBehaviour, CPPM(RexxString::makeArray), 1); defineKernelMethod(CHAR_EQUALS ,TheStringBehaviour, CPPM(RexxString::equals), 1); defineKernelMethod(CHAR_EQUALSCASELESS ,TheStringBehaviour, CPPM(RexxString::equalsCaseless), 1); + defineKernelMethod(CHAR_MATCH ,TheStringBehaviour, CPPM(RexxString::match), 4); + defineKernelMethod(CHAR_CASELESSMATCH ,TheStringBehaviour, CPPM(RexxString::caselessMatch), 4); + defineKernelMethod(CHAR_MATCHCHAR ,TheStringBehaviour, CPPM(RexxString::matchChar), 2); + defineKernelMethod(CHAR_CASELESSMATCHCHAR ,TheStringBehaviour, CPPM(RexxString::caselessMatchChar), 2); /* set the scope of the methods to */ /* this classes oref */ TheStringBehaviour->setMethodDictionaryScope(TheStringClass); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |