Parsing 如何在C中解决typedef名称-标识符问题?

Parsing 如何在C中解决typedef名称-标识符问题?,parsing,compilation,grammar,context-sensitive-grammar,Parsing,Compilation,Grammar,Context Sensitive Grammar,我最近一直在为基于C的语言编写解析器。我正在使用CUP(Yacc for Java) 我想实现“lexer hack”(or),以区分typedef名称和变量/函数名称等,以便能够声明与前面声明的类型同名的变量(第一个链接中的示例): 我们必须引入一些新产品,其中变量/函数名可以是IDENTIFIER或TYPENAME。这是困难发生的时刻——语法上的冲突 我试图不在gcc 3.4()中使用这种混乱的Yacc语法,但这次我不知道如何独自解决冲突。我看了一下Yacc语法: declarator:

我最近一直在为基于C的语言编写解析器。我正在使用CUP(Yacc for Java)

我想实现“lexer hack”(or),以区分typedef名称和变量/函数名称等,以便能够声明与前面声明的类型同名的变量(第一个链接中的示例):

我们必须引入一些新产品,其中变量/函数名可以是
IDENTIFIER
TYPENAME
。这是困难发生的时刻——语法上的冲突

我试图不在gcc 3.4()中使用这种混乱的Yacc语法,但这次我不知道如何独自解决冲突。我看了一下Yacc语法:

declarator:
    after_type_declarator
    | notype_declarator
    ;

after_type_declarator:
    ...
    | TYPENAME
    ;

notype_declarator:
    ...
    | IDENTIFIER
    ;

fndef:
    declspecs_ts setspecs declarator
    // some action code
    // the rest of production
...

setspecs: /* empty */
    // some action code
declspecs\u ts
表示声明说明符,其中 是否已看到类型说明符;在类型说明符之后,typedef名称是重新声明的标识符(_ts或_nots)

从12月份我们可以到达

typespec_nonreserved_nonattr:
    TYPENAME
    ...
    ;
乍一看,我简直不敢相信移位/减少冲突怎么会不出现!
setspecs
是空的,因此我们有
declspecs
后跟
declarator
,因此我们可以预期解析器应该混淆
TYPENAME
是来自
declarspecs
还是来自
declarator

有人能简单地(甚至准确地)解释一下吗。提前谢谢

编辑:
有用的链接:

我无法说出具体的代码

但基本技巧是C lexer检查每个标识符,并决定是否可能是typedef的名称。如果是这样,那么它将lexeme类型更改为TYPEDEF并将其交给解析器

lexer如何知道什么标识符是typedef?解析器实际上必须通过在运行时捕获typedef信息来告诉它。在与声明相关的语法中,必须有一个操作来提供此信息。我本以为它会附在typedef声明的语法规则中

你没有展示“setspec”做了什么;也许就是那个地方。与LR解析器生成器一起使用的一个常用技巧是用一个空的右手(你的例子“SESESPEC”)引入一个语法规则E,在其他语法规则(你的例子“FNDEF”)的中间调用,以便在处理规则的过程中访问语义动作。
如果您无法区分typedef和其他标识符,那么整个技巧就是避免解析歧义。如果您的解析器容忍歧义,那么您根本不需要这种攻击;只需解析,并使用两个(子)解析构建AST。获取AST后,树漫游可以找到类型信息并消除不一致的子pars。我们用GLR来做C和C++,它将解析与名字解析完美地分开了。

你是对的,但是在这种情况下,发生了一些不同的事情。您可以在代码段上方的链接中读取
setspec
定义。我对这段代码进行了更深入的研究
declspec\u ts
只包含一个
TYPENAME
和一些其他说明符(如
INLINE
等限定符)。还有其他变体,如
declspecs\u nots
,我们必须将不同的
declspecs
after\u type\u declarator
notype\u declarator
组合起来,以支持所有可能的组合。这甚至更复杂(因为属性),但是它的组织/拆分足够聪明,可以防止冲突。欢迎使用生产语法,它不仅有“标准”langauge结构,还有特定编译器/方言(例如GCC、MS、GreenHills)扔进堆中的所有其他垃圾。当你添加人们所做的所有扩展时,语法往往不再简单。如果你幸运的话,语法仍然是“有组织的/足够聪明的”可以管理的。GLR解析器实际上使对大型复杂语法的处理变得更加容易,因为不必纠结于诸如TYPEDEF之类的东西来检查语法本身。这就是我的看法:
declspecs\u-after\u-type\u声明
适用于typename被重新声明为变量(可能是其他一些typename2)的情况,例如:
typedef int myType1;typedef float myType2;{myType1 myType2;/*myType1*/}类型的变量myType2(name)
declspecs\u nots notype\u声明
用于简单的
int foo OK,你能推荐java的任何GLR解析器吗?考虑到我没有这个方面的具体经验,但是策略人员是一个很好的行为。如果你在附近发现一个C语法,我也不会感到惊讶。
typespec_nonreserved_nonattr:
    TYPENAME
    ...
    ;