|
|
@@ -1,238 +0,0 @@
|
|
|
-#!/usr/bin/env python
|
|
|
-"""
|
|
|
-A simple pybison parser program implementing a calculator
|
|
|
-"""
|
|
|
-
|
|
|
-from __future__ import division
|
|
|
-from sympy import Symbol
|
|
|
-
|
|
|
-import os.path
|
|
|
-PYBISON_BUILD = os.path.realpath('build/external/pybison')
|
|
|
-EXTERNAL_MODS = os.path.realpath('external')
|
|
|
-
|
|
|
-import sys
|
|
|
-sys.path.insert(0, PYBISON_BUILD)
|
|
|
-sys.path.insert(1, EXTERNAL_MODS)
|
|
|
-
|
|
|
-from pybison import BisonParser
|
|
|
-
|
|
|
-
|
|
|
-class Parser(BisonParser):
|
|
|
- """
|
|
|
- Implements the calculator parser. Grammar rules are defined in the method
|
|
|
- docstrings. Scanner rules are in the 'lexscript' attribute.
|
|
|
- """
|
|
|
-
|
|
|
- # Output directory of generated pybison files, including a trailing slash.
|
|
|
- buildDirectory = PYBISON_BUILD + '/'
|
|
|
-
|
|
|
- # ----------------------------------------------------------------
|
|
|
- # lexer tokens - these must match those in your lex script (below)
|
|
|
- # ----------------------------------------------------------------
|
|
|
- tokens = ['NUMBER', 'IDENTIFIER',
|
|
|
- 'PLUS', 'MINUS', 'TIMES', 'DIVIDE', 'POW',
|
|
|
- 'LPAREN', 'RPAREN',
|
|
|
- 'NEWLINE', 'QUIT']
|
|
|
-
|
|
|
- # ------------------------------
|
|
|
- # precedences
|
|
|
- # ------------------------------
|
|
|
- precedences = (
|
|
|
- ('left', ('MINUS', 'PLUS')),
|
|
|
- ('left', ('TIMES', 'DIVIDE')),
|
|
|
- ('left', ('NEG', )),
|
|
|
- ('right', ('POW', )),
|
|
|
- )
|
|
|
-
|
|
|
- interactive = 0
|
|
|
-
|
|
|
- def __init__(self, **kwargs):
|
|
|
- BisonParser.__init__(self, **kwargs)
|
|
|
- self.interactive = kwargs.get('interactive', 0)
|
|
|
- self.timeout = kwargs.get('timeout', 0)
|
|
|
-
|
|
|
- # ------------------------------------------------------------------
|
|
|
- # override default read method with a version that prompts for input
|
|
|
- # ------------------------------------------------------------------
|
|
|
- def read(self, nbytes):
|
|
|
- try:
|
|
|
- return raw_input('>>> ') + "\n"
|
|
|
- except EOFError:
|
|
|
- return ''
|
|
|
-
|
|
|
- # ---------------------------------------------------------------
|
|
|
- # These methods are the python handlers for the bison targets.
|
|
|
- # (which get called by the bison code each time the corresponding
|
|
|
- # parse target is unambiguously reached)
|
|
|
- #
|
|
|
- # WARNING - don't touch the method docstrings unless you know what
|
|
|
- # you are doing - they are in bison rule syntax, and are passed
|
|
|
- # verbatim to bison to build the parser engine library.
|
|
|
- # ---------------------------------------------------------------
|
|
|
-
|
|
|
- # Declare the start target here (by name)
|
|
|
- start = "input"
|
|
|
-
|
|
|
- def on_input(self, target, option, names, values):
|
|
|
- """
|
|
|
- input :
|
|
|
- | input line
|
|
|
- """
|
|
|
-
|
|
|
- if option == 1:
|
|
|
- # Interactive mode is enabled if the term rewriting system is used
|
|
|
- # as a shell. In that case, it is useful that the shell prints the
|
|
|
- # output of the evaluation.
|
|
|
- if self.interactive:
|
|
|
- print values[1]
|
|
|
-
|
|
|
- return values[1]
|
|
|
-
|
|
|
- def on_line(self, target, option, names, values):
|
|
|
- """
|
|
|
- line : NEWLINE
|
|
|
- | exp NEWLINE
|
|
|
- """
|
|
|
- if option in [1, 2]:
|
|
|
- if self.verbose:
|
|
|
- print 'on_line: exp =', values[0]
|
|
|
-
|
|
|
- return values[0]
|
|
|
-
|
|
|
- def on_exp(self, target, option, names, values):
|
|
|
- """
|
|
|
- exp : NUMBER
|
|
|
- | IDENTIFIER
|
|
|
- | exp PLUS exp
|
|
|
- | exp MINUS exp
|
|
|
- | exp TIMES exp
|
|
|
- | exp DIVIDE exp
|
|
|
- | MINUS exp %prec NEG
|
|
|
- | exp POW exp
|
|
|
- | LPAREN exp RPAREN
|
|
|
- | symbolic
|
|
|
- """
|
|
|
-
|
|
|
- if self.verbose:
|
|
|
- print 'on_exp: got %s %s %s %s' % (target, option, names, values)
|
|
|
-
|
|
|
- # rule: NUMBER
|
|
|
- if option == 0:
|
|
|
- # TODO: A bit hacky, this achieves long integers and floats.
|
|
|
- #return float(values[0]) if '.' in values[0] else long(values[0])
|
|
|
- #return float(values[0])
|
|
|
- return float(values[0]) if '.' in values[0] else int(values[0])
|
|
|
-
|
|
|
- # rule: IDENTIFIER
|
|
|
- if option == 1:
|
|
|
- return Symbol(values[0])
|
|
|
-
|
|
|
- # rule: LPAREN exp RPAREN
|
|
|
- if option == 8:
|
|
|
- return values[1]
|
|
|
-
|
|
|
- # rule: symbolic
|
|
|
- if option == 9:
|
|
|
- return values[1]
|
|
|
-
|
|
|
- try:
|
|
|
- # rule: exp PLUS expo
|
|
|
- if option == 2:
|
|
|
- return values[0] + values[2]
|
|
|
-
|
|
|
- # rule: exp MINUS expo
|
|
|
- if option == 3:
|
|
|
- return values[0] - values[2]
|
|
|
-
|
|
|
- # rule: exp TIMES expo
|
|
|
- if option == 4:
|
|
|
- return values[0] * values[2]
|
|
|
-
|
|
|
- # rule: exp DIVIDE expo
|
|
|
- if option == 5:
|
|
|
- return values[0] / values[2]
|
|
|
-
|
|
|
- # rule: NEG expo
|
|
|
- if option == 6:
|
|
|
- return - values[1]
|
|
|
-
|
|
|
- # rule: exp POW expo
|
|
|
- if option == 7:
|
|
|
- return values[0] ** values[2]
|
|
|
- except OverflowError:
|
|
|
- print >>sys.stderr, 'error: Overflow occured in "%s" %s %s %s' \
|
|
|
- % (target, option, names, values)
|
|
|
-
|
|
|
- def on_symbolic(self, target, option, names, values):
|
|
|
- """
|
|
|
- symbolic : NUMBER IDENTIFIER
|
|
|
- | IDENTIFIER NUMBER
|
|
|
- | IDENTIFIER IDENTIFIER
|
|
|
- """
|
|
|
- # TODO: this class method requires verification.
|
|
|
-
|
|
|
- # rule: NUMBER IDENTIFIER
|
|
|
- if option == 0:
|
|
|
- # 4x -> 4*x
|
|
|
- return values[0] * Symbol(values[1])
|
|
|
-
|
|
|
- # rule: IDENTIFIER NUMBER
|
|
|
- if option == 1:
|
|
|
- # x4 -> x^4
|
|
|
- return Symbol(values[0]) ** values[1]
|
|
|
-
|
|
|
- # rule: IDENTIFIER IDENTIFIER
|
|
|
- if option == 2:
|
|
|
- # a b -> a * b
|
|
|
- return Symbol(values[0]) * Symbol(values[1])
|
|
|
-
|
|
|
- # -----------------------------------------
|
|
|
- # raw lex script, verbatim here
|
|
|
- # -----------------------------------------
|
|
|
- lexscript = r"""
|
|
|
- %{
|
|
|
- //int yylineno = 0;
|
|
|
- #include <stdio.h>
|
|
|
- #include <string.h>
|
|
|
- #include "Python.h"
|
|
|
- #define YYSTYPE void *
|
|
|
- #include "tokens.h"
|
|
|
- extern void *py_parser;
|
|
|
- extern void (*py_input)(PyObject *parser, char *buf, int *result,
|
|
|
- int max_size);
|
|
|
- #define returntoken(tok) \
|
|
|
- yylval = PyString_FromString(strdup(yytext)); return (tok);
|
|
|
- #define YY_INPUT(buf,result,max_size) { \
|
|
|
- (*py_input)(py_parser, buf, &result, max_size); \
|
|
|
- }
|
|
|
- %}
|
|
|
-
|
|
|
- %%
|
|
|
-
|
|
|
- [0-9]+ { returntoken(NUMBER); }
|
|
|
- [a-zA-Z][a-zA-Z0-9]* { returntoken(IDENTIFIER); }
|
|
|
- "(" { returntoken(LPAREN); }
|
|
|
- ")" { returntoken(RPAREN); }
|
|
|
- "+" { returntoken(PLUS); }
|
|
|
- "-" { returntoken(MINUS); }
|
|
|
- "*" { returntoken(TIMES); }
|
|
|
- "^" { returntoken(POW); }
|
|
|
- "/" { returntoken(DIVIDE); }
|
|
|
- "quit" { printf("lex: got QUIT\n"); yyterminate(); returntoken(QUIT); }
|
|
|
-
|
|
|
- [ \t\v\f] {}
|
|
|
- [\n] {yylineno++; returntoken(NEWLINE); }
|
|
|
- . { printf("unknown char %c ignored, yytext=0x%lx\n",
|
|
|
- yytext[0], yytext); /* ignore bad chars */}
|
|
|
-
|
|
|
- %%
|
|
|
-
|
|
|
- yywrap() { return(1); }
|
|
|
- """
|
|
|
-
|
|
|
-if __name__ == '__main__':
|
|
|
- p = Parser(verbose=0, keepfiles=1, interactive=1)
|
|
|
- p.run(debug=0)
|
|
|
-
|
|
|
- # Clear the line, when the shell exits.
|
|
|
- print
|