我正在使用ply(Lex和Yacc的流行python实现)为自定义语言创建简单的编译器。
目前我的词法分析器如下所示:
reserved = {
'begin': 'BEGIN',
'end': 'END',
'DECLARE': 'DECL',
'IMPORT': 'IMP',
'Dow': 'DOW',
'Enddo': 'ENDW',
'For': 'FOR',
'FEnd': 'ENDF',
'CASE': 'CASE',
'WHEN': 'WHN',
'Call': 'CALL',
'THEN': 'THN',
'ENDC': 'ENDC',
'Object': 'OBJ',
'Move': 'MOV',
'INCLUDE': 'INC',
'Dec': 'DEC',
'Vibration': 'VIB',
'Inclination': 'INCLI',
'Temperature': 'TEMP',
'Brightness': 'BRI',
'Sound': 'SOU',
'Time': 'TIM',
'Procedure': 'PROC'
}
tokens = ["INT", "COM", "SEMI", "PARO", "PARC", "EQ", "NAME"] + list(reserved.values())
t_COM = r'//'
t_SEMI = r";"
t_PARO = r'\('
t_PARC = r'\)'
t_EQ = r'='
t_NAME = r'[a-z][a-zA-Z_&!0-9]{0,9}'
def t_INT(t):
r'\d+'
t.value = int(t.value)
return t
def t_error(t):
print("Syntax error: Illegal character '%s'" % t.value[0])
t.lexer.skip(1)
Per the documentation,我正在为保留关键字创建字典,然后将它们添加到tokens
列表中,而不是为其添加单独的规则。该文档还指出,优先级是根据以下2条规则确定的:
我遇到的问题是,当我使用此测试字符串测试词法分析器时
testInput = "// ; begin end DECLARE IMPORT Dow Enddo For FEnd CASE WHEN Call THEN ENDC (asdf) = Object Move INCLUDE Dec Vibration Inclination Temperature Brightness Sound Time Procedure 985568asdfLYBasdf ; Alol"
词法分析器返回以下错误:
LexToken(COM,'//',1,0) LexToken(SEMI,';',1,2) LexToken(NAME,'begin',1,3) Syntax error: Illegal character ' ' LexToken(NAME,'end',1,9) Syntax error: Illegal character ' ' Syntax error: Illegal character 'D' Syntax error: Illegal character 'E' Syntax error: Illegal character 'C' Syntax error: Illegal character 'L' Syntax error: Illegal character 'A' Syntax error: Illegal character 'R' Syntax error: Illegal character 'E'
(这不是全部错误,但足以了解发生了什么事情
由于某种原因,Lex在解析关键字之前先解析NAME
令牌。即使完成解析NAME
令牌后,它也无法识别DECLARE
保留关键字。我还尝试过使用正则表达式在其余的令牌中添加保留关键字,但得到的结果是相同的(文档也建议不要这样做)。
有人知道如何解决此问题吗?我希望Lexer首先识别保留的关键字,然后尝试对其余输入进行标记。
谢谢!
编辑:
即使使用文档中示例的t_ID函数,我也会得到相同的结果:
def t_NAME(t):
r'[a-z][a-zA-Z_&!0-9]{0,9}'
t.type = reserved.get(t.value,'NAME')
return t
答案 0 :(得分:1)
这里的主要问题是您没有忽略空格;所有错误都是后果。在语法中添加t_ignore
definition可以消除这些错误。
但是即使您解决了空白问题,该语法也无法按预期运行,因为您似乎缺少该文档的重要方面,该方面告诉您如何实际使用字典reserved
:>
要处理保留字,您应该编写一条规则以匹配标识符,并在类似这样的函数中进行特殊的名称查找:
reserved = {
'if' : 'IF',
'then' : 'THEN',
'else' : 'ELSE',
'while' : 'WHILE',
...
}
tokens = ['LPAREN','RPAREN',...,'ID'] + list(reserved.values())
def t_ID(t):
r'[a-zA-Z_][a-zA-Z_0-9]*'
t.type = reserved.get(t.value,'ID') # Check for reserved words
return t
(在您的情况下,它将是NAME
,而不是ID
。)
Ply对字典reserved
一无所知,并且也不知道如何生成tokens
中枚举的令牌名称。 tokens
的唯一要点是让Ply知道语法中的哪些符号表示标记,哪些符号表示非终结符。 tokens
中有一个单词这一事实本身并不能为该令牌定义模式。