xref: /freebsd/bin/sh/arith_yylex.c (revision b9f654b163bce26de79705e77b872427c9f2afa1)
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 __FBSDID("$FreeBSD$");
37 
38 #include <ctype.h>
39 #include <errno.h>
40 #include <inttypes.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include "shell.h"
44 #include "arith_yacc.h"
45 #include "expand.h"
46 #include "error.h"
47 #include "memalloc.h"
48 #include "parser.h"
49 #include "syntax.h"
50 
51 #if ARITH_BOR + 11 != ARITH_BORASS || ARITH_ASS + 11 != ARITH_EQ
52 #error Arithmetic tokens are out of order.
53 #endif
54 
55 arith_t
56 strtoarith_t(const char *restrict nptr, char **restrict endptr)
57 {
58 	arith_t val;
59 
60 	while (isspace((unsigned char)*nptr))
61 		nptr++;
62 	switch (*nptr) {
63 		case '-':
64 			return strtoimax(nptr, endptr, 0);
65 		case '0':
66 			return (arith_t)strtoumax(nptr, endptr, 0);
67 		default:
68 			val = (arith_t)strtoumax(nptr, endptr, 0);
69 			if (val >= 0)
70 				return val;
71 			else if (val == ARITH_MIN) {
72 				errno = ERANGE;
73 				return ARITH_MIN;
74 			} else {
75 				errno = ERANGE;
76 				return ARITH_MAX;
77 			}
78 	}
79 }
80 
81 int
82 yylex(void)
83 {
84 	int value;
85 	const char *buf = arith_buf;
86 	char *end;
87 	const char *p;
88 
89 	for (;;) {
90 		value = *buf;
91 		switch (value) {
92 		case ' ':
93 		case '\t':
94 		case '\n':
95 			buf++;
96 			continue;
97 		default:
98 			return ARITH_BAD;
99 		case '0':
100 		case '1':
101 		case '2':
102 		case '3':
103 		case '4':
104 		case '5':
105 		case '6':
106 		case '7':
107 		case '8':
108 		case '9':
109 			yylval.val = strtoarith_t(buf, &end);
110 			arith_buf = end;
111 			return ARITH_NUM;
112 		case 'A':
113 		case 'B':
114 		case 'C':
115 		case 'D':
116 		case 'E':
117 		case 'F':
118 		case 'G':
119 		case 'H':
120 		case 'I':
121 		case 'J':
122 		case 'K':
123 		case 'L':
124 		case 'M':
125 		case 'N':
126 		case 'O':
127 		case 'P':
128 		case 'Q':
129 		case 'R':
130 		case 'S':
131 		case 'T':
132 		case 'U':
133 		case 'V':
134 		case 'W':
135 		case 'X':
136 		case 'Y':
137 		case 'Z':
138 		case '_':
139 		case 'a':
140 		case 'b':
141 		case 'c':
142 		case 'd':
143 		case 'e':
144 		case 'f':
145 		case 'g':
146 		case 'h':
147 		case 'i':
148 		case 'j':
149 		case 'k':
150 		case 'l':
151 		case 'm':
152 		case 'n':
153 		case 'o':
154 		case 'p':
155 		case 'q':
156 		case 'r':
157 		case 's':
158 		case 't':
159 		case 'u':
160 		case 'v':
161 		case 'w':
162 		case 'x':
163 		case 'y':
164 		case 'z':
165 			p = buf;
166 			while (buf++, is_in_name(*buf))
167 				;
168 			yylval.name = stalloc(buf - p + 1);
169 			memcpy(yylval.name, p, buf - p);
170 			yylval.name[buf - p] = '\0';
171 			value = ARITH_VAR;
172 			goto out;
173 		case '=':
174 			value += ARITH_ASS - '=';
175 checkeq:
176 			buf++;
177 checkeqcur:
178 			if (*buf != '=')
179 				goto out;
180 			value += 11;
181 			break;
182 		case '>':
183 			switch (*++buf) {
184 			case '=':
185 				value += ARITH_GE - '>';
186 				break;
187 			case '>':
188 				value += ARITH_RSHIFT - '>';
189 				goto checkeq;
190 			default:
191 				value += ARITH_GT - '>';
192 				goto out;
193 			}
194 			break;
195 		case '<':
196 			switch (*++buf) {
197 			case '=':
198 				value += ARITH_LE - '<';
199 				break;
200 			case '<':
201 				value += ARITH_LSHIFT - '<';
202 				goto checkeq;
203 			default:
204 				value += ARITH_LT - '<';
205 				goto out;
206 			}
207 			break;
208 		case '|':
209 			if (*++buf != '|') {
210 				value += ARITH_BOR - '|';
211 				goto checkeqcur;
212 			}
213 			value += ARITH_OR - '|';
214 			break;
215 		case '&':
216 			if (*++buf != '&') {
217 				value += ARITH_BAND - '&';
218 				goto checkeqcur;
219 			}
220 			value += ARITH_AND - '&';
221 			break;
222 		case '!':
223 			if (*++buf != '=') {
224 				value += ARITH_NOT - '!';
225 				goto out;
226 			}
227 			value += ARITH_NE - '!';
228 			break;
229 		case 0:
230 			goto out;
231 		case '(':
232 			value += ARITH_LPAREN - '(';
233 			break;
234 		case ')':
235 			value += ARITH_RPAREN - ')';
236 			break;
237 		case '*':
238 			value += ARITH_MUL - '*';
239 			goto checkeq;
240 		case '/':
241 			value += ARITH_DIV - '/';
242 			goto checkeq;
243 		case '%':
244 			value += ARITH_REM - '%';
245 			goto checkeq;
246 		case '+':
247 			if (buf[1] == '+')
248 				return ARITH_BAD;
249 			value += ARITH_ADD - '+';
250 			goto checkeq;
251 		case '-':
252 			if (buf[1] == '-')
253 				return ARITH_BAD;
254 			value += ARITH_SUB - '-';
255 			goto checkeq;
256 		case '~':
257 			value += ARITH_BNOT - '~';
258 			break;
259 		case '^':
260 			value += ARITH_BXOR - '^';
261 			goto checkeq;
262 		case '?':
263 			value += ARITH_QMARK - '?';
264 			break;
265 		case ':':
266 			value += ARITH_COLON - ':';
267 			break;
268 		}
269 		break;
270 	}
271 
272 	buf++;
273 out:
274 	arith_buf = buf;
275 	return value;
276 }
277