Home | History | Annotate | Line # | Download | only in sh
arith_token.c revision 1.3
      1 /*	$NetBSD: arith_token.c,v 1.3 2017/03/20 13:12:35 kre Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2002
      5  *	Herbert Xu.
      6  * Copyright (c) 1991, 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  * From FreeBSD, from dash
     37  */
     38 
     39 #include <sys/cdefs.h>
     40 
     41 #ifndef lint
     42 __RCSID("$NetBSD: arith_token.c,v 1.3 2017/03/20 13:12:35 kre Exp $");
     43 #endif /* not lint */
     44 
     45 #include <inttypes.h>
     46 #include <limits.h>
     47 #include <stdlib.h>
     48 #include <string.h>
     49 
     50 #include "shell.h"
     51 #include "arith_tokens.h"
     52 #include "expand.h"
     53 #include "error.h"
     54 #include "memalloc.h"
     55 #include "parser.h"
     56 #include "syntax.h"
     57 
     58 #if ARITH_BOR + ARITH_ASS_GAP != ARITH_BORASS || \
     59 	ARITH_ASS + ARITH_ASS_GAP != ARITH_EQ
     60 #error Arithmetic tokens are out of order.
     61 #endif
     62 
     63 /*
     64  * Scan next arithmetic token, return its type,
     65  * leave its value (when applicable) in (global) a_t_val.
     66  *
     67  * Input text is in (global) arith_buf which is updated to
     68  * refer to the next char after the token returned, except
     69  * on error (ARITH_BAD returned) where arith_buf is not altered.
     70  */
     71 int
     72 arith_token(void)
     73 {
     74 	int token;
     75 	const char *buf = arith_buf;
     76 	char *end;
     77 	const char *p;
     78 
     79 	for (;;) {
     80 		token = *buf;
     81 
     82 		if (isdigit(token)) {
     83 			/*
     84 			 * Numbers all start with a digit, and nothing
     85 			 * else does, the number ends wherever
     86 			 * strtoimax() stops...
     87 			 */
     88 			a_t_val.val = strtoimax(buf, &end, 0);
     89 			arith_buf = end;
     90 			return ARITH_NUM;
     91 
     92 		} else if (is_name(token)) {
     93 			/*
     94 			 * Variable names all start with an alpha (or '_')
     95 			 * and nothing else does.  They continue for the
     96 			 * longest unbroken sequence of alphanumerics ( + _ )
     97 			 */
     98 			p = buf;
     99 			while (buf++, is_in_name(*buf))
    100 				;
    101 			a_t_val.name = stalloc(buf - p + 1);
    102 			memcpy(a_t_val.name, p, buf - p);
    103 			a_t_val.name[buf - p] = '\0';
    104 			arith_buf = buf;
    105 			return ARITH_VAR;
    106 
    107 		} else switch (token) {
    108 			/*
    109 			 * everything else must be some kind of
    110 			 * operator, white space, or an error.
    111 			 */
    112 		case ' ':
    113 		case '\t':
    114 		case '\n':
    115 			buf++;
    116 			continue;
    117 
    118 		default:
    119 			error("arithmetic: unexpected '%c' (%#x) in expression",
    120 			    token, token);
    121 			/* NOTREACHED */
    122 
    123 		case '=':
    124 			token = ARITH_ASS;
    125  checkeq:
    126 			buf++;
    127  checkeqcur:
    128 			if (*buf != '=')
    129 				goto out;
    130 			token += ARITH_ASS_GAP;
    131 			break;
    132 
    133 		case '>':
    134 			switch (*++buf) {
    135 			case '=':
    136 				token = ARITH_GE;
    137 				break;
    138 			case '>':
    139 				token = ARITH_RSHIFT;
    140 				goto checkeq;
    141 			default:
    142 				token = ARITH_GT;
    143 				goto out;
    144 			}
    145 			break;
    146 
    147 		case '<':
    148 			switch (*++buf) {
    149 			case '=':
    150 				token = ARITH_LE;
    151 				break;
    152 			case '<':
    153 				token = ARITH_LSHIFT;
    154 				goto checkeq;
    155 			default:
    156 				token = ARITH_LT;
    157 				goto out;
    158 			}
    159 			break;
    160 
    161 		case '|':
    162 			if (*++buf != '|') {
    163 				token = ARITH_BOR;
    164 				goto checkeqcur;
    165 			}
    166 			token = ARITH_OR;
    167 			break;
    168 
    169 		case '&':
    170 			if (*++buf != '&') {
    171 				token = ARITH_BAND;
    172 				goto checkeqcur;
    173 			}
    174 			token = ARITH_AND;
    175 			break;
    176 
    177 		case '!':
    178 			if (*++buf != '=') {
    179 				token = ARITH_NOT;
    180 				goto out;
    181 			}
    182 			token = ARITH_NE;
    183 			break;
    184 
    185 		case 0:
    186 			goto out;
    187 
    188 		case '(':
    189 			token = ARITH_LPAREN;
    190 			break;
    191 		case ')':
    192 			token = ARITH_RPAREN;
    193 			break;
    194 
    195 		case '*':
    196 			token = ARITH_MUL;
    197 			goto checkeq;
    198 		case '/':
    199 			token = ARITH_DIV;
    200 			goto checkeq;
    201 		case '%':
    202 			token = ARITH_REM;
    203 			goto checkeq;
    204 
    205 		case '+':
    206 			if (buf[1] == '+')
    207 				error("arithmetic: ++ operator unsupported");
    208 			token = ARITH_ADD;
    209 			goto checkeq;
    210 		case '-':
    211 			if (buf[1] == '-')
    212 				error("arithmetic: -- operator unsupported");
    213 			token = ARITH_SUB;
    214 			goto checkeq;
    215 		case '~':
    216 			token = ARITH_BNOT;
    217 			break;
    218 		case '^':
    219 			token = ARITH_BXOR;
    220 			goto checkeq;
    221 
    222 		case '?':
    223 			token = ARITH_QMARK;
    224 			break;
    225 		case ':':
    226 			token = ARITH_COLON;
    227 			break;
    228 		}
    229 		break;
    230 	}
    231 	buf++;
    232  out:
    233 	arith_buf = buf;
    234 	return token;
    235 }
    236