arith_token.c revision 1.5 1 /* $NetBSD: arith_token.c,v 1.5 2017/06/07 05:08:32 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.5 2017/06/07 05:08:32 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 error("arithmetic: ++ operator unsupported");
217 token = ARITH_ADD;
218 goto checkeq;
219 case '-':
220 if (buf[1] == '-')
221 error("arithmetic: -- operator unsupported");
222 token = ARITH_SUB;
223 goto checkeq;
224 case '~':
225 token = ARITH_BNOT;
226 break;
227 case '^':
228 token = ARITH_BXOR;
229 goto checkeq;
230
231 case '?':
232 token = ARITH_QMARK;
233 break;
234 case ':':
235 token = ARITH_COLON;
236 break;
237 }
238 break;
239 }
240 buf++;
241 out:
242 arith_buf = buf;
243 VTRACE(DBG_ARITH, ("Arith token: %d\n", token));
244 return token;
245 }
246