动态打开和关闭 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
状态?那么所有规则都将具有 INITIAL
和 CMDOPT
状态,但 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()
在扫描开始之前适当地设置开始条件。这是我的建议。
如果您确实使用开始条件,那么您可以通过使用其中两个来简化您的规则,一个用于每个语法选项,并使它们成为 包含性。然后所有你没有用任何开始条件标记的规则将适用于两者,你只需要标记那些特定于一个开始条件或另一个的规则。
我有一个程序应该根据命令行参数对其输入进行词法分析。因此,要求 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
状态?那么所有规则都将具有 INITIAL
和 CMDOPT
状态,但 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()
在扫描开始之前适当地设置开始条件。这是我的建议。
如果您确实使用开始条件,那么您可以通过使用其中两个来简化您的规则,一个用于每个语法选项,并使它们成为 包含性。然后所有你没有用任何开始条件标记的规则将适用于两者,你只需要标记那些特定于一个开始条件或另一个的规则。