在我的语言中,在特定点我需要从一组令牌中接受最多一个令牌。举一个例子,带括号的表达式后面的任何顺序最多可以跟!^&
一个,所以下面两行应该是等价的
(foo)!^
(foo)^!
以下一个是非法的(令牌重复两次)
(foo)^!^
这是否可行,当然不能用CFG规则耗尽所有可能性?无论是词汇(flex)还是句法(bison)等级都可以。
答案 0 :(得分:1)
除了枚举所有可能性之外,无法使用正则表达式或CFG执行此操作,这是一个因子量的工作。 (通过分组,可以减小实际大小,但它仍然是指数级。)如果您只有一个实例,并且只有三个令牌,那么列表可能是最简单的解决方案。
但是如果存在各种令牌,并且您可能希望将来扩展列表,则可能更容易允许所有令牌组合,但将位图与令牌列表相关联以使其易于检查是否有重复,这可能会导致错误消息。
对于您提到的具体案例,这是一个简单的flex
解决方案。 (在我原来,我复制了很多代码,但我认为以下内容更容易阅读。)<MODS>
开始条件是由[&^!]
的第一次出现触发的,用于吸收其余的他们;遇到任何其他字符时,会将其标记为重新扫描(yyless(0)
),并返回修饰符的当前掩码。
%{
// The MODS token has %type <ModMask>, and the associated
// semantic value will be the union of the enum bits.
typedef unsigned int ModMask;
enum { MOD_HAT=1, MOD_BANG=2, MOD_AMP=4 };
// This function maps a character to a modmask value.
// A real implementation would use a lookup table. I just included
// this definition so the snippet is usable.
ModMask tokenToMask(unsigned char c) {
return c == '^' ? MOD_HAT :
c == '!' ? MOD_BANG :
c == '&' ? MOD_AMP : 0;
%}
%x SC_MODS
%%
[&^!] { yylval.modmask = tokenToMask(yytext[0]; BEGIN(MODS); }
<MODS>[&^!] { ModMask m = tokenToMask(yytext[0];
if (yylval.modmask & m) {
yyerror("Duplicate modifier");
}
yylval.modmask |= m;
}
<MODS>.|\n { yyless(0); BEGIN(INITIAL); return MODS; }