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 <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
53int
54yylex(void)
55{
56	int value;
57	const char *buf = arith_buf;
58	char *end;
59	const char *p;
60
61	for (;;) {
62		value = *buf;
63		switch (value) {
64		case ' ':
65		case '\t':
66		case '\n':
67			buf++;
68			continue;
69		default:
70			return ARITH_BAD;
71		case '0':
72		case '1':
73		case '2':
74		case '3':
75		case '4':
76		case '5':
77		case '6':
78		case '7':
79		case '8':
80		case '9':
81			yylval.val = strtoarith_t(buf, &end, 0);
82			arith_buf = end;
83			return ARITH_NUM;
84		case 'A':
85		case 'B':
86		case 'C':
87		case 'D':
88		case 'E':
89		case 'F':
90		case 'G':
91		case 'H':
92		case 'I':
93		case 'J':
94		case 'K':
95		case 'L':
96		case 'M':
97		case 'N':
98		case 'O':
99		case 'P':
100		case 'Q':
101		case 'R':
102		case 'S':
103		case 'T':
104		case 'U':
105		case 'V':
106		case 'W':
107		case 'X':
108		case 'Y':
109		case 'Z':
110		case '_':
111		case 'a':
112		case 'b':
113		case 'c':
114		case 'd':
115		case 'e':
116		case 'f':
117		case 'g':
118		case 'h':
119		case 'i':
120		case 'j':
121		case 'k':
122		case 'l':
123		case 'm':
124		case 'n':
125		case 'o':
126		case 'p':
127		case 'q':
128		case 'r':
129		case 's':
130		case 't':
131		case 'u':
132		case 'v':
133		case 'w':
134		case 'x':
135		case 'y':
136		case 'z':
137			p = buf;
138			while (buf++, is_in_name(*buf))
139				;
140			yylval.name = stalloc(buf - p + 1);
141			memcpy(yylval.name, p, buf - p);
142			yylval.name[buf - p] = '\0';
143			value = ARITH_VAR;
144			goto out;
145		case '=':
146			value += ARITH_ASS - '=';
147checkeq:
148			buf++;
149checkeqcur:
150			if (*buf != '=')
151				goto out;
152			value += 11;
153			break;
154		case '>':
155			switch (*++buf) {
156			case '=':
157				value += ARITH_GE - '>';
158				break;
159			case '>':
160				value += ARITH_RSHIFT - '>';
161				goto checkeq;
162			default:
163				value += ARITH_GT - '>';
164				goto out;
165			}
166			break;
167		case '<':
168			switch (*++buf) {
169			case '=':
170				value += ARITH_LE - '<';
171				break;
172			case '<':
173				value += ARITH_LSHIFT - '<';
174				goto checkeq;
175			default:
176				value += ARITH_LT - '<';
177				goto out;
178			}
179			break;
180		case '|':
181			if (*++buf != '|') {
182				value += ARITH_BOR - '|';
183				goto checkeqcur;
184			}
185			value += ARITH_OR - '|';
186			break;
187		case '&':
188			if (*++buf != '&') {
189				value += ARITH_BAND - '&';
190				goto checkeqcur;
191			}
192			value += ARITH_AND - '&';
193			break;
194		case '!':
195			if (*++buf != '=') {
196				value += ARITH_NOT - '!';
197				goto out;
198			}
199			value += ARITH_NE - '!';
200			break;
201		case 0:
202			goto out;
203		case '(':
204			value += ARITH_LPAREN - '(';
205			break;
206		case ')':
207			value += ARITH_RPAREN - ')';
208			break;
209		case '*':
210			value += ARITH_MUL - '*';
211			goto checkeq;
212		case '/':
213			value += ARITH_DIV - '/';
214			goto checkeq;
215		case '%':
216			value += ARITH_REM - '%';
217			goto checkeq;
218		case '+':
219			if (buf[1] == '+')
220				return ARITH_BAD;
221			value += ARITH_ADD - '+';
222			goto checkeq;
223		case '-':
224			if (buf[1] == '-')
225				return ARITH_BAD;
226			value += ARITH_SUB - '-';
227			goto checkeq;
228		case '~':
229			value += ARITH_BNOT - '~';
230			break;
231		case '^':
232			value += ARITH_BXOR - '^';
233			goto checkeq;
234		case '?':
235			value += ARITH_QMARK - '?';
236			break;
237		case ':':
238			value += ARITH_COLON - ':';
239			break;
240		}
241		break;
242	}
243
244	buf++;
245out:
246	arith_buf = buf;
247	return value;
248}
249