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