Full calculator functions with named variables — and AISC structural properties!
# General use as a numerical calculator
calc > a = 3
calc > b = 4
calc > c=(a**2+b**2)**0.5 # white space does not matter
calc > a
3.0
calc > b
4.0
calc > c
5.0
calc > 5 + (30 * 3 ** 2) - 23/46
274.5
# Use with structural properties
# W8x31
calc > ddet(!w8x31!)
8.0
calc > tf(!w8x31!)
0.435
calc > ix(!w8x31!)
110.0
calc > sy(!w8x31!)
9.27
# W24x62
calc > twdet(!w24x62!)
0.4375
calc > tw(!w24x62!)
0.43
# Single angle shapes
calc > sy(!L3x3x3/8!)
0.825
calc > sy(!L3-1/2x3-1/2x3/8!)
1.15
calc > rx(!L3-1/2x3-1/2x3/8!)
1.07
calc > t(!L3-1/2x3-1/2x3/8!)
0.375
# Double angle shapes
calc > rx(!2L3-1/2x3-1/2x3/8!)
1.07
calc > ry(!2L3-1/2x3-1/2x3/8!)
1.47
# Channel shape
calc > bfdet(!c10x15.3!)
2.625
calc > bf(!c10x15.3!)
2.6
# Area of a flange
calc > bf(!w12x40!) * tf(!w12x40!)
4.12515
calc > bf(!w12x40!) * tf(!w12x40!) * 2
8.2503
# Named variables
calc > A_flange = bf(!w12x40!) * tf(!w12x40!)
calc > A_both_flanges = 2 * A_flange
calc > A_both_flanges
8.2503
calc > A_web = a(!w12x40!) - A_both_flanges
calc > A_web
3.4497
# Assign shape to a variable name
calc > my_column = !w12x40!
calc > tf(my_column)
0.515
Thanks to David Beazley. Click here to go to https://github.com/dabeaz/sly.
# calc.py
# —————————————————————————–
from sly import Lexer, Parser
import AISCV1415Shapesdefsonly as V1415
import clipboard
a = V1415.getallShapes15()
class CalcLexer(Lexer):
tokens = { EXPA, EXPC, NAME, NUMBER,
PLUS, TIMES, MINUS, DIVIDE,
ASSIGN,
LPAREN, RPAREN,
SHAPE}
ignore = ‘ \t’
# Tokens
NAME = r'[a-zA-Z_][a-zA-Z0-9_]*’
NUMBER = r'(?=\d|\.\d)\d*(\.\d*)?’
SHAPE = r’![a-zA-Z2_\/\-][a-zA-Z0-9_\/\-\.]*!’
# ddet(!w8x31!)
# Special symbols
PLUS = r’\+’
MINUS = r’-‘
# Q = r’\”
# ATFUN = r’\$’
EXPA = r’\*\*’
EXPC = r’\^’
TIMES = r’\*’
DIVIDE = r’/’
ASSIGN = r’=’
# LBRACK = r’\[‘
# RBRACK = r’\]’
LPAREN = r’\(‘
RPAREN = r’\)’
# Ignored pattern
ignore_newline = r’\n+’
# Extra action for newlines
def ignore_newline(self, t):
self.lineno += t.value.count(‘\n’)
def error(self, t):
print("Illegal character ‘%s’" % t.value[0])
self.index += 1
class CalcParser(Parser):
tokens = CalcLexer.tokens
precedence = (
(‘left’, PLUS, MINUS),
(‘left’, TIMES, DIVIDE),
(‘right’, EXPA, EXPC),
(‘right’, UMINUS),
)
def __init__(self):
self.names = { }
@_(‘NAME ASSIGN expr’)
def statement(self, p):
self.names[p.NAME] = p.expr
@_(‘NAME ASSIGN SHAPE’)
def statement(self, p):
shape = p.SHAPE.strip("!").upper()
self.names[p.NAME] = a[shape]
@_(‘expr’)
def statement(self, p):
print(p.expr)
@_(‘NAME LPAREN SHAPE RPAREN’)
def expr(self, p):
shape = p.SHAPE.strip("!").upper()
try:
result = getattr(a[shape], p.NAME.upper())
except:
result = ‘function failed’
return result
@_(‘NAME LPAREN expr RPAREN’)
def expr(self, p):
#shape = p.SHAPE.strip("!").upper()
try:
result = getattr(p.expr, p.NAME.upper())
except:
result = ‘function failed’
return result
@_(‘expr EXPA expr’)
def expr(self, p):
return pow(p.expr0, p.expr1)
@_(‘expr EXPC expr’)
def expr(self, p):
return pow(p.expr0, p.expr1)
@_(‘expr PLUS expr’)
def expr(self, p):
return p.expr0 + p.expr1
@_(‘expr MINUS expr’)
def expr(self, p):
return p.expr0 – p.expr1
@_(‘expr TIMES expr’)
def expr(self, p):
return p.expr0 * p.expr1
@_(‘expr DIVIDE expr’)
def expr(self, p):
return p.expr0 / p.expr1
@_(‘MINUS expr %prec UMINUS’)
def expr(self, p):
return -p.expr
@_(‘LPAREN expr RPAREN’)
def expr(self, p):
return p.expr
@_(‘NUMBER’)
def expr(self, p):
return float(p.NUMBER)
@_(‘NAME’)
def expr(self, p):
try:
return self.names[p.NAME]
except LookupError:
print(f’Undefined name {p.NAME!r}’)
return 0
if __name__ == ‘__main__’:
lexer = CalcLexer()
parser = CalcParser()
clipboard.set(‘ddet(!w8x31!)’)
while True:
try:
text = input(‘calc > ‘)
except EOFError:
break
if text:
parser.parse(lexer.tokenize(text))
clipboard.set(text)