Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
%{
2
typedef struct Exp Exp;
3
enum {
4
	NUM,
5
	DOT,
6
	DOLLAR,
7
	ADD,
8
	SUB,
9
	MUL,
10
	DIV,
11
	FRAC,
12
	NEG,
13
};
14
 
15
struct Exp {
16
	int ty;
17
	long long n;
18
	Exp *e1;
19
	Exp *e2;
20
};
21
 
22
typedef Exp* Expptr;
23
#define YYSTYPE Expptr
24
Exp *yyexp;
25
%}
26
 
27
%token NUMBER
28
 
29
%left '+' '-'
30
%left '*' '/'
31
%left UNARYMINUS '%'
32
%%
33
top:	expr	{ yyexp = $1; return 0; }
34
 
35
expr:	NUMBER
36
	| '.'	{ $$ = mkOP(DOT, nil, nil); }
37
	| '$'	{ $$ = mkOP(DOLLAR, nil, nil); }
38
	| '(' expr ')'	{ $$ = $2; }
39
	| expr '+' expr	{ $$ = mkOP(ADD, $1, $3); }
40
	| expr '-' expr 	{ $$ = mkOP(SUB, $1, $3); }
41
	| expr '*' expr	{ $$ = mkOP(MUL, $1, $3); }
42
	| expr '/' expr	{ $$ = mkOP(DIV, $1, $3); }
43
	| expr '%'		{ $$ = mkOP(FRAC, $1, nil); }
44
	| '-' expr %prec UNARYMINUS	{ $$ = mkOP(NEG, $2, nil); }
45
	;
46
 
47
%%
48
 
49
#include <u.h>
50
#include <libc.h>
51
#include <ctype.h>
52
#include "disk.h"
53
#include "edit.h"
54
 
55
static Exp*
56
mkNUM(vlong x)
57
{
58
	Exp *n;
59
 
60
	n = emalloc(sizeof *n);
61
 
62
	n->ty = NUM;
63
	n->n = x;
64
	return n;
65
}
66
 
67
static Exp*
68
mkOP(int ty, Exp *e1, Exp *e2)
69
{
70
	Exp *n;
71
 
72
	n = emalloc(sizeof *n);
73
	n->ty = ty;
74
	n->e1 = e1;
75
	n->e2 = e2;
76
 
77
	return n;
78
}
79
 
80
static char *inp;
81
static jmp_buf jmp;
82
static vlong dot, size, dollar;
83
static char** errp;
84
 
85
static int
86
yylex(void)
87
{
88
	int c;
89
	uvlong n;
90
 
91
	while(isspace(*inp))
92
		inp++;
93
 
94
	if(*inp == 0)
95
		return 0;
96
 
97
	if(isdigit(*inp)) {
98
		n = strtoull(inp, &inp, 0);	/* default unit is sectors */
99
		c = *inp++;
100
		if(isascii(c) && isupper(c))
101
			c = tolower(c);
102
		switch(c) {
103
		case 't':
104
			n *= 1024;
105
			/* fall through */
106
		case 'g':
107
			n *= 1024;
108
			/* fall through */
109
		case 'm':
110
			n *= 1024;
111
			/* fall through */
112
		case 'k':
113
			n *= 2;
114
			break;
115
		default:
116
			--inp;
117
			break;
118
		}
119
		yylval = mkNUM(n);
120
		return NUMBER;
121
	}
122
	return *inp++;
123
}
124
 
125
static void
126
yyerror(char *s)
127
{
128
	*errp = s;
129
	longjmp(jmp, 1);
130
}
131
 
132
static vlong
133
eval(Exp *e)
134
{
135
	vlong i;
136
 
137
	switch(e->ty) {
138
	case NUM:
139
		return e->n;
140
	case DOT:
141
		return dot;
142
	case DOLLAR:
143
		return dollar;
144
	case ADD:
145
		return eval(e->e1)+eval(e->e2);
146
	case SUB:
147
		return eval(e->e1)-eval(e->e2);
148
	case MUL:
149
		return eval(e->e1)*eval(e->e2);
150
	case DIV:
151
		i = eval(e->e2);
152
		if(i == 0)
153
			yyerror("division by zero");
154
		return eval(e->e1)/i;
155
	case FRAC:
156
		return (size*eval(e->e1))/100;
157
	case NEG:
158
		return -eval(e->e1);
159
	}
160
	assert(0);
161
	return 0;
162
}
163
 
164
int yyparse(void);
165
 
166
char*
167
parseexpr(char *s, vlong xdot, vlong xdollar, vlong xsize, vlong *result)
168
{
169
	char *err;
170
 
171
	errp = &err;
172
	if(setjmp(jmp))
173
		return err;
174
 
175
	inp = s;
176
	dot = xdot;
177
	size = xsize;
178
	dollar = xdollar;
179
	yyparse();
180
	if(yyexp == nil)
181
		return "nil yylval?";
182
	*result = eval(yyexp);
183
	return nil;
184
}
185
 
186
#ifdef TEST
187
void
188
main(int argc, char **argv)
189
{
190
	int i;
191
	vlong r;
192
	char *e;
193
 
194
	for(i=1; i<argc; i++)
195
		if(e = parseexpr(argv[i], 1000, 1000000, 1000000, &r))
196
			print("%s\n", e);
197
		else
198
			print("%lld\n", r);
199
}
200
#endif