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
55arith_t
56strtoarith_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
81int
82yylex(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 - '=';
175checkeq:
176			buf++;
177checkeqcur:
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++;
273out:
274	arith_buf = buf;
275	return value;
276}
277