c++parsingbnfc

Write BNFC grammar for a C++ program


So I am writing a grammar using the BNF-Convertor (BNFC) to parse a c++ program. The c++ program is as follows.

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

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

The BNF grammar I wrote for this is as follows.

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)* ;

I have written the rules for both :: and the left shift operators here << and >> right shift operators but for some reason it's not parsing correctly. What am I doing wrong?

According to my understanding this should work but it gives this error.

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

Solution

  • Your problem is that std::cout is not an Id. It might be an [Id] -- that is, a list of Ids -- because of the declaration

    separator nonempty Id "::" ;
    

    but that declaration conflicts with the later declaration

    separator Id "," ;
    

    I don't know enough about BNFC to predict the result of that conflict, but it is hard to imagine that the result is what you want.

    The syntax for an expression does not use [Id]; it only allows Id:

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

    So the qualified name std::cout is not going to be parsed as an Exp15.

    You have two very different contexts in which you attempt to use lists of Ids; they differ both syntactically and semantically. So you really cannot expect to use [Id] for both of them.

    Since you evidently want to be able to handle namespace'd names, I'd suggest explicitly defining Name as a non-empty ::-separated list of Ids. You could use the [Id] macro instead of your own definition, of course; that's really a judgement of style. To me, it seems less clear but tastes vary.

    In the other context -- declarations -- the use of [Id] is really not correct, although it might be sufficient for your simplified grammar. Here, I'd recommend using a new Declarator non-terminal, which you could initially define as just Id but which you will eventually want to expand to include pointer declarators (*foo), array declarators (foo[3]) and maybe even function declarators. With the Declarator non-terminal, you can replace

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

    with

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

    Note: from the "LBNF Grammar Formalism", in section 7 (Macros):

    separator nonempty Stm ";" ;
    

    means

    (:[]). [Stm] ::= Stm ;
    (:). [Stm] ::= Stm ";" [Stm] ;