2010-11-10 39 views
14

我想在我的Flex解​​析C風格的多行註釋(.L)文件:爲什麼flex/bison中的多行註釋如此迴避?

%s ML_COMMENT 
%% 

... 

<INITIAL>"/*"     BEGIN(ML_COMMENT); 
<ML_COMMENT>"*/"    BEGIN(INITIAL); 
<ML_COMMENT>[.\n]+    { } 

我不返回任何令牌和我的語法(.Y)沒有解決意見以任何方式。

當我運行我的可執行文件,我得到一個解析錯誤:

$ ./a.out 
/* 
abc 
def 
Parse error: parse error 
$ echo "/* foo */" | ./a.out 
Parse error: parse error 

(我的yyerror函數做一個printf(「解析錯誤:%s \ n」),這是其中的第一個半多餘的錯誤信息來自)。

我可以看到爲什麼第二個示例失敗,因爲整個輸入是註釋,並且由於語法忽略了註釋,所以沒有語句。因此輸入不是一個有效的程序。但是,第一部分在我完成評論之前拋出了一個解析錯誤。

另外混亂:

$ ./a.out 
/* foo */ 
a = b; 
Parse error: parse error 

在這種情況下,註釋之前實際有效的輸入(其沒有評論,解析就好)關閉。在解析「a」之後實際發生失敗,而不是在嘗試解析賦值「a = b;」之後發生。如果我自己輸入「a」,它仍然會報錯。

鑑於錯誤消息是一個解析器錯誤,而不是掃描儀錯誤,是否有什麼關鍵我在我的.y文件中缺少?或者我在掃描器規則中做錯了什麼,傳播到解析器端?

編輯:每@魯迪的建議下,我打開調試,發現:

$ ./a.out 
Starting parse 
Entering state 0 
Reading a token: /* 
foo 
Next token is 44 (IDENTIFER) 
Shifting token 44 (IDENTIFER), Entering state 4 
Reducing via rule 5 (line 130), IDENTIFER -> identifier 
state stack now 0 
Entering state 5 

我關掉調試,發現確實/* foo */ = bar;解析一樣foo = bar;。我使用的是flex 2.5.4;它並沒有給我任何關於我試圖使用的有狀態規則的警告。

+1

我重新標記彎曲以GNU-FLEX。您的掃描儀規則看起來沒問題。解析錯誤指示解析器的無效令牌輸入。你可能想發佈一些相應的Bison規則。此外,它可能是一個好主意,把printf()的報表您的野牛規則裏面,這樣你可以看到什麼樣的規則令牌的掃描過程中解析器嘗試。 – Kizaru 2010-11-10 14:40:24

+2

爲您的掃描儀創建單獨的測試工具也是一個好主意。這樣您就可以將掃描儀缺陷與解析器缺陷隔離開來。任何掃描分析器系統是複雜的,以至於當你添加了'--debug'標誌的野牛,你不需要通過執行集成測試,當你真正想要的是要進行單元測試...... – bstpierre 2010-11-10 15:11:51

+1

注入額外的複雜性調用並設置'YYDEBUG = 1'的'yyparse()'呼叫之前,則解析器發出調試信息爲每一個令牌從詞法分析器看到。 – Rudi 2010-11-10 15:14:41

回答

5

我認爲你必須聲明你ML_COMMENT開始條件作爲獨家開始條件,所以只有ML_COMMENT規則處於活動狀態。的%x ML_COMMENT代替%s ML_COMMENT

沒有啓動的條件,否則規則也很活躍。

+0

啊!這似乎已經成功了。我現在唯一的問題是:爲什麼我的多行評論的內容迴應了?當我在STDIN中輸入'/ * foo bar * /'時,我將'foo bar'打印到STDOUT。 – adelarge 2010-11-10 17:24:52

+2

[。\ n]沒有做你認爲它正在做的事。用2個規則替換它。還有一個用於\ n。默認彈性回聲輸入,不符合任何規則。這就是爲什麼許多lex規則集以「。」結尾的原因。所以每個輸入匹配的東西。 – Craig 2010-11-10 18:07:12

+0

這樣做。謝謝! – adelarge 2010-11-10 19:23:59

5

解析意見這種方式可能會導致錯誤的原因是:

  • 你需要添加條件所有的規則法
  • ,如果你也想處理//它變得更加複雜評論
  • 你仍然有風險,yacc /野牛合併兩個評論,包括之間的所有內容

在我的解析器中,我處理這樣的評論。首先定義註釋開始的lex規則,如下所示:

\/\*  { 
     if (!SkipComment()) 
      return(-1); 
     } 

\/\/  { 
     if (!SkipLine()) 
      return(-1); 
     } 

然後編寫SkipComment和SkipLine函數。他們需要消耗所有的輸入,直到註釋的結尾被發現(這是很舊代碼,所以原諒我有點陳舊結構):

bool SkipComment (void) 
{ 
int Key; 

Key=!EOF; 
while (true) 
    { 
    if (Key==EOF) 
     { 
     /* yyerror("Unexpected EOF within comment."); */ 
     break; 
     } 
    switch ((char)Key) 
     { 
     case '*' : 
     Key=input(); 
     if (char)Key=='/') return true; 
     else    continue; 
     break; 
     case '\n' : 
     ++LineNr; 
     break; 
     } 
    Key=input(); 
    } 

return false; 
} 

bool SkipLine (void) 
{ 
int Key; 

Key=!EOF; 
while (true) 
    { 
    if (Key==EOF) 
     return true; 
    switch ((char)Key) 
     { 
     case '\n' : 
     unput('\n'); 
     return true; 
     break; 
     } 
    Key=input(); 
    } 

return false; 
} 
+1

這是否處理註釋開始/結束字符序列,如果它出現在引用文本中? (例如'富=「這不包含/ *註釋* /」') – 2010-11-10 17:00:15

+0

我並沒有明確提到這一點,但你必須解析字符串完全相同的方式。如果你想支持像在C/C++中那樣的反斜槓,你尤其必須這樣做。 – Patrick 2010-11-10 22:39:55

+1

這是更復雜,更容易出錯,更詳細,更難以不僅僅是使用Flex開始狀態正常的事情。它基本上只是你的詞法分析器的手寫部分 - 如果你不喜歡flex,爲什麼不直接手寫全部內容呢? – 2016-03-18 14:28:48

1

除了與%x VS %s的問題,也有在.[.\n]比賽(只)字面.,而不是「比任何其他換行字符」就像一個裸.做的問題。你要像

<ML_COMMENT>.|"\n"  { /* do nothing */ } 

的規則,而不是