diff options
author | Mike Frysinger <vapier@gentoo.org> | 2009-04-02 10:02:37 +0000 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2009-04-02 10:02:37 +0000 |
commit | 98c52645c02dacebccae7d68d6c2627f9318fcf7 (patch) | |
tree | e0c64b5b24206f95e72fd060336f74cb459f2109 /shell/ash.c | |
parent | 551ffdccea39a9223ad451954db40fd7a6e20e79 (diff) | |
download | busybox-w32-98c52645c02dacebccae7d68d6c2627f9318fcf7.tar.gz busybox-w32-98c52645c02dacebccae7d68d6c2627f9318fcf7.tar.bz2 busybox-w32-98c52645c02dacebccae7d68d6c2627f9318fcf7.zip |
split math code out of ash and into a standalone library so we can use it in any shell (like hush!)
Diffstat (limited to 'shell/ash.c')
-rw-r--r-- | shell/ash.c | 734 |
1 files changed, 35 insertions, 699 deletions
diff --git a/shell/ash.c b/shell/ash.c index 4f7f38f6d..0d3ab0ff5 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -17,19 +17,6 @@ | |||
17 | */ | 17 | */ |
18 | 18 | ||
19 | /* | 19 | /* |
20 | * rewrite arith.y to micro stack based cryptic algorithm by | ||
21 | * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com> | ||
22 | * | ||
23 | * Modified by Paul Mundt <lethal@linux-sh.org> (c) 2004 to support | ||
24 | * dynamic variables. | ||
25 | * | ||
26 | * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2005 to be | ||
27 | * used in busybox and size optimizations, | ||
28 | * rewrote arith (see notes to this), added locale support, | ||
29 | * rewrote dynamic variables. | ||
30 | */ | ||
31 | |||
32 | /* | ||
33 | * The following should be set to reflect the type of system you have: | 20 | * The following should be set to reflect the type of system you have: |
34 | * JOBS -> 1 if you have Berkeley job control, 0 otherwise. | 21 | * JOBS -> 1 if you have Berkeley job control, 0 otherwise. |
35 | * define SYSV if you are running under System V. | 22 | * define SYSV if you are running under System V. |
@@ -63,6 +50,7 @@ | |||
63 | #include <paths.h> | 50 | #include <paths.h> |
64 | #include <setjmp.h> | 51 | #include <setjmp.h> |
65 | #include <fnmatch.h> | 52 | #include <fnmatch.h> |
53 | #include "math.h" | ||
66 | 54 | ||
67 | #if defined SINGLE_APPLET_MAIN | 55 | #if defined SINGLE_APPLET_MAIN |
68 | /* STANDALONE does not make sense, and won't compile */ | 56 | /* STANDALONE does not make sense, and won't compile */ |
@@ -197,6 +185,10 @@ struct globals_misc { | |||
197 | #define debug optlist[15] | 185 | #define debug optlist[15] |
198 | #endif | 186 | #endif |
199 | 187 | ||
188 | #if ENABLE_SH_MATH_SUPPORT | ||
189 | arith_eval_hooks_t math_hooks; | ||
190 | #endif | ||
191 | |||
200 | /* trap handler commands */ | 192 | /* trap handler commands */ |
201 | /* | 193 | /* |
202 | * Sigmode records the current value of the signal handlers for the various | 194 | * Sigmode records the current value of the signal handlers for the various |
@@ -246,6 +238,7 @@ extern struct globals_misc *const ash_ptr_to_globals_misc; | |||
246 | #define random_LCG (G_misc.random_LCG ) | 238 | #define random_LCG (G_misc.random_LCG ) |
247 | #define backgndpid (G_misc.backgndpid ) | 239 | #define backgndpid (G_misc.backgndpid ) |
248 | #define job_warning (G_misc.job_warning) | 240 | #define job_warning (G_misc.job_warning) |
241 | #define math_hooks (G_misc.math_hooks ) | ||
249 | #define INIT_G_misc() do { \ | 242 | #define INIT_G_misc() do { \ |
250 | (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \ | 243 | (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \ |
251 | barrier(); \ | 244 | barrier(); \ |
@@ -1998,7 +1991,7 @@ findvar(struct var **vpp, const char *name) | |||
1998 | /* | 1991 | /* |
1999 | * Find the value of a variable. Returns NULL if not set. | 1992 | * Find the value of a variable. Returns NULL if not set. |
2000 | */ | 1993 | */ |
2001 | static char * | 1994 | static const char * |
2002 | lookupvar(const char *name) | 1995 | lookupvar(const char *name) |
2003 | { | 1996 | { |
2004 | struct var *v; | 1997 | struct var *v; |
@@ -2024,7 +2017,7 @@ lookupvar(const char *name) | |||
2024 | /* | 2017 | /* |
2025 | * Search the environment of a builtin command. | 2018 | * Search the environment of a builtin command. |
2026 | */ | 2019 | */ |
2027 | static char * | 2020 | static const char * |
2028 | bltinlookup(const char *name) | 2021 | bltinlookup(const char *name) |
2029 | { | 2022 | { |
2030 | struct strlist *sp; | 2023 | struct strlist *sp; |
@@ -2637,7 +2630,7 @@ pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
2637 | #define USE_SIT_FUNCTION | 2630 | #define USE_SIT_FUNCTION |
2638 | #endif | 2631 | #endif |
2639 | 2632 | ||
2640 | #if ENABLE_ASH_MATH_SUPPORT | 2633 | #if ENABLE_SH_MATH_SUPPORT |
2641 | static const char S_I_T[][4] = { | 2634 | static const char S_I_T[][4] = { |
2642 | #if ENABLE_ASH_ALIAS | 2635 | #if ENABLE_ASH_ALIAS |
2643 | { CSPCL, CIGN, CIGN, CIGN }, /* 0, PEOA */ | 2636 | { CSPCL, CIGN, CIGN, CIGN }, /* 0, PEOA */ |
@@ -2681,7 +2674,7 @@ static const char S_I_T[][3] = { | |||
2681 | { CCTL, CCTL, CCTL } /* 14, CTLESC ... */ | 2674 | { CCTL, CCTL, CCTL } /* 14, CTLESC ... */ |
2682 | #endif | 2675 | #endif |
2683 | }; | 2676 | }; |
2684 | #endif /* ASH_MATH_SUPPORT */ | 2677 | #endif /* SH_MATH_SUPPORT */ |
2685 | 2678 | ||
2686 | #ifdef USE_SIT_FUNCTION | 2679 | #ifdef USE_SIT_FUNCTION |
2687 | 2680 | ||
@@ -4273,7 +4266,7 @@ cmdputs(const char *s) | |||
4273 | case CTLBACKQ+CTLQUOTE: | 4266 | case CTLBACKQ+CTLQUOTE: |
4274 | str = "\"$(...)\""; | 4267 | str = "\"$(...)\""; |
4275 | goto dostr; | 4268 | goto dostr; |
4276 | #if ENABLE_ASH_MATH_SUPPORT | 4269 | #if ENABLE_SH_MATH_SUPPORT |
4277 | case CTLARI: | 4270 | case CTLARI: |
4278 | str = "$(("; | 4271 | str = "$(("; |
4279 | goto dostr; | 4272 | goto dostr; |
@@ -5258,17 +5251,8 @@ redirectsafe(union node *redir, int flags) | |||
5258 | * We have to deal with backquotes, shell variables, and file metacharacters. | 5251 | * We have to deal with backquotes, shell variables, and file metacharacters. |
5259 | */ | 5252 | */ |
5260 | 5253 | ||
5261 | #if ENABLE_ASH_MATH_SUPPORT_64 | 5254 | #if ENABLE_SH_MATH_SUPPORT |
5262 | typedef int64_t arith_t; | ||
5263 | #define arith_t_type long long | ||
5264 | #else | ||
5265 | typedef long arith_t; | ||
5266 | #define arith_t_type long | ||
5267 | #endif | ||
5268 | |||
5269 | #if ENABLE_ASH_MATH_SUPPORT | ||
5270 | static arith_t dash_arith(const char *); | 5255 | static arith_t dash_arith(const char *); |
5271 | static arith_t arith(const char *expr, int *perrcode); | ||
5272 | #endif | 5256 | #endif |
5273 | 5257 | ||
5274 | /* | 5258 | /* |
@@ -5328,11 +5312,7 @@ cvtnum(arith_t num) | |||
5328 | int len; | 5312 | int len; |
5329 | 5313 | ||
5330 | expdest = makestrspace(32, expdest); | 5314 | expdest = makestrspace(32, expdest); |
5331 | #if ENABLE_ASH_MATH_SUPPORT_64 | 5315 | len = fmtstr(expdest, 32, arith_t_fmt, num); |
5332 | len = fmtstr(expdest, 32, "%lld", (long long) num); | ||
5333 | #else | ||
5334 | len = fmtstr(expdest, 32, "%ld", num); | ||
5335 | #endif | ||
5336 | STADJUST(len, expdest); | 5316 | STADJUST(len, expdest); |
5337 | return len; | 5317 | return len; |
5338 | } | 5318 | } |
@@ -5696,7 +5676,7 @@ expbackq(union node *cmd, int quoted, int quotes) | |||
5696 | stackblock() + startloc)); | 5676 | stackblock() + startloc)); |
5697 | } | 5677 | } |
5698 | 5678 | ||
5699 | #if ENABLE_ASH_MATH_SUPPORT | 5679 | #if ENABLE_SH_MATH_SUPPORT |
5700 | /* | 5680 | /* |
5701 | * Expand arithmetic expression. Backup to start of expression, | 5681 | * Expand arithmetic expression. Backup to start of expression, |
5702 | * evaluate, place result in (backed up) result, adjust string position. | 5682 | * evaluate, place result in (backed up) result, adjust string position. |
@@ -5782,7 +5762,7 @@ argstr(char *p, int flag, struct strlist *var_str_list) | |||
5782 | CTLVAR, | 5762 | CTLVAR, |
5783 | CTLBACKQ, | 5763 | CTLBACKQ, |
5784 | CTLBACKQ | CTLQUOTE, | 5764 | CTLBACKQ | CTLQUOTE, |
5785 | #if ENABLE_ASH_MATH_SUPPORT | 5765 | #if ENABLE_SH_MATH_SUPPORT |
5786 | CTLENDARI, | 5766 | CTLENDARI, |
5787 | #endif | 5767 | #endif |
5788 | 0 | 5768 | 0 |
@@ -5819,7 +5799,7 @@ argstr(char *p, int flag, struct strlist *var_str_list) | |||
5819 | length += strcspn(p + length, reject); | 5799 | length += strcspn(p + length, reject); |
5820 | c = p[length]; | 5800 | c = p[length]; |
5821 | if (c && (!(c & 0x80) | 5801 | if (c && (!(c & 0x80) |
5822 | #if ENABLE_ASH_MATH_SUPPORT | 5802 | #if ENABLE_SH_MATH_SUPPORT |
5823 | || c == CTLENDARI | 5803 | || c == CTLENDARI |
5824 | #endif | 5804 | #endif |
5825 | )) { | 5805 | )) { |
@@ -5897,7 +5877,7 @@ argstr(char *p, int flag, struct strlist *var_str_list) | |||
5897 | expbackq(argbackq->n, c, quotes); | 5877 | expbackq(argbackq->n, c, quotes); |
5898 | argbackq = argbackq->next; | 5878 | argbackq = argbackq->next; |
5899 | goto start; | 5879 | goto start; |
5900 | #if ENABLE_ASH_MATH_SUPPORT | 5880 | #if ENABLE_SH_MATH_SUPPORT |
5901 | case CTLENDARI: | 5881 | case CTLENDARI: |
5902 | p--; | 5882 | p--; |
5903 | expari(quotes); | 5883 | expari(quotes); |
@@ -6291,7 +6271,7 @@ static ssize_t | |||
6291 | varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) | 6271 | varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) |
6292 | { | 6272 | { |
6293 | int num; | 6273 | int num; |
6294 | char *p; | 6274 | const char *p; |
6295 | int i; | 6275 | int i; |
6296 | int sep = 0; | 6276 | int sep = 0; |
6297 | int sepq = 0; | 6277 | int sepq = 0; |
@@ -6324,14 +6304,13 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) | |||
6324 | len = cvtnum(num); | 6304 | len = cvtnum(num); |
6325 | break; | 6305 | break; |
6326 | case '-': | 6306 | case '-': |
6327 | p = makestrspace(NOPTS, expdest); | 6307 | expdest = makestrspace(NOPTS, expdest); |
6328 | for (i = NOPTS - 1; i >= 0; i--) { | 6308 | for (i = NOPTS - 1; i >= 0; i--) { |
6329 | if (optlist[i]) { | 6309 | if (optlist[i]) { |
6330 | USTPUTC(optletters(i), p); | 6310 | USTPUTC(optletters(i), expdest); |
6331 | len++; | 6311 | len++; |
6332 | } | 6312 | } |
6333 | } | 6313 | } |
6334 | expdest = p; | ||
6335 | break; | 6314 | break; |
6336 | case '@': | 6315 | case '@': |
6337 | if (sep) | 6316 | if (sep) |
@@ -8710,7 +8689,7 @@ static int getoptscmd(int, char **); | |||
8710 | #if !ENABLE_FEATURE_SH_EXTRA_QUIET | 8689 | #if !ENABLE_FEATURE_SH_EXTRA_QUIET |
8711 | static int helpcmd(int, char **); | 8690 | static int helpcmd(int, char **); |
8712 | #endif | 8691 | #endif |
8713 | #if ENABLE_ASH_MATH_SUPPORT | 8692 | #if ENABLE_SH_MATH_SUPPORT |
8714 | static int letcmd(int, char **); | 8693 | static int letcmd(int, char **); |
8715 | #endif | 8694 | #endif |
8716 | static int readcmd(int, char **); | 8695 | static int readcmd(int, char **); |
@@ -8792,7 +8771,7 @@ static const struct builtincmd builtintab[] = { | |||
8792 | { BUILTIN_REGULAR "jobs", jobscmd }, | 8771 | { BUILTIN_REGULAR "jobs", jobscmd }, |
8793 | { BUILTIN_REGULAR "kill", killcmd }, | 8772 | { BUILTIN_REGULAR "kill", killcmd }, |
8794 | #endif | 8773 | #endif |
8795 | #if ENABLE_ASH_MATH_SUPPORT | 8774 | #if ENABLE_SH_MATH_SUPPORT |
8796 | { BUILTIN_NOSPEC "let", letcmd }, | 8775 | { BUILTIN_NOSPEC "let", letcmd }, |
8797 | #endif | 8776 | #endif |
8798 | { BUILTIN_ASSIGN "local", localcmd }, | 8777 | { BUILTIN_ASSIGN "local", localcmd }, |
@@ -10935,7 +10914,7 @@ readtoken1(int firstc, int syntax, char *eofmark, int striptabs) | |||
10935 | USTPUTC(c, out); | 10914 | USTPUTC(c, out); |
10936 | } | 10915 | } |
10937 | break; | 10916 | break; |
10938 | #if ENABLE_ASH_MATH_SUPPORT | 10917 | #if ENABLE_SH_MATH_SUPPORT |
10939 | case CLP: /* '(' in arithmetic */ | 10918 | case CLP: /* '(' in arithmetic */ |
10940 | parenlevel++; | 10919 | parenlevel++; |
10941 | USTPUTC(c, out); | 10920 | USTPUTC(c, out); |
@@ -10991,7 +10970,7 @@ readtoken1(int firstc, int syntax, char *eofmark, int striptabs) | |||
10991 | } /* for (;;) */ | 10970 | } /* for (;;) */ |
10992 | } | 10971 | } |
10993 | endword: | 10972 | endword: |
10994 | #if ENABLE_ASH_MATH_SUPPORT | 10973 | #if ENABLE_SH_MATH_SUPPORT |
10995 | if (syntax == ARISYNTAX) | 10974 | if (syntax == ARISYNTAX) |
10996 | raise_error_syntax("missing '))'"); | 10975 | raise_error_syntax("missing '))'"); |
10997 | #endif | 10976 | #endif |
@@ -11168,7 +11147,7 @@ parsesub: { | |||
11168 | pungetc(); | 11147 | pungetc(); |
11169 | } else if (c == '(') { /* $(command) or $((arith)) */ | 11148 | } else if (c == '(') { /* $(command) or $((arith)) */ |
11170 | if (pgetc() == '(') { | 11149 | if (pgetc() == '(') { |
11171 | #if ENABLE_ASH_MATH_SUPPORT | 11150 | #if ENABLE_SH_MATH_SUPPORT |
11172 | PARSEARITH(); | 11151 | PARSEARITH(); |
11173 | #else | 11152 | #else |
11174 | raise_error_syntax("you disabled math support for $((arith)) syntax"); | 11153 | raise_error_syntax("you disabled math support for $((arith)) syntax"); |
@@ -11423,7 +11402,7 @@ parsebackq: { | |||
11423 | goto parsebackq_newreturn; | 11402 | goto parsebackq_newreturn; |
11424 | } | 11403 | } |
11425 | 11404 | ||
11426 | #if ENABLE_ASH_MATH_SUPPORT | 11405 | #if ENABLE_SH_MATH_SUPPORT |
11427 | /* | 11406 | /* |
11428 | * Parse an arithmetic expansion (indicate start of one and set state) | 11407 | * Parse an arithmetic expansion (indicate start of one and set state) |
11429 | */ | 11408 | */ |
@@ -12384,7 +12363,7 @@ timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
12384 | return 0; | 12363 | return 0; |
12385 | } | 12364 | } |
12386 | 12365 | ||
12387 | #if ENABLE_ASH_MATH_SUPPORT | 12366 | #if ENABLE_SH_MATH_SUPPORT |
12388 | static arith_t | 12367 | static arith_t |
12389 | dash_arith(const char *s) | 12368 | dash_arith(const char *s) |
12390 | { | 12369 | { |
@@ -12392,7 +12371,7 @@ dash_arith(const char *s) | |||
12392 | int errcode = 0; | 12371 | int errcode = 0; |
12393 | 12372 | ||
12394 | INT_OFF; | 12373 | INT_OFF; |
12395 | result = arith(s, &errcode); | 12374 | result = arith(s, &errcode, &math_hooks); |
12396 | if (errcode < 0) { | 12375 | if (errcode < 0) { |
12397 | if (errcode == -3) | 12376 | if (errcode == -3) |
12398 | ash_msg_and_raise_error("exponent less than 0"); | 12377 | ash_msg_and_raise_error("exponent less than 0"); |
@@ -12427,7 +12406,7 @@ letcmd(int argc UNUSED_PARAM, char **argv) | |||
12427 | 12406 | ||
12428 | return !i; | 12407 | return !i; |
12429 | } | 12408 | } |
12430 | #endif /* ASH_MATH_SUPPORT */ | 12409 | #endif /* SH_MATH_SUPPORT */ |
12431 | 12410 | ||
12432 | 12411 | ||
12433 | /* ============ miscbltin.c | 12412 | /* ============ miscbltin.c |
@@ -12951,654 +12930,6 @@ ulimitcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
12951 | return 0; | 12930 | return 0; |
12952 | } | 12931 | } |
12953 | 12932 | ||
12954 | |||
12955 | /* ============ Math support */ | ||
12956 | |||
12957 | #if ENABLE_ASH_MATH_SUPPORT | ||
12958 | |||
12959 | /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com> | ||
12960 | |||
12961 | Permission is hereby granted, free of charge, to any person obtaining | ||
12962 | a copy of this software and associated documentation files (the | ||
12963 | "Software"), to deal in the Software without restriction, including | ||
12964 | without limitation the rights to use, copy, modify, merge, publish, | ||
12965 | distribute, sublicense, and/or sell copies of the Software, and to | ||
12966 | permit persons to whom the Software is furnished to do so, subject to | ||
12967 | the following conditions: | ||
12968 | |||
12969 | The above copyright notice and this permission notice shall be | ||
12970 | included in all copies or substantial portions of the Software. | ||
12971 | |||
12972 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
12973 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
12974 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
12975 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
12976 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
12977 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
12978 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
12979 | */ | ||
12980 | |||
12981 | /* This is my infix parser/evaluator. It is optimized for size, intended | ||
12982 | * as a replacement for yacc-based parsers. However, it may well be faster | ||
12983 | * than a comparable parser written in yacc. The supported operators are | ||
12984 | * listed in #defines below. Parens, order of operations, and error handling | ||
12985 | * are supported. This code is thread safe. The exact expression format should | ||
12986 | * be that which POSIX specifies for shells. */ | ||
12987 | |||
12988 | /* The code uses a simple two-stack algorithm. See | ||
12989 | * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html | ||
12990 | * for a detailed explanation of the infix-to-postfix algorithm on which | ||
12991 | * this is based (this code differs in that it applies operators immediately | ||
12992 | * to the stack instead of adding them to a queue to end up with an | ||
12993 | * expression). */ | ||
12994 | |||
12995 | /* To use the routine, call it with an expression string and error return | ||
12996 | * pointer */ | ||
12997 | |||
12998 | /* | ||
12999 | * Aug 24, 2001 Manuel Novoa III | ||
13000 | * | ||
13001 | * Reduced the generated code size by about 30% (i386) and fixed several bugs. | ||
13002 | * | ||
13003 | * 1) In arith_apply(): | ||
13004 | * a) Cached values of *numptr and &(numptr[-1]). | ||
13005 | * b) Removed redundant test for zero denominator. | ||
13006 | * | ||
13007 | * 2) In arith(): | ||
13008 | * a) Eliminated redundant code for processing operator tokens by moving | ||
13009 | * to a table-based implementation. Also folded handling of parens | ||
13010 | * into the table. | ||
13011 | * b) Combined all 3 loops which called arith_apply to reduce generated | ||
13012 | * code size at the cost of speed. | ||
13013 | * | ||
13014 | * 3) The following expressions were treated as valid by the original code: | ||
13015 | * 1() , 0! , 1 ( *3 ) . | ||
13016 | * These bugs have been fixed by internally enclosing the expression in | ||
13017 | * parens and then checking that all binary ops and right parens are | ||
13018 | * preceded by a valid expression (NUM_TOKEN). | ||
13019 | * | ||
13020 | * Note: It may be desirable to replace Aaron's test for whitespace with | ||
13021 | * ctype's isspace() if it is used by another busybox applet or if additional | ||
13022 | * whitespace chars should be considered. Look below the "#include"s for a | ||
13023 | * precompiler test. | ||
13024 | */ | ||
13025 | |||
13026 | /* | ||
13027 | * Aug 26, 2001 Manuel Novoa III | ||
13028 | * | ||
13029 | * Return 0 for null expressions. Pointed out by Vladimir Oleynik. | ||
13030 | * | ||
13031 | * Merge in Aaron's comments previously posted to the busybox list, | ||
13032 | * modified slightly to take account of my changes to the code. | ||
13033 | * | ||
13034 | */ | ||
13035 | |||
13036 | /* | ||
13037 | * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru> | ||
13038 | * | ||
13039 | * - allow access to variable, | ||
13040 | * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6) | ||
13041 | * - realize assign syntax (VAR=expr, +=, *= etc) | ||
13042 | * - realize exponentiation (** operator) | ||
13043 | * - realize comma separated - expr, expr | ||
13044 | * - realise ++expr --expr expr++ expr-- | ||
13045 | * - realise expr ? expr : expr (but, second expr calculate always) | ||
13046 | * - allow hexadecimal and octal numbers | ||
13047 | * - was restored loses XOR operator | ||
13048 | * - remove one goto label, added three ;-) | ||
13049 | * - protect $((num num)) as true zero expr (Manuel`s error) | ||
13050 | * - always use special isspace(), see comment from bash ;-) | ||
13051 | */ | ||
13052 | |||
13053 | #define arith_isspace(arithval) \ | ||
13054 | (arithval == ' ' || arithval == '\n' || arithval == '\t') | ||
13055 | |||
13056 | typedef unsigned char operator; | ||
13057 | |||
13058 | /* An operator's token id is a bit of a bitfield. The lower 5 bits are the | ||
13059 | * precedence, and 3 high bits are an ID unique across operators of that | ||
13060 | * precedence. The ID portion is so that multiple operators can have the | ||
13061 | * same precedence, ensuring that the leftmost one is evaluated first. | ||
13062 | * Consider * and /. */ | ||
13063 | |||
13064 | #define tok_decl(prec,id) (((id)<<5)|(prec)) | ||
13065 | #define PREC(op) ((op) & 0x1F) | ||
13066 | |||
13067 | #define TOK_LPAREN tok_decl(0,0) | ||
13068 | |||
13069 | #define TOK_COMMA tok_decl(1,0) | ||
13070 | |||
13071 | #define TOK_ASSIGN tok_decl(2,0) | ||
13072 | #define TOK_AND_ASSIGN tok_decl(2,1) | ||
13073 | #define TOK_OR_ASSIGN tok_decl(2,2) | ||
13074 | #define TOK_XOR_ASSIGN tok_decl(2,3) | ||
13075 | #define TOK_PLUS_ASSIGN tok_decl(2,4) | ||
13076 | #define TOK_MINUS_ASSIGN tok_decl(2,5) | ||
13077 | #define TOK_LSHIFT_ASSIGN tok_decl(2,6) | ||
13078 | #define TOK_RSHIFT_ASSIGN tok_decl(2,7) | ||
13079 | |||
13080 | #define TOK_MUL_ASSIGN tok_decl(3,0) | ||
13081 | #define TOK_DIV_ASSIGN tok_decl(3,1) | ||
13082 | #define TOK_REM_ASSIGN tok_decl(3,2) | ||
13083 | |||
13084 | /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */ | ||
13085 | #define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0) | ||
13086 | |||
13087 | /* conditional is right associativity too */ | ||
13088 | #define TOK_CONDITIONAL tok_decl(4,0) | ||
13089 | #define TOK_CONDITIONAL_SEP tok_decl(4,1) | ||
13090 | |||
13091 | #define TOK_OR tok_decl(5,0) | ||
13092 | |||
13093 | #define TOK_AND tok_decl(6,0) | ||
13094 | |||
13095 | #define TOK_BOR tok_decl(7,0) | ||
13096 | |||
13097 | #define TOK_BXOR tok_decl(8,0) | ||
13098 | |||
13099 | #define TOK_BAND tok_decl(9,0) | ||
13100 | |||
13101 | #define TOK_EQ tok_decl(10,0) | ||
13102 | #define TOK_NE tok_decl(10,1) | ||
13103 | |||
13104 | #define TOK_LT tok_decl(11,0) | ||
13105 | #define TOK_GT tok_decl(11,1) | ||
13106 | #define TOK_GE tok_decl(11,2) | ||
13107 | #define TOK_LE tok_decl(11,3) | ||
13108 | |||
13109 | #define TOK_LSHIFT tok_decl(12,0) | ||
13110 | #define TOK_RSHIFT tok_decl(12,1) | ||
13111 | |||
13112 | #define TOK_ADD tok_decl(13,0) | ||
13113 | #define TOK_SUB tok_decl(13,1) | ||
13114 | |||
13115 | #define TOK_MUL tok_decl(14,0) | ||
13116 | #define TOK_DIV tok_decl(14,1) | ||
13117 | #define TOK_REM tok_decl(14,2) | ||
13118 | |||
13119 | /* exponent is right associativity */ | ||
13120 | #define TOK_EXPONENT tok_decl(15,1) | ||
13121 | |||
13122 | /* For now unary operators. */ | ||
13123 | #define UNARYPREC 16 | ||
13124 | #define TOK_BNOT tok_decl(UNARYPREC,0) | ||
13125 | #define TOK_NOT tok_decl(UNARYPREC,1) | ||
13126 | |||
13127 | #define TOK_UMINUS tok_decl(UNARYPREC+1,0) | ||
13128 | #define TOK_UPLUS tok_decl(UNARYPREC+1,1) | ||
13129 | |||
13130 | #define PREC_PRE (UNARYPREC+2) | ||
13131 | |||
13132 | #define TOK_PRE_INC tok_decl(PREC_PRE, 0) | ||
13133 | #define TOK_PRE_DEC tok_decl(PREC_PRE, 1) | ||
13134 | |||
13135 | #define PREC_POST (UNARYPREC+3) | ||
13136 | |||
13137 | #define TOK_POST_INC tok_decl(PREC_POST, 0) | ||
13138 | #define TOK_POST_DEC tok_decl(PREC_POST, 1) | ||
13139 | |||
13140 | #define SPEC_PREC (UNARYPREC+4) | ||
13141 | |||
13142 | #define TOK_NUM tok_decl(SPEC_PREC, 0) | ||
13143 | #define TOK_RPAREN tok_decl(SPEC_PREC, 1) | ||
13144 | |||
13145 | #define NUMPTR (*numstackptr) | ||
13146 | |||
13147 | static int | ||
13148 | tok_have_assign(operator op) | ||
13149 | { | ||
13150 | operator prec = PREC(op); | ||
13151 | |||
13152 | convert_prec_is_assing(prec); | ||
13153 | return (prec == PREC(TOK_ASSIGN) || | ||
13154 | prec == PREC_PRE || prec == PREC_POST); | ||
13155 | } | ||
13156 | |||
13157 | static int | ||
13158 | is_right_associativity(operator prec) | ||
13159 | { | ||
13160 | return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) | ||
13161 | || prec == PREC(TOK_CONDITIONAL)); | ||
13162 | } | ||
13163 | |||
13164 | typedef struct { | ||
13165 | arith_t val; | ||
13166 | arith_t contidional_second_val; | ||
13167 | char contidional_second_val_initialized; | ||
13168 | char *var; /* if NULL then is regular number, | ||
13169 | else is variable name */ | ||
13170 | } v_n_t; | ||
13171 | |||
13172 | typedef struct chk_var_recursive_looped_t { | ||
13173 | const char *var; | ||
13174 | struct chk_var_recursive_looped_t *next; | ||
13175 | } chk_var_recursive_looped_t; | ||
13176 | |||
13177 | static chk_var_recursive_looped_t *prev_chk_var_recursive; | ||
13178 | |||
13179 | static int | ||
13180 | arith_lookup_val(v_n_t *t) | ||
13181 | { | ||
13182 | if (t->var) { | ||
13183 | const char * p = lookupvar(t->var); | ||
13184 | |||
13185 | if (p) { | ||
13186 | int errcode; | ||
13187 | |||
13188 | /* recursive try as expression */ | ||
13189 | chk_var_recursive_looped_t *cur; | ||
13190 | chk_var_recursive_looped_t cur_save; | ||
13191 | |||
13192 | for (cur = prev_chk_var_recursive; cur; cur = cur->next) { | ||
13193 | if (strcmp(cur->var, t->var) == 0) { | ||
13194 | /* expression recursion loop detected */ | ||
13195 | return -5; | ||
13196 | } | ||
13197 | } | ||
13198 | /* save current lookuped var name */ | ||
13199 | cur = prev_chk_var_recursive; | ||
13200 | cur_save.var = t->var; | ||
13201 | cur_save.next = cur; | ||
13202 | prev_chk_var_recursive = &cur_save; | ||
13203 | |||
13204 | t->val = arith (p, &errcode); | ||
13205 | /* restore previous ptr after recursiving */ | ||
13206 | prev_chk_var_recursive = cur; | ||
13207 | return errcode; | ||
13208 | } | ||
13209 | /* allow undefined var as 0 */ | ||
13210 | t->val = 0; | ||
13211 | } | ||
13212 | return 0; | ||
13213 | } | ||
13214 | |||
13215 | /* "applying" a token means performing it on the top elements on the integer | ||
13216 | * stack. For a unary operator it will only change the top element, but a | ||
13217 | * binary operator will pop two arguments and push a result */ | ||
13218 | static int | ||
13219 | arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr) | ||
13220 | { | ||
13221 | v_n_t *numptr_m1; | ||
13222 | arith_t numptr_val, rez; | ||
13223 | int ret_arith_lookup_val; | ||
13224 | |||
13225 | /* There is no operator that can work without arguments */ | ||
13226 | if (NUMPTR == numstack) goto err; | ||
13227 | numptr_m1 = NUMPTR - 1; | ||
13228 | |||
13229 | /* check operand is var with noninteger value */ | ||
13230 | ret_arith_lookup_val = arith_lookup_val(numptr_m1); | ||
13231 | if (ret_arith_lookup_val) | ||
13232 | return ret_arith_lookup_val; | ||
13233 | |||
13234 | rez = numptr_m1->val; | ||
13235 | if (op == TOK_UMINUS) | ||
13236 | rez *= -1; | ||
13237 | else if (op == TOK_NOT) | ||
13238 | rez = !rez; | ||
13239 | else if (op == TOK_BNOT) | ||
13240 | rez = ~rez; | ||
13241 | else if (op == TOK_POST_INC || op == TOK_PRE_INC) | ||
13242 | rez++; | ||
13243 | else if (op == TOK_POST_DEC || op == TOK_PRE_DEC) | ||
13244 | rez--; | ||
13245 | else if (op != TOK_UPLUS) { | ||
13246 | /* Binary operators */ | ||
13247 | |||
13248 | /* check and binary operators need two arguments */ | ||
13249 | if (numptr_m1 == numstack) goto err; | ||
13250 | |||
13251 | /* ... and they pop one */ | ||
13252 | --NUMPTR; | ||
13253 | numptr_val = rez; | ||
13254 | if (op == TOK_CONDITIONAL) { | ||
13255 | if (!numptr_m1->contidional_second_val_initialized) { | ||
13256 | /* protect $((expr1 ? expr2)) without ": expr" */ | ||
13257 | goto err; | ||
13258 | } | ||
13259 | rez = numptr_m1->contidional_second_val; | ||
13260 | } else if (numptr_m1->contidional_second_val_initialized) { | ||
13261 | /* protect $((expr1 : expr2)) without "expr ? " */ | ||
13262 | goto err; | ||
13263 | } | ||
13264 | numptr_m1 = NUMPTR - 1; | ||
13265 | if (op != TOK_ASSIGN) { | ||
13266 | /* check operand is var with noninteger value for not '=' */ | ||
13267 | ret_arith_lookup_val = arith_lookup_val(numptr_m1); | ||
13268 | if (ret_arith_lookup_val) | ||
13269 | return ret_arith_lookup_val; | ||
13270 | } | ||
13271 | if (op == TOK_CONDITIONAL) { | ||
13272 | numptr_m1->contidional_second_val = rez; | ||
13273 | } | ||
13274 | rez = numptr_m1->val; | ||
13275 | if (op == TOK_BOR || op == TOK_OR_ASSIGN) | ||
13276 | rez |= numptr_val; | ||
13277 | else if (op == TOK_OR) | ||
13278 | rez = numptr_val || rez; | ||
13279 | else if (op == TOK_BAND || op == TOK_AND_ASSIGN) | ||
13280 | rez &= numptr_val; | ||
13281 | else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN) | ||
13282 | rez ^= numptr_val; | ||
13283 | else if (op == TOK_AND) | ||
13284 | rez = rez && numptr_val; | ||
13285 | else if (op == TOK_EQ) | ||
13286 | rez = (rez == numptr_val); | ||
13287 | else if (op == TOK_NE) | ||
13288 | rez = (rez != numptr_val); | ||
13289 | else if (op == TOK_GE) | ||
13290 | rez = (rez >= numptr_val); | ||
13291 | else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN) | ||
13292 | rez >>= numptr_val; | ||
13293 | else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN) | ||
13294 | rez <<= numptr_val; | ||
13295 | else if (op == TOK_GT) | ||
13296 | rez = (rez > numptr_val); | ||
13297 | else if (op == TOK_LT) | ||
13298 | rez = (rez < numptr_val); | ||
13299 | else if (op == TOK_LE) | ||
13300 | rez = (rez <= numptr_val); | ||
13301 | else if (op == TOK_MUL || op == TOK_MUL_ASSIGN) | ||
13302 | rez *= numptr_val; | ||
13303 | else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN) | ||
13304 | rez += numptr_val; | ||
13305 | else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN) | ||
13306 | rez -= numptr_val; | ||
13307 | else if (op == TOK_ASSIGN || op == TOK_COMMA) | ||
13308 | rez = numptr_val; | ||
13309 | else if (op == TOK_CONDITIONAL_SEP) { | ||
13310 | if (numptr_m1 == numstack) { | ||
13311 | /* protect $((expr : expr)) without "expr ? " */ | ||
13312 | goto err; | ||
13313 | } | ||
13314 | numptr_m1->contidional_second_val_initialized = op; | ||
13315 | numptr_m1->contidional_second_val = numptr_val; | ||
13316 | } else if (op == TOK_CONDITIONAL) { | ||
13317 | rez = rez ? | ||
13318 | numptr_val : numptr_m1->contidional_second_val; | ||
13319 | } else if (op == TOK_EXPONENT) { | ||
13320 | if (numptr_val < 0) | ||
13321 | return -3; /* exponent less than 0 */ | ||
13322 | else { | ||
13323 | arith_t c = 1; | ||
13324 | |||
13325 | if (numptr_val) | ||
13326 | while (numptr_val--) | ||
13327 | c *= rez; | ||
13328 | rez = c; | ||
13329 | } | ||
13330 | } else if (numptr_val==0) /* zero divisor check */ | ||
13331 | return -2; | ||
13332 | else if (op == TOK_DIV || op == TOK_DIV_ASSIGN) | ||
13333 | rez /= numptr_val; | ||
13334 | else if (op == TOK_REM || op == TOK_REM_ASSIGN) | ||
13335 | rez %= numptr_val; | ||
13336 | } | ||
13337 | if (tok_have_assign(op)) { | ||
13338 | char buf[sizeof(arith_t_type)*3 + 2]; | ||
13339 | |||
13340 | if (numptr_m1->var == NULL) { | ||
13341 | /* Hmm, 1=2 ? */ | ||
13342 | goto err; | ||
13343 | } | ||
13344 | /* save to shell variable */ | ||
13345 | #if ENABLE_ASH_MATH_SUPPORT_64 | ||
13346 | snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez); | ||
13347 | #else | ||
13348 | snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez); | ||
13349 | #endif | ||
13350 | setvar(numptr_m1->var, buf, 0); | ||
13351 | /* after saving, make previous value for v++ or v-- */ | ||
13352 | if (op == TOK_POST_INC) | ||
13353 | rez--; | ||
13354 | else if (op == TOK_POST_DEC) | ||
13355 | rez++; | ||
13356 | } | ||
13357 | numptr_m1->val = rez; | ||
13358 | /* protect geting var value, is number now */ | ||
13359 | numptr_m1->var = NULL; | ||
13360 | return 0; | ||
13361 | err: | ||
13362 | return -1; | ||
13363 | } | ||
13364 | |||
13365 | /* longest must be first */ | ||
13366 | static const char op_tokens[] ALIGN1 = { | ||
13367 | '<','<','=',0, TOK_LSHIFT_ASSIGN, | ||
13368 | '>','>','=',0, TOK_RSHIFT_ASSIGN, | ||
13369 | '<','<', 0, TOK_LSHIFT, | ||
13370 | '>','>', 0, TOK_RSHIFT, | ||
13371 | '|','|', 0, TOK_OR, | ||
13372 | '&','&', 0, TOK_AND, | ||
13373 | '!','=', 0, TOK_NE, | ||
13374 | '<','=', 0, TOK_LE, | ||
13375 | '>','=', 0, TOK_GE, | ||
13376 | '=','=', 0, TOK_EQ, | ||
13377 | '|','=', 0, TOK_OR_ASSIGN, | ||
13378 | '&','=', 0, TOK_AND_ASSIGN, | ||
13379 | '*','=', 0, TOK_MUL_ASSIGN, | ||
13380 | '/','=', 0, TOK_DIV_ASSIGN, | ||
13381 | '%','=', 0, TOK_REM_ASSIGN, | ||
13382 | '+','=', 0, TOK_PLUS_ASSIGN, | ||
13383 | '-','=', 0, TOK_MINUS_ASSIGN, | ||
13384 | '-','-', 0, TOK_POST_DEC, | ||
13385 | '^','=', 0, TOK_XOR_ASSIGN, | ||
13386 | '+','+', 0, TOK_POST_INC, | ||
13387 | '*','*', 0, TOK_EXPONENT, | ||
13388 | '!', 0, TOK_NOT, | ||
13389 | '<', 0, TOK_LT, | ||
13390 | '>', 0, TOK_GT, | ||
13391 | '=', 0, TOK_ASSIGN, | ||
13392 | '|', 0, TOK_BOR, | ||
13393 | '&', 0, TOK_BAND, | ||
13394 | '*', 0, TOK_MUL, | ||
13395 | '/', 0, TOK_DIV, | ||
13396 | '%', 0, TOK_REM, | ||
13397 | '+', 0, TOK_ADD, | ||
13398 | '-', 0, TOK_SUB, | ||
13399 | '^', 0, TOK_BXOR, | ||
13400 | /* uniq */ | ||
13401 | '~', 0, TOK_BNOT, | ||
13402 | ',', 0, TOK_COMMA, | ||
13403 | '?', 0, TOK_CONDITIONAL, | ||
13404 | ':', 0, TOK_CONDITIONAL_SEP, | ||
13405 | ')', 0, TOK_RPAREN, | ||
13406 | '(', 0, TOK_LPAREN, | ||
13407 | 0 | ||
13408 | }; | ||
13409 | /* ptr to ")" */ | ||
13410 | #define endexpression (&op_tokens[sizeof(op_tokens)-7]) | ||
13411 | |||
13412 | static arith_t | ||
13413 | arith(const char *expr, int *perrcode) | ||
13414 | { | ||
13415 | char arithval; /* Current character under analysis */ | ||
13416 | operator lasttok, op; | ||
13417 | operator prec; | ||
13418 | operator *stack, *stackptr; | ||
13419 | const char *p = endexpression; | ||
13420 | int errcode; | ||
13421 | v_n_t *numstack, *numstackptr; | ||
13422 | unsigned datasizes = strlen(expr) + 2; | ||
13423 | |||
13424 | /* Stack of integers */ | ||
13425 | /* The proof that there can be no more than strlen(startbuf)/2+1 integers | ||
13426 | * in any given correct or incorrect expression is left as an exercise to | ||
13427 | * the reader. */ | ||
13428 | numstackptr = numstack = alloca((datasizes / 2) * sizeof(numstack[0])); | ||
13429 | /* Stack of operator tokens */ | ||
13430 | stackptr = stack = alloca(datasizes * sizeof(stack[0])); | ||
13431 | |||
13432 | *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */ | ||
13433 | *perrcode = errcode = 0; | ||
13434 | |||
13435 | while (1) { | ||
13436 | arithval = *expr; | ||
13437 | if (arithval == 0) { | ||
13438 | if (p == endexpression) { | ||
13439 | /* Null expression. */ | ||
13440 | return 0; | ||
13441 | } | ||
13442 | |||
13443 | /* This is only reached after all tokens have been extracted from the | ||
13444 | * input stream. If there are still tokens on the operator stack, they | ||
13445 | * are to be applied in order. At the end, there should be a final | ||
13446 | * result on the integer stack */ | ||
13447 | |||
13448 | if (expr != endexpression + 1) { | ||
13449 | /* If we haven't done so already, */ | ||
13450 | /* append a closing right paren */ | ||
13451 | expr = endexpression; | ||
13452 | /* and let the loop process it. */ | ||
13453 | continue; | ||
13454 | } | ||
13455 | /* At this point, we're done with the expression. */ | ||
13456 | if (numstackptr != numstack+1) { | ||
13457 | /* ... but if there isn't, it's bad */ | ||
13458 | err: | ||
13459 | *perrcode = -1; | ||
13460 | return *perrcode; | ||
13461 | } | ||
13462 | if (numstack->var) { | ||
13463 | /* expression is $((var)) only, lookup now */ | ||
13464 | errcode = arith_lookup_val(numstack); | ||
13465 | } | ||
13466 | ret: | ||
13467 | *perrcode = errcode; | ||
13468 | return numstack->val; | ||
13469 | } | ||
13470 | |||
13471 | /* Continue processing the expression. */ | ||
13472 | if (arith_isspace(arithval)) { | ||
13473 | /* Skip whitespace */ | ||
13474 | goto prologue; | ||
13475 | } | ||
13476 | p = endofname(expr); | ||
13477 | if (p != expr) { | ||
13478 | size_t var_name_size = (p-expr) + 1; /* trailing zero */ | ||
13479 | |||
13480 | numstackptr->var = alloca(var_name_size); | ||
13481 | safe_strncpy(numstackptr->var, expr, var_name_size); | ||
13482 | expr = p; | ||
13483 | num: | ||
13484 | numstackptr->contidional_second_val_initialized = 0; | ||
13485 | numstackptr++; | ||
13486 | lasttok = TOK_NUM; | ||
13487 | continue; | ||
13488 | } | ||
13489 | if (isdigit(arithval)) { | ||
13490 | numstackptr->var = NULL; | ||
13491 | #if ENABLE_ASH_MATH_SUPPORT_64 | ||
13492 | numstackptr->val = strtoll(expr, (char **) &expr, 0); | ||
13493 | #else | ||
13494 | numstackptr->val = strtol(expr, (char **) &expr, 0); | ||
13495 | #endif | ||
13496 | goto num; | ||
13497 | } | ||
13498 | for (p = op_tokens; ; p++) { | ||
13499 | const char *o; | ||
13500 | |||
13501 | if (*p == 0) { | ||
13502 | /* strange operator not found */ | ||
13503 | goto err; | ||
13504 | } | ||
13505 | for (o = expr; *p && *o == *p; p++) | ||
13506 | o++; | ||
13507 | if (!*p) { | ||
13508 | /* found */ | ||
13509 | expr = o - 1; | ||
13510 | break; | ||
13511 | } | ||
13512 | /* skip tail uncompared token */ | ||
13513 | while (*p) | ||
13514 | p++; | ||
13515 | /* skip zero delim */ | ||
13516 | p++; | ||
13517 | } | ||
13518 | op = p[1]; | ||
13519 | |||
13520 | /* post grammar: a++ reduce to num */ | ||
13521 | if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC) | ||
13522 | lasttok = TOK_NUM; | ||
13523 | |||
13524 | /* Plus and minus are binary (not unary) _only_ if the last | ||
13525 | * token was as number, or a right paren (which pretends to be | ||
13526 | * a number, since it evaluates to one). Think about it. | ||
13527 | * It makes sense. */ | ||
13528 | if (lasttok != TOK_NUM) { | ||
13529 | switch (op) { | ||
13530 | case TOK_ADD: | ||
13531 | op = TOK_UPLUS; | ||
13532 | break; | ||
13533 | case TOK_SUB: | ||
13534 | op = TOK_UMINUS; | ||
13535 | break; | ||
13536 | case TOK_POST_INC: | ||
13537 | op = TOK_PRE_INC; | ||
13538 | break; | ||
13539 | case TOK_POST_DEC: | ||
13540 | op = TOK_PRE_DEC; | ||
13541 | break; | ||
13542 | } | ||
13543 | } | ||
13544 | /* We don't want a unary operator to cause recursive descent on the | ||
13545 | * stack, because there can be many in a row and it could cause an | ||
13546 | * operator to be evaluated before its argument is pushed onto the | ||
13547 | * integer stack. */ | ||
13548 | /* But for binary operators, "apply" everything on the operator | ||
13549 | * stack until we find an operator with a lesser priority than the | ||
13550 | * one we have just extracted. */ | ||
13551 | /* Left paren is given the lowest priority so it will never be | ||
13552 | * "applied" in this way. | ||
13553 | * if associativity is right and priority eq, applied also skip | ||
13554 | */ | ||
13555 | prec = PREC(op); | ||
13556 | if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) { | ||
13557 | /* not left paren or unary */ | ||
13558 | if (lasttok != TOK_NUM) { | ||
13559 | /* binary op must be preceded by a num */ | ||
13560 | goto err; | ||
13561 | } | ||
13562 | while (stackptr != stack) { | ||
13563 | if (op == TOK_RPAREN) { | ||
13564 | /* The algorithm employed here is simple: while we don't | ||
13565 | * hit an open paren nor the bottom of the stack, pop | ||
13566 | * tokens and apply them */ | ||
13567 | if (stackptr[-1] == TOK_LPAREN) { | ||
13568 | --stackptr; | ||
13569 | /* Any operator directly after a */ | ||
13570 | lasttok = TOK_NUM; | ||
13571 | /* close paren should consider itself binary */ | ||
13572 | goto prologue; | ||
13573 | } | ||
13574 | } else { | ||
13575 | operator prev_prec = PREC(stackptr[-1]); | ||
13576 | |||
13577 | convert_prec_is_assing(prec); | ||
13578 | convert_prec_is_assing(prev_prec); | ||
13579 | if (prev_prec < prec) | ||
13580 | break; | ||
13581 | /* check right assoc */ | ||
13582 | if (prev_prec == prec && is_right_associativity(prec)) | ||
13583 | break; | ||
13584 | } | ||
13585 | errcode = arith_apply(*--stackptr, numstack, &numstackptr); | ||
13586 | if (errcode) goto ret; | ||
13587 | } | ||
13588 | if (op == TOK_RPAREN) { | ||
13589 | goto err; | ||
13590 | } | ||
13591 | } | ||
13592 | |||
13593 | /* Push this operator to the stack and remember it. */ | ||
13594 | *stackptr++ = lasttok = op; | ||
13595 | prologue: | ||
13596 | ++expr; | ||
13597 | } /* while */ | ||
13598 | } | ||
13599 | #endif /* ASH_MATH_SUPPORT */ | ||
13600 | |||
13601 | |||
13602 | /* ============ main() and helpers */ | 12933 | /* ============ main() and helpers */ |
13603 | 12934 | ||
13604 | /* | 12935 | /* |
@@ -13786,7 +13117,7 @@ extern int etext(); | |||
13786 | int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 13117 | int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
13787 | int ash_main(int argc UNUSED_PARAM, char **argv) | 13118 | int ash_main(int argc UNUSED_PARAM, char **argv) |
13788 | { | 13119 | { |
13789 | char *shinit; | 13120 | const char *shinit; |
13790 | volatile smallint state; | 13121 | volatile smallint state; |
13791 | struct jmploc jmploc; | 13122 | struct jmploc jmploc; |
13792 | struct stackmark smark; | 13123 | struct stackmark smark; |
@@ -13799,6 +13130,11 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
13799 | INIT_G_alias(); | 13130 | INIT_G_alias(); |
13800 | #endif | 13131 | #endif |
13801 | INIT_G_cmdtable(); | 13132 | INIT_G_cmdtable(); |
13133 | #if ENABLE_SH_MATH_SUPPORT | ||
13134 | math_hooks.lookupvar = lookupvar; | ||
13135 | math_hooks.setvar = setvar; | ||
13136 | math_hooks.endofname = endofname; | ||
13137 | #endif | ||
13802 | 13138 | ||
13803 | #if PROFILE | 13139 | #if PROFILE |
13804 | monitor(4, etext, profile_buf, sizeof(profile_buf), 50); | 13140 | monitor(4, etext, profile_buf, sizeof(profile_buf), 50); |