Я работаю над небольшим компилятором, чтобы лучше понять трудности создания собственного языка. Прямо сейчас я нахожусь на этапе добавления функциональности указателя в свою грамматику, но при этом у меня возник конфликт уменьшения/уменьшения.
Вот упрощенная версия моей грамматики, которую компилирует bnfc
. Я использую генератор синтаксического анализатора happy
, и это программа, сообщающая мне о конфликте уменьшения/уменьшения.
entrypoints Stmt ;
-- Statements
-------------
SDecl. Stmt ::= Type Ident; -- ex: "int my_var;"
SExpr. Stmt ::= Expr; -- ex: "printInt(123); "
-- Types
-------------
TInt. Type ::= "int" ;
TPointer. Type ::= Type "*" ;
TAlias. Type ::= Ident ; -- This is how I implement typedefs
-- Expressions
--------------
EMult. Expr1 ::= Expr1 "*" Expr2 ;
ELitInt. Expr2 ::= Integer ;
EVariable. Expr2 ::= Ident ;
-- and the standard corecions
_. Expr ::= Expr1 ;
_. Expr1 ::= Expr2 ;
Я нахожусь в стадии изучения того, как работают грамматики. Но я думаю, что знаю, что происходит. Рассмотрим эти две программы
main(){
int a;
int b;
a * b;
}
и
typedef int my_type;
main(){
my_type * my_type_pointer_variable;
}
(Часть typedef
и main(){}
не имеет отношения к моей грамматике. Но они дают некоторый контекст)
В первой программе я бы хотел, чтобы она разбирала a "*" b
как Stmt ==(SExpr)==> Expr ==(EMult)==> Expr * Expr ==(..)==> Ident "*" Ident
, то есть, по сути, начинала пошагово, используя правило SExpr
.
При этом хотелось бы, чтобы my_type * my_type_pointer_variable
расширяли с помощью правил. Stmt ==(SDecl)==> Type Ident ==(TPointer)==> Type "*" Ident ==(TAlias)==> Ident "*" Ident
.
Но этап грамматики не знает, является ли идентификатор изначально псевдонимом типа или переменной.
(1) Как я могу избавиться от конфликта уменьшения/уменьшения и (2) у меня одного возникла эта проблема? Есть ли очевидное решение и как грамматика c решает эту проблему?
До сих пор мне удавалось просто изменить синтаксис моего языка, используя «&» или какой-либо другой символ вместо «*», но это очень нежелательно. Кроме того, я не могу разобраться в различных общедоступных грамматиках c и пытался понять, почему у них нет этой проблемы, но мне в этом не повезло.
И наконец, как мне решить подобные проблемы самостоятельно? Все, что я понял из более подробного вывода happy
, это то, как возникает конфликт, является ли хитрость единственным способом обойти эти конфликты? Боюсь, я наткнусь на еще больше проблем, например, при представлении EIndir. Expr = '*' Expr;