动态打开和关闭 flex 令牌

Dynamically turning on and off flex tokens

我有一个程序应该根据命令行参数对其输入进行词法分析。因此,要求 1/2 被词法化为:

NUMBER
SLASH
NUMBER

...当给定一个命令行参数时,词法分析为:

FREEFORM_TOKEN

...当给定另一个命令行参数时。我使用的工具是 flex.

我想知道 flex 是否可以支持这种用例。我的规则是:

[0-9]+(.[0-9]+)?([eE][-+]?[0-9]+)? {
  yylval->d = atof(yytext);
  return NUMBER;
}

[A-Za-z0-9_.]([A-Za-z0-9_./]*[A-Za-z0-9_.])? {
  yylval->s = strdup(yytext);
  return FREEFORM_TOKEN;
}

我可以简单地通过 if 语句动态地转换 on/off 然后标记,就像这样:

[0-9]+(.[0-9]+)?([eE][-+]?[0-9]+)? {
  yylval->d = atof(yytext);
  return NUMBER;
}

[A-Za-z0-9_.]([A-Za-z0-9_./]*[A-Za-z0-9_.])? {
  if (cmd_line_argument_given)
  {
    yylval->s = strdup(yytext);
    return FREEFORM_TOKEN;
  }
}

...或者在 .l 文件中使用长正则表达式是否存在一些问题,这会导致 1/2 匹配但不匹配 return 任何东西?

我应该如何实际执行此要求?

我应该这样做吗:

<INITIAL,CMDOPT>[0-9]+(.[0-9]+)?([eE][-+]?[0-9]+)? {
  yylval->d = atof(yytext);
  return NUMBER;
}

<CMDOPT>[A-Za-z0-9_.]([A-Za-z0-9_./]*[A-Za-z0-9_.])? {
  yylval->s = strdup(yytext);
  return FREEFORM_TOKEN;
}

...如果我想打开 FREEFORM_TOKEN 然后执行 BEGIN(CMDOPT) 如果我想关闭 FREEFORM_TOKEN 则将其保持在 INITIAL 状态?那么所有规则都将具有 INITIALCMDOPT 状态,但 FREEFORM_TOKEN 除外,它只有 CMDOPT 状态。

我认为您应该使用开始条件。然后当你启动你的软件时,在你真正开始词法分析之前使用yy_push_state(YOUR_STATE)切换到不同的启动条件。​​

I'm wondering whether flex can support this use case.

是的,以各种方式。

Can I simply dynamically turn on/off then token by an if statement, like this:

不,那不是(完全)一种方法。如果您只是将是否采取任何行动作为条件,那么当采取 no 行动时,令牌将被静默消耗,而不是根据不同的规则进行匹配。

在这种情况下,要让 flex 回退到不同的规则,您可以使用 the REJECT() directive。这指示 flex 改为应用与输入(或其前缀)匹配的下一个最佳规则。

请注意,REJECT 完全出现在您的扫描器定义中会使整个扫描器变慢。这是您可以为扫描仪性能做的最糟糕的事情。但实际上这对您来说可能不是问题。

How in practice should I implement this requirement?

Should I [use start conditions] instead [?]

开始条件通常是在不同规则子集中进行选择的更好选择。正如@Cheatah 首先观察到的,您可以使用 yy_push_state() 在扫描开始之前适当地设置开始条件。这是我的建议。

如果您确实使用开始条件,那么您可以通过使用其中两个来简化您的规则,一个用于每个语法选项,并使它们成为 包含性。然后所有你没有用任何开始条件标记的规则将适用于两者,你只需要标记那些特定于一个开始条件或另一个的规则。