summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorDavid Beazley <dave@dabeaz.com>2006-11-21 15:09:46 +0000
committerDavid Beazley <dave@dabeaz.com>2006-11-21 15:09:46 +0000
commit80c8c2d0a6e63745ff099b33ad2848b6fb17285a (patch)
tree36d223fc55a5649dc85a4f8a3fa9d17cb130c6c3 /test
downloadply-80c8c2d0a6e63745ff099b33ad2848b6fb17285a.tar.gz
initial checkin
Diffstat (limited to 'test')
-rw-r--r--test/README11
-rw-r--r--test/calclex.py49
-rwxr-xr-xtest/cleanup.sh4
-rw-r--r--test/lex_doc1.exp1
-rw-r--r--test/lex_doc1.py30
-rw-r--r--test/lex_dup1.exp2
-rw-r--r--test/lex_dup1.py29
-rw-r--r--test/lex_dup2.exp2
-rw-r--r--test/lex_dup2.py33
-rw-r--r--test/lex_dup3.exp2
-rw-r--r--test/lex_dup3.py31
-rw-r--r--test/lex_empty.exp1
-rw-r--r--test/lex_empty.py20
-rw-r--r--test/lex_error1.exp1
-rw-r--r--test/lex_error1.py24
-rw-r--r--test/lex_error2.exp1
-rw-r--r--test/lex_error2.py26
-rw-r--r--test/lex_error3.exp2
-rw-r--r--test/lex_error3.py27
-rw-r--r--test/lex_error4.exp2
-rw-r--r--test/lex_error4.py27
-rw-r--r--test/lex_hedit.exp3
-rw-r--r--test/lex_hedit.py47
-rw-r--r--test/lex_ignore.exp7
-rw-r--r--test/lex_ignore.py31
-rw-r--r--test/lex_nowarn.exp0
-rw-r--r--test/lex_nowarn.py30
-rw-r--r--test/lex_re1.exp7
-rw-r--r--test/lex_re1.py27
-rw-r--r--test/lex_re2.exp7
-rw-r--r--test/lex_re2.py27
-rw-r--r--test/lex_re3.exp8
-rw-r--r--test/lex_re3.py29
-rw-r--r--test/lex_rule1.exp2
-rw-r--r--test/lex_rule1.py27
-rw-r--r--test/lex_state1.exp7
-rw-r--r--test/lex_state1.py40
-rw-r--r--test/lex_state2.exp8
-rw-r--r--test/lex_state2.py40
-rw-r--r--test/lex_state3.exp8
-rw-r--r--test/lex_state3.py42
-rw-r--r--test/lex_state4.exp7
-rw-r--r--test/lex_state4.py41
-rw-r--r--test/lex_state5.exp7
-rw-r--r--test/lex_state5.py42
-rw-r--r--test/lex_state_noerror.exp1
-rw-r--r--test/lex_state_noerror.py41
-rw-r--r--test/lex_state_norule.exp7
-rw-r--r--test/lex_state_norule.py42
-rw-r--r--test/lex_state_try.exp7
-rw-r--r--test/lex_state_try.py48
-rw-r--r--test/lex_token1.exp1
-rw-r--r--test/lex_token1.py21
-rw-r--r--test/lex_token2.exp1
-rw-r--r--test/lex_token2.py23
-rw-r--r--test/lex_token3.exp2
-rw-r--r--test/lex_token3.py27
-rw-r--r--test/lex_token4.exp2
-rw-r--r--test/lex_token4.py28
-rw-r--r--test/lex_token5.exp1
-rw-r--r--test/lex_token5.py33
-rw-r--r--test/rununit.py62
-rwxr-xr-xtest/testlex.py57
-rw-r--r--test/testyacc.py58
-rw-r--r--test/yacc_badargs.exp3
-rw-r--r--test/yacc_badargs.py68
-rw-r--r--test/yacc_badprec.exp1
-rw-r--r--test/yacc_badprec.py65
-rw-r--r--test/yacc_badprec2.exp3
-rw-r--r--test/yacc_badprec2.py69
-rw-r--r--test/yacc_badrule.exp5
-rw-r--r--test/yacc_badrule.py69
-rw-r--r--test/yacc_badtok.exp1
-rw-r--r--test/yacc_badtok.py70
-rw-r--r--test/yacc_dup.exp4
-rw-r--r--test/yacc_dup.py69
-rw-r--r--test/yacc_error1.exp1
-rw-r--r--test/yacc_error1.py69
-rw-r--r--test/yacc_error2.exp1
-rw-r--r--test/yacc_error2.py69
-rw-r--r--test/yacc_error3.exp1
-rw-r--r--test/yacc_error3.py68
-rw-r--r--test/yacc_inf.exp5
-rw-r--r--test/yacc_inf.py57
-rw-r--r--test/yacc_missing1.exp2
-rw-r--r--test/yacc_missing1.py69
-rw-r--r--test/yacc_nodoc.exp2
-rw-r--r--test/yacc_nodoc.py68
-rw-r--r--test/yacc_noerror.exp2
-rw-r--r--test/yacc_noerror.py67
-rw-r--r--test/yacc_nop.exp2
-rw-r--r--test/yacc_nop.py69
-rw-r--r--test/yacc_notfunc.exp4
-rw-r--r--test/yacc_notfunc.py67
-rw-r--r--test/yacc_notok.exp1
-rw-r--r--test/yacc_notok.py68
-rw-r--r--test/yacc_rr.exp2
-rw-r--r--test/yacc_rr.py73
-rw-r--r--test/yacc_simple.exp1
-rw-r--r--test/yacc_simple.py69
-rw-r--r--test/yacc_sr.exp2
-rw-r--r--test/yacc_sr.py64
-rw-r--r--test/yacc_term1.exp2
-rw-r--r--test/yacc_term1.py69
-rw-r--r--test/yacc_unused.exp4
-rw-r--r--test/yacc_unused.py78
-rw-r--r--test/yacc_uprec.exp2
-rw-r--r--test/yacc_uprec.py64
108 files changed, 2830 insertions, 0 deletions
diff --git a/test/README b/test/README
new file mode 100644
index 0000000..aac12b0
--- /dev/null
+++ b/test/README
@@ -0,0 +1,11 @@
+This directory mostly contains tests for various types of error
+conditions. To run:
+
+ $ python testlex.py .
+ $ python testyacc.py .
+
+The tests can also be run using the Python unittest module.
+
+ $ python rununit.py
+
+The script 'cleanup.sh' cleans up this directory to its original state.
diff --git a/test/calclex.py b/test/calclex.py
new file mode 100644
index 0000000..2550734
--- /dev/null
+++ b/test/calclex.py
@@ -0,0 +1,49 @@
+# -----------------------------------------------------------------------------
+# calclex.py
+# -----------------------------------------------------------------------------
+import sys
+
+sys.path.append("..")
+import ply.lex as lex
+
+tokens = (
+ 'NAME','NUMBER',
+ 'PLUS','MINUS','TIMES','DIVIDE','EQUALS',
+ 'LPAREN','RPAREN',
+ )
+
+# Tokens
+
+t_PLUS = r'\+'
+t_MINUS = r'-'
+t_TIMES = r'\*'
+t_DIVIDE = r'/'
+t_EQUALS = r'='
+t_LPAREN = r'\('
+t_RPAREN = r'\)'
+t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*'
+
+def t_NUMBER(t):
+ r'\d+'
+ try:
+ t.value = int(t.value)
+ except ValueError:
+ print "Integer value too large", t.value
+ t.value = 0
+ return t
+
+t_ignore = " \t"
+
+def t_newline(t):
+ r'\n+'
+ t.lineno += t.value.count("\n")
+
+def t_error(t):
+ print "Illegal character '%s'" % t.value[0]
+ t.lexer.skip(1)
+
+# Build the lexer
+lex.lex()
+
+
+
diff --git a/test/cleanup.sh b/test/cleanup.sh
new file mode 100755
index 0000000..d7d99b6
--- /dev/null
+++ b/test/cleanup.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+rm -f *~ *.pyc *.dif *.out
+
diff --git a/test/lex_doc1.exp b/test/lex_doc1.exp
new file mode 100644
index 0000000..5b63c1e
--- /dev/null
+++ b/test/lex_doc1.exp
@@ -0,0 +1 @@
+./lex_doc1.py:18: No regular expression defined for rule 't_NUMBER'
diff --git a/test/lex_doc1.py b/test/lex_doc1.py
new file mode 100644
index 0000000..3951b5c
--- /dev/null
+++ b/test/lex_doc1.py
@@ -0,0 +1,30 @@
+# lex_token.py
+#
+# Missing documentation string
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = [
+ "PLUS",
+ "MINUS",
+ "NUMBER",
+ ]
+
+t_PLUS = r'\+'
+t_MINUS = r'-'
+def t_NUMBER(t):
+ pass
+
+def t_error(t):
+ pass
+
+
+import sys
+sys.tracebacklimit = 0
+
+lex.lex()
+
+
diff --git a/test/lex_dup1.exp b/test/lex_dup1.exp
new file mode 100644
index 0000000..2098a40
--- /dev/null
+++ b/test/lex_dup1.exp
@@ -0,0 +1,2 @@
+./lex_dup1.py:20: Rule t_NUMBER redefined. Previously defined on line 18
+SyntaxError: lex: Unable to build lexer.
diff --git a/test/lex_dup1.py b/test/lex_dup1.py
new file mode 100644
index 0000000..68f8092
--- /dev/null
+++ b/test/lex_dup1.py
@@ -0,0 +1,29 @@
+# lex_token.py
+#
+# Duplicated rule specifiers
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = [
+ "PLUS",
+ "MINUS",
+ "NUMBER",
+ ]
+
+t_PLUS = r'\+'
+t_MINUS = r'-'
+t_NUMBER = r'\d+'
+
+t_NUMBER = r'\d+'
+
+def t_error(t):
+ pass
+
+sys.tracebacklimit = 0
+
+lex.lex()
+
+
diff --git a/test/lex_dup2.exp b/test/lex_dup2.exp
new file mode 100644
index 0000000..d327cfe
--- /dev/null
+++ b/test/lex_dup2.exp
@@ -0,0 +1,2 @@
+./lex_dup2.py:22: Rule t_NUMBER redefined. Previously defined on line 18
+SyntaxError: lex: Unable to build lexer.
diff --git a/test/lex_dup2.py b/test/lex_dup2.py
new file mode 100644
index 0000000..f4d346e
--- /dev/null
+++ b/test/lex_dup2.py
@@ -0,0 +1,33 @@
+# lex_token.py
+#
+# Duplicated rule specifiers
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = [
+ "PLUS",
+ "MINUS",
+ "NUMBER",
+ ]
+
+t_PLUS = r'\+'
+t_MINUS = r'-'
+def t_NUMBER(t):
+ r'\d+'
+ pass
+
+def t_NUMBER(t):
+ r'\d+'
+ pass
+
+def t_error(t):
+ pass
+
+sys.tracebacklimit = 0
+
+lex.lex()
+
+
diff --git a/test/lex_dup3.exp b/test/lex_dup3.exp
new file mode 100644
index 0000000..ec0680c
--- /dev/null
+++ b/test/lex_dup3.exp
@@ -0,0 +1,2 @@
+./lex_dup3.py:20: Rule t_NUMBER redefined. Previously defined on line 18
+SyntaxError: lex: Unable to build lexer.
diff --git a/test/lex_dup3.py b/test/lex_dup3.py
new file mode 100644
index 0000000..e17b520
--- /dev/null
+++ b/test/lex_dup3.py
@@ -0,0 +1,31 @@
+# lex_token.py
+#
+# Duplicated rule specifiers
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = [
+ "PLUS",
+ "MINUS",
+ "NUMBER",
+ ]
+
+t_PLUS = r'\+'
+t_MINUS = r'-'
+t_NUMBER = r'\d+'
+
+def t_NUMBER(t):
+ r'\d+'
+ pass
+
+def t_error(t):
+ pass
+
+sys.tracebacklimit = 0
+
+lex.lex()
+
+
diff --git a/test/lex_empty.exp b/test/lex_empty.exp
new file mode 100644
index 0000000..af38602
--- /dev/null
+++ b/test/lex_empty.exp
@@ -0,0 +1 @@
+SyntaxError: lex: no rules of the form t_rulename are defined.
diff --git a/test/lex_empty.py b/test/lex_empty.py
new file mode 100644
index 0000000..96625f7
--- /dev/null
+++ b/test/lex_empty.py
@@ -0,0 +1,20 @@
+# lex_token.py
+#
+# No rules defined
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = [
+ "PLUS",
+ "MINUS",
+ "NUMBER",
+ ]
+
+sys.tracebacklimit = 0
+
+lex.lex()
+
+
diff --git a/test/lex_error1.exp b/test/lex_error1.exp
new file mode 100644
index 0000000..baa19e5
--- /dev/null
+++ b/test/lex_error1.exp
@@ -0,0 +1 @@
+lex: Warning. no t_error rule is defined.
diff --git a/test/lex_error1.py b/test/lex_error1.py
new file mode 100644
index 0000000..a99d9be
--- /dev/null
+++ b/test/lex_error1.py
@@ -0,0 +1,24 @@
+# lex_token.py
+#
+# Missing t_error() rule
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = [
+ "PLUS",
+ "MINUS",
+ "NUMBER",
+ ]
+
+t_PLUS = r'\+'
+t_MINUS = r'-'
+t_NUMBER = r'\d+'
+
+sys.tracebacklimit = 0
+
+lex.lex()
+
+
diff --git a/test/lex_error2.exp b/test/lex_error2.exp
new file mode 100644
index 0000000..fb1b55c
--- /dev/null
+++ b/test/lex_error2.exp
@@ -0,0 +1 @@
+SyntaxError: lex: Rule 't_error' must be defined as a function
diff --git a/test/lex_error2.py b/test/lex_error2.py
new file mode 100644
index 0000000..a59c8d4
--- /dev/null
+++ b/test/lex_error2.py
@@ -0,0 +1,26 @@
+# lex_token.py
+#
+# t_error defined, but not function
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = [
+ "PLUS",
+ "MINUS",
+ "NUMBER",
+ ]
+
+t_PLUS = r'\+'
+t_MINUS = r'-'
+t_NUMBER = r'\d+'
+
+t_error = "foo"
+
+sys.tracebacklimit = 0
+
+lex.lex()
+
+
diff --git a/test/lex_error3.exp b/test/lex_error3.exp
new file mode 100644
index 0000000..1b482bf
--- /dev/null
+++ b/test/lex_error3.exp
@@ -0,0 +1,2 @@
+./lex_error3.py:20: Rule 't_error' requires an argument.
+SyntaxError: lex: Unable to build lexer.
diff --git a/test/lex_error3.py b/test/lex_error3.py
new file mode 100644
index 0000000..584600f
--- /dev/null
+++ b/test/lex_error3.py
@@ -0,0 +1,27 @@
+# lex_token.py
+#
+# t_error defined as function, but with wrong # args
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = [
+ "PLUS",
+ "MINUS",
+ "NUMBER",
+ ]
+
+t_PLUS = r'\+'
+t_MINUS = r'-'
+t_NUMBER = r'\d+'
+
+def t_error():
+ pass
+
+sys.tracebacklimit = 0
+
+lex.lex()
+
+
diff --git a/test/lex_error4.exp b/test/lex_error4.exp
new file mode 100644
index 0000000..98505a2
--- /dev/null
+++ b/test/lex_error4.exp
@@ -0,0 +1,2 @@
+./lex_error4.py:20: Rule 't_error' has too many arguments.
+SyntaxError: lex: Unable to build lexer.
diff --git a/test/lex_error4.py b/test/lex_error4.py
new file mode 100644
index 0000000..d05de74
--- /dev/null
+++ b/test/lex_error4.py
@@ -0,0 +1,27 @@
+# lex_token.py
+#
+# t_error defined as function, but too many args
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = [
+ "PLUS",
+ "MINUS",
+ "NUMBER",
+ ]
+
+t_PLUS = r'\+'
+t_MINUS = r'-'
+t_NUMBER = r'\d+'
+
+def t_error(t,s):
+ pass
+
+sys.tracebacklimit = 0
+
+lex.lex()
+
+
diff --git a/test/lex_hedit.exp b/test/lex_hedit.exp
new file mode 100644
index 0000000..7b27dcb
--- /dev/null
+++ b/test/lex_hedit.exp
@@ -0,0 +1,3 @@
+(H_EDIT_DESCRIPTOR,'abc',1,0)
+(H_EDIT_DESCRIPTOR,'abcdefghij',1,6)
+(H_EDIT_DESCRIPTOR,'xy',1,20)
diff --git a/test/lex_hedit.py b/test/lex_hedit.py
new file mode 100644
index 0000000..0f87423
--- /dev/null
+++ b/test/lex_hedit.py
@@ -0,0 +1,47 @@
+# -----------------------------------------------------------------------------
+# hedit.py
+#
+# Paring of Fortran H Edit descriptions (Contributed by Pearu Peterson)
+#
+# These tokens can't be easily tokenized because they are of the following
+# form:
+#
+# nHc1...cn
+#
+# where n is a positive integer and c1 ... cn are characters.
+#
+# This example shows how to modify the state of the lexer to parse
+# such tokens
+# -----------------------------------------------------------------------------
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = (
+ 'H_EDIT_DESCRIPTOR',
+ )
+
+# Tokens
+t_ignore = " \t\n"
+
+def t_H_EDIT_DESCRIPTOR(t):
+ r"\d+H.*" # This grabs all of the remaining text
+ i = t.value.index('H')
+ n = eval(t.value[:i])
+
+ # Adjust the tokenizing position
+ t.lexer.lexpos -= len(t.value) - (i+1+n)
+ t.value = t.value[i+1:i+1+n]
+ return t
+
+def t_error(t):
+ print "Illegal character '%s'" % t.value[0]
+ t.lexer.skip(1)
+
+# Build the lexer
+lex.lex()
+lex.runmain(data="3Habc 10Habcdefghij 2Hxy")
+
+
+
diff --git a/test/lex_ignore.exp b/test/lex_ignore.exp
new file mode 100644
index 0000000..85e2961
--- /dev/null
+++ b/test/lex_ignore.exp
@@ -0,0 +1,7 @@
+./lex_ignore.py:20: Rule 't_ignore' must be defined as a string.
+Traceback (most recent call last):
+ File "./lex_ignore.py", line 29, in ?
+ lex.lex()
+ File "../ply/lex.py", line 758, in lex
+ raise SyntaxError,"lex: Unable to build lexer."
+SyntaxError: lex: Unable to build lexer.
diff --git a/test/lex_ignore.py b/test/lex_ignore.py
new file mode 100644
index 0000000..94b0266
--- /dev/null
+++ b/test/lex_ignore.py
@@ -0,0 +1,31 @@
+# lex_token.py
+#
+# Improperly specific ignore declaration
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = [
+ "PLUS",
+ "MINUS",
+ "NUMBER",
+ ]
+
+t_PLUS = r'\+'
+t_MINUS = r'-'
+t_NUMBER = r'\d+'
+
+def t_ignore(t):
+ ' \t'
+ pass
+
+def t_error(t):
+ pass
+
+import sys
+
+lex.lex()
+
+
diff --git a/test/lex_nowarn.exp b/test/lex_nowarn.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/lex_nowarn.exp
diff --git a/test/lex_nowarn.py b/test/lex_nowarn.py
new file mode 100644
index 0000000..d60d31c
--- /dev/null
+++ b/test/lex_nowarn.py
@@ -0,0 +1,30 @@
+# lex_token.py
+#
+# Missing t_error() rule
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = [
+ "PLUS",
+ "MINUS",
+ "NUMBER",
+ "NUMBER",
+ ]
+
+states = (('foo','exclusive'),)
+
+t_ignore = ' \t'
+t_PLUS = r'\+'
+t_MINUS = r'-'
+t_NUMBER = r'\d+'
+
+t_foo_NUMBER = r'\d+'
+
+sys.tracebacklimit = 0
+
+lex.lex(nowarn=1)
+
+
diff --git a/test/lex_re1.exp b/test/lex_re1.exp
new file mode 100644
index 0000000..b9e621c
--- /dev/null
+++ b/test/lex_re1.exp
@@ -0,0 +1,7 @@
+lex: Invalid regular expression for rule 't_NUMBER'. unbalanced parenthesis
+Traceback (most recent call last):
+ File "./lex_re1.py", line 25, in ?
+ lex.lex()
+ File "../ply/lex.py", line 758, in lex
+ raise SyntaxError,"lex: Unable to build lexer."
+SyntaxError: lex: Unable to build lexer.
diff --git a/test/lex_re1.py b/test/lex_re1.py
new file mode 100644
index 0000000..9e544fe
--- /dev/null
+++ b/test/lex_re1.py
@@ -0,0 +1,27 @@
+# lex_token.py
+#
+# Bad regular expression in a string
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = [
+ "PLUS",
+ "MINUS",
+ "NUMBER",
+ ]
+
+t_PLUS = r'\+'
+t_MINUS = r'-'
+t_NUMBER = r'(\d+'
+
+def t_error(t):
+ pass
+
+import sys
+
+lex.lex()
+
+
diff --git a/test/lex_re2.exp b/test/lex_re2.exp
new file mode 100644
index 0000000..7ba89b4
--- /dev/null
+++ b/test/lex_re2.exp
@@ -0,0 +1,7 @@
+lex: Regular expression for rule 't_PLUS' matches empty string.
+Traceback (most recent call last):
+ File "./lex_re2.py", line 25, in ?
+ lex.lex()
+ File "../ply/lex.py", line 758, in lex
+ raise SyntaxError,"lex: Unable to build lexer."
+SyntaxError: lex: Unable to build lexer.
diff --git a/test/lex_re2.py b/test/lex_re2.py
new file mode 100644
index 0000000..522b415
--- /dev/null
+++ b/test/lex_re2.py
@@ -0,0 +1,27 @@
+# lex_token.py
+#
+# Regular expression rule matches empty string
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = [
+ "PLUS",
+ "MINUS",
+ "NUMBER",
+ ]
+
+t_PLUS = r'\+?'
+t_MINUS = r'-'
+t_NUMBER = r'(\d+)'
+
+def t_error(t):
+ pass
+
+import sys
+
+lex.lex()
+
+
diff --git a/test/lex_re3.exp b/test/lex_re3.exp
new file mode 100644
index 0000000..7cdcae4
--- /dev/null
+++ b/test/lex_re3.exp
@@ -0,0 +1,8 @@
+lex: Invalid regular expression for rule 't_POUND'. unbalanced parenthesis
+lex: Make sure '#' in rule 't_POUND' is escaped with '\#'.
+Traceback (most recent call last):
+ File "./lex_re3.py", line 27, in ?
+ lex.lex()
+ File "../ply/lex.py", line 758, in lex
+ raise SyntaxError,"lex: Unable to build lexer."
+SyntaxError: lex: Unable to build lexer.
diff --git a/test/lex_re3.py b/test/lex_re3.py
new file mode 100644
index 0000000..099e156
--- /dev/null
+++ b/test/lex_re3.py
@@ -0,0 +1,29 @@
+# lex_token.py
+#
+# Regular expression rule matches empty string
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = [
+ "PLUS",
+ "MINUS",
+ "NUMBER",
+ "POUND",
+ ]
+
+t_PLUS = r'\+'
+t_MINUS = r'-'
+t_NUMBER = r'(\d+)'
+t_POUND = r'#'
+
+def t_error(t):
+ pass
+
+import sys
+
+lex.lex()
+
+
diff --git a/test/lex_rule1.exp b/test/lex_rule1.exp
new file mode 100644
index 0000000..0c23ca2
--- /dev/null
+++ b/test/lex_rule1.exp
@@ -0,0 +1,2 @@
+lex: t_NUMBER not defined as a function or string
+SyntaxError: lex: Unable to build lexer.
diff --git a/test/lex_rule1.py b/test/lex_rule1.py
new file mode 100644
index 0000000..e49a15b
--- /dev/null
+++ b/test/lex_rule1.py
@@ -0,0 +1,27 @@
+# lex_token.py
+#
+# Rule defined as some other type
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = [
+ "PLUS",
+ "MINUS",
+ "NUMBER",
+ ]
+
+t_PLUS = r'\+'
+t_MINUS = r'-'
+t_NUMBER = 1
+
+def t_error(t):
+ pass
+
+sys.tracebacklimit = 0
+
+lex.lex()
+
+
diff --git a/test/lex_state1.exp b/test/lex_state1.exp
new file mode 100644
index 0000000..8b58050
--- /dev/null
+++ b/test/lex_state1.exp
@@ -0,0 +1,7 @@
+lex: states must be defined as a tuple or list.
+Traceback (most recent call last):
+ File "./lex_state1.py", line 38, in ?
+ lex.lex()
+ File "../ply/lex.py", line 758, in lex
+ raise SyntaxError,"lex: Unable to build lexer."
+SyntaxError: lex: Unable to build lexer.
diff --git a/test/lex_state1.py b/test/lex_state1.py
new file mode 100644
index 0000000..7eb2976
--- /dev/null
+++ b/test/lex_state1.py
@@ -0,0 +1,40 @@
+# lex_state1.py
+#
+# Bad state declaration
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = [
+ "PLUS",
+ "MINUS",
+ "NUMBER",
+ ]
+
+states = 'comment'
+
+t_PLUS = r'\+'
+t_MINUS = r'-'
+t_NUMBER = r'\d+'
+
+# Comments
+def t_comment(t):
+ r'/\*'
+ t.lexer.begin('comment')
+ print "Entering comment state"
+
+def t_comment_body_part(t):
+ r'(.|\n)*\*/'
+ print "comment body", t
+ t.lexer.begin('INITIAL')
+
+def t_error(t):
+ pass
+
+import sys
+
+lex.lex()
+
+
diff --git a/test/lex_state2.exp b/test/lex_state2.exp
new file mode 100644
index 0000000..11c33a7
--- /dev/null
+++ b/test/lex_state2.exp
@@ -0,0 +1,8 @@
+lex: invalid state specifier 'comment'. Must be a tuple (statename,'exclusive|inclusive')
+lex: invalid state specifier 'example'. Must be a tuple (statename,'exclusive|inclusive')
+Traceback (most recent call last):
+ File "./lex_state2.py", line 38, in ?
+ lex.lex()
+ File "../ply/lex.py", line 758, in lex
+ raise SyntaxError,"lex: Unable to build lexer."
+SyntaxError: lex: Unable to build lexer.
diff --git a/test/lex_state2.py b/test/lex_state2.py
new file mode 100644
index 0000000..b76b0db
--- /dev/null
+++ b/test/lex_state2.py
@@ -0,0 +1,40 @@
+# lex_state2.py
+#
+# Bad state declaration
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = [
+ "PLUS",
+ "MINUS",
+ "NUMBER",
+ ]
+
+states = ('comment','example')
+
+t_PLUS = r'\+'
+t_MINUS = r'-'
+t_NUMBER = r'\d+'
+
+# Comments
+def t_comment(t):
+ r'/\*'
+ t.lexer.begin('comment')
+ print "Entering comment state"
+
+def t_comment_body_part(t):
+ r'(.|\n)*\*/'
+ print "comment body", t
+ t.lexer.begin('INITIAL')
+
+def t_error(t):
+ pass
+
+import sys
+
+lex.lex()
+
+
diff --git a/test/lex_state3.exp b/test/lex_state3.exp
new file mode 100644
index 0000000..2c3442c
--- /dev/null
+++ b/test/lex_state3.exp
@@ -0,0 +1,8 @@
+lex: state name 1 must be a string
+lex: No rules defined for state 'example'
+Traceback (most recent call last):
+ File "./lex_state3.py", line 40, in ?
+ lex.lex()
+ File "../ply/lex.py", line 758, in lex
+ raise SyntaxError,"lex: Unable to build lexer."
+SyntaxError: lex: Unable to build lexer.
diff --git a/test/lex_state3.py b/test/lex_state3.py
new file mode 100644
index 0000000..fb4ce6c
--- /dev/null
+++ b/test/lex_state3.py
@@ -0,0 +1,42 @@
+# lex_state2.py
+#
+# Bad state declaration
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = [
+ "PLUS",
+ "MINUS",
+ "NUMBER",
+ ]
+
+comment = 1
+states = ((comment, 'inclusive'),
+ ('example', 'exclusive'))
+
+t_PLUS = r'\+'
+t_MINUS = r'-'
+t_NUMBER = r'\d+'
+
+# Comments
+def t_comment(t):
+ r'/\*'
+ t.lexer.begin('comment')
+ print "Entering comment state"
+
+def t_comment_body_part(t):
+ r'(.|\n)*\*/'
+ print "comment body", t
+ t.lexer.begin('INITIAL')
+
+def t_error(t):
+ pass
+
+import sys
+
+lex.lex()
+
+
diff --git a/test/lex_state4.exp b/test/lex_state4.exp
new file mode 100644
index 0000000..7497a47
--- /dev/null
+++ b/test/lex_state4.exp
@@ -0,0 +1,7 @@
+lex: state type for state comment must be 'inclusive' or 'exclusive'
+Traceback (most recent call last):
+ File "./lex_state4.py", line 39, in ?
+ lex.lex()
+ File "../ply/lex.py", line 758, in lex
+ raise SyntaxError,"lex: Unable to build lexer."
+SyntaxError: lex: Unable to build lexer.
diff --git a/test/lex_state4.py b/test/lex_state4.py
new file mode 100644
index 0000000..0993aa9
--- /dev/null
+++ b/test/lex_state4.py
@@ -0,0 +1,41 @@
+# lex_state2.py
+#
+# Bad state declaration
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = [
+ "PLUS",
+ "MINUS",
+ "NUMBER",
+ ]
+
+comment = 1
+states = (('comment', 'exclsive'),)
+
+t_PLUS = r'\+'
+t_MINUS = r'-'
+t_NUMBER = r'\d+'
+
+# Comments
+def t_comment(t):
+ r'/\*'
+ t.lexer.begin('comment')
+ print "Entering comment state"
+
+def t_comment_body_part(t):
+ r'(.|\n)*\*/'
+ print "comment body", t
+ t.lexer.begin('INITIAL')
+
+def t_error(t):
+ pass
+
+import sys
+
+lex.lex()
+
+
diff --git a/test/lex_state5.exp b/test/lex_state5.exp
new file mode 100644
index 0000000..e9e43e8
--- /dev/null
+++ b/test/lex_state5.exp
@@ -0,0 +1,7 @@
+lex: state 'comment' already defined.
+Traceback (most recent call last):
+ File "./lex_state5.py", line 40, in ?
+ lex.lex()
+ File "../ply/lex.py", line 758, in lex
+ raise SyntaxError,"lex: Unable to build lexer."
+SyntaxError: lex: Unable to build lexer.
diff --git a/test/lex_state5.py b/test/lex_state5.py
new file mode 100644
index 0000000..c3c1cbf
--- /dev/null
+++ b/test/lex_state5.py
@@ -0,0 +1,42 @@
+# lex_state2.py
+#
+# Bad state declaration
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = [
+ "PLUS",
+ "MINUS",
+ "NUMBER",
+ ]
+
+comment = 1
+states = (('comment', 'exclusive'),
+ ('comment', 'exclusive'))
+
+t_PLUS = r'\+'
+t_MINUS = r'-'
+t_NUMBER = r'\d+'
+
+# Comments
+def t_comment(t):
+ r'/\*'
+ t.lexer.begin('comment')
+ print "Entering comment state"
+
+def t_comment_body_part(t):
+ r'(.|\n)*\*/'
+ print "comment body", t
+ t.lexer.begin('INITIAL')
+
+def t_error(t):
+ pass
+
+import sys
+
+lex.lex()
+
+
diff --git a/test/lex_state_noerror.exp b/test/lex_state_noerror.exp
new file mode 100644
index 0000000..e14149f
--- /dev/null
+++ b/test/lex_state_noerror.exp
@@ -0,0 +1 @@
+lex: Warning. no error rule is defined for exclusive state 'comment'
diff --git a/test/lex_state_noerror.py b/test/lex_state_noerror.py
new file mode 100644
index 0000000..853b157
--- /dev/null
+++ b/test/lex_state_noerror.py
@@ -0,0 +1,41 @@
+# lex_state2.py
+#
+# Declaration of a state for which no rules are defined
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = [
+ "PLUS",
+ "MINUS",
+ "NUMBER",
+ ]
+
+comment = 1
+states = (('comment', 'exclusive'),)
+
+t_PLUS = r'\+'
+t_MINUS = r'-'
+t_NUMBER = r'\d+'
+
+# Comments
+def t_comment(t):
+ r'/\*'
+ t.lexer.begin('comment')
+ print "Entering comment state"
+
+def t_comment_body_part(t):
+ r'(.|\n)*\*/'
+ print "comment body", t
+ t.lexer.begin('INITIAL')
+
+def t_error(t):
+ pass
+
+import sys
+
+lex.lex()
+
+
diff --git a/test/lex_state_norule.exp b/test/lex_state_norule.exp
new file mode 100644
index 0000000..a8ff4ca
--- /dev/null
+++ b/test/lex_state_norule.exp
@@ -0,0 +1,7 @@
+lex: No rules defined for state 'example'
+Traceback (most recent call last):
+ File "./lex_state_norule.py", line 40, in ?
+ lex.lex()
+ File "../ply/lex.py", line 758, in lex
+ raise SyntaxError,"lex: Unable to build lexer."
+SyntaxError: lex: Unable to build lexer.
diff --git a/test/lex_state_norule.py b/test/lex_state_norule.py
new file mode 100644
index 0000000..e48a319
--- /dev/null
+++ b/test/lex_state_norule.py
@@ -0,0 +1,42 @@
+# lex_state2.py
+#
+# Declaration of a state for which no rules are defined
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = [
+ "PLUS",
+ "MINUS",
+ "NUMBER",
+ ]
+
+comment = 1
+states = (('comment', 'exclusive'),
+ ('example', 'exclusive'))
+
+t_PLUS = r'\+'
+t_MINUS = r'-'
+t_NUMBER = r'\d+'
+
+# Comments
+def t_comment(t):
+ r'/\*'
+ t.lexer.begin('comment')
+ print "Entering comment state"
+
+def t_comment_body_part(t):
+ r'(.|\n)*\*/'
+ print "comment body", t
+ t.lexer.begin('INITIAL')
+
+def t_error(t):
+ pass
+
+import sys
+
+lex.lex()
+
+
diff --git a/test/lex_state_try.exp b/test/lex_state_try.exp
new file mode 100644
index 0000000..65f2e38
--- /dev/null
+++ b/test/lex_state_try.exp
@@ -0,0 +1,7 @@
+(NUMBER,'3',1,0)
+(PLUS,'+',1,2)
+(NUMBER,'4',1,4)
+Entering comment state
+comment body LexToken(comment_body_part,'This is a comment */',1,9)
+(PLUS,'+',1,30)
+(NUMBER,'10',1,32)
diff --git a/test/lex_state_try.py b/test/lex_state_try.py
new file mode 100644
index 0000000..a16403e
--- /dev/null
+++ b/test/lex_state_try.py
@@ -0,0 +1,48 @@
+# lex_state2.py
+#
+# Declaration of a state for which no rules are defined
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = [
+ "PLUS",
+ "MINUS",
+ "NUMBER",
+ ]
+
+comment = 1
+states = (('comment', 'exclusive'),)
+
+t_PLUS = r'\+'
+t_MINUS = r'-'
+t_NUMBER = r'\d+'
+
+t_ignore = " \t"
+
+# Comments
+def t_comment(t):
+ r'/\*'
+ t.lexer.begin('comment')
+ print "Entering comment state"
+
+def t_comment_body_part(t):
+ r'(.|\n)*\*/'
+ print "comment body", t
+ t.lexer.begin('INITIAL')
+
+def t_error(t):
+ pass
+
+t_comment_error = t_error
+t_comment_ignore = t_ignore
+
+import sys
+
+lex.lex()
+
+data = "3 + 4 /* This is a comment */ + 10"
+
+lex.runmain(data=data)
diff --git a/test/lex_token1.exp b/test/lex_token1.exp
new file mode 100644
index 0000000..3792831
--- /dev/null
+++ b/test/lex_token1.exp
@@ -0,0 +1 @@
+SyntaxError: lex: module does not define 'tokens'
diff --git a/test/lex_token1.py b/test/lex_token1.py
new file mode 100644
index 0000000..380c31c
--- /dev/null
+++ b/test/lex_token1.py
@@ -0,0 +1,21 @@
+# lex_token.py
+#
+# Tests for absence of tokens variable
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+t_PLUS = r'\+'
+t_MINUS = r'-'
+t_NUMBER = r'\d+'
+
+def t_error(t):
+ pass
+
+sys.tracebacklimit = 0
+
+lex.lex()
+
+
diff --git a/test/lex_token2.exp b/test/lex_token2.exp
new file mode 100644
index 0000000..3f98fe5
--- /dev/null
+++ b/test/lex_token2.exp
@@ -0,0 +1 @@
+SyntaxError: lex: tokens must be a list or tuple.
diff --git a/test/lex_token2.py b/test/lex_token2.py
new file mode 100644
index 0000000..87db8a0
--- /dev/null
+++ b/test/lex_token2.py
@@ -0,0 +1,23 @@
+# lex_token.py
+#
+# Tests for tokens of wrong type
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = "PLUS MINUS NUMBER"
+
+t_PLUS = r'\+'
+t_MINUS = r'-'
+t_NUMBER = r'\d+'
+
+def t_error(t):
+ pass
+
+sys.tracebacklimit = 0
+
+lex.lex()
+
+
diff --git a/test/lex_token3.exp b/test/lex_token3.exp
new file mode 100644
index 0000000..d991d3c
--- /dev/null
+++ b/test/lex_token3.exp
@@ -0,0 +1,2 @@
+lex: Rule 't_MINUS' defined for an unspecified token MINUS.
+SyntaxError: lex: Unable to build lexer.
diff --git a/test/lex_token3.py b/test/lex_token3.py
new file mode 100644
index 0000000..27ce947
--- /dev/null
+++ b/test/lex_token3.py
@@ -0,0 +1,27 @@
+# lex_token.py
+#
+# tokens is right type, but is missing a token for one rule
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = [
+ "PLUS",
+ "NUMBER",
+ ]
+
+t_PLUS = r'\+'
+t_MINUS = r'-'
+t_NUMBER = r'\d+'
+
+def t_error(t):
+ pass
+
+
+sys.tracebacklimit = 0
+
+lex.lex()
+
+
diff --git a/test/lex_token4.exp b/test/lex_token4.exp
new file mode 100644
index 0000000..3dd88e0
--- /dev/null
+++ b/test/lex_token4.exp
@@ -0,0 +1,2 @@
+lex: Bad token name '-'
+SyntaxError: lex: Unable to build lexer.
diff --git a/test/lex_token4.py b/test/lex_token4.py
new file mode 100644
index 0000000..612ff13
--- /dev/null
+++ b/test/lex_token4.py
@@ -0,0 +1,28 @@
+# lex_token.py
+#
+# Bad token name
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = [
+ "PLUS",
+ "MINUS",
+ "-",
+ "NUMBER",
+ ]
+
+t_PLUS = r'\+'
+t_MINUS = r'-'
+t_NUMBER = r'\d+'
+
+def t_error(t):
+ pass
+
+sys.tracebacklimit = 0
+
+lex.lex()
+
+
diff --git a/test/lex_token5.exp b/test/lex_token5.exp
new file mode 100644
index 0000000..2f03889
--- /dev/null
+++ b/test/lex_token5.exp
@@ -0,0 +1 @@
+ply.lex.LexError: ./lex_token5.py:19: Rule 't_NUMBER' returned an unknown token type 'NUM'
diff --git a/test/lex_token5.py b/test/lex_token5.py
new file mode 100644
index 0000000..77fabde
--- /dev/null
+++ b/test/lex_token5.py
@@ -0,0 +1,33 @@
+# lex_token.py
+#
+# Return a bad token name
+
+import sys
+sys.path.insert(0,"..")
+
+import ply.lex as lex
+
+tokens = [
+ "PLUS",
+ "MINUS",
+ "NUMBER",
+ ]
+
+t_PLUS = r'\+'
+t_MINUS = r'-'
+
+def t_NUMBER(t):
+ r'\d+'
+ t.type = "NUM"
+ return t
+
+def t_error(t):
+ pass
+
+sys.tracebacklimit = 0
+
+lex.lex()
+lex.input("1234")
+t = lex.token()
+
+
diff --git a/test/rununit.py b/test/rununit.py
new file mode 100644
index 0000000..d6b36fd
--- /dev/null
+++ b/test/rununit.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python
+'''Script to run all tests using python "unittest" module'''
+
+__author__ = "Miki Tebeka <miki.tebeka@zoran.com>"
+
+from unittest import TestCase, main, makeSuite, TestSuite
+from os import popen, environ, remove
+from glob import glob
+from sys import executable, argv
+from os.path import isfile, basename, splitext
+
+# Add path to lex.py and yacc.py
+environ["PYTHONPATH"] = ".."
+
+class PLYTest(TestCase):
+ '''General test case for PLY test'''
+ def _runtest(self, filename):
+ '''Run a single test file an compare result'''
+ exp_file = filename.replace(".py", ".exp")
+ self.failUnless(isfile(exp_file), "can't find %s" % exp_file)
+ pipe = popen("%s %s 2>&1" % (executable, filename))
+ out = pipe.read().strip()
+ self.failUnlessEqual(out, open(exp_file).read().strip())
+
+
+class LexText(PLYTest):
+ '''Testing Lex'''
+ pass
+
+class YaccTest(PLYTest):
+ '''Testing Yacc'''
+
+ def tearDown(self):
+ '''Cleanup parsetab.py[c] file'''
+ for ext in (".py", ".pyc"):
+ fname = "parsetab%s" % ext
+ if isfile(fname):
+ remove(fname)
+
+def add_test(klass, filename):
+ '''Add a test to TestCase class'''
+ def t(self):
+ self._runtest(filename)
+ # Test name is test_FILENAME without the ./ and without the .py
+ setattr(klass, "test_%s" % (splitext(basename(filename))[0]), t)
+
+# Add lex tests
+for file in glob("./lex_*.py"):
+ add_test(LexText, file)
+lex_suite = makeSuite(LexText, "test_")
+
+# Add yacc tests
+for file in glob("./yacc_*.py"):
+ add_test(YaccTest, file)
+yacc_suite = makeSuite(YaccTest, "test_")
+
+# All tests suite
+test_suite = TestSuite((lex_suite, yacc_suite))
+
+if __name__ == "__main__":
+ main()
+
diff --git a/test/testlex.py b/test/testlex.py
new file mode 100755
index 0000000..2dae47a
--- /dev/null
+++ b/test/testlex.py
@@ -0,0 +1,57 @@
+#!/usr/local/bin
+# ----------------------------------------------------------------------
+# testlex.py
+#
+# Run tests for the lexing module
+# ----------------------------------------------------------------------
+
+import sys,os,glob
+
+if len(sys.argv) < 2:
+ print "Usage: python testlex.py directory"
+ raise SystemExit
+
+dirname = None
+make = 0
+
+for o in sys.argv[1:]:
+ if o == '-make':
+ make = 1
+ else:
+ dirname = o
+ break
+
+if not dirname:
+ print "Usage: python testlex.py [-make] directory"
+ raise SystemExit
+
+f = glob.glob("%s/%s" % (dirname,"lex_*.py"))
+
+print "**** Running tests for lex ****"
+
+for t in f:
+ name = t[:-3]
+ print "Testing %-32s" % name,
+ if make:
+ if not os.path.exists("%s.exp" % name):
+ os.system("python %s.py >%s.exp 2>&1" % (name,name))
+ passed = 1
+ else:
+ os.system("python %s.py >%s.out 2>&1" % (name,name))
+ a = os.system("diff %s.out %s.exp >%s.dif" % (name,name,name))
+ if a == 0:
+ passed = 1
+ else:
+ passed = 0
+
+ if passed:
+ print "Passed"
+ else:
+ print "Failed. See %s.dif" % name
+
+
+
+
+
+
+
diff --git a/test/testyacc.py b/test/testyacc.py
new file mode 100644
index 0000000..f976ff5
--- /dev/null
+++ b/test/testyacc.py
@@ -0,0 +1,58 @@
+#!/usr/local/bin
+# ----------------------------------------------------------------------
+# testyacc.py
+#
+# Run tests for the yacc module
+# ----------------------------------------------------------------------
+
+import sys,os,glob
+
+if len(sys.argv) < 2:
+ print "Usage: python testyacc.py directory"
+ raise SystemExit
+
+dirname = None
+make = 0
+
+for o in sys.argv[1:]:
+ if o == '-make':
+ make = 1
+ else:
+ dirname = o
+ break
+
+if not dirname:
+ print "Usage: python testyacc.py [-make] directory"
+ raise SystemExit
+
+f = glob.glob("%s/%s" % (dirname,"yacc_*.py"))
+
+print "**** Running tests for yacc ****"
+
+for t in f:
+ name = t[:-3]
+ print "Testing %-32s" % name,
+ os.system("rm -f %s/parsetab.*" % dirname)
+ if make:
+ if not os.path.exists("%s.exp" % name):
+ os.system("python %s.py >%s.exp 2>&1" % (name,name))
+ passed = 1
+ else:
+ os.system("python %s.py >%s.out 2>&1" % (name,name))
+ a = os.system("diff %s.out %s.exp >%s.dif" % (name,name,name))
+ if a == 0:
+ passed = 1
+ else:
+ passed = 0
+
+ if passed:
+ print "Passed"
+ else:
+ print "Failed. See %s.dif" % name
+
+
+
+
+
+
+
diff --git a/test/yacc_badargs.exp b/test/yacc_badargs.exp
new file mode 100644
index 0000000..e994676
--- /dev/null
+++ b/test/yacc_badargs.exp
@@ -0,0 +1,3 @@
+./yacc_badargs.py:23: Rule 'p_statement_assign' has too many arguments.
+./yacc_badargs.py:27: Rule 'p_statement_expr' requires an argument.
+ply.yacc.YaccError: Unable to construct parser.
diff --git a/test/yacc_badargs.py b/test/yacc_badargs.py
new file mode 100644
index 0000000..810e529
--- /dev/null
+++ b/test/yacc_badargs.py
@@ -0,0 +1,68 @@
+# -----------------------------------------------------------------------------
+# yacc_badargs.py
+#
+# Rules with wrong # args
+# -----------------------------------------------------------------------------
+import sys
+sys.tracebacklimit = 0
+sys.path.insert(0,"..")
+import ply.yacc as yacc
+
+from calclex import tokens
+
+# Parsing rules
+precedence = (
+ ('left','PLUS','MINUS'),
+ ('left','TIMES','DIVIDE'),
+ ('right','UMINUS'),
+ )
+
+# dictionary of names
+names = { }
+
+def p_statement_assign(t,s):
+ 'statement : NAME EQUALS expression'
+ names[t[1]] = t[3]
+
+def p_statement_expr():
+ 'statement : expression'
+ print t[1]
+
+def p_expression_binop(t):
+ '''expression : expression PLUS expression
+ | expression MINUS expression
+ | expression TIMES expression
+ | expression DIVIDE expression'''
+ if t[2] == '+' : t[0] = t[1] + t[3]
+ elif t[2] == '-': t[0] = t[1] - t[3]
+ elif t[2] == '*': t[0] = t[1] * t[3]
+ elif t[3] == '/': t[0] = t[1] / t[3]
+
+def p_expression_uminus(t):
+ 'expression : MINUS expression %prec UMINUS'
+ t[0] = -t[2]
+
+def p_expression_group(t):
+ 'expression : LPAREN expression RPAREN'
+ t[0] = t[2]
+
+def p_expression_number(t):
+ 'expression : NUMBER'
+ t[0] = t[1]
+
+def p_expression_name(t):
+ 'expression : NAME'
+ try:
+ t[0] = names[t[1]]
+ except LookupError:
+ print "Undefined name '%s'" % t[1]
+ t[0] = 0
+
+def p_error(t):
+ print "Syntax error at '%s'" % t.value
+
+yacc.yacc()
+
+
+
+
diff --git a/test/yacc_badprec.exp b/test/yacc_badprec.exp
new file mode 100644
index 0000000..f4f574b
--- /dev/null
+++ b/test/yacc_badprec.exp
@@ -0,0 +1 @@
+ply.yacc.YaccError: precedence must be a list or tuple.
diff --git a/test/yacc_badprec.py b/test/yacc_badprec.py
new file mode 100644
index 0000000..8f64652
--- /dev/null
+++ b/test/yacc_badprec.py
@@ -0,0 +1,65 @@
+# -----------------------------------------------------------------------------
+# yacc_badprec.py
+#
+# Bad precedence specifier
+# -----------------------------------------------------------------------------
+import sys
+sys.tracebacklimit = 0
+
+sys.path.insert(0,"..")
+import ply.yacc as yacc
+
+from calclex import tokens
+
+# Parsing rules
+precedence = "blah"
+
+# dictionary of names
+names = { }
+
+def p_statement_assign(t):
+ 'statement : NAME EQUALS expression'
+ names[t[1]] = t[3]
+
+def p_statement_expr(t):
+ 'statement : expression'
+ print t[1]
+
+def p_expression_binop(t):
+ '''expression : expression PLUS expression
+ | expression MINUS expression
+ | expression TIMES expression
+ | expression DIVIDE expression'''
+ if t[2] == '+' : t[0] = t[1] + t[3]
+ elif t[2] == '-': t[0] = t[1] - t[3]
+ elif t[2] == '*': t[0] = t[1] * t[3]
+ elif t[3] == '/': t[0] = t[1] / t[3]
+
+def p_expression_uminus(t):
+ 'expression : MINUS expression %prec UMINUS'
+ t[0] = -t[2]
+
+def p_expression_group(t):
+ 'expression : LPAREN expression RPAREN'
+ t[0] = t[2]
+
+def p_expression_number(t):
+ 'expression : NUMBER'
+ t[0] = t[1]
+
+def p_expression_name(t):
+ 'expression : NAME'
+ try:
+ t[0] = names[t[1]]
+ except LookupError:
+ print "Undefined name '%s'" % t[1]
+ t[0] = 0
+
+def p_error(t):
+ print "Syntax error at '%s'" % t.value
+
+yacc.yacc()
+
+
+
+
diff --git a/test/yacc_badprec2.exp b/test/yacc_badprec2.exp
new file mode 100644
index 0000000..8fac075
--- /dev/null
+++ b/test/yacc_badprec2.exp
@@ -0,0 +1,3 @@
+yacc: Invalid precedence table.
+yacc: Generating LALR parsing table...
+yacc: 8 shift/reduce conflicts
diff --git a/test/yacc_badprec2.py b/test/yacc_badprec2.py
new file mode 100644
index 0000000..206bda7
--- /dev/null
+++ b/test/yacc_badprec2.py
@@ -0,0 +1,69 @@
+# -----------------------------------------------------------------------------
+# yacc_badprec2.py
+#
+# Bad precedence
+# -----------------------------------------------------------------------------
+import sys
+sys.tracebacklimit = 0
+
+sys.path.insert(0,"..")
+import ply.yacc as yacc
+
+from calclex import tokens
+
+# Parsing rules
+precedence = (
+ 42,
+ ('left','TIMES','DIVIDE'),
+ ('right','UMINUS'),
+ )
+
+# dictionary of names
+names = { }
+
+def p_statement_assign(t):
+ 'statement : NAME EQUALS expression'
+ names[t[1]] = t[3]
+
+def p_statement_expr(t):
+ 'statement : expression'
+ print t[1]
+
+def p_expression_binop(t):
+ '''expression : expression PLUS expression
+ | expression MINUS expression
+ | expression TIMES expression
+ | expression DIVIDE expression'''
+ if t[2] == '+' : t[0] = t[1] + t[3]
+ elif t[2] == '-': t[0] = t[1] - t[3]
+ elif t[2] == '*': t[0] = t[1] * t[3]
+ elif t[3] == '/': t[0] = t[1] / t[3]
+
+def p_expression_uminus(t):
+ 'expression : MINUS expression %prec UMINUS'
+ t[0] = -t[2]
+
+def p_expression_group(t):
+ 'expression : LPAREN expression RPAREN'
+ t[0] = t[2]
+
+def p_expression_number(t):
+ 'expression : NUMBER'
+ t[0] = t[1]
+
+def p_expression_name(t):
+ 'expression : NAME'
+ try:
+ t[0] = names[t[1]]
+ except LookupError:
+ print "Undefined name '%s'" % t[1]
+ t[0] = 0
+
+def p_error(t):
+ print "Syntax error at '%s'" % t.value
+
+yacc.yacc()
+
+
+
+
diff --git a/test/yacc_badrule.exp b/test/yacc_badrule.exp
new file mode 100644
index 0000000..a87bf7d
--- /dev/null
+++ b/test/yacc_badrule.exp
@@ -0,0 +1,5 @@
+./yacc_badrule.py:25: Syntax error. Expected ':'
+./yacc_badrule.py:29: Syntax error in rule 'statement'
+./yacc_badrule.py:34: Syntax error. Expected ':'
+./yacc_badrule.py:43: Syntax error. Expected ':'
+ply.yacc.YaccError: Unable to construct parser.
diff --git a/test/yacc_badrule.py b/test/yacc_badrule.py
new file mode 100644
index 0000000..f5fef8a
--- /dev/null
+++ b/test/yacc_badrule.py
@@ -0,0 +1,69 @@
+# -----------------------------------------------------------------------------
+# yacc_badrule.py
+#
+# Syntax problems in the rule strings
+# -----------------------------------------------------------------------------
+import sys
+sys.tracebacklimit = 0
+
+sys.path.insert(0,"..")
+import ply.yacc as yacc
+
+from calclex import tokens
+
+# Parsing rules
+precedence = (
+ ('left','PLUS','MINUS'),
+ ('left','TIMES','DIVIDE'),
+ ('right','UMINUS'),
+ )
+
+# dictionary of names
+names = { }
+
+def p_statement_assign(t):
+ 'statement NAME EQUALS expression'
+ names[t[1]] = t[3]
+
+def p_statement_expr(t):
+ 'statement'
+ print t[1]
+
+def p_expression_binop(t):
+ '''expression : expression PLUS expression
+ expression MINUS expression
+ | expression TIMES expression
+ | expression DIVIDE expression'''
+ if t[2] == '+' : t[0] = t[1] + t[3]
+ elif t[2] == '-': t[0] = t[1] - t[3]
+ elif t[2] == '*': t[0] = t[1] * t[3]
+ elif t[3] == '/': t[0] = t[1] / t[3]
+
+def p_expression_uminus(t):
+ 'expression: MINUS expression %prec UMINUS'
+ t[0] = -t[2]
+
+def p_expression_group(t):
+ 'expression : LPAREN expression RPAREN'
+ t[0] = t[2]
+
+def p_expression_number(t):
+ 'expression : NUMBER'
+ t[0] = t[1]
+
+def p_expression_name(t):
+ 'expression : NAME'
+ try:
+ t[0] = names[t[1]]
+ except LookupError:
+ print "Undefined name '%s'" % t[1]
+ t[0] = 0
+
+def p_error(t):
+ print "Syntax error at '%s'" % t.value
+
+yacc.yacc()
+
+
+
+
diff --git a/test/yacc_badtok.exp b/test/yacc_badtok.exp
new file mode 100644
index 0000000..ccdc0e7
--- /dev/null
+++ b/test/yacc_badtok.exp
@@ -0,0 +1 @@
+ply.yacc.YaccError: tokens must be a list or tuple.
diff --git a/test/yacc_badtok.py b/test/yacc_badtok.py
new file mode 100644
index 0000000..4f2af51
--- /dev/null
+++ b/test/yacc_badtok.py
@@ -0,0 +1,70 @@
+# -----------------------------------------------------------------------------
+# yacc_badtok.py
+#
+# A grammar, but tokens is a bad datatype
+# -----------------------------------------------------------------------------
+
+import sys
+sys.tracebacklimit = 0
+
+sys.path.insert(0,"..")
+import ply.yacc as yacc
+
+tokens = "Hello"
+
+# Parsing rules
+precedence = (
+ ('left','PLUS','MINUS'),
+ ('left','TIMES','DIVIDE'),
+ ('right','UMINUS'),
+ )
+
+# dictionary of names
+names = { }
+
+def p_statement_assign(t):
+ 'statement : NAME EQUALS expression'
+ names[t[1]] = t[3]
+
+def p_statement_expr(t):
+ 'statement : expression'
+ print t[1]
+
+def p_expression_binop(t):
+ '''expression : expression PLUS expression
+ | expression MINUS expression
+ | expression TIMES expression
+ | expression DIVIDE expression'''
+ if t[2] == '+' : t[0] = t[1] + t[3]
+ elif t[2] == '-': t[0] = t[1] - t[3]
+ elif t[2] == '*': t[0] = t[1] * t[3]
+ elif t[3] == '/': t[0] = t[1] / t[3]
+
+def p_expression_uminus(t):
+ 'expression : MINUS expression %prec UMINUS'
+ t[0] = -t[2]
+
+def p_expression_group(t):
+ 'expression : LPAREN expression RPAREN'
+ t[0] = t[2]
+
+def p_expression_number(t):
+ 'expression : NUMBER'
+ t[0] = t[1]
+
+def p_expression_name(t):
+ 'expression : NAME'
+ try:
+ t[0] = names[t[1]]
+ except LookupError:
+ print "Undefined name '%s'" % t[1]
+ t[0] = 0
+
+def p_error(t):
+ print "Syntax error at '%s'" % t.value
+
+yacc.yacc()
+
+
+
+
diff --git a/test/yacc_dup.exp b/test/yacc_dup.exp
new file mode 100644
index 0000000..fdfb210
--- /dev/null
+++ b/test/yacc_dup.exp
@@ -0,0 +1,4 @@
+./yacc_dup.py:28: Function p_statement redefined. Previously defined on line 24
+yacc: Warning. Token 'EQUALS' defined, but not used.
+yacc: Warning. There is 1 unused token.
+yacc: Generating LALR parsing table...
diff --git a/test/yacc_dup.py b/test/yacc_dup.py
new file mode 100644
index 0000000..e0b683d
--- /dev/null
+++ b/test/yacc_dup.py
@@ -0,0 +1,69 @@
+# -----------------------------------------------------------------------------
+# yacc_dup.py
+#
+# Duplicated rule name
+# -----------------------------------------------------------------------------
+import sys
+sys.tracebacklimit = 0
+
+sys.path.insert(0,"..")
+import ply.yacc as yacc
+
+from calclex import tokens
+
+# Parsing rules
+precedence = (
+ ('left','PLUS','MINUS'),
+ ('left','TIMES','DIVIDE'),
+ ('right','UMINUS'),
+ )
+
+# dictionary of names
+names = { }
+
+def p_statement(t):
+ 'statement : NAME EQUALS expression'
+ names[t[1]] = t[3]
+
+def p_statement(t):
+ 'statement : expression'
+ print t[1]
+
+def p_expression_binop(t):
+ '''expression : expression PLUS expression
+ | expression MINUS expression
+ | expression TIMES expression
+ | expression DIVIDE expression'''
+ if t[2] == '+' : t[0] = t[1] + t[3]
+ elif t[2] == '-': t[0] = t[1] - t[3]
+ elif t[2] == '*': t[0] = t[1] * t[3]
+ elif t[3] == '/': t[0] = t[1] / t[3]
+
+def p_expression_uminus(t):
+ 'expression : MINUS expression %prec UMINUS'
+ t[0] = -t[2]
+
+def p_expression_group(t):
+ 'expression : LPAREN expression RPAREN'
+ t[0] = t[2]
+
+def p_expression_number(t):
+ 'expression : NUMBER'
+ t[0] = t[1]
+
+def p_expression_name(t):
+ 'expression : NAME'
+ try:
+ t[0] = names[t[1]]
+ except LookupError:
+ print "Undefined name '%s'" % t[1]
+ t[0] = 0
+
+def p_error(t):
+ print "Syntax error at '%s'" % t.value
+
+yacc.yacc()
+
+
+
+
diff --git a/test/yacc_error1.exp b/test/yacc_error1.exp
new file mode 100644
index 0000000..13bed04
--- /dev/null
+++ b/test/yacc_error1.exp
@@ -0,0 +1 @@
+ply.yacc.YaccError: ./yacc_error1.py:62: p_error() requires 1 argument.
diff --git a/test/yacc_error1.py b/test/yacc_error1.py
new file mode 100644
index 0000000..2768fc1
--- /dev/null
+++ b/test/yacc_error1.py
@@ -0,0 +1,69 @@
+# -----------------------------------------------------------------------------
+# yacc_error1.py
+#
+# Bad p_error() function
+# -----------------------------------------------------------------------------
+import sys
+sys.tracebacklimit = 0
+
+sys.path.insert(0,"..")
+import ply.yacc as yacc
+
+from calclex import tokens
+
+# Parsing rules
+precedence = (
+ ('left','PLUS','MINUS'),
+ ('left','TIMES','DIVIDE'),
+ ('right','UMINUS'),
+ )
+
+# dictionary of names
+names = { }
+
+def p_statement_assign(t):
+ 'statement : NAME EQUALS expression'
+ names[t[1]] = t[3]
+
+def p_statement_expr(t):
+ 'statement : expression'
+ print t[1]
+
+def p_expression_binop(t):
+ '''expression : expression PLUS expression
+ | expression MINUS expression
+ | expression TIMES expression
+ | expression DIVIDE expression'''
+ if t[2] == '+' : t[0] = t[1] + t[3]
+ elif t[2] == '-': t[0] = t[1] - t[3]
+ elif t[2] == '*': t[0] = t[1] * t[3]
+ elif t[3] == '/': t[0] = t[1] / t[3]
+
+def p_expression_uminus(t):
+ 'expression : MINUS expression %prec UMINUS'
+ t[0] = -t[2]
+
+def p_expression_group(t):
+ 'expression : LPAREN expression RPAREN'
+ t[0] = t[2]
+
+def p_expression_number(t):
+ 'expression : NUMBER'
+ t[0] = t[1]
+
+def p_expression_name(t):
+ 'expression : NAME'
+ try:
+ t[0] = names[t[1]]
+ except LookupError:
+ print "Undefined name '%s'" % t[1]
+ t[0] = 0
+
+def p_error(t,s):
+ print "Syntax error at '%s'" % t.value
+
+yacc.yacc()
+
+
+
+
diff --git a/test/yacc_error2.exp b/test/yacc_error2.exp
new file mode 100644
index 0000000..4a7628d
--- /dev/null
+++ b/test/yacc_error2.exp
@@ -0,0 +1 @@
+ply.yacc.YaccError: ./yacc_error2.py:62: p_error() requires 1 argument.
diff --git a/test/yacc_error2.py b/test/yacc_error2.py
new file mode 100644
index 0000000..8f3a052
--- /dev/null
+++ b/test/yacc_error2.py
@@ -0,0 +1,69 @@
+# -----------------------------------------------------------------------------
+# yacc_error1.py
+#
+# Bad p_error() function
+# -----------------------------------------------------------------------------
+import sys
+sys.tracebacklimit = 0
+
+sys.path.insert(0,"..")
+import ply.yacc as yacc
+
+from calclex import tokens
+
+# Parsing rules
+precedence = (
+ ('left','PLUS','MINUS'),
+ ('left','TIMES','DIVIDE'),
+ ('right','UMINUS'),
+ )
+
+# dictionary of names
+names = { }
+
+def p_statement_assign(t):
+ 'statement : NAME EQUALS expression'
+ names[t[1]] = t[3]
+
+def p_statement_expr(t):
+ 'statement : expression'
+ print t[1]
+
+def p_expression_binop(t):
+ '''expression : expression PLUS expression
+ | expression MINUS expression
+ | expression TIMES expression
+ | expression DIVIDE expression'''
+ if t[2] == '+' : t[0] = t[1] + t[3]
+ elif t[2] == '-': t[0] = t[1] - t[3]
+ elif t[2] == '*': t[0] = t[1] * t[3]
+ elif t[3] == '/': t[0] = t[1] / t[3]
+
+def p_expression_uminus(t):
+ 'expression : MINUS expression %prec UMINUS'
+ t[0] = -t[2]
+
+def p_expression_group(t):
+ 'expression : LPAREN expression RPAREN'
+ t[0] = t[2]
+
+def p_expression_number(t):
+ 'expression : NUMBER'
+ t[0] = t[1]
+
+def p_expression_name(t):
+ 'expression : NAME'
+ try:
+ t[0] = names[t[1]]
+ except LookupError:
+ print "Undefined name '%s'" % t[1]
+ t[0] = 0
+
+def p_error():
+ print "Syntax error at '%s'" % t.value
+
+yacc.yacc()
+
+
+
+
diff --git a/test/yacc_error3.exp b/test/yacc_error3.exp
new file mode 100644
index 0000000..7fca2fe
--- /dev/null
+++ b/test/yacc_error3.exp
@@ -0,0 +1 @@
+ply.yacc.YaccError: 'p_error' defined, but is not a function or method.
diff --git a/test/yacc_error3.py b/test/yacc_error3.py
new file mode 100644
index 0000000..b387de5
--- /dev/null
+++ b/test/yacc_error3.py
@@ -0,0 +1,68 @@
+# -----------------------------------------------------------------------------
+# yacc_error1.py
+#
+# Bad p_error() function
+# -----------------------------------------------------------------------------
+import sys
+sys.tracebacklimit = 0
+
+sys.path.insert(0,"..")
+import ply.yacc as yacc
+
+from calclex import tokens
+
+# Parsing rules
+precedence = (
+ ('left','PLUS','MINUS'),
+ ('left','TIMES','DIVIDE'),
+ ('right','UMINUS'),
+ )
+
+# dictionary of names
+names = { }
+
+def p_statement_assign(t):
+ 'statement : NAME EQUALS expression'
+ names[t[1]] = t[3]
+
+def p_statement_expr(t):
+ 'statement : expression'
+ print t[1]
+
+def p_expression_binop(t):
+ '''expression : expression PLUS expression
+ | expression MINUS expression
+ | expression TIMES expression
+ | expression DIVIDE expression'''
+ if t[2] == '+' : t[0] = t[1] + t[3]
+ elif t[2] == '-': t[0] = t[1] - t[3]
+ elif t[2] == '*': t[0] = t[1] * t[3]
+ elif t[3] == '/': t[0] = t[1] / t[3]
+
+def p_expression_uminus(t):
+ 'expression : MINUS expression %prec UMINUS'
+ t[0] = -t[2]
+
+def p_expression_group(t):
+ 'expression : LPAREN expression RPAREN'
+ t[0] = t[2]
+
+def p_expression_number(t):
+ 'expression : NUMBER'
+ t[0] = t[1]
+
+def p_expression_name(t):
+ 'expression : NAME'
+ try:
+ t[0] = names[t[1]]
+ except LookupError:
+ print "Undefined name '%s'" % t[1]
+ t[0] = 0
+
+p_error = "blah"
+
+yacc.yacc()
+
+
+
+
diff --git a/test/yacc_inf.exp b/test/yacc_inf.exp
new file mode 100644
index 0000000..88cfa4a
--- /dev/null
+++ b/test/yacc_inf.exp
@@ -0,0 +1,5 @@
+yacc: Warning. Token 'NUMBER' defined, but not used.
+yacc: Warning. There is 1 unused token.
+yacc: Infinite recursion detected for symbol 'statement'.
+yacc: Infinite recursion detected for symbol 'expression'.
+ply.yacc.YaccError: Unable to construct parser.
diff --git a/test/yacc_inf.py b/test/yacc_inf.py
new file mode 100644
index 0000000..9b9aef7
--- /dev/null
+++ b/test/yacc_inf.py
@@ -0,0 +1,57 @@
+# -----------------------------------------------------------------------------
+# yacc_inf.py
+#
+# Infinite recursion
+# -----------------------------------------------------------------------------
+import sys
+sys.tracebacklimit = 0
+
+sys.path.insert(0,"..")
+import ply.yacc as yacc
+
+from calclex import tokens
+
+# Parsing rules
+precedence = (
+ ('left','PLUS','MINUS'),
+ ('left','TIMES','DIVIDE'),
+ ('right','UMINUS'),
+ )
+
+# dictionary of names
+names = { }
+
+def p_statement_assign(t):
+ 'statement : NAME EQUALS expression'
+ names[t[1]] = t[3]
+
+def p_statement_expr(t):
+ 'statement : expression'
+ print t[1]
+
+def p_expression_binop(t):
+ '''expression : expression PLUS expression
+ | expression MINUS expression
+ | expression TIMES expression
+ | expression DIVIDE expression'''
+ if t[2] == '+' : t[0] = t[1] + t[3]
+ elif t[2] == '-': t[0] = t[1] - t[3]
+ elif t[2] == '*': t[0] = t[1] * t[3]
+ elif t[3] == '/': t[0] = t[1] / t[3]
+
+def p_expression_uminus(t):
+ 'expression : MINUS expression %prec UMINUS'
+ t[0] = -t[2]
+
+def p_expression_group(t):
+ 'expression : LPAREN expression RPAREN'
+ t[0] = t[2]
+
+def p_error(t):
+ print "Syntax error at '%s'" % t.value
+
+yacc.yacc()
+
+
+
+
diff --git a/test/yacc_missing1.exp b/test/yacc_missing1.exp
new file mode 100644
index 0000000..de63d4f
--- /dev/null
+++ b/test/yacc_missing1.exp
@@ -0,0 +1,2 @@
+./yacc_missing1.py:25: Symbol 'location' used, but not defined as a token or a rule.
+ply.yacc.YaccError: Unable to construct parser.
diff --git a/test/yacc_missing1.py b/test/yacc_missing1.py
new file mode 100644
index 0000000..fbc54d8
--- /dev/null
+++ b/test/yacc_missing1.py
@@ -0,0 +1,69 @@
+# -----------------------------------------------------------------------------
+# yacc_missing1.py
+#
+# Grammar with a missing rule
+# -----------------------------------------------------------------------------
+import sys
+sys.tracebacklimit = 0
+
+sys.path.insert(0,"..")
+import ply.yacc as yacc
+
+from calclex import tokens
+
+# Parsing rules
+precedence = (
+ ('left','PLUS','MINUS'),
+ ('left','TIMES','DIVIDE'),
+ ('right','UMINUS'),
+ )
+
+# dictionary of names
+names = { }
+
+def p_statement_assign(t):
+ 'statement : location EQUALS expression'
+ names[t[1]] = t[3]
+
+def p_statement_expr(t):
+ 'statement : expression'
+ print t[1]
+
+def p_expression_binop(t):
+ '''expression : expression PLUS expression
+ | expression MINUS expression
+ | expression TIMES expression
+ | expression DIVIDE expression'''
+ if t[2] == '+' : t[0] = t[1] + t[3]
+ elif t[2] == '-': t[0] = t[1] - t[3]
+ elif t[2] == '*': t[0] = t[1] * t[3]
+ elif t[3] == '/': t[0] = t[1] / t[3]
+
+def p_expression_uminus(t):
+ 'expression : MINUS expression %prec UMINUS'
+ t[0] = -t[2]
+
+def p_expression_group(t):
+ 'expression : LPAREN expression RPAREN'
+ t[0] = t[2]
+
+def p_expression_number(t):
+ 'expression : NUMBER'
+ t[0] = t[1]
+
+def p_expression_name(t):
+ 'expression : NAME'
+ try:
+ t[0] = names[t[1]]
+ except LookupError:
+ print "Undefined name '%s'" % t[1]
+ t[0] = 0
+
+def p_error(t):
+ print "Syntax error at '%s'" % t.value
+
+yacc.yacc()
+
+
+
+
diff --git a/test/yacc_nodoc.exp b/test/yacc_nodoc.exp
new file mode 100644
index 0000000..889ccfc
--- /dev/null
+++ b/test/yacc_nodoc.exp
@@ -0,0 +1,2 @@
+./yacc_nodoc.py:28: No documentation string specified in function 'p_statement_expr'
+yacc: Generating LALR parsing table...
diff --git a/test/yacc_nodoc.py b/test/yacc_nodoc.py
new file mode 100644
index 0000000..4c5ab20
--- /dev/null
+++ b/test/yacc_nodoc.py
@@ -0,0 +1,68 @@
+# -----------------------------------------------------------------------------
+# yacc_nodoc.py
+#
+# Rule with a missing doc-string
+# -----------------------------------------------------------------------------
+import sys
+sys.tracebacklimit = 0
+
+sys.path.insert(0,"..")
+import ply.yacc as yacc
+
+from calclex import tokens
+
+# Parsing rules
+precedence = (
+ ('left','PLUS','MINUS'),
+ ('left','TIMES','DIVIDE'),
+ ('right','UMINUS'),
+ )
+
+# dictionary of names
+names = { }
+
+def p_statement_assign(t):
+ 'statement : NAME EQUALS expression'
+ names[t[1]] = t[3]
+
+def p_statement_expr(t):
+ print t[1]
+
+def p_expression_binop(t):
+ '''expression : expression PLUS expression
+ | expression MINUS expression
+ | expression TIMES expression
+ | expression DIVIDE expression'''
+ if t[2] == '+' : t[0] = t[1] + t[3]
+ elif t[2] == '-': t[0] = t[1] - t[3]
+ elif t[2] == '*': t[0] = t[1] * t[3]
+ elif t[3] == '/': t[0] = t[1] / t[3]
+
+def p_expression_uminus(t):
+ 'expression : MINUS expression %prec UMINUS'
+ t[0] = -t[2]
+
+def p_expression_group(t):
+ 'expression : LPAREN expression RPAREN'
+ t[0] = t[2]
+
+def p_expression_number(t):
+ 'expression : NUMBER'
+ t[0] = t[1]
+
+def p_expression_name(t):
+ 'expression : NAME'
+ try:
+ t[0] = names[t[1]]
+ except LookupError:
+ print "Undefined name '%s'" % t[1]
+ t[0] = 0
+
+def p_error(t):
+ print "Syntax error at '%s'" % t.value
+
+yacc.yacc()
+
+
+
+
diff --git a/test/yacc_noerror.exp b/test/yacc_noerror.exp
new file mode 100644
index 0000000..658f907
--- /dev/null
+++ b/test/yacc_noerror.exp
@@ -0,0 +1,2 @@
+yacc: Generating LALR parsing table...
+yacc: Warning. no p_error() function is defined.
diff --git a/test/yacc_noerror.py b/test/yacc_noerror.py
new file mode 100644
index 0000000..9c11838
--- /dev/null
+++ b/test/yacc_noerror.py
@@ -0,0 +1,67 @@
+# -----------------------------------------------------------------------------
+# yacc_noerror.py
+#
+# No p_error() rule defined.
+# -----------------------------------------------------------------------------
+import sys
+sys.tracebacklimit = 0
+
+sys.path.insert(0,"..")
+import ply.yacc as yacc
+
+from calclex import tokens
+
+# Parsing rules
+precedence = (
+ ('left','PLUS','MINUS'),
+ ('left','TIMES','DIVIDE'),
+ ('right','UMINUS'),
+ )
+
+# dictionary of names
+names = { }
+
+def p_statement_assign(t):
+ 'statement : NAME EQUALS expression'
+ names[t[1]] = t[3]
+
+def p_statement_expr(t):
+ 'statement : expression'
+ print t[1]
+
+def p_expression_binop(t):
+ '''expression : expression PLUS expression
+ | expression MINUS expression
+ | expression TIMES expression
+ | expression DIVIDE expression'''
+ if t[2] == '+' : t[0] = t[1] + t[3]
+ elif t[2] == '-': t[0] = t[1] - t[3]
+ elif t[2] == '*': t[0] = t[1] * t[3]
+ elif t[3] == '/': t[0] = t[1] / t[3]
+
+def p_expression_uminus(t):
+ 'expression : MINUS expression %prec UMINUS'
+ t[0] = -t[2]
+
+def p_expression_group(t):
+ 'expression : LPAREN expression RPAREN'
+ t[0] = t[2]
+
+def p_expression_number(t):
+ 'expression : NUMBER'
+ t[0] = t[1]
+
+def p_expression_name(t):
+ 'expression : NAME'
+ try:
+ t[0] = names[t[1]]
+ except LookupError:
+ print "Undefined name '%s'" % t[1]
+ t[0] = 0
+
+
+yacc.yacc()
+
+
+
+
diff --git a/test/yacc_nop.exp b/test/yacc_nop.exp
new file mode 100644
index 0000000..515fff7
--- /dev/null
+++ b/test/yacc_nop.exp
@@ -0,0 +1,2 @@
+./yacc_nop.py:28: Warning. Possible grammar rule 'statement_expr' defined without p_ prefix.
+yacc: Generating LALR parsing table...
diff --git a/test/yacc_nop.py b/test/yacc_nop.py
new file mode 100644
index 0000000..c0b431d
--- /dev/null
+++ b/test/yacc_nop.py
@@ -0,0 +1,69 @@
+# -----------------------------------------------------------------------------
+# yacc_nop.py
+#
+# Possible grammar rule defined without p_ prefix
+# -----------------------------------------------------------------------------
+import sys
+sys.tracebacklimit = 0
+
+sys.path.insert(0,"..")
+import ply.yacc as yacc
+
+from calclex import tokens
+
+# Parsing rules
+precedence = (
+ ('left','PLUS','MINUS'),
+ ('left','TIMES','DIVIDE'),
+ ('right','UMINUS'),
+ )
+
+# dictionary of names
+names = { }
+
+def p_statement_assign(t):
+ 'statement : NAME EQUALS expression'
+ names[t[1]] = t[3]
+
+def statement_expr(t):
+ 'statement : expression'
+ print t[1]
+
+def p_expression_binop(t):
+ '''expression : expression PLUS expression
+ | expression MINUS expression
+ | expression TIMES expression
+ | expression DIVIDE expression'''
+ if t[2] == '+' : t[0] = t[1] + t[3]
+ elif t[2] == '-': t[0] = t[1] - t[3]
+ elif t[2] == '*': t[0] = t[1] * t[3]
+ elif t[3] == '/': t[0] = t[1] / t[3]
+
+def p_expression_uminus(t):
+ 'expression : MINUS expression %prec UMINUS'
+ t[0] = -t[2]
+
+def p_expression_group(t):
+ 'expression : LPAREN expression RPAREN'
+ t[0] = t[2]
+
+def p_expression_number(t):
+ 'expression : NUMBER'
+ t[0] = t[1]
+
+def p_expression_name(t):
+ 'expression : NAME'
+ try:
+ t[0] = names[t[1]]
+ except LookupError:
+ print "Undefined name '%s'" % t[1]
+ t[0] = 0
+
+def p_error(t):
+ print "Syntax error at '%s'" % t.value
+
+yacc.yacc()
+
+
+
+
diff --git a/test/yacc_notfunc.exp b/test/yacc_notfunc.exp
new file mode 100644
index 0000000..f73bc93
--- /dev/null
+++ b/test/yacc_notfunc.exp
@@ -0,0 +1,4 @@
+yacc: Warning. 'p_statement_assign' not defined as a function
+yacc: Warning. Token 'EQUALS' defined, but not used.
+yacc: Warning. There is 1 unused token.
+yacc: Generating LALR parsing table...
diff --git a/test/yacc_notfunc.py b/test/yacc_notfunc.py
new file mode 100644
index 0000000..8389355
--- /dev/null
+++ b/test/yacc_notfunc.py
@@ -0,0 +1,67 @@
+# -----------------------------------------------------------------------------
+# yacc_notfunc.py
+#
+# p_rule not defined as a function
+# -----------------------------------------------------------------------------
+import sys
+sys.tracebacklimit = 0
+
+sys.path.insert(0,"..")
+import ply.yacc as yacc
+
+from calclex import tokens
+
+# Parsing rules
+precedence = (
+ ('left','PLUS','MINUS'),
+ ('left','TIMES','DIVIDE'),
+ ('right','UMINUS'),
+ )
+
+# dictionary of names
+names = { }
+
+p_statement_assign = "Blah"
+
+def p_statement_expr(t):
+ 'statement : expression'
+ print t[1]
+
+def p_expression_binop(t):
+ '''expression : expression PLUS expression
+ | expression MINUS expression
+ | expression TIMES expression
+ | expression DIVIDE expression'''
+ if t[2] == '+' : t[0] = t[1] + t[3]
+ elif t[2] == '-': t[0] = t[1] - t[3]
+ elif t[2] == '*': t[0] = t[1] * t[3]
+ elif t[3] == '/': t[0] = t[1] / t[3]
+
+def p_expression_uminus(t):
+ 'expression : MINUS expression %prec UMINUS'
+ t[0] = -t[2]
+
+def p_expression_group(t):
+ 'expression : LPAREN expression RPAREN'
+ t[0] = t[2]
+
+def p_expression_number(t):
+ 'expression : NUMBER'
+ t[0] = t[1]
+
+def p_expression_name(t):
+ 'expression : NAME'
+ try:
+ t[0] = names[t[1]]
+ except LookupError:
+ print "Undefined name '%s'" % t[1]
+ t[0] = 0
+
+def p_error(t):
+ print "Syntax error at '%s'" % t.value
+
+yacc.yacc()
+
+
+
+
diff --git a/test/yacc_notok.exp b/test/yacc_notok.exp
new file mode 100644
index 0000000..d2399fe
--- /dev/null
+++ b/test/yacc_notok.exp
@@ -0,0 +1 @@
+ply.yacc.YaccError: module does not define a list 'tokens'
diff --git a/test/yacc_notok.py b/test/yacc_notok.py
new file mode 100644
index 0000000..e566a1b
--- /dev/null
+++ b/test/yacc_notok.py
@@ -0,0 +1,68 @@
+# -----------------------------------------------------------------------------
+# yacc_notok.py
+#
+# A grammar, but we forgot to import the tokens list
+# -----------------------------------------------------------------------------
+
+import sys
+sys.tracebacklimit = 0
+
+sys.path.insert(0,"..")
+import ply.yacc as yacc
+
+# Parsing rules
+precedence = (
+ ('left','PLUS','MINUS'),
+ ('left','TIMES','DIVIDE'),
+ ('right','UMINUS'),
+ )
+
+# dictionary of names
+names = { }
+
+def p_statement_assign(t):
+ 'statement : NAME EQUALS expression'
+ names[t[1]] = t[3]
+
+def p_statement_expr(t):
+ 'statement : expression'
+ print t[1]
+
+def p_expression_binop(t):
+ '''expression : expression PLUS expression
+ | expression MINUS expression
+ | expression TIMES expression
+ | expression DIVIDE expression'''
+ if t[2] == '+' : t[0] = t[1] + t[3]
+ elif t[2] == '-': t[0] = t[1] - t[3]
+ elif t[2] == '*': t[0] = t[1] * t[3]
+ elif t[3] == '/': t[0] = t[1] / t[3]
+
+def p_expression_uminus(t):
+ 'expression : MINUS expression %prec UMINUS'
+ t[0] = -t[2]
+
+def p_expression_group(t):
+ 'expression : LPAREN expression RPAREN'
+ t[0] = t[2]
+
+def p_expression_number(t):
+ 'expression : NUMBER'
+ t[0] = t[1]
+
+def p_expression_name(t):
+ 'expression : NAME'
+ try:
+ t[0] = names[t[1]]
+ except LookupError:
+ print "Undefined name '%s'" % t[1]
+ t[0] = 0
+
+def p_error(t):
+ print "Syntax error at '%s'" % t.value
+
+yacc.yacc()
+
+
+
+
diff --git a/test/yacc_rr.exp b/test/yacc_rr.exp
new file mode 100644
index 0000000..f73cefd
--- /dev/null
+++ b/test/yacc_rr.exp
@@ -0,0 +1,2 @@
+yacc: Generating LALR parsing table...
+yacc: 1 reduce/reduce conflict
diff --git a/test/yacc_rr.py b/test/yacc_rr.py
new file mode 100644
index 0000000..bb8cba2
--- /dev/null
+++ b/test/yacc_rr.py
@@ -0,0 +1,73 @@
+# -----------------------------------------------------------------------------
+# yacc_rr.py
+#
+# A grammar with a reduce/reduce conflict
+# -----------------------------------------------------------------------------
+import sys
+sys.tracebacklimit = 0
+
+sys.path.insert(0,"..")
+import ply.yacc as yacc
+
+from calclex import tokens
+
+# Parsing rules
+precedence = (
+ ('left','PLUS','MINUS'),
+ ('left','TIMES','DIVIDE'),
+ ('right','UMINUS'),
+ )
+
+# dictionary of names
+names = { }
+
+def p_statement_assign(t):
+ 'statement : NAME EQUALS expression'
+ names[t[1]] = t[3]
+
+def p_statement_assign_2(t):
+ 'statement : NAME EQUALS NUMBER'
+ names[t[1]] = t[3]
+
+def p_statement_expr(t):
+ 'statement : expression'
+ print t[1]
+
+def p_expression_binop(t):
+ '''expression : expression PLUS expression
+ | expression MINUS expression
+ | expression TIMES expression
+ | expression DIVIDE expression'''
+ if t[2] == '+' : t[0] = t[1] + t[3]
+ elif t[2] == '-': t[0] = t[1] - t[3]
+ elif t[2] == '*': t[0] = t[1] * t[3]
+ elif t[3] == '/': t[0] = t[1] / t[3]
+
+def p_expression_uminus(t):
+ 'expression : MINUS expression %prec UMINUS'
+ t[0] = -t[2]
+
+def p_expression_group(t):
+ 'expression : LPAREN expression RPAREN'
+ t[0] = t[2]
+
+def p_expression_number(t):
+ 'expression : NUMBER'
+ t[0] = t[1]
+
+def p_expression_name(t):
+ 'expression : NAME'
+ try:
+ t[0] = names[t[1]]
+ except LookupError:
+ print "Undefined name '%s'" % t[1]
+ t[0] = 0
+
+def p_error(t):
+ print "Syntax error at '%s'" % t.value
+
+yacc.yacc()
+
+
+
+
diff --git a/test/yacc_simple.exp b/test/yacc_simple.exp
new file mode 100644
index 0000000..3836031
--- /dev/null
+++ b/test/yacc_simple.exp
@@ -0,0 +1 @@
+yacc: Generating LALR parsing table...
diff --git a/test/yacc_simple.py b/test/yacc_simple.py
new file mode 100644
index 0000000..b5dc9f3
--- /dev/null
+++ b/test/yacc_simple.py
@@ -0,0 +1,69 @@
+# -----------------------------------------------------------------------------
+# yacc_simple.py
+#
+# A simple, properly specifier grammar
+# -----------------------------------------------------------------------------
+import sys
+sys.tracebacklimit = 0
+
+sys.path.insert(0,"..")
+import ply.yacc as yacc
+
+from calclex import tokens
+
+# Parsing rules
+precedence = (
+ ('left','PLUS','MINUS'),
+ ('left','TIMES','DIVIDE'),
+ ('right','UMINUS'),
+ )
+
+# dictionary of names
+names = { }
+
+def p_statement_assign(t):
+ 'statement : NAME EQUALS expression'
+ names[t[1]] = t[3]
+
+def p_statement_expr(t):
+ 'statement : expression'
+ print t[1]
+
+def p_expression_binop(t):
+ '''expression : expression PLUS expression
+ | expression MINUS expression
+ | expression TIMES expression
+ | expression DIVIDE expression'''
+ if t[2] == '+' : t[0] = t[1] + t[3]
+ elif t[2] == '-': t[0] = t[1] - t[3]
+ elif t[2] == '*': t[0] = t[1] * t[3]
+ elif t[3] == '/': t[0] = t[1] / t[3]
+
+def p_expression_uminus(t):
+ 'expression : MINUS expression %prec UMINUS'
+ t[0] = -t[2]
+
+def p_expression_group(t):
+ 'expression : LPAREN expression RPAREN'
+ t[0] = t[2]
+
+def p_expression_number(t):
+ 'expression : NUMBER'
+ t[0] = t[1]
+
+def p_expression_name(t):
+ 'expression : NAME'
+ try:
+ t[0] = names[t[1]]
+ except LookupError:
+ print "Undefined name '%s'" % t[1]
+ t[0] = 0
+
+def p_error(t):
+ print "Syntax error at '%s'" % t.value
+
+yacc.yacc()
+
+
+
+
diff --git a/test/yacc_sr.exp b/test/yacc_sr.exp
new file mode 100644
index 0000000..1b76450
--- /dev/null
+++ b/test/yacc_sr.exp
@@ -0,0 +1,2 @@
+yacc: Generating LALR parsing table...
+yacc: 20 shift/reduce conflicts
diff --git a/test/yacc_sr.py b/test/yacc_sr.py
new file mode 100644
index 0000000..e2f03ec
--- /dev/null
+++ b/test/yacc_sr.py
@@ -0,0 +1,64 @@
+# -----------------------------------------------------------------------------
+# yacc_sr.py
+#
+# A grammar with shift-reduce conflicts
+# -----------------------------------------------------------------------------
+import sys
+sys.tracebacklimit = 0
+
+sys.path.insert(0,"..")
+import ply.yacc as yacc
+
+from calclex import tokens
+
+# Parsing rules
+
+# dictionary of names
+names = { }
+
+def p_statement_assign(t):
+ 'statement : NAME EQUALS expression'
+ names[t[1]] = t[3]
+
+def p_statement_expr(t):
+ 'statement : expression'
+ print t[1]
+
+def p_expression_binop(t):
+ '''expression : expression PLUS expression
+ | expression MINUS expression
+ | expression TIMES expression
+ | expression DIVIDE expression'''
+ if t[2] == '+' : t[0] = t[1] + t[3]
+ elif t[2] == '-': t[0] = t[1] - t[3]
+ elif t[2] == '*': t[0] = t[1] * t[3]
+ elif t[3] == '/': t[0] = t[1] / t[3]
+
+def p_expression_uminus(t):
+ 'expression : MINUS expression'
+ t[0] = -t[2]
+
+def p_expression_group(t):
+ 'expression : LPAREN expression RPAREN'
+ t[0] = t[2]
+
+def p_expression_number(t):
+ 'expression : NUMBER'
+ t[0] = t[1]
+
+def p_expression_name(t):
+ 'expression : NAME'
+ try:
+ t[0] = names[t[1]]
+ except LookupError:
+ print "Undefined name '%s'" % t[1]
+ t[0] = 0
+
+def p_error(t):
+ print "Syntax error at '%s'" % t.value
+
+yacc.yacc()
+
+
+
+
diff --git a/test/yacc_term1.exp b/test/yacc_term1.exp
new file mode 100644
index 0000000..40f9bdf
--- /dev/null
+++ b/test/yacc_term1.exp
@@ -0,0 +1,2 @@
+./yacc_term1.py:25: Illegal rule name 'NUMBER'. Already defined as a token.
+ply.yacc.YaccError: Unable to construct parser.
diff --git a/test/yacc_term1.py b/test/yacc_term1.py
new file mode 100644
index 0000000..bbc52da
--- /dev/null
+++ b/test/yacc_term1.py
@@ -0,0 +1,69 @@
+# -----------------------------------------------------------------------------
+# yacc_term1.py
+#
+# Terminal used on the left-hand-side
+# -----------------------------------------------------------------------------
+import sys
+sys.tracebacklimit = 0
+
+sys.path.insert(0,"..")
+import ply.yacc as yacc
+
+from calclex import tokens
+
+# Parsing rules
+precedence = (
+ ('left','PLUS','MINUS'),
+ ('left','TIMES','DIVIDE'),
+ ('right','UMINUS'),
+ )
+
+# dictionary of names
+names = { }
+
+def p_statement_assign(t):
+ 'NUMBER : NAME EQUALS expression'
+ names[t[1]] = t[3]
+
+def p_statement_expr(t):
+ 'statement : expression'
+ print t[1]
+
+def p_expression_binop(t):
+ '''expression : expression PLUS expression
+ | expression MINUS expression
+ | expression TIMES expression
+ | expression DIVIDE expression'''
+ if t[2] == '+' : t[0] = t[1] + t[3]
+ elif t[2] == '-': t[0] = t[1] - t[3]
+ elif t[2] == '*': t[0] = t[1] * t[3]
+ elif t[3] == '/': t[0] = t[1] / t[3]
+
+def p_expression_uminus(t):
+ 'expression : MINUS expression %prec UMINUS'
+ t[0] = -t[2]
+
+def p_expression_group(t):
+ 'expression : LPAREN expression RPAREN'
+ t[0] = t[2]
+
+def p_expression_number(t):
+ 'expression : NUMBER'
+ t[0] = t[1]
+
+def p_expression_name(t):
+ 'expression : NAME'
+ try:
+ t[0] = names[t[1]]
+ except LookupError:
+ print "Undefined name '%s'" % t[1]
+ t[0] = 0
+
+def p_error(t):
+ print "Syntax error at '%s'" % t.value
+
+yacc.yacc()
+
+
+
+
diff --git a/test/yacc_unused.exp b/test/yacc_unused.exp
new file mode 100644
index 0000000..6caafd2
--- /dev/null
+++ b/test/yacc_unused.exp
@@ -0,0 +1,4 @@
+./yacc_unused.py:63: Symbol 'COMMA' used, but not defined as a token or a rule.
+yacc: Symbol 'COMMA' is unreachable.
+yacc: Symbol 'exprlist' is unreachable.
+ply.yacc.YaccError: Unable to construct parser.
diff --git a/test/yacc_unused.py b/test/yacc_unused.py
new file mode 100644
index 0000000..3a61f99
--- /dev/null
+++ b/test/yacc_unused.py
@@ -0,0 +1,78 @@
+# -----------------------------------------------------------------------------
+# yacc_unused.py
+#
+# A grammar with an unused rule
+# -----------------------------------------------------------------------------
+import sys
+sys.tracebacklimit = 0
+
+sys.path.insert(0,"..")
+import ply.yacc as yacc
+
+from calclex import tokens
+
+# Parsing rules
+precedence = (
+ ('left','PLUS','MINUS'),
+ ('left','TIMES','DIVIDE'),
+ ('right','UMINUS'),
+ )
+
+# dictionary of names
+names = { }
+
+def p_statement_assign(t):
+ 'statement : NAME EQUALS expression'
+ names[t[1]] = t[3]
+
+def p_statement_expr(t):
+ 'statement : expression'
+ print t[1]
+
+def p_expression_binop(t):
+ '''expression : expression PLUS expression
+ | expression MINUS expression
+ | expression TIMES expression
+ | expression DIVIDE expression'''
+ if t[2] == '+' : t[0] = t[1] + t[3]
+ elif t[2] == '-': t[0] = t[1] - t[3]
+ elif t[2] == '*': t[0] = t[1] * t[3]
+ elif t[3] == '/': t[0] = t[1] / t[3]
+
+def p_expression_uminus(t):
+ 'expression : MINUS expression %prec UMINUS'
+ t[0] = -t[2]
+
+def p_expression_group(t):
+ 'expression : LPAREN expression RPAREN'
+ t[0] = t[2]
+
+def p_expression_number(t):
+ 'expression : NUMBER'
+ t[0] = t[1]
+
+def p_expression_name(t):
+ 'expression : NAME'
+ try:
+ t[0] = names[t[1]]
+ except LookupError:
+ print "Undefined name '%s'" % t[1]
+ t[0] = 0
+
+def p_expr_list(t):
+ 'exprlist : exprlist COMMA expression'
+ pass
+
+def p_expr_list_2(t):
+ 'exprlist : expression'
+ pass
+
+
+def p_error(t):
+ print "Syntax error at '%s'" % t.value
+
+yacc.yacc()
+
+
+
+
diff --git a/test/yacc_uprec.exp b/test/yacc_uprec.exp
new file mode 100644
index 0000000..eb9a398
--- /dev/null
+++ b/test/yacc_uprec.exp
@@ -0,0 +1,2 @@
+./yacc_uprec.py:38: Nothing known about the precedence of 'UMINUS'
+ply.yacc.YaccError: Unable to construct parser.
diff --git a/test/yacc_uprec.py b/test/yacc_uprec.py
new file mode 100644
index 0000000..0e8711e
--- /dev/null
+++ b/test/yacc_uprec.py
@@ -0,0 +1,64 @@
+# -----------------------------------------------------------------------------
+# yacc_uprec.py
+#
+# A grammar with a bad %prec specifier
+# -----------------------------------------------------------------------------
+import sys
+sys.tracebacklimit = 0
+
+sys.path.insert(0,"..")
+import ply.yacc as yacc
+
+from calclex import tokens
+
+# Parsing rules
+
+# dictionary of names
+names = { }
+
+def p_statement_assign(t):
+ 'statement : NAME EQUALS expression'
+ names[t[1]] = t[3]
+
+def p_statement_expr(t):
+ 'statement : expression'
+ print t[1]
+
+def p_expression_binop(t):
+ '''expression : expression PLUS expression
+ | expression MINUS expression
+ | expression TIMES expression
+ | expression DIVIDE expression'''
+ if t[2] == '+' : t[0] = t[1] + t[3]
+ elif t[2] == '-': t[0] = t[1] - t[3]
+ elif t[2] == '*': t[0] = t[1] * t[3]
+ elif t[3] == '/': t[0] = t[1] / t[3]
+
+def p_expression_uminus(t):
+ 'expression : MINUS expression %prec UMINUS'
+ t[0] = -t[2]
+
+def p_expression_group(t):
+ 'expression : LPAREN expression RPAREN'
+ t[0] = t[2]
+
+def p_expression_number(t):
+ 'expression : NUMBER'
+ t[0] = t[1]
+
+def p_expression_name(t):
+ 'expression : NAME'
+ try:
+ t[0] = names[t[1]]
+ except LookupError:
+ print "Undefined name '%s'" % t[1]
+ t[0] = 0
+
+def p_error(t):
+ print "Syntax error at '%s'" % t.value
+
+yacc.yacc()
+
+
+
+