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