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")
Выше приведен код лексера и анализатора, использующий библиотеку ply. Я только что инкапсулировал весь мой код в форме класса. Проблемы, с которыми я сталкиваюсь:
1.) Я пытаюсь передать dict_obj классу анализатора. Я не знаю, что я делаю неправильно и получаю сообщение об ошибке:
AttributeError: 'Parser' object has no attribute 'dict_obj'
2.) Что я пытаюсь сделать?
Я хочу передать этот dict_obj классу синтаксического анализатора, а затем передать его и классу lexer, а затем использовать его в методе lexer - одном из методов токенов (t_FUNC). В этом методе мое регулярное выражение вернет ключи объекта dict obj.
Я думаю, что делаю что-то не так и, следовательно, не могу это реализовать. Пожалуйста, помогите.