我正在尝试通过flex / bison使用SMTP协议(以及某些扩展名)。 BDAT extension特别令人感兴趣。它的工作方式是这样的:
Client: BDAT 100 <CRLF>
Client: <100 bytes of binary data>
Client: BDAT 256 <CRLF>
Client: <256 bytes of binary data>
Server: 250 OK
Server: 250 OK
我面临的问题是flex控制输入流到令牌的使用,但是bison控制语法,因此知道何时发出了有效的BDAT命令。
在Flex中:
(?i:BDAT[ ]) { return BDAT; }
[0-9]+[ ] { yylval->number = ...;
return NUMBER: }
"\r\n" { return CRLF; }
在野牛中:
bdat_command: BDAT NUMBER CRLF
| BDAT NUMBER LAST CRLF
我想做的是在Bison中执行一个操作,该操作根据指定的缓冲区大小消耗了额外的输入:
bdat_command: BDAT NUMBER CRLF { uint8_t * data = input($2); }
| BDAT NUMBER LAST CRLF { uint8_t * data = input($2); }
其中input
是一个假设函数,它将消耗来自flex缓冲区的N个字节的输入。 Flex确实有an input
function,但是它没有在Flex标头中导出(并且一次读取一个字节)。
我可以完全在词法分析器中使用额外的输入,但是我担心某些输入序列会导致词法分析器由于不理解语法而错误地使用字节。例如,使用以下词法分析器规则:
(?i:BDAT[ ]) { BEGIN SC_BDAT;
return BDAT; }
<SC_BDAT>[0-9]+[ ] { yylval->number = ...;
return NUMBER: }
<SC_BDAT>"\r\n" { yylval->data = ...;
BEGIN INITIAL;
return CRLF; }
词法分析器将错误地对输入序列进行词法化,如下所示:
Client: BDAT 100 100 <CRLF>
Client: RSET <CRLF>
Server: 501 Bad command syntax
Server: 250 Ok
服务器应产生两个错误响应,如图所示,但词法分析器将吞噬第二条命令作为第一条命令的一部分。只有语法会知道在发出正确的令牌序列之前不消耗指定的字节数。
肯定有解决此问题的方法-通过向yylex
和yypush_parse
添加更多参数,以便通过调用者在词法分析器和解析器之间打开后退通道。但这似乎是解决此类用例的一种钝器,似乎几乎可以 属于flex / bison设计的用途。