2014-05-03 43 views
0

我想解析一個使用flex/bison具有某種「轉義序列」的語言。目前,我堅持定義詞法分析器。這是最簡單的例子來解釋:Flex:處理多字符註釋式分隔符

Text --> {if} test {literal} text 43.21 {if} foo {/literal} {if} 
      ---- ---- --------- ------------------- ---------- ---- etc. 
Desired --> IF TEXT (ignore)   TEXT   (ignore) IF 
    Token 

正如你所看到的,語言包含了一些終端的符號,如IFTEXT,這是相當直接的。 但是,{literal}{/literal}之間的所有內容都是TEXT,即使它包含的字符串本來會是特殊的標記。

我能想出一個詞法分析器的最佳到目前爲止是這樣的,它使用Start Conditions的不同狀態之間跳躍:如果遇到了一個{literal},它激活LITERAL規則。

%{ 
#include <stdio.h> 
#define YY_DECL int yylex() 
%} 
%x LITERAL 
%% 
[^{]+     {printf("TEXT: %s\n", yytext);} 
"{if}"    {printf("IF\n");} 
"{literal}"   {BEGIN(LITERAL);} 
<LITERAL>[^{]+  {printf("TEXT: %s\n", yytext);} 
<LITERAL>"{"   {printf("TEXT: %s\n", yytext);} 
<LITERAL>"{/literal}" {BEGIN(INITIAL);} 
%% 
main() {yylex();} 

但是如何離開LITERAL狀態?利用該定義與上面的實施例給出

IF 
TEXT: test 
TEXT: text 43.21 
TEXT: { 
TEXT: if} foo 
IF 

換句話說,在{literal}標記內的TEXT令牌在{被分割。我怎樣才能避免這種情況?

+0

您應該怎樣代碼處理字符串'{}字面「{/ literal}」{/ literal}'; ''''''''''''''/'''''''''''在某種程度上,這是不重要的(您所顯示的語言中沒有引用字符串)。但你需要知道答案。 –

+0

@JonathanLeffler:結束標籤沒有開始標籤將是一個語法錯誤。 – Geier

+1

好的:我認爲你的問題將是一個沒有接近引用的開盤報價,但我明白你的意思。我正在查看代碼,以瞭解我如何處理此類評論。答案是「它變化」,這取決於我需要做什麼'評論' - 我經常刪除它。所以我不確定我有一個好的答案,也不知道'yymore()'是否相關。 –

回答

2

{literal}內部的文本被分割爲{,因爲您匹配{;如果你不希望文字被拆分,則需要使用LITERAL開始條件中的規則來延伸延伸的比賽,而不是每個人創建一個新的比賽。這是一個相當普遍的(F)法成語,且有專門爲此目的設計的一個特點:yymore

yymore()告訴在下一次的規則相匹配的掃描器,相應的令牌應該被附加到所述yytext的當前值而不是替換它。
(從 flex manual

利用方便的功能,我們可以這樣寫:

"{literal}"   {BEGIN(LITERAL);} 
<LITERAL>[^{]+  {yymore();} 
<LITERAL>"{"   {yymore();} 
<LITERAL>"{/literal}" { 
         /* Now we have to provide the token, but we've matched 
         * 10 extra characters, the close marker, and so the 
         * token is the text from yytext with length yyleng-10. 
         * Here we just print it out, but normally we'd copy 
         * yytext to a temporary for future processing. 
         * Most compilers will optimize out the call to strlen. 
         */ 
         BEGIN(INITIAL); 
         printf("TEXT: %.*s\n", 
           (int)(yyleng - strlen("{/literal}")), 
           yytext); 
         } 

上述假定LITERAL狀態是字面字面:),也就是說,它僅與終止無論上下文如何,{/literal}標籤和{/literal}標籤始終都會被識別。但是,它不依賴於此;您可以在文字掃描中進行更復雜的標記識別,只要您在除結束標記的操作之外的每個操作中始終使用yymore()即可。

如果我的假設是正確的,另一個解決方案是可用的:簡單地匹配整個文字與正則表達式。使用非貪婪匹配來編寫正則表達式會更容易(甚至可以直接作爲有限狀態機),但是不幸的是flex沒有實現這些,所以它必須長期完成,而且它確實很長。幸運的是,結束標記以一個不包含在結束標記內的字符開頭,所以正則表達式可以很容易地機械生成。在這裏,我用柔性的定義,以避免一個很長的線,並且使圖案一點更加明顯:

l1    [{] 
l2   "/"[{] 
l3   "/l"[{] 
l4  "/li"[{] 
l5  "/lit"[{] 
l6  "/lite"[{] 
l7  "/liter"[{] 
l8 "/litera"[{] 
l9 "/literal"[{] 
loop [{](l1|l2|l3|l4|l5|l6|l7|l8|l9)* 

n1    [^{/] 
n2   "/"[^{l] 
n3   "/l"[^{i] 
n4  "/li"[^{t] 
n5  "/lit"[^{e] 
n6  "/lite"[^{r] 
n7  "/liter"[^{a] 
n8 "/litera"[^{l] 
n9 "/literal"[^{}] 
next n1|n2|n3|n4|n5|n6|n7|n8|n9 

prefix "{literal}" 
middle ([^{]|{loop}{next})* 
suffix {loop}"/literal}" 

literal {prefix}{middle}{suffix} 

%%

{literal} { 
       /* The token includes both the {literal} opener and 
       * the {/literal} closer, so we need to get rid of 
       * both of them. 
       */ 
       printf("TEXT: %.*s\n", 
        (int)(yyleng - strlen("{literal}") - strlen("{/literal}")), 
        yytext + strlen("{literal}")); 
      } 
+0

謝謝,這正是我正在尋找的。不過,我認爲你的第一個解決方案就足夠了;) – Geier