我正在使用 lex 和 yacc 定义一种新语言。词法分析器工作正常,但解析器却不行。我认为问题是语法无法识别标记,但经过大量研究和试验后,我确实陷入了困境。我不太确定语法是否完全正确。我从解析器收到“输入中的语法错误”,但数据中没有语法错误。
输入的数据是:
F 100
这是此语法的另一个示例:
L 36 [L 4 [F 100 R 90] R 10]
我的词法分析器(lexing.py)代码:
import lex
tokens = (
'NUMBER',
'RED',
'GREEN',
'BLUE',
'BLACK',
'FORW',
'RIGHT',
'LOOP',
'COLOR',
'PEN',
'LSQB',
'RSQB',
'EMPTY'
)
t_FORW = r'F'
t_RIGHT = r'R'
t_LOOP = r'L'
t_COLOR = r'COLOR'
t_PEN = r'PEN'
t_LSQB = r'\['
t_RSQB = r'\]'
t_RED = r'K'
t_GREEN = r'Y'
t_BLUE = r'M'
t_BLACK = r'S'
t_EMPTY = r'\ '
def t_NUMBER(t):
r'\d+'
t.value = int(t.value)
return t
def t_newline(t):
r'\n+'
t.lexer.lineno += len(t.value)
t_ignore = ' \t'
def t_error(t):
print("Illegal character '%s'" % t.value[0])
t.lexer.skip(1)
lexer = lex.lex()
data = '''
F 100
'''
lexer.input(data)
for tok in lexer:
print(tok)
这是解析代码:
import yacc
from lexing import tokens
def p_root(p):
'''root : function NUMBER option
| COLOR colors option
| PEN NUMBER option '''
def p_option(p):
'''option : root
| LSQB root RSQB root
| EMPTY '''
def p_function(p):
'''function : FORW
| RIGHT
| LOOP '''
def p_colors(p):
'''colors : RED
| BLUE
| GREEN
| BLACK '''
def p_error(p):
print("Syntax error in input!")
from lexing import data
# Build the parser
parser=yacc.yacc()
result=parser.parse(data)
#print (result)
我尝试了所有我知道的方法。如您所见,我还没有编写 p 参数,但尝试编写这并不是解决方案。真正的问题可能是什么?
最佳答案
眼前的问题是您使用 EMPTY
作为标记(单个空格字符)。该定义与 t_ignore
中的忽略字符列表冲突,这也会成为一个问题。但请注意,您的输入末尾没有空格字符(输入以换行符结尾,该换行符将被忽略),并且您的语法要求 option
以 EMPTY
结尾。这肯定会产生语法错误。 (在这个答案的第一个版本中,我说 t_ignore
被显式标记模式覆盖,但事实证明我错了。您可以在内部使用被忽略的字符一条规则,但不在开头;以被忽略的字符开头的标记永远不会匹配。)
特别是如果这是您的第一个项目,您应该遵循更系统的调试技术。首先确保输入按照您期望的方式进行标记,而不尝试解析标记流。当您开始解析流时,请确保任何语法错误都会报告产生错误的标记,包括其在输入中的位置。
词法分析器和解析器都可以使用关键字参数debug=True
来调用,这将提供解析器操作的调试日志。这绝对应该是您调试的一部分。
尽管如此,我觉得你的语法对于确定输入的结构并不是很有用。良好的语法读取方式与您用自己的语言描述输入的方式相同,其中可能包括如下描述:
- 输入是命令列表。
- 命令可以是正向命令、向右命令……或循环命令。
- 转发命令是一个
F
后跟一个数字。 - 循环命令是一个
L
后跟一个数字,后跟[
和]
内的命令列表。
关于python - 为什么我定义的语法不使用标记?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72317628/