如何在Lex中禁用最大的munch规则?

时间:2014-12-30 11:37:19

标签: c regex compiler-construction lex

假设我想处理某些模式,并且在输出文件中有其他文本(VHDL代码)。

为此目的,我需要在最后写一个主规则

(MY_PATTERN){
// do something with my pattern
}

(.*){
return TOK_VHDL_CODE;

}

这个策略的问题是MY_PATTERN在这种情况下没用,并且会通过最大的munch规则与。*匹配。

那我怎样才能获得这个功能呢?

2 个答案:

答案 0 :(得分:1)

理论上,可以找到一个与不包含模式的字符串匹配的正则表达式,但除非是非常简单的模式,否则它既不容易也不易读。

如果您只想搜索特定模式(并做出反应),您可以使用与一个字符匹配的默认规则,并且不执行任何操作:

{Pattern1}   { /* Do something with the pattern */ }
{Pattern2}   { /* Do something with the pattern */ }
.|\n         /* Default rule does nothing */

另一方面,如果你想对不匹配的字符串做一些事情(如你的例子中所示),你需要默认规则来累积字符串,并且模式规则要“发送” (返回)累积的令牌,然后对他们匹配的令牌进行操作。这意味着某些操作需要发送两个令牌,这对于标准parser calls scanner for a token架构来说有点尴尬,因为它需要扫描程序维持某种状态。

如果您有一个不太古老的bison版本,则可以使用“推送解析器”,这样扫描程序就可以调用解析器。这样可以轻松地在一个动作中发送两个令牌。否则,您需要在扫描仪中构建一种状态机。

下面是一个使用推送解析器的简单示例(需要使用模式定义等)。

%{
  #include <stdlib.h>
  #include <string.h>
  #include "parser.tab.h"
  /* Since the lexer calls the parser and we call the lexer,
   * we pass through a parser (state) to the lexer. This is
   * how you change the `yylex` prototype:
   */
  #define YY_DECL static int yylex(yypstate* parser)
%}

pattern1   ...
pattern2   ...

/* Standard "avoid warnings" options */
%option noyywrap noinput nounput nodefault

%%
  /* Indented code before the first pattern is inserted at the beginning
   * of yylex, perfect for local variables.
   */
  size_t vhdl_length = 0;
  /* These are macros because they do out-of-sequence return on error. */
  /* If you don't like macros, please accept my apologies for the offense. */
  #define SEND_(toke, leng) do { \
    size_t leng_ = leng; \
    char* text = memmove(malloc(leng_ + 1), yytext, leng_); \
    text[leng_] = 0; \
    int status = yypush_parse(parser, toke, &text); \
    if (status != YYPUSH_MORE) return status; \
  } while(0);
  #define SEND_TOKEN(toke) SEND_(toke, yyleng)
  #define SEND_TEXT do if(vhdl_length){ \
    SEND_(TEXT, vhdl_length); \
    yytext += vhdl_length; yyleng -= vhdl_length; vhdl_length = 0; \
  } while(0);

{pattern1}   { SEND_TEXT; SEND_TOKEN(TOK_1); }
{pattern2}   { SEND_TEXT; SEND_TOKEN(TOK_2); }
  /* Default action just registers that we have one more char 
   * calls yymore() to keep accumulating the token.
   */
.|\n      { ++vhdl_length; yymore(); }
  /* In the push model, we're responsible for sending EOF to the parser */
<<EOF>>   { SEND_TEXT; return yypush_parse(parser, 0, 0); }

%%

/* In this model, the lexer drives everything, so we provide the
 * top-level interface here.
 */

int parse_vhdl(FILE* in) {
  yyin = in;
  /* Create a new pure push parser */
  yypstate* parser = yypstate_new();
  int status = yylex(parser);
  yypstate_delete(parser);
  return status;
}

要真正让它与野牛一起工作,你需要提供一些额外的选择:

parser.y

%code requires {
  /* requires blocks get copied into the tab.h file */
  /* Don't do this if you prefer a %union declaration, of course */
  #define YYSTYPE char*
}
%code {
  #include <stdio.h>
  void yyerror(const char* msg) { fprintf(stderr, "%s\n", msg); }
}

%define api.pure full
%define api.push-pull push

答案 1 :(得分:1)

最简单的方法是在最后删除默认规则中的*,然后使用

.    { append_to_buffer(*yytext); }

因此,您的默认规则会将所有与之前规则不匹配的内容收集起来并将其填充到缓冲区中,然后由其他人处理。