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 "arith_yacc.h"
 45#include "error.h"
 46#include "expand.h"
 47#include "memalloc.h"
 48#include "parser.h"
 49#include "shell.h"
 50#include "syntax.h"
 51#include <ctype.h>
 52#include <errno.h>
 53#include <inttypes.h>
 54#include <stdlib.h>
 55#include <string.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 - '=';
181      checkeq:
182        buf++;
183      checkeqcur:
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}