在lex中识别关键字对

2 投票
1 回答
1020 浏览
提问于 2025-04-30 00:15

我正在尝试为一种文件类型编写解析器,这种文件使用的是成对的关键字(用空格分隔),但我在正确的实现方式上遇到了一些困难。一些可能的标记示例如下:

angle spring
angle dampen
angle collision

此外,还有块定义和结束该块的标记,例如:

dynamics
    angle spring 1.0
    angle dampen 0.0
    angle collision 0.0
    some 1 2 3
    more ['stuff' 'here']
    tokens "values can be strings, paths, etc"
end dynamics

换行符似乎很重要,我一直在利用它来判断我是在查看关键字还是普通字符串(关键字应该是每行的第一个标记)。我这样做是否正确?我是否应该直接将所有内容进行标记化,并在yacc阶段更严格地定义成对的关键字?

谢谢你的时间!

暂无标签

1 个回答

4

问题在于,你把本来应该看作一个整体的东西,分成了多个部分。如果一个关键字里面有空格,那就说明这些空格也是这个关键字的一部分。

如果你在定义关键字的时候把空格也包括进去,那么在解析的时候就不需要单独处理这些空格了。这意味着你应该把关键字的匹配和普通标识符的匹配分开来处理。

举个例子:

from ply.lex import TOKEN

KEYWORDS = [
    r'some', r'keyword',
    r'keyword with token',
    r'other keyword',
]

keyword = '|'.join(keyword.replace(' ', '\s+') for keyword in KEYWORDS)

@TOKEN(keyword)
def t_KEYWORD(t):
    # remove spaces
    value = ''.join(x for x in t.value if not x.isspace())
    return value.upper()

注意那行 @TOKEN(keyword):你可以通过 TOKEN 装饰器动态设置函数的文档字符串。这允许你使用复杂的正则表达式来定义关键字,即使定义它们“需要”使用表达式,而不是简单的字符串。


另一种方法是把用空格分开的关键字当作多个关键字来处理。所以你可以保留通常的标识符和关键字的定义,并修改你的语法来使用多个关键字,而不是一个。

比如你可以有这样的语法规则:

def p_dynamics(p):
    'DYNAMICS BLOCK END DYNAMICS'

而不是:

def p_dynamics(p):
    'DYNAMICS BLOCK END_DYNAMICS'

根据你的限制条件,有一种解决方案可能更容易实现。

撰写回答