通常認爲在您的解析器中檢測錯誤(如12.34.56
)通常更好,而不是掃描儀。但是也有一種觀點認爲,通過從詞彙上檢測錯誤,你可以產生更好的錯誤信息。
如果你想這樣做,你可以使用兩種模式;第一個檢測只有正確的數字,第二個檢測到一個更大的字符串集合,包括所有錯誤的字符串(但不是任何可能合法的字符串)。這依賴於(f)lex的匹配行爲:它總是接受最長匹配,並且如果最長的標記符合兩個或更多個規則,則它使用第一個匹配規則。
例如,假設您想自己接受點爲'.'
,數字爲NUMBER
標記,並且在具有多個點的數字字符串上產生錯誤。你可以用三條規則做到這一點:
/* If the token is just a dot, match it here */
\. { return '.'; }
/* Match integers without decimal points */
[[:digit:]]+ { return INTEGER; }
/* If the token is a number including a decimal point,
* match it here. This pattern will also match just '.',
* but the previous rules will be preferred.) */
[[:digit:]]*\.[[:digit:]]* { return FLOAT; }
/* This rule matches any sequence of dots and digits.
* That will also match single dots and correct numbers, but
* again, the previous rules are preferred. */
[.[:digit:]]+ { /* signal error */
return BADNUMBER; }
你需要非常小心的解決上述問題。例如,過去的規則將匹配..
和...
,這可能是有效的令牌(或.
令牌甚至有效序列。)
假設,例如,你的語言許可證「範圍內」這樣的表達式4 .. 17
(指列表從4到17的整數,或一些這樣的)。您的用戶可能希望4..17
被接受爲一個範圍的表達,但上面會產生一個BADNUMBER錯誤,即使你在一開始添加規則
".." { return RANGE; }
,因爲4..
將在之前的點匹配BADNUMBER
掃描。
爲了避免錯誤警報,我們需要修改BADNUMBER規則以避免匹配包含兩個(或多個)連續點的字符串。而且我們還需要確保4..17
不會因爲4.
後跟.17
而變得易混淆。 (這第二個問題可以通過堅持.
沒有開始沒有結束一個數字令牌,但可能會激怒一些用戶是可以避免的。)
所以,我們開始與實際點標記:
"." { return '.'; }
".." { return RANGE; }
"..." { return ELLIPSIS; }
爲了避免匹配一個數字後跟..
,我們可以使用flex的尾隨上下文運算符。在這裏,我們認識到一個.
終止僅在字符串後面跟着一個非.
其他的東西了一些數字序列:
[[:digit:]]+ { return INTEGER; }
/* Change * to + so that we don't do numbers ending with . */
[[:digit:]]*(\.[[:digit:]]+)? { return FLOAT; }
/* Numbers which end with dot not followed by dot */
[[:digit:]]+\./[^.] { return FLOAT; }
現在我們需要修復的錯誤的規則。首先,我們將其限制爲識別每個點後跟一個數字的字符串。然後,類似於上述情況,我們做匹配,那裏是一個句點後面沒有其他點的情況下:
[[:digit:]]*(\.[[:digit:]]+)+ { return BADNUMBER; }
[[:digit:]]*(\.[[:digit:]]+)+\./[^.] { return BADNUMBER; }
你真的需要嗎?無論如何,「12.34.56」(大概)會成爲語法錯誤,所以它不是一個詞法錯誤真的很重要嗎? – sepp2k