367 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			367 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
%{
 | 
						|
/*-
 | 
						|
 * Copyright (c) 1993
 | 
						|
 *	The Regents of the University of California.  All rights reserved.
 | 
						|
 *
 | 
						|
 * This code is derived from software contributed to Berkeley by
 | 
						|
 * Kenneth Almquist.
 | 
						|
 *
 | 
						|
 * Redistribution and use in source and binary forms, with or without
 | 
						|
 * modification, are permitted provided that the following conditions
 | 
						|
 * are met:
 | 
						|
 * 1. Redistributions of source code must retain the above copyright
 | 
						|
 *    notice, this list of conditions and the following disclaimer.
 | 
						|
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
						|
 *    notice, this list of conditions and the following disclaimer in the
 | 
						|
 *    documentation and/or other materials provided with the distribution.
 | 
						|
 * 4. Neither the name of the University nor the names of its contributors
 | 
						|
 *    may be used to endorse or promote products derived from this software
 | 
						|
 *    without specific prior written permission.
 | 
						|
 *
 | 
						|
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 | 
						|
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
						|
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
						|
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 | 
						|
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
						|
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | 
						|
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
						|
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
						|
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
						|
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
						|
 * SUCH DAMAGE.
 | 
						|
 */
 | 
						|
 | 
						|
#if 0
 | 
						|
#ifndef lint
 | 
						|
static char sccsid[] = "@(#)arith.y	8.3 (Berkeley) 5/4/95";
 | 
						|
#endif
 | 
						|
#endif /* not lint */
 | 
						|
/*
 | 
						|
#include <sys/cdefs.h>
 | 
						|
__FBSDID("$FreeBSD: src/bin/sh/arith.y,v 1.19 2004/05/24 10:11:31 stefanf Exp $");
 | 
						|
*/
 | 
						|
 | 
						|
#include <limits.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <stdio.h>
 | 
						|
 | 
						|
#include "shell.h"
 | 
						|
#include "arith.h"
 | 
						|
#include "arith_lex.h"
 | 
						|
#include "var.h"
 | 
						|
%}
 | 
						|
%union {
 | 
						|
	arith_t l_value;
 | 
						|
	char* s_value;
 | 
						|
}
 | 
						|
%token <l_value> ARITH_NUM ARITH_LPAREN ARITH_RPAREN
 | 
						|
%token <s_value> ARITH_VAR
 | 
						|
 | 
						|
%type <l_value>	expr
 | 
						|
%right ARITH_ASSIGN
 | 
						|
%right ARITH_ADDASSIGN ARITH_SUBASSIGN
 | 
						|
%right ARITH_MULASSIGN ARITH_DIVASSIGN ARITH_REMASSIGN
 | 
						|
%right ARITH_RSHASSIGN ARITH_LSHASSIGN
 | 
						|
%right ARITH_BANDASSIGN ARITH_BXORASSIGN ARITH_BORASSIGN
 | 
						|
%left ARITH_OR
 | 
						|
%left ARITH_AND
 | 
						|
%left ARITH_BOR
 | 
						|
%left ARITH_BXOR
 | 
						|
%left ARITH_BAND
 | 
						|
%left ARITH_EQ ARITH_NE
 | 
						|
%left ARITH_LT ARITH_GT ARITH_GE ARITH_LE
 | 
						|
%left ARITH_LSHIFT ARITH_RSHIFT
 | 
						|
%left ARITH_ADD ARITH_SUB
 | 
						|
%left ARITH_MUL ARITH_DIV ARITH_REM
 | 
						|
%left ARITH_UNARYMINUS ARITH_UNARYPLUS ARITH_NOT ARITH_BNOT
 | 
						|
%%
 | 
						|
 | 
						|
exp:
 | 
						|
	expr
 | 
						|
		{ return ($1); }
 | 
						|
	;
 | 
						|
 | 
						|
