2012-07-15 40 views
-1

我想用flex和bison編寫解析器,但是我對它的工作原理感到困惑。我試圖採取下列方式格式化的文本文件:在野牛上處理羣體

Version Header Version 1.00 <--- File always starts with a header 
Key      : Value <--- Each section includes these but these after the version header are in the "Root" section 
==Section Name <--- A section 
$Key     : Value <--- These are properties 
Key      : Value <--- Same thing as in the "Root" section 

樣本格式:

NasuTek Licensing Version 1.00 
Vendor     : NASUTEKENTERPRISES 
Notice     : NasuTek Enterprises 
License Group   : NasuTek Asheila 
License Name   : NasuTek Asheila 
Vendor Notice   : NasuTek Asheila Internal Build License 
Serial     : ASHEL-87267-4987-3737-37821:32742 
Start Date    : Wed July 04 00:00:00 2012 
End Date    : Sat July 20 00:00:00 2013 
Trial     : Yes 
Count     : 0 
Components    : EXPORT 
Host     : Any 

==Software Configuration 
$Signed Section   : Yes 
Export Configuration : { 
    Supports Export to XML  : Yes 
    Supports Export to Text  : Yes 
} 

==Signature 
vpUsQJ+Qo4OS+RQg0vuLW0mXjAj/o6v[trunicated] 

我怎樣才能做到這一點是我在分組困惑。我可以得到它看到密鑰對,因爲這很簡單,但我不知道如何處理分裂使用==和{}對?

+0

你在解析? – iammilind 2012-07-15 04:49:29

+0

你真的需要使用完整的解析器嗎?它看起來像你的輸入格式非常簡單,你可以逐行閱讀並根據需要生成輸出。 – 2012-07-15 04:51:45

+0

它是我正在編寫的應用程序的一種配置文件。 「==」是部分拆分,任何不在部分中的版本頭部將進入根部分。 – DrHouse 2012-07-15 04:52:35

回答

1

好的,你的語法不是那麼簡單。但是,我所做的是在詞法分析器中定義一個令牌,將\n==視爲段起始符號(我稱之爲EQEQ)。所以,語法規則看上去像:

section_line: 
     EQEQ section_name NEWLINE 
    ; 

和令牌化規則看起來像:

"\n=="   { BEGIN(SEC); return EQEQ; } 

我爲了使用的啓動條件是能夠治療的話Signature像關鍵字,如果它是右後EQEQ,另有啓動條件,這樣的簽名部分將在簽名數據只作爲拉一個單一的文本斑點:

<SEC>"Signature" { BEGIN(SIG); return SIGNATURE; } 
<SIG>{text}  { return (BEGIN(INITIAL), TEXT); } 

的GRO uping規則最容易在單個規則中定義。這是我用一個屬性鍵值對的語法:

section_property: 
     key COLON value NEWLINE 
    | key COLON value_block NEWLINE 
    ; 

然後這是我用來定義value_block規則:

value_block: 
     LBRACE NEWLINE sub_properties RBRACE 
    ; 

而且,一個sub_property看起來就像一個section_property

每遇到新節,解析代碼應記住後續值對屬於哪個節。同樣,在解析子屬性塊時,應該保存封閉屬性關鍵字,以便可以適當地分配子屬性。

有一件事可能會像解析器一樣在yacc中絆倒你,它的底部屬性就是它。由於規則的葉元素被識別,請將值保存在葉規則中,並在您的封閉規則中引用保存的值。例如,這條規則:

words: 
     WORD { words_add($1); free($1); } 
    | WORD { words_add($1); free($1); } words 
    ; 

將連續字保存到表示字序列的保存緩衝區中。然後,在一個封閉的規則,從而節省緩衝重新保存:

key: 
     words { words_save_as_key(); } 
    ; 

words_save_as_key基本上覆本保存字的緩衝區,然後重置該緩衝區爲不同的序列將被保存(有可能的,序列代表相關值)。

3

那麼,無論何時試圖決定如何設計基於flex/bison的解析器,第一個問題是應該在flex中做什麼以及在野牛中做什麼?

Flex可以使用任意正則表達式,甚至可以使用狀態在不同的上下文中允許不同的RE,但通常它只能識別孤立的事物 - 太多的上下文(超過可以通過幾個start狀態)或任何遞歸是硬/不可能在flex

野牛另一方面,很容易處理遞歸,並可以很容易地涉及在不同的上下文中的標記,但規則只是簡單的標記序列,沒有正則表達式和有限的(1令牌)。

所以在你的情況下,你需要看看那些難以識別的東西。出現的第一件事是: - 你使用這個字符從值中分離鍵和值。它可以出現在鍵?如果不是,那麼你可能只想在一條線上處理第一個:(很容易在flex中做一個開始狀態;由於它需要通過描述所有可能包含冒號的值,野牛有點難)

Next in '棘手的識別'是間隔 - 鍵和值中有空格,還有其他空間應該被忽略。你可以很容易地管理這些flex。但是,您不會描述可能出現在輸入文件中的任何類型的評論。如果有評論,你通常想要在flex中識別(忽略)它們,將它們視爲被忽略的空間。

最後還有其他所有可能出現在文件中的字符,但在您的示例中沒有描述。這些包括所有其他標點符號 - 它們在鍵或值中是否合法?該$==被描述爲只出現在一行的開始 - 當給定的,如果他們是在其他地方(無論是在一行的開頭或在空格後/後項或值?)

我的傾向像這樣的東西只是一個模糊的,不完整的例子,就是說其他任何東西都是非法的,並且應該給出關於錯誤發生的體面的錯誤信息。所以我想最終的柔性掃描儀,看起來像:

{KVchar} [-A-Za-z0-9.+/]  /* legal characters in a key or value */ 
{WS}  [ \t\r]    /* whitespace -- ignored but allowed in a key or value */ 

%s COLON       /* seen a colon on the current line */ 
%% 

":"  { BEGIN(COLON); return ':'; } 
\n   { BEGIN(INITIAL); return '\n'; } 
<INITIAL>({KVchar}+({WS}+{KVchar}+)*)   { 
      yylval.key = strdup(yytext); 
      return KEY; } 
<COLON>({KVchar}+((:|{WS})+{KVchar}+)*)   { 
      /* values may contain colons, but can't start or end with them */ 
      yylval.key = strdup(yytext); 
      return VALUE; } 
[${}]  { return *yytext; } 
"=="  { return EQEQ; } 
{WS}+  ; /* ignore */ 
.   { fprintf(stderr, "Spurious character '%c' in input\n"); } 

和野牛文件看起來像:

%union { 
    char *key; /* or value */ 
} 
%token<key> KEY VALUE 
%token  EQEQ 
%% 

input: header kvpairs sections ; 

header: KEY 
; 

kvpairs: kvpairs kvpair 
     | /* empty */ 
; 

kvpair: key ':' value '\n' 
     | '\n' 
; 

key: KEY 
    | '$' KEY 
; 

value: VALUE 
    | '{' '\n' kvpairs '}' '\n' 
; 

sections: sections section | /*empty*/ ; 

section: EQEQ KEY '\n' kvpairs ;