парсинг — написать грамматику BNFC для программы на C ++

Поэтому я пишу грамматику, используя BNF-конвертер (BNFC) разобрать программу на с ++. Программа на С ++ выглядит следующим образом.

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

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

Грамматика БНФ, которую я написал для этого, выглядит следующим образом.

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

0

Решение

Ваша проблема в том, что 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 нетерминал, который вы могли бы изначально определить как просто Id но который вы в конечном итоге захотите расширить, чтобы включить в него объявления указателей (*foo), деклараторы массива (foo[3]) и, возможно, даже объявления функций. С Declarator нетерминал, вы можете заменить

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

с

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

Примечание: из «Формализма грамматики LBNF», в разделе 7 (Макросы):

separator nonempty Stm ";" ;

средства

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

Другие решения

Других решений пока нет …