Уменьшить/уменьшить конфликт при введении указателей в мою грамматику

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

Вот упрощенная версия моей грамматики, которую компилирует 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;


person Tarrasch    schedule 06.01.2013    source источник


Ответы (1)


Обычный способ решения этой проблемы в C-парсерах называется "обратная связь с лексером" . Это «взлом» в том смысле, что он вообще не имеет отношения к грамматике; вместо этого, когда лексер распознает идентификатор, он классифицирует этот идентификатор либо как имя типа, либо как имя, не являющееся именем типа, и возвращает другой токен для каждого случая (обычно обозначаемый «TypeIdent» для идентификатора, который является именем типа, и просто «Ident» для любой другой). Лексер делает этот выбор, просматривая текущее состояние таблицы символов, поэтому он видит все определения типов, возникшие до текущей точки синтаксического анализа, но не видит определения типов, расположенные после текущей точки. Вот почему C требует, чтобы вы объявляли определения типов перед их первым использованием в каждой единице компиляции.

person Chris Dodd    schedule 07.01.2013
comment
Как очень интересно! Есть ли способ сделать это без написания собственного лексера, которому не нужна память? Или на самом деле не существует языка программирования, который имеет синтаксис, подобный Си (использует * для объявления указателя и умножения) и позволяет размещать объявления псевдонимов типов (typedefs) в любом месте кода? - person Tarrasch; 07.01.2013
comment
Отмечено как правильное сейчас. Я только что понял, что лексический хак — это реальный термин, который даже объясняется в Википедии. Я отредактировал ответ, чтобы четко отразить это. - person Tarrasch; 14.01.2013