2013-11-15 46 views
1

我正在使用flex + bison C++編寫一個mgf文件解析器(語法:http://www.matrixscience.com/help/data_file_help.html)。flex和野牛:解析字符串不用引號

我意識到了詞法分析器(lex)和解析器(yacc)。但是我有一個我無法解決的問題:當我嘗試解析字符串時。

重要的:不存在「或」串繞

下面是輸入的一個例子:

CHARGE=1+, 2+ and 3+ 
#some comments 

BEGIN IONS 
TITLE= Cmpd 1, +MSn(417.2108), 10.0 min //line 20 
PEPMASS=417.21083 35173 
CHARGE=3+ 
123.79550 20 
285.16455 56 
302.14335 146 1+ 
[other datas ...] 
END IONS 

BEGIN IONS 
[an other one ... ] 

在這裏,(最小)詞法分析: MGF_TOKEN_DEBUG是中庸之道打印的宏線

#define MGF_TOKEN_DEBUG(val) std::cout<<"token: "<<val<<std::endl 

\n { 
    MGF_TOKEN_DEBUG("T_EOL"); 
    return token::T_EOL; 
} 

^[#;!/][^\n]* { 
    MGF_TOKEN_DEBUG("T_COMMENT"); 
    return token::T_COMMENT; 
} 

[[:space:]] {} 

/** values **/ 
[0-9]+ { 
    MGF_TOKEN_DEBUG("V_INTEGER"<<" (="<<yytext<<")"); 
    return token::V_INTEGER; 
} 

[0-9]+"."[0-9]* { 
    MGF_TOKEN_DEBUG("V_DOUBLE"<<" (="<<yytext<<")"); 
    return token::V_DOUBLE; 
} 

[0-9]+("."[0-9]+)?[eE][+-][0-9]+ { 
    MGF_TOKEN_DEBUG("V_DOUBLE"<<" (="<<yytext<<")"); 
    return token::V_DOUBLE; 
} 

"+" { 
    MGF_TOKEN_DEBUG("T_PLUS"); 
    return token::T_PLUS; 
} 


"=" { 
    MGF_TOKEN_DEBUG("T_EQUALS"); 
    return token::T_EQUALS; 
} 

"," { 
    MGF_TOKEN_DEBUG("T_COMA"); 
    return token::T_COMA; 
} 

"and" { 
    MGF_TOKEN_DEBUG("T_AND"); 
    return token::T_AND; 
} 
/*** keywords */ 
^"CHARGE" { 
    MGF_TOKEN_DEBUG("K_CHARGE"); 
    return token::K_CHARGE; 
} 

^"TITLE" { 
    MGF_TOKEN_DEBUG("K_TITLE"); 
    return token::K_TITLE; 
} 
[ others keywords ...] 

/**** string : problem here **/ 
[A-Za-z]([:;,()A-Za-z0-9_.-]|[[:space]])* { 
    MGF_TOKEN_DEBUG("V_STRING"<<" (="<<yytext<<")"); 
    return token::V_STRING; 
} 

而(最小化)的解析器。

start : headerparams blocks T_END; 

headerparams : /* empty */| headerparams headerparam; 

headerparam : K_CHARGE T_EQUALS charge_list T_EOL | [others ...]; 

blocks : /* empty */ | blocks block; 

block : T_BEGIN_IONS T_EOL blockparams ions T_END_IONS T_EOL| T_BEGIN_IONS T_EOL blockparams T_END_IONS T_EOL; 

blockparam : K_CHARGE T_EQUALS charge T_EOL | K_TITLE T_EQUALS V_STRING T_EOL | [others...]; 

ion : number number T_EOL| number number charge T_EOL; 

ions : ions ion| ion; 

number : V_INTEGER | V_DOUBLE; 

charge : V_INTEGER T_PLUS | V_INTEGER T_MINUS; 

charge_list : charge| charge_list T_COMA charge | charge_list T_AND charge; 

我的問題是,我得到的下一個標記:

[...] 
[line 20] 
token: K_TITLE 
token: T_EQUALS 
token: v_STRING (= Cmpd) 
token: V_INTEGER (= 1) 
Error line 20: syntax error, unexpected integer, expecting end of line 

我想有:

[...] 
[line 20] 
token: K_TITLE 
token: T_EQUALS 
token: v_STRING (Cmpd 1, +MSn (417.2108), 10.0 min) 
token: T_EOL 

如果有人能幫助我...


編輯#1 我使用標記串聯「解決」了問題:

法:

[A-Za-z][^\n[:space:]+-=,]* { 
    MGF_TOKEN_DEBUG("V_STRING"<<" (="<<yytext<<")")) 
    return token::V_STRING;t 
} 

