2013-01-06 39 views
1

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

这是我的语法的简化版本,可由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语法如何解决这个问题?

到目前为止,我已经成功地通过使用“&”或其他符号而不是“*”成功地更改了我的语言的语法,但这是非常不可取的。另外,我不能从各种公共C语法中理解,并试图明白为什么他们没有这个问题,但我没有在这方面运气。

最后,我该如何自行解决这些问题?我从happy得知的更详细的输出是冲突发生的方式,是巧妙解决这些冲突的唯一方法吗?恐怕我会偶然发现更多的问题,例如介绍EIndir. Expr = '*' Expr;

回答

3

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

+0

非常有趣!有没有办法做到这一点,而不用编写自己的不需要有内存的词法分析器?或者是否真的没有类似c语法的编程语言(使用'*'乘法*和*指针声明),并允许将类型别名声明(typedefs)放在代码中的任何位置? – Tarrasch

+0

现在标记为正确。我刚刚意识到,词法分析黑客是一个实际的术语,甚至在维基百科上进行了解释。我编辑了答案,清楚地反映了这一点。 – Tarrasch