1 /* $NetBSD: arith_token.c,v 1.7 2017/12/17 04:06:03 kre Exp $ */ 2 3 /*- 4 * Copyright (c) 2002 5 * Herbert Xu. 6 * Copyright (c) 1991, 1993 7 * The Regents of the University of California. All rights reserved. 8 * 9 * This code is derived from software contributed to Berkeley by 10 * Kenneth Almquist. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * From FreeBSD, from dash 37 */ 38 39 #include <sys/cdefs.h> 40 41 #ifndef lint 42 __RCSID("$NetBSD: arith_token.c,v 1.7 2017/12/17 04:06:03 kre Exp $"); 43 #endif /* not lint */ 44 45 #include <inttypes.h> 46 #include <limits.h> 47 #include <stdlib.h> 48 #include <string.h> 49 50 #include "shell.h" 51 #include "arith_tokens.h" 52 #include "expand.h" 53 #include "error.h" 54 #include "memalloc.h" 55 #include "parser.h" 56 #include "syntax.h" 57 #include "show.h" 58 59 #if ARITH_BOR + ARITH_ASS_GAP != ARITH_BORASS || \ 60 ARITH_ASS + ARITH_ASS_GAP != ARITH_EQ 61 #error Arithmetic tokens are out of order. 62 #endif 63 64 /* 65 * Scan next arithmetic token, return its type, 66 * leave its value (when applicable) in (global) a_t_val. 67 * 68 * Input text is in (global) arith_buf which is updated to 69 * refer to the next char after the token returned, except 70 * on error (ARITH_BAD returned) where arith_buf is not altered. 71 */ 72 int 73 arith_token(void) 74 { 75 int token; 76 const char *buf = arith_buf; 77 char *end; 78 const char *p; 79 80 for (;;) { 81 token = *buf; 82 83 if (isdigit(token)) { 84 /* 85 * Numbers all start with a digit, and nothing 86 * else does, the number ends wherever 87 * strtoimax() stops... 88 */ 89 a_t_val.val = strtoimax(buf, &end, 0); 90 if (is_in_name(*end)) { 91 token = *end; 92 while (is_in_name(*++end)) 93 continue; 94 error("arithmetic: unexpected '%c' " 95 "(out of range) in numeric constant: " 96 "%.*s", token, (int)(end - buf), buf); 97 } 98 arith_buf = end; 99 VTRACE(DBG_ARITH, ("Arith token ARITH_NUM=%jd\n", 100 a_t_val.val)); 101 return ARITH_NUM; 102 103 } else if (is_name(token)) { 104 /* 105 * Variable names all start with an alpha (or '_') 106 * and nothing else does. They continue for the 107 * longest unbroken sequence of alphanumerics ( + _ ) 108 */ 109 arith_var_lno = arith_lno; 110 p = buf; 111 while (buf++, is_in_name(*buf)) 112 ; 113 a_t_val.name = stalloc(buf - p + 1); 114 memcpy(a_t_val.name, p, buf - p); 115 a_t_val.name[buf - p] = '\0'; 116 arith_buf = buf; 117 VTRACE(DBG_ARITH, ("Arith token ARITH_VAR=\"%s\"\n", 118 a_t_val.name)); 119 return ARITH_VAR; 120 121 } else switch (token) { 122 /* 123 * everything else must be some kind of 124 * operator, white space, or an error. 125 */ 126 case '\n': 127 arith_lno++; 128 VTRACE(DBG_ARITH, ("Arith: newline\n")); 129 /* FALLTHROUGH */ 130 case ' ': 131 case '\t': 132 buf++; 133 continue; 134 135 default: 136 error("arithmetic: unexpected '%c' (%#x) in expression", 137 token, token); 138 /* NOTREACHED */ 139 140 case '=': 141 token = ARITH_ASS; 142 checkeq: 143 buf++; 144 checkeqcur: 145 if (*buf != '=') 146 goto out; 147 token += ARITH_ASS_GAP; 148 break; 149 150 case '>': 151 switch (*++buf) { 152 case '=': 153 token = ARITH_GE; 154 break; 155 case '>': 156 token = ARITH_RSHIFT; 157 goto checkeq; 158 default: 159 token = ARITH_GT; 160 goto out; 161 } 162 break; 163 164 case '<': 165 switch (*++buf) { 166 case '=': 167 token = ARITH_LE; 168 break; 169 case '<': 170 token = ARITH_LSHIFT; 171 goto checkeq; 172 default: 173 token = ARITH_LT; 174 goto out; 175 } 176 break; 177 178 case '|': 179 if (*++buf != '|') { 180 token = ARITH_BOR; 181 goto checkeqcur; 182 } 183 token = ARITH_OR; 184 break; 185 186 case '&': 187 if (*++buf != '&') { 188 token = ARITH_BAND; 189 goto checkeqcur; 190 } 191 token = ARITH_AND; 192 break; 193 194 case '!': 195 if (*++buf != '=') { 196 token = ARITH_NOT; 197 goto out; 198 } 199 token = ARITH_NE; 200 break; 201 202 case 0: 203 goto out; 204 205 case '(': 206 token = ARITH_LPAREN; 207 break; 208 case ')': 209 token = ARITH_RPAREN; 210 break; 211 212 case '*': 213 token = ARITH_MUL; 214 goto checkeq; 215 case '/': 216 token = ARITH_DIV; 217 goto checkeq; 218 case '%': 219 token = ARITH_REM; 220 goto checkeq; 221 222 case '+': 223 if (buf[1] == '+') { 224 buf++; 225 token = ARITH_INCR; 226 break; 227 } 228 token = ARITH_ADD; 229 goto checkeq; 230 case '-': 231 if (buf[1] == '-') { 232 buf++; 233 token = ARITH_DECR; 234 break; 235 } 236 token = ARITH_SUB; 237 goto checkeq; 238 case '~': 239 token = ARITH_BNOT; 240 break; 241 case '^': 242 token = ARITH_BXOR; 243 goto checkeq; 244 245 case '?': 246 token = ARITH_QMARK; 247 break; 248 case ':': 249 token = ARITH_COLON; 250 break; 251 case ',': 252 token = ARITH_COMMA; 253 break; 254 } 255 break; 256 } 257 buf++; 258 out: 259 arith_buf = buf; 260 VTRACE(DBG_ARITH, ("Arith token: %d\n", token)); 261 return token; 262 } 263