在我的语法中引入指针时减少/减少冲突

时间:2013-01-06 05:21:04

标签: grammar bnf happy reduce-reduce-conflict

我正在研究一个小型编译器,以便更好地理解创建自己语言的困难。现在我正处于向我的语法添加指针功能的阶段,但是通过这样做我得到了减少/减少冲突。

这是我的语法的简化版本,可由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;
}

typedefmain(){}部分与我的语法无关。但它们给出了一些背景信息)

在第一个程序中,我希望它将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语法如何解决这个问题?

到目前为止,我已成功通过使用“&”来改变语言的语法。或其他一些符号而不是“*”,但这是非常不受欢迎的。此外,我无法从各种公共语法中理解,并试图了解为什么他们没有这个问题,但我没有运气。

最后,如何自行解决这些问题?从happy更详细的输出我理解的是冲突是如何发生的,聪明是解决这些冲突的唯一方法吗?我担心在引入EIndir. Expr = '*' Expr;

时会遇到更多问题

1 个答案:

答案 0 :(得分:3)

在C解析器中处理此问题的常用方法通常称为"the lexer feedback hack"。它是一种“黑客”,因为它根本不涉及语法;相反,当词法分析器识别出一个标识符时,它会将该标识符分类为typename或non-typename,并为每个case返回一个不同的标记(通常将'TypeIdent'指定为一个类型名称的标识符,简单地为'Ident'任何其他)。词法分析器通过查看符号表的当前状态来进行此选择,因此它可以看到在解析中当前点之前发生的所有typedef,而不是当前点之后的typedef。这就是为什么C要求在第一次使用每个编译单元之前声明typedef的原因。