File indexing completed on 2024-04-14 14:56:24

0001 # -*- coding: utf-8 -*-
0002 #     Copyright 2007-8 Jim Bublitz <jbublitz@nwinternet.com>
0003 #
0004 # This program is free software; you can redistribute it and/or modify
0005 # it under the terms of the GNU General Public License as published by
0006 # the Free Software Foundation; either version 2 of the License, or
0007 # (at your option) any later version.
0008 #
0009 # This program is distributed in the hope that it will be useful,
0010 # but WITHOUT ANY WARRANTY; without even the implied warranty of
0011 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012 # GNU General Public License for more details.
0013 #
0014 # You should have received a copy of the GNU General Public License
0015 # along with this program; if not, write to the
0016 # Free Software Foundation, Inc.,
0017 # 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
0018 
0019 import ply.lex as lex
0020 import ply.yacc as yacc
0021 
0022 # Operators (+,-,*,/,%,|,&,~,^,<<,>>, ||, &&, !, <, <=, >, >=, ==, !=)
0023 operators = ('PLUS', 'MINUS', 'SLASH', 'PERCENT', 'VBAR', 'CARET', #'LSHIFT', 'RSHIFT',
0024     'LOR', 'LAND', 'BANG', 'LE', 'GE', 'EQ', 'NE',
0025     # Increment/decrement (++,--)
0026     'PLUSPLUS', 'MINUSMINUS',
0027     # Assignment (=, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=)
0028     'TIMESEQUAL', 'DIVEQUAL', 'MODEQUAL', 'PLUSEQUAL', 'MINUSEQUAL',
0029     'LSHIFTEQUAL',#'RSHIFTEQUAL', 
0030     'ANDEQUAL', 'XOREQUAL', 'OREQUAL','EQUALS', 'ASTERISK', 'AMPERSAND', 'TILDE', 'LT', 'GT'
0031 )
0032 
0033 tokens = operators + (
0034 # Literals (identifier, integer constant, float constant, string constant, char const)
0035 'ID', 'ICONST', 'OCTCONST', 'HEXCONST', 'FCONST', 'SCONST', 'CCONST',
0036 
0037 # Delimeters ( ) [ ] { } , . ; : ::
0038 'LPAREN', 'RPAREN',
0039 'LBRACKET', 'RBRACKET',
0040 'LBRACE', 'RBRACE',
0041 'COMMA', 'PERIOD', 'SEMI', 'COLON', 'COLON2',
0042 
0043 'ARRAYOP', 'FUNCPTR', 'defined' 
0044 )
0045     
0046 # Completely ignored characters
0047 t_ANY_ignore           = ' \t\x0c'
0048 
0049 # Operators
0050 t_PLUS             = r'\+'
0051 t_MINUS            = r'-'
0052 t_ASTERISK         = r'\*'
0053 t_SLASH            = r'/'
0054 t_PERCENT          = r'%'
0055 t_VBAR             = r'\|'
0056 t_AMPERSAND        = r'&'
0057 t_TILDE            = r'~'
0058 t_CARET            = r'\^'
0059 #t_LSHIFT           = r'<<'
0060 #t_RSHIFT           = r'>>'
0061 t_LOR              = r'\|\|'
0062 t_LAND             = r'&&'
0063 t_BANG             = r'!'
0064 t_LT               = r'<'
0065 t_GT               = r'>'
0066 t_LE               = r'<='
0067 t_GE               = r'>='
0068 t_EQ               = r'=='
0069 t_NE               = r'!='
0070 
0071 # Assignment operators
0072 
0073 t_EQUALS           = r'='
0074 t_TIMESEQUAL       = r'\*='
0075 t_DIVEQUAL         = r'/='
0076 t_MODEQUAL         = r'%='
0077 t_PLUSEQUAL        = r'\+='
0078 t_MINUSEQUAL       = r'-='
0079 t_LSHIFTEQUAL      = r'<<='
0080 #t_RSHIFTEQUAL      = r'>>='
0081 t_ANDEQUAL         = r'&='
0082 t_OREQUAL          = r'\|='
0083 t_XOREQUAL         = r'^='
0084 
0085 # Increment/decrement
0086 t_PLUSPLUS         = r'\+\+'
0087 t_MINUSMINUS       = r'--'
0088 
0089 # Delimeters
0090 t_LPAREN           = r'\('
0091 t_RPAREN           = r'\)'
0092 t_LBRACKET         = r'\['
0093 t_RBRACKET         = r'\]'
0094 t_LBRACE           = r'\{'
0095 t_RBRACE           = r'\}'
0096 t_COMMA            = r','
0097 t_PERIOD           = r'\.'
0098 t_SEMI             = r';'
0099 t_COLON            = r':'
0100 t_COLON2           = r'::'
0101 
0102 # Hex Literal
0103 def t_HEXCONST (t):
0104     r'0[x|X][\da-fA-F]+'
0105     t.value = eval (t.value)
0106     return t
0107 
0108 # Octal Literal
0109 t_OCTCONST = r'0[0-7]{3}?'
0110 
0111 # Floating literal
0112 def t_FCONST (t):
0113     r'((\d+)(\.\d+)(e(\+|-)?(\d+))? | (\d+)e(\+|-)?(\d+))([lL]|[fF])?'
0114     t.value = float (t.value)
0115     return t
0116 
0117 # Integer literal
0118 def t_ICONST (t):
0119     r'\d+([uU]|[lL]|[uU][lL]|[lL][uU])?'
0120     t.value = int (t.value)
0121     return t
0122 
0123 # Array operator
0124 t_ARRAYOP = r'[[].*[]]'
0125 
0126 # Function pointer
0127 t_FUNCPTR = r'\(\s*\*'
0128 
0129 # String literal
0130 t_SCONST = r'\"([^\\\n]|(\\.))*?\"'
0131 
0132 # Character constant 'c' or L'c'
0133 t_CCONST = r'(L)?\'([^\\\n]|(\\.))*?\''
0134 # Newlines
0135 
0136 # def t_CONTINUATION (t):
0137 #     r'\\\n'
0138 #     t.lexer.lineno += t.value.count("\n")
0139 
0140 def t_ANY_NEWLINE(t):
0141     r'\n+'
0142     t.lexer.lineno += t.value.count("\n")
0143         
0144 
0145 def t_ID(t):
0146     r'[A-Za-z_][\w_]*'
0147     if t.value == 'defined':
0148         t.type = 'defined'
0149     return t
0150 
0151 
0152 # Comments
0153 def t_ANY_comment(t):
0154     r' /\*(.|\n)*?\*/'
0155     t.lineno += t.value.count('\n')
0156         
0157 t_ANY_ignore_cppcomment = '//[^/].*'
0158     
0159     
0160 def t_ANY_error(t):
0161     print("Illegal character %s" % repr(t.value[0]))
0162     t.lexer.skip(1)
0163 
0164     
0165 exprLexer = lex.lex ()
0166 
0167 class ExpressionParser(object):
0168     precedence = (('left','PLUS','MINUS'), ('left','ASTERISK','SLASH'), ('right','UMINUS'), )
0169     
0170     def __init__ (self):
0171         self.lexer      = exprLexer
0172         self.test       = []       
0173         self.tokens = tokens        
0174         yacc.yacc (module = self, tabmodule = "expressionParserTab")
0175         self._parse = yacc.parse
0176                    
0177         self.values = {}                   
0178         
0179     def parse (self, s, mode = 'calc', values = None):
0180         self.values = values
0181         self.lexer.input (s)
0182         self.mode = mode
0183         self.result = None
0184         self._parse (debug = 0, lexer = self.lexer)
0185         return self.result
0186 
0187     def p_expression_result (self, p):
0188         'expression_result : expression'
0189         p [0] = p [1]
0190         self.result = p [0]
0191 
0192     def p_expression0 (self, p):
0193         """expression : add_expression
0194                      | sub_expression
0195                      | mult_expression
0196                      | div_expression
0197                      | mod_expression
0198                      | unary_expression
0199                      | or_expression
0200                      | and_expression
0201                      | xor_expression
0202                      | bitor_expression
0203                      | bitand_expression
0204                      | lt_expression
0205                      | le_expression
0206                      | eq_expression
0207                      | ge_expression
0208                      | gt_expression
0209                      | lshift_expression
0210                      | rshift_expression
0211                      | ICONST
0212                      | FCONST
0213                      | HEXCONST"""                    
0214         p [0] = p [1]
0215             
0216     def p_expression1 (self, p):
0217         'expression : LPAREN expression RPAREN'
0218         p [0] = p [2]
0219 
0220     def p_expression2 (self, p):
0221         'expression : ID'
0222         if self.mode == 'calc':
0223             p [0] = self.values [p [1]]
0224         elif self.mode == 'def':
0225             p [0] = p [1] in self.values
0226     
0227     def p_unary_expression (self, p):
0228         """unary_expression : sign_expression
0229                            | not_expression
0230                            | bitnot_expression
0231                            | defined_expression"""
0232         p [0] = p [1]
0233 
0234     def p_add_expression (self, p):
0235         'add_expression : expression PLUS expression'
0236         p [0] = p [1] + p [3]
0237         
0238     def p_sub_expression (self, p):
0239         'sub_expression : expression MINUS expression'
0240         p [0] = p [1] - p [3]
0241     
0242     def p_mult_expression (self, p):
0243         'mult_expression : expression ASTERISK expression'
0244         p [0] = p [1] * p [3]
0245     
0246     def p_div_expression (self, p):
0247         'div_expression : expression SLASH expression'
0248         p [0] = p [1] / p [3]
0249     
0250     def p_mod_expression (self, p):
0251         'mod_expression : expression PERCENT expression'
0252         p [0] = p [1] % p [3]
0253     
0254     def p_sign_expression (self, p):
0255         'sign_expression : MINUS expression %prec UMINUS'
0256         p [0] = - p [2]
0257     
0258     def p_or_expression (self, p):
0259         'or_expression : expression LOR expression'
0260         p [0] = p [1] or  p [3]
0261     
0262     def p_and_expression (self, p):
0263         'and_expression : expression LAND expression'
0264         p [0] = p [1] and p [3]
0265     
0266     def p_xor_expression (self, p):
0267         'xor_expression : expression CARET expression'
0268         p [0] = p [1] ^ p [3]
0269     
0270     def p_bitor_expression (self, p):
0271         'bitor_expression : expression VBAR expression'
0272         p [0] = p [1] | p [3]
0273     
0274     def p_bitand_expression (self, p):
0275         'bitand_expression : expression AMPERSAND expression'
0276         p [0] = p [1] & p [3]
0277     
0278     def p_lt_expression (self, p):
0279         'lt_expression : expression LT expression'
0280         p [0] = p [1] < p [3]
0281     
0282     def p_le_expression (self, p):
0283         'le_expression : expression LE expression'
0284         p [0] = p [1] <= p [3]
0285     
0286     def p_eq_expression (self, p):
0287         'eq_expression : expression EQ expression'
0288         p [0] = p [1] == p [3]
0289     
0290     def p_ge_expression (self, p):
0291         'ge_expression : expression GE expression'
0292         p [0] = p [1] >= p [3]
0293     
0294     def p_gt_expression (self, p):
0295         'gt_expression : expression GT expression'
0296         p [0] = p [1] > p [3]
0297     
0298     def p_lshift_expression (self, p):
0299         'lshift_expression : expression GT GT expression'
0300         p [0] = p [1] >> p [4]
0301     
0302     def p_rshift_expression (self, p):
0303         'rshift_expression : expression LT LT expression'
0304         p [0] = p [1] << p [4]
0305 
0306     def p_not_expression (self, p):
0307         'not_expression : BANG expression'
0308         p [0] = not p [2]
0309 
0310     def p_bitnot_expression (self, p):
0311         'bitnot_expression : TILDE expression'
0312         p [0] = ~ p[2]
0313 
0314     def p_defined_expression0 (self, p):
0315         'defined_expression : defined ID'
0316         p [0] = p[2] in self.values
0317 
0318     def p_defined_expression1 (self, p):        
0319         'defined_expression : defined LPAREN ID RPAREN'
0320         p [0] = p[3] in self.values
0321     
0322     def p_error(self, p):
0323         print("Syntax error at '%s'" % p.value)
0324 
0325                   
0326 if __name__ == '__main__':                  
0327     text = '2 +\
0328      2'
0329     
0330     parser = ExpressionParser ()
0331 #    exprLexer.input (text)
0332 #    print parser.parse (text, None)
0333     values = {'x': 2.0, 'macro': None}
0334     while 1:
0335         try:
0336             s = raw_input('calc > ')
0337         except EOFError:
0338             break
0339         if not s: continue
0340         print(parser.parse(s, values))