【问题标题】:Trouble with printf in Bison RuleBison Rule 中的 printf 问题
【发布时间】:2010-08-21 23:16:23
【问题描述】:

我在我的 Bison 文件中尝试过类似的操作...

ReturnS: RETURN expression {printf(";")}

...但是分号在下一个标记之后打印,超过了这个规则,而不是在表达式之后。制定此规则是因为我们需要将输入文件转换为类似 c 的形式,并且原始语言在 return 语句中的表达式后不需要分号,但 C 需要,所以我想我会添加它使用 printf 手动输出。这似乎不起作用,因为添加了分号,但由于某种原因,它是在解析下一个标记之后(在 ReturnS 规则之外)而不是在表达式规则返回 ReturnS 时添加的。

这条规则也会导致同样的结果:

loop_for: FOR var_name COLONEQUALS expression TO {printf("%s<=", $<chartype>2);} expression STEP {printf("%s+=", $<chartype>2);} expression {printf(")\n");} Code ENDFOR

除了前两个 printf 不能正常工作(我将发布另一个关于此的问题)之外,最后一个 printf 实际上是在解析“代码”规则的第一个标记/文字之后调用的,结果如下:

for (i=0; i<=5; i+=1
a)
=a+1;

而不是

for (i=0; i<=5; i+=1)
a=a+1;

任何想法我做错了什么?

【问题讨论】:

    标签: action printf bison flex-lexer


    【解决方案1】:

    可能是因为语法必须先看一个标记才能决定根据您显示的规则减少。

    当规约规则时执行该动作,并且非常典型的情况是,语法必须再读取一个标记才能知道它可以/应该规约前一条规则。

    例如,如果一个表达式可以包含不定序列的附加项,则它必须阅读最后一个项才能知道没有另一个“+”来继续该表达式。


    看了 Yacc/Bison 语法和 Lex/Flex 分析器后,有些问题变得很明显,而有些问题则需要稍微整理一下。

    • 让词法分析器完成大部分打印意味着语法无法正确控制何时出现的内容。分析器做的太多了。
    • 分析器也没有做足够的工作 - 使语法处理字符串和数字一次一个字符是可能的,但不必要的辛苦工作。
    • 如果需要保留 cmets,处理它们会很棘手。在常规的 C 编译器中,词法分析器会丢弃 cmets;在这种情况下,必须保留 cmets。处理此问题的规则已从语法(由于与 cmets 匹配的空字符串而导致移位/归约和归约/归约冲突的地方)移至词法分析器。这可能并不总是最佳的,但在这种情况下似乎可以正常工作。
    • 词法分析器需要确保在需要值时为 yylval 返回合适的值。
    • 语法需要在$$ 中传播合适的值,以确保规则具有必要的信息。大部分关键字不需要值;变量名和数字之类的东西。
    • 语法必须在适当的地方进行打印。

    返回的原型解决方案存在严重的内存泄漏,因为它大量使用了strdup(),而根本没有使用free()。确保泄漏得到修复 - 可能通过使用 char 数组而不是 YYSTYPE 的 char 指针 - 留给 OP。

    【讨论】:

    • 我明白了。感谢您的回复。不知道如何解决这个问题,但现在至少我知道去哪里找了。
    • 我已经尝试过,但似乎无法解决这个问题。关于如何实际解决此问题的任何想法?
    • @Leftos:通过电子邮件将代码发送给我 - 查看我的个人资料。我会看看我能做些什么。
    【解决方案2】:

    评论不是提供代码示例的好地方,所以我将提供一个有效的代码示例,在 Jonathan(上面回复)对我的代码做了一些工作之后。所有应得的功劳归他所有,这不是我的。

    Jonathan 建议 FLEX 什么都不打印,只返回给 BISON,然后由 BISON 自行处理所有打印,而不是让 FLEX 打印任何已识别的部分并让 BISON 进行格式化。

    所以,不要像这样......


    灵活

    "FOR"   {printf("for ("); return FOR;}
    "TO"    {printf("; "); return TO;}
    "STEP"  {printf("; "); return STEP;}
    "ENDFOR"    {printf("\n"); printf("}\n"); return ENDFOR;}
    [a-zA-Z]+   {printf("%s",yytext); yylval.strV = yytext; return CHARACTERS;}
    ":="    {printf("="); lisnew=0; return COLONEQUALS;}
    

    野牛

    loop_for:   FOR var_name {strcpy(myvar, $<strV>2);} COLONEQUALS expression TO {printf("%s<=", myvar);} expression STEP {printf("%s+=", myvar);} expression {printf(")\n");} Code ENDFOR
    

    ...他建议这样做:


    灵活

    [a-zA-Z][a-zA-Z0-9]*    { yylval = strdup(yytext); return VARNAME;}
    [1-9][0-9]*|0           { yylval = strdup(yytext); return NUMBER; }
    

    野牛

    loop_for:   FOR var_name COLONEQUALS NUMBER TO NUMBER STEP NUMBER
        { printf("for (%s = %s; %s <= %s; %s += %s)\n", $2, $4, $2, $6, $2, $8); }
    var_name:   VARNAME
    

    【讨论】:

    • 乔纳森,如果您想将上述示例添加到您的答案中,我很乐意删除我的答案。
    • 另外,如果有人想知道 printf 中的 $x 及其工作原理,另请参阅 SO 3539498。stackoverflow.com/questions/3539498/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-08
    • 1970-01-01
    相关资源
    最近更新 更多