处理对上下文敏感的重叠词法分析器模式的最佳方法是什么?

What is the best way to handle overlapping lexer patterns that are sensitive to context?

我正在尝试编写用于解析 C4 DSL 的 Antlr 语法。然而,DSL 有许多语法非常开放的地方,导致词法分析器规则重叠(在多个标记规则匹配的意义上)。

例如,workspace rule can have a child properties 元素定义 <name> <value> 对。这是一个有效的文件:

workspace "Name" "Description" {
    properties {
        xyz "a string property"
        nonstring nodoublequotes
    }
}

我 运行 遇到的问题是 <name><value> 的规则必须非常广泛,基本上除了空格之外的任何内容。此外,带有双引号的空格的属性将匹配我的 STRING 令牌。

我目前的解决方案是下面的语法,使用 property_element: BLOB | STRING; 匹配值,使用 BLOB 匹配名称。这里有更好的方法吗?如果我可以制作上下文敏感的词法分析器标记,我会制作 NAMEVALUE 标记。在实际语法中,我为 workspaceproperties 之类的想法定义了不区分大小写的名称标记。这使我可以轻松地匹配现有的 DSL 语义,但会出现 属性 名称或 workspace 的值将标记化为 K_WORKSPACE.

的问题
grammar c4mce;

workspace : 'workspace' (STRING (STRING)?)?  '{' NL workspace_body '}';

workspace_body : (workspace_element NL)* ;
workspace_element: 'properties' '{' NL (property_element NL)* '}';

property_element: BLOB property_value;
property_value : BLOB | STRING;

BLOB: [\p{Alpha}]+;
STRING: '"' (~('\n' | '\r' | '"' | '\') | '\\' | '\"')* '"';
NL: '\r'? '\n';
WS: [ \t]+ -> skip;

这标记化为

[@0,0:8='workspace',<'workspace'>,1:0]
[@1,10:15='"Name"',<STRING>,1:10]
[@2,17:29='"Description"',<STRING>,1:17]
[@3,31:31='{',<'{'>,1:31]
[@4,32:32='\n',<NL>,1:32]
[@5,37:46='properties',<'properties'>,2:4]
[@6,48:48='{',<'{'>,2:15]
[@7,49:49='\n',<NL>,2:16]
[@8,58:60='xyz',<BLOB>,3:8]
[@9,62:80='"a string property"',<STRING>,3:12]
[@10,81:81='\n',<NL>,3:31]
[@11,90:98='nonstring',<BLOB>,4:8]
[@12,100:113='nodoublequotes',<BLOB>,4:18]
[@13,114:114='\n',<NL>,4:32]
[@14,119:119='}',<'}'>,5:4]
[@15,120:120='\n',<NL>,5:5]
[@16,121:121='}',<'}'>,6:0]
[@17,122:122='\n',<NL>,6:1]
[@18,123:122='<EOF>',<EOF>,7:0]

一切都很好,我想这与 DSL 语法给我的一样多。有没有更好的方法来处理这种情况? 当我扩展语法时,我希望有很多 BLOB 标记,因为在词法分析器中创建一个更窄的标记是没有意义的,因为 BLOB 会匹配。

这是经典的keywords-as-identifier问题。如果您希望特定的字符组合(被词法化为关键字)也可以在某些地方用作普通标识符,那么您必须将此关键字列为可能的替代项。例如:

property_element: (BLOB | K_WORKSPACE) property_value;
property_value : BLOB | STRING | K_WORKSPACE;