Parsing Ebnf&x2013;这是LL(1)语法吗?

Parsing Ebnf&x2013;这是LL(1)语法吗?,parsing,ebnf,ll,Parsing,Ebnf,Ll,我在维基百科上找到了以下描述EBNF的内容: letter = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" ; digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7"

我在维基百科上找到了以下描述EBNF的内容:

letter = "A" | "B" | "C" | "D" | "E" | "F" | "G"
   | "H" | "I" | "J" | "K" | "L" | "M" | "N"
   | "O" | "P" | "Q" | "R" | "S" | "T" | "U"
   | "V" | "W" | "X" | "Y" | "Z" ;
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
symbol = "[" | "]" | "{" | "}" | "(" | ")" | "<" | ">"
   | "'" | '"' | "=" | "|" | "." | "," | ";" ;
character = letter | digit | symbol | "_" ;

identifier = letter , { letter | digit | "_" } ;
terminal = "'" , character , { character } , "'" 
     | '"' , character , { character } , '"' ;

lhs = identifier ;
rhs = identifier
 | terminal
 | "[" , rhs , "]"
 | "{" , rhs , "}"
 | "(" , rhs , ")"
 | rhs , "|" , rhs
 | rhs , "," , rhs ;

rule = lhs , "=" , rhs , ";" ;
grammar = { rule } ;
letter=“A”|“B”|“C”|“D”|“E”|“F”|“G”
|“H”|“I”|“J”|“K”|“L”|“M”|“N”
|“O”|“P”|“Q”|“R”|“S”|“T”|“U”
|“V”|“W”|“X”|“Y”|“Z”;
digit=“0”|“1”|“2”|“3”|“4”|“5”|“6”|“7”|“8”|“9”;
symbol=“[“|”]“|”{“|”}”|“(“|”)”|”
| "'" | '"' | "=" | "|" | "." | "," | ";" ;
字符=字母|数字|符号|“|”;
标识符=字母,{字母|数字| |“};
terminal=“”,character,{character},“”
|“,字符,{character},”;
lhs=标识符;
rhs=标识符
|终点站
|“[”,rhs,””
|“{”,rhs,“}”
|(,rhs,)
|rhs,“|”,rhs
|rhs,,,rhs;
规则=lhs,“=”,rhs,”;" ;
语法={rule};
现在,由于我对解析器和语法的知识有限,我不知道这是否是LL(1)语法。我试图为它编写一个解析器,但在尝试读取rhs时失败,rhs再次读取自身,再次读取自身,哦,你明白了

  • 这是LL(1)语法吗
  • 如果没有,如何将其转换为一个(可能?)

    • 简言之,不,你的语法是不是LL(1)

      第一个原因是您已经发现的
      rhs
      的左递归。 我假设您编写了一个递归下降解析器(或其他基于LL(1)语法的解析器)。这样的解析器无法处理左递归规则,因为它们会导致所谓的第一/第一冲突(cf.)的特殊情况


      要解决这个问题并回答问题的第二部分,您可以使用左因子语法并替换左递归,如所示。

      引用的Wikipedia摘录不是正确的EBNF语法。它也不可左解析:事实上,它是不明确的,因此根本不可明确解析

      一般来说,术语
      LL(k)
      LR(k)
      (以及许多其他此类术语)适用于上下文无关语法(CFG)(并且,通过扩展,这些语法生成的语言).EBNF不是描述CFG的形式主义。它被设计为描述上下文无关语言的形式主义,因此可以从给定的EBNF语法创建CFG(但请参见注释1),但EBNF语法规则和CFG中的单个结果之间没有直接对应关系

      也就是说,您通常可以使用一些标准转换直接创建CFG。例如:

      { ... }
      
      可以用生成的非终端M“”替换,并添加以下结果:(
      ε
      为空字符串)

      上面的转换不引入左递归,因此它不会人为地使原始语法非LL(1)

      引用的语法中最重要的错误[注2]是歧义EBNF规则:

      rhs = identifier
          | terminal
          | "[" , rhs , "]"
          | "{" , rhs , "}"
          | "(" , rhs , ")"
          | rhs , "|" , rhs
          | rhs , "," , rhs
          ;
      
      它也是左递归的,因此它不会对应于LL(1)CFG。但更重要的是,它既不表示
      |
      运算符的关联性,也不表示它们的优先级。(从语义上讲,这些运算符没有定义的关联性,但语法仍应指定一个;否则,不可能明确地创建解析树。从语义上讲,两个运算符之间的优先级很重要。)

      更好的规则是:

      primary = identifier
              | terminal
              | "[" , rhs , "]"
              | "{" , rhs , "}"
              | "(" , rhs , ")"
              ;
      factor  = primary , { "|" , primary } ;
      rhs     = factor ,  { "," , factor } ;
      
      这仍然是一个过于简单化的问题,但它涵盖了大量的用例。它既不含糊也不左递归


      注释

    • 不过,注释中指定的语法约束可能不容易转换为CFG。例如,EBNF的ISO标准EBNF对非终结“语法异常”的定义如下:

      语法异常=
      ?可以替换的句法因素
      由一个包含no的句法因素决定
      元标识符



      上述文本的目的是将异常限制为常规语言。这很重要,因为两种上下文无关语言之间的集合差异不一定是上下文无关的,而上下文无关语言和常规语言之间的差异可以证明是上下文无关的。具有讽刺意味的是,“特殊序列”“描述这一限制不能用上下文无关的语法来表达,因为它取决于元标识符的定义。(如果它说“一个语法因素不包含元标识符”,那么写起来就很容易,而不需要使用特殊的序列,但显然这不是目的。)

    • Wikipedia摘录中还有另一个重要错误。它将两种类型的带引号的字符串定义为具有相同的正文,但这是不正确的;双引号的字符串不能包含双引号字符,单引号的字符串不能包含单引号字符。因此,在这两种软管定义不正确

    • 正式的EBNF语法允许
      primary
      为空。我省略了它,因为它通常不需要


    • 好的,这很有道理,我会努力的!非常感谢你的回答!没有问题了!
      primary = identifier
              | terminal
              | "[" , rhs , "]"
              | "{" , rhs , "}"
              | "(" , rhs , ")"
              ;
      factor  = primary , { "|" , primary } ;
      rhs     = factor ,  { "," , factor } ;