如何将两个令牌定义为一个令牌?
how to define two tokens as one token?
我试图在我的词法分析器中将由 space 分隔的两个词定义为一个标记
但是当我传递像 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
这是您识别 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
不是那个字典的key(in\sout
是不是同一个字符串),无论怎样都不能识别为关键字t.value
恰好是什么。
但是t.value
也不能是in out
,因为t.value
总是匹配控制t_IDENTIFIER
:
的正则表达式
[a-zA-Z]+([(a-zA-Z)*|(\d+)*|(_*)])*
并且该正则表达式从不匹配具有 space 字符的任何内容。 (该正则表达式有各种问题;第二个字符 class 中的字符 *
、(
、)
、|
和 +
被处理作为普通字符。请参阅下面的正确正则表达式。)
在编辑之前,您当然可以按照与原始问题中建议的方式类似的方式将 in out
匹配为标记。然而,
t_KEYINOUT = r'in\sout'
将不起作用,因为 Ply 不使用常见的 "maximum munch" 算法来决定接受哪个正则表达式模式。相反,它只是对所有模式进行排序并选择第一个匹配的模式,其中顺序包括所有标记化 函数 (按照它们定义的顺序),然后是标记变量按正则表达式长度的相反顺序排序。由于t_IDENTIFIER
是一个函数,它会在变量t_KEYINOUT
之前被尝试。为保证t_KEYINOUT
先试,必须做成函数放在前 t_IDENTIFIER
.
然而,这仍然不是您想要的,因为它会标记化
in outwards
作为
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
我试图在我的词法分析器中将由 space 分隔的两个词定义为一个标记
但是当我传递像 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
这是您识别 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
不是那个字典的key(in\sout
是不是同一个字符串),无论怎样都不能识别为关键字t.value
恰好是什么。
但是t.value
也不能是in out
,因为t.value
总是匹配控制t_IDENTIFIER
:
[a-zA-Z]+([(a-zA-Z)*|(\d+)*|(_*)])*
并且该正则表达式从不匹配具有 space 字符的任何内容。 (该正则表达式有各种问题;第二个字符 class 中的字符 *
、(
、)
、|
和 +
被处理作为普通字符。请参阅下面的正确正则表达式。)
在编辑之前,您当然可以按照与原始问题中建议的方式类似的方式将 in out
匹配为标记。然而,
t_KEYINOUT = r'in\sout'
将不起作用,因为 Ply 不使用常见的 "maximum munch" 算法来决定接受哪个正则表达式模式。相反,它只是对所有模式进行排序并选择第一个匹配的模式,其中顺序包括所有标记化 函数 (按照它们定义的顺序),然后是标记变量按正则表达式长度的相反顺序排序。由于t_IDENTIFIER
是一个函数,它会在变量t_KEYINOUT
之前被尝试。为保证t_KEYINOUT
先试,必须做成函数放在前 t_IDENTIFIER
.
然而,这仍然不是您想要的,因为它会标记化
in outwards
作为
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