柠檬LALR解析器的简单语法

时间:2011-07-20 19:35:04

标签: parsing parser-generator lalr lemon

我已经坚持了一段时间了。我想解析一些简单的东西:

LIKES:word1 word2 ... wordN HATES:word1 word2 ... wordN

我正在使用Lemon + Flex。目前我的语法看起来像这样:

%left LIKES MOODS FROM HATES INFO.

%syntax_error {  
  std::cout << "Syntax error!" << std::endl;  
}   

final ::= likes_stmt.
final ::= hates_stmt.

likes_stmt ::= LIKES list(A). { Data *data=Data::getInstance();data->likes.push_back(A);}
hates_stmt ::= HATES list(A). { Data *data=Data::getInstance();data->hates.push_back(A);}

list ::= likes_stmt VALUE(A).   { Data *data=Data::getInstance();data->likes.push_back(A);}
list ::= hates_stmt VALUE(A).   { Data *data=Data::getInstance();data->hates.push_back(A); }

list(A) ::= VALUE(B).           {A=B;}

但这仅适用于前2个单词。显然我做错了,可能是在递归定义中?任何抬头都表示赞赏:)

2 个答案:

答案 0 :(得分:2)

在我看来,您的likes_stmt是按照列表定义的,而列表是根据喜欢来定义的。我很惊讶它对任何单词都有效。可能是我不理解LEMON语法(我肯定不会得到列表(A)位),但语法BNF往往非常相似。

我希望你的语法看起来更像:

 final = likes_stmt ;

 likes_stmt = LIKES list ;
 likes_stmt = HATES list ;


  list = value ;
  list = list value ;

当然,这只能识别一个LIKES短语或一个HATES短语,但不能同时识别问题第2行所暗示的相同时间或顺序。

答案 1 :(得分:2)

@crozzfire,Ira为您的原始问题提供了正确答案,请考虑投票。

让我回答这个问题,你需要将解析后的值分成两个列表。不要为解析这些列表创建不同的规则,因为列表的语法对于两种情况都是相同的。你需要的是一个标志,表明在列表前面是否找到了LIKES或HATES。 Lemon Parse函数的第四个参数最适合这种需求。请参阅Lemon documentation的“分析器界面”部分。

下面更新了Ira的语法,用于设置和检查这样的标志变量。请注意,需要在LIKES和HATES令牌之前放置规则set_likes_stateset_hites_state,以便在令牌减少时执行相关操作。

    %extra_argument {unsigned* state}

    final ::= likes_stmt.
    final ::= hates_stmt.

    likes_stmt ::= set_likes_state LIKES list(A).
    hates_stmt ::= set_hites_state HATES list(A).

    list ::= list VALUE(A).   { if (*state == 0) {/*add A to list1*/} else {/*add A to list2*/}; }
    list ::= VALUE(A).        { if (*state == 0) {/*add A to list1*/} else {/*add A to list2*/}; }

    set_likes_state ::= .     { *state = 0; }
    set_hites_state ::= .     { *state = 1; }