2012-07-15 70 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 ;