0ccc8305eda657a067901d2f9ab4e141171bec11
[p5sagit/p5-mst-13.2.git] / regexec.c
1 /* NOTE: this is derived from Henry Spencer's regexp code, and should not
2  * confused with the original package (see point 3 below).  Thanks, Henry!
3  */
4
5 /* Additional note: this code is very heavily munged from Henry's version
6  * in places.  In some spots I've traded clarity for efficiency, so don't
7  * blame Henry for some of the lack of readability.
8  */
9
10 /* $Header: regexec.c,v 3.0.1.2 89/12/21 20:16:27 lwall Locked $
11  *
12  * $Log:        regexec.c,v $
13  * Revision 3.0.1.2  89/12/21  20:16:27  lwall
14  * patch7: certain patterns didn't match correctly at end of string
15  * 
16  * Revision 3.0.1.1  89/11/11  04:52:04  lwall
17  * patch2: /\b$foo/ didn't work
18  * 
19  * Revision 3.0  89/10/18  15:22:53  lwall
20  * 3.0 baseline
21  * 
22  */
23
24 /*
25  * regcomp and regexec -- regsub and regerror are not used in perl
26  *
27  *      Copyright (c) 1986 by University of Toronto.
28  *      Written by Henry Spencer.  Not derived from licensed software.
29  *
30  *      Permission is granted to anyone to use this software for any
31  *      purpose on any computer system, and to redistribute it freely,
32  *      subject to the following restrictions:
33  *
34  *      1. The author is not responsible for the consequences of use of
35  *              this software, no matter how awful, even if they arise
36  *              from defects in it.
37  *
38  *      2. The origin of this software must not be misrepresented, either
39  *              by explicit claim or by omission.
40  *
41  *      3. Altered versions must be plainly marked as such, and must not
42  *              be misrepresented as being the original software.
43  *
44  ****    Alterations to Henry's code are...
45  ****
46  ****    Copyright (c) 1989, Larry Wall
47  ****
48  ****    You may distribute under the terms of the GNU General Public License
49  ****    as specified in the README file that comes with the perl 3.0 kit.
50  *
51  * Beware that some of this code is subtly aware of the way operator
52  * precedence is structured in regular expressions.  Serious changes in
53  * regular-expression syntax might require a total rethink.
54  */
55 #include "EXTERN.h"
56 #include "perl.h"
57 #include "regcomp.h"
58
59 #ifndef STATIC
60 #define STATIC  static
61 #endif
62
63 #ifdef DEBUGGING
64 int regnarrate = 0;
65 #endif
66
67 /*
68  * regexec and friends
69  */
70
71 /*
72  * Global work variables for regexec().
73  */
74 static char *regprecomp;
75 static char *reginput;          /* String-input pointer. */
76 static char *regbol;            /* Beginning of input, for ^ check. */
77 static char *regeol;            /* End of input, for $ check. */
78 static char **regstartp;        /* Pointer to startp array. */
79 static char **regendp;          /* Ditto for endp. */
80 static char *reglastparen;      /* Similarly for lastparen. */
81 static char *regtill;
82
83 static char *regmystartp[10];   /* For remembering backreferences. */
84 static char *regmyendp[10];
85
86 /*
87  * Forwards.
88  */
89 STATIC int regtry();
90 STATIC int regmatch();
91 STATIC int regrepeat();
92
93 extern int multiline;
94
95 /*
96  - regexec - match a regexp against a string
97  */
98 int
99 regexec(prog, stringarg, strend, strbeg, minend, screamer, safebase)
100 register regexp *prog;
101 char *stringarg;
102 register char *strend;  /* pointer to null at end of string */
103 char *strbeg;   /* real beginning of string */
104 int minend;     /* end of match must be at least minend after stringarg */
105 STR *screamer;
106 int safebase;   /* no need to remember string in subbase */
107 {
108         register char *s;
109         register int i;
110         register char *c;
111         register char *string = stringarg;
112         register int tmp;
113         int minlen = 0;         /* must match at least this many chars */
114         int dontbother = 0;     /* how many characters not to try at end */
115         int beginning = (string == strbeg);     /* is ^ valid at stringarg? */
116
117         /* Be paranoid... */
118         if (prog == NULL || string == NULL) {
119                 fatal("NULL regexp parameter");
120                 return(0);
121         }
122
123         regprecomp = prog->precomp;
124         /* Check validity of program. */
125         if (UCHARAT(prog->program) != MAGIC) {
126                 FAIL("corrupted regexp program");
127         }
128
129         if (prog->do_folding) {
130                 safebase = FALSE;
131                 i = strend - string;
132                 New(1101,c,i+1,char);
133                 (void)bcopy(string, c, i+1);
134                 string = c;
135                 strend = string + i;
136                 for (s = string; s < strend; s++)
137                         if (isupper(*s))
138                                 *s = tolower(*s);
139         }
140
141         /* If there is a "must appear" string, look for it. */
142         s = string;
143         if (prog->regmust != Nullstr) {
144                 if (beginning && screamer) {
145                         if (screamfirst[prog->regmust->str_rare] >= 0)
146                                 s = screaminstr(screamer,prog->regmust);
147                         else
148                                 s = Nullch;
149                 }
150 #ifndef lint
151                 else
152                         s = fbminstr((unsigned char*)s, (unsigned char*)strend,
153                             prog->regmust);
154 #endif
155                 if (!s) {
156                         ++prog->regmust->str_u.str_useful;      /* hooray */
157                         goto phooey;    /* not present */
158                 }
159                 else if (prog->regback >= 0) {
160                         s -= prog->regback;
161                         if (s < string)
162                             s = string;
163                         minlen = prog->regback + prog->regmust->str_cur;
164                 }
165                 else if (--prog->regmust->str_u.str_useful < 0) { /* boo */
166                         str_free(prog->regmust);
167                         prog->regmust = Nullstr;        /* disable regmust */
168                         s = string;
169                 }
170                 else {
171                         s = string;
172                         minlen = prog->regmust->str_cur;
173                 }
174         }
175
176         /* Mark beginning of line for ^ . */
177         if (beginning)
178                 regbol = string;
179         else
180                 regbol = NULL;
181
182         /* Mark end of line for $ (and such) */
183         regeol = strend;
184
185         /* see how far we have to get to not match where we matched before */
186         regtill = string+minend;
187
188         /* Simplest case:  anchored match need be tried only once. */
189         /*  [unless multiline is set] */
190         if (prog->reganch) {
191                 if (regtry(prog, string))
192                         goto got_it;
193                 else if (multiline) {
194                         if (minlen)
195                             dontbother = minlen - 1;
196                         strend -= dontbother;
197                         /* for multiline we only have to try after newlines */
198                         if (s > string)
199                             s--;
200                         for (; s < strend; s++) {
201                             if (*s == '\n') {
202                                 if (++s < strend && regtry(prog, s))
203                                     goto got_it;
204                             }
205                         }
206                 }
207                 goto phooey;
208         }
209
210         /* Messy cases:  unanchored match. */
211         if (prog->regstart) {
212                 /* We know what string it must start with. */
213                 if (prog->regstart->str_pok == 3) {
214 #ifndef lint
215                     while ((s = fbminstr((unsigned char*)s,
216                       (unsigned char*)strend, prog->regstart)) != NULL)
217 #else
218                     while (s = Nullch)
219 #endif
220                     {
221                             if (regtry(prog, s))
222                                     goto got_it;
223                             s++;
224                     }
225                 }
226                 else {
227                     c = prog->regstart->str_ptr;
228                     while ((s = ninstr(s, strend,
229                       c, c + prog->regstart->str_cur )) != NULL) {
230                             if (regtry(prog, s))
231                                     goto got_it;
232                             s++;
233                     }
234                 }
235                 goto phooey;
236         }
237         if (c = prog->regstclass) {
238                 if (minlen)
239                     dontbother = minlen - 1;
240                 strend -= dontbother;   /* don't bother with what can't match */
241                 /* We know what class it must start with. */
242                 switch (OP(c)) {
243                 case ANYOF: case ANYBUT:
244                     c = OPERAND(c);
245                     while (s < strend) {
246                             i = *s;
247                             if (!(c[i >> 3] & (1 << (i&7))))
248                                     if (regtry(prog, s))
249                                             goto got_it;
250                             s++;
251                     }
252                     break;
253                 case BOUND:
254                     if (minlen)
255                         dontbother++,strend--;
256                     if (s != string) {
257                         i = s[-1];
258                         tmp = (isalpha(i) || isdigit(i) || i == '_');
259                     }
260                     else
261                         tmp = 0;        /* assume not alphanumeric */
262                     while (s < strend) {
263                             i = *s;
264                             if (tmp != (isalpha(i) || isdigit(i) || i == '_')) {
265                                     tmp = !tmp;
266                                     if (regtry(prog, s))
267                                             goto got_it;
268                             }
269                             s++;
270                     }
271                     if ((minlen || tmp) && regtry(prog,s))
272                             goto got_it;
273                     break;
274                 case NBOUND:
275                     if (minlen)
276                         dontbother++,strend--;
277                     if (s != string) {
278                         i = s[-1];
279                         tmp = (isalpha(i) || isdigit(i) || i == '_');
280                     }
281                     else
282                         tmp = 0;        /* assume not alphanumeric */
283                     while (s < strend) {
284                             i = *s;
285                             if (tmp != (isalpha(i) || isdigit(i) || i == '_'))
286                                     tmp = !tmp;
287                             else if (regtry(prog, s))
288                                     goto got_it;
289                             s++;
290                     }
291                     if ((minlen || !tmp) && regtry(prog,s))
292                             goto got_it;
293                     break;
294                 case ALNUM:
295                     while (s < strend) {
296                             i = *s;
297                             if (isalpha(i) || isdigit(i) || i == '_')
298                                     if (regtry(prog, s))
299                                             goto got_it;
300                             s++;
301                     }
302                     break;
303                 case NALNUM:
304                     while (s < strend) {
305                             i = *s;
306                             if (!isalpha(i) && !isdigit(i) && i != '_')
307                                     if (regtry(prog, s))
308                                             goto got_it;
309                             s++;
310                     }
311                     break;
312                 case SPACE:
313                     while (s < strend) {
314                             if (isspace(*s))
315                                     if (regtry(prog, s))
316                                             goto got_it;
317                             s++;
318                     }
319                     break;
320                 case NSPACE:
321                     while (s < strend) {
322                             if (!isspace(*s))
323                                     if (regtry(prog, s))
324                                             goto got_it;
325                             s++;
326                     }
327                     break;
328                 case DIGIT:
329                     while (s < strend) {
330                             if (isdigit(*s))
331                                     if (regtry(prog, s))
332                                             goto got_it;
333                             s++;
334                     }
335                     break;
336                 case NDIGIT:
337                     while (s < strend) {
338                             if (!isdigit(*s))
339                                     if (regtry(prog, s))
340                                             goto got_it;
341                             s++;
342                     }
343                     break;
344                 }
345         }
346         else {
347                 if (minlen)
348                     dontbother = minlen - 1;
349                 strend -= dontbother;
350                 /* We don't know much -- general case. */
351                 do {
352                         if (regtry(prog, s))
353                                 goto got_it;
354                 } while (s++ < strend);
355         }
356
357         /* Failure. */
358         goto phooey;
359
360     got_it:
361         if ((!safebase && (prog->nparens || sawampersand)) || prog->do_folding){
362                 strend += dontbother;   /* uncheat */
363                 if (safebase)                   /* no need for $digit later */
364                     s = strbeg;
365                 else if (strbeg != prog->subbase) {
366                     i = strend - string + (stringarg - strbeg);
367                     s = nsavestr(strbeg,i);     /* so $digit will work later */
368                     if (prog->subbase)
369                             Safefree(prog->subbase);
370                     prog->subbase = s;
371                 }
372                 else
373                     s = prog->subbase;
374                 s += (stringarg - strbeg);
375                 for (i = 0; i <= prog->nparens; i++) {
376                         if (prog->endp[i]) {
377                             prog->startp[i] = s + (prog->startp[i] - string);
378                             prog->endp[i] = s + (prog->endp[i] - string);
379                         }
380                 }
381                 if (prog->do_folding)
382                         Safefree(string);
383         }
384         return(1);
385
386     phooey:
387         if (prog->do_folding)
388                 Safefree(string);
389         return(0);
390 }
391
392 /*
393  - regtry - try match at specific point
394  */
395 static int                      /* 0 failure, 1 success */
396 regtry(prog, string)
397 regexp *prog;
398 char *string;
399 {
400         register int i;
401         register char **sp;
402         register char **ep;
403
404         reginput = string;
405         regstartp = prog->startp;
406         regendp = prog->endp;
407         reglastparen = &prog->lastparen;
408         prog->lastparen = 0;
409
410         sp = prog->startp;
411         ep = prog->endp;
412         if (prog->nparens) {
413                 for (i = NSUBEXP; i > 0; i--) {
414                         *sp++ = NULL;
415                         *ep++ = NULL;
416                 }
417         }
418         if (regmatch(prog->program + 1) && reginput >= regtill) {
419                 prog->startp[0] = string;
420                 prog->endp[0] = reginput;
421                 return(1);
422         } else
423                 return(0);
424 }
425
426 /*
427  - regmatch - main matching routine
428  *
429  * Conceptually the strategy is simple:  check to see whether the current
430  * node matches, call self recursively to see whether the rest matches,
431  * and then act accordingly.  In practice we make some effort to avoid
432  * recursion, in particular by going through "ordinary" nodes (that don't
433  * need to know whether the rest of the match failed) by a loop instead of
434  * by recursion.
435  */
436 /* [lwall] I've hoisted the register declarations to the outer block in order to
437  * maybe save a little bit of pushing and popping on the stack.  It also takes
438  * advantage of machines that use a register save mask on subroutine entry.
439  */
440 static int                      /* 0 failure, 1 success */
441 regmatch(prog)
442 char *prog;
443 {
444         register char *scan;    /* Current node. */
445         char *next;             /* Next node. */
446         register int nextchar;
447         register int n;         /* no or next */
448         register int ln;        /* len or last */
449         register char *s;       /* operand or save */
450         register char *locinput = reginput;
451
452         nextchar = *locinput;
453         scan = prog;
454 #ifdef DEBUGGING
455         if (scan != NULL && regnarrate)
456                 fprintf(stderr, "%s(\n", regprop(scan));
457 #endif
458         while (scan != NULL) {
459 #ifdef DEBUGGING
460                 if (regnarrate)
461                         fprintf(stderr, "%s...\n", regprop(scan));
462 #endif
463
464 #ifdef REGALIGN
465                 next = scan + NEXT(scan);
466                 if (next == scan)
467                     next = NULL;
468 #else
469                 next = regnext(scan);
470 #endif
471
472                 switch (OP(scan)) {
473                 case BOL:
474                         if (locinput == regbol ||
475                             ((nextchar || locinput < regeol) &&
476                               locinput[-1] == '\n') )
477                         {
478                                 regtill--;
479                                 break;
480                         }
481                         return(0);
482                 case EOL:
483                         if ((nextchar || locinput < regeol) && nextchar != '\n')
484                                 return(0);
485                         regtill--;
486                         break;
487                 case ANY:
488                         if ((nextchar == '\0' && locinput >= regeol) ||
489                           nextchar == '\n')
490                                 return(0);
491                         nextchar = *++locinput;
492                         break;
493                 case EXACTLY:
494                         s = OPERAND(scan);
495                         ln = *s++;
496                         /* Inline the first character, for speed. */
497                         if (*s != nextchar)
498                                 return(0);
499                         if (locinput + ln > regeol)
500                                 return 0;
501                         if (ln > 1 && bcmp(s, locinput, ln) != 0)
502                                 return(0);
503                         locinput += ln;
504                         nextchar = *locinput;
505                         break;
506                 case ANYOF:
507                 case ANYBUT:
508                         s = OPERAND(scan);
509                         if (nextchar < 0)
510                                 nextchar = UCHARAT(locinput);
511                         if (s[nextchar >> 3] & (1 << (nextchar&7)))
512                                 return(0);
513                         nextchar = *++locinput;
514                         if (!nextchar && locinput > regeol)
515                                 return 0;
516                         break;
517                 case ALNUM:
518                         if (!nextchar)
519                                 return(0);
520                         if (!isalpha(nextchar) && !isdigit(nextchar) &&
521                           nextchar != '_')
522                                 return(0);
523                         nextchar = *++locinput;
524                         break;
525                 case NALNUM:
526                         if (!nextchar && locinput >= regeol)
527                                 return(0);
528                         if (isalpha(nextchar) || isdigit(nextchar) ||
529                           nextchar == '_')
530                                 return(0);
531                         nextchar = *++locinput;
532                         break;
533                 case NBOUND:
534                 case BOUND:
535                         if (locinput == regbol) /* was last char in word? */
536                                 ln = 0;
537                         else 
538                                 ln = (isalpha(locinput[-1]) ||
539                                      isdigit(locinput[-1]) ||
540                                      locinput[-1] == '_' );
541                         n = (isalpha(nextchar) || isdigit(nextchar) ||
542                             nextchar == '_' );  /* is next char in word? */
543                         if ((ln == n) == (OP(scan) == BOUND))
544                                 return(0);
545                         break;
546                 case SPACE:
547                         if (!nextchar && locinput >= regeol)
548                                 return(0);
549                         if (!isspace(nextchar))
550                                 return(0);
551                         nextchar = *++locinput;
552                         break;
553                 case NSPACE:
554                         if (!nextchar)
555                                 return(0);
556                         if (isspace(nextchar))
557                                 return(0);
558                         nextchar = *++locinput;
559                         break;
560                 case DIGIT:
561                         if (!isdigit(nextchar))
562                                 return(0);
563                         nextchar = *++locinput;
564                         break;
565                 case NDIGIT:
566                         if (!nextchar && locinput >= regeol)
567                                 return(0);
568                         if (isdigit(nextchar))
569                                 return(0);
570                         nextchar = *++locinput;
571                         break;
572                 case REF:
573                 case REF+1:
574                 case REF+2:
575                 case REF+3:
576                 case REF+4:
577                 case REF+5:
578                 case REF+6:
579                 case REF+7:
580                 case REF+8:
581                 case REF+9:
582                         n = OP(scan) - REF;
583                         s = regmystartp[n];
584                         if (!s)
585                             return(0);
586                         if (!regmyendp[n])
587                             return(0);
588                         if (s == regmyendp[n])
589                             break;
590                         /* Inline the first character, for speed. */
591                         if (*s != nextchar)
592                                 return(0);
593                         ln = regmyendp[n] - s;
594                         if (locinput + ln > regeol)
595                                 return 0;
596                         if (ln > 1 && bcmp(s, locinput, ln) != 0)
597                                 return(0);
598                         locinput += ln;
599                         nextchar = *locinput;
600                         break;
601
602                 case NOTHING:
603                         break;
604                 case BACK:
605                         break;
606                 case OPEN+1:
607                 case OPEN+2:
608                 case OPEN+3:
609                 case OPEN+4:
610                 case OPEN+5:
611                 case OPEN+6:
612                 case OPEN+7:
613                 case OPEN+8:
614                 case OPEN+9:
615                         n = OP(scan) - OPEN;
616                         reginput = locinput;
617
618                         regmystartp[n] = locinput;      /* for REF */
619                         if (regmatch(next)) {
620                                 /*
621                                  * Don't set startp if some later
622                                  * invocation of the same parentheses
623                                  * already has.
624                                  */
625                                 if (regstartp[n] == NULL)
626                                         regstartp[n] = locinput;
627                                 return(1);
628                         } else
629                                 return(0);
630                         /* NOTREACHED */
631                 case CLOSE+1:
632                 case CLOSE+2:
633                 case CLOSE+3:
634                 case CLOSE+4:
635                 case CLOSE+5:
636                 case CLOSE+6:
637                 case CLOSE+7:
638                 case CLOSE+8:
639                 case CLOSE+9: {
640                                 n = OP(scan) - CLOSE;
641                                 reginput = locinput;
642
643                                 regmyendp[n] = locinput;        /* for REF */
644                                 if (regmatch(next)) {
645                                         /*
646                                          * Don't set endp if some later
647                                          * invocation of the same parentheses
648                                          * already has.
649                                          */
650                                         if (regendp[n] == NULL) {
651                                                 regendp[n] = locinput;
652                                                 if (n > *reglastparen)
653                                                     *reglastparen = n;
654                                         }
655                                         return(1);
656                                 } else
657                                         return(0);
658                         }
659                         /*NOTREACHED*/
660                 case BRANCH: {
661                                 if (OP(next) != BRANCH)         /* No choice. */
662                                         next = NEXTOPER(scan);  /* Avoid recursion. */
663                                 else {
664                                         do {
665                                                 reginput = locinput;
666                                                 if (regmatch(NEXTOPER(scan)))
667                                                         return(1);
668 #ifdef REGALIGN
669                                                 if (n = NEXT(scan))
670                                                     scan += n;
671                                                 else
672                                                     scan = NULL;
673 #else
674                                                 scan = regnext(scan);
675 #endif
676                                         } while (scan != NULL && OP(scan) == BRANCH);
677                                         return(0);
678                                         /* NOTREACHED */
679                                 }
680                         }
681                         break;
682                 case STAR:
683                 case PLUS:
684                         /*
685                          * Lookahead to avoid useless match attempts
686                          * when we know what character comes next.
687                          */
688                         if (OP(next) == EXACTLY)
689                                 nextchar = *(OPERAND(next)+1);
690                         else
691                                 nextchar = -1000;
692                         ln = (OP(scan) == STAR) ? 0 : 1;
693                         reginput = locinput;
694                         n = regrepeat(NEXTOPER(scan));
695                         while (n >= ln) {
696                                 /* If it could work, try it. */
697                                 if (nextchar == -1000 || *reginput == nextchar)
698                                         if (regmatch(next))
699                                                 return(1);
700                                 /* Couldn't or didn't -- back up. */
701                                 n--;
702                                 reginput = locinput + n;
703                         }
704                         return(0);
705                 case END:
706                         reginput = locinput; /* put where regtry can find it */
707                         return(1);      /* Success! */
708                 default:
709                         printf("%x %d\n",scan,scan[1]);
710                         FAIL("regexp memory corruption");
711                 }
712
713                 scan = next;
714         }
715
716         /*
717          * We get here only if there's trouble -- normally "case END" is
718          * the terminating point.
719          */
720         FAIL("corrupted regexp pointers");
721         /*NOTREACHED*/
722 #ifdef lint
723         return 0;
724 #endif
725 }
726
727 /*
728  - regrepeat - repeatedly match something simple, report how many
729  */
730 /*
731  * [This routine now assumes that it will only match on things of length 1.
732  * That was true before, but now we assume scan - reginput is the count,
733  * rather than incrementing count on every character.]
734  */
735 static int
736 regrepeat(p)
737 char *p;
738 {
739         register char *scan;
740         register char *opnd;
741         register int c;
742         register char *loceol = regeol;
743
744         scan = reginput;
745         opnd = OPERAND(p);
746         switch (OP(p)) {
747         case ANY:
748                 while (scan < loceol && *scan != '\n')
749                         scan++;
750                 break;
751         case EXACTLY:           /* length of string is 1 */
752                 opnd++;
753                 while (scan < loceol && *opnd == *scan)
754                         scan++;
755                 break;
756         case ANYOF:
757         case ANYBUT:
758                 c = UCHARAT(scan);
759                 while (scan < loceol && !(opnd[c >> 3] & (1 << (c & 7)))) {
760                         scan++;
761                         c = UCHARAT(scan);
762                 }
763                 break;
764         case ALNUM:
765                 while (isalpha(*scan) || isdigit(*scan) || *scan == '_')
766                         scan++;
767                 break;
768         case NALNUM:
769                 while (scan < loceol && (!isalpha(*scan) && !isdigit(*scan) &&
770                   *scan != '_'))
771                         scan++;
772                 break;
773         case SPACE:
774                 while (scan < loceol && isspace(*scan))
775                         scan++;
776                 break;
777         case NSPACE:
778                 while (scan < loceol && !isspace(*scan))
779                         scan++;
780                 break;
781         case DIGIT:
782                 while (isdigit(*scan))
783                         scan++;
784                 break;
785         case NDIGIT:
786                 while (scan < loceol && !isdigit(*scan))
787                         scan++;
788                 break;
789         default:                /* Oh dear.  Called inappropriately. */
790                 FAIL("internal regexp foulup");
791                 /* NOTREACHED */
792         }
793
794         c = scan - reginput;
795         reginput = scan;
796
797         return(c);
798 }
799
800 /*
801  - regnext - dig the "next" pointer out of a node
802  *
803  * [Note, when REGALIGN is defined there are two places in regmatch()
804  * that bypass this code for speed.]
805  */
806 char *
807 regnext(p)
808 register char *p;
809 {
810         register int offset;
811
812         if (p == &regdummy)
813                 return(NULL);
814
815         offset = NEXT(p);
816         if (offset == 0)
817                 return(NULL);
818
819 #ifdef REGALIGN
820         return(p+offset);
821 #else
822         if (OP(p) == BACK)
823                 return(p-offset);
824         else
825                 return(p+offset);
826 #endif
827 }