Parsing 手动解析简单语法

Parsing 手动解析简单语法,parsing,grammar,context-free-grammar,text-parsing,Parsing,Grammar,Context Free Grammar,Text Parsing,我需要实现一个简单的解析器来解析以下字符串: a[b[c,d],e],f[g,h[i],j[k,l] 在上面的示例中,有一组一个或多个对象。 每个对象都有嵌套对象(a中的b和h,f中的j)加上嵌套值(c、d、e、g、i、k、l) 所以,它有点像: GROUP : OBJECT (,OBJECT)* OBJECT: NAME '[' OBJECTorVALUE (OBJECTorVALUE)* ']' OBJECTorVALUE: OBJECT | VALUE VALUE : NAME 手动解析

我需要实现一个简单的解析器来解析以下字符串: a[b[c,d],e],f[g,h[i],j[k,l]

在上面的示例中,有一组一个或多个对象。 每个对象都有嵌套对象(a中的b和h,f中的j)加上嵌套值(c、d、e、g、i、k、l)

所以,它有点像:

GROUP : OBJECT (,OBJECT)*
OBJECT: NAME '[' OBJECTorVALUE (OBJECTorVALUE)* ']'
OBJECTorVALUE: OBJECT | VALUE
VALUE : NAME
手动解析此类语法的最简单方法是什么

我尝试用递归下降解析器解析它,它是可行的,但看起来很奇怪,因为您必须解析OBJECTorVALUE的产品:

OBJECTorVALUE: NAME '[' blabla ']'
OBJECTorVALUE: NAME
因此,要使其成为LL语法(由rec descent解析),我们应该将其解析为

OBJECTorVALUE: NAME Z
Z: eps | '[' blabla ']'
现在rec desc parser变得有些不必要的复杂性,感觉很不自然,所以我必须介绍一种rec desc方法来在名称后面查找Z。所以,不是简单的简单方法

parseGroup -> parseObjects 
parseObj -> parseName consume[ parseObjectValueGroup consume ]
parseObjectValueGroup -> parseObjectValues
parseObjectValue -> look('[') -> parseObj OR parseValue
我得到了同样的结果,但最后一句话变成了

parseObjectValue -> parseName parseZ
parseZ -> look('[') -> parseObjWithoutName OR return empty
parseObjWithoutName -> ...

我觉得这很混乱,我们能用更简单的吗?我的意思是,这是一个非常简单的语法,甚至可以通过字符串拆分来解析,看起来非常简单。也许简单LR解析器(SLR)在这种情况下会更具可读性?

我实际上认为尝试从上到下解析这种方法不会太糟糕。如果你试着把它写成正式语法,它看起来比实际情况糟糕得多。例如,以下是伪代码中的情况:

ParseGroup():
    result = empty list
    while true:
        read token 'next'; it's some identifier.
        if (there's no next token) {
           append 'next' to result.
           break;
        }
        else if (the next token is '[') {
           let inner = ParseGroup();
           read token; it's a ']';
           append 'next[inner]' to result.
        } else {
           append 'next' to result.
        }
        read token; it's a comma.
        append ',' to result.
    }
}

这基本上是一个经过轻微修改的LL(1)解析器,用于修改语法。

这确实是一个非常简单的语法。您的语法不完整,因为未定义
NAME
。ABNF(RFC 5234)语法中定义的语法如下(假设名称规则):

您可以这样理解:一个组由逗号分隔的元素组成。每个元素都有一个名称,可能在它后面的方括号中有一个子元素组。“名称”是一个或多个英文字母。在语法的每个部分之间都有允许的空白(零或更多):空格(20十六进制)、制表符(9十六进制)、换行符(A十六进制)或回车符(D十六进制)。如果不需要空白,只需完全删除WS-rule即可

这是语法,但有语法和语义:如果
元素
只有名称,那么它是
,否则它是
对象
。这是一个简单的消歧,应该在解析完成后进行

<>如果语法很简单,你不想自己编码,我已经制作了一个工具(TeaveScript Studio),它可以为C++生成语法。语法很简单,因此该工具的演示应该足够了。你也可以在线运行语法。TGS生成迭代解析器,这意味着,如果您的组嵌套过多,您不必担心堆栈溢出问题

另外,您还可以编写
1*('a'-'z'/'a'-'z')
,而不是十六进制值,因为TGS扩展了ABNF语法,使编写语法变得简单

group   = element *("," WS element)
element = name WS ["[" WS group "]" WS]
name    = 1*(%x61-7A / %x41-5A)
WS      = *(%x20 / %x9 / %xA / %xD)