Interactive Calculator on iPad using Pythonista
Properties are mathematical functions; structural shapes are delimited with exclamation points.
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
Improvement
This calculator was improved December 2019. Structural Property Calculator — Improved
Python Code
Uses sly to build this calculator.
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)