xref: /plan9/sys/src/ape/cmd/expr/expr.y (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1*219b2ee8SDavid du Colombier /* Yacc productions for "expr" command: */
2*219b2ee8SDavid du Colombier 
3*219b2ee8SDavid du Colombier %token OR AND ADD SUBT MULT DIV REM EQ GT GEQ LT LEQ NEQ
4*219b2ee8SDavid du Colombier %token A_STRING SUBSTR LENGTH INDEX NOARG MATCH
5*219b2ee8SDavid du Colombier 
6*219b2ee8SDavid du Colombier /* operators listed below in increasing precedence: */
7*219b2ee8SDavid du Colombier %left OR
8*219b2ee8SDavid du Colombier %left AND
9*219b2ee8SDavid du Colombier %left EQ LT GT GEQ LEQ NEQ
10*219b2ee8SDavid du Colombier %left ADD SUBT
11*219b2ee8SDavid du Colombier %left MULT DIV REM
12*219b2ee8SDavid du Colombier %left MCH
13*219b2ee8SDavid du Colombier %left MATCH
14*219b2ee8SDavid du Colombier %left SUBSTR
15*219b2ee8SDavid du Colombier %left LENGTH INDEX
16*219b2ee8SDavid du Colombier 
17*219b2ee8SDavid du Colombier %{
18*219b2ee8SDavid du Colombier #define YYSTYPE charp
19*219b2ee8SDavid du Colombier 
20*219b2ee8SDavid du Colombier typedef char *charp;
21*219b2ee8SDavid du Colombier %}
22*219b2ee8SDavid du Colombier 
23*219b2ee8SDavid du Colombier %%
24*219b2ee8SDavid du Colombier 
25*219b2ee8SDavid du Colombier /* a single `expression' is evaluated and printed: */
26*219b2ee8SDavid du Colombier 
27*219b2ee8SDavid du Colombier expression:	expr NOARG = {
28*219b2ee8SDavid du Colombier 			prt(1, $1);
29*219b2ee8SDavid du Colombier 			exit((!strcmp($1,"0")||!strcmp($1,"\0"))? 1: 0);
30*219b2ee8SDavid du Colombier 			}
31*219b2ee8SDavid du Colombier 	;
32*219b2ee8SDavid du Colombier 
33*219b2ee8SDavid du Colombier 
34*219b2ee8SDavid du Colombier expr:	'(' expr ')' = { $$ = $2; }
35*219b2ee8SDavid du Colombier 	| expr OR expr   = { $$ = conj(OR, $1, $3); }
36*219b2ee8SDavid du Colombier 	| expr AND expr   = { $$ = conj(AND, $1, $3); }
37*219b2ee8SDavid du Colombier 	| expr EQ expr   = { $$ = rel(EQ, $1, $3); }
38*219b2ee8SDavid du Colombier 	| expr GT expr   = { $$ = rel(GT, $1, $3); }
39*219b2ee8SDavid du Colombier 	| expr GEQ expr   = { $$ = rel(GEQ, $1, $3); }
40*219b2ee8SDavid du Colombier 	| expr LT expr   = { $$ = rel(LT, $1, $3); }
41*219b2ee8SDavid du Colombier 	| expr LEQ expr   = { $$ = rel(LEQ, $1, $3); }
42*219b2ee8SDavid du Colombier 	| expr NEQ expr   = { $$ = rel(NEQ, $1, $3); }
43*219b2ee8SDavid du Colombier 	| expr ADD expr   = { $$ = arith(ADD, $1, $3); }
44*219b2ee8SDavid du Colombier 	| expr SUBT expr   = { $$ = arith(SUBT, $1, $3); }
45*219b2ee8SDavid du Colombier 	| expr MULT expr   = { $$ = arith(MULT, $1, $3); }
46*219b2ee8SDavid du Colombier 	| expr DIV expr   = { $$ = arith(DIV, $1, $3); }
47*219b2ee8SDavid du Colombier 	| expr REM expr   = { $$ = arith(REM, $1, $3); }
48*219b2ee8SDavid du Colombier 	| expr MCH expr	 = { $$ = match($1, $3); }
49*219b2ee8SDavid du Colombier 	| MATCH expr expr = { $$ = match($2, $3); }
50*219b2ee8SDavid du Colombier 	| SUBSTR expr expr expr = { $$ = substr($2, $3, $4); }
51*219b2ee8SDavid du Colombier 	| LENGTH expr       = { $$ = length($2); }
52*219b2ee8SDavid du Colombier 	| INDEX expr expr = { $$ = index($2, $3); }
53*219b2ee8SDavid du Colombier 	| A_STRING
54*219b2ee8SDavid du Colombier 	;
55*219b2ee8SDavid du Colombier %%
56*219b2ee8SDavid du Colombier /*	expression command */
57*219b2ee8SDavid du Colombier #include <stdio.h>
58*219b2ee8SDavid du Colombier /* get rid of yacc debug printf's */
59*219b2ee8SDavid du Colombier #define printf
60*219b2ee8SDavid du Colombier #define ESIZE	512
61*219b2ee8SDavid du Colombier #define error(c)	errxx(c)
62*219b2ee8SDavid du Colombier #define EQL(x,y) !strcmp(x,y)
63*219b2ee8SDavid du Colombier long atol();
64*219b2ee8SDavid du Colombier char *ltoa();
65*219b2ee8SDavid du Colombier char	**Av;
66*219b2ee8SDavid du Colombier int	Ac;
67*219b2ee8SDavid du Colombier int	Argi;
68*219b2ee8SDavid du Colombier 
69*219b2ee8SDavid du Colombier char Mstring[1][128];
70*219b2ee8SDavid du Colombier char *malloc();
71*219b2ee8SDavid du Colombier extern int nbra;
72*219b2ee8SDavid du Colombier int yyparse(void);
73*219b2ee8SDavid du Colombier 
main(argc,argv)74*219b2ee8SDavid du Colombier main(argc, argv) char **argv; {
75*219b2ee8SDavid du Colombier 	Ac = argc;
76*219b2ee8SDavid du Colombier 	Argi = 1;
77*219b2ee8SDavid du Colombier 	Av = argv;
78*219b2ee8SDavid du Colombier 	yyparse();
79*219b2ee8SDavid du Colombier }
80*219b2ee8SDavid du Colombier 
81*219b2ee8SDavid du Colombier char *operator[] = { "|", "&", "+", "-", "*", "/", "%", ":",
82*219b2ee8SDavid du Colombier 	"=", "==", "<", "<=", ">", ">=", "!=",
83*219b2ee8SDavid du Colombier 	"match", "substr", "length", "index", "\0" };
84*219b2ee8SDavid du Colombier int op[] = { OR, AND, ADD,  SUBT, MULT, DIV, REM, MCH,
85*219b2ee8SDavid du Colombier 	EQ, EQ, LT, LEQ, GT, GEQ, NEQ,
86*219b2ee8SDavid du Colombier 	MATCH, SUBSTR, LENGTH, INDEX };
yylex()87*219b2ee8SDavid du Colombier yylex() {
88*219b2ee8SDavid du Colombier 	register char *p;
89*219b2ee8SDavid du Colombier 	register i;
90*219b2ee8SDavid du Colombier 
91*219b2ee8SDavid du Colombier 	if(Argi >= Ac) return NOARG;
92*219b2ee8SDavid du Colombier 
93*219b2ee8SDavid du Colombier 	p = Av[Argi++];
94*219b2ee8SDavid du Colombier 
95*219b2ee8SDavid du Colombier 	if(*p == '(' || *p == ')')
96*219b2ee8SDavid du Colombier 		return (int)*p;
97*219b2ee8SDavid du Colombier 	for(i = 0; *operator[i]; ++i)
98*219b2ee8SDavid du Colombier 		if(EQL(operator[i], p))
99*219b2ee8SDavid du Colombier 			return op[i];
100*219b2ee8SDavid du Colombier 
101*219b2ee8SDavid du Colombier 	yylval = p;
102*219b2ee8SDavid du Colombier 	return A_STRING;
103*219b2ee8SDavid du Colombier }
104*219b2ee8SDavid du Colombier 
rel(op,r1,r2)105*219b2ee8SDavid du Colombier char *rel(op, r1, r2) register char *r1, *r2; {
106*219b2ee8SDavid du Colombier 	register i;
107*219b2ee8SDavid du Colombier 
108*219b2ee8SDavid du Colombier 	if(ematch(r1, "-\\{0,1\\}[0-9]*$") && ematch(r2, "-\\{0,1\\}[0-9]*$"))
109*219b2ee8SDavid du Colombier 		i = atol(r1) - atol(r2);
110*219b2ee8SDavid du Colombier 	else
111*219b2ee8SDavid du Colombier 		i = strcmp(r1, r2);
112*219b2ee8SDavid du Colombier 	switch(op) {
113*219b2ee8SDavid du Colombier 	case EQ: i = i==0; break;
114*219b2ee8SDavid du Colombier 	case GT: i = i>0; break;
115*219b2ee8SDavid du Colombier 	case GEQ: i = i>=0; break;
116*219b2ee8SDavid du Colombier 	case LT: i = i<0; break;
117*219b2ee8SDavid du Colombier 	case LEQ: i = i<=0; break;
118*219b2ee8SDavid du Colombier 	case NEQ: i = i!=0; break;
119*219b2ee8SDavid du Colombier 	}
120*219b2ee8SDavid du Colombier 	return i? "1": "0";
121*219b2ee8SDavid du Colombier }
122*219b2ee8SDavid du Colombier 
arith(op,r1,r2)123*219b2ee8SDavid du Colombier char *arith(op, r1, r2) char *r1, *r2; {
124*219b2ee8SDavid du Colombier 	long i1, i2;
125*219b2ee8SDavid du Colombier 	register char *rv;
126*219b2ee8SDavid du Colombier 
127*219b2ee8SDavid du Colombier 	if(!(ematch(r1, "-\\{0,1\\}[0-9]*$") && ematch(r2, "-\\{0,1\\}[0-9]*$")))
128*219b2ee8SDavid du Colombier 		yyerror("non-numeric argument");
129*219b2ee8SDavid du Colombier 	i1 = atol(r1);
130*219b2ee8SDavid du Colombier 	i2 = atol(r2);
131*219b2ee8SDavid du Colombier 
132*219b2ee8SDavid du Colombier 	switch(op) {
133*219b2ee8SDavid du Colombier 	case ADD: i1 = i1 + i2; break;
134*219b2ee8SDavid du Colombier 	case SUBT: i1 = i1 - i2; break;
135*219b2ee8SDavid du Colombier 	case MULT: i1 = i1 * i2; break;
136*219b2ee8SDavid du Colombier 	case DIV: i1 = i1 / i2; break;
137*219b2ee8SDavid du Colombier 	case REM: i1 = i1 % i2; break;
138*219b2ee8SDavid du Colombier 	}
139*219b2ee8SDavid du Colombier 	rv = malloc(16);
140*219b2ee8SDavid du Colombier 	strcpy(rv, ltoa(i1));
141*219b2ee8SDavid du Colombier 	return rv;
142*219b2ee8SDavid du Colombier }
conj(op,r1,r2)143*219b2ee8SDavid du Colombier char *conj(op, r1, r2) char *r1, *r2; {
144*219b2ee8SDavid du Colombier 	register char *rv;
145*219b2ee8SDavid du Colombier 
146*219b2ee8SDavid du Colombier 	switch(op) {
147*219b2ee8SDavid du Colombier 
148*219b2ee8SDavid du Colombier 	case OR:
149*219b2ee8SDavid du Colombier 		if(EQL(r1, "0")
150*219b2ee8SDavid du Colombier 		|| EQL(r1, ""))
151*219b2ee8SDavid du Colombier 			if(EQL(r2, "0")
152*219b2ee8SDavid du Colombier 			|| EQL(r2, ""))
153*219b2ee8SDavid du Colombier 				rv = "0";
154*219b2ee8SDavid du Colombier 			else
155*219b2ee8SDavid du Colombier 				rv = r2;
156*219b2ee8SDavid du Colombier 		else
157*219b2ee8SDavid du Colombier 			rv = r1;
158*219b2ee8SDavid du Colombier 		break;
159*219b2ee8SDavid du Colombier 	case AND:
160*219b2ee8SDavid du Colombier 		if(EQL(r1, "0")
161*219b2ee8SDavid du Colombier 		|| EQL(r1, ""))
162*219b2ee8SDavid du Colombier 			rv = "0";
163*219b2ee8SDavid du Colombier 		else if(EQL(r2, "0")
164*219b2ee8SDavid du Colombier 		|| EQL(r2, ""))
165*219b2ee8SDavid du Colombier 			rv = "0";
166*219b2ee8SDavid du Colombier 		else
167*219b2ee8SDavid du Colombier 			rv = r1;
168*219b2ee8SDavid du Colombier 		break;
169*219b2ee8SDavid du Colombier 	}
170*219b2ee8SDavid du Colombier 	return rv;
171*219b2ee8SDavid du Colombier }
172*219b2ee8SDavid du Colombier 
substr(v,s,w)173*219b2ee8SDavid du Colombier char *substr(v, s, w) char *v, *s, *w; {
174*219b2ee8SDavid du Colombier register si, wi;
175*219b2ee8SDavid du Colombier register char *res;
176*219b2ee8SDavid du Colombier 
177*219b2ee8SDavid du Colombier 	si = atol(s);
178*219b2ee8SDavid du Colombier 	wi = atol(w);
179*219b2ee8SDavid du Colombier 	while(--si) if(*v) ++v;
180*219b2ee8SDavid du Colombier 
181*219b2ee8SDavid du Colombier 	res = v;
182*219b2ee8SDavid du Colombier 
183*219b2ee8SDavid du Colombier 	while(wi--) if(*v) ++v;
184*219b2ee8SDavid du Colombier 
185*219b2ee8SDavid du Colombier 	*v = '\0';
186*219b2ee8SDavid du Colombier 	return res;
187*219b2ee8SDavid du Colombier }
188*219b2ee8SDavid du Colombier 
length(s)189*219b2ee8SDavid du Colombier char *length(s) register char *s; {
190*219b2ee8SDavid du Colombier 	register i = 0;
191*219b2ee8SDavid du Colombier 	register char *rv;
192*219b2ee8SDavid du Colombier 
193*219b2ee8SDavid du Colombier 	while(*s++) ++i;
194*219b2ee8SDavid du Colombier 
195*219b2ee8SDavid du Colombier 	rv = malloc(8);
196*219b2ee8SDavid du Colombier 	strcpy(rv, ltoa((long)i));
197*219b2ee8SDavid du Colombier 	return rv;
198*219b2ee8SDavid du Colombier }
199*219b2ee8SDavid du Colombier 
index(s,t)200*219b2ee8SDavid du Colombier char *index(s, t) char *s, *t; {
201*219b2ee8SDavid du Colombier 	register i, j;
202*219b2ee8SDavid du Colombier 	register char *rv;
203*219b2ee8SDavid du Colombier 
204*219b2ee8SDavid du Colombier 	for(i = 0; s[i] ; ++i)
205*219b2ee8SDavid du Colombier 		for(j = 0; t[j] ; ++j)
206*219b2ee8SDavid du Colombier 			if(s[i]==t[j]) {
207*219b2ee8SDavid du Colombier 				strcpy(rv=malloc(8), ltoa((long)++i));
208*219b2ee8SDavid du Colombier 				return rv;
209*219b2ee8SDavid du Colombier 			}
210*219b2ee8SDavid du Colombier 	return "0";
211*219b2ee8SDavid du Colombier }
212*219b2ee8SDavid du Colombier 
match(s,p)213*219b2ee8SDavid du Colombier char *match(s, p)
214*219b2ee8SDavid du Colombier {
215*219b2ee8SDavid du Colombier 	register char *rv;
216*219b2ee8SDavid du Colombier 
217*219b2ee8SDavid du Colombier 	strcpy(rv=malloc(8), ltoa((long)ematch(s, p)));
218*219b2ee8SDavid du Colombier 	if(nbra) {
219*219b2ee8SDavid du Colombier 		rv = malloc(strlen(Mstring[0])+1);
220*219b2ee8SDavid du Colombier 		strcpy(rv, Mstring[0]);
221*219b2ee8SDavid du Colombier 	}
222*219b2ee8SDavid du Colombier 	return rv;
223*219b2ee8SDavid du Colombier }
224*219b2ee8SDavid du Colombier 
225*219b2ee8SDavid du Colombier #define INIT	register char *sp = instring;
226*219b2ee8SDavid du Colombier #define GETC()		(*sp++)
227*219b2ee8SDavid du Colombier #define PEEKC()		(*sp)
228*219b2ee8SDavid du Colombier #define UNGETC(c)	(--sp)
229*219b2ee8SDavid du Colombier #define RETURN(c)	return
230*219b2ee8SDavid du Colombier #define ERROR(c)	errxx(c)
231*219b2ee8SDavid du Colombier 
232*219b2ee8SDavid du Colombier 
ematch(s,p)233*219b2ee8SDavid du Colombier ematch(s, p)
234*219b2ee8SDavid du Colombier char *s;
235*219b2ee8SDavid du Colombier register char *p;
236*219b2ee8SDavid du Colombier {
237*219b2ee8SDavid du Colombier 	static char expbuf[ESIZE];
238*219b2ee8SDavid du Colombier 	char *compile();
239*219b2ee8SDavid du Colombier 	register num;
240*219b2ee8SDavid du Colombier 	extern char *braslist[], *braelist[], *loc2;
241*219b2ee8SDavid du Colombier 
242*219b2ee8SDavid du Colombier 	compile(p, expbuf, &expbuf[ESIZE], 0);
243*219b2ee8SDavid du Colombier 	if(nbra > 1)
244*219b2ee8SDavid du Colombier 		yyerror("Too many '\\('s");
245*219b2ee8SDavid du Colombier 	if(advance(s, expbuf)) {
246*219b2ee8SDavid du Colombier 		if(nbra == 1) {
247*219b2ee8SDavid du Colombier 			p = braslist[0];
248*219b2ee8SDavid du Colombier 			num = braelist[0] - p;
249*219b2ee8SDavid du Colombier 			strncpy(Mstring[0], p, num);
250*219b2ee8SDavid du Colombier 			Mstring[0][num] = '\0';
251*219b2ee8SDavid du Colombier 		}
252*219b2ee8SDavid du Colombier 		return(loc2-s);
253*219b2ee8SDavid du Colombier 	}
254*219b2ee8SDavid du Colombier 	return(0);
255*219b2ee8SDavid du Colombier }
256*219b2ee8SDavid du Colombier 
errxx(c)257*219b2ee8SDavid du Colombier errxx(c)
258*219b2ee8SDavid du Colombier {
259*219b2ee8SDavid du Colombier 	yyerror("RE error");
260*219b2ee8SDavid du Colombier }
261*219b2ee8SDavid du Colombier 
262*219b2ee8SDavid du Colombier #include  "regexp.h"
yyerror(s)263*219b2ee8SDavid du Colombier yyerror(s)
264*219b2ee8SDavid du Colombier 
265*219b2ee8SDavid du Colombier {
266*219b2ee8SDavid du Colombier 	write(2, "expr: ", 6);
267*219b2ee8SDavid du Colombier 	prt(2, s);
268*219b2ee8SDavid du Colombier 	exit(2);
269*219b2ee8SDavid du Colombier }
prt(fd,s)270*219b2ee8SDavid du Colombier prt(fd, s)
271*219b2ee8SDavid du Colombier char *s;
272*219b2ee8SDavid du Colombier {
273*219b2ee8SDavid du Colombier 	write(fd, s, strlen(s));
274*219b2ee8SDavid du Colombier 	write(fd, "\n", 1);
275*219b2ee8SDavid du Colombier }
ltoa(l)276*219b2ee8SDavid du Colombier char *ltoa(l)
277*219b2ee8SDavid du Colombier long l;
278*219b2ee8SDavid du Colombier {
279*219b2ee8SDavid du Colombier 	static char str[20];
280*219b2ee8SDavid du Colombier 	register char *sp = &str[18];
281*219b2ee8SDavid du Colombier 	register i;
282*219b2ee8SDavid du Colombier 	register neg = 0;
283*219b2ee8SDavid du Colombier 
284*219b2ee8SDavid du Colombier 	if(l < 0)
285*219b2ee8SDavid du Colombier 		++neg, l *= -1;
286*219b2ee8SDavid du Colombier 	str[19] = '\0';
287*219b2ee8SDavid du Colombier 	do {
288*219b2ee8SDavid du Colombier 		i = l % 10;
289*219b2ee8SDavid du Colombier 		*sp-- = '0' + i;
290*219b2ee8SDavid du Colombier 		l /= 10;
291*219b2ee8SDavid du Colombier 	} while(l);
292*219b2ee8SDavid du Colombier 	if(neg)
293*219b2ee8SDavid du Colombier 		*sp-- = '-';
294*219b2ee8SDavid du Colombier 	return ++sp;
295*219b2ee8SDavid du Colombier }
296