【问题标题】:How do I get yacc/bison and/or lex/flex to restart scanning after something like token substitution?在令牌替换之类的操作之后,如何让 yacc/bison 和/或 lex/flex 重新开始扫描?
【发布时间】:2026-01-25 01:00:02
【问题描述】:

在我用其他东西替换某些令牌后,有没有办法强制 bison 和/或 flex 重新开始扫描?

我的特定示例是替换特定的单词/字符串。如果我想将hello 的一个词替换为echo hello,我怎样才能得到flex 或bison 来替换hello,然后重新开始解析(选择2 个词而不是一个词)。所以它会是这样的:

  • 获取令牌WORD(字符串类型)
  • 如果hello,将令牌值替换为echo hello
  • 重新开始解析整个输入(现在是echo hello
  • 获取令牌 WORD (echo)
  • 获取令牌 WORD (hello)

我见过像yyrestart() 这样的非常诱人的功能,但我并不真正了解该功能的具体作用。非常感谢任何帮助,谢谢!

2010 年 4 月 23 日更新

我最终使用的一种 hack-and-slash 解决方案是对于每个通过的 word,我检查一个“别名”数组。如果word 有别名,我会替换该单词的值(例如使用strcopy($1,aliasval)),并标记aliasfound 标志。

一旦整行输入被解析一次,如果aliasfound标志为真,我使用yy_scan_string()将缓冲区状态切换到扩展别名的输入,并调用YYACCEPT

然后它跳到主函数,我再次调用yyparse(),缓冲区仍然指向我的字符串。这一直持续到找不到别名为止。完成所有语法操作后,我会致电 yyrestart(stdin) 以返回“正常”模式。

如果有人知道我如何使用别名值有效地扩展我的单词,注入stdin(或其他方法),并且基本上扩展所有别名(甚至嵌套),那就太棒了。我在玩 yypush_buffer_state()yypop_buffer_state() 以及 yy_switch_to_buffer(),但我无法通过继续解析工作来获得“内联”替换......

【问题讨论】:

    标签: c parsing bison yacc flex-lexer


    【解决方案1】:

    在我看来,解决这个问题的地方是词法分析器。我建议使用支持状态机的 flex(在 flex 文档中称为“Start Conditions”)。您使用BEGIN 更改状态,并且需要在定义部分中定义状态。

    所以,例如,你可以有一个类似的规则

    <INITIAL>hello    BEGIN(in_echo); yyless(0); return (WORD_ECHO);
    <in_echo>hello    BEGIN(0); return (WORD_HELLO);
    

    yyless()yytext 截断为给定值,因此这会将整个输入放回流中。

    我自己没有尝试过,但我认为这是您想要的解决方案的结构。

    【讨论】:

    • 谢谢,我会尽快试试看!
    【解决方案2】:

    根据我最终做的事情添加“答案”。想要将此问题标记为已回答。

    2010 年 4 月 23 日更新

    我最终使用的一种 hack-and-slash 解决方案是,对于出现的每个单词,我都会检查一个“别名”数组。如果单词有别名,我会替换单词的值(例如使用 strcopy($1,aliasval)),并标记 aliasfound 标志。

    一旦整行输入被解析一次,如果 aliasfound 标志为真,我使用 yy_scan_string() 将缓冲区状态切换到扩展别名的输入,并调用 YYACCEPT。

    然后它跳到主函数,我再次调用 yyparse(),缓冲区仍然指向我的字符串。这一直持续到找不到别名为止。完成所有语法操作后,我调用 yyrestart(stdin) 以返回“正常”模式。

    如果有人知道我如何有效地使用它们的别名值扩展我的单词,注入标准输入(或其他方法),并在我进行时基本上扩展所有别名(甚至是嵌套的),那就太棒了。我一直在玩 yypush_buffer_state() 和 yypop_buffer_state() 以及 yy_switch_to_buffer(),但我无法通过继续解析工作来获得“内联”替换...

    【讨论】:

      最近更新 更多