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
53arith_t
54strtoarith_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
79int
80yylex(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 - '=';
173checkeq:
174			buf++;
175checkeqcur:
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++;
271out:
272	arith_buf = buf;
273	return value;
274}
275