calc.py 4.3 KB

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