0

所以我正在使用BNF-Convertor (BNFC)编写语法来解析 c++ 程序。c++程序如下。

// a small C++ program
#include <iostream>

int main()
{
    std::cout << "i";
    return 0;
}

我为此写的BNF语法如下。

PDefs. Program ::= [Def] ;
terminator Def "" ;
comment "//" ;
comment "/*" "*/" ;
comment "#" ;
DFun. Def ::= Type Id "(" [Arg] ")" "{" [Stm] "}" ;
separator Arg "," ;
terminator Stm "" ;
separator nonempty Id "::" ;
ADecl. Arg ::= Type Id ;
SExp.    Stm ::= Exp ";"              ;
Sids.    Stm ::= Id                   ;
SDecl.   Stm ::= Type Id ";"          ;
SDecls.  Stm ::= Type Id "," [Id] ";" ;
SInit.   Stm ::= Type Id "=" Exp ";"  ;
SReturn. Stm ::= "return" Exp ";"     ;
SWhile.  Stm ::= "while" "(" Exp ")" Stm ;
SBlock.  Stm ::= "{" [Stm] "}" ;
SIfElse. Stm ::= "if" "(" Exp ")" Stm "else" Stm ;
EInt.    Exp15 ::= Integer ;
EDouble. Exp15 ::= Double ;
ETrue.   Exp15 ::= "true" ;
EFalse.  Exp15 ::= "false" ;
EId.     Exp15 ::= Id ;
EApp.    Exp15 ::= Id "(" [Exp] ")" ;
EStr.    Exp15 ::= "\"" Id "\"";
EPIncr.  Exp14 ::= Exp15 "++" ;
EPDecr.  Exp14 ::= Exp15 "--" ;
EIncr.   Exp13 ::= "++" Exp14 ;
EDecr.   Exp13 ::= "--" Exp14 ;
ETimes.  Exp12 ::= Exp12 "*" Exp13 ;
EDiv.    Exp12 ::= Exp12 "/" Exp13 ;
EPlus.   Exp11 ::= Exp11 "+" Exp12 ;
EMinus.  Exp11 ::= Exp11 "-" Exp12 ;
ELs.     Exp9  ::= Exp9 "<<" Exp10 ;
ERs.     Exp9  ::= Exp9 ">>" Exp10 ;
ELt.     Exp9  ::= Exp9 "<"  Exp10 ;
EGt.     Exp9  ::= Exp9 ">" Exp10 ;
ELtEq.   Exp9  ::= Exp9 "<=" Exp10 ;
EGtWq.   Exp9  ::= Exp9 ">=" Exp10 ;
EEq.     Exp8  ::= Exp8 "==" Exp9 ;
ENEq.    Exp8  ::= Exp8 "!=" Exp9 ;
EAnd.    Exp4  ::= Exp4 "&&" Exp5 ;
EOr.     Exp3  ::= Exp3 "||" Exp4 ;
EAss.    Exp2  ::= Exp3 "=" Exp2 ;
coercions Exp 15 ; 
separator Exp "," ;
separator Id "," ;
Tbool. Type ::= "bool" ;
Tdouble. Type ::= "double" ;
Tint. Type ::= "int" ;
Tvoid. Type ::= "void" ;
token Id (letter (letter | digit | '_' )*) ;
token Ids (letter)* ;

::我已经为这里的左移运算符<<和右移运算符编写了规则,>>但由于某种原因,它没有正确解析。我究竟做错了什么?

据我了解,这应该可以工作,但会出现此错误。

   syntax error at line 6 before << "i" ; return
4

1 回答 1

2

你的问题是那std::cout不是一个Id. 它可能是一个[Id]- 即Ids 的列表 - 因为声明

separator nonempty Id "::" ;

但该声明与后来的声明相冲突

separator Id "," ;

我对 BNFC 了解得不够多,无法预测那次冲突的结果,但很难想象结果是你想要的。

表达式的语法不使用[Id]; 它只允许Id

EId.     Exp15 ::= Id ;
EApp.    Exp15 ::= Id "(" [Exp] ")" ;

所以限定名称std::cout不会被解析为Exp15.

您尝试使用Ids 列表有两种非常不同的上下文;它们在句法和语义上都不同。所以你真的不能指望同时使用[Id]它们。

由于您显然希望能够处理命名空间的名称,因此我建议明确定义Name为非空::分隔的Ids 列表。当然,您可以使用[Id]宏来代替您自己的定义;这真的是对风格的判断。对我来说,它似乎不太清楚,但口味各不相同。

在另一种情况下——声明——使用[Id]确实是不正确的,尽管它可能足以满足您的简化语法。在这里,我建议使用一个新的Declarator非终端,您最初可以将其定义为 justId但您最终希望将其扩展为包括指针声明符 ( *foo)、数组声明符 ( foo[3]),甚至可能是函数声明符。使用Declarator非终端,您可以替换

SDecl.   Stm ::= Type Id ";"          ;
SDecls.  Stm ::= Type Id "," [Id] ";" ;

separator nonempty Declarator ","
SDecls.  Stm ::= Type [Declarator] ";" ;

注意:来自“LBNF Grammar Formalism”,第 7 节(宏):

separator nonempty Stm ";" ;

方法

(:[]). [Stm] ::= Stm ;
(:). [Stm] ::= Stm ";" [Stm] ; 
于 2017-11-06T16:00:51.887 回答