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 (3940B)


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