使用PLY为一个解析器实现多个词法分析器?

3 投票
3 回答
1733 浏览
提问于 2025-04-15 15:54

我正在尝试用 PLY 实现一个 Python 解析器,这个解析器是为了 Kconfig 语言而设计的,Kconfig 用于生成 Linux 内核的配置选项。

在这个语言中,有一个叫做 source 的关键字,它的作用是包含其他文件。所以当词法分析器(lexer)遇到这个关键字时,我会改变词法分析器的状态,创建一个新的词法分析器来解析被包含的文件:

def t_begin_source(t):
    r'source '
    t.lexer.begin('source')

def t_source_path(t):
    r'[^\n]+\n+'
    t.lexer.begin('INITIAL') 
    global path
    source_lexer = lex.lex(errorlog=lex.NullLogger())
    source_file_name = (path +  t.value.strip(' \"\n')) 
    sourced_file = file(path + t.value.strip(' \"\n')).read()

    source_lexer.input(sourced_file)

    while True:
        tok = source_lexer.token()
        if not tok:
            break

在其他地方,我有这一行:

lexer = lex.lex(errorlog=lex.NullLogger()) 

这是“主”或“根”词法分析器,它将被解析器调用。

我的问题是,我不知道怎么告诉解析器使用一个不同的词法分析器,或者怎么让“source_lexer”返回一些东西……

也许应该使用克隆(clone)函数……

谢谢

3 个回答

0

好的,

我做的事情是先建立一个所有“标记”的列表,这个列表是在真正解析之前就准备好的。

现在,解析器不再调用词法分析器(lexer),因为你可以在调用解析函数时,通过tokenfunc参数来替代解析器使用的getToken函数。

result = yacc.parse(kconfig,debug=1,tokenfunc=my_function)

而我现在用来获取下一个标记的函数,会遍历之前建立的标记列表。

在进行词法分析时,当我遇到一个源关键字时,我会复制我的词法分析器,并把输入改成包含文件的内容。

def sourcing_file(source_file_name):
    print "SOURCE FILE NAME " , source_file_name
    sourced_file = file(source_file_name).read()
    source_lexer = lexer.clone()
    source_lexer.input(sourced_file)
    print 'END OF SOURCING FILE'

    while True:
        tok = source_lexer.token()
        if not tok:
            break
        token_list.append(tok)
2

有趣的是,我在谷歌搜索中找到的一个链接,正好解释了如何为PLY解析器写自己的词法分析器。这篇文章讲得简单明了,不过主要是涉及四个实例变量和一个token方法。

2

我对PLY的具体细节不太了解,但在我构建的其他类似系统中,使用一个单独的词法分析器来管理包含文件的堆栈是最合理的做法。这样,词法分析器就能在遇到包含文件时,打开和关闭这些文件,并返回一个统一的标记流。

撰写回答