Использование BNFC для определения базового языка для логики высказываний (синтаксическая ошибка)

Я хотел бы анализировать предложения в пропозициональной логике, используя BNFC. Я написал следующую грамматику BNF, чтобы облегчить это:

Negation.     N ::= "(" "-" L")";
Conjuction.   C ::= "(" L "&" L ")";
Disjuction.   D ::= "(" L "|" L ")";
Implication.  I ::= "(" L "=>" L ")";
Equivalence.  E ::= "(" L "<=>" L ")";
Atom.         L ::= Ident | N | C | D | I | E ;

Однако с этой конструкцией я получаю следующую ошибку:

syntax error at line 6, column 27 before `|'

Что синтаксически неверно в предоставленной мной спецификации?

Изменить 1

Итак, похоже, что bnfc действительно не нравится идея использовать символ | для объединения. Как мне тогда назначить несколько продуктов одному правилу, если не через объединение? Я не хочу определять Atom1. L ::= Ident ;, Atom2. L ::= N ; и так далее, но нужно ли это, если я хочу, чтобы это работало?

Редактировать 2

Итак, давайте разные ярлыки каждому L-производству, как в

Negation.     N ::= "(" "-" L")";
Conjuction.   C ::= "(" L "&" L ")";
Disjuction.   D ::= "(" L "|" L ")";
Implication.  I ::= "(" L "=>" L ")";
Equivalence.  E ::= "(" L "<=>" L ")";
Atom1.        L ::= Ident ;
Atom2.        L ::= N ;
Atom3.        L ::= C ;
Atom4.        L ::= D ;
Atom5.        L ::= I ;
Atom6.        L ::= E ;

позволил файлу logic.cf пройти через bnfc без ошибок. Однако, когда файл компилируется с помощью команды

bnfc -m -c file.cf

и затем я пытаюсь запустить make, я получаю следующую ошибку, когда Make пытается запустить gcc в файле Printer.c, сгенерированном bnfc:

gcc -g -W -Wall -c Absyn.c
flex -Plogic -oLexer.c logic.l
gcc -g -W -Wall -c Lexer.c 
Lexer.c:1477:16: warning: ‘input’ defined but not used [-Wunused-function]
     static int input  (void)
                ^~~~~
Lexer.c:1434:17: warning: ‘yyunput’ defined but not used [-Wunused-function]
     static void yyunput (int c, char * yy_bp )
                 ^~~~~~~
bison -t -plogic logic.y -o Parser.c
gcc -g -W -Wall -c Parser.c
gcc -g -W -Wall -c Printer.c
Printer.c: In function ‘ppL’:
Printer.c:289:20: error: ‘union <anonymous>’ has no member named ‘atom_’; did you mean ‘atom1_’?
     ppIdent(_p_->u.atom_.ident_, 0);
                    ^~~~~
                    atom1_
Printer.c:296:16: error: ‘union <anonymous>’ has no member named ‘atom_’; did you mean ‘atom1_’?
     ppN(_p_->u.atom_.n_, 0);
                ^~~~~
                atom1_
Printer.c:303:16: error: ‘union <anonymous>’ has no member named ‘atom_’; did you mean ‘atom1_’?
     ppC(_p_->u.atom_.c_, 0);
                ^~~~~
                atom1_
Printer.c:310:16: error: ‘union <anonymous>’ has no member named ‘atom_’; did you mean ‘atom1_’?
     ppD(_p_->u.atom_.d_, 0);
                ^~~~~
                atom1_
Printer.c:317:16: error: ‘union <anonymous>’ has no member named ‘atom_’; did you mean ‘atom1_’?
     ppI(_p_->u.atom_.i_, 0);
                ^~~~~
                atom1_
Printer.c:324:16: error: ‘union <anonymous>’ has no member named ‘atom_’; did you mean ‘atom1_’?
     ppE(_p_->u.atom_.e_, 0);
                ^~~~~
                atom1_
Printer.c: In function ‘ppInteger’:
Printer.c:336:31: warning: unused parameter ‘i’ [-Wunused-parameter]
 void ppInteger(Integer n, int i)
                               ^
Printer.c: In function ‘ppDouble’:
Printer.c:342:29: warning: unused parameter ‘i’ [-Wunused-parameter]
 void ppDouble(Double d, int i)
                             ^
Printer.c: In function ‘ppChar’:
Printer.c:348:25: warning: unused parameter ‘i’ [-Wunused-parameter]
 void ppChar(Char c, int i)
                         ^
Printer.c: In function ‘ppString’:
Printer.c:354:29: warning: unused parameter ‘i’ [-Wunused-parameter]
 void ppString(String s, int i)
                             ^
Printer.c: In function ‘ppIdent’:
Printer.c:360:28: warning: unused parameter ‘i’ [-Wunused-parameter]
 void ppIdent(String s, int i)
                            ^
Printer.c: In function ‘shL’:
Printer.c:507:20: error: ‘union <anonymous>’ has no member named ‘atom_’; did you mean ‘atom1_’?
     shIdent(_p_->u.atom_.ident_);
                    ^~~~~
                    atom1_
Printer.c:522:16: error: ‘union <anonymous>’ has no member named ‘atom_’; did you mean ‘atom1_’?
     shN(_p_->u.atom_.n_);
                ^~~~~
                atom1_
Printer.c:537:16: error: ‘union <anonymous>’ has no member named ‘atom_’; did you mean ‘atom1_’?
     shC(_p_->u.atom_.c_);
                ^~~~~
                atom1_
Printer.c:552:16: error: ‘union <anonymous>’ has no member named ‘atom_’; did you mean ‘atom1_’?
     shD(_p_->u.atom_.d_);
                ^~~~~
                atom1_
Printer.c:567:16: error: ‘union <anonymous>’ has no member named ‘atom_’; did you mean ‘atom1_’?
     shI(_p_->u.atom_.i_);
                ^~~~~
                atom1_
Printer.c:582:16: error: ‘union <anonymous>’ has no member named ‘atom_’; did you mean ‘atom1_’?
     shE(_p_->u.atom_.e_);
                ^~~~~
                atom1_
Makefile:42: recipe for target 'Printer.o' failed
make: *** [Printer.o] Error 1

Я без понятия что это значит. Почему он пытается найти atom_, когда я не указал такую ​​вещь в logic.cf Если есть люди, более опытные во внутренностях bnfc, я был бы не против вас услышать.

Редактировать 3

Итак, пишите метки как

Negation.     N ::= "(" "-" L ")";
Conjuction.   C ::= "(" L "&" L ")";
Disjuction.   D ::= "(" L "|" L ")";
Implication.  I ::= "(" L "=>" L ")";
Equivalence.  E ::= "(" L "<=>" L ")";
Atom.         L ::= Ident;
AtomN.        L ::= N ;
AtomC.        L ::= C ;
AtomD.        L ::= D ;
AtomI.        L ::= I ;
AtomE.        L ::= E ;

каким-то волшебным образом позволил make пройти. Однако мой синтаксический анализатор не совсем работает, так как что-то такое простое, как

echo "p" | ./Testlogic

возвращается с

error: line 1: syntax error at p

Разве p не является допустимым идентификатором, и поэтому производство Atom. L ::= Ident; должно его пропускать? Почему это не так?


person SeSodesa    schedule 11.04.2020    source источник
comment
привет, у меня та же проблема, что и до тех пор, пока я использую | выдает ошибку, похожую на вашу. Вы нашли какое-либо решение для правильного использования |? :(   -  person arslan    schedule 17.06.2020


Ответы (2)


Оказывается, BNFC немного разборчив, когда дело доходит до порядка производства. я должен был написать

Atom.         L ::= Ident;
AtomN.        L ::= N ;
AtomC.        L ::= C ;
AtomD.        L ::= D ;
AtomI.        L ::= I ;
AtomE.        L ::= E ;
Negation.     N ::= "(" "-" L ")";
Conjuction.   C ::= "(" L "&" L ")";
Disjuction.   D ::= "(" L "|" L ")";
Implication.  I ::= "(" L "=>" L ")";
Equivalence.  E ::= "(" L "<=>" L ")";

в дополнение к избавлению от цифр на концах этикеток, чтобы заставить его работать. Теперь я могу анализировать простые предложения в логике предикатов:

$ echo "(a&(a<=>b))" | ./Testlogic 

Parse Succesful!

[Abstract Syntax]
(AtomC [(Conjuction (Atom ["a"]) (AtomE [(Equivalence (Atom ["a"]) (Atom ["b"]))]))])

[Linearized Tree]
(a  & (a <=> b))

person SeSodesa    schedule 11.04.2020

Первый нетерминал считается точкой входа синтаксического анализатора, если только вы не объявили точки входа с помощью директивы entrypoint. Это объясняет, почему Правка 3 еще не работала.

person Andreas Abel    schedule 21.03.2021