ParseTarget.cpp
Go to the documentation of this file.
1 /*----------------------------------------------------------------------------*/
2 /* */
3 /* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved. */
4 /* Copyright (c) 2005-2009 Rexx Language Association. All rights reserved. */
5 /* */
6 /* This program and the accompanying materials are made available under */
7 /* the terms of the Common Public License v1.0 which accompanies this */
8 /* distribution. A copy is also available at the following address: */
9 /* http://www.oorexx.org/license.html */
10 /* */
11 /* Redistribution and use in source and binary forms, with or */
12 /* without modification, are permitted provided that the following */
13 /* conditions are met: */
14 /* */
15 /* Redistributions of source code must retain the above copyright */
16 /* notice, this list of conditions and the following disclaimer. */
17 /* Redistributions in binary form must reproduce the above copyright */
18 /* notice, this list of conditions and the following disclaimer in */
19 /* the documentation and/or other materials provided with the distribution. */
20 /* */
21 /* Neither the name of Rexx Language Association nor the names */
22 /* of its contributors may be used to endorse or promote products */
23 /* derived from this software without specific prior written permission. */
24 /* */
25 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
26 /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
27 /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */
28 /* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
29 /* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
30 /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED */
31 /* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */
32 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY */
33 /* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */
34 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
35 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
36 /* */
37 /*----------------------------------------------------------------------------*/
38 /******************************************************************************/
39 /* REXX Translator */
40 /* */
41 /* Primitive Procedure Parse Trigger Class */
42 /* */
43 /******************************************************************************/
44 #include <stdlib.h>
45 #include "RexxCore.h"
46 #include "StringClass.hpp"
47 #include "ArrayClass.hpp"
48 #include "RexxActivation.hpp"
49 #include "ParseTarget.hpp"
50 #include "ParseInstruction.hpp"
51 
53  RexxObject *_string, /* target string */
54  RexxObject **_arglist, /* argument list */
55  size_t _argcount, /* size of the argument list */
56  size_t _translate, /* translation flag */
57  bool multiple, /* have multiple strings */
58  RexxActivation *context, /* execution context */
59  RexxExpressionStack *s) /* current expression stack */
60 /******************************************************************************/
61 /* Function: Initialize a parse target object */
62 /******************************************************************************/
63 {
64  this->translate = _translate; /* save the translation flag */
65  this->arglist = _arglist; /* we have an array of strings */
66  this->argcount = _argcount;
67  this->string = (RexxString *)_string; /* save the string also */
68  this->next_argument = 1; /* start with the first argument */
69  this->stack = s; // save the expression stack for saving object references in
70  this->stackTop = s->location(); // save the stack top for resets
71  this->next(context); /* go perform needed resets */
72 }
73 
75  RexxActivation *context) /* current execution context */
76 /******************************************************************************/
77 /* Function: Step to the "next" string to parse, resetting all of the */
78 /* cursor movement values. */
79 /******************************************************************************/
80 {
81  if (this->arglist != OREF_NULL) /* have an argument list? */
82  {
83  /* beyond the array bounds? */
84  if (this->next_argument > this->argcount)
85  {
86  this->string = OREF_NULLSTRING; /* just use a null string */
87  }
88  else
89  {
90  /* get the first element */
91  this->string = (RexxString *)this->arglist[this->next_argument - 1];
92  if (this->string == OREF_NULL) /* omitted argument? */
93  {
94  this->string = OREF_NULLSTRING;/* use the null string */
95  }
96  }
97  }
98  else
99  {
100  if (this->next_argument != 1) /* beyond the first argument */
101  this->string = OREF_NULLSTRING; /* just use a null string */
102  }
103  this->next_argument++; /* bump the argument position */
104  /* make sure this is a string */
105  this->string = (RexxString *)REQUEST_STRING(this->string);
106  if (this->translate == parse_upper) /* need to uppercase? */
107  {
108  /* fold it up */
109  this->string = this->string->upper();
110  }
111  /* need to lowercase? */
112  else if (this->translate == parse_lower)
113  {
114  /* down we go */
115  this->string = this->string->lower();
116  }
117 
118  // reset the stack to the entry top, and push this value on to protect it.
119  this->stack->setTop(this->stackTop);
120  this->stack->push(string);
121  // if tracing results or intermediates, show the string being parsed.
122  context->traceResult(string);
123  this->start = 0; /* start at the beginning */
124  this->pattern_end = 0; /* no pattern done yet */
125  this->pattern_start = 0; /* save the pattern start */
126  /* save the over all length */
127  this->string_length = this->string->getCLength();
128  this->subcurrent = 0; /* no sub piece to process yet */
129 }
130 
132 /******************************************************************************/
133 /* Function: Move the current cursor to the string end */
134 /******************************************************************************/
135 {
136  this->start = this->pattern_end; /* start from end of last pattern */
137  /* pattern at the end too */
138  this->pattern_end = this->string_length;
139  /* no pattern length either */
140  this->pattern_start = this->string_length;
141  this->end = this->string_length; /* string end is at end also */
142  /* save the over all length */
143  /* no sub piece to process yet */
144  this->subcurrent = this->start; /* set starting point */
145 }
146 
148  stringsize_t offset) /* offset to move */
149 /******************************************************************************/
150 /* Arguments: distance to move the parse pointer */
151 /******************************************************************************/
152 {
153  this->start = this->pattern_start; /* start position is last position */
154  this->end = this->start + offset; /* set the end position */
155  if (this->end >= this->string_length)/* take us past the end? */
156  {
157  this->end = this->string_length; /* just use the end position */
158  }
159  if (this->end <= this->start) /* no forward movement? */
160  {
161  this->end = this->string_length; /* just use the end position */
162  this->pattern_start = this->start; /* start here for the next one */
163  }
164  else /* normal movement */
165  {
166  this->pattern_start = this->end; /* this is new start position */
167  }
168  /* and have a zero length pattern */
169  this->pattern_end = this->pattern_start;
170  this->subcurrent = this->start; /* set the subpiece pointer */
171 }
172 
174  stringsize_t offset) /* offset to move */
175 /******************************************************************************/
176 /* Arguments: distance to move the parse pointer */
177 /******************************************************************************/
178 {
179  this->start = this->pattern_start; /* start position is last position */
180  this->end = this->start + offset; /* set the end position */
181  if (this->end >= this->string_length)/* take us past the end? */
182  {
183  this->end = this->string_length; /* just use the end position */
184  }
185  this->pattern_start = this->end; /* this is new start position */
186  /* and have a zero length pattern */
187  this->pattern_end = this->pattern_start;
188  this->subcurrent = this->start; /* set the subpiece pointer */
189 }
190 
191 
193  stringsize_t offset) /* offset to move */
194 /******************************************************************************/
195 /* Arguments: new parse position */
196 /******************************************************************************/
197 {
198  if (offset > 0) /* positive offset? */
199  {
200  offset--; /* make origin zero */
201  }
202  this->start = this->pattern_end; /* start position is last position */
203  if ((size_t)offset <= this->start) /* backward movement? */
204  {
205  this->end = this->string_length; /* matches to the end */
206  this->pattern_start = offset; /* pattern start is actual position */
207  }
208  else /* forward movement */
209  {
210  this->end = offset; /* use the specified position */
211  /* take us past the end? */
212  if (this->end >= this->string_length)
213  {
214  /* just use the end position */
215  this->end = this->string_length;
216  }
217  this->pattern_start = this->end; /* this is new start position */
218  }
219  /* and have a zero length pattern */
220  this->pattern_end = this->pattern_start;
221  this->subcurrent = this->start; /* set the subpiece pointer */
222 }
223 
225  stringsize_t offset) /* offset to move */
226 /******************************************************************************/
227 /* Arguments: distance to move the parse pointer */
228 /******************************************************************************/
229 {
230  this->start = this->pattern_start; /* start position is last position */
231  this->end = this->string_length; /* negatives always use to the end */
232  /* go past start of string? */
233  if (offset > this->pattern_start)
234  {
235  this->pattern_start = 0; /* this resets to the start */
236  }
237  else
238  {
239  this->pattern_start -= offset; /* just back up */
240  }
241  /* and have a zero length pattern */
242  this->pattern_end = this->pattern_start;
243  this->subcurrent = this->start; /* set the subpiece pointer */
244 }
245 
246 
248  stringsize_t offset) /* offset to move */
249 /******************************************************************************/
250 /* Arguments: distance to move the parse pointer */
251 /******************************************************************************/
252 {
253  this->start = this->pattern_start; /* start position is last position */
254  this->end = this->string_length; /* negatives always use to the end */
255  /* go past start of string? */
256  if (offset > this->pattern_start)
257  {
258  this->start = 0;
259  }
260  else
261  {
262  this->start = this->pattern_start - offset;
263  }
264  this->end = this->pattern_start; // the end is the starting location
265  /* and have a zero length pattern */
266  this->pattern_end = this->pattern_start;
267  this->subcurrent = this->start; /* set the subpiece pointer */
268 }
269 
270 
272  RexxString *needle) /* target search string */
273 /******************************************************************************/
274 /* Arguments: target location string */
275 /******************************************************************************/
276 {
277  /* start position for strings is the */
278  this->start = this->pattern_end; /* end of the last pattern */
279  /* search for the string trigger */
280  this->end = this->string->pos(needle, this->start);
281  if (this->end == 0) /* not found? */
282  {
283  this->end = this->string_length; /* that is the end position */
284  /* next pattern is end also */
285  this->pattern_start = this->string_length;
286  /* and the end pattern is also there */
287  this->pattern_end = this->string_length;
288  }
289  else
290  {
291  this->end--; /* convert to origin zero */
292  this->pattern_start = this->end; /* this is the starting point */
293  /* end is start + trigger length */
294  this->pattern_end = this->pattern_start + needle->getCLength();
295  }
296  this->subcurrent = this->start; /* set the subpiece pointer */
297 }
298 
300  RexxString *needle) /* target search string */
301 /******************************************************************************/
302 /* Arguments: target location string */
303 /******************************************************************************/
304 {
305  /* start position for strings is the */
306  this->start = this->pattern_end; /* end of the last pattern */
307  /* search for the string trigger */
308  this->end = this->string->caselessPos(needle, this->start);
309  if (this->end == 0) /* not found? */
310  {
311  this->end = this->string_length; /* that is the end position */
312  /* next pattern is end also */
313  this->pattern_start = this->string_length;
314  /* and the end pattern is also there */
315  this->pattern_end = this->string_length;
316  }
317  else
318  {
319  this->end--; /* convert to origin zero */
320  this->pattern_start = this->end; /* this is the starting point */
321  /* end is start + trigger length */
322  this->pattern_end = this->pattern_start + needle->getCLength();
323  }
324  this->subcurrent = this->start; /* set the subpiece pointer */
325 }
326 
328 /******************************************************************************/
329 /* Returned: Next word extracted from parsed substring */
330 /******************************************************************************/
331 {
332  RexxString *word; /* extracted word */
333  sizeC_t length; /* word length */
334  const char *scan; /* scan pointer */
335  const char *endScan; /* end of string location */
336 
337  if (this->subcurrent >= this->end) /* already used up? */
338  {
339  word = OREF_NULLSTRING; /* just return a null string */
340  }
341  else /* need to scan off a word */
342  {
343  /* point to the current position */
344  scan = this->string->getStringData() + size_v(this->subcurrent); // todo m17n
345  /* and the scan end point */
346  endScan = this->string->getStringData() + size_v(this->end); // todo m17n
347  /* NOTE: All string objects have a terminating NULL, so the */
348  /* scan for nonblanks is guaranteed to stop before getting into */
349  /* trouble, which eliminates the need to check against the */
350  /* length */
351  while (*scan == ' ' || *scan == '\t')
352  {
353  scan++; /* step for each match found */
354  }
355  /* set the new location */
356  this->subcurrent = scan - this->string->getStringData();
357  if (this->subcurrent >= this->end) /* already used up? */
358  {
359  word = OREF_NULLSTRING; /* just return a null string */
360  }
361  else /* have a real word */
362  {
363  /* look for the next blank */
364  endScan = NULL;
365  const char *scanner = scan;
366  const char *endPosition = string->getStringData() + size_v(this->end); // todo m17n
367  while (scanner < endPosition)
368  {
369  if (*scanner == ' ' || *scanner == '\t')
370  {
371  endScan = scanner;
372  break;
373  }
374  scanner++;
375  }
376  if (endScan == NULL) /* no match? */
377  {
378  /* calculate the length */
379  length = this->end - this->subcurrent;
380  this->subcurrent = this->end; /* use the rest of it */
381  }
382  else
383  {
384  /* set the new location */
385  this->subcurrent = endScan - this->string->getStringData();
386  length = endScan - scan; /* calculate from the pointers */
387  }
388  /* step past terminating blank...note*/
389  /* that this is done unconditionally,*/
390  /* but safely, since the check at the*/
391  /* start will catch the out of bounds*/
392  this->subcurrent++; /* condition */
393  /* this the entire string? */
394  if (length == this->string_length)
395  {
396  word = this->string; /* just return it directly */
397  }
398  else
399  {
400  /* extract the subpiece */
401  word = new_string(scan, size_v(length)); // todo m17n
402  }
403  }
404  }
405  return word; /* give this word back */
406 }
407 
409 /******************************************************************************/
410 /* Returned: Next word extracted from parsed substring */
411 /******************************************************************************/
412 {
413  const char *scan; /* scan pointer */
414  const char *endScan; /* end of string location */
415 
416  if (this->subcurrent < this->end) /* something left? */
417  {
418  /* point to the current position */
419  scan = this->string->getStringData() + size_v(this->subcurrent); // todo m17n
420  /* and the scan end point */
421  endScan = this->string->getStringData() + size_v(this->end); // todo m17n
422  /* NOTE: All string objects have a terminating NULL, so the */
423  /* scan for nonblanks is guaranteed to stop before getting into */
424  /* trouble, which eliminates the need to check against the */
425  /* length */
426  while (*scan == ' ' || *scan == '\t')
427  {
428  scan++; /* step for each match found */
429  }
430  /* set the new location */
431  this->subcurrent = scan - this->string->getStringData();
432  if (this->subcurrent < this->end)/* something left over? */
433  {
434  /* look for the next blank */
435  endScan = NULL;
436  const char *scanner = scan;
437  const char *endPosition = string->getStringData() + size_v(this->end); // todo m17n
438  while (scanner < endPosition)
439  {
440  if (*scanner == ' ' || *scanner == '\t')
441  {
442  endScan = scanner;
443  break;
444  }
445  scanner++;
446  }
447  if (endScan == NULL) /* no match? */
448  {
449  this->subcurrent = this->end; /* use the rest of it */
450  }
451  else
452  {
453  /* set the new location */
454  this->subcurrent = endScan - this->string->getStringData();
455  }
456  /* step past terminating blank...note*/
457  /* that this is done unconditionally,*/
458  /* but safely, since the check at the*/
459  /* start will catch the out of bounds*/
460  this->subcurrent++; /* condition */
461  }
462  }
463 }
464 
466 /******************************************************************************/
467 /* Returned: Remaining portion of parsed substring */
468 /******************************************************************************/
469 {
470  RexxString *word; /* extracted word */
471  sizeC_t length; /* length to extract */
472 
473  if (this->subcurrent >= this->end) /* already used up? */
474  {
475  word = OREF_NULLSTRING; /* just return a null string */
476  }
477  else /* extract the remaining piece */
478  {
479  /* calculate the length */
480  length = this->end - this->subcurrent;
481  if (length == this->string_length) /* this the entire string? */
482  {
483  word = this->string; /* just return it directly */
484  }
485  else /* need to extract a piece */
486  {
487  word = this->string->extractC(this->subcurrent, length);
488  }
489  this->subcurrent = this->end; /* eat the remainder piece */
490  }
491  return word; /* give this word back */
492 }
#define parse_lower
#define parse_upper
#define OREF_NULL
Definition: RexxCore.h:60
RexxString * REQUEST_STRING(RexxObject *object)
Definition: RexxCore.h:283
RexxString * new_string(const char *s, stringsizeB_t bl, sizeC_t cl=-1)
void traceResult(RexxObject *v)
void push(RexxObject *value)
void setTop(size_t v)
RexxString * extractC(sizeC_t offset, sizeC_t sublength)
const char * getStringData()
RexxString * lower()
sizeC_t getCLength()
RexxString * upper()
void search(RexxString *)
void backward(stringsize_t)
RexxString * string
Definition: ParseTarget.hpp:71
stringsizeC_t start
Definition: ParseTarget.hpp:76
stringsizeC_t end
Definition: ParseTarget.hpp:77
void absolute(stringsize_t)
void backwardLength(stringsize_t)
RexxString * getWord()
stringsizeC_t subcurrent
Definition: ParseTarget.hpp:81
stringsizeC_t pattern_end
Definition: ParseTarget.hpp:79
void init(RexxObject *, RexxObject **, size_t, size_t, bool, RexxActivation *, RexxExpressionStack *)
Definition: ParseTarget.cpp:52
size_t stackTop
Definition: ParseTarget.hpp:74
RexxString * remainder()
stringsizeC_t string_length
Definition: ParseTarget.hpp:78
size_t argcount
Definition: ParseTarget.hpp:75
size_t next_argument
Definition: ParseTarget.hpp:82
void forwardLength(stringsize_t)
RexxObject ** arglist
Definition: ParseTarget.hpp:72
void caselessSearch(RexxString *)
void forward(stringsize_t)
size_t translate
Definition: ParseTarget.hpp:83
RexxExpressionStack * stack
Definition: ParseTarget.hpp:73
void next(RexxActivation *)
Definition: ParseTarget.cpp:74
void moveToEnd()
stringsizeC_t pattern_start
Definition: ParseTarget.hpp:80
void skipWord()
stringsizeC_t sizeC_t
Definition: rexx.h:242
#define size_v(X)
Definition: rexx.h:237
size_t stringsize_t
Definition: rexx.h:228