我已經慢慢習慣了彈性詞法分析器的奇思妙想,雖然它曾經很酷(1)我設法讓它真正作業并且(2)我已經了解它是如何作業的,但我不知道如何改進我的語法定義。
語法是中等復雜的,所以我不想在這里粘貼它。我添加了它 - 見下文 但這里是構建統計資訊。
/usr/local/bin/flex -P -d -v
classic.lpp:466: warning, -s option given but default rule can be matched
flex version 2.6.4 usage statistics:
scanner options: - dsvB8 -Cem -Pc
314/2000 NFA states
114/1000 DFA states (563 words)
40 rules
Compressed tables always back-up
7/40 start conditions
187 epsilon states, 127 double epsilon states
26/100 character classes needed 322/500 words of storage, 0 reused
1385 state/nextstate pairs created
250/1135 unique/duplicate transitions
123/1000 base-def entries created
545/2000 (peak 748) nxt-chk entries created
72/2500 (peak 333) template nxt-chk entries created
220 empty table entries
14 protos created
9 templates created, 18 uses
37/256 equivalence classes created
8/256 meta-equivalence classes created
2 (5 saved) hash collisions, 151 DFAs equal
0 sets of reallocations needed
1629 total table entries needed
除了我真的不知道上面的意思是什么(除了規則的數量和開始條件等明顯的東西)之外,我不知道如何讓 flex 告訴我默認規則在哪里可以匹配。
當然我可以添加一個默認規則'catch'
但這意味著我必須找到觸發它的方法。再一次,我可以無情地制定一個正則運算式/匹配分析并遍歷它,直到我發現缺少什么 - 但是 flex 沒有辦法告訴我,例如:“在開始規則 3 中,以下字符不匹配?
語法的最小示例如下
彈性版本 2.6.4
/usr/local/bin/flex -P -d -v adv.lpp
%option debug
%option noyywrap noinput nounput nodefault
%option noyymore
%option never-interactive
%option c
%option stack
%option warn
%x parm brace bracket fatone literal injection
DELIMITER ,
ALTDELIM ?
BRACKET_IN \(
BRACKET_OUT \)
FAT_ONE_IN ?
FAT_ONE_OUT ?
LITERAL_IN ?
BRACE_IN ?
BRACE_OUT ?
INJECT_SIGN ?
I_OFFSET \^*
I_NUMBER [0-9]
I_ITS [ijkn]
I_ITK [KN]
I_STACK p([s]|[0-9] )?
I_ITER ([ijknKN]([ -][0-9] )?([./]p?[0-9] )?)
I_MORE ([0-9] (" "?))
MACRO_SIGN ?
MACRO_NAME [a-zA-Z_0-9]
WHITESPACE [\t\x0d\x0a]
LCOMMENT ?comment\(
LBCOMMENT ?comment?
LITERAL_OUT ?
NOT_SPECIAL_1C [^\t\x0d\x0a,\(\)\xe2]
NOT_LITERAL_OUT [^\xe2]|(\xe2(([^\x8e][^\0])|(\x8e[^\xa6])))
NOT_SPECIAL_3C (\xe2[^\x81\x8c\x8d\x8e\x9d][^\0])|(\xe2\x81[^\x8f])|(\xe2\x8c[^\xbd])|(\xe2\x8d[^\x9f])|(\xe2\x8e[^\xa1\xa3\xa4\xa6])|(\xe2\x9d[^\xaa\xab])
JUST_TEXT ({NOT_SPECIAL_1C}|{NOT_SPECIAL_3C})
/**
E2 81|8C|8D|8E|9D
? E2 9D AA √ FAT_ONE_IN
? E2 9D AB √ FAT_ONE_OUT
? E2 81 8F √ ALTDELIM
? E2 8C BD √ MACRO_SIGN
? E2 8D 9F √ INJECT_SIGN
? E2 8E A1 √ BRACE_IN
? E2 8E A3 √ LITERAL_IN
? E2 8E A4 √ BRACE_OUT
? E2 8E A6 √ LITERAL_OUT
**/
%%
<literal>{
{LCOMMENT} {
yy_push_state(parm);
return( token::MACRO_IN );
}
{LBCOMMENT} {
yy_push_state(parm);
return( token::MACRO_IN );
}
{LITERAL_IN} {
yy_push_state(literal);
}
{LITERAL_OUT} {
yy_pop_state(); /** Pop Literal **/
}
{NOT_LITERAL_OUT} {
return( token::TEXT );
}
<<EOF>> {
cerr << "Unexpected end of text before close literal";
yy_pop_state();
}
}
<bracket>{
{BRACKET_OUT} {
yy_pop_state();
return( token::TEXT );
}
}
<fatone>{
{FAT_ONE_OUT} {
yy_pop_state();
return( token::TEXT );
}
}
<parm,brace,bracket,fatone>{
{INJECT_SIGN}({I_ITK}|{BRACKET_IN}{I_ITK}{BRACKET_OUT}) {
return(token::INJECTION);
}
}
<parm>{
{DELIMITER} {
return( token::PARM );
}
{ALTDELIM} {
return( token::PARM );
}
{BRACE_OUT} {
return( token::TEXT );
}
{BRACKET_OUT} {
yy_pop_state(); /** Pop Macro **/
return( token::MACRO_OUT );
}
{FAT_ONE_OUT} {
yy_pop_state(); /** Pop Macro **/
return( token::MACRO_OUT );
}
<<EOF>> {
cerr << "Unexpected end of text before macro close.";
yy_pop_state(); //pop parm!
}
}
<brace>{
{BRACE_OUT} {
yy_pop_state();
}
{ALTDELIM} {
return (token::PARMX);
}
<<EOF>> {
cerr << "Unexpected end of text before close brace";
yy_pop_state();
}
}
<brace,bracket,fatone>{
{DELIMITER} {
return( token::TEXT );
}
}
<INITIAL,parm,brace,bracket,fatone>{
{LITERAL_IN} {
yy_push_state(literal);
}
({WHITESPACE}) {
return( token::WSS );
}
{BRACE_IN} {
yy_push_state(brace);
}
{MACRO_SIGN}{MACRO_NAME}{BRACKET_IN} {
yy_push_state(parm);
return( token::MACRO_IN);
}
{MACRO_SIGN}{MACRO_NAME}{FAT_ONE_IN} {
yy_push_state(parm);
return( token::MACRO_IN );
}
{MACRO_SIGN}{MACRO_NAME}{NOT_SPECIAL_1C} {
return( token::TEXT );
}
{INJECT_SIGN}{I_OFFSET}({I_NUMBER}|{I_ITS}|({BRACKET_IN}{I_OFFSET}({I_STACK}|{I_ITER}|{I_MORE}){BRACKET_OUT})) {
return(token::INJECTION);
}
{BRACKET_IN} {
switch(YY_START) {
case bracket:
case parm: {
yy_push_state(bracket);
} break;
default: break;
}
return( token::TEXT );
}
{FAT_ONE_IN} {
switch(YY_START) {
case fatone:
case parm: {
yy_push_state(fatone);
} break;
default: break;
}
return( token::TEXT );
}
{JUST_TEXT} {
return( token::TEXT );
}
{MACRO_SIGN}|{INJECT_SIGN}|{BRACKET_OUT}|{FAT_ONE_OUT}|{LITERAL_OUT} {
return( token::TEXT );
}
}
<INITIAL>{
({DELIMITER}|{BRACKET_OUT}|{FAT_ONE_OUT}|{BRACE_OUT}|{ALTDELIM}|{LITERAL_OUT}) {
return(token::TEXT);
}
}
%%
uj5u.com熱心網友回復:
不幸的是,flex 沒有提供這樣的功能。
您可以通過在每個開始條件下嘗試每個字符來獲得線索,直到掃描儀報告錯誤。這只是幾行代碼,yy_scan_buffer用于設定單個字符輸入。[參見下面的代碼示例]。
不要忘記在每個開始條件下嘗試 EOF;該警告的一個常見原因是不處理 EOF 的啟動條件。有時這是誤報,但很多時候是因為您沒有考慮到 EOF 可能錯誤發生的所有可能位置。
當您知道下一個輸入字符是什么時輸入開始條件時,可能會發生誤報,可能是因為規則有尾隨背景關系,或者可能是因為您呼叫了<yyless. 在這種情況下,您可能會合理地無法匹配您知道不會出現的字符序列,但更好的方式可能是捕獲序列或 EOF 并插入您自己的錯誤訊息。
要查找的一種特殊情況是分隔標記(如字串或注釋)的模式,您尚未處理標記丟失其結束分隔符的可能性。對于字串,您還需要考慮輸入在轉義序列中間結束的可能性。
使用下面的代碼片段,我得到了以下報告:
Failed to match 0XE2 in state INITIAL
Failed to match 0XE2 in state parm
Failed to match 0XE2 in state brace
Failed to match 0XE2 in state bracket
Failed to match 0XE2 in state fatone
Failed to match 0XE2 in state literal
基本上,您可以識別以 0xE2 開頭的多位元組字符,并且您可以識別 0xE2 以外的位元組。但是如果輸入在從 0xE2 開始的多位元組序列中間到達 EOF 呢?(是的,這是一個無效的輸入。但 Flex 不知道。)
如果有用,這里有一個小代碼片段,可用于確定無法匹配的字符。為了使用它,您需要:
- 修改頂部的狀態串列
main - 將所有 flex 動作更改為
return 1;(這主要可以通過一個好的文本編輯器完成,只需在每個動作return 1;的前導后注入)。{ - 在最后添加 catch-all 規則,以避免在嘗試未處理的字符時觸發致命錯誤:
<*>.|\n { return 2; } <INITIAL><<EOF>> { return 0; /* Needed so the next rule doesn't apply. */} <<EOF>> { return 2; } - 洗掉對 Flex 檔案中未定義的任何符號的任何參考(支持函式、令牌定義等),或安排它們被定義。
完成所有這些后,您只需在 flex 檔案中添加以下內容(它需要在檔案中才能訪問開始條件定義):
注意:這是 C 版本。如果您洗掉所有操作,那么在 C 中進行此測驗應該沒問題,但如果您真的想使用 C ,那么您需要進行一些小的調整。
int main(void) {
#define X(n) { n, #n }
struct { int state; const char* name; } states[] = {
X(INITIAL), X(parm), X(brace), X(bracket), X(fatone), X(literal),
{ -1, 0 }
};
#undef X
for (int i = 0; states[i].state >= 0; i) {
int start = states[i].start;
char buf[3] = {0, 0, 0};
BEGIN(start);
yy_scan_buffer(buf, 2);
if (yylex() == 2)
fprintf(stderr, "Failed to match EOF in state %s\n",
states[i].name);
for (int ch = 0; ch < 256; ch) {
buf[0] = ch;
BEGIN(start);
yy_scan_buffer(buf, 3);
if (yylex() == 2)
fprintf(stderr, "Failed to match 0XX in state %s\n",
(unsigned)ch, states[i].name);
}
}
return 0;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/496185.html
