Skip to main content
Code Review

Return to Answer

Added easier way to exit, and differentiating between a constant and a function with no parameters
Source Link
holroy
  • 11.8k
  • 1
  • 27
  • 59

Here is an alternate version forLetting the variable numbers of operand sideother answers handle other aspects of the questionreview, this answer addresses two issues:

  • A simpler way to exit – Just call exit() or whatever when you encounter the token quit. If you don't want to exit() you could call a specific exception, i.e. QuitException, and catch this at the proper level
  • Variable number of operands – If first using slice operators to pick out the correct number of operands, and remove them from the stack, we can use unpacking of argument lists to call the operator with the list of operands. Rather neat, actually!

Here is the code changes:

from operator import add, sub, mul
import math
def foo():
 return 100.0
TOKENS = {
 '+' : (2, add),
 '-' : (2, sub),
 '*' : (2, mul),
 '/' : (2, lambda a, b: a / b),
 '^' : (2, lambda a, b: a ** b),
 '**' : (2, lambda a, b: a ** b),
 '%' : (2, lambda a, b: a % b),
 'mod' : (2, lambda a, b: a % b),
 '//' : (2, lambda a, b: a // b),
 'sqrt': (1, math.sqrt),
 'foo' : (0, foo),  # function with no parameters
 'pi' : (0-1, math.pi), # a constant
 }
 
 # Keep the else-block, but replace the if-block with:
 if token == 'quit':
 exit()  # Or possibly: raise QuitException :-)
 if token in TOKENS:
 operands_count, operator = TOKENS[token]
 
 if operands_count >>= 0:
 operands = stack[:operands_count]
 del stack[:operands_count]
 answer = operator(*operands)
 else:
 answer = operator
 stack.append(answer)

Using this I was able to parse '4 5 + 1 + 10 * 2 ** sqrt pi * 'foo quit 2 *' and got the expected 31431415.1592653599265359 as my final output. Tested '20 3 mod ' equals 2 also, just to verify that operand order had not changed.

Here is an alternate version for the variable numbers of operand side of the question:

from operator import add, sub, mul
import math
TOKENS = {
 '+' : (2, add),
 '-' : (2, sub),
 '*' : (2, mul),
 '/' : (2, lambda a, b: a / b),
 '^' : (2, lambda a, b: a ** b),
 '**' : (2, lambda a, b: a ** b),
 '%' : (2, lambda a, b: a % b),
 'mod' : (2, lambda a, b: a % b),
 '//' : (2, lambda a, b: a // b),
 'sqrt': (1, math.sqrt),
 'pi' : (0, math.pi),
 }
 
 # Keep the else-block, but replace the if-block with:
 if token in TOKENS:
 operands_count, operator = TOKENS[token]
 
 if operands_count > 0:
 operands = stack[:operands_count]
 del stack[:operands_count]
 answer = operator(*operands)
 else:
 answer = operator
 stack.append(answer)

Using this I was able to parse '4 5 + 1 + 10 * 2 ** sqrt pi * ' and got the expected 314.159265359 as my final output. Tested '20 3 mod ' equals 2 also, just to verify that operand order had not changed.

Letting the other answers handle other aspects of the review, this answer addresses two issues:

  • A simpler way to exit – Just call exit() or whatever when you encounter the token quit. If you don't want to exit() you could call a specific exception, i.e. QuitException, and catch this at the proper level
  • Variable number of operands – If first using slice operators to pick out the correct number of operands, and remove them from the stack, we can use unpacking of argument lists to call the operator with the list of operands. Rather neat, actually!

Here is the code changes:

from operator import add, sub, mul
import math
def foo():
 return 100.0
TOKENS = {
 '+' : (2, add),
 '-' : (2, sub),
 '*' : (2, mul),
 '/' : (2, lambda a, b: a / b),
 '^' : (2, lambda a, b: a ** b),
 '**' : (2, lambda a, b: a ** b),
 '%' : (2, lambda a, b: a % b),
 'mod' : (2, lambda a, b: a % b),
 '//' : (2, lambda a, b: a // b),
 'sqrt': (1, math.sqrt),
 'foo' : (0, foo),  # function with no parameters
 'pi' : (-1, math.pi), # a constant
 }
 
 # Keep the else-block, but replace the if-block with:
 if token == 'quit':
 exit()  # Or possibly: raise QuitException :-)
 if token in TOKENS:
 operands_count, operator = TOKENS[token]
 
 if operands_count >= 0:
 operands = stack[:operands_count]
 del stack[:operands_count]
 answer = operator(*operands)
 else:
 answer = operator
 stack.append(answer)

Using this I was able to parse '4 5 + 1 + 10 * 2 ** sqrt pi * foo quit 2 *' and got the expected 31415.9265359 as my final output. Tested '20 3 mod ' equals 2 also, just to verify that operand order had not changed.

Source Link
holroy
  • 11.8k
  • 1
  • 27
  • 59

Here is an alternate version for the variable numbers of operand side of the question:

from operator import add, sub, mul
import math
TOKENS = {
 '+' : (2, add),
 '-' : (2, sub),
 '*' : (2, mul),
 '/' : (2, lambda a, b: a / b),
 '^' : (2, lambda a, b: a ** b),
 '**' : (2, lambda a, b: a ** b),
 '%' : (2, lambda a, b: a % b),
 'mod' : (2, lambda a, b: a % b),
 '//' : (2, lambda a, b: a // b),
 'sqrt': (1, math.sqrt),
 'pi' : (0, math.pi),
 }
 
 # Keep the else-block, but replace the if-block with:
 if token in TOKENS:
 operands_count, operator = TOKENS[token]
 
 if operands_count > 0:
 operands = stack[:operands_count]
 del stack[:operands_count]
 answer = operator(*operands)
 else:
 answer = operator
 stack.append(answer)

Using this I was able to parse '4 5 + 1 + 10 * 2 ** sqrt pi * ' and got the expected 314.159265359 as my final output. Tested '20 3 mod ' equals 2 also, just to verify that operand order had not changed.

Have I mentioned that I like the slice operators, and the *operands in combination with the simplicity of adding function, constants and so on into a list? If not, considered it done!

lang-py

AltStyle によって変換されたページ (->オリジナル) /