我正在编写词法分析器来扫描修改后的INI文件版本。
我需要识别要赋给变量的变量,注释和字符串(在双引号之间)的声明。例如,这是正确的:
# 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); }
;
答案 0 :(得分: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();
函数中。
由于通常会忽略评论,因此最好忽略使用以下规则:
"#".* ; /* ignored */
在flex
文件中。这使得生成的扫描程序不会返回并忽略刚刚读取的令牌。
您可能没有考虑到您的解析器允许您在表单上引入行:
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 */
由于您要处理评论这一事实,这很复杂。如果你忽略它们(在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 ;
这样,文件中允许的第一件事是,除了注释之外,被忽略的空格(EOL
s不被视为空格,因为我们无法忽略它们,它们会终止行)