xref: /freebsd/bin/sh/arith_yylex.c (revision 7fdf597e96a02165cfe22ff357b857d5fa15ed8a)
1 /*-
2  * Copyright (c) 2002
3  *	Herbert Xu.
4  * Copyright (c) 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Kenneth Almquist.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include <sys/cdefs.h>
36 #include <ctype.h>
37 #include <errno.h>
38 #include <inttypes.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include "shell.h"
42 #include "arith_yacc.h"
43 #include "expand.h"
44 #include "error.h"
45 #include "memalloc.h"
46 #include "parser.h"
47 #include "syntax.h"
48 
49 #if ARITH_BOR + 11 != ARITH_BORASS || ARITH_ASS + 11 != ARITH_EQ
50 #error Arithmetic tokens are out of order.
51 #endif
52 
53 arith_t
54 strtoarith_t(const char *restrict nptr, char **restrict endptr)
55 {
56 	arith_t val;
57 
58 	while (isspace((unsigned char)*nptr))
59 		nptr++;
60 	switch (*nptr) {
61 		case '-':
62 			return strtoimax(nptr, endptr, 0);
63 		case '0':
64 			return (arith_t)strtoumax(nptr, endptr, 0);
65 		default:
66 			val = (arith_t)strtoumax(nptr, endptr, 0);
67 			if (val >= 0)
68 				return val;
69 			else if (val == ARITH_MIN) {
70 				errno = ERANGE;
71 				return ARITH_MIN;
72 			} else {
73 				errno = ERANGE;
74 				return ARITH_MAX;
75 			}
76 	}
77 }
78 
79 int
80 yylex(void)
81 {
82 	int value;
83 	const char *buf = arith_buf;
84 	char *end;
85 	const char *p;
86 
87 	for (;;) {
88 		value = *buf;
89 		switch (value) {
90 		case ' ':
91 		case '\t':
92 		case '\n':
93 			buf++;
94 			continue;
95 		default:
96 			return ARITH_BAD;
97 		case '0':
98 		case '1':
99 		case '2':
100 		case '3':
101 		case '4':
102 		case '5':
103 		case '6':
104 		case '7':
105 		case '8':
106 		case '9':
107 			yylval.val = strtoarith_t(buf, &end);
108 			arith_buf = end;
109 			return ARITH_NUM;
110 		case 'A':
111 		case 'B':
112 		case 'C':
113 		case 'D':
114 		case 'E':
115 		case 'F':
116 		case 'G':
117 		case 'H':
118 		case 'I':
119 		case 'J':
120 		case 'K':
121 		case 'L':
122 		case 'M':
123 		case 'N':
124 		case 'O':
125 		case 'P':
126 		case 'Q':
127 		case 'R':
128 		case 'S':
129 		case 'T':
130 		case 'U':
131 		case 'V':
132 		case 'W':
133 		case 'X':
134 		case 'Y':
135 		case 'Z':
136 		case '_':
137 		case 'a':
138 		case 'b':
139 		case 'c':
140 		case 'd':
141 		case 'e':
142 		case 'f':
143 		case 'g':
144 		case 'h':
145 		case 'i':
146 		case 'j':
147 		case 'k':
148 		case 'l':
149 		case 'm':
150 		case 'n':
151 		case 'o':
152 		case 'p':
153 		case 'q':
154 		case 'r':
155 		case 's':
156 		case 't':
157 		case 'u':
158 		case 'v':
159 		case 'w':
160 		case 'x':
161 		case 'y':
162 		case 'z':
163 			p = buf;
164 			while (buf++, is_in_name(*buf))
165 				;
166 			yylval.name = stalloc(buf - p + 1);
167 			memcpy(yylval.name, p, buf - p);
168 			yylval.name[buf - p] = '\0';
169 			value = ARITH_VAR;
170 			goto out;
171 		case '=':
172 			value += ARITH_ASS - '=';
173 checkeq:
174 			buf++;
175 checkeqcur:
176 			if (*buf != '=')
177 				goto out;
178 			value += 11;
179 			break;
180 		case '>':
181 			switch (*++buf) {
182 			case '=':
183 				value += ARITH_GE - '>';
184 				break;
185 			case '>':
186 				value += ARITH_RSHIFT - '>';
187 				goto checkeq;
188 			default:
189 				value += ARITH_GT - '>';
190 				goto out;
191 			}
192 			break;
193 		case '<':
194 			switch (*++buf) {
195 			case '=':
196 				value += ARITH_LE - '<';
197 				break;
198 			case '<':
199 				value += ARITH_LSHIFT - '<';
200 				goto checkeq;
201 			default:
202 				value += ARITH_LT - '<';
203 				goto out;
204 			}
205 			break;
206 		case '|':
207 			if (*++buf != '|') {
208 				value += ARITH_BOR - '|';
209 				goto checkeqcur;
210 			}
211 			value += ARITH_OR - '|';
212 			break;
213 		case '&':
214 			if (*++buf != '&') {
215 				value += ARITH_BAND - '&';
216 				goto checkeqcur;
217 			}
218 			value += ARITH_AND - '&';
219 			break;
220 		case '!':
221 			if (*++buf != '=') {
222 				value += ARITH_NOT - '!';
223 				goto out;
224 			}
225 			value += ARITH_NE - '!';
226 			break;
227 		case 0:
228 			goto out;
229 		case '(':
230 			value += ARITH_LPAREN - '(';
231 			break;
232 		case ')':
233 			value += ARITH_RPAREN - ')';
234 			break;
235 		case '*':
236 			value += ARITH_MUL - '*';
237 			goto checkeq;
238 		case '/':
239 			value += ARITH_DIV - '/';
240 			goto checkeq;
241 		case '%':
242 			value += ARITH_REM - '%';
243 			goto checkeq;
244 		case '+':
245 			if (buf[1] == '+')
246 				return ARITH_BAD;
247 			value += ARITH_ADD - '+';
248 			goto checkeq;
249 		case '-':
250 			if (buf[1] == '-')
251 				return ARITH_BAD;
252 			value += ARITH_SUB - '-';
253 			goto checkeq;
254 		case '~':
255 			value += ARITH_BNOT - '~';
256 			break;
257 		case '^':
258 			value += ARITH_BXOR - '^';
259 			goto checkeq;
260 		case '?':
261 			value += ARITH_QMARK - '?';
262 			break;
263 		case ':':
264 			value += ARITH_COLON - ':';
265 			break;
266 		}
267 		break;
268 	}
269 
270 	buf++;
271 out:
272 	arith_buf = buf;
273 	return value;
274 }
275