Skip to content

Instantly share code, notes, and snippets.

@donn
Created April 28, 2018 17:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save donn/aaa35192b6815ed838065f1bee5eb34f to your computer and use it in GitHub Desktop.
Save donn/aaa35192b6815ed838065f1bee5eb34f to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
# Calculator
# Product of a Python Lex-Yacc tutorial.
# Python 3
# --
# This is free and unencumbered software released into the public domain.
# Anyone is free to copy, modify, publish, use, compile, sell, or
# distribute this software, either in source code form or as a compiled
# binary, for any purpose, commercial or non-commercial, and by any
# means.
# In jurisdictions that recognize copyright laws, the author or authors
# of this software dedicate any and all copyright interest in the
# software to the public domain. We make this dedication for the benefit
# of the public at large and to the detriment of our heirs and
# successors. We intend this dedication to be an overt act of
# relinquishment in perpetuity of all present and future rights to this
# software under copyright law.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
# For more information, please refer to <http://unlicense.org/>
import ply.lex as lex
import ply.yacc as yacc
import sys
tokens = [
'INT',
'FLOAT',
'NAME',
'PLUS',
'MINUS',
'DIVIDE',
'MULTIPLY',
'EQUALS',
'MCLEAR'
]
def t_FLOAT(token):
r'[0-9]+\.[0-9]+'
token.value = float(token.value)
return token
def t_INT(token):
r'[0-9]+'
token.value = int(token.value)
return token
t_PLUS = r'\+'
t_MINUS = r'\-'
t_MULTIPLY = r'\*'
t_DIVIDE = r'\/'
t_EQUALS = r'\='
t_MCLEAR = r'\^'
t_NAME = r'[_A-Za-z][_A-Za-z0-9]*'
t_ignore = " \t\r"
def t_error(token):
print("Unexpected character " + token.value)
token.lexer.skip(1)
lexer = lex.lex()
precedence = (
('left', 'PLUS', 'MINUS'),
('left', 'MULTIPLY', 'DIVIDE'),
('left', 'MCLEAR')
)
global_dic = {}
def run(p):
global global_dic
if type(p) == tuple:
if p[0] == '+':
return run(p[1]) + run(p[2])
elif p[0] == '-':
return run(p[1]) - run(p[2])
elif p[0] == '*':
return run(p[1]) * run(p[2])
elif p[0] == '/':
return run(p[1]) / run(p[2])
elif p[0] == '=':
global_dic[p[1]] = run(p[2])
return p[1] + " = " + str(global_dic[p[1]])
elif p[0] == 'var':
if p[1] in global_dic:
return global_dic[p[1]]
else:
return 'Variable ' + p[1] + ' not found.'
else:
if p == "^":
global_dic = {}
return "Memory cleared."
elif type(p) == int or type(p) == float:
return p
return "Execution error."
def p_calc(p):
'''
calc : MCLEAR
| assign
| expression
| empty
'''
print(run(p[1]))
def p_assign(p):
'''
assign : NAME EQUALS expression
'''
p[0] = ('=', p[1], p[3])
def p_expression(p):
'''
expression : expression MULTIPLY expression
| expression DIVIDE expression
| expression PLUS expression
| expression MINUS expression
'''
p[0] = (p[2], p[1], p[3])
def p_expression_int_float(p):
'''
expression : INT
| FLOAT
'''
p[0] = p[1]
def p_expression_var(p):
'''
expression : NAME
'''
p[0] = ('var', p[1])
def p_empty(p):
'''
empty :
'''
p[0] = None
def p_error(p):
print("Syntax error at " + str(p.value))
parser = yacc.yacc()
while True:
try:
s = input('> ')
except EOFError:
print("")
exit(0)
parser.parse(s)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment