Грамматика BNF для простого примера программы на C++

Итак, я пытаюсь написать грамматику для простой программы на С++.

вот как сейчас выглядит грамматика:

PDefs. Program ::= [Def] ;
terminator Def "" ;
comment "//" ;
comment "/*" "*/" ;
comment "#" ;
DFun. Def ::= Type Id "(" [Arg] ")" "{" [Stm] "}" ;
separator Arg "," ;
terminator Stm "" ;
ADecl. Arg ::= Type Id ;
SExp. Stm ::= Exp ";" ;
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] ")" ;
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 ;
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 | '_')*) ;

и это простая программа на С++, которую нужно разобрать

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

int main()
{
    std::cout << "Hello, world!" << std::endl;
    return 0;
}

поэтому, когда я пытаюсь разобрать его, я получаю ошибку в строке 6, что означает строку std::cout. Поскольку я новичок в bnf, я не знаю, как «думать», чтобы решить эту проблему. Если бы кто-то мог привести пример того, как бы вы поступили, чтобы решить подобную ситуацию, было бы здорово.!

Благодарю вас!


person Community    schedule 30.01.2015    source источник
comment
У вас нет правила для приема токенов <<.   -  person TartanLlama    schedule 30.01.2015
comment
как насчет (std::cout) или endln? мне нужны правила для них, потому что я не сделал правило о них? @тартанлама   -  person    schedule 30.01.2015
comment
@TartanLlama: ни для квалификаторов пространства имен   -  person Sander De Dycker    schedule 30.01.2015
comment
Похоже, у вас тоже нет правил для пространств имен. std::cout можно лексировать как ID(std) SCOPE ID(cout).   -  person TartanLlama    schedule 30.01.2015
comment
Итак, я понимаю, что переменная слева — это имя, которое я могу определить и выбрать. что насчет (Exp(number)) означает и как я узнаю, какой номер выбрать?   -  person    schedule 30.01.2015
comment
Хорошо, а откуда у вас такая информация? Если полный новичок хочет знать, как это сделать? @тартанлама   -  person    schedule 30.01.2015
comment
Зачем ты пишешь эту грамматику? Чтобы узнать, как они работают? C++ — зверь для разбора, потому что он очень чувствителен к контексту. Я бы рекомендовал начать с более простого языка, возможно, подмножества C.   -  person TartanLlama    schedule 30.01.2015
comment
Я знаю C, C++, Objective-C и Java. В плане программирования я не новичок. Это то, чем мы научились заниматься в школе... @TartanLlama   -  person    schedule 30.01.2015
comment
Если вы хотите узнать, как должен анализироваться C++, официальная ссылка — это стандарт C++. Вот доступная для просмотра версия грамматики C++ 98, если вам интересно: slps .github.io/zoo/cpp/iso-14882-1998.html — для вашей проблемы взгляните на правило спецификатора вложенного имени.   -  person Sander De Dycker    schedule 30.01.2015
comment
Спасибо за ссылку. Когда я смотрю на правило спецификатора вложенного имени, оно вообще ничего мне не говорит. Я так и не понял, как это связать с моей проблемой? Пожалуйста, приведите пример, чтобы я мог извлечь из этого уроки... @SanderDeDycker   -  person    schedule 30.01.2015
comment
Это кажется очень странным упражнением. Вы не собираетесь писать (даже полу) реалистичную грамматику для C++ для задания. У вас также нет сил подробно читать стандарт C++, чтобы получить необходимые для этого знания. Так что в лучшем случае вы напишете плохую грамматику, которая может прочитать эту конкретную программу. Если цель состоит в том, чтобы заставить вас написать и проверить грамматику, я думаю, это... едва ли... хорошо. Но это означает, что вы можете написать любую плохую грамматику, которая работает, включая глупую версию правила, в которой говорится, что pgm = ‹текст вашей конкретной программы›. Меня больше интересует ваш учитель.   -  person Ira Baxter    schedule 30.01.2015
comment
Учитывая, что вас просят написать плохую грамматику, то простая процедура состоит в том, чтобы взять любую грамматику, которая у вас есть (эту), и, когда вы столкнетесь с синтаксической ошибкой, добавить правило, покрывающее этот синтаксис. В той мере, в какой вы можете отличить выражения от утверждений, вы можете написать соответствующие правила. Типичные выражения невероятно просты для написания правил. Типичные операторы — почти одно правило на каждый вариант оператора.   -  person Ira Baxter    schedule 30.01.2015


Ответы (1)


Строка, в которой он не работает, не может быть проанализирована, потому что вам не хватает некоторых правил:

  1. Вам нужно правило для разбора полных идентификаторов.
    Полноценный идентификатор — это особый тип идентификатора, который (для ваших целей) можно использовать в тех же ситуациях, что и (неполный) идентификатор.
    std::cout и std::endl являются квалифицированными идентификаторами, и (упрощенное) правило для них может выглядеть примерно так:

    <qualified_id> ::= <nested_name_specifier> <unqualified_id>
    <nested_name_specifier> ::= <namespace_name> "::" <nested_name_specifier>?
    

    в котором (для ваших целей) ‹unqualified_id› и ‹namespace_name› могут рассматриваться как идентификаторы.

  2. Вам нужно правило для разбора выражения с помощью оператора <<.
    (упрощенное) правило для этого дополнительного типа выражения может выглядеть примерно так:

    <shift_left_expression> ::= <other_expression>
    <shift_left_expression> ::= <shift_left_expression> "<<" <other_expression>
    

    в котором (для ваших целей) ‹other_expression› обозначает любой другой тип выражения.

  3. Вам нужно правило для синтаксического анализа строчных литералов.
    Строковый литерал — это тип литерала, и его можно использовать (для ваших целей) как часть выражения, например идентификатор.< br/> "Hello, world!" — это строковый литерал, и (упрощенное) правило для них может выглядеть примерно так:

    <string_literal> ::= "\"" <s_char_sequence>? "\""
    <s_char_sequence> ::= <s_char>
    <s_char_sequence> ::= <s_char_sequence> <s_char>
    

    в котором ‹s_char› — это любой символ, который вы хотите разрешить внутри строкового литерала (для простоты не допускайте, например, символ ").

person Sander De Dycker    schedule 30.01.2015
comment
так, например, глядя на этот pdf. cse.chalmers.se/edu/ year/2012/course/DAT150/lections/ на странице 43 в таблице. Я бы написал ‹s_char› как букву. - person ; 30.01.2015
comment
@Meruem: в вашем примере есть строковый литерал с буквами (как строчными, так и прописными), пробелами и специальными символами (запятая и восклицательный знак). Таким образом, вы захотите, по крайней мере, поддержать их. Но, вероятно, вы хотите поддержать все, что (разумно) появилось бы в письменном тексте. - person Sander De Dycker; 30.01.2015