YACC:

string_st : V_STRING 
     | string_st V_STRING 
     | string_st number 
     | string_st T_COMA 
     | string_st T_PLUS 
     | string_st T_MINUS 
     ; 

blockparam : K_CHARGE T_EQUALS charge T_EOL | K_TITLE T_EQUALS string_st T_EOL | [others...]; 
+1

適當的標籤是'flex-lexer',因爲'flex'與Adobe有關。 – crashmstr

回答

1

,如果你的字符串總是支持先從一些文字TITLE和一些文字\n(新行字符)
我會建議你使用start conditions結束,

%x IN_TITLE 

"TITLE"  { /* return V_STRING of TITILE in c++ code */ BEGIN(IN_TITLE); } 
<IN_TITLE>= { /* return T_EQUALS in c++ code */; } 
<IN_TITLE>"\n" { BEGIN(INITIAL); } 
<IN_TITLE>.* { MGF_TOKEN_DEBUG("V_STRING"<<" (="<<yytext<<")");return token::V_STRING; } 

%x IN_TITLE定義了IN_TITLE狀態,並且模式文本TITLE將使其開始。一旦它開始,\n將回到初始狀態(INITIAL是預定義的),並且其他所有角色將被消耗到V_STRING而不需要任何特殊的操作。

1

你的基本問題是一個簡單的拼寫錯誤:

[A-Za-z]([:;,()A-Za-z0-9_.-]|[[:space]])* 

應該是:

[A-Za-z]([:;,()A-Za-z0-9_.-]|[[:space:]])* 
            ^

你實際上並不需要|操作。以下是完全合法的(但可能不是你想要的要麼;見下文):

[A-Za-z][[:space:]:;,()A-Za-z0-9_.-]* 

一旦你解決這個問題,你會發現你有一個問題:你的關鍵字(TITLE,例如)將因爲STRING模式較長而被放置爲STRING。 (實際上,由於[:space:]包括\n,該STRING模式可能會擴展到輸入的結尾,你可能想[:blank:]。)

我參加了一個快速瀏覽一下你正在試圖解析格式的描述,但它不是一個非常精確的描述。但看來參數行的格式爲:

^[[:alpha:]]+=.*$ 

也許:alpha:應該:alnum:甚至一些更寬鬆的;正如我所說,描述並不十分精確。但有一點是:

  • 的關鍵詞是不區分大小寫的,所以無論TITLEtitle將相同的工作,
  • =標誌是強制性的,可能沒有其任一側的空間。 (所以你的TITLE=行不正確,但也許沒關係)。

爲了不與數據的解析干擾,你可能想使上面,其值是=之後的部分,並且其類型對應於(情況下歸一化的)關鍵字的單個「令牌」。當然,每個參數類型都可能需要特殊值解析器,這隻能通過使用開始條件在flex中實現。無論如何,你應該考慮TITLE中不屬於STRING模式的流浪角色的後果,以及你如何提出處理由此產生的詞彙錯誤。


您的代碼沒有說清楚如何將文本值從詞法分析器傳遞到解析器。您需要注意的是,yytext的值僅在其對應的令牌的詞法分析器操作內部是安全的。下一次對詞法分析器的調用將使其無效,而野牛解析器幾乎總是有一個超前標記,所以在處理標記之前詞法分析器會再次被調用。因此,您必須必須複製yytext才能將它傳遞給解析器,並且解析器需要獲取副本的所有權,以便最終不會泄漏內存。