解析含任意元数据的关系声明时的语法分析问题求助
解决嵌套块中关系声明的语法歧义问题
问题场景
示例文件结构如下:
blockA { uniqueName42 -> uniqueName aWord1 anotherWord "Some text" anotherUniqueName -> uniqueName23 aWord2 blockB { thing -> anotherThing } }
文件支持任意嵌套层级的块,带->的行定义两个对象间的关系,每个关系可包含任意数量的可选元数据(无引号的单个单词或带引号的多词文本)。
当前语法规则如下:
block : BLOCK LBRACE relationshipDeclaration* RBRACE ; relationshipDeclaration : StringLiteral? ARROW StringLiteral StringLiteral* ;
问题:由于元数据数量不固定,解析器会将下一个关系的起始标识符(比如示例中的anotherUniqueName)识别为上一个关系的元数据,而非新关系的开头。
解决方案(避免使用词法模式)
1. 修正基础结构+否定向前断言
原规则中StringLiteral?的设计不符合实际语法——每个关系声明都以起始标识符开头,而非可选。在此基础上,通过否定向前断言过滤元数据:确保匹配的元数据后面不会紧跟->,让解析器把带->的标识符留给下一个关系声明。
以ANTLR语法为例,修改后的规则:
block : BLOCK LBRACE relationshipDeclaration* RBRACE ; relationshipDeclaration : StringLiteral ARROW StringLiteral (StringLiteral {!_input.LT(1).getText().equals("->")}?)* ;
这里的{!_input.LT(1).getText().equals("->")}?是向前检查逻辑:当前匹配的StringLiteral之后的第一个token如果是->,就不将其作为当前关系的元数据。
2. 利用行终止符辅助分割(依赖格式规范)
如果你的文件中每个关系声明都独占一行,可以在规则中加入换行符检查,强制解析器在遇到换行或块结束符时终止当前关系声明。示例规则:
block : BLOCK LBRACE relationshipDeclaration* RBRACE ; relationshipDeclaration : StringLiteral ARROW StringLiteral StringLiteral* (NEWLINE | RBRACE) ;
这种方法实现简单,但依赖严格的格式规范,若存在跨多行的关系声明则不适用。
3. 显式定义元数据的终止条件
可以将元数据规则明确为“任意不触发新关系的元素”,通过语法规则区分:元数据不能是后跟->的标识符。部分语法分析器支持更简洁的否定向前看语法,具体写法需参考你使用的解析器文档。
内容的提问来源于stack exchange,提问作者ct_
相关产品推荐
相关产品推荐

