Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Corrected ParserReflect.get_pfunctions on Python 3 #71

Merged
merged 2 commits into from
Aug 25, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions ply/yacc.py
Original file line number Diff line number Diff line change
Expand Up @@ -3108,8 +3108,14 @@ def get_pfunctions(self):
module = inspect.getmodule(item)
p_functions.append((line, module, name, item.__doc__))

# Sort all of the actions by line number
p_functions.sort()
# Sort all of the actions by line number; make sure to stringify
# modules to make them sortable, since `line` may not uniquely sort all
# p functions
p_functions.sort(key=lambda p_function: (
p_function[0],
str(p_function[1]),
p_function[2],
p_function[3]))
self.pfuncs = p_functions

# Validate all of the p_functions
Expand Down
9 changes: 9 additions & 0 deletions test/pkg_test6/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Tests proper sorting of modules in yacc.ParserReflect.get_pfunctions

# Here for testing purposes
import sys
if '..' not in sys.path:
sys.path.insert(0, '..')

from .parsing.calcparse import parser

Empty file.
48 changes: 48 additions & 0 deletions test/pkg_test6/parsing/calclex.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# -----------------------------------------------------------------------------
# calclex.py
# -----------------------------------------------------------------------------

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 %s" % t.value)
t.value = 0
return t

t_ignore = " \t"

def t_newline(t):
r'\n+'
t.lexer.lineno += t.value.count("\n")

def t_error(t):
print("Illegal character '%s'" % t.value[0])
t.lexer.skip(1)

# Build the lexer
import os.path
lexer = lex.lex(optimize=True, outputdir=os.path.dirname(__file__))



33 changes: 33 additions & 0 deletions test/pkg_test6/parsing/calcparse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# -----------------------------------------------------------------------------
# yacc_simple.py
#
# A simple, properly specifier grammar
# -----------------------------------------------------------------------------

from .calclex import tokens
from ply import yacc

# Parsing rules
precedence = (
('left','PLUS','MINUS'),
('left','TIMES','DIVIDE'),
('right','UMINUS'),
)

# dictionary of names
names = { }

from .statement import *

from .expression import *

def p_error(t):
print("Syntax error at '%s'" % t.value)

import os.path
parser = yacc.yacc(outputdir=os.path.dirname(__file__))





31 changes: 31 additions & 0 deletions test/pkg_test6/parsing/expression.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# This file contains definitions of expression grammar

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[2] == '/': 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
9 changes: 9 additions & 0 deletions test/pkg_test6/parsing/statement.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# This file contains definitions of statement grammar

def p_statement_assign(t):
'statement : NAME EQUALS expression'
names[t[1]] = t[3]

def p_statement_expr(t):
'statement : expression'
t[0] = t[1]
8 changes: 8 additions & 0 deletions test/testyacc.py
Original file line number Diff line number Diff line change
Expand Up @@ -441,4 +441,12 @@ def test_pkg_test5(self):
r = parser.parse('3+4+5')
self.assertEqual(r, 12)

def test_pkg_test6(self):
from pkg_test6 import parser
self.assertTrue(os.path.exists('pkg_test6/parsing/parsetab.py'))
self.assertTrue(os.path.exists('pkg_test6/parsing/lextab.py'))
self.assertTrue(os.path.exists('pkg_test6/parsing/parser.out'))
r = parser.parse('3+4+5')
self.assertEqual(r, 12)

unittest.main()