cscg24-lolpython

CSCG 2024 Challenge 'Can I Haz Lolpython?'
git clone https://git.sinitax.com/sinitax/cscg24-lolpython
Log | Files | Refs | sfeed.txt

calc.py (4007B)


      1#!/usr/bin/env python
      2
      3# -----------------------------------------------------------------------------
      4# calc.py
      5#
      6# A simple calculator with variables.   This is from O'Reilly's
      7# "Lex and Yacc", p. 63.
      8#
      9# Class-based example contributed to PLY by David McNab.
     10#
     11# Modified to use new-style classes.   Test case.
     12# -----------------------------------------------------------------------------
     13
     14import sys
     15sys.path.insert(0,"../..")
     16
     17import readline
     18import ply.lex as lex
     19import ply.yacc as yacc
     20import os
     21
     22class Parser(object):
     23    """
     24    Base class for a lexer/parser that has the rules defined as methods
     25    """
     26    tokens = ()
     27    precedence = ()
     28
     29
     30    def __init__(self, **kw):
     31        self.debug = kw.get('debug', 0)
     32        self.names = { }
     33        try:
     34            modname = os.path.split(os.path.splitext(__file__)[0])[1] + "_" + self.__class__.__name__
     35        except:
     36            modname = "parser"+"_"+self.__class__.__name__
     37        self.debugfile = modname + ".dbg"
     38        self.tabmodule = modname + "_" + "parsetab"
     39        #print self.debugfile, self.tabmodule
     40
     41        # Build the lexer and parser
     42        lex.lex(module=self, debug=self.debug)
     43        yacc.yacc(module=self,
     44                  debug=self.debug,
     45                  debugfile=self.debugfile,
     46                  tabmodule=self.tabmodule)
     47
     48    def run(self):
     49        while 1:
     50            try:
     51                s = raw_input('calc > ')
     52            except EOFError:
     53                break
     54            if not s: continue     
     55            yacc.parse(s)
     56
     57    
     58class Calc(Parser):
     59
     60    tokens = (
     61        'NAME','NUMBER',
     62        'PLUS','MINUS','EXP', 'TIMES','DIVIDE','EQUALS',
     63        'LPAREN','RPAREN',
     64        )
     65
     66    # Tokens
     67
     68    t_PLUS    = r'\+'
     69    t_MINUS   = r'-'
     70    t_EXP     = r'\*\*'
     71    t_TIMES   = r'\*'
     72    t_DIVIDE  = r'/'
     73    t_EQUALS  = r'='
     74    t_LPAREN  = r'\('
     75    t_RPAREN  = r'\)'
     76    t_NAME    = r'[a-zA-Z_][a-zA-Z0-9_]*'
     77
     78    def t_NUMBER(self, t):
     79        r'\d+'
     80        try:
     81            t.value = int(t.value)
     82        except ValueError:
     83            print "Integer value too large", t.value
     84            t.value = 0
     85        #print "parsed number %s" % repr(t.value)
     86        return t
     87
     88    t_ignore = " \t"
     89
     90    def t_newline(self, t):
     91        r'\n+'
     92        t.lexer.lineno += t.value.count("\n")
     93    
     94    def t_error(self, t):
     95        print "Illegal character '%s'" % t.value[0]
     96        t.lexer.skip(1)
     97
     98    # Parsing rules
     99
    100    precedence = (
    101        ('left','PLUS','MINUS'),
    102        ('left','TIMES','DIVIDE'),
    103        ('left', 'EXP'),
    104        ('right','UMINUS'),
    105        )
    106
    107    def p_statement_assign(self, p):
    108        'statement : NAME EQUALS expression'
    109        self.names[p[1]] = p[3]
    110
    111    def p_statement_expr(self, p):
    112        'statement : expression'
    113        print p[1]
    114
    115    def p_expression_binop(self, p):
    116        """
    117        expression : expression PLUS expression
    118                  | expression MINUS expression
    119                  | expression TIMES expression
    120                  | expression DIVIDE expression
    121                  | expression EXP expression
    122        """
    123        #print [repr(p[i]) for i in range(0,4)]
    124        if p[2] == '+'  : p[0] = p[1] + p[3]
    125        elif p[2] == '-': p[0] = p[1] - p[3]
    126        elif p[2] == '*': p[0] = p[1] * p[3]
    127        elif p[2] == '/': p[0] = p[1] / p[3]
    128        elif p[2] == '**': p[0] = p[1] ** p[3]
    129
    130    def p_expression_uminus(self, p):
    131        'expression : MINUS expression %prec UMINUS'
    132        p[0] = -p[2]
    133
    134    def p_expression_group(self, p):
    135        'expression : LPAREN expression RPAREN'
    136        p[0] = p[2]
    137
    138    def p_expression_number(self, p):
    139        'expression : NUMBER'
    140        p[0] = p[1]
    141
    142    def p_expression_name(self, p):
    143        'expression : NAME'
    144        try:
    145            p[0] = self.names[p[1]]
    146        except LookupError:
    147            print "Undefined name '%s'" % p[1]
    148            p[0] = 0
    149
    150    def p_error(self, p):
    151        print "Syntax error at '%s'" % p.value
    152
    153if __name__ == '__main__':
    154    calc = Calc()
    155    calc.run()