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
Your problem is that std::cout
is not an Id
. It might be an [Id]
-- that is, a list of Id
s -- 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 Id
s; 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 Id
s. 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] ;