import operator
import re
from ply import lex, yacc
class Lexer(object):
tokens = [
'COMMA',
'TILDE',
'PARAM',
'LP',
'RP',
'FUNC'
]
# Regular expression rules for simple tokens
t_COMMA = r'\,'
t_TILDE = r'\~'
t_PARAM = r'[^\s\(\),&:\"\'~]+'
def __init__(self, dict_obj):
self.dict_obj = dict_obj
def t_LP(self, t):
r'\('
return t
def t_RP(self, t):
r'\)'
return t
def t_FUNC(self, t):
# I want to generate token for this FUNC from the keys of model map
# For eg: r'key1|key2'
r'(?i)FUNC'
return t
# Define a rule so we can track line numbers
def t_newline(self, t):
r'\n+'
t.lexer.lineno += len(t.value)
# A string containing ignored characters (spaces and tabs)
t_ignore = ' \t'
# Error handling rule
def t_error(self, t):
print("Illegal character '%s' on line %d, column %d" % (t.value[0], t.lexer.lineno, t.lexer.lexpos))
t.lexer.skip(1)
# Build the lexer
def build_lexer(self, **kwargs):
self.lexer = lex.lex(module=self, **kwargs)
return self.lexer
class Parser(object):
tokens = Lexer.tokens
def __init__(self, **kwargs):
self.parser = yacc.yacc(module=self, **kwargs)
self.lexer = None
self._dict_obj = None
self.error = ""
self.result = ""
@property
def dict_obj(self):
return self._dict_obj
@dict_obj.setter
def dict_obj(self, dict_obj):
self._dict_obj = dict_obj
self.lexer = Lexer(self._dict_obj).build_lexer()
# Handles LP expression RP
def p_expression(self, p):
"""
expression : LP expression RP
"""
# Handles TILDE PARAM - call search
def p_tilde_param(self, p):
"""
expression : TILDE PARAM
"""
p[0] = p[2]
return p[0]
# Handles ANY LP PARAM RP - call search
def p_expression_any(self, p):
"""
expression : FUNC LP PARAM RP
"""
p[0] = p[3]
return p[0]
# Error handling rule
def p_error(self, p):
if p:
stack_state_str = " ".join([symbol.type for symbol in self.parser.symstack[1:]])
self.error = "Syntax error at %s, type %s, on line %d, Parser state: %s %s . %s" % (
p.value, p.type, p.lineno, self.parser.state, stack_state_str, p
)
else:
self.error = "SYNTAX ERROR IN INPUT"
def get_result(self, input_):
input_ = input_.strip()
if input_:
self.result = self.parser.parse(input_, lexer=self.lexer)
return self.result
else:
raise ValueError("EMPTY EXPRESSION ERROR")
def parser(input_):
par_obj = Parser()
par_obj.dict_obj = {
'key1' : 'value1',
'key2' : 'value2'
}
return par_obj.get_result(input_)
result = parser("~hello")
上面是使用层库的词法分析器和解析器的代码。我刚刚将所有代码封装为类形式。我面临的问题:
1。)我正在尝试将dict_obj传递给解析器类。我不知道我在做错什么,并得到类似这样的错误:
AttributeError: 'Parser' object has no attribute 'dict_obj'
2。)我要做什么?
我想将此dict_obj传递给解析器类,然后也将其传递给lexer类,然后在Tokener方法(t_FUNC)方法之一的lexer中使用它。在这种方法中,我的正则表达式将返回此dict obj的键。
我认为我做错了什么,因此无法实现。请帮忙。
答案 0 :(得分:0)
在__init__
对象的构造函数(Parser
中,您要求Ply在完全构造Parser
对象之前生成解析器:
def __init__(self, **kwargs):
self.parser = yacc.yacc(module=self, **kwargs)
# This is the critical line:
self._dict_obj = None
为了从对象(yacc.yacc(module=self)
)构造解析器,Ply需要遍历对象的所有属性。例如,它需要找到所有解析器函数以便提取其文档字符串以确定语法。
Ply使用内置的dir
函数来创建一个包含所有对象属性的字典。由于您的Parser
对象具有自定义属性dict_obj
,因此该键是从dir
返回的,因此Ply尝试使用其值缓存该属性。但是,当它调用gettattr(module, 'dict_obj')
时,将调用getter,并且getter尝试返回self._dict_obj
。但是,self._dict_obj
尚未定义,因此最终会引发错误:
AttributeError: 'Parser' object has no attribute '_dict_obj'
请注意,这不是不是您在问题中报告的错误消息;该错误表明没有属性dict_obj
。也许那是复制粘贴错误。
如果将呼叫移至yacc.yacc
到初始化程序的末尾,则该特定问题将消失:
def __init__(self, **kwargs):
self.lexer = None
self._dict_obj = None
self.error = ""
self.result = ""
self.parser = yacc.yacc(module=self, **kwargs)
但是,代码摘录中还有许多其他问题,使得很难验证此解决方案。这些包括:
没有LexerNmsysSearch
。我以为你是说Lexer
。
没有node_expression
。我不知道那应该是什么,所以我只是删除了测试。
您的语法与您正在测试的输入不匹配,因此解析器会立即引发语法错误。我将输入更改为"(~hello)"
,以尝试产生可解析的内容。
解析器操作未设置语义值,因此self.parse.parse()
不返回任何值。这会导致get_result
引发错误。
那时候,我放弃了尝试从代码中产生任何有意义的东西。为将来参考,请确保正确引用错误消息,并且可以运行问题中包含的示例代码。