calc.y 2.9 KB

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