【问题标题】:Flex RegEx to find string not starting with a patternFlex RegEx 查找不以模式开头的字符串
【发布时间】:2015-12-17 21:22:27
【问题描述】:

我正在编写一个词法分析器来扫描 INI 文件的修改版本。

我需要识别要分配给变量的变量、cmets 和字符串(在双引号之间)的声明。例如,这是正确的:

# this is a comment
var1 = "string value"

我已经成功地识别出这些标记,它们在评论正则表达式的乞求处强制使用#,在字符串正则表达式的末尾强制使用",但我不想这样做,因为稍后会,使用 Bison,我得到的令牌正好是 # this is a comment"string value"。相反,我想要this is a comment(没有#)和string value(没有"

这些是我目前使用的正则表达式:

[a-zA-Z][a-zA-Z0-9]*    { return TOKEN_VAR_NAME; }
["][^\n\r]*["]          { return TOKEN_STRING;   }
[#][^\n\r]*             { return TOKEN_COMMENT;  }

显然,在字符串、注释以及变量名和=之间可以有任意数量的空格和制表符。

我怎样才能达到我想要的结果?


如果我向您展示一个正确输入文件的完整示例以及我在 Flex 和 Bison 中使用的语法规则,也许会更容易。

正确的输入文件示例:

[section1]
var1 = "string value"
var2 = "var1 = text"
# this is a comment
# var5 = "some text" this is also a valid comment

这些是词法分析器的正则表达式:

"["                     { return TOKEN::SECTION_START; } 
"]"                     { return TOKEN::SECTION_END; }
"="                     { return TOKEN::ASSIGNMENT; }
[#][^\n\r]*             { return TOKEN::COMMENT; }
[a-zA-Z][a-zA-Z0-9]*    { *m_yylval = yytext; return TOKEN::ID; }
["][^\n\r]*["]          { *m_yylval = yytext; return TOKEN::STRING; }

这些是语法规则:

input   : input line
        | line
        ;

line    : section
        | value
        | comment
        ;

section : SECTION_START ID SECTION_END      { createNewSection($2); }
        ;

value   : ID ASSIGNMENT STRING              { addStringValue($1, $3); }
        ;

comment : COMMENT                           { addComment($1); }
        ;

【问题讨论】:

  • 似乎使用词法分析器必须解析每个字符。我不知道使用环视断言是否可行。因此,您可能必须使用["] 和使用[#]COMMENT_START 来维持STRING_START(和结束)状态。此外,要获取简单字符串的内容(对转义引号一无所知),您将使用 [^"]* 跨行(即,不是 [^\n\r]*

标签: regex string flex-lexer


【解决方案1】:

为此,您必须将 "# 视为不同的令牌(因此它们会作为单独的令牌进行扫描,与您现在正在扫描的令牌不同)并使用 %s%x 开始条件在使用扫描仪输入读取这些令牌时更改接受的常规模式。

这增加了另一个缺点,即您将在注释之前收到# 作为单独的标记,在字符串内容之前和之后收到",您必须在语法中处理这些问题。这会使你的语法和扫描器变得复杂,所以我不鼓励你采用这种方法。

有一个更好的解决方案,通过编写一个例程来取消转义,并通过返回 yytext 中的所有输入字符串让扫描器变得更简单

m_yylval = unescapeString(yytext);  /* drop the " chars */  
return STRING; 

m_yylval = uncomment(yytext); /* drop the # at the beginning */
return COMMENT;  /* return EOL if you are trying the exmample at the end */

yylex(); 函数中。

注意

由于 cmets 通常会被忽略,因此最好使用如下规则忽略:

"#".*         ; /* ignored */

在您的 flex 文件中。这使得生成的扫描器不会返回并忽略刚刚读取的令牌。

注2

您可能没有考虑到您的解析器将允许您在表单中引入行:

var = "data"

在任何前面

[section]

行,因此在没有创建任何部分时尝试addStringvalue(...); 会遇到麻烦。一种可能的解决方案是修改语法以将文件分段并强制它们以分段行开头,例如:

compilation: file comments ;

file: file section
    | ; /* empty */

section: section_header section_body;

section_header: comments `[` ident `]` EOL

section_body: section_body comments assignment
    | ; /* empty */

comments: comments COMMENT
    | ; /* empty */

由于您要处理 cmets,这使情况变得复杂。如果您要忽略它们(在 flex 扫描仪中使用 ;),语法将是:

file: empty_lines file section
    | ; /* empty */

empty_lines: empty_lines EOL
    | ; /* empty */

section: header body ;

header: '[' IDENT ']' EOL ;

body: body assignment
    | ; /* empty */

assignment: IDENT '=' strings EOL
    | EOL ; /* empty lines or lines with comments */

strings: 
      strings unit
    | unit ;

unit: STRING
    | IDENT
    | NUMBER ;

这样,除了 cmets 之外,文件中允许的第一件事是被忽略和空格(EOLs 不被视为空格,因为我们不能忽略它们,它们会终止行)

【讨论】:

    猜你喜欢
    • 2022-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-21
    • 1970-01-01
    • 1970-01-01
    • 2011-08-06
    相关资源
    最近更新 更多