xref: /plan9/sys/src/cmd/disk/prep/calc.y (revision bfb6eab9346d861b5f68a2b1af55a1768a8fe25b)
17dd7cddfSDavid du Colombier %{
27dd7cddfSDavid du Colombier typedef struct Exp Exp;
37dd7cddfSDavid du Colombier enum {
47dd7cddfSDavid du Colombier 	NUM,
57dd7cddfSDavid du Colombier 	DOT,
67dd7cddfSDavid du Colombier 	DOLLAR,
77dd7cddfSDavid du Colombier 	ADD,
87dd7cddfSDavid du Colombier 	SUB,
97dd7cddfSDavid du Colombier 	MUL,
107dd7cddfSDavid du Colombier 	DIV,
117dd7cddfSDavid du Colombier 	FRAC,
127dd7cddfSDavid du Colombier 	NEG,
137dd7cddfSDavid du Colombier };
147dd7cddfSDavid du Colombier 
157dd7cddfSDavid du Colombier struct Exp {
167dd7cddfSDavid du Colombier 	int ty;
177dd7cddfSDavid du Colombier 	long long n;
187dd7cddfSDavid du Colombier 	Exp *e1;
197dd7cddfSDavid du Colombier 	Exp *e2;
207dd7cddfSDavid du Colombier };
217dd7cddfSDavid du Colombier 
227dd7cddfSDavid du Colombier typedef Exp* Expptr;
237dd7cddfSDavid du Colombier #define YYSTYPE Expptr
247dd7cddfSDavid du Colombier Exp *yyexp;
257dd7cddfSDavid du Colombier %}
267dd7cddfSDavid du Colombier 
277dd7cddfSDavid du Colombier %token NUMBER
287dd7cddfSDavid du Colombier 
297dd7cddfSDavid du Colombier %left '+' '-'
307dd7cddfSDavid du Colombier %left '*' '/'
317dd7cddfSDavid du Colombier %left UNARYMINUS '%'
327dd7cddfSDavid du Colombier %%
337dd7cddfSDavid du Colombier top:	expr	{ yyexp = $1; return 0; }
347dd7cddfSDavid du Colombier 
357dd7cddfSDavid du Colombier expr:	NUMBER
367dd7cddfSDavid du Colombier 	| '.'	{ $$ = mkOP(DOT, nil, nil); }
377dd7cddfSDavid du Colombier 	| '$'	{ $$ = mkOP(DOLLAR, nil, nil); }
387dd7cddfSDavid du Colombier 	| '(' expr ')'	{ $$ = $2; }
397dd7cddfSDavid du Colombier 	| expr '+' expr	{ $$ = mkOP(ADD, $1, $3); }
407dd7cddfSDavid du Colombier 	| expr '-' expr 	{ $$ = mkOP(SUB, $1, $3); }
417dd7cddfSDavid du Colombier 	| expr '*' expr	{ $$ = mkOP(MUL, $1, $3); }
427dd7cddfSDavid du Colombier 	| expr '/' expr	{ $$ = mkOP(DIV, $1, $3); }
437dd7cddfSDavid du Colombier 	| expr '%'		{ $$ = mkOP(FRAC, $1, nil); }
447dd7cddfSDavid du Colombier 	| '-' expr %prec UNARYMINUS	{ $$ = mkOP(NEG, $2, nil); }
457dd7cddfSDavid du Colombier 	;
467dd7cddfSDavid du Colombier 
477dd7cddfSDavid du Colombier %%
487dd7cddfSDavid du Colombier 
497dd7cddfSDavid du Colombier #include <u.h>
507dd7cddfSDavid du Colombier #include <libc.h>
517dd7cddfSDavid du Colombier #include <ctype.h>
527dd7cddfSDavid du Colombier #include "disk.h"
537dd7cddfSDavid du Colombier #include "edit.h"
547dd7cddfSDavid du Colombier 
557dd7cddfSDavid du Colombier static Exp*
567dd7cddfSDavid du Colombier mkNUM(vlong x)
577dd7cddfSDavid du Colombier {
587dd7cddfSDavid du Colombier 	Exp *n;
597dd7cddfSDavid du Colombier 
607dd7cddfSDavid du Colombier 	n = emalloc(sizeof *n);
617dd7cddfSDavid du Colombier 
627dd7cddfSDavid du Colombier 	n->ty = NUM;
637dd7cddfSDavid du Colombier 	n->n = x;
647dd7cddfSDavid du Colombier 	return n;
657dd7cddfSDavid du Colombier }
667dd7cddfSDavid du Colombier 
677dd7cddfSDavid du Colombier static Exp*
mkOP(int ty,Exp * e1,Exp * e2)687dd7cddfSDavid du Colombier mkOP(int ty, Exp *e1, Exp *e2)
697dd7cddfSDavid du Colombier {
707dd7cddfSDavid du Colombier 	Exp *n;
717dd7cddfSDavid du Colombier 
727dd7cddfSDavid du Colombier 	n = emalloc(sizeof *n);
737dd7cddfSDavid du Colombier 	n->ty = ty;
747dd7cddfSDavid du Colombier 	n->e1 = e1;
757dd7cddfSDavid du Colombier 	n->e2 = e2;
767dd7cddfSDavid du Colombier 
777dd7cddfSDavid du Colombier 	return n;
787dd7cddfSDavid du Colombier }
797dd7cddfSDavid du Colombier 
807dd7cddfSDavid du Colombier static char *inp;
817dd7cddfSDavid du Colombier static jmp_buf jmp;
827dd7cddfSDavid du Colombier static vlong dot, size, dollar;
8374f16c81SDavid du Colombier static char** errp;
847dd7cddfSDavid du Colombier 
857dd7cddfSDavid du Colombier static int
yylex(void)867dd7cddfSDavid du Colombier yylex(void)
877dd7cddfSDavid du Colombier {
88*bfb6eab9SDavid du Colombier 	int c;
89*bfb6eab9SDavid du Colombier 	uvlong n;
90*bfb6eab9SDavid du Colombier 
917dd7cddfSDavid du Colombier 	while(isspace(*inp))
927dd7cddfSDavid du Colombier 		inp++;
937dd7cddfSDavid du Colombier 
947dd7cddfSDavid du Colombier 	if(*inp == 0)
957dd7cddfSDavid du Colombier 		return 0;
967dd7cddfSDavid du Colombier 
977dd7cddfSDavid du Colombier 	if(isdigit(*inp)) {
98*bfb6eab9SDavid du Colombier 		n = strtoull(inp, &inp, 0);	/* default unit is sectors */
99*bfb6eab9SDavid du Colombier 		c = *inp++;
100*bfb6eab9SDavid du Colombier 		if(isascii(c) && isupper(c))
101*bfb6eab9SDavid du Colombier 			c = tolower(c);
102*bfb6eab9SDavid du Colombier 		switch(c) {
103*bfb6eab9SDavid du Colombier 		case 't':
104*bfb6eab9SDavid du Colombier 			n *= 1024;
105*bfb6eab9SDavid du Colombier 			/* fall through */
106*bfb6eab9SDavid du Colombier 		case 'g':
107*bfb6eab9SDavid du Colombier 			n *= 1024;
108*bfb6eab9SDavid du Colombier 			/* fall through */
109*bfb6eab9SDavid du Colombier 		case 'm':
110*bfb6eab9SDavid du Colombier 			n *= 1024;
111*bfb6eab9SDavid du Colombier 			/* fall through */
112*bfb6eab9SDavid du Colombier 		case 'k':
113*bfb6eab9SDavid du Colombier 			n *= 2;
114*bfb6eab9SDavid du Colombier 			break;
115*bfb6eab9SDavid du Colombier 		default:
116*bfb6eab9SDavid du Colombier 			--inp;
117*bfb6eab9SDavid du Colombier 			break;
118*bfb6eab9SDavid du Colombier 		}
119*bfb6eab9SDavid du Colombier 		yylval = mkNUM(n);
1207dd7cddfSDavid du Colombier 		return NUMBER;
1217dd7cddfSDavid du Colombier 	}
1227dd7cddfSDavid du Colombier 	return *inp++;
1237dd7cddfSDavid du Colombier }
1247dd7cddfSDavid du Colombier 
1257dd7cddfSDavid du Colombier static void
yyerror(char * s)1267dd7cddfSDavid du Colombier yyerror(char *s)
1277dd7cddfSDavid du Colombier {
12874f16c81SDavid du Colombier 	*errp = s;
12974f16c81SDavid du Colombier 	longjmp(jmp, 1);
1307dd7cddfSDavid du Colombier }
1317dd7cddfSDavid du Colombier 
1327dd7cddfSDavid du Colombier static vlong
eval(Exp * e)1337dd7cddfSDavid du Colombier eval(Exp *e)
1347dd7cddfSDavid du Colombier {
1357dd7cddfSDavid du Colombier 	vlong i;
1367dd7cddfSDavid du Colombier 
1377dd7cddfSDavid du Colombier 	switch(e->ty) {
1387dd7cddfSDavid du Colombier 	case NUM:
1397dd7cddfSDavid du Colombier 		return e->n;
1407dd7cddfSDavid du Colombier 	case DOT:
1417dd7cddfSDavid du Colombier 		return dot;
1427dd7cddfSDavid du Colombier 	case DOLLAR:
1437dd7cddfSDavid du Colombier 		return dollar;
1447dd7cddfSDavid du Colombier 	case ADD:
1457dd7cddfSDavid du Colombier 		return eval(e->e1)+eval(e->e2);
1467dd7cddfSDavid du Colombier 	case SUB:
1477dd7cddfSDavid du Colombier 		return eval(e->e1)-eval(e->e2);
1487dd7cddfSDavid du Colombier 	case MUL:
1497dd7cddfSDavid du Colombier 		return eval(e->e1)*eval(e->e2);
1507dd7cddfSDavid du Colombier 	case DIV:
1517dd7cddfSDavid du Colombier 		i = eval(e->e2);
1527dd7cddfSDavid du Colombier 		if(i == 0)
1537dd7cddfSDavid du Colombier 			yyerror("division by zero");
1547dd7cddfSDavid du Colombier 		return eval(e->e1)/i;
1557dd7cddfSDavid du Colombier 	case FRAC:
1567dd7cddfSDavid du Colombier 		return (size*eval(e->e1))/100;
1577dd7cddfSDavid du Colombier 	case NEG:
1587dd7cddfSDavid du Colombier 		return -eval(e->e1);
1597dd7cddfSDavid du Colombier 	}
1607dd7cddfSDavid du Colombier 	assert(0);
1617dd7cddfSDavid du Colombier 	return 0;
1627dd7cddfSDavid du Colombier }
1637dd7cddfSDavid du Colombier 
1647dd7cddfSDavid du Colombier int yyparse(void);
1657dd7cddfSDavid du Colombier 
1667dd7cddfSDavid du Colombier char*
parseexpr(char * s,vlong xdot,vlong xdollar,vlong xsize,vlong * result)1677dd7cddfSDavid du Colombier parseexpr(char *s, vlong xdot, vlong xdollar, vlong xsize, vlong *result)
1687dd7cddfSDavid du Colombier {
1697dd7cddfSDavid du Colombier 	char *err;
1707dd7cddfSDavid du Colombier 
17174f16c81SDavid du Colombier 	errp = &err;
17274f16c81SDavid du Colombier 	if(setjmp(jmp))
1737dd7cddfSDavid du Colombier 		return err;
1747dd7cddfSDavid du Colombier 
1757dd7cddfSDavid du Colombier 	inp = s;
1767dd7cddfSDavid du Colombier 	dot = xdot;
1777dd7cddfSDavid du Colombier 	size = xsize;
1787dd7cddfSDavid du Colombier 	dollar = xdollar;
1797dd7cddfSDavid du Colombier 	yyparse();
1807dd7cddfSDavid du Colombier 	if(yyexp == nil)
1817dd7cddfSDavid du Colombier 		return "nil yylval?";
1827dd7cddfSDavid du Colombier 	*result = eval(yyexp);
1837dd7cddfSDavid du Colombier 	return nil;
1847dd7cddfSDavid du Colombier }
1857dd7cddfSDavid du Colombier 
1867dd7cddfSDavid du Colombier #ifdef TEST
1877dd7cddfSDavid du Colombier void
main(int argc,char ** argv)1887dd7cddfSDavid du Colombier main(int argc, char **argv)
1897dd7cddfSDavid du Colombier {
1907dd7cddfSDavid du Colombier 	int i;
1917dd7cddfSDavid du Colombier 	vlong r;
1927dd7cddfSDavid du Colombier 	char *e;
1937dd7cddfSDavid du Colombier 
1947dd7cddfSDavid du Colombier 	for(i=1; i<argc; i++)
1957dd7cddfSDavid du Colombier 		if(e = parseexpr(argv[i], 1000, 1000000, 1000000, &r))
1967dd7cddfSDavid du Colombier 			print("%s\n", e);
1977dd7cddfSDavid du Colombier 		else
1987dd7cddfSDavid du Colombier 			print("%lld\n", r);
1997dd7cddfSDavid du Colombier }
2007dd7cddfSDavid du Colombier #endif
201