summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul McGuire <ptmcg@austin.rr.com>2019-08-04 09:52:35 -0500
committerPaul McGuire <ptmcg@austin.rr.com>2019-08-04 09:52:35 -0500
commite0db26b5cbc05df73f7917ffeb8f1d3144e74ec1 (patch)
tree00bf06406ebebb0fac5a212f473e29e6ccbf3a58
parent36aa91c4f603ddb15054b0ff9f5daf5044b1dd31 (diff)
downloadpyparsing-git-e0db26b5cbc05df73f7917ffeb8f1d3144e74ec1.tar.gz
fourFn.py updates - handle leading '+' and '-' unary signs for parenthesized expressions; and real numbers with no leading digit before the decimal
-rw-r--r--examples/fourFn.py15
-rw-r--r--unitTests.py9
2 files changed, 15 insertions, 9 deletions
diff --git a/examples/fourFn.py b/examples/fourFn.py
index 5108c19..e07125f 100644
--- a/examples/fourFn.py
+++ b/examples/fourFn.py
@@ -11,7 +11,7 @@
# Copyright 2003-2019 by Paul McGuire
#
from pyparsing import (Literal, Word, Group, Forward, alphas, alphanums, Regex, ParseException,
- CaselessKeyword, Suppress, delimitedList)
+ CaselessKeyword, Suppress, delimitedList, pyparsing_common as ppc, tokenMap)
import math
import operator
@@ -49,6 +49,8 @@ def BNF():
# fnumber = Combine(Word("+-"+nums, nums) +
# Optional("." + Optional(Word(nums))) +
# Optional(e + Word("+-"+nums, nums)))
+ # or use provided pyparsing_common.number, but convert back to str:
+ # fnumber = ppc.number().addParseAction(lambda t: str(t[0]))
fnumber = Regex(r"[+-]?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?")
ident = Word(alphas, alphanums+"_$")
@@ -62,9 +64,10 @@ def BNF():
expr_list = delimitedList(Group(expr))
# add parse action that replaces the function identifier with a (name, number of args) tuple
fn_call = (ident + lpar - Group(expr_list) + rpar).setParseAction(lambda t: t.insert(0, (t.pop(0), len(t[0]))))
- atom = (minus[...] +
- (fn_call | pi | e | fnumber | ident).setParseAction(push_first)
- | Group(lpar + expr + rpar)).setParseAction(push_unary_minus)
+ atom = (addop[...] +
+ ((fn_call | pi | e | fnumber | ident).setParseAction(push_first)
+ | Group(lpar + expr + rpar))
+ ).setParseAction(push_unary_minus)
# by defining exponentiation as "atom [ ^ factor ]..." instead of "atom [ ^ atom ]...", we get right-to-left
# exponents, instead of left-to-right that is, 2^3^2 = 2^(3^2), not (2^3)^2.
@@ -183,6 +186,8 @@ if __name__ == "__main__":
test("sgn(cos(PI/4))", 1)
test("sgn(cos(PI/2))", 0)
test("sgn(cos(PI*3/4))", -1)
+ test("+(sgn(cos(PI/4)))", 1)
+ test("-(sgn(cos(PI/4)))", -1)
"""
@@ -229,4 +234,6 @@ round(PI^2, 3) = 9.87 [('round', 2), [['PI', '^', '2'], ['3']]] => ['PI', '2', '
sgn(cos(PI/4)) = 1 [('sgn', 1), [[('cos', 1), [['PI', '/', '4']]]]] => ['PI', '4', '/', ('cos', 1), ('sgn', 1)]
sgn(cos(PI/2)) = 0 [('sgn', 1), [[('cos', 1), [['PI', '/', '2']]]]] => ['PI', '2', '/', ('cos', 1), ('sgn', 1)]
sgn(cos(PI*3/4)) = -1 [('sgn', 1), [[('cos', 1), [['PI', '*', '3', '/', '4']]]]] => ['PI', '3', '*', '4', '/', ('cos', 1), ('sgn', 1)]
++(sgn(cos(PI/4))) = 1 ['+', [('sgn', 1), [[('cos', 1), [['PI', '/', '4']]]]]] => ['PI', '4', '/', ('cos', 1), ('sgn', 1)]
+-(sgn(cos(PI/4))) = -1 ['-', [('sgn', 1), [[('cos', 1), [['PI', '/', '4']]]]]] => ['PI', '4', '/', ('cos', 1), ('sgn', 1), 'unary -']
"""
diff --git a/unitTests.py b/unitTests.py
index 4e27776..330afe1 100644
--- a/unitTests.py
+++ b/unitTests.py
@@ -127,8 +127,9 @@ class PyparsingTestInit(ParseTestCase):
class ParseFourFnTest(ParseTestCase):
def runTest(self):
import examples.fourFn as fourFn
+ import math
def test(s, ans):
- fourFn.exprStack = []
+ fourFn.exprStack[:] = []
results = fourFn.BNF().parseString(s)
try:
resultValue = fourFn.evaluate_stack(fourFn.exprStack)
@@ -138,10 +139,6 @@ class ParseFourFnTest(ParseTestCase):
self.assertTrue(resultValue == ans, "failed to evaluate %s, got %f" % (s, resultValue))
print_(s, "->", resultValue)
-
- import math
- e = math.exp(1)
-
test("9", 9)
test("-9", -9)
test("--9", 9)
@@ -183,6 +180,8 @@ class ParseFourFnTest(ParseTestCase):
test("sgn(cos(PI/4))", 1)
test("sgn(cos(PI/2))", 0)
test("sgn(cos(PI*3/4))", -1)
+ test("+(sgn(cos(PI/4)))", 1)
+ test("-(sgn(cos(PI/4)))", -1)
class ParseSQLTest(ParseTestCase):
def runTest(self):