Flex 混淆了逐个字符地转换字符串
Flex confusing to transform string character by character
我想使用 flex 根据简单的规则转换字符串。我的规则是第一个字符保持不变,第二个和第三个字符可能会改变。就像第二个字符是字母一样,它会变成下面规则中列出的数字。如果第三个是数字,就变成某个字母。
%%
/*^[a-z] {char *yycopy = strdup( yytext ); unput(yycopy[0]);}*/
[ajs] {putchar('1');}
[bkt] {putchar('2');}
[clu] {putchar('3');}
[dmv] {putchar('4');}
[1] {putchar('j');}
[2] {putchar('k');}
[3] {putchar('l');}
[4] {putchar('m');} /*more number rules till 9*/
%%
int yywrap(void){return 1;}
int main( int argc, char **argv )
{
++argv, --argc; /* skip over program name */
if ( argc > 0 )
yyin = fopen( argv[0], "r" );
else
yyin = stdin;
while (yylex());
}
如果字符串中不同位置的字符有不同的规则,如何使用开始条件来更改特定字符(即第二个和第三个字符的规则不同)。
您可以使用 BEGIN 操作切换开始条件。 Flex 永远不会自动更改启动条件,因此当您需要 return 到初始启动条件(称为 INITIAL
)时,您必须明确地这样做 (BEGIN(INITIAL)
).
您需要在 (f)lex 序言中声明开始条件名称,通常使用 %x
命令。 (%s
也是可能的,但具有不同的语义。有关详细信息,请参阅 the Flex manual。)
您通过在尖括号中以开始条件名称开始规则来指示开始条件适用于规则。您可以在尖括号内放置多个开始条件;用逗号分隔它们,不要使用 spaces。也不要在尖括号后放置 space;它们是模式的一部分,并且 (f)lex 模式不能包含不带引号的 space 个字符。
BEGIN
是一个宏,它不需要在开始条件名称周围加上括号,但我建议无论如何都要使用它们,这样您就不必担心宏扩展到什么。开始条件名称是小整数(enum
常量或预处理器宏)但没有任何东西保证它们的值,所以不要做假设。
就是这样。所以你可以实现你的天文命理编码器:
%x SECOND THIRD REST
%%
[a-z] ECHO; BEGIN(SECOND);
<SECOND>[ajs] putchar('1'); BEGIN(THIRD);
/* More SECOND rules */
<THIRD>1 putchar('j'); BEGIN(REST);
/* More THIRD rules */
<*>.*\n? ECHO; BEGIN(INITIAL);
(我故意没有添加任何 <REST>
规则,因为最后的回退覆盖了它。我还故意在第一条规则中省略了锚点,因为我的规则保证 INITIAL
开始条件在一行的开头有效。请参阅最后一条规则。最后一条规则指定一个可选的换行符,以防文件不以换行符结尾,这种情况偶尔会发生,尽管它在技术上是无效的。)
我想使用 flex 根据简单的规则转换字符串。我的规则是第一个字符保持不变,第二个和第三个字符可能会改变。就像第二个字符是字母一样,它会变成下面规则中列出的数字。如果第三个是数字,就变成某个字母。
%%
/*^[a-z] {char *yycopy = strdup( yytext ); unput(yycopy[0]);}*/
[ajs] {putchar('1');}
[bkt] {putchar('2');}
[clu] {putchar('3');}
[dmv] {putchar('4');}
[1] {putchar('j');}
[2] {putchar('k');}
[3] {putchar('l');}
[4] {putchar('m');} /*more number rules till 9*/
%%
int yywrap(void){return 1;}
int main( int argc, char **argv )
{
++argv, --argc; /* skip over program name */
if ( argc > 0 )
yyin = fopen( argv[0], "r" );
else
yyin = stdin;
while (yylex());
}
如果字符串中不同位置的字符有不同的规则,如何使用开始条件来更改特定字符(即第二个和第三个字符的规则不同)。
您可以使用 BEGIN 操作切换开始条件。 Flex 永远不会自动更改启动条件,因此当您需要 return 到初始启动条件(称为 INITIAL
)时,您必须明确地这样做 (BEGIN(INITIAL)
).
您需要在 (f)lex 序言中声明开始条件名称,通常使用 %x
命令。 (%s
也是可能的,但具有不同的语义。有关详细信息,请参阅 the Flex manual。)
您通过在尖括号中以开始条件名称开始规则来指示开始条件适用于规则。您可以在尖括号内放置多个开始条件;用逗号分隔它们,不要使用 spaces。也不要在尖括号后放置 space;它们是模式的一部分,并且 (f)lex 模式不能包含不带引号的 space 个字符。
BEGIN
是一个宏,它不需要在开始条件名称周围加上括号,但我建议无论如何都要使用它们,这样您就不必担心宏扩展到什么。开始条件名称是小整数(enum
常量或预处理器宏)但没有任何东西保证它们的值,所以不要做假设。
就是这样。所以你可以实现你的天文命理编码器:
%x SECOND THIRD REST
%%
[a-z] ECHO; BEGIN(SECOND);
<SECOND>[ajs] putchar('1'); BEGIN(THIRD);
/* More SECOND rules */
<THIRD>1 putchar('j'); BEGIN(REST);
/* More THIRD rules */
<*>.*\n? ECHO; BEGIN(INITIAL);
(我故意没有添加任何 <REST>
规则,因为最后的回退覆盖了它。我还故意在第一条规则中省略了锚点,因为我的规则保证 INITIAL
开始条件在一行的开头有效。请参阅最后一条规则。最后一条规则指定一个可选的换行符,以防文件不以换行符结尾,这种情况偶尔会发生,尽管它在技术上是无效的。)