我试图在我的词法分析器中定义两个由空格分隔的单词作为一个标记
但当我传递in out
之类的输入时,它会显示LexToken(KEYIN,'in',1,0)
和LexToken(KEYOUT,'out',1,3)
我需要它像LexToken(KEYINOUT,'in out',1,0)
PS:KEYIN
和KEYOUT
是两个不同的标记,因为语法的定义
以下是导致问题的测试:
import lex
reserved = {'in': 'KEYIN', 'out': 'KEYOUT', 'in\sout': 'KEYINOUT'} # the problem is in here
tokens = ['PLUS', 'MINUS', 'IDENTIFIER'] + list(reserved.values())
t_MINUS = r'-'
t_PLUS = r'\+'
t_ignore = ' \t'
def t_IDENTIFIER(t):
r'[a-zA-Z]+([(a-zA-Z)*|(\d+)*|(_*)])*'
t.type = reserved.get(t.value, 'IDENTIFIER') # Check for reserved words
return t
def t_error(t):
print("Illegal character '%s'" % t.value[0], "at line", t.lexer.lineno, "at position", t.lexer.lexpos)
t.lexer.skip(1)
lex.lex()
lex.input("in out inout + - ")
while True:
tok = lex.token()
print(tok)
if not tok:
break
输出:
LexToken(KEYIN,'in',1,0)
LexToken(KEYOUT,'out',1,3)
LexToken(IDENTIFIER,'inout',1,7)
LexToken(PLUS,'+',1,13)
LexToken(MINUS,'-',1,15)
None
答案 0 :(得分:0)
这是您识别IDENTIFIER
和关键字的功能:
def t_IDENTIFIER(t):
r'[a-zA-Z]+([(a-zA-Z)*|(\d+)*|(_*)])*'
t.type = reserved.get(t.value, 'IDENTIFIER') # Check for reserved words
return t
首先,很明显它能够识别的关键字正是字典reserved
的关键字,它们是:
in
out
in\sout
由于in out
不是该字典中的键(in\sout
不是相同的字符串),因此无论{{1}是什么t.value
都无法将其识别为关键字碰巧是。
但t.value
也不能in out
,因为t.value
将始终与控制t_IDENTIFIER
的正则表达式匹配:
[a-zA-Z]+([(a-zA-Z)*|(\d+)*|(_*)])*
并且正则表达式永远不会匹配任何带空格字符的内容。 (该正则表达式存在各种问题;第二个字符类中的字符*
,(
,)
,|
和+
被视为普通字符。请参阅下面的正确的正则表达式。)
您可以在编辑之前以与原始问题中建议的方式类似的方式将in out
作为令牌进行匹配。然而,
t_KEYINOUT = r'in\sout'
不起作用,因为Ply不使用常见的“最大munch”算法来决定接受哪个正则表达式模式。相反,它只是命令所有模式并选择匹配的第一个模式,其中顺序包含所有标记化函数(按照它们的定义顺序),然后是标记变量以正则表达式长度的相反顺序排序。由于t_IDENTIFIER
是一个函数,因此将在变量t_KEYINOUT
之前尝试。为确保首先尝试t_KEYINOUT
,必须将其设置为一个函数,然后将放在 t_IDENTIFIER
之前。
然而,这仍然不是你想要的,因为它会标记化
in outwards
as
LexToken(KEYINOUT,'in out',1,0)
LexToken(IDENTIFIER,'wards',1,6)
而不是
LexToken(KEYIN,'in',1,0)
LexToken(IDENTIFIER,'outwards',1,3)
要获得正确的分析,您需要确保in out
仅在out
为完整字词时才匹配;换句话说,如果在比赛结束时有一个单词边界。所以一个解决方案是:
reserved = {'in': 'KEYIN', 'out': 'KEYOUT'}
def t_KEYINOUT(t):
r'in\sout\b'
return t
def t_IDENTIFIER(t):
r'[a-zA-Z][a-zA-Z0-9_]*'
t.type = reserved.get(t.value, 'IDENTIFIER') # Check for reserved words
return t
但是,词法分析器将in out
识别为单个标记几乎肯定不是必要。由于in
和out
都是关键字,因此很容易将它留给解析器注意它们何时作为in out
指示符一起使用:
parameter: KEYIN IDENTIFIER
| KEYOUT IDENTIFIER
| KEYIN KEYOUT IDENTIFIER