1 /* $NetBSD: arith_token.c,v 1.6 2017/07/24 13:21:14 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.6 2017/07/24 13:21:14 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 arith_buf = end; 91 VTRACE(DBG_ARITH, ("Arith token ARITH_NUM=%jd\n", 92 a_t_val.val)); 93 return ARITH_NUM; 94 95 } else if (is_name(token)) { 96 /* 97 * Variable names all start with an alpha (or '_') 98 * and nothing else does. They continue for the 99 * longest unbroken sequence of alphanumerics ( + _ ) 100 */ 101 arith_var_lno = arith_lno; 102 p = buf; 103 while (buf++, is_in_name(*buf)) 104 ; 105 a_t_val.name = stalloc(buf - p + 1); 106 memcpy(a_t_val.name, p, buf - p); 107 a_t_val.name[buf - p] = '\0'; 108 arith_buf = buf; 109 VTRACE(DBG_ARITH, ("Arith token ARITH_VAR=\"%s\"\n", 110 a_t_val.name)); 111 return ARITH_VAR; 112 113 } else switch (token) { 114 /* 115 * everything else must be some kind of 116 * operator, white space, or an error. 117 */ 118 case '\n': 119 arith_lno++; 120 VTRACE(DBG_ARITH, ("Arith: newline\n")); 121 /* FALLTHROUGH */ 122 case ' ': 123 case '\t': 124 buf++; 125 continue; 126 127 default: 128 error("arithmetic: unexpected '%c' (%#x) in expression", 129 token, token); 130 /* NOTREACHED */ 131 132 case '=': 133 token = ARITH_ASS; 134 checkeq: 135 buf++; 136 checkeqcur: 137 if (*buf != '=') 138 goto out; 139 token += ARITH_ASS_GAP; 140 break; 141 142 case '>': 143 switch (*++buf) { 144 case '=': 145 token = ARITH_GE; 146 break; 147 case '>': 148 token = ARITH_RSHIFT; 149 goto checkeq; 150 default: 151 token = ARITH_GT; 152 goto out; 153 } 154 break; 155 156 case '<': 157 switch (*++buf) { 158 case '=': 159 token = ARITH_LE; 160 break; 161 case '<': 162 token = ARITH_LSHIFT; 163 goto checkeq; 164 default: 165 token = ARITH_LT; 166 goto out; 167 } 168 break; 169 170 case '|': 171 if (*++buf != '|') { 172 token = ARITH_BOR; 173 goto checkeqcur; 174 } 175 token = ARITH_OR; 176 break; 177 178 case '&': 179 if (*++buf != '&') { 180 token = ARITH_BAND; 181 goto checkeqcur; 182 } 183 token = ARITH_AND; 184 break; 185 186 case '!': 187 if (*++buf != '=') { 188 token = ARITH_NOT; 189 goto out; 190 } 191 token = ARITH_NE; 192 break; 193 194 case 0: 195 goto out; 196 197 case '(': 198 token = ARITH_LPAREN; 199 break; 200 case ')': 201 token = ARITH_RPAREN; 202 break; 203 204 case '*': 205 token = ARITH_MUL; 206 goto checkeq; 207 case '/': 208 token = ARITH_DIV; 209 goto checkeq; 210 case '%': 211 token = ARITH_REM; 212 goto checkeq; 213 214 case '+': 215 if (buf[1] == '+') { 216 buf++; 217 token = ARITH_INCR; 218 break; 219 } 220 token = ARITH_ADD; 221 goto checkeq; 222 case '-': 223 if (buf[1] == '-') { 224 buf++; 225 token = ARITH_DECR; 226 break; 227 } 228 token = ARITH_SUB; 229 goto checkeq; 230 case '~': 231 token = ARITH_BNOT; 232 break; 233 case '^': 234 token = ARITH_BXOR; 235 goto checkeq; 236 237 case '?': 238 token = ARITH_QMARK; 239 break; 240 case ':': 241 token = ARITH_COLON; 242 break; 243 case ',': 244 token = ARITH_COMMA; 245 break; 246 } 247 break; 248 } 249 buf++; 250 out: 251 arith_buf = buf; 252 VTRACE(DBG_ARITH, ("Arith token: %d\n", token)); 253 return token; 254 } 255