summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2006-02-13 19:16:41 +0000
committerRob Landley <rob@landley.net>2006-02-13 19:16:41 +0000
commit7bfa88f315d71c7f7a1b76fcec3886c7506aca24 (patch)
tree5995ddbb62eeda3512fa408b78bbd1eb8832ae4a /scripts
parentf251ec6847d28035ae42ad2c1ae94454d36c36d3 (diff)
downloadbusybox-w32-7bfa88f315d71c7f7a1b76fcec3886c7506aca24.tar.gz
busybox-w32-7bfa88f315d71c7f7a1b76fcec3886c7506aca24.tar.bz2
busybox-w32-7bfa88f315d71c7f7a1b76fcec3886c7506aca24.zip
New USE() macros
For each CONFIG_SYMBOL, include/bb_config.h now has both ENABLE_SYMBOL and USE_SYMBOL(x). ENABLE_SYMBOL is still always defined (1 or 0) so that if(ENABLE) should optimize out when it's zero. The USE_SYMBOL(X) will only splice in X if the symbol is defined, otherwise it'll be empty. Thus we can convert this: #ifdef CONFIG_ARGS opt = bb_getopt_ulflags(argc, argv, "ab:c" #ifdef CONFIG_THINGY "d:" #endif , &bvalue #ifdef CONFIG_THINGY , &thingy #endif ); #endif into this: if (ENABLE_ARGS) { opt = bb_getopt_ulflags(argc, argv, "ab:c" USE_THINGY("d:"), &bvalue USE_THINGY(, &thingy)); } And it should produce the same code. Unlike the old versions in include/_usage.h, the new USE_SYMBOL(x) can handle commas in its arguments (as shown above). (The _usage.h file is obsolete and no longer generated.) Nobody should need to include config.h directly anymore, bb_config.h should define all the configuration stuff we need. Someday, the CONFIG_SYMBOL versions should go away in favor of ENABLE_SYMBOL and USE_SYMBOL(). Thanks to vodz for the new version of bb_mkdep.c that works with function macros.
Diffstat (limited to 'scripts')
-rw-r--r--scripts/bb_mkdep.c931
1 files changed, 866 insertions, 65 deletions
diff --git a/scripts/bb_mkdep.c b/scripts/bb_mkdep.c
index 3fea20aed..7219feef9 100644
--- a/scripts/bb_mkdep.c
+++ b/scripts/bb_mkdep.c
@@ -1,10 +1,15 @@
1/* 1/*
2 * Another fast dependencies generator for Makefiles, Version 3.0 2 * Another fast dependencies generator for Makefiles, Version 4.0
3 * 3 *
4 * Copyright (C) 2005 by Vladimir Oleynik <dzo@simtreas.ru> 4 * Copyright (C) 2005,2006 by Vladimir Oleynik <dzo@simtreas.ru>
5 * 5 *
6 * mmaping file may be originally by Linus Torvalds. 6 * mmaping file may be originally by Linus Torvalds.
7 * 7 *
8 * infix parser/evaluator for #if expression
9 * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
10 * Copyright (c) 2001 Manuel Novoa III <mjn3@codepoet.org>
11 * Copyright (c) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12 *
8 * bb_simplify_path() 13 * bb_simplify_path()
9 * Copyright (C) 2005 Manuel Novoa III <mjn3@codepoet.org> 14 * Copyright (C) 2005 Manuel Novoa III <mjn3@codepoet.org>
10 * 15 *
@@ -15,7 +20,7 @@
15 * Copyright (C) 2003 Glenn McGrath 20 * Copyright (C) 2003 Glenn McGrath
16 * Copyright (C) Vladimir Oleynik <dzo@simtreas.ru> 21 * Copyright (C) Vladimir Oleynik <dzo@simtreas.ru>
17 * 22 *
18 * (c) 2005 Bernhard Fischer: 23 * (c) 2005,2006 Bernhard Fischer:
19 * - commentary typos, 24 * - commentary typos,
20 * - move "memory exhausted" into msg_enomem, 25 * - move "memory exhausted" into msg_enomem,
21 * - more verbose --help output. 26 * - more verbose --help output.
@@ -29,6 +34,7 @@
29 * path/inc.h: include/config/key*.h found_included_include_*.h 34 * path/inc.h: include/config/key*.h found_included_include_*.h
30 * 5) save include/config/key*.h if changed after previous usage 35 * 5) save include/config/key*.h if changed after previous usage
31 * This program does not generate dependencies for #include <...> 36 * This program does not generate dependencies for #include <...>
37 * Config file can have #if #elif #else #ifdef #ifndef #endif lines
32 */ 38 */
33 39
34#define LOCAL_INCLUDE_PATH "include" 40#define LOCAL_INCLUDE_PATH "include"
@@ -103,9 +109,9 @@ static llist_t *configs; /* list of -c usaged and them stat() after parsed */
103static llist_t *Iop; /* list of -I include usaged */ 109static llist_t *Iop; /* list of -I include usaged */
104 110
105static char *pwd; /* current work directory */ 111static char *pwd; /* current work directory */
106static size_t replace; /* replace current work directory with build dir */ 112static size_t replace; /* replace current work derectory to build dir */
107 113
108static const char *kp; /* KEY path, argument of -k used */ 114static const char *kp; /* KEY path, argument of -k usaged */
109static size_t kp_len; 115static size_t kp_len;
110static struct stat st_kp; /* stat(kp) */ 116static struct stat st_kp; /* stat(kp) */
111 117
@@ -139,22 +145,44 @@ static inline bb_key_t *check_key(bb_key_t *k, const char *nk, size_t key_sz)
139 return NULL; 145 return NULL;
140} 146}
141 147
148static inline const char *lookup_key(const char *nk, size_t key_sz)
149{
150 bb_key_t *cur;
151
152 for(cur = key_top; cur; cur = cur->next) {
153 if(key_sz == cur->key_sz && memcmp(cur->keyname, nk, key_sz) == 0) {
154 return cur->value;
155 }
156 }
157 return NULL;
158}
159
142/* for lexical analyser */ 160/* for lexical analyser */
143static int pagesizem1; /* padding mask = getpagesize() - 1 */ 161static int pagesizem1; /* padding mask = getpagesize() - 1 */
144 162
145/* for speed tricks */ 163/* for speed tricks */
146static char first_chars[1+UCHAR_MAX]; /* + L_EOF */ 164static char first_chars[1+UCHAR_MAX]; /* + L_EOF */
147static char isalnums[1+UCHAR_MAX]; /* + L_EOF */ 165static char isalnums[1+UCHAR_MAX]; /* + L_EOF */
148/* trick for fast find "define", "include", "undef" */ 166
149static const char first_chars_diu[UCHAR_MAX] = { 167/* trick for fast find "define", "include", "undef",
150 [(int)'d'] = (char)5, /* strlen("define") - 1; */ 168"if((n)def)" "else", "endif" */
151 [(int)'i'] = (char)6, /* strlen("include") - 1; */ 169static const char * const preproc[] = {
152 [(int)'u'] = (char)4, /* strlen("undef") - 1; */ 170/* 0 1 2 3 4 5 6 7 8 9 */
171"", "efine", "lif", "lse", "ndif", "f", "fdef", "fndef", "nclude", "ndef" };
172static const unsigned char first_chars_deiu[UCHAR_MAX] = {
173 [(int)'d'] = (unsigned char)(1|0x10), /* define */
174 [(int)'e'] = (unsigned char)(2|0x40), /* elif, else, endif */
175 [(int)'i'] = (unsigned char)(5|0x80), /* if ifdef ifndef include */
176 [(int)'u'] = (unsigned char)(9|0x90), /* undef */
153}; 177};
154 178
155#define CONFIG_MODE 0 179#define CONFIG_MODE 0
156#define SOURCES_MODE 1 180#define IF0_MODE 1 /* #if 0 */
157static int mode; 181#define IF1_MODE 2 /* #if 1 */
182#define ELSE0_MODE 4 /* #else found after #if 0 */
183#define ELSE1_MODE 8 /* #else found after #if 1 */
184#define ELIF1_MODE 16 /* #elif found after #if 1 */
185#define FALSE_MODES (IF0_MODE|ELSE1_MODE|ELIF1_MODE)
158 186
159#define yy_error_d(s) bb_error_d("%s:%d hmm, %s", fname, line, s) 187#define yy_error_d(s) bb_error_d("%s:%d hmm, %s", fname, line, s)
160 188
@@ -165,9 +193,15 @@ static int mode;
165#define REM '/' /* block comment */ 193#define REM '/' /* block comment */
166#define BS '\\' /* back slash */ 194#define BS '\\' /* back slash */
167#define POUND '#' /* # */ 195#define POUND '#' /* # */
168#define D '5' /* #define preprocessor's directive */ 196#define D '1' /* #define preprocessor's directive */
169#define I '6' /* #include preprocessor's directive */ 197#define EI '2' /* #elif preprocessor's directive */
170#define U '4' /* #undef preprocessor's directive */ 198#define E '3' /* #else preprocessor's directive */
199#define EF '4' /* #endif preprocessor's directive */
200#define F '5' /* #if preprocessor's directive */
201#define IFD '6' /* #ifdef preprocessor's directive */
202#define IFND '7' /* #ifndef preprocessor's directive */
203#define I '8' /* #include preprocessor's directive */
204#define U '9' /* #undef preprocessor's directive */
171#define DK 'K' /* #define KEY... (config mode) */ 205#define DK 'K' /* #define KEY... (config mode) */
172#define ANY '*' /* any unparsed chars */ 206#define ANY '*' /* any unparsed chars */
173 207
@@ -189,16 +223,508 @@ static char id_s[4096];
189#define put_id(ic) do { if(id_len == sizeof(id_s)) goto too_long; \ 223#define put_id(ic) do { if(id_len == sizeof(id_s)) goto too_long; \
190 id[id_len++] = ic; } while(0) 224 id[id_len++] = ic; } while(0)
191 225
226static char ifcpp_stack[1024];
227static int ptr_ifcpp_stack;
228#define push_mode() do { \
229 if(ptr_ifcpp_stack == (int)sizeof(ifcpp_stack)) \
230 yy_error_d("#if* stack overflow"); \
231 ifcpp_stack[ptr_ifcpp_stack++] = (char)mode; \
232 } while(0)
233
234#define pop_mode() do { \
235 if(ptr_ifcpp_stack == 0) \
236 yy_error_d("unexpected #endif"); \
237 mode = ifcpp_stack[--ptr_ifcpp_stack]; \
238 } while(0)
239
240/* #if expression */
241typedef long long arith_t;
242
243static arith_t arith (const char *expr, int *perrcode);
244
245/* The code uses a simple two-stack algorithm. See
246 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
247 * for a detailed explanation of the infix-to-postfix algorithm on which
248 * this is based (this code differs in that it applies operators immediately
249 * to the stack instead of adding them to a queue to end up with an
250 * expression). */
251
252#define arith_isspace(arithval) \
253 (arithval == ' ' || arithval == '\v' || arithval == '\t' || arithval == '\f')
254
255
256typedef unsigned char operator;
257
258/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
259 * precedence, and 3 high bits are an ID unique across operators of that
260 * precedence. The ID portion is so that multiple operators can have the
261 * same precedence, ensuring that the leftmost one is evaluated first.
262 * Consider * and /. */
263
264#define tok_decl(prec,id) (((id)<<5)|(prec))
265#define PREC(op) ((op) & 0x1F)
266
267#define TOK_LPAREN tok_decl(0,0)
268
269#define TOK_COMMA tok_decl(1,0)
270
271/* conditional is right associativity too */
272#define TOK_CONDITIONAL tok_decl(2,0)
273#define TOK_CONDITIONAL_SEP tok_decl(2,1)
274
275#define TOK_OR tok_decl(3,0)
276
277#define TOK_AND tok_decl(4,0)
278
279#define TOK_BOR tok_decl(5,0)
280
281#define TOK_BXOR tok_decl(6,0)
282
283#define TOK_BAND tok_decl(7,0)
284
285#define TOK_EQ tok_decl(8,0)
286#define TOK_NE tok_decl(8,1)
287
288#define TOK_LT tok_decl(9,0)
289#define TOK_GT tok_decl(9,1)
290#define TOK_GE tok_decl(9,2)
291#define TOK_LE tok_decl(9,3)
292
293#define TOK_LSHIFT tok_decl(10,0)
294#define TOK_RSHIFT tok_decl(10,1)
295
296#define TOK_ADD tok_decl(11,0)
297#define TOK_SUB tok_decl(11,1)
298
299#define TOK_MUL tok_decl(12,0)
300#define TOK_DIV tok_decl(12,1)
301#define TOK_REM tok_decl(12,2)
302
303/* For now unary operators. */
304#define UNARYPREC 13
305#define TOK_BNOT tok_decl(UNARYPREC,0)
306#define TOK_NOT tok_decl(UNARYPREC,1)
307
308#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
309#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
310
311#define SPEC_PREC (UNARYPREC+1)
312
313#define TOK_NUM tok_decl(SPEC_PREC, 0)
314#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
192 315
193/* stupid C lexical analyser */ 316#define NUMPTR (*numstackptr)
194static void c_lex(const char *fname, long fsize) 317
318typedef struct ARITCH_VAR_NUM {
319 arith_t val;
320 arith_t contidional_second_val;
321 char contidional_second_val_initialized;
322} v_n_t;
323
324
325typedef struct CHK_VAR_RECURSIVE_LOOPED {
326 const char *var;
327 size_t var_sz;
328 struct CHK_VAR_RECURSIVE_LOOPED *next;
329} chk_var_recursive_looped_t;
330
331static chk_var_recursive_looped_t *prev_chk_var_recursive;
332
333
334static int arith_lookup_val(const char *var, size_t key_sz, arith_t *pval)
335{
336 const char * p = lookup_key(var, key_sz);
337
338 if(p) {
339 int errcode;
340
341 /* recursive try as expression */
342 chk_var_recursive_looped_t *cur;
343 chk_var_recursive_looped_t cur_save;
344
345 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
346 if(cur->var_sz == key_sz && memcmp(cur->var, var, key_sz) == 0) {
347 /* expression recursion loop detected */
348 return -5;
349 }
350 }
351 /* save current lookuped var name */
352 cur = prev_chk_var_recursive;
353 cur_save.var = var;
354 cur_save.var_sz = key_sz;
355 cur_save.next = cur;
356 prev_chk_var_recursive = &cur_save;
357
358 *pval = arith (p, &errcode);
359 /* restore previous ptr after recursiving */
360 prev_chk_var_recursive = cur;
361 return errcode;
362 } else {
363 /* disallow undefined var */
364 fprintf(stderr, "%.*s ", (int)key_sz, var);
365 return -4;
366 }
367}
368
369/* "applying" a token means performing it on the top elements on the integer
370 * stack. For a unary operator it will only change the top element, but a
371 * binary operator will pop two arguments and push a result */
372static inline int
373arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
374{
375 v_n_t *numptr_m1;
376 arith_t numptr_val, rez;
377
378 if (NUMPTR == numstack) goto err; /* There is no operator that can work
379 without arguments */
380 numptr_m1 = NUMPTR - 1;
381
382 rez = numptr_m1->val;
383 if (op == TOK_UMINUS)
384 rez *= -1;
385 else if (op == TOK_NOT)
386 rez = !rez;
387 else if (op == TOK_BNOT)
388 rez = ~rez;
389 else if (op != TOK_UPLUS) {
390 /* Binary operators */
391
392 /* check and binary operators need two arguments */
393 if (numptr_m1 == numstack) goto err;
394
395 /* ... and they pop one */
396 --NUMPTR;
397 numptr_val = rez;
398 if (op == TOK_CONDITIONAL) {
399 if(! numptr_m1->contidional_second_val_initialized) {
400 /* protect $((expr1 ? expr2)) without ": expr" */
401 goto err;
402 }
403 rez = numptr_m1->contidional_second_val;
404 } else if(numptr_m1->contidional_second_val_initialized) {
405 /* protect $((expr1 : expr2)) without "expr ? " */
406 goto err;
407 }
408 numptr_m1 = NUMPTR - 1;
409 if (op == TOK_CONDITIONAL) {
410 numptr_m1->contidional_second_val = rez;
411 }
412 rez = numptr_m1->val;
413 if (op == TOK_BOR)
414 rez |= numptr_val;
415 else if (op == TOK_OR)
416 rez = numptr_val || rez;
417 else if (op == TOK_BAND)
418 rez &= numptr_val;
419 else if (op == TOK_BXOR)
420 rez ^= numptr_val;
421 else if (op == TOK_AND)
422 rez = rez && numptr_val;
423 else if (op == TOK_EQ)
424 rez = (rez == numptr_val);
425 else if (op == TOK_NE)
426 rez = (rez != numptr_val);
427 else if (op == TOK_GE)
428 rez = (rez >= numptr_val);
429 else if (op == TOK_RSHIFT)
430 rez >>= numptr_val;
431 else if (op == TOK_LSHIFT)
432 rez <<= numptr_val;
433 else if (op == TOK_GT)
434 rez = (rez > numptr_val);
435 else if (op == TOK_LT)
436 rez = (rez < numptr_val);
437 else if (op == TOK_LE)
438 rez = (rez <= numptr_val);
439 else if (op == TOK_MUL)
440 rez *= numptr_val;
441 else if (op == TOK_ADD)
442 rez += numptr_val;
443 else if (op == TOK_SUB)
444 rez -= numptr_val;
445 else if (op == TOK_COMMA)
446 rez = numptr_val;
447 else if (op == TOK_CONDITIONAL_SEP) {
448 if (numptr_m1 == numstack) {
449 /* protect $((expr : expr)) without "expr ? " */
450 goto err;
451 }
452 numptr_m1->contidional_second_val_initialized = op;
453 numptr_m1->contidional_second_val = numptr_val;
454 }
455 else if (op == TOK_CONDITIONAL) {
456 rez = rez ?
457 numptr_val : numptr_m1->contidional_second_val;
458 }
459 else if(numptr_val==0) /* zero divisor check */
460 return -2;
461 else if (op == TOK_DIV)
462 rez /= numptr_val;
463 else if (op == TOK_REM)
464 rez %= numptr_val;
465 }
466 numptr_m1->val = rez;
467 return 0;
468err: return(-1);
469}
470
471/* longest must first */
472static const char op_tokens[] = {
473 '<','<', 0, TOK_LSHIFT,
474 '>','>', 0, TOK_RSHIFT,
475 '|','|', 0, TOK_OR,
476 '&','&', 0, TOK_AND,
477 '!','=', 0, TOK_NE,
478 '<','=', 0, TOK_LE,
479 '>','=', 0, TOK_GE,
480 '=','=', 0, TOK_EQ,
481 '!', 0, TOK_NOT,
482 '<', 0, TOK_LT,
483 '>', 0, TOK_GT,
484 '|', 0, TOK_BOR,
485 '&', 0, TOK_BAND,
486 '*', 0, TOK_MUL,
487 '/', 0, TOK_DIV,
488 '%', 0, TOK_REM,
489 '+', 0, TOK_ADD,
490 '-', 0, TOK_SUB,
491 '^', 0, TOK_BXOR,
492 '~', 0, TOK_BNOT,
493 ',', 0, TOK_COMMA,
494 '?', 0, TOK_CONDITIONAL,
495 ':', 0, TOK_CONDITIONAL_SEP,
496 ')', 0, TOK_RPAREN,
497 '(', 0, TOK_LPAREN,
498 0
499};
500/* ptr to ")" */
501#define endexpression &op_tokens[sizeof(op_tokens)-7]
502
503/*
504 * Return of a legal variable name (a letter or underscore followed by zero or
505 * more letters, underscores, and digits).
506 */
507
508static inline char *
509endofname(const char *name)
510{
511 char *p;
512
513 p = (char *) name;
514 if (! ID(*p))
515 return p;
516 while (*++p) {
517 if (! ISALNUM(*p))
518 break;
519 }
520 return p;
521}
522
523
524/* Like strncpy but make sure the resulting string is always 0 terminated. */
525static inline char * safe_strncpy(char *dst, const char *src, size_t size)
526{
527 dst[size-1] = '\0';
528 return strncpy(dst, src, size-1);
529}
530
531static arith_t arith (const char *expr, int *perrcode)
532{
533 char arithval; /* Current character under analysis */
534 operator lasttok, op;
535 operator prec;
536
537 const char *p = endexpression;
538 int errcode;
539
540 size_t datasizes = strlen(expr) + 2;
541
542 /* Stack of integers */
543 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
544 * in any given correct or incorrect expression is left as an exercise to
545 * the reader. */
546 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
547 *numstackptr = numstack;
548 /* Stack of operator tokens */
549 operator *stack = alloca((datasizes) * sizeof(operator)),
550 *stackptr = stack;
551
552 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
553 *perrcode = errcode = 0;
554
555 while(1) {
556 if ((arithval = *expr) == 0) {
557 if (p == endexpression) {
558 /* Null expression. */
559err:
560 return (*perrcode = -1);
561 }
562
563 /* This is only reached after all tokens have been extracted from the
564 * input stream. If there are still tokens on the operator stack, they
565 * are to be applied in order. At the end, there should be a final
566 * result on the integer stack */
567
568 if (expr != endexpression + 1) {
569 /* If we haven't done so already, */
570 /* append a closing right paren */
571 expr = endexpression;
572 /* and let the loop process it. */
573 continue;
574 }
575 /* At this point, we're done with the expression. */
576 if (numstackptr != numstack+1) {
577 /* ... but if there isn't, it's bad */
578 goto err;
579 }
580 ret:
581 *perrcode = errcode;
582 return numstack->val;
583 } else {
584 /* Continue processing the expression. */
585 if (arith_isspace(arithval)) {
586 /* Skip whitespace */
587 goto prologue;
588 }
589 if((p = endofname(expr)) != expr) {
590 size_t var_name_size = (p-expr);
591
592 if(var_name_size == 7 &&
593 strncmp(expr, "defined", var_name_size) == 0) {
594 int brace_form = 0;
595 const char *v;
596
597 while(arith_isspace(*p)) p++;
598 if(*p == '(') {
599 p++;
600 while(arith_isspace(*p)) p++;
601 brace_form = 1;
602 }
603 expr = p;
604 if((p = endofname(expr)) == expr)
605 goto err;
606 var_name_size = (p-expr);
607 while(arith_isspace(*p)) p++;
608 if(brace_form && *p++ != ')')
609 goto err;
610 v = lookup_key(expr, var_name_size);
611 numstackptr->val = (v != NULL) ? 1 : 0;
612 } else {
613 errcode = arith_lookup_val(expr, var_name_size,
614 &(numstackptr->val));
615 if(errcode) goto ret;
616 }
617 expr = p;
618 num:
619 numstackptr->contidional_second_val_initialized = 0;
620 numstackptr++;
621 lasttok = TOK_NUM;
622 continue;
623 } else if (arithval >= '0' && arithval <= '9') {
624 numstackptr->val = strtoll(expr, (char **) &expr, 0);
625 while(*expr == 'l' || *expr == 'L' || *expr == 'u' ||
626 *expr == 'U')
627 expr++;
628 goto num;
629 }
630 for(p = op_tokens; ; p++) {
631 const char *o;
632
633 if(*p == 0) {
634 /* strange operator not found */
635 goto err;
636 }
637 for(o = expr; *p && *o == *p; p++)
638 o++;
639 if(! *p) {
640 /* found */
641 expr = o - 1;
642 break;
643 }
644 /* skip tail uncompared token */
645 while(*p)
646 p++;
647 /* skip zero delim */
648 p++;
649 }
650 op = p[1];
651
652 /* Plus and minus are binary (not unary) _only_ if the last
653 * token was as number, or a right paren (which pretends to be
654 * a number, since it evaluates to one). Think about it.
655 * It makes sense. */
656 if (lasttok != TOK_NUM) {
657 if(op == TOK_ADD)
658 op = TOK_UPLUS;
659 else if(op == TOK_SUB)
660 op = TOK_UMINUS;
661 }
662 /* We don't want a unary operator to cause recursive descent on the
663 * stack, because there can be many in a row and it could cause an
664 * operator to be evaluated before its argument is pushed onto the
665 * integer stack. */
666 /* But for binary operators, "apply" everything on the operator
667 * stack until we find an operator with a lesser priority than the
668 * one we have just extracted. */
669 /* Left paren is given the lowest priority so it will never be
670 * "applied" in this way.
671 * if associativity is right and priority eq, applied also skip
672 */
673 prec = PREC(op);
674 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
675 /* not left paren or unary */
676 if (lasttok != TOK_NUM) {
677 /* binary op must be preceded by a num */
678 goto err;
679 }
680 while (stackptr != stack) {
681 if (op == TOK_RPAREN) {
682 /* The algorithm employed here is simple: while we don't
683 * hit an open paren nor the bottom of the stack, pop
684 * tokens and apply them */
685 if (stackptr[-1] == TOK_LPAREN) {
686 --stackptr;
687 /* Any operator directly after a */
688 lasttok = TOK_NUM;
689 /* close paren should consider itself binary */
690 goto prologue;
691 }
692 } else {
693 operator prev_prec = PREC(stackptr[-1]);
694
695 if (prev_prec < prec)
696 break;
697 /* check right assoc */
698 if(prev_prec == prec && prec == PREC(TOK_CONDITIONAL))
699 break;
700 }
701 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
702 if(errcode) goto ret;
703 }
704 if (op == TOK_RPAREN) {
705 goto err;
706 }
707 }
708
709 /* Push this operator to the stack and remember it. */
710 *stackptr++ = lasttok = op;
711
712 prologue:
713 ++expr;
714 }
715 }
716}
717
718/* stupid C lexical analyser for configs.h */
719static void c_lex_config(const char *fname, long fsize)
195{ 720{
196 int c; 721 int c;
197 int state; 722 int state;
198 int line; 723 int line;
199 char *id = id_s; 724 char *id = id_s;
200 size_t id_len = 0; /* stupid initialization */ 725 size_t id_len = 0; /* stupid initialize */
201 unsigned char *optr, *oend; 726 unsigned char *optr, *oend;
727 int mode = CONFIG_MODE;
202 728
203 int fd; 729 int fd;
204 char *map; 730 char *map;
@@ -242,6 +768,8 @@ static void c_lex(const char *fname, long fsize)
242 /* <S><<EOF>> */ 768 /* <S><<EOF>> */
243 munmap(map, mapsize); 769 munmap(map, mapsize);
244 close(fd); 770 close(fd);
771 if(mode != CONFIG_MODE)
772 yy_error_d("expected #endif");
245 return; 773 return;
246 } 774 }
247 if(c == REM) { 775 if(c == REM) {
@@ -282,7 +810,7 @@ static void c_lex(const char *fname, long fsize)
282 810
283 /* trick for fast drop id 811 /* trick for fast drop id
284 if key with this first char undefined */ 812 if key with this first char undefined */
285 if(first_chars[c] == 0) { 813 if(first_chars[c] == 0 || (mode & FALSE_MODES) != 0) {
286 /* skip <S>[A-Z_a-z0-9]+ */ 814 /* skip <S>[A-Z_a-z0-9]+ */
287 do getc1(); while(isalnums[c]); 815 do getc1(); while(isalnums[c]);
288 } else { 816 } else {
@@ -314,30 +842,37 @@ static void c_lex(const char *fname, long fsize)
314 } 842 }
315 if(state == POUND) { 843 if(state == POUND) {
316 /* tricks */ 844 /* tricks */
317 static const char * const preproc[] = { 845 int diu = (int)first_chars_deiu[c]; /* preproc ptr */
318 /* 0 1 2 3 4 5 6 */
319 "", "", "", "", "ndef", "efine", "nclude"
320 };
321 size_t diu = first_chars_diu[c]; /* strlen and preproc ptr */
322 846
323 state = S; 847 state = S;
324 if(diu != S) { 848 if(diu != S) {
849 int p_num_str, p_num_max;
850
325 getc1(); 851 getc1();
326 id_len = 0; 852 id_len = 0;
327 while(isalnums[c]) { 853 while(isalnums[c]) {
328 put_id(c); 854 put_id(c);
329 getc1(); 855 getc1();
330 } 856 }
331 /* str begins with c, read == strlen key and compared */ 857 put_id(0);
332 if(diu == id_len && !memcmp(id, preproc[diu], diu)) { 858 p_num_str = diu & 0xf;
333 state = diu + '0'; 859 p_num_max = diu >> 4;
334 id_len = 0; /* common for save */ 860 for(diu = p_num_str; diu <= p_num_max; diu++)
861 if(!strcmp(id, preproc[diu])) {
862 state = (diu + '0');
863 /* common */
864 id_len = 0;
865 break;
335 } 866 }
336 } else { 867 } else {
337 while(isalnums[c]) getc1(); 868 while(isalnums[c]) getc1();
338 } 869 }
870 } else if(state == EF) {
871 /* #endif */
872 pop_mode();
873 state = S;
339 } else if(state == I) { 874 } else if(state == I) {
340 if(c == STR) { 875 if(c == STR && (mode & FALSE_MODES) == 0) {
341 /* <I>\" */ 876 /* <I>\" */
342 for(;;) { 877 for(;;) {
343 getc1(); 878 getc1();
@@ -354,31 +889,84 @@ static void c_lex(const char *fname, long fsize)
354 } 889 }
355 /* else another (may be wrong) #include ... */ 890 /* else another (may be wrong) #include ... */
356 state = S; 891 state = S;
892 } else if(state == F) {
893 arith_t t;
894 int errcode;
895
896 while(c != '\n' && c != L_EOF) {
897 put_id(c);
898 getc1();
899 }
900 put_id(0);
901 t = arith(id, &errcode);
902 if (errcode < 0) {
903 if (errcode == -2)
904 yy_error_d("divide by zero");
905 else if (errcode == -4)
906 yy_error_d("undefined");
907 else if (errcode == -5)
908 yy_error_d("expression recursion loop detected");
909 else
910 yy_error_d("syntax error");
911 }
912 push_mode();
913 mode = t != 0 ? IF1_MODE : IF0_MODE;
914 state = S;
915 } else if(state == IFD || state == IFND) {
916 /* save KEY from #if(n)def KEY ... */
917 const char *v;
918
919 push_mode();
920 while(isalnums[c]) {
921 put_id(c);
922 getc1();
923 }
924 if(!id_len)
925 yy_error_d("expected identifier");
926 v = lookup_key(id, id_len);
927 mode = IF1_MODE;
928 if(state == IFD && v == NULL)
929 mode = IF0_MODE;
930 else if(state == IFND && v != NULL)
931 mode = IF0_MODE;
932 state = S;
933 } else if(state == EI) {
934 /* #elif */
935 if(mode == CONFIG_MODE || mode == ELSE0_MODE || mode == ELSE1_MODE)
936 yy_error_d("unexpected #elif");
937 if(mode == IF0_MODE) {
938 pop_mode();
939 state = F;
940 } else {
941 mode = ELIF1_MODE;
942 state = S;
943 }
944 } else if(state == E) {
945 if(mode == CONFIG_MODE || mode == ELSE0_MODE || mode == ELSE1_MODE)
946 yy_error_d("unexpected #else");
947 if(mode == IF0_MODE)
948 mode = ELSE0_MODE;
949 else if(mode == IF1_MODE)
950 mode = ELSE1_MODE;
951 state = S;
357 } else if(state == D || state == U) { 952 } else if(state == D || state == U) {
358 if(mode == SOURCES_MODE) { 953 /* save KEY from #"define"|"undef" ... */
359 /* ignore depend with #define or #undef KEY */ 954 while(isalnums[c]) {
360 while(isalnums[c]) getc1(); 955 put_id(c);
956 getc1();
957 }
958 if(!id_len)
959 yy_error_d("expected identifier");
960 if(state == U) {
961 if((mode & FALSE_MODES) == 0)
962 parse_conf_opt(id, NULL, id_len);
361 state = S; 963 state = S;
362 } else { 964 } else {
363 /* save KEY from #"define"|"undef" ... */ 965 /* D -> DK */
364 while(isalnums[c]) { 966 state = DK;
365 put_id(c);
366 getc1();
367 }
368 if(!id_len)
369 yy_error_d("expected identifier");
370 if(state == U) {
371 parse_conf_opt(id, NULL, id_len);
372 state = S;
373 } else {
374 /* D -> DK */
375 if(c == '(')
376 yy_error_d("unexpected function macro");
377 state = DK;
378 }
379 } 967 }
380 } else { 968 } else {
381 /* state==<DK> #define KEY[ ] (config mode) */ 969 /* state==<DK> #define KEY[ ] */
382 size_t opt_len = id_len; 970 size_t opt_len = id_len;
383 char *val = id + opt_len; 971 char *val = id + opt_len;
384 char *sp; 972 char *sp;
@@ -395,7 +983,8 @@ static void c_lex(const char *fname, long fsize)
395 while(--sp >= val && (*sp == ' ' || *sp == '\t' 983 while(--sp >= val && (*sp == ' ' || *sp == '\t'
396 || *sp == '\f' || *sp == '\v')) 984 || *sp == '\f' || *sp == '\v'))
397 *sp = '\0'; 985 *sp = '\0';
398 parse_conf_opt(id, val, opt_len); 986 if((mode & FALSE_MODES) == 0)
987 parse_conf_opt(id, val, opt_len);
399 state = S; 988 state = S;
400 } 989 }
401 } 990 }
@@ -426,8 +1015,219 @@ too_long:
426 yy_error_d("phrase too long"); 1015 yy_error_d("phrase too long");
427} 1016}
428 1017
1018/* trick for fast find "define", "include", "undef" */
1019static const char first_chars_diu[UCHAR_MAX] = {
1020 [(int)'d'] = (char)5, /* strlen("define") - 1; */
1021 [(int)'i'] = (char)6, /* strlen("include") - 1; */
1022 [(int)'u'] = (char)4, /* strlen("undef") - 1; */
1023};
1024
1025#undef D
1026#undef I
1027#undef U
1028#define D '5' /* #define preprocessor's directive */
1029#define I '6' /* #include preprocessor's directive */
1030#define U '4' /* #undef preprocessor's directive */
1031
1032/* stupid C lexical analyser for sources */
1033static void c_lex_src(const char *fname, long fsize)
1034{
1035 int c;
1036 int state;
1037 int line;
1038 char *id = id_s;
1039 size_t id_len = 0; /* stupid initialize */
1040 unsigned char *optr, *oend;
1041
1042 int fd;
1043 char *map;
1044 int mapsize;
429 1045
430/* bb_simplify_path special variant for absolute pathname */ 1046 if(fsize == 0) {
1047 fprintf(stderr, "Warning: %s is empty\n", fname);
1048 return;
1049 }
1050 fd = open(fname, O_RDONLY);
1051 if(fd < 0) {
1052 perror(fname);
1053 return;
1054 }
1055 mapsize = (fsize+pagesizem1) & ~pagesizem1;
1056 map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
1057 if ((long) map == -1)
1058 bb_error_d("%s: mmap: %m", fname);
1059
1060 optr = (unsigned char *)map;
1061 oend = optr + fsize;
1062
1063 line = 1;
1064 state = S;
1065
1066 for(;;) {
1067 getc1();
1068 for(;;) {
1069 /* [ \t]+ eat first space */
1070 while(c == ' ' || c == '\t')
1071 getc1();
1072
1073 if(state == S) {
1074 while(first_chars[c] == ANY) {
1075 /* <S>unparsed */
1076 if(c == '\n')
1077 line++;
1078 getc1();
1079 }
1080 if(c == L_EOF) {
1081 /* <S><<EOF>> */
1082 munmap(map, mapsize);
1083 close(fd);
1084 return;
1085 }
1086 if(c == REM) {
1087 /* <S>/ */
1088 getc0();
1089 if(c == REM) {
1090 /* <S>"//"[^\n]* */
1091 do getc0(); while(c != '\n' && c != L_EOF);
1092 } else if(c == '*') {
1093 /* <S>[/][*] goto parse block comments */
1094 break;
1095 }
1096 } else if(c == POUND) {
1097 /* <S># */
1098 state = c;
1099 getc1();
1100 } else if(c == STR || c == CHR) {
1101 /* <S>\"|\' */
1102 int qc = c;
1103
1104 for(;;) {
1105 /* <STR,CHR>. */
1106 getc1();
1107 if(c == qc) {
1108 /* <STR>\" or <CHR>\' */
1109 break;
1110 }
1111 if(c == BS) {
1112 /* <STR,CHR>\\ but is not <STR,CHR>\\\n */
1113 getc0();
1114 }
1115 if(c == '\n' || c == L_EOF)
1116 yy_error_d("unterminated");
1117 }
1118 getc1();
1119 } else {
1120 /* <S>[A-Z_a-z0-9] */
1121
1122 /* trick for fast drop id
1123 if key with this first char undefined */
1124 if(first_chars[c] == 0) {
1125 /* skip <S>[A-Z_a-z0-9]+ */
1126 do getc1(); while(isalnums[c]);
1127 } else {
1128 id_len = 0;
1129 do {
1130 /* <S>[A-Z_a-z0-9]+ */
1131 put_id(c);
1132 getc1();
1133 } while(isalnums[c]);
1134 check_key(key_top, id, id_len);
1135 }
1136 }
1137 continue;
1138 }
1139 /* begin preprocessor states */
1140 if(c == L_EOF)
1141 yy_error_d("unexpected EOF");
1142 if(c == REM) {
1143 /* <#.*>/ */
1144 getc0();
1145 if(c == REM)
1146 yy_error_d("detected // in preprocessor line");
1147 if(c == '*') {
1148 /* <#.*>[/][*] goto parse block comments */
1149 break;
1150 }
1151 /* hmm, #.*[/] */
1152 yy_error_d("strange preprocessor line");
1153 }
1154 if(state == POUND) {
1155 /* tricks */
1156 static const char * const p_preproc[] = {
1157 /* 0 1 2 3 4 5 6 */
1158 "", "", "", "", "ndef", "efine", "nclude"
1159 };
1160 size_t diu = first_chars_diu[c]; /* strlen and p_preproc ptr */
1161
1162 state = S;
1163 if(diu != S) {
1164 getc1();
1165 id_len = 0;
1166 while(isalnums[c]) {
1167 put_id(c);
1168 getc1();
1169 }
1170 /* have str begined with c, readed == strlen key and compared */
1171 if(diu == id_len && !memcmp(id, p_preproc[diu], diu)) {
1172 state = diu + '0';
1173 id_len = 0; /* common for save */
1174 }
1175 } else {
1176 while(isalnums[c]) getc1();
1177 }
1178 } else if(state == I) {
1179 if(c == STR) {
1180 /* <I>\" */
1181 for(;;) {
1182 getc1();
1183 if(c == STR)
1184 break;
1185 if(c == L_EOF)
1186 yy_error_d("unexpected EOF");
1187 put_id(c);
1188 }
1189 put_id(0);
1190 /* store "include.h" */
1191 parse_inc(id, fname);
1192 getc1();
1193 }
1194 /* else another (may be wrong) #include ... */
1195 state = S;
1196 } else /* if(state == D || state == U) */ {
1197 /* ignore depend with #define or #undef KEY */
1198 while(isalnums[c]) getc1();
1199 state = S;
1200 }
1201 }
1202
1203 /* <REM> */
1204 getc0();
1205 for(;;) {
1206 /* <REM>[^*]+ */
1207 while(c != '*') {
1208 if(c == '\n') {
1209 /* <REM>\n */
1210 if(state != S)
1211 yy_error_d("unexpected newline");
1212 line++;
1213 } else if(c == L_EOF)
1214 yy_error_d("unexpected EOF");
1215 getc0();
1216 }
1217 /* <REM>[*] */
1218 getc0();
1219 if(c == REM) {
1220 /* <REM>[*][/] */
1221 break;
1222 }
1223 }
1224 }
1225too_long:
1226 yy_error_d("phrase too long");
1227}
1228
1229
1230/* bb_simplify_path special variant for apsolute pathname */
431static size_t bb_qa_simplify_path(char *path) 1231static size_t bb_qa_simplify_path(char *path)
432{ 1232{
433 char *s, *p; 1233 char *s, *p;
@@ -477,7 +1277,7 @@ static void parse_inc(const char *include, const char *fname)
477 const char *p; 1277 const char *p;
478 1278
479 lo = Iop; 1279 lo = Iop;
480 p = strrchr(fname, '/'); /* fname has absolute pathname */ 1280 p = strrchr(fname, '/'); /* fname have absolute pathname */
481 w = (p-fname); 1281 w = (p-fname);
482 /* find from current directory of source file */ 1282 /* find from current directory of source file */
483 ap = bb_asprint("%.*s/%s", w, fname, include); 1283 ap = bb_asprint("%.*s/%s", w, fname, include);
@@ -502,14 +1302,15 @@ static void parse_inc(const char *include, const char *fname)
502 1302
503 /* find from "-I include" specified directories */ 1303 /* find from "-I include" specified directories */
504 free(ap); 1304 free(ap);
505 /* lo->data has absolute pathname */ 1305 /* lo->data have absolute pathname */
506 ap = bb_asprint("%s/%s", lo->data, include); 1306 ap = bb_asprint("%s/%s", lo->data, include);
507 lo = lo->link; 1307 lo = lo->link;
508 } 1308 }
509 1309
510 cur = xmalloc(sizeof(bb_key_t)); 1310 cur = xmalloc(sizeof(bb_key_t));
511 cur->keyname = cur->stored_path = ap; 1311 cur->keyname = ap;
512 cur->key_sz = key_sz; 1312 cur->key_sz = key_sz;
1313 cur->stored_path = ap;
513 cur->value = cur->checked = p_i; 1314 cur->value = cur->checked = p_i;
514 if(p_i == NULL && noiwarning) 1315 if(p_i == NULL && noiwarning)
515 fprintf(stderr, "%s: Warning: #include \"%s\" not found\n", fname, include); 1316 fprintf(stderr, "%s: Warning: #include \"%s\" not found\n", fname, include);
@@ -528,7 +1329,7 @@ static void parse_conf_opt(const char *opt, const char *val, size_t key_sz)
528 1329
529 cur = check_key(key_top, opt, key_sz); 1330 cur = check_key(key_top, opt, key_sz);
530 if(cur != NULL) { 1331 if(cur != NULL) {
531 /* already present */ 1332 /* present already */
532 cur->checked = NULL; /* store only */ 1333 cur->checked = NULL; /* store only */
533 if(cur->value == NULL && val == NULL) 1334 if(cur->value == NULL && val == NULL)
534 return; 1335 return;
@@ -568,7 +1369,7 @@ static void parse_conf_opt(const char *opt, const char *val, size_t key_sz)
568 first_chars[(int)*k] = *k; 1369 first_chars[(int)*k] = *k;
569 1370
570 cur->stored_path = k = bb_asprint("%s/%s.h", kp, k); 1371 cur->stored_path = k = bb_asprint("%s/%s.h", kp, k);
571 /* key conversion [A-Z_] -> [a-z/] */ 1372 /* key converting [A-Z_] -> [a-z/] */
572 for(p = k + kp_len + 1; *p; p++) { 1373 for(p = k + kp_len + 1; *p; p++) {
573 if(*p >= 'A' && *p <= 'Z') 1374 if(*p >= 'A' && *p <= 'Z')
574 *p = *p - 'A' + 'a'; 1375 *p = *p - 'A' + 'a';
@@ -604,7 +1405,7 @@ static void store_keys(void)
604 } 1405 }
605 /* size_t -> ssize_t :( */ 1406 /* size_t -> ssize_t :( */
606 rw_ret = (ssize_t)recordsz; 1407 rw_ret = (ssize_t)recordsz;
607 /* check kp/key.h, compare after previous use */ 1408 /* check kp/key.h, compare after previous usage */
608 cmp_ok = 0; 1409 cmp_ok = 0;
609 k = cur->stored_path; 1410 k = cur->stored_path;
610 if(stat(k, &st)) { 1411 if(stat(k, &st)) {
@@ -709,7 +1510,7 @@ parse_chd(const char *fe, const char *p, size_t dirlen)
709 } 1510 }
710 } 1511 }
711 /* direntry is *.[ch] regular file and is not configs */ 1512 /* direntry is *.[ch] regular file and is not configs */
712 c_lex(fp, st.st_size); 1513 c_lex_src(fp, st.st_size);
713 if(!dontgenerate_dep) { 1514 if(!dontgenerate_dep) {
714 int first; 1515 int first;
715 if(*e == 'c') { 1516 if(*e == 'c') {
@@ -740,7 +1541,7 @@ parse_chd(const char *fe, const char *p, size_t dirlen)
740 return NULL; 1541 return NULL;
741} 1542}
742 1543
743/* from libbb but inlined for speed considerations */ 1544/* from libbb but inline for fast */
744static inline llist_t *llist_add_to(llist_t *old_head, char *new_item) 1545static inline llist_t *llist_add_to(llist_t *old_head, char *new_item)
745{ 1546{
746 llist_t *new_head; 1547 llist_t *new_head;
@@ -763,7 +1564,7 @@ static void scan_dir_find_ch_files(const char *p)
763 1564
764 dirs = llist_add_to(NULL, bb_simplify_path(p)); 1565 dirs = llist_add_to(NULL, bb_simplify_path(p));
765 replace = strlen(dirs->data); 1566 replace = strlen(dirs->data);
766 /* emulate recursion */ 1567 /* emulate recursive */
767 while(dirs) { 1568 while(dirs) {
768 d_add = NULL; 1569 d_add = NULL;
769 while(dirs) { 1570 while(dirs) {
@@ -803,7 +1604,7 @@ int main(int argc, char **argv)
803 llist_t *fl; 1604 llist_t *fl;
804 1605
805 { 1606 {
806 /* for bb_simplify_path, this program has no chdir() */ 1607 /* for bb_simplify_path, this program have not chdir() */
807 /* libbb-like my xgetcwd() */ 1608 /* libbb-like my xgetcwd() */
808 unsigned path_max = 512; 1609 unsigned path_max = 512;
809 1610
@@ -863,7 +1664,7 @@ int main(int argc, char **argv)
863 for(i = 0; i < UCHAR_MAX; i++) { 1664 for(i = 0; i < UCHAR_MAX; i++) {
864 if(ISALNUM(i)) 1665 if(ISALNUM(i))
865 isalnums[i] = i; 1666 isalnums[i] = i;
866 /* set unparsed chars to speed up the parser */ 1667 /* set unparsed chars for speed up of parser */
867 else if(i != CHR && i != STR && i != POUND && i != REM) 1668 else if(i != CHR && i != STR && i != POUND && i != REM)
868 first_chars[i] = ANY; 1669 first_chars[i] = ANY;
869 } 1670 }
@@ -875,7 +1676,7 @@ int main(int argc, char **argv)
875 1676
876 if(stat(fl->data, &st)) 1677 if(stat(fl->data, &st))
877 bb_error_d("stat(%s): %m", fl->data); 1678 bb_error_d("stat(%s): %m", fl->data);
878 c_lex(fl->data, st.st_size); 1679 c_lex_config(fl->data, st.st_size);
879 free(fl->data); 1680 free(fl->data);
880 /* trick for fast comparing found files with configs */ 1681 /* trick for fast comparing found files with configs */
881 fl->data = xmalloc(sizeof(struct stat)); 1682 fl->data = xmalloc(sizeof(struct stat));
@@ -883,7 +1684,6 @@ int main(int argc, char **argv)
883 } 1684 }
884 1685
885 /* main loop */ 1686 /* main loop */
886 mode = SOURCES_MODE;
887 argv += optind; 1687 argv += optind;
888 if(*argv) { 1688 if(*argv) {
889 while(*argv) 1689 while(*argv)
@@ -923,6 +1723,7 @@ static char *bb_asprint(const char *format, ...)
923} 1723}
924 1724
925/* partial libbb routine as is */ 1725/* partial libbb routine as is */
1726
926static char *bb_simplify_path(const char *path) 1727static char *bb_simplify_path(const char *path)
927{ 1728{
928 char *s, *start, *p; 1729 char *s, *start, *p;
@@ -930,7 +1731,7 @@ static char *bb_simplify_path(const char *path)
930 if (path[0] == '/') 1731 if (path[0] == '/')
931 start = bb_xstrdup(path); 1732 start = bb_xstrdup(path);
932 else { 1733 else {
933 /* is not libbb, but this program has no chdir() */ 1734 /* is not libbb, but this program have not chdir() */
934 start = bb_asprint("%s/%s", pwd, path); 1735 start = bb_asprint("%s/%s", pwd, path);
935 } 1736 }
936 p = s = start; 1737 p = s = start;