expr:
 | 
						|
	ARITH_LPAREN expr ARITH_RPAREN
 | 
						|
		{ $$ = $2; } |
 | 
						|
	expr ARITH_OR expr
 | 
						|
		{ $$ = $1 ? $1 : $3 ? $3 : 0; } |
 | 
						|
	expr ARITH_AND expr
 | 
						|
		{ $$ = $1 ? ( $3 ? $3 : 0 ) : 0; } |
 | 
						|
	expr ARITH_BOR expr
 | 
						|
		{ $$ = $1 | $3; } |
 | 
						|
	expr ARITH_BXOR expr
 | 
						|
		{ $$ = $1 ^ $3; } |
 | 
						|
	expr ARITH_BAND expr
 | 
						|
		{ $$ = $1 & $3; } |
 | 
						|
	expr ARITH_EQ expr
 | 
						|
		{ $$ = $1 == $3; } |
 | 
						|
	expr ARITH_GT expr
 | 
						|
		{ $$ = $1 > $3; } |
 | 
						|
	expr ARITH_GE expr
 | 
						|
		{ $$ = $1 >= $3; } |
 | 
						|
	expr ARITH_LT expr
 | 
						|
		{ $$ = $1 < $3; } |
 | 
						|
	expr ARITH_LE expr
 | 
						|
		{ $$ = $1 <= $3; } |
 | 
						|
	expr ARITH_NE expr
 | 
						|
		{ $$ = $1 != $3; } |
 | 
						|
	expr ARITH_LSHIFT expr
 | 
						|
		{ $$ = $1 << $3; } |
 | 
						|
	expr ARITH_RSHIFT expr
 | 
						|
		{ $$ = $1 >> $3; } |
 | 
						|
	expr ARITH_ADD expr
 | 
						|
		{ $$ = $1 + $3; } |
 | 
						|
	expr ARITH_SUB expr
 | 
						|
		{ $$ = $1 - $3; } |
 | 
						|
	expr ARITH_MUL expr
 | 
						|
		{ $$ = $1 * $3; } |
 | 
						|
	expr ARITH_DIV expr
 | 
						|
		{
 | 
						|
		if ($3 == 0)
 | 
						|
			yyerror("division by zero");
 | 
						|
		$$ = $1 / $3;
 | 
						|
		} |
 | 
						|
	expr ARITH_REM expr
 | 
						|
		{
 | 
						|
		if ($3 == 0)
 | 
						|
			yyerror("division by zero");
 | 
						|
		$$ = $1 % $3;
 | 
						|
		} |
 | 
						|
	ARITH_NOT expr
 | 
						|
		{ $$ = !($2); } |
 | 
						|
	ARITH_BNOT expr
 | 
						|
		{ $$ = ~($2); } |
 | 
						|
	ARITH_SUB expr %prec ARITH_UNARYMINUS
 | 
						|
		{ $$ = -($2); } |
 | 
						|
	ARITH_ADD expr %prec ARITH_UNARYPLUS
 | 
						|
		{ $$ = $2; } |
 | 
						|
	ARITH_NUM |
 | 
						|
	ARITH_VAR
 | 
						|
		{
 | 
						|
		char *p;
 | 
						|
		arith_t arith_val;
 | 
						|
		char *str_val;
 | 
						|
 | 
						|
		if (lookupvar($1) == NULL)
 | 
						|
			setvarsafe($1, "0", 0);
 | 
						|
		str_val = lookupvar($1);
 | 
						|
		arith_val = strtoarith_t(str_val, &p, 0);
 | 
						|
		/*
 | 
						|
		 * Conversion is successful only in case
 | 
						|
		 * we've converted _all_ characters.
 | 
						|
		 */
 | 
						|
		if (*p != '\0')
 | 
						|
			yyerror("variable conversion error");
 | 
						|
		$$ = arith_val;
 | 
						|
		} |
 | 
						|
	ARITH_VAR ARITH_ASSIGN expr
 | 
						|
		{
 | 
						|
		if (arith_assign($1, $3) != 0)
 | 
						|
			yyerror("variable assignment error");
 | 
						|
		$$ = $3;
 | 
						|
		} |
 | 
						|
	ARITH_VAR ARITH_ADDASSIGN expr
 | 
						|
		{
 | 
						|
		arith_t value;
 | 
						|
 | 
						|
		value = atoarith_t(lookupvar($1)) + $3;
 | 
						|
		if (arith_assign($1, value) != 0)
 | 
						|
			yyerror("variable assignment error");
 | 
						|
		$$ = value;
 | 
						|
		} |
 | 
						|
	ARITH_VAR ARITH_SUBASSIGN expr
 | 
						|
		{
 | 
						|
		arith_t value;
 | 
						|
 | 
						|
		value = atoarith_t(lookupvar($1)) - $3;
 | 
						|
		if (arith_assign($1, value) != 0)
 | 
						|
			yyerror("variable assignment error");
 | 
						|
		$$ = value;
 | 
						|
		} |
 | 
						|
	ARITH_VAR ARITH_MULASSIGN expr
 | 
						|
		{
 | 
						|
		arith_t value;
 | 
						|
 | 
						|
		value = atoarith_t(lookupvar($1)) * $3;
 | 
						|
		if (arith_assign($1, value) != 0)
 | 
						|
			yyerror("variable assignment error");
 | 
						|
		$$ = value;
 | 
						|
		} |
 | 
						|
	ARITH_VAR ARITH_DIVASSIGN expr
 | 
						|
		{
 | 
						|
		arith_t value;
 | 
						|
 | 
						|
		if ($3 == 0)
 | 
						|
			yyerror("division by zero");
 | 
						|
 | 
						|
		value = atoarith_t(lookupvar($1)) / $3;
 | 
						|
		if (arith_assign($1, value) != 0)
 | 
						|
			yyerror("variable assignment error");
 | 
						|
		$$ = value;
 | 
						|
		} |
 | 
						|
	ARITH_VAR ARITH_REMASSIGN expr
 | 
						|
		{
 | 
						|
		arith_t value;
 | 
						|
 | 
						|
		if ($3 == 0)
 | 
						|
			yyerror("division by zero");
 | 
						|
 | 
						|
		value = atoarith_t(lookupvar($1)) % $3;
 | 
						|
		if (arith_assign($1, value) != 0)
 | 
						|
			yyerror("variable assignment error");
 | 
						|
		$$ = value;
 | 
						|
		} |
 | 
						|
	ARITH_VAR ARITH_RSHASSIGN expr
 | 
						|
		{
 | 
						|
		arith_t value;
 | 
						|
 | 
						|
		value = atoarith_t(lookupvar($1)) >> $3;
 | 
						|
		if (arith_assign($1, value) != 0)
 | 
						|
			yyerror("variable assignment error");
 | 
						|
		$$ = value;
 | 
						|
		} |
 | 
						|
	ARITH_VAR ARITH_LSHASSIGN expr
 | 
						|
		{
 | 
						|
		arith_t value;
 | 
						|
 | 
						|
		value = atoarith_t(lookupvar($1)) << $3;
 | 
						|
		if (arith_assign($1, value) != 0)
 | 
						|
			yyerror("variable assignment error");
 | 
						|
		$$ = value;
 | 
						|
		} |
 | 
						|
	ARITH_VAR ARITH_BANDASSIGN expr
 | 
						|
		{
 | 
						|
		arith_t value;
 | 
						|
 | 
						|
		value = atoarith_t(lookupvar($1)) & $3;
 | 
						|
		if (arith_assign($1, value) != 0)
 | 
						|
			yyerror("variable assignment error");
 | 
						|
		$$ = value;
 | 
						|
		} |
 | 
						|
	ARITH_VAR ARITH_BXORASSIGN expr
 | 
						|
		{
 | 
						|
		arith_t value;
 | 
						|
 | 
						|
		value = atoarith_t(lookupvar($1)) ^ $3;
 | 
						|
		if (arith_assign($1, value) != 0)
 | 
						|
			yyerror("variable assignment error");
 | 
						|
		$$ = value;
 | 
						|
		} |
 | 
						|
	ARITH_VAR ARITH_BORASSIGN expr
 | 
						|
		{
 | 
						|
		arith_t value;
 | 
						|
 | 
						|
		value = atoarith_t(lookupvar($1)) | $3;
 | 
						|
		if (arith_assign($1, value) != 0)
 | 
						|
			yyerror("variable assignment error");
 | 
						|
		$$ = value;
 | 
						|
		} ;
 | 
						|
