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