1 %{ 2 /* $NetBSD: arith.y,v 1.22 2012/03/20 18:42:29 matt Exp $ */ 3 4 /*- 5 * Copyright (c) 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Kenneth Almquist. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)arith.y 8.3 (Berkeley) 5/4/95"; 40 #else 41 __RCSID("$NetBSD: arith.y,v 1.22 2012/03/20 18:42:29 matt Exp $"); 42 #endif 43 #endif /* not lint */ 44 45 #include <stdlib.h> 46 #include "expand.h" 47 #include "builtins.h" 48 #include "shell.h" 49 #include "error.h" 50 #include "output.h" 51 #include "memalloc.h" 52 53 typedef intmax_t YYSTYPE; 54 #define YYSTYPE YYSTYPE 55 56 intmax_t arith_result; 57 const char *arith_buf, *arith_startbuf; 58 59 __dead static void yyerror(const char *); 60 #ifdef TESTARITH 61 int main(int , char *[]); 62 int error(char *); 63 #endif 64 65 %} 66 %token ARITH_NUM ARITH_LPAREN ARITH_RPAREN 67 68 %left ARITH_OR 69 %left ARITH_AND 70 %left ARITH_BOR 71 %left ARITH_BXOR 72 %left ARITH_BAND 73 %left ARITH_EQ ARITH_NE 74 %left ARITH_LT ARITH_GT ARITH_GE ARITH_LE 75 %left ARITH_LSHIFT ARITH_RSHIFT 76 %left ARITH_ADD ARITH_SUB 77 %left ARITH_MUL ARITH_DIV ARITH_REM 78 %left ARITH_UNARYMINUS ARITH_UNARYPLUS ARITH_NOT ARITH_BNOT 79 %% 80 81 exp: expr { 82 /* 83 * yyparse() returns int, so we have to save 84 * the desired result elsewhere. 85 */ 86 arith_result = $1; 87 } 88 ; 89 90 91 expr: ARITH_LPAREN expr ARITH_RPAREN { $$ = $2; } 92 | expr ARITH_OR expr { $$ = $1 ? $1 : $3 ? $3 : 0; } 93 | expr ARITH_AND expr { $$ = $1 ? ( $3 ? $3 : 0 ) : 0; } 94 | expr ARITH_BOR expr { $$ = $1 | $3; } 95 | expr ARITH_BXOR expr { $$ = $1 ^ $3; } 96 | expr ARITH_BAND expr { $$ = $1 & $3; } 97 | expr ARITH_EQ expr { $$ = $1 == $3; } 98 | expr ARITH_GT expr { $$ = $1 > $3; } 99 | expr ARITH_GE expr { $$ = $1 >= $3; } 100 | expr ARITH_LT expr { $$ = $1 < $3; } 101 | expr ARITH_LE expr { $$ = $1 <= $3; } 102 | expr ARITH_NE expr { $$ = $1 != $3; } 103 | expr ARITH_LSHIFT expr { $$ = $1 << $3; } 104 | expr ARITH_RSHIFT expr { $$ = $1 >> $3; } 105 | expr ARITH_ADD expr { $$ = $1 + $3; } 106 | expr ARITH_SUB expr { $$ = $1 - $3; } 107 | expr ARITH_MUL expr { $$ = $1 * $3; } 108 | expr ARITH_DIV expr { 109 if ($3 == 0) 110 yyerror("division by zero"); 111 $$ = $1 / $3; 112 } 113 | expr ARITH_REM expr { 114 if ($3 == 0) 115 yyerror("division by zero"); 116 $$ = $1 % $3; 117 } 118 | ARITH_NOT expr { $$ = !($2); } 119 | ARITH_BNOT expr { $$ = ~($2); } 120 | ARITH_SUB expr %prec ARITH_UNARYMINUS { $$ = -($2); } 121 | ARITH_ADD expr %prec ARITH_UNARYPLUS { $$ = $2; } 122 | ARITH_NUM 123 ; 124 %% 125 intmax_t 126 arith(const char *s) 127 { 128 intmax_t result; 129 130 arith_buf = arith_startbuf = s; 131 132 INTOFF; 133 (void) yyparse(); 134 result = arith_result; 135 arith_lex_reset(); /* reprime lex */ 136 INTON; 137 138 return (result); 139 } 140 141 142 /* 143 * The exp(1) builtin. 144 */ 145 int 146 expcmd(int argc, char **argv) 147 { 148 const char *p; 149 char *concat; 150 char **ap; 151 intmax_t i; 152 153 if (argc > 1) { 154 p = argv[1]; 155 if (argc > 2) { 156 /* 157 * concatenate arguments 158 */ 159 STARTSTACKSTR(concat); 160 ap = argv + 2; 161 for (;;) { 162 while (*p) 163 STPUTC(*p++, concat); 164 if ((p = *ap++) == NULL) 165 break; 166 STPUTC(' ', concat); 167 } 168 STPUTC('\0', concat); 169 p = grabstackstr(concat); 170 } 171 } else 172 p = ""; 173 174 (void)arith(p); 175 i = arith_result; 176 177 out1fmt("%"PRIdMAX"\n", i); 178 return (! i); 179 } 180 181 /*************************/ 182 #ifdef TEST_ARITH 183 #include <stdio.h> 184 main(argc, argv) 185 char *argv[]; 186 { 187 printf("%"PRIdMAX"\n", exp(argv[1])); 188 } 189 error(s) 190 char *s; 191 { 192 fprintf(stderr, "exp: %s\n", s); 193 exit(1); 194 } 195 #endif 196 197 static void 198 yyerror(const char *s) 199 { 200 201 yyerrok; 202 yyclearin; 203 arith_lex_reset(); /* reprime lex */ 204 error("arithmetic expression: %s: \"%s\"", s, arith_startbuf); 205 /* NOTREACHED */ 206 } 207