%%
 | 
						|
#include "error.h"
 | 
						|
#include "output.h"
 | 
						|
#include "memalloc.h"
 | 
						|
#include "builtins.h"
 | 
						|
 | 
						|
#define lstrlen(var) (3 + (2 + CHAR_BIT * sizeof((var))) / 3)
 | 
						|
 | 
						|
char *arith_buf, *arith_startbuf;
 | 
						|
 | 
						|
int yylex(void);
 | 
						|
int yyparse(void);
 | 
						|
 | 
						|
int
 | 
						|
arith_assign(char *name, arith_t value)
 | 
						|
{
 | 
						|
	char *str;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	str = (char *)ckmalloc(lstrlen(value));
 | 
						|
	sprintf(str, ARITH_FORMAT_STR, value);
 | 
						|
	ret = setvarsafe(name, str, 0);
 | 
						|
	free(str);
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
arith(char *s)
 | 
						|
{
 | 
						|
	long result;
 | 
						|
 | 
						|
	arith_buf = arith_startbuf = s;
 | 
						|
 | 
						|
	INTOFF;
 | 
						|
	result = yyparse();
 | 
						|
	arith_lex_reset();	/* Reprime lex. */
 | 
						|
	INTON;
 | 
						|
 | 
						|
	return result;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
yyerror(char *s)
 | 
						|
{
 | 
						|
 | 
						|
	yyerrok;
 | 
						|
	yyclearin;
 | 
						|
	arith_lex_reset();	/* Reprime lex. */
 | 
						|
	error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 *  The exp(1) builtin.
 | 
						|
 */
 | 
						|
int
 | 
						|
expcmd(int argc, char **argv)
 | 
						|
{
 | 
						|
	char *p;
 | 
						|
	char *concat;
 | 
						|
	char **ap;
 | 
						|
	long i;
 | 
						|
 | 
						|
	if (argc > 1) {
 | 
						|
		p = argv[1];
 | 
						|
		if (argc > 2) {
 | 
						|
			/*
 | 
						|
			 * Concatenate arguments.
 | 
						|
			 */
 | 
						|
			STARTSTACKSTR(concat);
 | 
						|
			ap = argv + 2;
 | 
						|
			for (;;) {
 | 
						|
				while (*p)
 | 
						|
					STPUTC(*p++, concat);
 | 
						|
				if ((p = *ap++) == NULL)
 | 
						|
					break;
 | 
						|
				STPUTC(' ', concat);
 | 
						|
			}
 | 
						|
			STPUTC('\0', concat);
 | 
						|
			p = grabstackstr(concat);
 | 
						|
		}
 | 
						|
	} else
 | 
						|
		p = "";
 | 
						|
 | 
						|
	i = arith(p);
 | 
						|
 | 
						|
	out1fmt("%ld\n", i);
 | 
						|
	return !i;
 | 
						|
}
 | 
						|
 | 
						|
/*************************/
 | 
						|
#ifdef TEST_ARITH
 | 
						|
#include <stdio.h>
 | 
						|
main(int argc, char *argv[])
 | 
						|
{
 | 
						|
	printf("%d\n", exp(argv[1]));
 | 
						|
}
 | 
						|
 | 
						|
error(char *s)
 | 
						|
{
 | 
						|
	fprintf(stderr, "exp: %s\n", s);
 | 
						|
	exit(1);
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
/*
 | 
						|
 * $PchId: arith.y,v 1.6 2006/05/22 12:41:47 philip Exp $
 | 
						|
 */
 |