不使用 `input()` 隐式终止 flex 中的开始条件

Implicit termination of start conditions in flex without using `unput()`

假设我在 flex 中解析十六进制数。我有这样的东西:

%x hexnumber
%%
"0x"                { BEGIN hexnumber }
<hexnumber>[0-9A-F] { process_digit(); }

这很好用; 0x前缀开始十六进制解析模式,然后依次处理每个数字。

问题是十六进制常量没有明确的终止符标记。那么,如何切换回 INITIAL 状态呢?当我知道下一个字符不是数字常量的一部分时,它已经被消耗了。

我总是可以使用 unput():

将它推回输入流
<hexnumber>.        { unput(*yytext); BEGIN INITIAL; }

...但我非常不想这样做(因为使用 unput() 超出此问题范围的实现细节对我来说非常昂贵)。

我知道生成的状态机能够在不消耗下一个字符的情况下自动切换回 INITIAL 状态,因为否则像 [0-9A-F]+ 这样的规则将不起作用。有没有办法使用明确的开始条件来实现这一点?

使用yyless(0)代替unput(*yytext)yyless 基本上是免费的,因为它只调整了几个指针。它不会尝试重新分配或移动输入缓冲区。 (当然你还需要BEGIN(INITIAL)。)

一个更混乱的解决方案是使用尾随上下文来区分十六进制字符后跟其他十六进制字符:

 [[:xdigit:]]/[[:xdigit:]]    process_digit();
 [[:xdigit:]]                 process_digit(); BEGIN(INITIAL);

但是这样就不太灵活了。