/* expr.c - Don Yang (uguu.org) 03/13/04 */ /*@ -usedef @*/ #include #include #include #include static int GetN(char **p); static int SetMarker(char *str, int size, int dir, int *pos1, int *pos2, char *expr); int main(int argc, char **argv) { int size, left, right, i; if( argc < 4 ) return printf("%s \n", *argv); size = (int)strlen(argv[3]); left = 0; right = size - 1; printf("execute ^%s -> %d\n", argv[1], SetMarker(argv[3], size, 1, &left, &right, argv[1])); printf("execute $%s -> %d\n", argv[2], SetMarker(argv[3], size, -1, &right, &left, argv[2])); printf("cursor: %d / %d\n", left, right); (void)puts(argv[3]); for(i = 0; i < size; i++) { if( i == left ) (void)putchar(left == right ? '^' : '['); else if( i == right ) (void)putchar(']'); else (void)putchar(' '); } (void)putchar('\n'); return 0; } static int GetN(char **p) { int n; for(n = (int)*((*p)++) - (int)'0'; isdigit(**p); ++*p) n = n * 10 + (int)**p - (int)'0'; --*p; return n; } static int SetMarker(char *str, int size, int dir, int *pos1, int *pos2, char *expr) { #define MAX_NEST 8 char *paren[MAX_NEST], *p, *q; int repeat[MAX_NEST + 1], cursor, lastsearch, nest; cursor = *pos1; lastsearch = nest = 0; repeat[0] = 0; for(p = expr; *p != '\0'; p++) { switch( *p ) { /* Set current cursor position / direction */ case '^': cursor = 0; /*@fallthrough@*/ case '+': dir = 1; break; case '$': cursor = size - 1; /*@fallthrough@*/ case '-': dir = -1; break; /* Set other marker position */ case '@': *pos2 = cursor; break; /* Repeat expression */ case '(': if( nest >= MAX_NEST ) return 5; /* Error5: Nest level too deep */ paren[nest++] = p; repeat[nest] = 0; break; case ')': if( nest == 0 ) return 6; /* Error6: Unmatched parentheses */ nest--; if( repeat[nest] > 1 ) { /* Repeat */ assert(paren[nest] != NULL); p = paren[nest]; repeat[nest]--; nest++; } else if( repeat[nest] == 1 ) { /* End last iteration */ assert(isdigit(*(p + 1))); p++; (void)GetN(&p); repeat[nest]--; } else { /* Start repeat */ q = p + 1; if( !isdigit(*q) ) return 4; /* Error4: No repeat count */ if( (repeat[nest] = GetN(&q)) < 2 ) { p = q; repeat[nest] = 0; } else { p--; nest++; } } break; /* Move cursor */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': cursor += GetN(&p) * dir; if( cursor < 0 || cursor >= size ) return 3; /* Error3: Cursor moved out of range */ lastsearch = 0; break; /* Character search */ default: if( strchr("asdiASDI", *p) != NULL ) { /* Character class */ if( lastsearch == -(int)*p ) cursor += dir; switch( *p ) { #define CHARSEARCH(chartest) \ for(; cursor >= 0 && cursor < size; cursor += dir) \ { \ if( chartest(str[cursor]) ) \ break; \ } \ if( cursor < 0 || cursor >= size ) return 1; case 'a': CHARSEARCH(isalpha); break; case 's': CHARSEARCH(isspace); break; case 'd': CHARSEARCH(isdigit); break; case 'i': CHARSEARCH(isalnum); break; #undef CHARSEARCH #define CHARSEARCH(chartest) \ for(; cursor >= 0 && cursor < size; cursor += dir) \ { \ if( !chartest(str[cursor]) ) \ break; \ } \ if( cursor < 0 || cursor >= size ) return 1; case 'A': CHARSEARCH(isalpha); break; case 'S': CHARSEARCH(isspace); break; case 'D': CHARSEARCH(isdigit); break; case 'I': CHARSEARCH(isalnum); break; #undef CHARSEARCH default: assert(0); break; } lastsearch = -(int)*p; } else { /* Single character */ if( *p == '/' ) { if( *++p == '\0' ) return 2; /* Error2: "/" not followed by char */ } if( lastsearch == (int)*p ) cursor += dir; for(; cursor >= 0 && cursor < size; cursor += dir) { if( str[cursor] == *p ) break; } if( cursor < 0 || cursor >= size ) return 1; /* Error1: Search character not found */ lastsearch = (int)*p; } break; } } *pos1 = cursor; return 0; }