200 lines · 2.7 KB · Text
RawDownload
%{typedef struct Exp Exp;enum {	NUM,	DOT,	DOLLAR,	ADD,	SUB,	MUL,	DIV,	FRAC,	NEG,}; struct Exp {	int ty;	long long n;	Exp *e1;	Exp *e2;}; typedef Exp* Expptr;#define YYSTYPE ExpptrExp *yyexp;%} %token NUMBER %left '+' '-'%left '*' '/'%left UNARYMINUS '%'%%top:	expr	{ yyexp = $1; return 0; } expr:	NUMBER	| '.'	{ $$ = mkOP(DOT, nil, nil); }	| '$'	{ $$ = mkOP(DOLLAR, nil, nil); }	| '(' expr ')'	{ $$ = $2; }	| expr '+' expr	{ $$ = mkOP(ADD, $1, $3); }	| expr '-' expr 	{ $$ = mkOP(SUB, $1, $3); }	| expr '*' expr	{ $$ = mkOP(MUL, $1, $3); }	| expr '/' expr	{ $$ = mkOP(DIV, $1, $3); }	| expr '%'		{ $$ = mkOP(FRAC, $1, nil); }	| '-' expr %prec UNARYMINUS	{ $$ = mkOP(NEG, $2, nil); }	; %% #include <u.h>#include <libc.h>#include <ctype.h>#include "disk.h"#include "edit.h" static Exp*mkNUM(vlong x){	Exp *n; 	n = emalloc(sizeof *n); 	n->ty = NUM;	n->n = x;	return n;} static Exp*mkOP(int ty, Exp *e1, Exp *e2){	Exp *n; 	n = emalloc(sizeof *n);	n->ty = ty;	n->e1 = e1;	n->e2 = e2; 	return n;} static char *inp;static jmp_buf jmp;static vlong dot, size, dollar;static char** errp; static intyylex(void){	int c;	uvlong n; 	while(isspace(*inp))		inp++; 	if(*inp == 0)		return 0; 	if(isdigit(*inp)) {		n = strtoull(inp, &inp, 0);	/* default unit is sectors */		c = *inp++;		if(isascii(c) && isupper(c))			c = tolower(c);		switch(c) {		case 't':			n *= 1024;			/* fall through */		case 'g':			n *= 1024;			/* fall through */		case 'm':			n *= 1024;			/* fall through */		case 'k':			n *= 2;			break;		default:			--inp;			break;		}		yylval = mkNUM(n);		return NUMBER;	}	return *inp++;} static voidyyerror(char *s){	*errp = s;	longjmp(jmp, 1);} static vlongeval(Exp *e){	vlong i; 	switch(e->ty) {	case NUM:		return e->n;	case DOT:		return dot;	case DOLLAR:		return dollar;	case ADD:		return eval(e->e1)+eval(e->e2);	case SUB:		return eval(e->e1)-eval(e->e2);	case MUL:		return eval(e->e1)*eval(e->e2);	case DIV:		i = eval(e->e2);		if(i == 0)			yyerror("division by zero");		return eval(e->e1)/i;	case FRAC:		return (size*eval(e->e1))/100;	case NEG:		return -eval(e->e1);	}	assert(0);	return 0;} int yyparse(void); char*parseexpr(char *s, vlong xdot, vlong xdollar, vlong xsize, vlong *result){	char *err; 	errp = &err;	if(setjmp(jmp))		return err; 	inp = s;	dot = xdot;	size = xsize;	dollar = xdollar;	yyparse();	if(yyexp == nil)		return "nil yylval?";	*result = eval(yyexp);	return nil;} #ifdef TESTvoidmain(int argc, char **argv){	int i;	vlong r;	char *e; 	for(i=1; i<argc; i++)		if(e = parseexpr(argv[i], 1000, 1000000, 1000000, &r))			print("%s\n", e);		else			print("%lld\n", r);}#endif