calc.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. #!/usr/bin/env python
  2. """
  3. A simple pybison parser program implementing a calculator
  4. """
  5. from bison import BisonParser
  6. class Parser(BisonParser):
  7. """
  8. Implements the calculator parser. Grammar rules are defined in the method
  9. docstrings. Scanner rules are in the 'lexscript' attribute.
  10. """
  11. # ----------------------------------------------------------------
  12. # lexer tokens - these must match those in your lex script (below)
  13. # ----------------------------------------------------------------
  14. tokens = ['NUMBER',
  15. 'PLUS', 'MINUS', 'TIMES', 'DIVIDE', 'POW',
  16. 'LPAREN', 'RPAREN',
  17. 'NEWLINE', 'QUIT']
  18. # ------------------------------
  19. # precedences
  20. # ------------------------------
  21. precedences = (
  22. ('left', ('MINUS', 'PLUS')),
  23. ('left', ('TIMES', 'DIVIDE')),
  24. ('left', ('NEG', )),
  25. ('right', ('POW', )),
  26. )
  27. # ------------------------------------------------------------------
  28. # override default read method with a version that prompts for input
  29. # ------------------------------------------------------------------
  30. def read(self, nbytes):
  31. try:
  32. return raw_input("> ") + "\n"
  33. except EOFError:
  34. return ''
  35. # ---------------------------------------------------------------
  36. # These methods are the python handlers for the bison targets.
  37. # (which get called by the bison code each time the corresponding
  38. # parse target is unambiguously reached)
  39. #
  40. # WARNING - don't touch the method docstrings unless you know what
  41. # you are doing - they are in bison rule syntax, and are passed
  42. # verbatim to bison to build the parser engine library.
  43. # ---------------------------------------------------------------
  44. # Declare the start target here (by name)
  45. start = "input"
  46. def on_input(self, target, option, names, values):
  47. """
  48. input :
  49. | input line
  50. """
  51. return
  52. def on_line(self, target, option, names, values):
  53. """
  54. line : NEWLINE
  55. | exp NEWLINE
  56. """
  57. if option == 1:
  58. print values[0]
  59. def on_exp(self, target, option, names, values):
  60. """
  61. exp : NUMBER
  62. | exp PLUS exp
  63. | exp MINUS exp
  64. | exp TIMES exp
  65. | exp DIVIDE exp
  66. | MINUS exp %prec NEG
  67. | exp POW exp
  68. | LPAREN exp RPAREN
  69. """
  70. #print "on_exp: got %s %s %s %s" % (target, option, names, values)
  71. if option == 0:
  72. return float(values[0])
  73. elif option == 1:
  74. return values[0] + values[2]
  75. elif option == 2:
  76. return values[0] - values[2]
  77. elif option == 3:
  78. return values[0] * values[2]
  79. elif option == 4:
  80. return values[0] / values[2]
  81. elif option == 5:
  82. return - values[1]
  83. elif option == 6:
  84. return values[0] ** values[2]
  85. elif option == 7:
  86. return values[1]
  87. # -----------------------------------------
  88. # raw lex script, verbatim here
  89. # -----------------------------------------
  90. lexscript = r"""
  91. %{
  92. //int yylineno = 0;
  93. #include <stdio.h>
  94. #include <string.h>
  95. #include "Python.h"
  96. #define YYSTYPE void *
  97. #include "tokens.h"
  98. extern void *py_parser;
  99. extern void (*py_input)(PyObject *parser, char *buf, int *result,
  100. int max_size);
  101. #define returntoken(tok) \
  102. yylval = PyString_FromString(strdup(yytext)); return (tok);
  103. #define YY_INPUT(buf,result,max_size) { \
  104. (*py_input)(py_parser, buf, &result, max_size); \
  105. }
  106. %}
  107. %%
  108. [0-9]+ { returntoken(NUMBER); }
  109. "(" { returntoken(LPAREN); }
  110. ")" { returntoken(RPAREN); }
  111. "+" { returntoken(PLUS); }
  112. "-" { returntoken(MINUS); }
  113. "*" { returntoken(TIMES); }
  114. "**" { returntoken(POW); }
  115. "/" { returntoken(DIVIDE); }
  116. "quit" { printf("lex: got QUIT\n"); yyterminate(); returntoken(QUIT); }
  117. [ \t\v\f] {}
  118. [\n] {yylineno++; returntoken(NEWLINE); }
  119. . { printf("unknown char %c ignored, yytext=0x%lx\n", yytext[0],
  120. yytext); /* ignore bad chars */}
  121. %%
  122. yywrap() { return(1); }
  123. """
  124. if __name__ == '__main__':
  125. Parser().run()