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*
mkOP(int ty,Exp * e1,Exp * e2)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
yylex(void)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
yyerror(char * s)126 yyerror(char *s)
127 {
128 *errp = s;
129 longjmp(jmp, 1);
130 }
131
132 static vlong
eval(Exp * e)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*
parseexpr(char * s,vlong xdot,vlong xdollar,vlong xsize,vlong * result)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
main(int argc,char ** argv)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
201