diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 1997-12-15 15:58:49 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 1997-12-15 15:58:49 -0200 |
commit | 82d09fbf0dbd5aee890f033b25b09dc48ce58a48 (patch) | |
tree | 7a77947d7efc3e8d1a128590588249278eb57d77 | |
parent | 9be85d164855e74140b9da0c55568d7b7bf49d8a (diff) | |
download | lua-82d09fbf0dbd5aee890f033b25b09dc48ce58a48.tar.gz lua-82d09fbf0dbd5aee890f033b25b09dc48ce58a48.tar.bz2 lua-82d09fbf0dbd5aee890f033b25b09dc48ce58a48.zip |
new structure for closures, without static variables.
-rw-r--r-- | lstrlib.c | 112 |
1 files changed, 62 insertions, 50 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstrlib.c,v 1.2 1997/11/26 18:53:45 roberto Exp roberto $ | 2 | ** $Id: lstrlib.c,v 1.3 1997/12/09 13:35:19 roberto Exp roberto $ |
3 | ** Standard library for strings and pattern-matching | 3 | ** Standard library for strings and pattern-matching |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -145,45 +145,47 @@ static void str_ascii (void) | |||
145 | 145 | ||
146 | #define MAX_CAPT 9 | 146 | #define MAX_CAPT 9 |
147 | 147 | ||
148 | static struct { | 148 | struct Capture { |
149 | char *init; | 149 | struct { |
150 | int len; /* -1 signals unfinished capture */ | 150 | char *init; |
151 | } capture[MAX_CAPT]; | 151 | int len; /* -1 signals unfinished capture */ |
152 | 152 | } capture[MAX_CAPT]; | |
153 | static int num_captures; /* only valid after a sucessful call to match */ | 153 | int level; /* total number of captures (finished or unfinished) */ |
154 | }; | ||
154 | 155 | ||
155 | 156 | ||
156 | #define ESC '%' | 157 | #define ESC '%' |
157 | #define SPECIALS "^$*?.([%-" | 158 | #define SPECIALS "^$*?.([%-" |
158 | 159 | ||
159 | 160 | ||
160 | static void push_captures (void) | 161 | static void push_captures (struct Capture *cap) |
161 | { | 162 | { |
162 | int i; | 163 | int i; |
163 | for (i=0; i<num_captures; i++) { | 164 | for (i=0; i<cap->level; i++) { |
164 | int l = capture[i].len; | 165 | int l = cap->capture[i].len; |
165 | char *buff = openspace(l+1); | 166 | char *buff = openspace(l+1); |
166 | if (l == -1) lua_error("unfinished capture"); | 167 | if (l == -1) lua_error("unfinished capture"); |
167 | strncpy(buff, capture[i].init, l); | 168 | strncpy(buff, cap->capture[i].init, l); |
168 | buff[l] = 0; | 169 | buff[l] = 0; |
169 | lua_pushstring(buff); | 170 | lua_pushstring(buff); |
170 | } | 171 | } |
171 | } | 172 | } |
172 | 173 | ||
173 | 174 | ||
174 | static int check_cap (int l, int level) | 175 | static int check_cap (int l, struct Capture *cap) |
175 | { | 176 | { |
176 | l -= '1'; | 177 | l -= '1'; |
177 | if (!(0 <= l && l < level && capture[l].len != -1)) | 178 | if (!(0 <= l && l < cap->level && cap->capture[l].len != -1)) |
178 | lua_error("invalid capture index"); | 179 | lua_error("invalid capture index"); |
179 | return l; | 180 | return l; |
180 | } | 181 | } |
181 | 182 | ||
182 | 183 | ||
183 | static int capture_to_close (int level) | 184 | static int capture_to_close (struct Capture *cap) |
184 | { | 185 | { |
186 | int level = cap->level; | ||
185 | for (level--; level>=0; level--) | 187 | for (level--; level>=0; level--) |
186 | if (capture[level].len == -1) return level; | 188 | if (cap->capture[level].len == -1) return level; |
187 | lua_error("invalid pattern capture"); | 189 | lua_error("invalid pattern capture"); |
188 | return 0; /* to avoid warnings */ | 190 | return 0; /* to avoid warnings */ |
189 | } | 191 | } |
@@ -269,15 +271,15 @@ static char *matchbalance (char *s, int b, int e) | |||
269 | } | 271 | } |
270 | 272 | ||
271 | 273 | ||
272 | static char *matchitem (char *s, char *p, int level, char **ep) | 274 | static char *matchitem (char *s, char *p, struct Capture *cap, char **ep) |
273 | { | 275 | { |
274 | if (*p == ESC) { | 276 | if (*p == ESC) { |
275 | p++; | 277 | p++; |
276 | if (isdigit((unsigned char)*p)) { /* capture */ | 278 | if (isdigit((unsigned char)*p)) { /* capture */ |
277 | int l = check_cap(*p, level); | 279 | int l = check_cap(*p, cap); |
278 | *ep = p+1; | 280 | *ep = p+1; |
279 | if (strncmp(capture[l].init, s, capture[l].len) == 0) | 281 | if (strncmp(cap->capture[l].init, s, cap->capture[l].len) == 0) |
280 | return s+capture[l].len; | 282 | return s+cap->capture[l].len; |
281 | else return NULL; | 283 | else return NULL; |
282 | } | 284 | } |
283 | else if (*p == 'b') { /* balanced string */ | 285 | else if (*p == 'b') { /* balanced string */ |
@@ -293,58 +295,61 @@ static char *matchitem (char *s, char *p, int level, char **ep) | |||
293 | } | 295 | } |
294 | 296 | ||
295 | 297 | ||
296 | static char *match (char *s, char *p, int level) | 298 | static char *match (char *s, char *p, struct Capture *cap) |
297 | { | 299 | { |
298 | init: /* using goto's to optimize tail recursion */ | 300 | init: /* using goto's to optimize tail recursion */ |
299 | switch (*p) { | 301 | switch (*p) { |
300 | case '(': /* start capture */ | 302 | case '(': { /* start capture */ |
301 | if (level >= MAX_CAPT) lua_error("too many captures"); | 303 | char *res; |
302 | capture[level].init = s; | 304 | if (cap->level >= MAX_CAPT) lua_error("too many captures"); |
303 | capture[level].len = -1; | 305 | cap->capture[cap->level].init = s; |
304 | level++; p++; goto init; /* return match(s, p+1, level); */ | 306 | cap->capture[cap->level].len = -1; |
307 | cap->level++; | ||
308 | if ((res=match(s, p+1, cap)) == NULL) /* match failed? */ | ||
309 | cap->level--; /* undo capture */ | ||
310 | return res; | ||
311 | } | ||
305 | case ')': { /* end capture */ | 312 | case ')': { /* end capture */ |
306 | int l = capture_to_close(level); | 313 | int l = capture_to_close(cap); |
307 | char *res; | 314 | char *res; |
308 | capture[l].len = s - capture[l].init; /* close capture */ | 315 | cap->capture[l].len = s - cap->capture[l].init; /* close capture */ |
309 | if ((res = match(s, p+1, level)) == NULL) /* match failed? */ | 316 | if ((res = match(s, p+1, cap)) == NULL) /* match failed? */ |
310 | capture[l].len = -1; /* undo capture */ | 317 | cap->capture[l].len = -1; /* undo capture */ |
311 | return res; | 318 | return res; |
312 | } | 319 | } |
313 | case '\0': case '$': /* (possibly) end of pattern */ | 320 | case '\0': case '$': /* (possibly) end of pattern */ |
314 | if (*p == 0 || (*(p+1) == 0 && *s == 0)) { | 321 | if (*p == 0 || (*(p+1) == 0 && *s == 0)) |
315 | num_captures = level; | ||
316 | return s; | 322 | return s; |
317 | } | ||
318 | /* else go through */ | 323 | /* else go through */ |
319 | default: { /* it is a pattern item */ | 324 | default: { /* it is a pattern item */ |
320 | char *ep; /* get what is next */ | 325 | char *ep; /* get what is next */ |
321 | char *s1 = matchitem(s, p, level, &ep); | 326 | char *s1 = matchitem(s, p, cap, &ep); |
322 | switch (*ep) { | 327 | switch (*ep) { |
323 | case '*': { /* repetition */ | 328 | case '*': { /* repetition */ |
324 | char *res; | 329 | char *res; |
325 | if (s1 && (res = match(s1, p, level))) | 330 | if (s1 && (res = match(s1, p, cap))) |
326 | return res; | 331 | return res; |
327 | p=ep+1; goto init; /* else return match(s, ep+1, level); */ | 332 | p=ep+1; goto init; /* else return match(s, ep+1, cap); */ |
328 | } | 333 | } |
329 | case '-': { /* repetition */ | 334 | case '-': { /* repetition */ |
330 | char *res; | 335 | char *res; |
331 | if ((res = match(s, ep+1, level)) != 0) | 336 | if ((res = match(s, ep+1, cap)) != 0) |
332 | return res; | 337 | return res; |
333 | else if (s1) { | 338 | else if (s1) { |
334 | s = s1; | 339 | s = s1; |
335 | goto init; /* return match(s1, p, level); */ | 340 | goto init; /* return match(s1, p, cap); */ |
336 | } | 341 | } |
337 | else | 342 | else |
338 | return NULL; | 343 | return NULL; |
339 | } | 344 | } |
340 | case '?': { /* optional */ | 345 | case '?': { /* optional */ |
341 | char *res; | 346 | char *res; |
342 | if (s1 && (res = match(s1, ep+1, level))) | 347 | if (s1 && (res = match(s1, ep+1, cap))) |
343 | return res; | 348 | return res; |
344 | p=ep+1; goto init; /* else return match(s, ep+1, level); */ | 349 | p=ep+1; goto init; /* else return match(s, ep+1, cap); */ |
345 | } | 350 | } |
346 | default: | 351 | default: |
347 | if (s1) { s=s1; p=ep; goto init; } /* return match(s1, ep, level); */ | 352 | if (s1) { s=s1; p=ep; goto init; } /* return match(s1, ep, cap); */ |
348 | else return NULL; | 353 | else return NULL; |
349 | } | 354 | } |
350 | } | 355 | } |
@@ -370,11 +375,13 @@ static void str_find (void) | |||
370 | int anchor = (*p == '^') ? (p++, 1) : 0; | 375 | int anchor = (*p == '^') ? (p++, 1) : 0; |
371 | char *s1=s+init; | 376 | char *s1=s+init; |
372 | do { | 377 | do { |
378 | struct Capture cap; | ||
373 | char *res; | 379 | char *res; |
374 | if ((res=match(s1, p, 0)) != NULL) { | 380 | cap.level = 0; |
381 | if ((res=match(s1, p, &cap)) != NULL) { | ||
375 | lua_pushnumber(s1-s+1); /* start */ | 382 | lua_pushnumber(s1-s+1); /* start */ |
376 | lua_pushnumber(res-s); /* end */ | 383 | lua_pushnumber(res-s); /* end */ |
377 | push_captures(); | 384 | push_captures(&cap); |
378 | return; | 385 | return; |
379 | } | 386 | } |
380 | } while (*s1++ && !anchor); | 387 | } while (*s1++ && !anchor); |
@@ -382,7 +389,7 @@ static void str_find (void) | |||
382 | } | 389 | } |
383 | 390 | ||
384 | 391 | ||
385 | static void add_s (lua_Object newp) | 392 | static void add_s (lua_Object newp, struct Capture *cap) |
386 | { | 393 | { |
387 | if (lua_isstring(newp)) { | 394 | if (lua_isstring(newp)) { |
388 | char *news = lua_getstring(newp); | 395 | char *news = lua_getstring(newp); |
@@ -390,8 +397,8 @@ static void add_s (lua_Object newp) | |||
390 | if (*news != ESC || !isdigit((unsigned char)*++news)) | 397 | if (*news != ESC || !isdigit((unsigned char)*++news)) |
391 | luaI_addchar(*news++); | 398 | luaI_addchar(*news++); |
392 | else { | 399 | else { |
393 | int l = check_cap(*news++, num_captures); | 400 | int l = check_cap(*news++, cap); |
394 | addnchar(capture[l].init, capture[l].len); | 401 | addnchar(cap->capture[l].init, cap->capture[l].len); |
395 | } | 402 | } |
396 | } | 403 | } |
397 | } | 404 | } |
@@ -400,7 +407,7 @@ static void add_s (lua_Object newp) | |||
400 | struct lbuff oldbuff; | 407 | struct lbuff oldbuff; |
401 | int status; | 408 | int status; |
402 | lua_beginblock(); | 409 | lua_beginblock(); |
403 | push_captures(); | 410 | push_captures(cap); |
404 | /* function may use lbuffer, so save it and create a luaM_new one */ | 411 | /* function may use lbuffer, so save it and create a luaM_new one */ |
405 | oldbuff = lbuffer; | 412 | oldbuff = lbuffer; |
406 | lbuffer.b = NULL; lbuffer.max = lbuffer.size = 0; | 413 | lbuffer.b = NULL; lbuffer.max = lbuffer.size = 0; |
@@ -428,10 +435,13 @@ static void str_gsub (void) | |||
428 | int n = 0; | 435 | int n = 0; |
429 | luaI_emptybuff(); | 436 | luaI_emptybuff(); |
430 | while (n < max_s) { | 437 | while (n < max_s) { |
431 | char *e = match(src, p, 0); | 438 | struct Capture cap; |
439 | char *e; | ||
440 | cap.level = 0; | ||
441 | e = match(src, p, &cap); | ||
432 | if (e) { | 442 | if (e) { |
433 | n++; | 443 | n++; |
434 | add_s(newp); | 444 | add_s(newp, &cap); |
435 | } | 445 | } |
436 | if (e && e>src) /* non empty match? */ | 446 | if (e && e>src) /* non empty match? */ |
437 | src = e; /* skip it */ | 447 | src = e; /* skip it */ |
@@ -471,11 +481,13 @@ static void str_format (void) | |||
471 | luaI_addchar(*strfrmt++); /* %% */ | 481 | luaI_addchar(*strfrmt++); /* %% */ |
472 | else { /* format item */ | 482 | else { /* format item */ |
473 | char form[MAX_FORMAT]; /* store the format ('%...') */ | 483 | char form[MAX_FORMAT]; /* store the format ('%...') */ |
484 | struct Capture cap; | ||
474 | char *buff; | 485 | char *buff; |
475 | char *initf = strfrmt; | 486 | char *initf = strfrmt; |
476 | form[0] = '%'; | 487 | form[0] = '%'; |
477 | strfrmt = match(strfrmt, "%d?%$?[-+ #]*(%d*)%.?(%d*)", 0); | 488 | cap.level = 0; |
478 | if (capture[0].len > 3 || capture[1].len > 3) /* < 1000? */ | 489 | strfrmt = match(strfrmt, "%d?%$?[-+ #]*(%d*)%.?(%d*)", &cap); |
490 | if (cap.capture[0].len > 3 || cap.capture[1].len > 3) /* < 1000? */ | ||
479 | lua_error("invalid format (width or precision too long)"); | 491 | lua_error("invalid format (width or precision too long)"); |
480 | if (isdigit((unsigned char)initf[0]) && initf[1] == '$') { | 492 | if (isdigit((unsigned char)initf[0]) && initf[1] == '$') { |
481 | arg = initf[0] - '0'; | 493 | arg = initf[0] - '0'; |