在 ply LALR 解析器上需要帮助
Need help on ply LALR parser
我正在尝试使用 ply 构建脚本工具。但是我被一些解析错误阻止了。通过将那些 p_xxx 函数移动到不同的地方,我得到了不同的语法错误。有哪位大侠帮忙帮忙吗?
例如
如果我在其他 p_xxx 函数之后移动 p_funcall,那么我得到:
Syntax error at '(', lineno 4, pos 8, data '
fun(arg1,arg2,arg3)
'
下面是源代码:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
__version__ = '3.16'
import sys
sys.path.insert(0, "..")
import ply.lex as lex
import ply.yacc as yacc
import os
import dumper
class TdsParser(object):
'''
Base class for a lexer/parser that has the rules defined as methods
'''
def __init__(self, **kw):
self.debug = kw.get('debug', 0)
self.names = {}
try:
modname = os.path.split(os.path.splitext(__file__)[0])[
1] + "_" + self.__class__.__name__
except:
modname = "parser" + "_" + self.__class__.__name__
self.debugfile = modname + ".dbg"
self.tabmodule = modname + "_" + "parsetab"
print(self.debugfile, self.tabmodule)
# Build the lexer and parser
self.lexer = lex.lex(module=self, debug=self.debug)
self.yaccer = yacc.yacc(module=self,
debug=self.debug,
debugfile=self.debugfile,
tabmodule=self.tabmodule)
tokens = (
'COMMA', 'COLON',
'LPAREN', 'RPAREN', 'LBRACE', 'RBRACE',
'ATOM', 'NUMBER',
)
# Tokens
# Tokens
t_COMMA = r','
t_COLON = r':'
def t_LPAREN(self, t):
r'\('
return t
def t_RPAREN(self, t):
r'\)'
return t
def t_ATOM(self, t):
r'[a-zA-Z_][a-zA-Z0-9_]*'
return t
def t_NUMBER(self, t):
r'\d+|0[Bb][01]+|0[oO][0-7]|0[xX][a-f0-9]'
return t
def t_newline(self, t):
r'\n+'
t.lexer.lineno += len(t.value)
t_ignore = ' \t'
def t_error(self, t):
print("Illegal character '%s', lineno %d, pos %d, data '%s'"
% (t.value, t.lexer.lineno, t.lexer.lexpos, t.lexer.lexdata))
t.lexer.skip(1)
def t_COMMENT(self, t):
r'\#.*'
pass
#yacc parser
def p_funcall(self, p):
'''
funcall : ATOM LPAREN arglist RPAREN
| ATOM LPAREN RPAREN
'''
print("\n###", sys._getframe().f_code.co_name, "###\n")
pass
def p_varlist(self, p) :
'''
varlist : varlist expression
| expression
'''
print("\n###", sys._getframe().f_code.co_name, "###\n")
pass
def p_arglist(self, p) :
'''
arglist : arglist COMMA expression
| expression
'''
print("\n###", sys._getframe().f_code.co_name, "###\n")
pass
def p_expression(self, p) :
'''
expression : ATOM
| NUMBER
'''
print("\n###", sys._getframe().f_code.co_name, "###\n")
dumper.dump(p[1])
pass
def p_error(self, p):
if p:
#dumper.dump(p)
print("Syntax error at '%s', lineno %d, pos %d, data '%s'"
% (p.value, p.lexer.lineno, p.lexer.lexpos, p.lexer.lexdata))
else:
print("Syntax error at EOF")
def yacc_input(self, data):
self.yaccer.parse(data)
if __name__ == "__main__":
data = 'fun(arg1,arg2,arg3)'
tdsparser = TdsParser()
tdsparser.yacc_input(data)
谢谢。
您文件中第一个解析器函数中的第一个产生式定义了解析的目标:每次调用时,解析器都会尝试解析 start 非终端的单个实例。
正如问题中所写,解析器将识别(单个)funcall
。但是如果你将 p_funcall
移到别处,你最终会生成一个试图匹配不同起始符号的解析器。如果你不移动任何其他东西,那将是 varlist
,你的输入看起来一点也不像 varlist
。
您也可以显式声明开始符号。有关详细信息,请参阅 Ply manual。
我正在尝试使用 ply 构建脚本工具。但是我被一些解析错误阻止了。通过将那些 p_xxx 函数移动到不同的地方,我得到了不同的语法错误。有哪位大侠帮忙帮忙吗?
例如 如果我在其他 p_xxx 函数之后移动 p_funcall,那么我得到:
Syntax error at '(', lineno 4, pos 8, data ' fun(arg1,arg2,arg3) '
下面是源代码:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
__version__ = '3.16'
import sys
sys.path.insert(0, "..")
import ply.lex as lex
import ply.yacc as yacc
import os
import dumper
class TdsParser(object):
'''
Base class for a lexer/parser that has the rules defined as methods
'''
def __init__(self, **kw):
self.debug = kw.get('debug', 0)
self.names = {}
try:
modname = os.path.split(os.path.splitext(__file__)[0])[
1] + "_" + self.__class__.__name__
except:
modname = "parser" + "_" + self.__class__.__name__
self.debugfile = modname + ".dbg"
self.tabmodule = modname + "_" + "parsetab"
print(self.debugfile, self.tabmodule)
# Build the lexer and parser
self.lexer = lex.lex(module=self, debug=self.debug)
self.yaccer = yacc.yacc(module=self,
debug=self.debug,
debugfile=self.debugfile,
tabmodule=self.tabmodule)
tokens = (
'COMMA', 'COLON',
'LPAREN', 'RPAREN', 'LBRACE', 'RBRACE',
'ATOM', 'NUMBER',
)
# Tokens
# Tokens
t_COMMA = r','
t_COLON = r':'
def t_LPAREN(self, t):
r'\('
return t
def t_RPAREN(self, t):
r'\)'
return t
def t_ATOM(self, t):
r'[a-zA-Z_][a-zA-Z0-9_]*'
return t
def t_NUMBER(self, t):
r'\d+|0[Bb][01]+|0[oO][0-7]|0[xX][a-f0-9]'
return t
def t_newline(self, t):
r'\n+'
t.lexer.lineno += len(t.value)
t_ignore = ' \t'
def t_error(self, t):
print("Illegal character '%s', lineno %d, pos %d, data '%s'"
% (t.value, t.lexer.lineno, t.lexer.lexpos, t.lexer.lexdata))
t.lexer.skip(1)
def t_COMMENT(self, t):
r'\#.*'
pass
#yacc parser
def p_funcall(self, p):
'''
funcall : ATOM LPAREN arglist RPAREN
| ATOM LPAREN RPAREN
'''
print("\n###", sys._getframe().f_code.co_name, "###\n")
pass
def p_varlist(self, p) :
'''
varlist : varlist expression
| expression
'''
print("\n###", sys._getframe().f_code.co_name, "###\n")
pass
def p_arglist(self, p) :
'''
arglist : arglist COMMA expression
| expression
'''
print("\n###", sys._getframe().f_code.co_name, "###\n")
pass
def p_expression(self, p) :
'''
expression : ATOM
| NUMBER
'''
print("\n###", sys._getframe().f_code.co_name, "###\n")
dumper.dump(p[1])
pass
def p_error(self, p):
if p:
#dumper.dump(p)
print("Syntax error at '%s', lineno %d, pos %d, data '%s'"
% (p.value, p.lexer.lineno, p.lexer.lexpos, p.lexer.lexdata))
else:
print("Syntax error at EOF")
def yacc_input(self, data):
self.yaccer.parse(data)
if __name__ == "__main__":
data = 'fun(arg1,arg2,arg3)'
tdsparser = TdsParser()
tdsparser.yacc_input(data)
谢谢。
您文件中第一个解析器函数中的第一个产生式定义了解析的目标:每次调用时,解析器都会尝试解析 start 非终端的单个实例。
正如问题中所写,解析器将识别(单个)funcall
。但是如果你将 p_funcall
移到别处,你最终会生成一个试图匹配不同起始符号的解析器。如果你不移动任何其他东西,那将是 varlist
,你的输入看起来一点也不像 varlist
。
您也可以显式声明开始符号。有关详细信息,请参阅 Ply manual。