calc.y 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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. struct Exp {
  15. int ty;
  16. long long n;
  17. Exp *e1;
  18. Exp *e2;
  19. };
  20. typedef Exp* Expptr;
  21. #define YYSTYPE Expptr
  22. Exp *yyexp;
  23. %}
  24. %token NUMBER
  25. %left '+' '-'
  26. %left '*' '/'
  27. %left UNARYMINUS '%'
  28. %%
  29. top: expr { yyexp = $1; return 0; }
  30. expr: NUMBER
  31. | '.' { $$ = mkOP(DOT, nil, nil); }
  32. | '$' { $$ = mkOP(DOLLAR, nil, nil); }
  33. | '(' expr ')' { $$ = $2; }
  34. | expr '+' expr { $$ = mkOP(ADD, $1, $3); }
  35. | expr '-' expr { $$ = mkOP(SUB, $1, $3); }
  36. | expr '*' expr { $$ = mkOP(MUL, $1, $3); }
  37. | expr '/' expr { $$ = mkOP(DIV, $1, $3); }
  38. | expr '%' { $$ = mkOP(FRAC, $1, nil); }
  39. | '-' expr %prec UNARYMINUS { $$ = mkOP(NEG, $2, nil); }
  40. ;
  41. %%
  42. #include <u.h>
  43. #include <libc.h>
  44. #include <ctype.h>
  45. #include "disk.h"
  46. #include "edit.h"
  47. static Exp*
  48. mkNUM(vlong x)
  49. {
  50. Exp *n;
  51. n = emalloc(sizeof *n);
  52. n->ty = NUM;
  53. n->n = x;
  54. return n;
  55. }
  56. static Exp*
  57. mkOP(int ty, Exp *e1, Exp *e2)
  58. {
  59. Exp *n;
  60. n = emalloc(sizeof *n);
  61. n->ty = ty;
  62. n->e1 = e1;
  63. n->e2 = e2;
  64. return n;
  65. }
  66. static char *inp;
  67. static jmp_buf jmp;
  68. static vlong dot, size, dollar;
  69. static char** errp;
  70. static int
  71. yylex(void)
  72. {
  73. while(isspace(*inp))
  74. inp++;
  75. if(*inp == 0)
  76. return 0;
  77. if(isdigit(*inp)) {
  78. yylval = mkNUM(strtoll(inp, &inp, 0));
  79. return NUMBER;
  80. }
  81. return *inp++;
  82. }
  83. static void
  84. yyerror(char *s)
  85. {
  86. *errp = s;
  87. longjmp(jmp, 1);
  88. }
  89. static vlong
  90. eval(Exp *e)
  91. {
  92. vlong i;
  93. switch(e->ty) {
  94. case NUM:
  95. return e->n;
  96. case DOT:
  97. return dot;
  98. case DOLLAR:
  99. return dollar;
  100. case ADD:
  101. return eval(e->e1)+eval(e->e2);
  102. case SUB:
  103. return eval(e->e1)-eval(e->e2);
  104. case MUL:
  105. return eval(e->e1)*eval(e->e2);
  106. case DIV:
  107. i = eval(e->e2);
  108. if(i == 0)
  109. yyerror("division by zero");
  110. return eval(e->e1)/i;
  111. case FRAC:
  112. return (size*eval(e->e1))/100;
  113. case NEG:
  114. return -eval(e->e1);
  115. }
  116. assert(0);
  117. return 0;
  118. }
  119. int yyparse(void);
  120. char*
  121. parseexpr(char *s, vlong xdot, vlong xdollar, vlong xsize, vlong *result)
  122. {
  123. char *err;
  124. errp = &err;
  125. if(setjmp(jmp))
  126. return err;
  127. inp = s;
  128. dot = xdot;
  129. size = xsize;
  130. dollar = xdollar;
  131. yyparse();
  132. if(yyexp == nil)
  133. return "nil yylval?";
  134. *result = eval(yyexp);
  135. return nil;
  136. }
  137. #ifdef TEST
  138. void
  139. main(int argc, char **argv)
  140. {
  141. int i;
  142. vlong r;
  143. char *e;
  144. for(i=1; i<argc; i++)
  145. if(e = parseexpr(argv[i], 1000, 1000000, 1000000, &r))
  146. print("%s\n", e);
  147. else
  148. print("%lld\n", r);
  149. }
  150. #endif